diff --git a/src/hos_celix/CMakeLists.txt b/src/hos_celix/CMakeLists.txt index fc3c5de1..64f971b3 100644 --- a/src/hos_celix/CMakeLists.txt +++ b/src/hos_celix/CMakeLists.txt @@ -95,6 +95,7 @@ ExternalProject_Add( celix_project SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src CONFIGURE_COMMAND cmake ${CMAKE_CURRENT_SOURCE_DIR}/src -DCMAKE_INSTALL_PREFIX=${CATKIN_DEVEL_PREFIX} + -DBUILD_SHARED_LIBS=TRUE -DBUILD_FRAMEWORK=TRUE -DBUILD_LAUNCHER=TRUE -DBUILD_UTILS=TRUE diff --git a/src/hos_cosgi_core/CMakeLists.txt b/src/hos_cosgi_core/CMakeLists.txt new file mode 100644 index 00000000..cdb3bbf3 --- /dev/null +++ b/src/hos_cosgi_core/CMakeLists.txt @@ -0,0 +1,161 @@ +cmake_minimum_required(VERSION 2.8.3) +project(hos_cosgi_core) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + hos_celix +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependencies might have been +## pulled in transitively but can be declared for certainty nonetheless: +## * add a build_depend tag for "message_generation" +## * add a run_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# std_msgs # Or other packages containing msgs +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if you package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( + INCLUDE_DIRS include +# LIBRARIES hos_cosgi_core + CATKIN_DEPENDS hos_celix +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +# include_directories(include) +include_directories( + ${catkin_INCLUDE_DIRS} +) + +## Declare a cpp library +# add_library(hos_cosgi_core +# src/${PROJECT_NAME}/hos_cosgi_core.cpp +# ) + +## Declare a cpp executable +# add_executable(hos_cosgi_core_node src/hos_cosgi_core_node.cpp) + +## Add cmake target dependencies of the executable/library +## as an example, message headers may need to be generated before nodes +# add_dependencies(hos_cosgi_core_node hos_cosgi_core_generate_messages_cpp) + +## Specify libraries to link a library or executable target against +# target_link_libraries(hos_cosgi_core_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# install(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables and/or libraries for installation +# install(TARGETS hos_cosgi_core hos_cosgi_core_node +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +install(DIRECTORY include/${PROJECT_NAME}/ + DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} + FILES_MATCHING PATTERN "*.h" + PATTERN ".svn" EXCLUDE +) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_hos_cosgi_core.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/src/hos_cosgi_core/include/hos_cosgi_core/cosgi_core.h b/src/hos_cosgi_core/include/hos_cosgi_core/cosgi_core.h new file mode 100644 index 00000000..cc2a94cb --- /dev/null +++ b/src/hos_cosgi_core/include/hos_cosgi_core/cosgi_core.h @@ -0,0 +1,25 @@ +/* + * cosgi_core.h + * + * Created on: 19.04.2015 + * Author: matzman + */ + +#ifndef INCLUDE_HOS_COSGI_CORE_COSGI_CORE_H_ +#define INCLUDE_HOS_COSGI_CORE_COSGI_CORE_H_ + + +class COSGI_Object_Interface { +public: + virtual ~COSGI_Object_Interface() {} +}; + + +class COSGI_Service_Interface : public COSGI_Object_Interface { +public: + virtual const char* getServiceName() = 0; + virtual void getServiceVersion(int& major, int& minor) = 0; +}; + + +#endif /* INCLUDE_HOS_COSGI_CORE_COSGI_CORE_H_ */ diff --git a/src/hos_cosgi_core/package.xml b/src/hos_cosgi_core/package.xml new file mode 100644 index 00000000..41f67a15 --- /dev/null +++ b/src/hos_cosgi_core/package.xml @@ -0,0 +1,52 @@ + + + hos_cosgi_core + 0.0.0 + The hos_cosgi_core package + + + + + matzman + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + hos_celix + hos_celix + + + + + + + + \ No newline at end of file diff --git a/src/hos_cosgi_devicerepository/CMakeLists.txt b/src/hos_cosgi_devicerepository/CMakeLists.txt index 9dd2f47e..85ce2844 100644 --- a/src/hos_cosgi_devicerepository/CMakeLists.txt +++ b/src/hos_cosgi_devicerepository/CMakeLists.txt @@ -8,6 +8,9 @@ find_package(catkin REQUIRED COMPONENTS hos_celix hos_core_msgs hos_cosgi_launcher + hos_cosgi_core + hos_libvariant + roscpp ) ## System dependencies are found with CMake's conventions @@ -87,7 +90,7 @@ find_package(Boost REQUIRED) catkin_package( INCLUDE_DIRS include # LIBRARIES hos_cosgi_devicerepository - CATKIN_DEPENDS hos_celix hos_core_msgs hos_cosgi_launcher + CATKIN_DEPENDS hos_celix hos_core_msgs hos_cosgi_launcher roscpp hos_cosgi_core hos_libvariant # DEPENDS system_lib ) diff --git a/src/hos_cosgi_devicerepository/include/hos_cosgi_devicerepository/hos_devicerepository_service.h b/src/hos_cosgi_devicerepository/include/hos_cosgi_devicerepository/hos_devicerepository_service.h index f3232447..8754d518 100644 --- a/src/hos_cosgi_devicerepository/include/hos_cosgi_devicerepository/hos_devicerepository_service.h +++ b/src/hos_cosgi_devicerepository/include/hos_cosgi_devicerepository/hos_devicerepository_service.h @@ -2,6 +2,7 @@ #define _HOS_DEVICEREPOSITORY_SERVICE_H_ +#include #include #include @@ -11,10 +12,8 @@ namespace hos { class DeviceEvent; class DeviceEventListener; -class GenericDevice { +class GenericDevice : public COSGI_Object_Interface { public: - virtual ~GenericDevice() {} - virtual std::string getDeviceID() = 0; virtual bool registerDeviceStatusListener(DeviceEventListener& listener) = 0; @@ -30,26 +29,23 @@ public: }; -class DeviceEventListener { +class DeviceEventListener : public COSGI_Object_Interface { public: - virtual ~DeviceEventListener() {} virtual void deviceEventReceived(const DeviceEvent& event) = 0; }; -class HOSDeviceRepositoryService { +class HOSDeviceRepositoryService : public COSGI_Service_Interface { public: static constexpr const char* SERVICE_NAME = "hos_devicerepository_service"; - - virtual ~HOSDeviceRepositoryService() {} + static constexpr int SERVICE_VERSION_MAJOR = 1; + static constexpr int SERVICE_VERSION_MINOR = 0; virtual GenericDevice* getDevice(std::string device_id) = 0; virtual std::vector& getDevices(std::vector& devices) = 0; virtual bool registerDeviceStatusListener(DeviceEventListener& listener) = 0; virtual bool unregisterDeviceStatusListener(DeviceEventListener& listener) = 0; - - virtual void getVersion(int& major, int& minor) = 0; }; diff --git a/src/hos_cosgi_devicerepository/package.xml b/src/hos_cosgi_devicerepository/package.xml index 8a8c761a..0486b7ca 100644 --- a/src/hos_cosgi_devicerepository/package.xml +++ b/src/hos_cosgi_devicerepository/package.xml @@ -43,9 +43,15 @@ hos_celix hos_core_msgs hos_cosgi_launcher + roscpp + hos_cosgi_core + hos_libvariant hos_celix hos_core_msgs hos_cosgi_launcher + roscpp + hos_cosgi_core + hos_libvariant @@ -56,4 +62,4 @@ - \ No newline at end of file + diff --git a/src/hos_cosgi_devicerepository/src/bundle_activator.cpp b/src/hos_cosgi_devicerepository/src/bundle_activator.cpp index bbe5f3cd..a6e92897 100644 --- a/src/hos_cosgi_devicerepository/src/bundle_activator.cpp +++ b/src/hos_cosgi_devicerepository/src/bundle_activator.cpp @@ -56,7 +56,7 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) ROS_ERROR("DeviceRepositoryService: Could not retrieve HOSCoreService."); } else { int major = 0, minor = 0; - coreService->getVersion(major, minor); + coreService->getServiceVersion(major, minor); ROS_INFO_STREAM("DeviceRepositoryService: Found HOSCoreService Version " << major << "." << minor); // Create and register hos-devicerepository-service if (myUserData->serviceReg != nullptr) { diff --git a/src/hos_cosgi_devicerepository/src/hos_devicerepository_service_impl.cpp b/src/hos_cosgi_devicerepository/src/hos_devicerepository_service_impl.cpp index 22df7dc6..84c0e2e2 100644 --- a/src/hos_cosgi_devicerepository/src/hos_devicerepository_service_impl.cpp +++ b/src/hos_cosgi_devicerepository/src/hos_devicerepository_service_impl.cpp @@ -41,8 +41,6 @@ HOSDeviceRepositoryServiceImpl::HOSDeviceRepositoryServiceImpl(HOSCoreService& c privateNodeHandle.getParam("~device_repository_prefix", deviceRepositoryPrefix); } -HOSDeviceRepositoryServiceImpl::~HOSDeviceRepositoryServiceImpl() {} - GenericDevice* HOSDeviceRepositoryServiceImpl::getDevice(std::string device_id) { return this->devices[device_id]; } @@ -75,9 +73,9 @@ bool HOSDeviceRepositoryServiceImpl::unregisterDeviceStatusListener(DeviceEventL } -void HOSDeviceRepositoryServiceImpl::getVersion(int& major, int& minor) { - major = 1; - minor = 0; +void HOSDeviceRepositoryServiceImpl::getServiceVersion(int& major, int& minor) { + major = SERVICE_VERSION_MAJOR; + minor = SERVICE_VERSION_MINOR; } int HOSDeviceRepositoryServiceImpl::getRefCount() { diff --git a/src/hos_cosgi_devicerepository/src/hos_devicerepository_service_impl.h b/src/hos_cosgi_devicerepository/src/hos_devicerepository_service_impl.h index 5e281143..930f2671 100644 --- a/src/hos_cosgi_devicerepository/src/hos_devicerepository_service_impl.h +++ b/src/hos_cosgi_devicerepository/src/hos_devicerepository_service_impl.h @@ -45,7 +45,6 @@ private: public: HOSDeviceRepositoryServiceImpl(HOSCoreService& coreService); - virtual ~HOSDeviceRepositoryServiceImpl(); virtual GenericDevice* getDevice(std::string device_id); virtual std::vector& getDevices(std::vector& devices); @@ -53,7 +52,9 @@ public: virtual bool registerDeviceStatusListener(DeviceEventListener& listener); virtual bool unregisterDeviceStatusListener(DeviceEventListener& listener); - virtual void getVersion(int& major, int& minor); + virtual const char* getServiceName() { return SERVICE_NAME; } + virtual void getServiceVersion(int& major, int& minor); + virtual int getRefCount(); }; diff --git a/src/hos_cosgi_launcher/CMakeLists.txt b/src/hos_cosgi_launcher/CMakeLists.txt index 8709eed1..92447fab 100644 --- a/src/hos_cosgi_launcher/CMakeLists.txt +++ b/src/hos_cosgi_launcher/CMakeLists.txt @@ -7,6 +7,7 @@ project(hos_cosgi_launcher) find_package(catkin REQUIRED COMPONENTS hos_celix roscpp + hos_cosgi_core ) ## System dependencies are found with CMake's conventions @@ -82,7 +83,7 @@ find_package(APR REQUIRED) catkin_package( INCLUDE_DIRS include # LIBRARIES hos_cosgi_launcher - CATKIN_DEPENDS hos_celix + CATKIN_DEPENDS hos_celix hos_cosgi_core # DEPENDS system_lib ) diff --git a/src/hos_cosgi_launcher/include/hos_cosgi_launcher/hos_core_service.h b/src/hos_cosgi_launcher/include/hos_cosgi_launcher/hos_core_service.h index 55474873..68af32ec 100644 --- a/src/hos_cosgi_launcher/include/hos_cosgi_launcher/hos_core_service.h +++ b/src/hos_cosgi_launcher/include/hos_cosgi_launcher/hos_core_service.h @@ -2,22 +2,24 @@ #define SRC_HOS_CORE_SERVICE_H_ +#include + + namespace ros { class NodeHandle; } namespace hos { -class HOSCoreService { +class HOSCoreService : public COSGI_Service_Interface { public: static constexpr const char* SERVICE_NAME = "hos_core_service"; - - virtual ~HOSCoreService() {} + static constexpr int SERVICE_VERSION_MAJOR = 1; + static constexpr int SERVICE_VERSION_MINOR = 0; virtual ros::NodeHandle& getPublicNodeHandle() = 0; virtual ros::NodeHandle& getPrivateNodeHandle() = 0; virtual void requestShutdown() = 0; - virtual void getVersion(int& major, int& minor) = 0; }; } // namespace hos diff --git a/src/hos_cosgi_launcher/package.xml b/src/hos_cosgi_launcher/package.xml index 32437d2d..5d74924f 100644 --- a/src/hos_cosgi_launcher/package.xml +++ b/src/hos_cosgi_launcher/package.xml @@ -42,8 +42,10 @@ catkin hos_celix roscpp + hos_cosgi_core hos_celix roscpp + hos_cosgi_core diff --git a/src/hos_cosgi_launcher/src/hos_core_service_impl.cpp b/src/hos_cosgi_launcher/src/hos_core_service_impl.cpp index 180e59ab..22fcd3b5 100644 --- a/src/hos_cosgi_launcher/src/hos_core_service_impl.cpp +++ b/src/hos_cosgi_launcher/src/hos_core_service_impl.cpp @@ -14,8 +14,6 @@ namespace hos { HOSCoreServiceImpl::HOSCoreServiceImpl(ros::NodeHandle& publicNodeHandle, ros::NodeHandle& privateNodeHandle) : publicNodeHandle(publicNodeHandle), privateNodeHandle(privateNodeHandle) {} -HOSCoreServiceImpl::~HOSCoreServiceImpl() {} - ros::NodeHandle& HOSCoreServiceImpl::getPublicNodeHandle() { return publicNodeHandle; @@ -31,9 +29,9 @@ void HOSCoreServiceImpl::requestShutdown() { ros::shutdown(); } -void HOSCoreServiceImpl::getVersion(int& major, int& minor) { - major = 1; - minor = 0; +void HOSCoreServiceImpl::getServiceVersion(int& major, int& minor) { + major = SERVICE_VERSION_MAJOR; + minor = SERVICE_VERSION_MINOR; } } // namespace hos diff --git a/src/hos_cosgi_launcher/src/hos_core_service_impl.h b/src/hos_cosgi_launcher/src/hos_core_service_impl.h index 50a7ce1b..85a66b13 100644 --- a/src/hos_cosgi_launcher/src/hos_core_service_impl.h +++ b/src/hos_cosgi_launcher/src/hos_core_service_impl.h @@ -20,12 +20,12 @@ private: public: HOSCoreServiceImpl(ros::NodeHandle& publicNodeHandle, ros::NodeHandle& privateNodeHandle); - virtual ~HOSCoreServiceImpl(); virtual ros::NodeHandle& getPublicNodeHandle(); virtual ros::NodeHandle& getPrivateNodeHandle(); virtual void requestShutdown(); - virtual void getVersion(int& major, int& minor); + virtual const char* getServiceName() { return SERVICE_NAME; } + virtual void getServiceVersion(int& major, int& minor); }; } // namespace hos diff --git a/src/hos_libvariant/CMakeLists.txt b/src/hos_libvariant/CMakeLists.txt new file mode 100644 index 00000000..b138e1c7 --- /dev/null +++ b/src/hos_libvariant/CMakeLists.txt @@ -0,0 +1,193 @@ +cmake_minimum_required(VERSION 2.8.3) +project(hos_libvariant) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependencies might have been +## pulled in transitively but can be declared for certainty nonetheless: +## * add a build_depend tag for "message_generation" +## * add a run_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# std_msgs # Or other packages containing msgs +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if you package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( + INCLUDE_DIRS include + LIBRARIES Variant +# CATKIN_DEPENDS other_catkin_pkg +# DEPENDS system_lib +) + +########### +## Build ## +########### + +include(ExternalProject) + +ExternalProject_Add( libvariant_project + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src + CONFIGURE_COMMAND cmake ${CMAKE_CURRENT_SOURCE_DIR}/src + -DCMAKE_INSTALL_PREFIX=${CATKIN_DEVEL_PREFIX} + -DBUILD_SHARED_LIBS=FALSE + -DLIBVARIANT_BUILD_EXAMPLES=FALSE + -DLIBVARIANT_BUILD_TESTS=FALSE + -DLIBVARIANT_BUILD_WALL=TRUE + -DLIBVARIANT_ENABLE_CURL=TRUE + -DLIBVARIANT_ENABLE_MSGPACK=FALSE + -DLIBVARIANT_ENABLE_XML=TRUE + -DLIBVARIANT_ENABLE_YAML=TRUE + BUILD_COMMAND make all + INSTALL_COMMAND make install +) + +add_library( Variant STATIC IMPORTED ) +set_property( TARGET Variant PROPERTY IMPORTED_LOCATION "${CATKIN_DEVEL_PREFIX}/lib/libVariant.a") +add_dependencies( Variant libvariant_project ) + +## Specify additional locations of header files +## Your package locations should be listed before other locations +# include_directories(include) + +## Declare a cpp library +# add_library(hos_libvariant +# src/${PROJECT_NAME}/hos_libvariant.cpp +# ) + +## Declare a cpp executable +# add_executable(hos_libvariant_node src/hos_libvariant_node.cpp) + +## Add cmake target dependencies of the executable/library +## as an example, message headers may need to be generated before nodes +# add_dependencies(hos_libvariant_node hos_libvariant_generate_messages_cpp) + +## Specify libraries to link a library or executable target against +# target_link_libraries(hos_libvariant_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +install(DIRECTORY include/${PROJECT_NAME}/ + DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +) +install(DIRECTORY ${CATKIN_DEVEL_PREFIX}/lib/ + DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +) +install(DIRECTORY ${CATKIN_DEVEL_PREFIX}/bin/ + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} + USE_SOURCE_PERMISSIONS +) +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/cmake + FILES_MATCHING PATTERN "*.cmake" +) + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# install(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables and/or libraries for installation +# install(TARGETS hos_libvariant hos_libvariant_node +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_hos_libvariant.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/src/hos_libvariant/include/hos_libvariant/ArgParse.h b/src/hos_libvariant/include/hos_libvariant/ArgParse.h new file mode 100644 index 00000000..74248bec --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/ArgParse.h @@ -0,0 +1,302 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_ARGPARSER_H +#define VARIANT_ARGPARSER_H + +#pragma once +#include "../hos_libvariant/Variant.h" +#include +#include +namespace libvariant { + + + enum ArgParseAction { + ARGACTION_UNKNOWN, // Unknown action (invalid) + ARGACTION_STORE, // Interpret the option argument and store it at the path + ARGACTION_STORE_CONST, // Store const into the path + ARGACTION_STORE_TRUE, // Store true into the path + ARGACTION_STORE_FALSE, // Store false into the path + ARGACTION_APPEND, // Append the option argument to the list at path + ARGACTION_COUNT, // Make the value at path be the count of this options occurrences + ARGACTION_HELP, // Print out the help text and exit + ARGACTION_ADVHELP, // Print the advanced help and exit + ARGACTION_CONFIG, // Consider the option argument a filename to be loaded and parsed as a config + ARGACTION_CONFIG_JSON, // force parser to use jscn + ARGACTION_CONFIG_YAML, // force parser to use yaml + ARGACTION_CONFIG_PLIST, // force parser to use xmlplist + ARGACTION_PRINT_CONFIG // At the end of parsing print out the resulting config and exit. + }; + + // A constrained list of only the valid types for ArgParse + enum ArgParseType { + ARGTYPE_GUESS = Variant::NullType, // No type specification, guess, uses deserialize machinery + ARGTYPE_INT = Variant::IntegerType, // Error if it cannot be turned into an integer + ARGTYPE_UINT = Variant::UnsignedType, // Error if it cannot be turned into a unsigned + ARGTYPE_FLOAT = Variant::FloatType, // Error if it cannot be turned into a float + ARGTYPE_STRING = Variant::StringType, // store as string + ARGTYPE_BOOL = Variant::BoolType // Error if it cannot be turned into a boolean type + // it treats 0 or the strings 'false' and 'no' or any substring ignoring case as false + // and everything else as true + }; + + //! Valid values are: + // This is used for converting the enum to a Variant and back for + // ArgParse::GetDescription and ArgParse::Merge + // store -- store the value into the key (default) + // store_const -- store const (see Const) into the key + // store_true -- store true into the key (i.e. no option argument) + // store_false -- store false into the key + // append -- make the value a list of instances of the option + // count -- count the number of instances of this argument + // help -- display the help text and exit + // config -- load a file and merge it into the result (uses GuessFormat) + // config_json -- same as config, force to use json parser + // config_yaml -- same as config, force to use yaml parser + // config_plist -- same as config, force to use xml-plist parser + // config_print -- when finished parsing, print out the config and exit + ArgParseAction ArgParseActionFromStr(const std::string &action); + std::string ArgParseActionToStr(ArgParseAction action); + + class ArgParse; + struct ArgParseImpl; + struct ArgParseOptImpl; + struct ArgParseGroupImpl; + + //! ArgParseOption is a part of class ArgParse. + // ArgParseOption is the interface that ArgParse provides to the user to be able + // to conveniently set the options for an option. + class ArgParseOption { + public: + + //! Set the title of this option. The title is used + // as an argument placeholder string. + ArgParseOption &Title(const std::string &title); + + //! What action to perform when this option is encountered. + // See ArgParseAction above for a list of actions. + ArgParseOption &Action(ArgParseAction action); + DEPRECATED ArgParseOption &Action(const std::string &action); + + //! Set the type parsing and validation. + // If set and the argument is not of this type, then it is invalid. + // Default: ARGTYPE_GUESS + // If type is ARGTYPE_GUESS then ArgParse attempts to parse the + // argument with the same machinery that is used by the deserializers + // to figure out the type of a scalar. + // ARGTYPE_UINT is the same as ARGTYPE_INT but with + // Minimum set to 0. + // See ArgParseType for the list of valid types. + ArgParseOption &Type(ArgParseType type); + // Same as above but throws on invalid type + DEPRECATED ArgParseOption &Type(Variant::Type_t type); + // String version of the above + // Valid types are "string", "number", "integer", "boolean", or "null". + // Default type is "null". + DEPRECATED ArgParseOption &Type(const std::string &type); + + //! Set the const value for "store_const" + ArgParseOption &Const(Variant val); + + //! Set the default value used when the option is not set. + ArgParseOption &Default(Variant val); + + //! Set the environment variable name to check for a value for this option. + // When the environment variable is present this acts like Default was set + // to the environment variable's value. I.e., this overrides default, + // command line arguments override this. + ArgParseOption &Env(const char *env); + + //! If the resulting value is a number, require to be at least this minimum. + ArgParseOption &Minimum(Variant val); + + //! If the resulting value is a number, require to be at most this maximum. + ArgParseOption &Maximum(Variant val); + + //! Add choices. + // If a choice is added, the value of the option must be one of the choices. + ArgParseOption &AddChoice(Variant val); + + //! Set choices (old ones forgotten) from a vector. + ArgParseOption &SetChoices(const std::vector &val); + + //! Return the vector of choices set. + const std::vector &GetChoices(); + + //! Is this option required? + ArgParseOption &Required(bool req=true); + + //! Set the help text for this option. + ArgParseOption &Help(const std::string &helptxt); + + //! If this option is a string, it must match the regex in pattern. + ArgParseOption &Pattern(const std::string &pattern); + + //! If this option is a string, it must be no longer than maxLength. + ArgParseOption &MaxLength(unsigned l); + + //! If this option is a string, it must be no shorter than minLength. + ArgParseOption &MinLength(unsigned l); + + //! If this option can be specified multiple times, it must be + // specified minArgs times at least. + // A value of 0 means zero arguments is valid. + ArgParseOption &MinArgs(unsigned l); + + //! If this option can be specified multiple times, it cannot be + // specified more than maxArgs. + // A value of 0 means any number + ArgParseOption &MaxArgs(unsigned l); + + //! Specify that this argument must be present l times. + // Sets both minArgs and maxArgs to l + ArgParseOption &NumArgs(unsigned l); + + //! Adds this option to group gname. If gname does not exist, + //it will be created with an empty title and description. + ArgParseOption &Group(const std::string &gname); + + //! Sets this argument to be an advanced option + // This hides the option when not printing advanced options + ArgParseOption &Advanced(bool adv = true); + + private: + ArgParseOption(ArgParseOptImpl *i) : impl(i) {} + ArgParseOptImpl *impl; + friend class ArgParse; + }; + + //! Groups are a way to organize the option and to provide mutual exclusion + //of option. An argument may be part of more than one group, but may only + //be part of one group that has a non-empty title and description. An + //attempt is made to order the help text so that options within the same + //group appear together and if a group has a title and/or description the + //options are placed within a subsection headed with the title and + //description. + class OptionGroup { + public: + //! Set the title for this group + OptionGroup &Title(const std::string &t); + //! Set the description for this group + OptionGroup &Description(const std::string &d); + //! Set that the options in this group are mutually exclusive + OptionGroup &MutuallyExclusive(bool exclusive=true); + //! Set that at least one option in this group is required. + //Has no meaning when the group is not mutually exclusive. + OptionGroup &Required(bool req=true); + + OptionGroup &Add(const std::string &keypath); + OptionGroup &Add(const Path &keypath); + + //! Sets this option group to be advanced + // Hide the group when not printing advanced options. + // This only hides the group when it has a title or description + OptionGroup &Advanced(bool adv=true); + private: + OptionGroup(ArgParseGroupImpl *i) : impl(i) {} + ArgParseGroupImpl *impl; + friend class ArgParse; + }; + + class ArgParse { + public: + //! addhelp true causes AddHelp to be called. + ArgParse(bool addhelp=true); + ArgParse(const std::string &pname, bool addhelp=true); + + //! Add the option and configure it as an option that takes an argument. + //The default action will be "store" and type will be unspecified + // + // keypath must be a valid path as defined in Path.h + // + // For no short option, shortOpt may be 0, and for no long option, longOpt may be + // the empty string. If both shortOpt is 0 and longOpt is empty then this option + // is hidden unless Env is also set for the option. + ArgParseOption AddOption(const std::string &keypath, int shortOpt, const std::string &longOpt="", + const std::string &helptxt=""); + + //! Convenience methods for getting an existing option. + // ArgParse args(argv[0]); + // args.AddOption("key1", 'k', "key1", "how many things").Type("integer"); + // args.AddOption("key2", 'K', "key2", "what to name it").Type("string"); + // (... some intermediate code ...) + // args.At("key1").Default(42); + // args["key2"].Default("foo"); + ArgParseOption At(const std::string &keypath); + ArgParseOption operator[](const std::string &keypath) { return At(keypath); } + + //! Add the option and configure it as an option that is default false and + //if present sets to true + //i.e., same as: + // AddOption(keypath, shortOpt, longOpt, helptxt).Type("boolean") + // .Action("store_true").Default(false); + ArgParseOption AddFlag(const std::string &keypath, int shortOpt, const std::string &longOpt="", + const std::string &helptxt=""); + + //! Adds the group name. + OptionGroup AddGroup(const std::string &name, const std::string &title="", const std::string &description=""); + //! Returns the group name. + OptionGroup GetGroup(const std::string &name); + + //! Add a positional argument. + // By default the new positional argument will have NumArgs as 1. + // Arguments are processed in the order they are added. + // If maxArgs is 0, then no positional arguments after this one will + // be processed. + // Default action is store. + ArgParseOption AddArgument(const std::string &keypath, const std::string &helptxt=""); + + //! Convenience methods for getting an existing argument. + // ArgParse args(argv[0]); + // args.AddArgument("arg0", "pick one").AddChoice("AAA").AddChoice("BBB"); + // args.AddArgument("arg1", "scale factor").Type("float"); + // (... some intermediate code ...) + // args.At(0).AddChoice("CCC"); + // args[1].Default(0.456); + ArgParseOption At(size_t argumentIndex); + ArgParseOption operator[](size_t argumentIndex) { return At(argumentIndex); } + + //! When this is on, trying to add a second option with the same short option + //will cause the second option to act as though it had no short option specified. + void ConflictResolution(bool resolve=true); + + //! Add a --config and --print-config option + // --config is set with action ARGACTION_CONFIG and + // --print-config is set with action ARGACTION_PRINT_CONFIG + void AddConfigDefaults(); + + //! Add -h,--help option with action ARGACTION_HELP + void AddHelp(); + + //! Set the description text that follows the usage message. + void SetDescription(const std::string &txt); + //! Set the epilog text at the end of help. + void SetEpilog(const std::string &txt); + //! Override the default program name. + void SetProgramName(const std::string &pname, bool do_basename=true); + std::string GetProgramName() const; + + void Merge(Variant newopts); + void Merge(const ArgParse &other); + + //! Validate the argparse description against the internal schema + void Validate() const; + + //! Parse the arguments with the internal description + Variant Parse(int argc, char *const *argv); + + //! Print the help message and exit. + void PrintHelp(bool advanced=false) const; + + //! Return the Variant that describes the arguments + Variant GetDescription() const; + + //! Generate a schema for the Variant returned by Parse from the argument description + Variant GenerateSchema() const; + + private: + shared_ptr impl; + }; +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/Blob.h b/src/hos_libvariant/include/hos_libvariant/Blob.h new file mode 100644 index 00000000..b2706e4d --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/Blob.h @@ -0,0 +1,63 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_BLOB_H +#define VARIANT_BLOB_H + +#pragma once +#include "../../../src/include/Variant/SharedPtr.h" +#include +#include + +namespace libvariant { + class Blob; + typedef shared_ptr BlobPtr; + typedef shared_ptr ConstBlobPtr; + + typedef void (*BlobFreeFunc)(void *ptr, void *ctx); + + class Blob { + public: + + /// Reference the buffer and call ffunc when Blob no longer references it + static BlobPtr Create(void *ptr, unsigned len, BlobFreeFunc ffunc, void *context); + /// Will call ffunc on each buffer in iov + static BlobPtr Create(struct iovec *iov, unsigned iov_len, BlobFreeFunc ffunc, void *context); + /// Copy the data into a newly allocatd buffer + static BlobPtr CreateCopy(const void *ptr, unsigned len); + static BlobPtr CreateCopy(const struct iovec *iov, unsigned iov_len); + /// Reference the buffer and when done call free to free the buffer + static BlobPtr CreateFree(void *ptr, unsigned len); + static BlobPtr CreateFree(struct iovec *iov, unsigned iov_len); + /// Reference the buffer, assume static or other allocation lifetime where + // calling a free function is not required + static BlobPtr CreateReferenced(void *ptr, unsigned len); + static BlobPtr CreateReferenced(struct iovec *iov, unsigned iov_len); + ~Blob(); + + BlobPtr Copy() const; + + void *GetPtr(unsigned i) { return iov[i].iov_base; } + const void *GetPtr(unsigned i) const { return iov[i].iov_base; } + unsigned GetLength(unsigned i) const { return iov[i].iov_len; } + struct iovec *GetIOVec() { return &iov[0]; } + const struct iovec *GetIOVec() const { return &iov[0]; } + unsigned GetNumBuffers() const { return iov.size(); } + unsigned GetTotalLength() const; + + int Compare(ConstBlobPtr other) const; + + private: + Blob(); + Blob(const Blob&); + Blob(struct iovec *v, unsigned l, BlobFreeFunc f, void *c); + Blob operator=(const Blob&); + + std::vector iov; + BlobFreeFunc free_func; + void *ctx; + }; + +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/Config.h b/src/hos_libvariant/include/hos_libvariant/Config.h new file mode 100644 index 00000000..32f40d22 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/Config.h @@ -0,0 +1,13 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_CONFIG_H +#define VARIANT_CONFIG_H +#pragma once + +/* #undef HAVE_CXX11_SHAREDPTR */ +#define HAVE_TR1_SHAREDPTR 1 +/* #undef USE_BOOST_SHAREDPTR */ + +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/Emitter.h b/src/hos_libvariant/include/hos_libvariant/Emitter.h new file mode 100644 index 00000000..1b113470 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/Emitter.h @@ -0,0 +1,226 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_EMITTER_H +#define VARIANT_EMITTER_H + +#pragma once +#include +#include +#include +#include +#include "../../../src/include/Variant/Variant.h" +#include "../../../src/include/Variant/Blob.h" +#include "../../../src/include/Variant/EmitterOutput.h" +#include +#include + +namespace libvariant { + + /** + * Class to override to implement an Emitter + */ + class EmitterImpl { + public: + virtual ~EmitterImpl(); + + virtual void BeginDocument() = 0; + virtual void EndDocument() = 0; + virtual void BeginMap(int length) = 0; + virtual void EndMap() = 0; + virtual void BeginList(int length) = 0; + virtual void EndList() = 0; + + virtual void EmitNull() = 0; + virtual void EmitTrue() = 0; + virtual void EmitFalse() = 0; + virtual void Emit(const char *v) = 0; + virtual void Emit(intmax_t v) = 0; + virtual void Emit(uintmax_t v) = 0; + virtual void Emit(double v) = 0; + virtual void Emit(ConstBlobPtr b) = 0; + + virtual void Flush() = 0; + virtual void Close() = 0; + + virtual Variant GetParam(const std::string &key) = 0; + virtual Variant GetParams() = 0; + virtual void SetParam(const std::string &key, Variant value) = 0; + virtual void SetParams(Variant params); + }; + + /** + * Actual emitter class. + */ + class Emitter { + public: + Emitter(); + Emitter(shared_ptr i); + ~Emitter(); + + Emitter &BeginDocument(); + Emitter &EndDocument(); + + //Some emitter implementations require the length of the map at the + //beginning. Such implementations should buffer events if length == -1 + //Implementations are free to ignore the length. + Emitter &BeginMap() { return BeginMap(-1); } + Emitter &BeginMap(int length); + Emitter &EndMap(); + //Some emitter implementations require the length of the list at the + //beginning. Such implementations should buffer events if length == -1 + Emitter &BeginList() { return BeginList(-1); } + Emitter &BeginList(int length); + Emitter &EndList(); + + Emitter &EmitNull(); + Emitter &EmitTrue(); + Emitter &EmitFalse(); + Emitter &Emit(bool v) { return (v ? EmitTrue() : EmitFalse()); } + Emitter &Emit(const std::string &v); + Emitter &Emit(const char *v); + Emitter &Emit(intmax_t v); + Emitter &Emit(uintmax_t v); + Emitter &Emit(double v); + Emitter &Emit(ConstBlobPtr b); + + void Flush(); + void Close(); + + /// Get the value of parameters of the parser (e.g. pretty printing, + // styles, etc.) + // See individual emitter below for supported values. + Variant GetParam(const std::string &key); + /// Get a dict of all parameters + Variant GetParams(); + /// Set the value of parameters. + // See individual emitter below for supported values. + void SetParam(const std::string &key, Variant value); + /// Set all parameters from a dict + void SetParams(Variant params); + /// Internal/advanced function to get the underlying implementation + shared_ptr GetImpl() { return impl; } + private: + shared_ptr impl; + }; + + template + inline Emitter &operator<<(Emitter &e, const std::vector &v) { + e.BeginList(v.size()); + for (typename std::vector::const_iterator i(v.begin()), end(v.end()); i!=end; i++) { + e << *i; + } + e.EndList(); + return e; + } + + template + inline Emitter &operator<<(Emitter &e, const std::map &v) { + e.BeginMap(v.size()); + for (typename std::map::const_iterator i(v.begin()), end(v.end()); i!=end; ++i) { + e.Emit(i->first); + e << i->second; + } + e.EndMap(); + return e; + } + inline Emitter &operator<<(Emitter &e, bool v) { e.Emit(v); return e; } + inline Emitter &operator<<(Emitter &e, char v) { e.Emit(intmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, short v) { e.Emit(intmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, int v) { e.Emit(intmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, long v) { e.Emit(intmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, long long v) { e.Emit(intmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, unsigned char v) { e.Emit(uintmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, unsigned short v) { e.Emit(uintmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, unsigned int v) { e.Emit(uintmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, unsigned long v) { e.Emit(uintmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, unsigned long long v) { e.Emit(uintmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, const char *v) { e.Emit(v); return e; } + inline Emitter &operator<<(Emitter &e, const std::string &v) { e.Emit(v); return e; } + inline Emitter &operator<<(Emitter &e, float v) { e.Emit(double(v)); return e; } + inline Emitter &operator<<(Emitter &e, double v) { e.Emit(v); return e; } + inline Emitter &operator<<(Emitter &e, ConstBlobPtr v) { e.Emit(v); return e; } + + shared_ptr CreateEmitterOutput(void *ptr, unsigned len, unsigned *out_len=0); + shared_ptr CreateEmitterOutput(const char *filename); + shared_ptr CreateEmitterOutput(FILE *f); + shared_ptr CreateEmitterOutput(std::streambuf *sb); + + /** + * Create an Emiter that Emits the format specified by type. + * Supported parameters are dependent on type (see below). + */ + Emitter CreateEmitter(shared_ptr o, SerializeType type, Variant params = Variant::NullType); + + /** + * Create an Emitter that Emits the JSON format. + * + * Supported parameters are: + * "pretty": boolean + * "indent": integer (number of spaces to indent when pretty is on, + * default 4) + * "precision": integer (number of digits for floats) + * "strict": be more strict about emitting correct json + */ + Emitter JSONEmitter(shared_ptr o, Variant params = Variant::NullType); + + /** + * Supported parameters are (first is default): + * + * "scalar_style": "any"|"plain"|"single quoted"|"double + * quoted"|"literal"|"folded" + * + * "map_style": "any"|"block"|"flow" + * + * "list_style": "any"|"block"|"flow" + * + * "implicit_document_begin": false|true + * + * "implicit_document_end": false|true + * + * "indent": integer (number of spaces to indent) + * + * "width": integer (set prefered line width) + * + * "precision": integer (number of digits for floats) + */ + Emitter YAMLEmitter(shared_ptr o, Variant params = Variant::NullType); + + /** + * Supported params are: + * + * "pretty": true|false + * "indent": integer (amount to indent for pretty) + * "precision": integer (number of digits for floats) + */ + Emitter XMLPLISTEmitter(shared_ptr o, Variant params = Variant::NullType); + /** + * Supported params are: + * + * "precision": integer (number of digits for floats) + */ + Emitter BundleHdrEmitter(shared_ptr o, Variant params = Variant::NullType); + + /** + * No parameters supported. + */ + Emitter MsgPackEmitter(shared_ptr o, Variant params = Variant::NullType); +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/EmitterOutput.h b/src/hos_libvariant/include/hos_libvariant/EmitterOutput.h new file mode 100644 index 00000000..ffc5b1e8 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/EmitterOutput.h @@ -0,0 +1,87 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + * + * The end user should not need to look at this file unless they are + * creating custom outputs for the emitters. + */ +#ifndef VARIANT_EMITTEROUTPUT_H +#define VARIANT_EMITTEROUTPUT_H +#pragma once +#include +#include + +namespace libvariant { + + class EmitterOutput { + public: + virtual ~EmitterOutput(); + /// Return the number of bytes written, or throw an exception + virtual unsigned Write(const void *ptr, unsigned len) = 0; + virtual void Flush() {} + virtual unsigned NumBytesWritten() const = 0; + }; + + class EmitterFileOutput : public EmitterOutput { + public: + EmitterFileOutput(FILE *f, bool c); + ~EmitterFileOutput(); + virtual unsigned Write(const void *ptr, unsigned len); + virtual void Flush(); + virtual unsigned NumBytesWritten() const { return num_bytes; } + protected: + FILE *file; + unsigned num_bytes; + bool cls; + }; + + class EmitterFilenameOutput : public EmitterFileOutput { + public: + EmitterFilenameOutput(const char *filename, const char *mode="w"); + }; + + class EmitterStreambufOutput : public EmitterOutput { + public: + EmitterStreambufOutput(std::streambuf *sb, bool d); + ~EmitterStreambufOutput(); + virtual unsigned Write(const void *ptr, unsigned len); + virtual void Flush(); + virtual unsigned NumBytesWritten() const { return num_bytes; } + protected: + std::streambuf *streambuf; + unsigned num_bytes; + bool del; + }; + + class EmitterMemoryOutput : public EmitterOutput { + public: + EmitterMemoryOutput(void *ptr, unsigned len, unsigned *out_len = 0); + + virtual unsigned Write(const void *ptr, unsigned len); + + virtual unsigned NumBytesWritten() const { return *out_length; } + protected: + void *data_ptr; + unsigned length; + unsigned out_length_dummy; + unsigned *out_length; + }; + +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/Exceptions.h b/src/hos_libvariant/include/hos_libvariant/Exceptions.h new file mode 100644 index 00000000..20c33383 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/Exceptions.h @@ -0,0 +1,88 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_EXCEPTIONS_H +#define VARIANT_EXCEPTIONS_H +#include +#include +#include + +#include "../../../src/include/Variant/VariantDefines.h" +namespace libvariant { + + /// \brief Exception thrown when a key does not exist. + class KeyError : public std::runtime_error { + public: + KeyError(const std::string &key) throw(); + }; + + /// \brief Exception thrown when internal state is corrupt. + class UnknownTypeError : public std::runtime_error { + public: + UnknownTypeError(VariantDefines::Type_t type) throw(); + }; + + /// \brief Exception thrown when a function expects a specific type but the action type conflicts. + class UnexpectedTypeError : public std::runtime_error { + public: + UnexpectedTypeError(VariantDefines::Type_t expected, VariantDefines::Type_t value) throw(); + UnexpectedTypeError(const std::vector &expected, VariantDefines::Type_t value) throw(); + }; + + /// \brief Exception thrown when a function cannot convert the Variant to an acceptable type for the routine. + class UnableToConvertError : public std::runtime_error { + public: + UnableToConvertError(VariantDefines::Type_t sourcetype, const std::string &targettype) throw(); + }; + + /// \brief Exception thrown when trying to index a type other than map or list. + class TypeNotIndexableError : public std::runtime_error { + public: + TypeNotIndexableError(VariantDefines::Type_t type) throw(); + }; + + /// \brief Exception thrown when attempting a numeric operation on a non numeric type. + class NotNumericTypeError : public std::runtime_error { + public: + NotNumericTypeError(VariantDefines::Type_t type) throw(); + }; + + /// \brief Exception thrown from path functions + class BadPathError : public std::runtime_error { + public: + BadPathError(VariantDefines::Type_t type) throw(); + BadPathError(const std::string &msg) throw(); + }; + + class InvalidReferenceError : public std::runtime_error { + public: + InvalidReferenceError(const std::string &msg) throw(); + }; + + class InvalidOperationError : public std::runtime_error { + public: + InvalidOperationError(VariantDefines::Type_t type, const std::string &opname) throw(); + }; + + std::ostream &operator <<(std::ostream &os, VariantDefines::Type_t type); + + void AddStackTrace(std::ostream &os, int level); +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/Extensions.h b/src/hos_libvariant/include/hos_libvariant/Extensions.h new file mode 100644 index 00000000..a3f615bc --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/Extensions.h @@ -0,0 +1,92 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author Josh Staley + * \brief Useful extension functions for Variant + */ + +#ifndef VARIANT_EXTENSIONS_H +#define VARIANT_EXTENSIONS_H + +#include "../../../src/include/Variant/Variant.h" + +namespace libvariant { + + /// \brief Returns a default parameters for use with FlattenPath and ExpandPath functions. + Variant ExtensionParams(); + + /// \brief Sets any missing Extension parameters to 'params' for use with FlattenPath and ExpandPath functions. + void ExtensionParams( VariantRef params ); + + /// \brief Returns a version of 'var' with flat paths based on 'params' + Variant FlattenPath( const Variant &var, Variant params = ExtensionParams() ); + + /// \brief Returns a version of 'var' with expanded paths based on 'params' + Variant ExpandPath( const Variant &var, Variant params = ExtensionParams() ); + + /// \brief Flattens 'var' paths to 'flat' based on 'params' + void FlattenPathTo( VariantRef flat, const Variant &var, Variant params = ExtensionParams(), std::string prefix = "" ); + + /// \brief Expands 'var' paths to 'expand' based on 'params' + void ExpandPathTo( VariantRef expand, const Variant &var, Variant params = ExtensionParams() ); + + /// \brief Returns a string string map representation of 'var' based on 'params' + std::map + FlattenPathToStrStrMap( const Variant &var, Variant params = ExtensionParams() ); + + /// \brief Returns a variant representing elements in 'compare' that differ from 'base' recursively + Variant RDiff( const Variant &base, const Variant &compare ); + + /// \brief Sets elements into 'diff' from 'compare' that differ from 'base' recursively + void RDiff( VariantRef diff, const Variant &base, const Variant &compare ); + + /// \brief Updates 'base' with entries in 'update' recursively + void RUpdate( VariantRef base, const Variant &update ); + + /// Perform an operations on v according to RFC6901 and RFC6902. + // Note that JSON Pointer is ambiguous without the presence of a document. + // These function throw if the lookup fails because of incorrect types or + // on ambiguity. + // On return (or throw) the operation will have either succedded or no + // change will have been made. + + /// Add data to v at the spot specified by pointer + void JSONPointerAdd(const std::string &pointer, VariantRef v, Variant data); + /// Remove the element in v at the spot specified by pointer + void JSONPointerRemove(const std::string &pointer, VariantRef v); + /// Replace the value at pointer with data, error if the location does not already exist + void JSONPointerReplace(const std::string &pointer, VariantRef v, Variant data); + /// Move the value from src to dst (equivalent to get(src), remove(src), add(dst) + void JSONPointerMove(const std::string &src, const std::string &dst, VariantRef v); + /// Copy the value from src to dst (equivalent to add(dst, get(src).Copy())) + void JSONPointerCopy(const std::string &src, const std::string &dst, VariantRef v); + /// Perform a lookup into v according to RFC6901, return a reference to the value at the location + VariantRef JSONPointerLookup(const std::string &pointer, VariantRef v); + + std::string FormJSONPointer(const Path &path); + + /// Perform a patch operation on v with the patch as described by diff according to RFC6902 + // Returns true if the patch is applied and all tests pass, + // false if any tests failed and no patch is applied + std::pair JSONPatch(VariantRef v, const Variant &diff); + + /// Create a diff suitable to give to JSONPatch to transform src into dst. + Variant JSONDiff(const Variant &src, const Variant &dst); + +} // namespace libvariant + +#endif /*#ifndef VARIANT_EXTENSIONS_H*/ diff --git a/src/hos_libvariant/include/hos_libvariant/GuessFormat.h b/src/hos_libvariant/include/hos_libvariant/GuessFormat.h new file mode 100644 index 00000000..9687d863 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/GuessFormat.h @@ -0,0 +1,23 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_GUESSFORMAT_H +#define VARIANT_GUESSFORMAT_H + +#pragma once +#include "../../../src/include/Variant/Variant.h" +#include "../../../src/include/Variant/Parser.h" +namespace libvariant { + + /// + // Try to guess the format of the input without removing any + // input from the input object. + // + // Currently only looks at the first non-whitespace character + // and if it is '<' then says XMLPLIST, otherwise says YAML + // if enabled otherwise JSON. + // + SerializeType GuessFormat(ParserInput* in); +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/Parser.h b/src/hos_libvariant/include/hos_libvariant/Parser.h new file mode 100644 index 00000000..b430d835 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/Parser.h @@ -0,0 +1,158 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_PARSER_H +#define VARIANT_PARSER_H + +#pragma once +#include +#include +#include "../../../src/include/Variant/Blob.h" +#include "../../../src/include/Variant/ParserInput.h" +#include "../../../src/include/Variant/Variant.h" +#include + +namespace libvariant { + + class ParserImpl; + + class ParserActions { + public: + virtual ~ParserActions(); + virtual void BeginDocument(ParserImpl *p) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void EndDocument(ParserImpl *p) + { throw std::runtime_error("Parser: Unexpected event"); } + // If length < 0, unknown length + virtual void BeginMap(ParserImpl *p, int length, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void EndMap(ParserImpl *p) + { throw std::runtime_error("Parser: Unexpected event"); } + // If length < 0, unknown length + virtual void BeginList(ParserImpl *p, int length, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void EndList(ParserImpl *p) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Alias(ParserImpl *p, const char *anchor) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, double v, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, const char *str, unsigned length, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, bool v, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Null(ParserImpl *p, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, intmax_t v, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, uintmax_t v, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, BlobPtr b, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + }; + + /// The class that parser implementations override + class ParserImpl { + public: + virtual ~ParserImpl(); + /** + * Attempt to parse some actions. + * At least one ParserActions should be on the action stack. + * + * Run is not guaranteed to be recursively callable from inside a + * ParserActions callback. Do not do that. + * + * return 0 on success + * return 1 when done + * return -1 if needing more data is detected (not all parsers support this; can be treated as an error) + * throw on error + */ + virtual int Run() = 0; + + /** + * Push a new ParserActions handler onto the action handler stack. + */ + virtual void PushAction(shared_ptr action) { action_stack.push_back(action); } + + /** + * Pop the top ParserActions handler off the action handler stack and + * return it. + */ + virtual shared_ptr PopAction() { + if (action_stack.empty()) + { throw std::runtime_error("Parser: Attempting to parse an actions without any action handlers"); } + shared_ptr ret = action_stack.back(); + action_stack.pop_back(); + return ret; + } + + /** + * Access the top ParserActions + */ + ParserActions *TopAction() { + if (action_stack.empty()) + { throw std::runtime_error("Parser: Attempting to parse an actions without any action handlers"); } + return action_stack.back().get(); + } + + /** These three functiosn can be used to query the state + * later. + * Done means that a call to Process will immediately return 1 + * Error if Process threw an exception last + * Ok if everything looks good (Process never been called, or last return 0 or possibly -1) + */ + virtual bool Done() const = 0; + virtual bool Error() const = 0; + virtual bool Ok() const = 0; + /// Return a string describing the last error suitable for presentation to a user + virtual std::string ErrorStr() const = 0; + /// Reset the parser + virtual void Reset() = 0; + protected: + std::deque< shared_ptr< ParserActions > > action_stack; + }; + + class Parser { + public: + Parser(); + Parser(shared_ptr pi); + ~Parser(); + /// 0 on success, 1 when done, -1 other problem, throw on error + int Run() { return impl->Run(); } + /// Push an action handler onto the action stack. + void PushAction(shared_ptr action) { impl->PushAction(action); } + /// Pop the top action handler off the stack. + shared_ptr PopAction() { return impl->PopAction(); } + + /// Query state + bool Done() const { return impl->Done(); } + bool Error() const { return impl->Error(); } + bool Ok() const { return impl->Ok(); } + /// Return a string describing the last error suitable for presentation to a user + std::string ErrorStr() const { return impl->ErrorStr(); } + /// Reset the parser if applicable (some types will throw) + void Reset() { impl->Reset(); } + + /// Internal/advanced function to get the underlying implementation + shared_ptr GetImpl() { return impl; } + private: + shared_ptr impl; + }; + + shared_ptr CreateParserInput(const std::string &str); + shared_ptr CreateParserInput(const char *str); + shared_ptr CreateParserInput(const void *ptr, unsigned len); + shared_ptr CreateParserInputFile(const char *filename); + shared_ptr CreateParserInputFile(FILE *f); + shared_ptr CreateParserInputFile(std::streambuf *sb); + + Parser CreateParser(shared_ptr i, SerializeType type); + Parser CreateParserGuess(shared_ptr i); + Parser JSONParser(shared_ptr i); + Parser YAMLParser(shared_ptr i); + Parser XMLPLISTParser(shared_ptr i); + Parser BundleHdrParser(shared_ptr i); + Parser MsgPackParser(shared_ptr i); +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/ParserInput.h b/src/hos_libvariant/include/hos_libvariant/ParserInput.h new file mode 100644 index 00000000..5fa66311 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/ParserInput.h @@ -0,0 +1,104 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_PARSERINPUT_H +#define VARIANT_PARSERINPUT_H +#pragma once +#include +#include +#include +#include + +namespace libvariant { + + class ParserInput { + public: + virtual ~ParserInput(); + // Get a pointer and length to the unprocessed data that is available + // (return null on end of data) len being an in/out parameter, + // the initial value of len is how much the parser wants. An input value of zero + // in means give whatever is currently available. + virtual const void *GetPtr(unsigned &len) = 0; + + // Tell the input that the parser is done with len bytes from the last + // GetPtr + virtual void Release(unsigned len) = 0; + }; + + class ParserStreamInput : public ParserInput { + public: + ParserStreamInput(unsigned buffer_len); + virtual const void *GetPtr(unsigned &len); + virtual void Release(unsigned len); + /// return number of bytes read into ptr, 0 on EOF + // and throw on error + virtual unsigned Read(void *ptr, unsigned len) = 0; + protected: + std::vector buffer; + unsigned num; + unsigned offset; + bool eof; + }; + + class ParserMemoryInput : public ParserInput { + public: + ParserMemoryInput(const void *ptr, unsigned len); + virtual const void *GetPtr(unsigned &len); + virtual void Release(unsigned len); + protected: + const void *data_ptr; + unsigned data_len; + unsigned offset; + }; + + class ParserStringInput : public ParserInput { + public: + ParserStringInput(const std::string &str); + virtual const void *GetPtr(unsigned &len); + virtual void Release(unsigned len); + protected: + const std::string val; + unsigned offset; + }; + + class ParserFileInput : public ParserStreamInput { + public: + ParserFileInput(FILE *f); + virtual unsigned Read(void *ptr, unsigned len); + protected: + FILE *file; + }; + + class ParserFilenameInput : public ParserFileInput { + public: + ParserFilenameInput(const char *filename, const char *mode = "r"); + ~ParserFilenameInput(); + }; + + class ParserStreambufInput : public ParserStreamInput { + public: + ParserStreambufInput(std::streambuf *sb); + unsigned Read(void *ptr, unsigned len); + protected: + std::streambuf *streambuf; + }; + +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/Path.h b/src/hos_libvariant/include/hos_libvariant/Path.h new file mode 100644 index 00000000..53426fd3 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/Path.h @@ -0,0 +1,100 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_PATH_H +#define VARIANT_PATH_H + +#pragma once +#include +#include +#include "../../../src/include/Variant/Exceptions.h" +namespace libvariant { + + // A simple xpath like path functionality for Variant + // + // Map keys are specified using a "/" then the key. + // List indeces are specified using [index] + // A "/" at the end of the path is ignored. + // Characters "\/[]" must all be escaped with "\" + // + // For example: + // { + // "key1": [ 1, 2, 3, { "blork": true } ], + // "key2": { + // "subkey": [ "a", { "furple": 1 }, 2 ], + // "sub/key2": true + // } + // } + // + // Then all paths enumerated are: + // Path Value + // "/" Identity + // "/key1" [ 1, 2, 3, { "blork": true } ], + // "/key1[0]" 1 + // "/key1[1]" 2 + // "/key1[2]" 3 + // "/key1[3]" { "blork": true } + // "/key1[3]/blork" true + // "/key2" { "subkey": [ "a", { "furple": 1 }, 2 ], "sub/key2": true } + // "/key2/subkey" [ "a", { "furple": 1 }, 2 ] + // "/key2/subkey[0]" "a" + // "/key2/subkey[1]" { "furple": 1 } + // "/key2/subkey[1]/furple" 1 + // "/key2/subkey[2]" 2 + // "/key2/sub\/key2" true + // + // For all these functions PathList must act like a vector + // It may be of some other type (like deque) + + class PathElement { + public: + enum Type_t { INDEX, KEY }; + PathElement(const std::string &k) : type(KEY), key(k) {} + PathElement(const char *k) : type(KEY), key(k) {} + PathElement(unsigned i) : type(INDEX), index(i) {} + + bool IsNumber() const { return type == INDEX; } + unsigned AsUnsigned() const { + if (type != INDEX) throw BadPathError("Variant path element is not a number"); + return index; + } + bool IsString() const { return type == KEY; } + const std::string &AsString() const { + if (type != KEY) throw BadPathError("Variant path element is not a key"); + return key; + } + private: + Type_t type; + unsigned index; + std::string key; + }; + + typedef std::deque Path; + + //! + // Parse the path string into path tokens. + void ParsePath(Path &parsed_path, const std::string &path); + Path ParsePath(const std::string &path); + + //! Take the set of path tokens and turn it into a path string + std::string PathString(const Path &path); + +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/Payload.h b/src/hos_libvariant/include/hos_libvariant/Payload.h new file mode 100644 index 00000000..6b3a11cd --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/Payload.h @@ -0,0 +1,130 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_PAYLOAD_H +#define VARIANT_PAYLOAD_H + +#pragma once +#include "../hos_libvariant/Variant.h" +#include "../hos_libvariant/Emitter.h" +#include "../hos_libvariant/Parser.h" +namespace libvariant { + + // Serialize and Deserialize a header, null byte, and a binary payload + // + // All restrictions of the given serialization format are required. + // + // Parameters for payload data location: + // "length_path": path to where the payload length should be + // placed for serialization and where the payload length should be read + // from for deserialization + // Defaults to: +#define VARIANT_PAYLOAD_LENGTH_PATH "payload/length" +#define VARIANT_BUNDLE_PAYLOAD_LENGTH_PATH "payload.length" + // "data_path": path to where the payload is located for + // serialization and path to store payload for deserialization + // Defaults to: +#define VARIANT_PAYLOAD_DATA_PATH "payload/data" +#define VARIANT_BUNDLE_PAYLOAD_DATA_PATH "payload.data" + // The defaults are the values for compatibility with the bundle format. + // + // Serialize only parameters: + // "ignore_payload": true|false (default false) + // Don't output the payload, only the header, alignment and null byte. + // If the payload exists in the Variant, use the length for the payload length + // value, if not look in parameters for the payload length value, if not there + // look in the Variant for the payload length. + // "payload_length": num + // Payload length override, put this number in as the payload length + // regardless of what size the blob is. + // Note that unless ingnore_payload is true, the emitter will try to output the whole + // payload (and no more) regardless of what this number is. + + void SerializeWithPayload(shared_ptr out, Variant v, SerializeType type, + Variant params = Variant::NullType); + Variant DeserializeWithPayload(shared_ptr in, SerializeType type, + Variant params = Variant::NullType, bool be_safe=true); + + std::string SerializeWithPayload(Variant v, SerializeType type, Variant params = Variant::NullType); + void SerializeWithPayload(const std::string &filename, Variant v, SerializeType type, + Variant params = Variant::NullType); + void SerializeWithPayload(FILE *f, Variant v, SerializeType type, + Variant params = Variant::NullType); + void SerializeWithPayload(std::streambuf *sb, Variant v, SerializeType type, + Variant params = Variant::NullType); + unsigned SerializeWithPayload(void *ptr, unsigned len, Variant v, SerializeType type, + Variant params = Variant::NullType); + + Variant DeserializeWithPayload(const std::string &str, SerializeType type, + Variant params = Variant::NullType); + /// If the be_safe parameter is false, then it is considered OK + // to __/NOT/__ copy the payload and just reference it in the BlobPtr. + // This is only safe when you know your buffer is going to stick around + // until after your done with the resulting Variant. + // (This is to support zero copy) + // No null terminated string version provided as these formats contain nulls. + Variant DeserializeWithPayload(const void *ptr, unsigned len, SerializeType type, + Variant params = Variant::NullType, bool be_safe=true); + Variant DeserializeWithPayloadFile(const char *filename, SerializeType type, + Variant params = Variant::NullType); + Variant DeserializeWithPayloadFile(FILE *f, SerializeType type, + Variant params = Variant::NullType); + Variant DeserializeWithPayloadFile(std::streambuf *sb, SerializeType type, + Variant params = Variant::NullType); + + + /// Bundle is a simple format used internally at ARL for passing around + // a textual key value map plus a binary payload. The payload is often a very large + // array of numbers that would produce unacceptable overhead to serialize into text. + // These serialize routines assume that the passed in Variant is of MapType + // and if a key named "payload.data" exists it is to be written as the payload + // of the Bundle. + // + // If a key "payload.data" does not exist, these are almost the same as using the BundleHdrEmitter + // except it adds a null byte at the end. + inline std::string SerializeBundle(Variant v) + { return SerializeWithPayload(v, SERIALIZE_BUNDLEHDR); } + inline void SerializeBundle(const std::string &filename, Variant v) + { SerializeWithPayload(filename, v, SERIALIZE_BUNDLEHDR); } + inline void SerializeBundle(FILE *f, Variant v) + { SerializeWithPayload(f, v, SERIALIZE_BUNDLEHDR); } + inline void SerializeBundle(std::streambuf *sb, Variant v) + { SerializeWithPayload(sb, v, SERIALIZE_BUNDLEHDR); } + inline unsigned SerializeBundle(void *ptr, unsigned len, Variant v) + { return SerializeWithPayload(ptr, len, v, SERIALIZE_BUNDLEHDR); } + + inline Variant DeserializeBundle(const std::string &str) + { return DeserializeWithPayload(str, SERIALIZE_BUNDLEHDR); } + /// If the be_safe parameter is false, then it is considered OK + // to __/NOT/__ copy the payload and just reference it in the BlobPtr. + // This is only safe when you know your buffer is going to stick around + // until after your done with the resulting Variant. + // (This is to support zero copy) + // No null terminated string version provided as bundles contain nulls. + inline Variant DeserializeBundle(const void *ptr, unsigned len, bool be_safe=true) + { return DeserializeWithPayload(ptr, len, SERIALIZE_BUNDLEHDR, Variant::NullType, be_safe); } + inline Variant DeserializeBundleFile(const char *filename) + { return DeserializeWithPayloadFile(filename, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleFile(FILE *f) { return DeserializeWithPayloadFile(f, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleFile(std::streambuf *sb) + { return DeserializeWithPayloadFile(sb, SERIALIZE_BUNDLEHDR); } + +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/Schema.h b/src/hos_libvariant/include/hos_libvariant/Schema.h new file mode 100644 index 00000000..235627c2 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/Schema.h @@ -0,0 +1,175 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief A schema validator. + * + * This code is based on the public domain JSONv4 validator tv4. + * tv4 is available at http://geraintluff.github.com/tv4/ + */ +#ifndef VARIANT_SCHEMA_H +#define VARIANT_SCHEMA_H + +#pragma once +#include "../../../src/include/Variant/Variant.h" +#include +#include +#include +#include +namespace libvariant { + + class SchemaResult; + + class ValidationError { + public: + ValidationError(const std::string &m, const Path &dpath, + const Path &spath); + + void AddSubError(const SchemaResult &err); + + const std::string &GetMessage() const { return message; } + const Path &GetDataPath() const { return data_path; } + std::string GetDataPathStr() const; + const Path &GetSchemaPath() const { return schema_path; } + std::string GetSchemaPathStr() const; + const std::vector &GetSubErrors() const { return sub_errors; } + + std::string PrettyPrintMessage() const; + void PrettyPrintMessage(std::ostream &os, unsigned indent=0) const; + private: + std::string message; + Path data_path; + Path schema_path; + std::vector sub_errors; + }; + + class SchemaError { + public: + SchemaError(const std::string &m, const Path &spath); + + const std::string &GetMessage() const { return message; } + const Path &GetSchemaPath() const { return schema_path; } + std::string GetSchemaPathStr() const; + + std::string PrettyPrintMessage() const; + void PrettyPrintMessage(std::ostream &os, unsigned indent=0) const; + private: + std::string message; + Path schema_path; + }; + + class SchemaResult { + public: + SchemaResult(); + + void AddError(const ValidationError &err); + void AddSchemaError(const SchemaError &err); + + bool Error() const { return !errors.empty() || !schema_errors.empty(); } + bool ValidationErrors() const { return !errors.empty(); } + bool SchemaErrors() const { return !schema_errors.empty(); } + + const std::vector &GetErrors() const { return errors; } + const std::vector &GetSchemaErrors() const { return schema_errors; } + + std::string PrettyPrintMessage() const; + void PrettyPrintMessage(std::ostream &os, unsigned indent=0) const; + private: + std::vector errors; + std::vector schema_errors; + }; + + inline std::ostream &operator<<(std::ostream &os, const SchemaResult &sr) { + sr.PrettyPrintMessage(os); + return os; + } + + class SchemaLoader { + public: + class LoaderError { + public: + LoaderError(); + ~LoaderError(); + void AddError(const std::string &uri, const std::string &msg); + std::string GetErrorMessage() const { return erross.str(); } + private: + std::ostringstream erross; + }; + + typedef bool (*MissingHandlerType)(SchemaLoader*,const std::string&,LoaderError &,void*); + SchemaLoader(); + SchemaLoader(SchemaLoader *b); + virtual ~SchemaLoader(); + // Get the schema at the uri specified. + // Internal lookup first, then call HandleMissing if the uri is not internally available. + // If the schema then is still not available return Variant::NullType. + virtual Variant GetSchema(const std::string &uri); + // Add a schema to the loader at the uri specified. + // returns the schema(s) added with the corresponding uri(s) + virtual std::map AddSchema(const std::string &uri, Variant schema); + // Forget a schema with the specified uri. + virtual void ForgetSchema(const std::string &uri); + // Called when a schema is not in the loader. + // Default implementation is to call the missing handler + // or add a not found error to the LoaderError and return false + // Return true on success, otherwise false, any errors are filled into the LoaderError + virtual bool HandleMissing(const std::string &uri, LoaderError &error); + void SetMissingHandler(MissingHandlerType, void *ctx); + + static void NormSchema(Variant &schema, const std::string &uri); + //! + // A realpath function for schema URIs. + // href is the "current working directory" and base is + // possibly a relative path. + static std::string ResolveURI(const std::string &base, const std::string &href); + + struct URIInfo { + std::string href; // EX: the whole uri if matched + std::string protocol; // EX: http:// + std::string authority; // user:host@hostname:port + std::string pathname; // The path segment + std::string search; // ?q=234 + std::string hash; // #tag + }; + + //! Break a uri into its components and store them into the URIInfo struct + //! returns true if the parsing was successful + static bool ParseURI(URIInfo &info, const std::string &uri); + protected: + + static void SearchForTrustedSchemas(std::map &m, Variant schema, const std::string &uri); + MissingHandlerType missingHandler; + void *missingctx; + std::map schemas; + SchemaLoader *base; + }; + + //! Validate data against a schema. + //! + //! The schema parameter is either a schema, a string uri to a schema, or null. + //! If it is a schema then data is validated against it. + //! If it is a string then it calls loader->GetSchema() and validates data against the result. + //! If schema is null, then look for a key "$schema" in data, set schema to it and proceed as above. + SchemaResult SchemaValidate(Variant schema, Variant data, SchemaLoader *loader=0); + + //! Add the defaults specified in schema to data if they do not exist. + //! Ignores default in some combinations and types that could match multiple entries (not, + //! additionalProperties, patternProperties, etc.) + //! schema is processed the same as for SchemaValidate + void AddSchemaDefaults(Variant schema, VariantRef data, SchemaLoader *loader=0); +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/SchemaLoader.h b/src/hos_libvariant/include/hos_libvariant/SchemaLoader.h new file mode 100644 index 00000000..e4edd00b --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/SchemaLoader.h @@ -0,0 +1,54 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief An advanced schema loader. + */ +#ifndef VARIANT_SCHEMALOADER_H +#define VARIANT_SCHEMALOADER_H + +#pragma once + +#include "../../../src/include/Variant/Schema.h" + +namespace libvariant { + + //! The advanced schema loader will try to load missing schemas from + //! the file system and optionally curl if built. + //! If the url begins with file:// it will always use LoadFromFile + //! otherwise if the protocol is empty it will try loading from a file + //! then try loading from curl. Otherwise if the protocol is not file:// + //! it will try to load from curl. + class AdvSchemaLoader : public SchemaLoader { + public: + + //! The advanced schema loader will search for a schema in the paths + //! added to it on the file system. If the schema uri looks like a + //! relative path, then it will be searched for in the paths set with + //! this function. If no paths are added, then only absolute paths will + //! be looked up in the file system. + // + void AddPath(const std::string &path); + + virtual bool HandleMissing(const std::string &uri, LoaderError &error); + protected: + bool LoadFromFile(URIInfo &info, LoaderError &error); + bool LoadFromCurl(URIInfo &info, LoaderError &error); + std::vector< std::string > paths; + }; +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/SharedPtr.h b/src/hos_libvariant/include/hos_libvariant/SharedPtr.h new file mode 100644 index 00000000..fd4cef91 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/SharedPtr.h @@ -0,0 +1,41 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_SHAREDPTR_H +#define VARIANT_SHAREDPTR_H + +#pragma once +#include "../hos_libvariant/Config.h" + +#if defined(__GXX_EXPERIMENTAL_CXX0X) || __cplusplus >= 201103L || defined(HAVE_CXX11_SHAREDPTR) +// The C++11 implementation is available +#include +namespace libvariant { + using std::shared_ptr; + using std::dynamic_pointer_cast; +} + +#elif defined(HAVE_TR1_SHAREDPTR) +// Use the tr1 implementation +#include +namespace libvariant { + using std::tr1::shared_ptr; + using std::tr1::dynamic_pointer_cast; +} + +#elif defined(USE_BOOST_SHAREDPTR) +// Use the boost implementation +#include +namespace libvariant { + using boost::shared_ptr; + using boost::dynamic_pointer_cast; +} + +#else + +#error libvariant requires a shared_ptr implementation + +#endif + +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/Variant.h b/src/hos_libvariant/include/hos_libvariant/Variant.h new file mode 100644 index 00000000..3b0173e6 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/Variant.h @@ -0,0 +1,816 @@ +// vim: foldmethod=marker +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= + +/** \file + * + * \brief Main implementation file for Variant and related functions + */ + + +#ifndef VARIANT_VARIANT_H +#define VARIANT_VARIANT_H + +#pragma once +#include "../../../src/include/Variant/Blob.h" +#include "../../../src/include/Variant/SharedPtr.h" +#include "../../../src/include/Variant/Exceptions.h" +#include "../../../src/include/Variant/VariantInternal.h" +#include +#include +#include +#include +#include +#include +#include + +namespace libvariant { + + /** \brief The Variant class. + * This is a variant type inspired by types from several different + * scripting languages. + * + * \author John Bridgman + * + * This class gives the power and convenience of a scripting language variable + * to C++ with all the same /downsides/ that such a variable has as well. The + * main idea is that things should be simple, lists are behind the scenes an + * std::vector and maps are an std::map. + * + * A Variant may be null, a number, a string, a boolean, a reference to a list, + * or a reference to a map. This means that const Variant of a map is not a + * const map but a const reference. Lists and maps are reference counted. If + * one wants to copy use the Copy member function. + * + * If you need a reference to a Variant to assign to it or change its type, + * use VariantRef. + * A const Variant & should be used for an immutable reference. + * E.g., void foo(VariantRef inout_param, const Variant &in_param); + * That is to say, if you think you want Variant &, you don't, you want + * VariantRef. + * The library is written so that: + * Variant v; + * void bar(Variant &); + * bar(v["foo"]); + * is a compile error. + * But + * Variant v; + * void moo(const Variant &); + * moo(v["moo"]); + * is correct. + * + * + * Note that this implementation will let you create a back reference (i.e., a + * map with itself as a member) but unless the user explicitly breaks it, it + * will result in a memory leak. Checking for this case was deemed too + * expensive. + * + * A Variant will only change its own type if the type is null. That is to say + * that a null Variant that gets treated as a map will become a map. But, a + * Variant of any other type will never automatically convert. + * + */ + class Variant : protected Internal::Data, public VariantDefines { + public: + + typedef VariantRefImpl VariantRef; + + typedef std::vector List; + typedef std::map Map; + + typedef Map::iterator MapIterator; + typedef Map::const_iterator ConstMapIterator; + typedef List::iterator ListIterator; + typedef List::const_iterator ConstListIterator; + + Variant() {} + Variant(VariantDefines::Type_t type) { Assign(type); } + Variant(bool v) { Assign(v); } + + Variant(int v) { Assign(v); } + Variant(unsigned v) { Assign(v); } + Variant(long v) { Assign(v); } + Variant(unsigned long v) { Assign(v); } + Variant(long long v) { Assign(v); } + Variant(unsigned long long v) { Assign(v); } + Variant(double v) { Assign(v); } + Variant(long double v) { Assign(v); } + + Variant(BlobPtr b) { Assign(b); } + + Variant(const std::string &v) { Assign(v); } + Variant(const char *v) { Assign(v); } + Variant(const Variant &v) { Assign(v); } + Variant(const VariantRefImpl &v) { Assign(v); } + + /// Construct a list from a std::vector. + template + Variant(const std::vector &v) { Assign(v); } + + /// Construct a map from a std::map. + template + Variant(const std::map &v) { Assign(v); } + + ~Variant(); + + Variant &operator=(const Variant &o) { Assign(o); return *this; } + + Variant &operator=(VariantDefines::Type_t v) { Assign(v); return *this; } + Variant &operator=(bool v) { Assign(v); return *this; } + Variant &operator=(int v) { Assign(v); return *this; } + Variant &operator=(unsigned v) { Assign(v); return *this; } + Variant &operator=(long v) { Assign(v); return *this; } + Variant &operator=(unsigned long v) { Assign(v); return *this; } + Variant &operator=(long long v) { Assign(v); return *this; } + Variant &operator=(unsigned long long v) { Assign(v); return *this; } + Variant &operator=(double v) { Assign(v); return *this; } + Variant &operator=(long double v) { Assign(v); return *this; } + Variant &operator=(BlobPtr v) { Assign(v); return *this; } + Variant &operator=(const std::string & v) { Assign(v); return *this; } + Variant &operator=(const char * v) { Assign(v); return *this; } + + template + Variant &operator=(const std::vector &v) { Assign(v); return *this; } + template + Variant &operator=(const std::map &v) { Assign(v); return *this; } + + // Type query functions + + Type_t GetType() const; ///< Return the type of this Variant + + bool IsNull() const { return NullType == GetType(); } + bool IsBool() const { return BoolType == GetType(); } + bool IsTrue() const { return (BoolType == GetType()) && AsBool(); } + bool IsFalse() const { return (BoolType == GetType()) && !AsBool(); } + bool IsNumber() const + { return IntegerType == GetType() || UnsignedType == GetType() || FloatType == GetType(); } + bool IsInt() const { return IntegerType == GetType(); } + bool IsUnsigned() const { return UnsignedType == GetType(); } + bool IsFloat() const { return FloatType == GetType(); } + bool IsString() const { return StringType == GetType(); } + bool IsList() const { return ListType == GetType(); } + bool IsMap() const { return MapType == GetType(); } + bool IsBlob() const { return BlobType == GetType(); } + + + // Accessor functions + + bool AsBool() const; ///< Return the value as a bool + long double AsLongDouble() const; ///< Return the value as a long double + double AsDouble() const { return (double)AsLongDouble(); } + uintmax_t AsUnsigned() const; ///< Return the value as an unsigned + intmax_t AsInt() const; ///< Return the value as an integer + template + T AsNumber() const { return static_cast(AsLongDouble()); } + std::string AsString() const; ///< Return the value as a string + BlobPtr AsBlob(); + ConstBlobPtr AsBlob() const; + + template + T As() const; + + /// \brief If the type is string, list, map or blob returns its size, + /// otherwise throws an exception + unsigned Size() const; + + /// \brief If the type is string, list or map return if size == 0 otherwise + /// throw an exception + bool Empty() const; + + /// \brief If the type is string, list or map, empty the container otherwise + /// set type to NullType + void Clear(); + + // List specific accessors + List &AsList(); + const List &AsList() const; + ListIterator ListBegin() ///< Equivalent to AsList().begin() + { return AsList().begin(); } + ConstListIterator ListBegin() const ///< Equivalent to AsList().begin() + { return AsList().begin(); } + ListIterator ListEnd() ///< Equivalent to AsList().end() + { return AsList().end(); } + ConstListIterator ListEnd() const ///< Equivalent to AsList().end() + { return AsList().end(); } + VariantRef At(unsigned i); //< Return a proxy/reference to the element at index i + VariantRef At(unsigned i, Variant def); //< sets to def if doesn't exist + const Variant &At(unsigned i) const; + Variant Get(unsigned i) const; //< Return the element at index i or throw + Variant Get(unsigned i, Variant def) const; //< Return the element at index i or return def + Variant &Set(unsigned i, Variant v); //< Set the element at index i to v + /// \brief Only valid when of type ListType Returns *this, so you can + /// do Variant().Append(v1).Append(v2)... + Variant &Append(Variant value); + + /// \brief If list return true if list is at least i in size, if map then convert i + /// to a string, otherwise throw + bool Contains(unsigned i) const; + /// \brief Return the index hat v is at. + /// If v is not contained in the list it return this->Size() + unsigned Index(Variant v) const; + + /// \brief If list set index i to null, if index at end, reduce size by 1 + /// throw if not a list + void Erase(unsigned i); + + // Map specific accessors + Map &AsMap(); + const Map &AsMap() const; + MapIterator MapBegin() ///< Equivalent to AsMap().begin() + { return AsMap().begin(); } + ConstMapIterator MapBegin() const ///< Equivalent to AsMap().begin() + { return AsMap().begin(); } + MapIterator MapEnd() ///< Equivalent to AsMap().end() + { return AsMap().end(); } + ConstMapIterator MapEnd() const ///< Equivalent to AsMap().end() + { return AsMap().end(); } + VariantRef At(const std::string &s); // Return a proxy/reference to the element at key s + VariantRef At(const std::string &s, Variant def); //< Sets to def if doesn't exist and return a reference to it + const Variant &At(const std::string &s) const; + + /// \brief If s in *this: return this->At(s); else throw; + Variant Get(const std::string &s) const; + /// \brief If s in *this: return this->At(s); else return def + /// Only works if type is map + Variant Get(const std::string &s, Variant def) const; + + /// \brief Set the key s to v + // returns *this + Variant &Set(const std::string &s, Variant v); + + /// \brief If map return true if s is a key in the map, if list then convert + /// s to an unsigned and the above Contains, otherwise throw + bool Contains(const std::string &s) const; + /// \brief Erase a key in a map, throws if type is not MapType + void Erase(const std::string &key); + + VariantRef operator[](int i) { return At(i); } + const Variant &operator[](int i) const { return At(i); } + + VariantRef operator[](unsigned i) { return At(i); } + const Variant &operator[](unsigned i) const { return At(i); } + + VariantRef operator[](const std::string &s) { return At(s); } + const Variant &operator[](const std::string &s) const { return At(s); } + + // Path related accessors + // These are the same as the non-path functions but take a path instead. + VariantRef AtPath(const Path &path); + VariantRef AtPath(const std::string &path) { return AtPath(ParsePath(path)); } + VariantRef AtPath(const Path &path, Variant def); + VariantRef AtPath(const std::string &path, Variant def) { return AtPath(ParsePath(path), def); } + const Variant &AtPath(const Path &path) const; + const Variant &AtPath(const std::string &path) const { return AtPath(ParsePath(path)); } + + /// \brief Like Variant::Get but it takes a path instead. + Variant GetPath(const Path &path) const; + Variant GetPath(const std::string &path) const { return GetPath(ParsePath(path)); } + /// \brief Like Variant::Get but it takes a path instead. The path is + /// very like xpath, /key[index]/key/key. See Variant/Path.h + Variant GetPath(const Path &path, Variant def) const; + Variant GetPath(const std::string &path, Variant def) const { return GetPath(ParsePath(path), def); } + + /// \brief Set the value at the path, creating elements if they do not + /// exist. throws if an intermediate path element exists but is not a + /// map or list. returns *this + Variant &SetPath(const Path &path, Variant val); + Variant &SetPath(const std::string &path, Variant val) { return SetPath(ParsePath(path), val); } + + /// \brief Erase a value at a path, if remove_empty is false only erase the very end + /// otherwise erase empty lists and maps in the path. returns *this + Variant &ErasePath(const Path &path, bool remove_empty=false); + Variant &ErasePath(const std::string &path, bool remove_empty=false) + { return ErasePath(ParsePath(path), remove_empty); } + + /// \brief Tester functions for paths, returns true if path is valid and exists. + bool HasPath(const Path &path) const; + bool HasPath(const std::string &path) const { return HasPath(ParsePath(path)); } + + /// \brief Just like Variant::Get except a reference to the value to + /// set is passed in and Variant does the casting. + template + void GetInto(T &lvalue, const std::string &s) const; + + /// \brief An into version of GetPath + template + void GetPathInto(T &lvalue, const Path &path) const; + template + void GetPathInto(T &lvalue, const std::string &path) const + { GetPathInto(lvalue, ParsePath(path)); } + + /// \brief Just like Variant::Get except a reference to the value to + /// set is passed in and Variant does the casting. + template + void GetInto(T &lvalue, const std::string &s, const T &def) const; + + /// \brief An into version of GetPath + template + void GetPathInto(T &lvalue, const Path &path, const T &def) const; + template + void GetPathInto(T &lvalue, const std::string &path, const T &def) const + { GetPathInto(lvalue, ParsePath(path), def); } + + /// \brief This type and other type must be MapType. + /// for (k, v) in other: this[k] = v + void Merge(Variant other); + + /// \brief Comparison operator + /// Returns -1 if we are less than other + /// 0 if we are equal + /// 1 if we are greater than + /// This function always returns 1 if Comparable returns false + /// This compare is not completely consistent + /// i.e. it can be such that two Variants are + /// both < and > (ex map and list types) + int Compare(const Variant &other) const; + + /// \brief Return true if this and other are comparable. Two types are + /// considered comparable if they have the same type or if they are both + /// number types. + bool Comparable(const Variant &other) const; + + void Incr(); + void Decr(); + void Add(const Variant &o); + void Sub(const Variant &o); + void Mul(const Variant &o); + void Div(const Variant &o); + void Rem(const Variant &o); + + Variant Neg() const; + + Variant &operator++() { Incr(); return *this; } + Variant &operator--() { Decr(); return *this; } + Variant operator++(int) { Variant tmp = *this; ++(*this); return tmp; } + Variant operator--(int) { Variant tmp = *this; --(*this); return tmp; } + Variant operator-() const { return Neg(); } + Variant operator+() const { return *this; } + + Variant &operator+=(const Variant &o) { Add(o); return *this; } + Variant &operator-=(const Variant &o) { Sub(o); return *this; } + Variant &operator*=(const Variant &o) { Mul(o); return *this; } + Variant &operator/=(const Variant &o) { Div(o); return *this; } + Variant &operator%=(const Variant &o) { Rem(o); return *this; } + + VariantRef Ref(); //< Return a new VariantRef to this Variant + Variant Copy() const; //< Return a copy of this Variant + Variant &Resolve(); //< Return *this or return the Variant this is a reference to + const Variant &Resolve() const; + /// Return *this or Variant referenced to if exists, otherwise create it with def. + Variant &Resolve(const Variant &def); + /// Return weather or not Resolve() const would throw. + bool Exists() const; + + /// Make this equal other. + void Assign(const Variant &other); + + void Assign(VariantDefines::Type_t type); + void Assign(bool v); + void Assign(int v); + void Assign(unsigned v); + void Assign(long v); + void Assign(unsigned long v); + void Assign(long long v); + void Assign(unsigned long long v); + void Assign(double v); + void Assign(long double v); + void Assign(BlobPtr b); + void Assign(const std::string &v); + void Assign(const char *v); + + template + void Assign(const std::vector &v) { + Assign(VariantDefines::ListType); + AsList().assign(v.begin(), v.end()); + } + + template + void Assign(const std::map &v) { + Assign(VariantDefines::MapType); + AsMap().insert(v.begin(), v.end()); + } + + protected: + Variant(const RefTag &, const Variant &o); + Variant(const RefTag &, Variant &o, Path::const_iterator b, Path::const_iterator e); + /// Reassing this reference, only available through the VariantRef interface. + /// The regular Assign makes what this is refering to equal the new value, this + /// function makes this reference refer to the new value. + void ReassignRef(const Variant &o); + friend class Internal::VTable; + }; + + typedef VariantRefImpl VariantRef; + + inline bool operator==(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) == 0; } + inline bool operator!=(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) != 0; } + inline bool operator<(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) < 0; } + inline bool operator>(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) > 0; } + inline bool operator<=(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) <= 0; } + inline bool operator>=(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) >= 0; } + + inline Variant operator+(const Variant &lhs, const Variant &rhs) { + Variant ret = lhs; + return ret += rhs; + } + inline Variant operator-(const Variant &lhs, const Variant &rhs) { + Variant ret = lhs; + return ret -= rhs; + } + inline Variant operator*(const Variant &lhs, const Variant &rhs) { + Variant ret = lhs; + return ret *= rhs; + } + inline Variant operator/(const Variant &lhs, const Variant &rhs) { + Variant ret = lhs; + return ret /= rhs; + } + inline Variant operator%(const Variant &lhs, const Variant &rhs) { + Variant ret = lhs; + return ret %= rhs; + } + + /// \defgroup variant_cast Template casting operators. + /// These are for use inside templates to extract the value of a Variant into + /// a templated type. + /// @{ + + template + struct VariantCaster { + static T Cast(const Variant &v); + }; + + // Default + template inline T VariantCaster::Cast(const Variant &v) { return T(v); } + + template + inline T variant_cast(const Variant &v) { return VariantCaster::Cast(v); } + + // Provide specializations for all the basic types + template<> inline bool VariantCaster::Cast(const Variant &v) { return v.AsBool(); } + template<> inline char VariantCaster::Cast(const Variant &v) { return (char)v.AsInt(); } + template<> inline unsigned char VariantCaster::Cast(const Variant &v) { return (unsigned char)v.AsUnsigned(); } + template<> inline signed char VariantCaster::Cast(const Variant &v) { return (signed char)v.AsUnsigned(); } + template<> inline short VariantCaster::Cast(const Variant &v) { return (short)v.AsInt(); } + template<> inline unsigned short VariantCaster::Cast(const Variant &v) { return (unsigned short)v.AsUnsigned(); } + template<> inline int VariantCaster::Cast(const Variant &v) { return (int)v.AsInt(); } + template<> inline unsigned VariantCaster::Cast(const Variant &v) { return (unsigned)v.AsUnsigned(); } + template<> inline long VariantCaster::Cast(const Variant &v) { return (long)v.AsInt(); } + template<> inline unsigned long VariantCaster::Cast(const Variant &v) { return (unsigned long)v.AsUnsigned(); } + template<> inline long long VariantCaster::Cast(const Variant &v) { return (long long)v.AsInt(); } + template<> inline unsigned long long VariantCaster::Cast(const Variant &v) { return (unsigned long long)v.AsUnsigned(); } + template<> inline float VariantCaster::Cast(const Variant &v) { return (float)v.AsDouble(); } + template<> inline double VariantCaster::Cast(const Variant &v) { return v.AsDouble(); } + template<> inline long double VariantCaster::Cast(const Variant &v) { return v.AsLongDouble(); } + template<> inline std::string VariantCaster::Cast(const Variant &v) { return v.AsString(); } + + // Allow things like variant_cast< std::vector >(v) to work + template + struct VariantCaster< std::vector > { + static std::vector Cast(const Variant &v); + }; + + template + inline std::vector VariantCaster< std::vector >::Cast(const Variant &v) { + std::vector ret; + for (Variant::ConstListIterator i(v.ListBegin()), e(v.ListEnd()); i != e; ++i) { + ret.push_back( variant_cast( *i ) ); + } + return ret; + } + + template<> inline Variant::List VariantCaster::Cast(const Variant &v) { return v.AsList(); } + + // allow things like variant_cast< std::map >(v) + // to work + template + struct VariantCaster< std::map > { + static std::map Cast(const Variant &v); + }; + + template + inline std::map VariantCaster< std::map >::Cast(const Variant &v) { + std::map ret; + for (Variant::ConstMapIterator i(v.MapBegin()), e(v.MapEnd()); i != e; ++i) { + ret.insert( std::make_pair( i->first, variant_cast( i->second ) ) ); + } + return ret; + } + + template<> inline Variant::Map VariantCaster::Cast(const Variant &v) { return v.AsMap(); } + + template + struct VariantCaster< std::complex > { + static std::complex Cast(const Variant &v); + }; + + template + std::complex VariantCaster< std::complex >::Cast(const Variant &v) { + if (v.IsNull()) { + return std::complex(); + } else if (v.IsNumber()) { + return std::complex(v.As(), T()); + } else if (v.IsMap()) { + T r = variant_cast(v.Get("real", T())); + T c = variant_cast(v.Get("imag", T())); + return std::complex(r, c); + } else if (v.IsList()) { + if (v.Size() > 1) { + return std::complex(v[0].As(), v[1].As()); + } else if (v.Size() > 0) { + return std::complex(v[0].As(), T()); + } else { + return std::complex(); + } + } + throw UnableToConvertError(v.GetType(), "std::complex"); + } + + /// @} + + template + T Variant::As() const { return variant_cast(*this); } + + template + void Variant::GetInto(T &lvalue, const std::string &s) const { + lvalue = variant_cast(Get(s)); + } + + template + void Variant::GetPathInto(T &lvalue, const Path &p) const { + lvalue = variant_cast(GetPath(p)); + } + + template + void Variant::GetInto(T &lvalue, const std::string &s, const T &def) const { + if (Contains(s)) { lvalue = variant_cast(Get(s)); } + else { lvalue = def; } + } + + template + void Variant::GetPathInto(T &lvalue, const Path &p, const T &def) const { + lvalue = variant_cast(GetPath(p, def)); + } + + class Parser; + /// \brief Takes a parser and produces a Variant from it. + Variant ParseVariant(Parser &p); + + class Emitter; + /// Takes a Variant and Emitter and emits the Variant. + Emitter &operator<<(Emitter &e, const Variant &v); + + /// \brief The different types of serialization supported. + enum SerializeType { + // Attempt to guess the format + // Cannot be specified as an output format. + SERIALIZE_GUESS = 0x0, + + // Built in text formats + SERIALIZE_JSON = 0x00000001, + SERIALIZE_YAML, + SERIALIZE_XMLPLIST, + SERIALIZE_BUNDLEHDR, + + // Built in binary formats + SERIALIZE_MSGPACK = 0x000000FF, + + }; + + + /// \brief An iterator that iterates over all documents that the parser will generate + class LoadAllIterator { + public: + typedef Variant value_type; + typedef ptrdiff_t difference_type; + typedef Variant* pointer; + typedef Variant& reference; + typedef std::forward_iterator_tag iterator_category; + + LoadAllIterator(); + explicit LoadAllIterator(Parser &parser); + Variant &operator*() { return Get(); } + Variant *operator->() { return &Get(); } + Variant &Get(); + void Next(); + LoadAllIterator &operator++() { + Next(); + return *this; + } + LoadAllIterator operator++(int) { + LoadAllIterator copy = *this; + Next(); + return copy; + } + bool operator==(const LoadAllIterator &that) const; + bool operator!=(const LoadAllIterator &that) const { return !(*this == that); } + private: + class Impl; + shared_ptr impl; + struct Value; + shared_ptr value; + }; + + // Some convenience functions + // A version is provided that will go to/from a string, + // a memory buffer, a file name, an open FILE*, and + // a streambuf* (usually acquired through iostream.rdbuf()). + + /// \brief Serialize a Variant to a string using format type. + std::string Serialize(Variant v, SerializeType type, Variant params = Variant::NullType); + /// \brief Serialize a Variant to a file using format type. + void Serialize(const std::string &filename, Variant v, SerializeType type, + Variant params = Variant::NullType); + /// \brief Serialize a Variant to a FILE pointer using format type. + void Serialize(FILE *f, Variant v, SerializeType type, + Variant params = Variant::NullType); + /// \brief Serialize a Variant to a streambuf* (iostrem.rdbuf()) using format type. + void Serialize(std::streambuf *sb, Variant v, SerializeType type, + Variant params = Variant::NullType); + /// \brief Serialize a Variant to a memory buffer of length len, using format type + //and return how many bytes produced. + unsigned Serialize(void *ptr, unsigned len, Variant v, SerializeType type, + Variant params = Variant::NullType); + + // The basic deserializing functions + + /// \brief Attempt to deserialize a string in format type to a Variant + Variant Deserialize(const std::string &str, SerializeType type); + /// \brief Attempt to deserialize a null terminated string in format type to a Variant + Variant Deserialize(const char *str, SerializeType type); + /// \brief Attempt to deserialize a pointer and length in format type to a Variant + Variant Deserialize(const void *ptr, unsigned len, SerializeType type); + /// \brief Attempt to deserialize the file to a Variant in format type + Variant DeserializeFile(const char *filename, SerializeType type); + /// \brief Deserialize from a FILE pointer to a Variant in format type + Variant DeserializeFile(FILE *f, SerializeType type); + /// \brief Deserialize from a streambuf to a Variant in format type + Variant DeserializeFile(std::streambuf *sb, SerializeType type); + + /// \defgroup deserialize_guess Guess format + /// These functions attempt to guess the type of the input. The guessing + /// function only looks at the first non-whitespace character to make the + /// decision. As such on sufficiently badly behaved input can select the + /// wrong format. + /// @{ + Variant DeserializeGuess(const std::string &str); + Variant DeserializeGuess(const char *str); + Variant DeserializeGuess(const void *ptr, unsigned len); + Variant DeserializeGuessFile(const char *filename); + Variant DeserializeGuessFile(FILE *f); + Variant DeserializeGuessFile(std::streambuf *sb); + /// @} + + /// \defgroup deserialize_all Deserialize all elements + /// These functions return an iterator. These are for format types that + /// support multiple documents in one stream. Otherwise same as Deserialize + /// functions above. + /// @{ + LoadAllIterator DeserializeAll(const std::string &str, SerializeType type); + LoadAllIterator DeserializeAll(const char *str, SerializeType type); + LoadAllIterator DeserializeAll(const void *ptr, unsigned len, SerializeType type); + LoadAllIterator DeserializeAllFile(const char *filename, SerializeType type); + /// File must remain open for as long as the iterator is referenced + LoadAllIterator DeserializeAllFile(FILE *f, SerializeType type); + /// Streambuf must exist for as long as the iterator is referenced + LoadAllIterator DeserializeAllFile(std::streambuf *sb, SerializeType type); + /// @} + + + // Serialize and Deserializing JSON + // + inline std::string SerializeJSON(Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + return Serialize(v, SERIALIZE_JSON, param); + } + inline void SerializeJSON(const std::string &filename, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(filename, v, SERIALIZE_JSON, param); + } + inline void SerializeJSON(FILE *f, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(f, v, SERIALIZE_JSON, param); + } + inline void SerializeJSON(std::streambuf *sb, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(sb, v, SERIALIZE_JSON, param); + } + inline unsigned SerializeJSON(void *ptr, unsigned len, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + return Serialize(ptr, len, v, SERIALIZE_JSON, param); + } + inline Variant DeserializeJSON(const std::string &str) { return Deserialize(str, SERIALIZE_JSON); } + inline Variant DeserializeJSON(const char *str) { return Deserialize(str, SERIALIZE_JSON); } + inline Variant DeserializeJSON(const void *ptr, unsigned len) { return Deserialize(ptr, len, SERIALIZE_JSON); } + inline Variant DeserializeJSONFile(const char *filename) { return DeserializeFile(filename, SERIALIZE_JSON); } + inline Variant DeserializeJSONFile(FILE *f) { return DeserializeFile(f, SERIALIZE_JSON); } + inline Variant DeserializeJSONFile(std::streambuf *sb) { return DeserializeFile(sb, SERIALIZE_JSON); } + + //Serialize and Deserialize YAML + // + inline std::string SerializeYAML(Variant v) { return Serialize(v, SERIALIZE_YAML); } + inline void SerializeYAML(const std::string &filename, Variant v) { Serialize(filename, v, SERIALIZE_YAML); } + inline void SerializeYAML(FILE *f, Variant v) { Serialize(f, v, SERIALIZE_YAML); } + inline void SerializeYAML(std::streambuf *sb, Variant v) { Serialize(sb, v, SERIALIZE_YAML); } + inline unsigned SerializeYAML(void *ptr, unsigned len, Variant v) { return Serialize(ptr, len, v, SERIALIZE_YAML); } + + inline Variant DeserializeYAML(const std::string &str) { return Deserialize(str, SERIALIZE_YAML); } + inline Variant DeserializeYAML(const char *str) { return Deserialize(str, SERIALIZE_YAML); } + inline Variant DeserializeYAML(const void *ptr, unsigned len) { return Deserialize(ptr, len, SERIALIZE_YAML); } + inline Variant DeserializeYAMLFile(const char *filename) { return DeserializeFile(filename, SERIALIZE_YAML); } + inline Variant DeserializeYAMLFile(FILE *f) { return DeserializeFile(f, SERIALIZE_YAML); } + inline Variant DeserializeYAMLFile(std::streambuf *sb) { return DeserializeFile(sb, SERIALIZE_YAML); } + + inline LoadAllIterator DeserializeYAMLAll(const std::string &str) { return DeserializeAll(str, SERIALIZE_YAML); } + inline LoadAllIterator DeserializeYAMLAll(const char *str) { return DeserializeAll(str, SERIALIZE_YAML); } + inline LoadAllIterator DeserializeYAMLAll(const void *ptr, unsigned len) { return DeserializeAll(ptr, len, SERIALIZE_YAML); } + inline LoadAllIterator DeserializeYAMLAllFile(const char *filename) { return DeserializeAllFile(filename, SERIALIZE_YAML); } + inline LoadAllIterator DeserializeYAMLAllFile(FILE *f) { return DeserializeAllFile(f, SERIALIZE_YAML); } + inline LoadAllIterator DeserializeYAMLAllFile(std::streambuf *sb) { return DeserializeAllFile(sb, SERIALIZE_YAML); } + + //Serialize and Deserialize XML plist + // + inline std::string SerializeXMLPLIST(Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + return Serialize(v, SERIALIZE_XMLPLIST, param); + } + inline void SerializeXMLPLIST(const std::string &filename, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(filename, v, SERIALIZE_XMLPLIST, param); + } + inline void SerializeXMLPLIST(FILE *f, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(f, v, SERIALIZE_XMLPLIST, param); + } + inline void SerializeXMLPLIST(std::streambuf *sb, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(sb, v, SERIALIZE_XMLPLIST, param); + } + inline unsigned SerializeXMLPLIST(void *ptr, unsigned len, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + return Serialize(ptr, len, v, SERIALIZE_XMLPLIST, param); + } + + inline Variant DeserializeXMLPLIST(const std::string &str) { return Deserialize(str, SERIALIZE_XMLPLIST); } + inline Variant DeserializeXMLPLIST(const char *str) { return Deserialize(str, SERIALIZE_XMLPLIST); } + inline Variant DeserializeXMLPLIST(const void *ptr, unsigned len) { return Deserialize(ptr, len, SERIALIZE_XMLPLIST); } + inline Variant DeserializeXMLPLISTFile(const char *filename) { return DeserializeFile(filename, SERIALIZE_XMLPLIST); } + inline Variant DeserializeXMLPLISTFile(FILE *f) { return DeserializeFile(f, SERIALIZE_XMLPLIST); } + inline Variant DeserializeXMLPLISTFile(std::streambuf *sb) { return DeserializeFile(sb, SERIALIZE_XMLPLIST); } + + //Serialize and Deserialize BundleHdr + // + // BundleHdr requires the root element to be of MapType and + // no submaps exist. + // + // Note that these do not add a null byte to the end. + // Use SerializeBundle for that. + + inline std::string SerializeBundleHdr(Variant v) { + Variant param = Variant::MapType; + return Serialize(v, SERIALIZE_BUNDLEHDR, param); + } + inline void SerializeBundleHdr(const std::string &filename, Variant v) { + Variant param = Variant::MapType; + Serialize(filename, v, SERIALIZE_BUNDLEHDR, param); + } + inline void SerializeBundleHdr(FILE *f, Variant v) { + Variant param = Variant::MapType; + Serialize(f, v, SERIALIZE_BUNDLEHDR, param); + } + inline void SerializeBundleHdr(std::streambuf *sb, Variant v) { + Variant param = Variant::MapType; + Serialize(sb, v, SERIALIZE_BUNDLEHDR, param); + } + inline unsigned SerializeBundleHdr(void *ptr, unsigned len, Variant v) { + Variant param = Variant::MapType; + return Serialize(ptr, len, v, SERIALIZE_BUNDLEHDR, param); + } + + inline Variant DeserializeBundleHdr(const std::string &str) { return Deserialize(str, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleHdr(const char *str) { return Deserialize(str, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleHdr(const void *ptr, unsigned len) { return Deserialize(ptr, len, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleHdrFile(const char *filename) { return DeserializeFile(filename, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleHdrFile(FILE *f) { return DeserializeFile(f, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleHdrFile(std::streambuf *sb) { return DeserializeFile(sb, SERIALIZE_BUNDLEHDR); } + +} + +/// Debug function not inside the namespace to print out a variant (calls SerializeJSON) +void VariantPrint(const libvariant::Variant v); + +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/VariantDefines.h b/src/hos_libvariant/include/hos_libvariant/VariantDefines.h new file mode 100644 index 00000000..6a6df997 --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/VariantDefines.h @@ -0,0 +1,50 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_DEFINES_H +#define VARIANT_DEFINES_H + +#ifdef __GNUC__ +#define DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED __declspec(deprecated) +#else +#pragma message("WARNING: You need to implement DEPRECATED for this compiler") +#define DEPRECATED +#endif + +namespace libvariant { + class VariantDefines { + public: + enum Type_t { + NullType = 0, // Explicitly defined as 0 + BoolType, + IntegerType, + UnsignedType, + FloatType, + StringType, + ListType, + MapType, + BlobType + }; + + }; +} +#endif diff --git a/src/hos_libvariant/include/hos_libvariant/VariantInternal.h b/src/hos_libvariant/include/hos_libvariant/VariantInternal.h new file mode 100644 index 00000000..8479795d --- /dev/null +++ b/src/hos_libvariant/include/hos_libvariant/VariantInternal.h @@ -0,0 +1,96 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_BASE_H +#define VARIANT_BASE_H +#include +#include +#include +#include + +#include "../hos_libvariant/Blob.h" +#include "../hos_libvariant/Path.h" +#include "../hos_libvariant/SharedPtr.h" +#include "../hos_libvariant/VariantDefines.h" +namespace libvariant { + + struct RefTag {}; + + class Variant; + template class VariantRefImpl; + + + /** + * Action implementation for the VariantRef class. + */ + template + class VariantRefImpl : public Base { + public: + VariantRefImpl(const Variant &o) : Base(RefTag(), o) {} + VariantRefImpl(Variant &o, const Path &path) + : Base(RefTag(), o, path.begin(), path.end()) {} + VariantRefImpl(Variant &o, Path::const_iterator b, Path::const_iterator e) + : Base(RefTag(), o, b, e) {} + VariantRefImpl(const VariantRefImpl &o) + : Base(RefTag(), o) {} + + using Base::operator=; + using Base::As; + using Base::AsNumber; + using Base::GetInto; + using Base::GetPathInto; + using Base::Assign; + + using Base::ReassignRef; + }; + + namespace Internal { + + class VTable; + struct Storage; + struct MapStorage; + struct ListStorage; + struct ProxyStorage; + struct RefData; + + struct Data { + Data(); + const VTable *vtable; + union { + bool b; + long double f; + intmax_t i; + uintmax_t u; + std::string *s; + MapStorage *m; + ListStorage *l; + BlobPtr *blob; + Data *ref; + ProxyStorage *proxy; + }; + shared_ptr ref_data; + shared_ptr storage; + }; + } + + + +} +#endif diff --git a/src/hos_libvariant/package.xml b/src/hos_libvariant/package.xml new file mode 100644 index 00000000..dd1ffe74 --- /dev/null +++ b/src/hos_libvariant/package.xml @@ -0,0 +1,50 @@ + + + hos_libvariant + 0.0.0 + The hos_libvariant package + + + + + matzman + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + + + + + + + + \ No newline at end of file diff --git a/src/hos_libvariant/src/.hg/00changelog.i b/src/hos_libvariant/src/.hg/00changelog.i new file mode 100644 index 00000000..d3a83110 Binary files /dev/null and b/src/hos_libvariant/src/.hg/00changelog.i differ diff --git a/src/hos_libvariant/src/.hg/branch b/src/hos_libvariant/src/.hg/branch new file mode 100644 index 00000000..4ad96d51 --- /dev/null +++ b/src/hos_libvariant/src/.hg/branch @@ -0,0 +1 @@ +default diff --git a/src/hos_libvariant/src/.hg/cache/branch2-served b/src/hos_libvariant/src/.hg/cache/branch2-served new file mode 100644 index 00000000..3fe9b174 --- /dev/null +++ b/src/hos_libvariant/src/.hg/cache/branch2-served @@ -0,0 +1,2 @@ +055488b93468e27c2893da3834e86506b1cd4b10 4 +055488b93468e27c2893da3834e86506b1cd4b10 o default diff --git a/src/hos_libvariant/src/.hg/dirstate b/src/hos_libvariant/src/.hg/dirstate new file mode 100644 index 00000000..105dbfaa Binary files /dev/null and b/src/hos_libvariant/src/.hg/dirstate differ diff --git a/src/hos_libvariant/src/.hg/hgrc b/src/hos_libvariant/src/.hg/hgrc new file mode 100644 index 00000000..383f66f2 --- /dev/null +++ b/src/hos_libvariant/src/.hg/hgrc @@ -0,0 +1,2 @@ +[paths] +default = https://bitbucket.org/gallen/libvariant diff --git a/src/hos_libvariant/src/.hg/requires b/src/hos_libvariant/src/.hg/requires new file mode 100644 index 00000000..f634f664 --- /dev/null +++ b/src/hos_libvariant/src/.hg/requires @@ -0,0 +1,4 @@ +dotencode +fncache +revlogv1 +store diff --git a/src/hos_libvariant/src/.hg/store/00changelog.i b/src/hos_libvariant/src/.hg/store/00changelog.i new file mode 100644 index 00000000..bba22b48 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/00changelog.i differ diff --git a/src/hos_libvariant/src/.hg/store/00manifest.i b/src/hos_libvariant/src/.hg/store/00manifest.i new file mode 100644 index 00000000..0abb1db3 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/00manifest.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/_c_make_lists.txt.i b/src/hos_libvariant/src/.hg/store/data/_c_make_lists.txt.i new file mode 100644 index 00000000..bd21e021 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/_c_make_lists.txt.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/_config.h.in.i b/src/hos_libvariant/src/.hg/store/data/_config.h.in.i new file mode 100644 index 00000000..8a20bbb9 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/_config.h.in.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/_doxyfile.in.i b/src/hos_libvariant/src/.hg/store/data/_doxyfile.in.i new file mode 100644 index 00000000..04d86a43 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/_doxyfile.in.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/_l_i_c_e_n_s_e.i b/src/hos_libvariant/src/.hg/store/data/_l_i_c_e_n_s_e.i new file mode 100644 index 00000000..b5d8a843 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/_l_i_c_e_n_s_e.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/_lib_variant_build_tree_settings.cmake.in.i b/src/hos_libvariant/src/.hg/store/data/_lib_variant_build_tree_settings.cmake.in.i new file mode 100644 index 00000000..e3a6505b Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/_lib_variant_build_tree_settings.cmake.in.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/_lib_variant_config.cmake.in.i b/src/hos_libvariant/src/.hg/store/data/_lib_variant_config.cmake.in.i new file mode 100644 index 00000000..409a060f Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/_lib_variant_config.cmake.in.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/_lib_variant_config_version.cmake.in.i b/src/hos_libvariant/src/.hg/store/data/_lib_variant_config_version.cmake.in.i new file mode 100644 index 00000000..741dcd29 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/_lib_variant_config_version.cmake.in.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/_r_e_a_d_m_e.i b/src/hos_libvariant/src/.hg/store/data/_r_e_a_d_m_e.i new file mode 100644 index 00000000..a9cf8614 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/_r_e_a_d_m_e.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/_r_e_a_d_m_e.md.i b/src/hos_libvariant/src/.hg/store/data/_r_e_a_d_m_e.md.i new file mode 100644 index 00000000..73a2c22e Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/_r_e_a_d_m_e.md.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/cmake/_modules/_find_lib_y_a_m_l.cmake.i b/src/hos_libvariant/src/.hg/store/data/cmake/_modules/_find_lib_y_a_m_l.cmake.i new file mode 100644 index 00000000..2aeff885 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/cmake/_modules/_find_lib_y_a_m_l.cmake.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/cmake/_modules/_find_msg_pack.cmake.i b/src/hos_libvariant/src/.hg/store/data/cmake/_modules/_find_msg_pack.cmake.i new file mode 100644 index 00000000..8289cdf8 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/cmake/_modules/_find_msg_pack.cmake.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/cmake/_modules/_make_t_b_z2.cmake.i b/src/hos_libvariant/src/.hg/store/data/cmake/_modules/_make_t_b_z2.cmake.i new file mode 100644 index 00000000..7b78398f Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/cmake/_modules/_make_t_b_z2.cmake.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/examples/_c_make_lists.txt.i b/src/hos_libvariant/src/.hg/store/data/examples/_c_make_lists.txt.i new file mode 100644 index 00000000..e8da8afc Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/examples/_c_make_lists.txt.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/examples/_r_e_a_d_m_e.i b/src/hos_libvariant/src/.hg/store/data/examples/_r_e_a_d_m_e.i new file mode 100644 index 00000000..dfea5a7a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/examples/_r_e_a_d_m_e.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/examples/arg__parse.cc.i b/src/hos_libvariant/src/.hg/store/data/examples/arg__parse.cc.i new file mode 100644 index 00000000..d02c9324 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/examples/arg__parse.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/examples/convert.cc.i b/src/hos_libvariant/src/.hg/store/data/examples/convert.cc.i new file mode 100644 index 00000000..282fa997 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/examples/convert.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/examples/example1.cc.i b/src/hos_libvariant/src/.hg/store/data/examples/example1.cc.i new file mode 100644 index 00000000..e391ac4a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/examples/example1.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/examples/example2.cc.i b/src/hos_libvariant/src/.hg/store/data/examples/example2.cc.i new file mode 100644 index 00000000..2df50ca1 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/examples/example2.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/examples/list__example.cc.i b/src/hos_libvariant/src/.hg/store/data/examples/list__example.cc.i new file mode 100644 index 00000000..3e99f72e Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/examples/list__example.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/examples/map__example.cc.i b/src/hos_libvariant/src/.hg/store/data/examples/map__example.cc.i new file mode 100644 index 00000000..8abf93d3 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/examples/map__example.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/examples/pretty__print.cc.i b/src/hos_libvariant/src/.hg/store/data/examples/pretty__print.cc.i new file mode 100644 index 00000000..2d53158b Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/examples/pretty__print.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_arg_parse.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_arg_parse.h.i new file mode 100644 index 00000000..36b506ea Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_arg_parse.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_blob.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_blob.h.i new file mode 100644 index 00000000..33a64ce6 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_blob.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_emitter.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_emitter.h.i new file mode 100644 index 00000000..ff25041e Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_emitter.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_emitter_output.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_emitter_output.h.i new file mode 100644 index 00000000..47823098 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_emitter_output.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_exceptions.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_exceptions.h.i new file mode 100644 index 00000000..be10ff44 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_exceptions.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_extensions.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_extensions.h.i new file mode 100644 index 00000000..cbad4713 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_extensions.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_guess_format.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_guess_format.h.i new file mode 100644 index 00000000..c84269aa Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_guess_format.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_parser.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_parser.h.i new file mode 100644 index 00000000..3b383209 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_parser.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_parser_input.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_parser_input.h.i new file mode 100644 index 00000000..eb7d1bc4 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_parser_input.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_path.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_path.h.i new file mode 100644 index 00000000..872e2341 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_path.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_payload.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_payload.h.i new file mode 100644 index 00000000..f69a4fe2 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_payload.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_schema.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_schema.h.i new file mode 100644 index 00000000..70c99b2d Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_schema.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_schema_loader.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_schema_loader.h.i new file mode 100644 index 00000000..acb7b99a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_schema_loader.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_shared_ptr.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_shared_ptr.h.i new file mode 100644 index 00000000..a46b91c0 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_shared_ptr.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_variant.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_variant.h.i new file mode 100644 index 00000000..f70b1363 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_variant.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_variant_defines.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_variant_defines.h.i new file mode 100644 index 00000000..5c1bf16d Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_variant_defines.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/include/_variant/_variant_internal.h.i b/src/hos_libvariant/src/.hg/store/data/include/_variant/_variant_internal.h.i new file mode 100644 index 00000000..d3d765ad Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/include/_variant/_variant_internal.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/lib/json/_j_s_o_n___p_a_r_s_e_r___r_e_a_d_m_e.htm.i b/src/hos_libvariant/src/.hg/store/data/lib/json/_j_s_o_n___p_a_r_s_e_r___r_e_a_d_m_e.htm.i new file mode 100644 index 00000000..ed0de587 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/lib/json/_j_s_o_n___p_a_r_s_e_r___r_e_a_d_m_e.htm.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/lib/json/_j_s_o_n__parser.c.i b/src/hos_libvariant/src/.hg/store/data/lib/json/_j_s_o_n__parser.c.i new file mode 100644 index 00000000..bdd500f3 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/lib/json/_j_s_o_n__parser.c.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/lib/json/_j_s_o_n__parser.h.i b/src/hos_libvariant/src/.hg/store/data/lib/json/_j_s_o_n__parser.h.i new file mode 100644 index 00000000..40cafbe9 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/lib/json/_j_s_o_n__parser.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/libvariant.pc.in.i b/src/hos_libvariant/src/.hg/store/data/libvariant.pc.in.i new file mode 100644 index 00000000..5e28a035 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/libvariant.pc.in.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_arg_parse.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_arg_parse.cc.i new file mode 100644 index 00000000..efda5e61 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_arg_parse.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_base64.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_base64.cc.i new file mode 100644 index 00000000..5a7909ce Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_base64.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_base64.h.i b/src/hos_libvariant/src/.hg/store/data/src/_base64.h.i new file mode 100644 index 00000000..21e08302 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_base64.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_blob.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_blob.cc.i new file mode 100644 index 00000000..4a32c6af Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_blob.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_blob_magic.h.i b/src/hos_libvariant/src/.hg/store/data/src/_blob_magic.h.i new file mode 100644 index 00000000..bcdb5528 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_blob_magic.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_emitter.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_emitter.cc.i new file mode 100644 index 00000000..c97ca434 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_emitter.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_emitter.h.i b/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_emitter.h.i new file mode 100644 index 00000000..2bab3ea4 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_emitter.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_parser.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_parser.cc.i new file mode 100644 index 00000000..3195171a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_parser.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_parser.h.i b/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_parser.h.i new file mode 100644 index 00000000..c13707fd Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_bundle_hdr_parser.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_c_make_lists.txt.i b/src/hos_libvariant/src/.hg/store/data/src/_c_make_lists.txt.i new file mode 100644 index 00000000..ad87db59 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_c_make_lists.txt.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_emitter.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_emitter.cc.i new file mode 100644 index 00000000..fbdadc2f Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_emitter.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_emitter_output.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_emitter_output.cc.i new file mode 100644 index 00000000..52e26ffe Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_emitter_output.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_event_buffer.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_event_buffer.cc.i new file mode 100644 index 00000000..dad0a449 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_event_buffer.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_event_buffer.h.i b/src/hos_libvariant/src/.hg/store/data/src/_event_buffer.h.i new file mode 100644 index 00000000..15aef3d0 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_event_buffer.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_exceptions.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_exceptions.cc.i new file mode 100644 index 00000000..77cd47db Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_exceptions.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_extensions.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_extensions.cc.i new file mode 100644 index 00000000..d7aa1adb Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_extensions.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_guess_format.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_guess_format.cc.i new file mode 100644 index 00000000..d8ca6ff0 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_guess_format.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_guess_scalar.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_guess_scalar.cc.i new file mode 100644 index 00000000..2266b087 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_guess_scalar.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_guess_scalar.h.i b/src/hos_libvariant/src/.hg/store/data/src/_guess_scalar.h.i new file mode 100644 index 00000000..5731227a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_guess_scalar.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_emitter.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_emitter.cc.i new file mode 100644 index 00000000..f70cc7b5 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_emitter.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_emitter.h.i b/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_emitter.h.i new file mode 100644 index 00000000..36716c0c Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_emitter.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_parser.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_parser.cc.i new file mode 100644 index 00000000..2c19a050 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_parser.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_parser.h.i b/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_parser.h.i new file mode 100644 index 00000000..dd42cab1 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_j_s_o_n_parser.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_emitter.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_emitter.cc.i new file mode 100644 index 00000000..bebe6b12 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_emitter.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_emitter.h.i b/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_emitter.h.i new file mode 100644 index 00000000..c82822b8 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_emitter.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_parser.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_parser.cc.i new file mode 100644 index 00000000..74f4012e Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_parser.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_parser.h.i b/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_parser.h.i new file mode 100644 index 00000000..23673f23 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_msg_pack_parser.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_parse_bool.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_parse_bool.cc.i new file mode 100644 index 00000000..6091c17a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_parse_bool.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_parse_bool.h.i b/src/hos_libvariant/src/.hg/store/data/src/_parse_bool.h.i new file mode 100644 index 00000000..a89095b9 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_parse_bool.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_parser.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_parser.cc.i new file mode 100644 index 00000000..c1ccc7de Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_parser.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_parser_input.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_parser_input.cc.i new file mode 100644 index 00000000..610bbea5 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_parser_input.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_path.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_path.cc.i new file mode 100644 index 00000000..9b9842b2 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_path.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_payload.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_payload.cc.i new file mode 100644 index 00000000..8a3ea0b4 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_payload.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_schema.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_schema.cc.i new file mode 100644 index 00000000..298ace90 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_schema.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_schema_loader.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_schema_loader.cc.i new file mode 100644 index 00000000..2831876d Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_schema_loader.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_stack_trace.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_stack_trace.cc.i new file mode 100644 index 00000000..52269ba3 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_stack_trace.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_stack_trace.h.i b/src/hos_libvariant/src/.hg/store/data/src/_stack_trace.h.i new file mode 100644 index 00000000..ed577f5f Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_stack_trace.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_variant.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_variant.cc.i new file mode 100644 index 00000000..cb936290 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_variant.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_variant_emitting.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_variant_emitting.cc.i new file mode 100644 index 00000000..613a0cad Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_variant_emitting.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_variant_parsing.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_variant_parsing.cc.i new file mode 100644 index 00000000..d206bb00 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_variant_parsing.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_defs.h.i b/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_defs.h.i new file mode 100644 index 00000000..f0ae3ff2 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_defs.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_emitter.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_emitter.cc.i new file mode 100644 index 00000000..05009e29 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_emitter.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_emitter.h.i b/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_emitter.h.i new file mode 100644 index 00000000..476fe549 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_emitter.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_parser.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_parser.cc.i new file mode 100644 index 00000000..77164258 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_parser.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_parser.h.i b/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_parser.h.i new file mode 100644 index 00000000..2cfbbc23 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_x_m_l_p_l_i_s_t_parser.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_emitter.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_emitter.cc.i new file mode 100644 index 00000000..82e851de Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_emitter.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_emitter.h.i b/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_emitter.h.i new file mode 100644 index 00000000..ee852568 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_emitter.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_parser.cc.i b/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_parser.cc.i new file mode 100644 index 00000000..02bbd694 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_parser.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_parser.h.i b/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_parser.h.i new file mode 100644 index 00000000..675f5a0c Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/_y_a_m_l_parser.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/argparse-schema.cc.i b/src/hos_libvariant/src/.hg/store/data/src/argparse-schema.cc.i new file mode 100644 index 00000000..6de4546a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/argparse-schema.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/argparse-schema.yaml.i b/src/hos_libvariant/src/.hg/store/data/src/argparse-schema.yaml.i new file mode 100644 index 00000000..cc4d998e Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/argparse-schema.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/gen-argparse-schema.i b/src/hos_libvariant/src/.hg/store/data/src/gen-argparse-schema.i new file mode 100644 index 00000000..502ae7db Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/gen-argparse-schema.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/gen-json-schema.i b/src/hos_libvariant/src/.hg/store/data/src/gen-json-schema.i new file mode 100644 index 00000000..d6e9af99 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/gen-json-schema.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/json-schema-v4.cc.i b/src/hos_libvariant/src/.hg/store/data/src/json-schema-v4.cc.i new file mode 100644 index 00000000..fbf6067d Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/json-schema-v4.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/json-schema-v4.json.i b/src/hos_libvariant/src/.hg/store/data/src/json-schema-v4.json.i new file mode 100644 index 00000000..4dcc940f Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/json-schema-v4.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/src/varsh.cc.i b/src/hos_libvariant/src/.hg/store/data/src/varsh.cc.i new file mode 100644 index 00000000..330f15ba Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/src/varsh.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/_c_make_lists.txt.i b/src/hos_libvariant/src/.hg/store/data/test/_c_make_lists.txt.i new file mode 100644 index 00000000..c7353529 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/_c_make_lists.txt.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/_test_assert.h.i b/src/hos_libvariant/src/.hg/store/data/test/_test_assert.h.i new file mode 100644 index 00000000..ea547a4b Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/_test_assert.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/_test_common.h.i b/src/hos_libvariant/src/.hg/store/data/test/_test_common.h.i new file mode 100644 index 00000000..f2413f01 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/_test_common.h.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/prof__msgpack.cc.i b/src/hos_libvariant/src/.hg/store/data/test/prof__msgpack.cc.i new file mode 100644 index 00000000..a45126b7 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/prof__msgpack.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/rand__test__json.cc.i b/src/hos_libvariant/src/.hg/store/data/test/rand__test__json.cc.i new file mode 100644 index 00000000..ee52a789 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/rand__test__json.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/rand__test__msgpack.cc.i b/src/hos_libvariant/src/.hg/store/data/test/rand__test__msgpack.cc.i new file mode 100644 index 00000000..eab9f453 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/rand__test__msgpack.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/rand__test__xml.cc.i b/src/hos_libvariant/src/.hg/store/data/test/rand__test__xml.cc.i new file mode 100644 index 00000000..2ed22e72 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/rand__test__xml.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/rand__test__yaml.cc.i b/src/hos_libvariant/src/.hg/store/data/test/rand__test__yaml.cc.i new file mode 100644 index 00000000..2f6f1a3e Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/rand__test__yaml.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__argparse.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__argparse.cc.i new file mode 100644 index 00000000..4fb00c7d Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__argparse.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__argparse.sh.in.i b/src/hos_libvariant/src/.hg/store/data/test/test__argparse.sh.in.i new file mode 100644 index 00000000..3d9cd038 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__argparse.sh.in.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__argparse__merge.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__argparse__merge.cc.i new file mode 100644 index 00000000..3bc6c17a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__argparse__merge.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__base64.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__base64.cc.i new file mode 100644 index 00000000..dfbdbba7 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__base64.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__bundleemitter.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__bundleemitter.cc.i new file mode 100644 index 00000000..97f9cff8 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__bundleemitter.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__bundlehdr.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__bundlehdr.cc.i new file mode 100644 index 00000000..c86b4a29 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__bundlehdr.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__bundleparser.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__bundleparser.cc.i new file mode 100644 index 00000000..8349db77 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__bundleparser.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__empty.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__empty.cc.i new file mode 100644 index 00000000..ec2a01f3 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__empty.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__extensions.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__extensions.cc.i new file mode 100644 index 00000000..0555675d Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__extensions.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__guess.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__guess.cc.i new file mode 100644 index 00000000..106efd78 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__guess.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__json__parser.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__json__parser.cc.i new file mode 100644 index 00000000..6ba31260 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__json__parser.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__loadall.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__loadall.cc.i new file mode 100644 index 00000000..9e7d1c20 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__loadall.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__memoryoutput.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__memoryoutput.cc.i new file mode 100644 index 00000000..a56c4c15 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__memoryoutput.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__numerics.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__numerics.cc.i new file mode 100644 index 00000000..669871fb Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__numerics.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__path.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__path.cc.i new file mode 100644 index 00000000..96204ae9 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__path.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__payload.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__payload.cc.i new file mode 100644 index 00000000..d415f60e Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__payload.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__roundtrip.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__roundtrip.cc.i new file mode 100644 index 00000000..5bc35576 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__roundtrip.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema.cc.i new file mode 100644 index 00000000..3eb5a219 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/invalid-schema.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/invalid-schema.test.i new file mode 100644 index 00000000..6b7af253 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/invalid-schema.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/invalid__path.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/invalid__path.test.i new file mode 100644 index 00000000..e684fab6 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/invalid__path.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/_makefile.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/_makefile.i new file mode 100644 index 00000000..96b901f2 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/_makefile.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/_r_e_a_d_m_e.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/_r_e_a_d_m_e.i new file mode 100644 index 00000000..9689dee8 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/_r_e_a_d_m_e.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_items.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_items.json.i new file mode 100644 index 00000000..0229b7f1 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_items.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_items.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_items.test.i new file mode 100644 index 00000000..a8a9843a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_items.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_properties.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_properties.json.i new file mode 100644 index 00000000..ccc9bc18 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_properties.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_properties.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_properties.test.i new file mode 100644 index 00000000..26f5462f Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/additional_properties.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/all_of.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/all_of.json.i new file mode 100644 index 00000000..2fdf6475 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/all_of.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/all_of.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/all_of.test.i new file mode 100644 index 00000000..4e785bea Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/all_of.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/any_of.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/any_of.json.i new file mode 100644 index 00000000..5cf5d300 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/any_of.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/any_of.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/any_of.test.i new file mode 100644 index 00000000..9d4e3f01 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/any_of.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/convert.py.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/convert.py.i new file mode 100644 index 00000000..9fb215fc Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/convert.py.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/definitions.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/definitions.json.i new file mode 100644 index 00000000..9e2878b7 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/definitions.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/definitions.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/definitions.test.i new file mode 100644 index 00000000..0dad6d7e Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/definitions.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/dependencies.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/dependencies.json.i new file mode 100644 index 00000000..fba01f77 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/dependencies.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/dependencies.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/dependencies.test.i new file mode 100644 index 00000000..d2ee0acb Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/dependencies.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/enum.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/enum.json.i new file mode 100644 index 00000000..c2e4fbfb Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/enum.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/enum.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/enum.test.i new file mode 100644 index 00000000..8c3549ec Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/enum.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/items.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/items.json.i new file mode 100644 index 00000000..91d68804 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/items.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/items.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/items.test.i new file mode 100644 index 00000000..cddc9162 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/items.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_items.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_items.json.i new file mode 100644 index 00000000..efab9c32 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_items.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_items.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_items.test.i new file mode 100644 index 00000000..715246b4 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_items.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_length.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_length.json.i new file mode 100644 index 00000000..1a107b33 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_length.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_length.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_length.test.i new file mode 100644 index 00000000..a96a89f6 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_length.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_properties.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_properties.json.i new file mode 100644 index 00000000..47cdd5fd Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_properties.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_properties.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_properties.test.i new file mode 100644 index 00000000..e607dce0 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/max_properties.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/maximum.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/maximum.json.i new file mode 100644 index 00000000..72fd4090 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/maximum.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/maximum.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/maximum.test.i new file mode 100644 index 00000000..cead4186 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/maximum.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_items.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_items.json.i new file mode 100644 index 00000000..f4d296c9 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_items.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_items.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_items.test.i new file mode 100644 index 00000000..cbe79e90 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_items.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_length.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_length.json.i new file mode 100644 index 00000000..00aac669 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_length.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_length.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_length.test.i new file mode 100644 index 00000000..2b842dcb Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_length.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_properties.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_properties.json.i new file mode 100644 index 00000000..c8f232ee Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_properties.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_properties.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_properties.test.i new file mode 100644 index 00000000..61a99f37 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/min_properties.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/minimum.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/minimum.json.i new file mode 100644 index 00000000..7117c87c Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/minimum.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/minimum.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/minimum.test.i new file mode 100644 index 00000000..bcc070e4 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/minimum.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/multiple_of.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/multiple_of.json.i new file mode 100644 index 00000000..559df288 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/multiple_of.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/multiple_of.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/multiple_of.test.i new file mode 100644 index 00000000..3998829c Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/multiple_of.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/not.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/not.json.i new file mode 100644 index 00000000..5708a0f3 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/not.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/not.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/not.test.i new file mode 100644 index 00000000..b094ea0f Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/not.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/one_of.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/one_of.json.i new file mode 100644 index 00000000..ca57a008 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/one_of.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/one_of.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/one_of.test.i new file mode 100644 index 00000000..acf4342a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/one_of.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern.json.i new file mode 100644 index 00000000..5fcaaf67 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern.test.i new file mode 100644 index 00000000..cb59e1ff Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern_properties.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern_properties.json.i new file mode 100644 index 00000000..f5b69539 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern_properties.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern_properties.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern_properties.test.i new file mode 100644 index 00000000..66ce8603 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/pattern_properties.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/properties.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/properties.json.i new file mode 100644 index 00000000..a24abbc5 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/properties.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/properties.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/properties.test.i new file mode 100644 index 00000000..e9827360 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/properties.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/ref.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/ref.json.i new file mode 100644 index 00000000..c33d427e Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/ref.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/ref.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/ref.test.i new file mode 100644 index 00000000..d30197a9 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/ref.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/required.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/required.json.i new file mode 100644 index 00000000..81f282b1 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/required.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/required.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/required.test.i new file mode 100644 index 00000000..e22a6fbe Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/required.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/type.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/type.json.i new file mode 100644 index 00000000..c416bb7a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/type.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/type.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/type.test.i new file mode 100644 index 00000000..b1c3c58b Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/type.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/unique_items.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/unique_items.json.i new file mode 100644 index 00000000..b7ded369 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/unique_items.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/unique_items.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/unique_items.test.i new file mode 100644 index 00000000..7136b2d0 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/jsonschema-tests/unique_items.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/negative-unique-items.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/negative-unique-items.test.i new file mode 100644 index 00000000..fbeae62b Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/negative-unique-items.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/recursion.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/recursion.test.i new file mode 100644 index 00000000..35e53ab7 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/recursion.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/sample-test.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/sample-test.test.i new file mode 100644 index 00000000..d83f3ea4 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/sample-test.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/simple-test-fail.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/simple-test-fail.json.i new file mode 100644 index 00000000..019d9d84 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/simple-test-fail.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/simple-test-schema.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/simple-test-schema.json.i new file mode 100644 index 00000000..3693a3e8 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/simple-test-schema.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/simple-test.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/simple-test.json.i new file mode 100644 index 00000000..cfe71ca0 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/simple-test.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/test__resolveuri.json.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/test__resolveuri.json.i new file mode 100644 index 00000000..d698ae49 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/test__resolveuri.json.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/01-type.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/01-type.test.i new file mode 100644 index 00000000..095d55e7 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/01-type.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/02-enum.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/02-enum.test.i new file mode 100644 index 00000000..abea3409 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/02-enum.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/02-enum.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/02-enum.yaml.i new file mode 100644 index 00000000..02319124 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/02-enum.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/_makefile.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/_makefile.i new file mode 100644 index 00000000..19ea61e8 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/01-any-type/_makefile.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/01-min-max.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/01-min-max.test.i new file mode 100644 index 00000000..20e0e72e Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/01-min-max.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/01-min-max.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/01-min-max.yaml.i new file mode 100644 index 00000000..88f0bb0c Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/01-min-max.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/02-multiple_of.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/02-multiple_of.test.i new file mode 100644 index 00000000..09e7c85c Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/02-multiple_of.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/02-multiple_of.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/02-multiple_of.yaml.i new file mode 100644 index 00000000..06f7efa7 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/02-multiple_of.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/_makefile.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/_makefile.i new file mode 100644 index 00000000..d2464947 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/02-numeric/_makefile.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/01-min-max-length.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/01-min-max-length.test.i new file mode 100644 index 00000000..954e3dfb Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/01-min-max-length.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/01-min-max-length.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/01-min-max-length.yaml.i new file mode 100644 index 00000000..2f8e9c7d Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/01-min-max-length.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/02-pattern.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/02-pattern.test.i new file mode 100644 index 00000000..db871bc7 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/02-pattern.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/02-pattern.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/02-pattern.yaml.i new file mode 100644 index 00000000..a6e68e76 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/02-pattern.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/_makefile.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/_makefile.i new file mode 100644 index 00000000..d2464947 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/03-strings/_makefile.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/01-min-max-length.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/01-min-max-length.test.i new file mode 100644 index 00000000..35361657 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/01-min-max-length.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/01-min-max-length.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/01-min-max-length.yaml.i new file mode 100644 index 00000000..8ebbdbb4 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/01-min-max-length.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/02-uniqueitems.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/02-uniqueitems.test.i new file mode 100644 index 00000000..14924e37 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/02-uniqueitems.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/02-uniqueitems.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/02-uniqueitems.yaml.i new file mode 100644 index 00000000..c56359ce Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/02-uniqueitems.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/03-items-plain.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/03-items-plain.test.i new file mode 100644 index 00000000..9e412ddb Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/03-items-plain.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/03-items-plain.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/03-items-plain.yaml.i new file mode 100644 index 00000000..8e39bda3 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/03-items-plain.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/04-items-tuple-typing.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/04-items-tuple-typing.test.i new file mode 100644 index 00000000..fa160201 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/04-items-tuple-typing.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/04-items-tuple-typing.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/04-items-tuple-typing.yaml.i new file mode 100644 index 00000000..4b17d54a Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/04-items-tuple-typing.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/05-additionalitems.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/05-additionalitems.test.i new file mode 100644 index 00000000..66f7616e Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/05-additionalitems.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/05-additionalitems.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/05-additionalitems.yaml.i new file mode 100644 index 00000000..8ffffad2 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/05-additionalitems.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/_makefile.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/_makefile.i new file mode 100644 index 00000000..d2464947 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/04-arrays/_makefile.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/01-min-max-properties.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/01-min-max-properties.test.i new file mode 100644 index 00000000..612019ee Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/01-min-max-properties.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/01-min-max-properties.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/01-min-max-properties.yaml.i new file mode 100644 index 00000000..d9a6818d Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/01-min-max-properties.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/02-required.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/02-required.test.i new file mode 100644 index 00000000..058fbf31 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/02-required.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/02-required.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/02-required.yaml.i new file mode 100644 index 00000000..b34b4c19 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/02-required.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/03-properties.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/03-properties.test.i new file mode 100644 index 00000000..d633e974 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/03-properties.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/03-properties.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/03-properties.yaml.i new file mode 100644 index 00000000..0cc235fc Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/03-properties.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/04-patternproperties.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/04-patternproperties.test.i new file mode 100644 index 00000000..f714f568 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/04-patternproperties.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/04-patternproperties.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/04-patternproperties.yaml.i new file mode 100644 index 00000000..de013658 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/04-patternproperties.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/05-additionalproperties.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/05-additionalproperties.test.i new file mode 100644 index 00000000..1d20f881 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/05-additionalproperties.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/05-additionalproperties.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/05-additionalproperties.yaml.i new file mode 100644 index 00000000..be521427 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/05-additionalproperties.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/06-dependencies.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/06-dependencies.test.i new file mode 100644 index 00000000..c5b68366 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/06-dependencies.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/06-dependencies.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/06-dependencies.yaml.i new file mode 100644 index 00000000..5c50fe91 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/06-dependencies.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/_makefile.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/_makefile.i new file mode 100644 index 00000000..d2464947 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/05-objects/_makefile.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/01-all_of.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/01-all_of.test.i new file mode 100644 index 00000000..1b5f032b Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/01-all_of.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/01-all_of.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/01-all_of.yaml.i new file mode 100644 index 00000000..0ae2d139 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/01-all_of.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/02-any_of.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/02-any_of.test.i new file mode 100644 index 00000000..4915b795 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/02-any_of.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/02-any_of.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/02-any_of.yaml.i new file mode 100644 index 00000000..63318bbd Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/02-any_of.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/03-one_of.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/03-one_of.test.i new file mode 100644 index 00000000..4a0066d3 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/03-one_of.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/03-one_of.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/03-one_of.yaml.i new file mode 100644 index 00000000..2e3a53ef Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/03-one_of.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/04-not.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/04-not.test.i new file mode 100644 index 00000000..254114d3 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/04-not.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/04-not.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/04-not.yaml.i new file mode 100644 index 00000000..e27772a7 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/04-not.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/_makefile.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/_makefile.i new file mode 100644 index 00000000..d2464947 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/06-combinations/_makefile.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/04-ref.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/04-ref.test.i new file mode 100644 index 00000000..da9c02de Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/04-ref.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/04-ref.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/04-ref.yaml.i new file mode 100644 index 00000000..c524a7b1 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/04-ref.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/05-inline-addressing.test.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/05-inline-addressing.test.i new file mode 100644 index 00000000..36a54184 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/05-inline-addressing.test.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/05-inline-addressing.yaml.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/05-inline-addressing.yaml.i new file mode 100644 index 00000000..20a27603 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/05-inline-addressing.yaml.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/_makefile.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/_makefile.i new file mode 100644 index 00000000..d2464947 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/07-ref/_makefile.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/_makefile.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/_makefile.i new file mode 100644 index 00000000..c004fa13 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/_makefile.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/_r_e_a_d_m_e.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/_r_e_a_d_m_e.i new file mode 100644 index 00000000..51a4e972 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/_r_e_a_d_m_e.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/submakefile.i b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/submakefile.i new file mode 100644 index 00000000..1ba00509 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__schema__data/tv4-tests/submakefile.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__variant.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__variant.cc.i new file mode 100644 index 00000000..672d8e38 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__variant.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__xml__parser.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__xml__parser.cc.i new file mode 100644 index 00000000..d2c89a53 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__xml__parser.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/test/test__yaml__parser.cc.i b/src/hos_libvariant/src/.hg/store/data/test/test__yaml__parser.cc.i new file mode 100644 index 00000000..73f7ba45 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/test/test__yaml__parser.cc.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/~2ehgignore.i b/src/hos_libvariant/src/.hg/store/data/~2ehgignore.i new file mode 100644 index 00000000..3cd28624 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/~2ehgignore.i differ diff --git a/src/hos_libvariant/src/.hg/store/data/~2ehgtags.i b/src/hos_libvariant/src/.hg/store/data/~2ehgtags.i new file mode 100644 index 00000000..3ec11211 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/data/~2ehgtags.i differ diff --git a/src/hos_libvariant/src/.hg/store/fncache b/src/hos_libvariant/src/.hg/store/fncache new file mode 100644 index 00000000..7970ba59 --- /dev/null +++ b/src/hos_libvariant/src/.hg/store/fncache @@ -0,0 +1,248 @@ +data/test/test_variant.cc.i +data/test/test_schema_data/jsonschema-tests/additionalProperties.test.i +data/test/test_schema_data/jsonschema-tests/not.test.i +data/test/test_schema_data/tv4-tests/01-any-type/02-enum.yaml.i +data/test/test_schema_data/tv4-tests/05-objects/01-min-max-properties.yaml.i +data/test/test_schema_data/jsonschema-tests/type.test.i +data/test/test_schema_data/tv4-tests/06-combinations/03-oneOf.yaml.i +data/test/test_extensions.cc.i +data/test/test_schema_data/jsonschema-tests/allOf.json.i +data/src/Emitter.cc.i +data/test/test_schema_data/tv4-tests/06-combinations/03-oneOf.test.i +data/test/test_schema_data/jsonschema-tests/properties.test.i +data/test/test_schema_data/jsonschema-tests/oneOf.json.i +data/src/StackTrace.h.i +data/test/test_schema_data/tv4-tests/06-combinations/01-allOf.test.i +data/src/YAMLEmitter.cc.i +data/include/Variant/SchemaLoader.h.i +data/test/test_schema_data/tv4-tests/06-combinations/01-allOf.yaml.i +data/test/test_schema_data/tv4-tests/06-combinations/Makefile.i +data/cmake/Modules/MakeTBZ2.cmake.i +data/test/test_schema_data/jsonschema-tests/required.test.i +data/test/test_schema_data/tv4-tests/05-objects/03-properties.test.i +data/src/XMLPLISTEmitter.cc.i +data/test/test_bundleemitter.cc.i +data/test/test_schema_data/jsonschema-tests/properties.json.i +data/include/Variant/VariantDefines.h.i +data/include/Variant/Blob.h.i +data/test/test_schema_data/tv4-tests/02-numeric/02-multipleOf.yaml.i +data/examples/map_example.cc.i +data/test/test_schema_data/jsonschema-tests/maximum.json.i +data/test/test_schema_data/tv4-tests/04-arrays/04-items-tuple-typing.test.i +data/src/JSONEmitter.cc.i +data/test/test_schema_data/tv4-tests/04-arrays/05-additionalitems.yaml.i +data/include/Variant/Variant.h.i +data/test/test_schema_data/tv4-tests/07-ref/05-inline-addressing.test.i +data/test/test_schema_data/jsonschema-tests/maxItems.json.i +data/test/test_schema_data/simple-test-fail.json.i +data/test/test_argparse.cc.i +data/test/test_schema_data/jsonschema-tests/Makefile.i +data/src/EventBuffer.cc.i +data/test/test_schema_data/tv4-tests/01-any-type/02-enum.test.i +data/test/test_argparse_merge.cc.i +data/test/test_schema_data/jsonschema-tests/maxItems.test.i +data/test/test_schema_data/jsonschema-tests/anyOf.json.i +data/examples/arg_parse.cc.i +data/src/JSONEmitter.h.i +data/test/test_schema_data/jsonschema-tests/type.json.i +data/include/Variant/Payload.h.i +data/src/VariantParsing.cc.i +data/examples/pretty_print.cc.i +data/test/test_schema_data/jsonschema-tests/maximum.test.i +data/src/Parser.cc.i +data/src/JSONParser.h.i +data/test/test_schema_data/jsonschema-tests/ref.test.i +data/test/test_schema_data/tv4-tests/05-objects/Makefile.i +data/src/XMLPLISTEmitter.h.i +data/libvariant.pc.in.i +data/test/test_schema_data/jsonschema-tests/additionalProperties.json.i +data/test/test_empty.cc.i +data/test/test_schema_data/jsonschema-tests/pattern.json.i +data/.hgtags.i +data/LibVariantConfigVersion.cmake.in.i +data/test/test_schema_data/jsonschema-tests/enum.test.i +data/test/TestCommon.h.i +data/test/test_schema_data/simple-test.json.i +data/include/Variant/EmitterOutput.h.i +data/test/test_bundleparser.cc.i +data/src/ArgParse.cc.i +data/include/Variant/Extensions.h.i +data/test/test_schema_data/tv4-tests/04-arrays/Makefile.i +data/src/MsgPackEmitter.cc.i +data/examples/convert.cc.i +data/test/test_schema_data/tv4-tests/03-strings/Makefile.i +data/test/test_schema_data/jsonschema-tests/minProperties.test.i +data/include/Variant/Schema.h.i +data/include/Variant/SharedPtr.h.i +data/src/BundleHdrParser.cc.i +data/src/Payload.cc.i +data/test/test_schema_data/jsonschema-tests/multipleOf.json.i +data/src/ParseBool.h.i +data/examples/README.i +data/lib/json/JSON_parser.c.i +data/test/test_schema_data/jsonschema-tests/minItems.json.i +data/test/test_schema_data/tv4-tests/03-strings/02-pattern.test.i +data/test/test_bundlehdr.cc.i +data/Doxyfile.in.i +data/test/test_schema_data/jsonschema-tests/oneOf.test.i +data/src/MsgPackEmitter.h.i +data/src/json-schema-v4.cc.i +data/test/test_schema_data/tv4-tests/04-arrays/05-additionalitems.test.i +data/src/GuessScalar.cc.i +data/test/test_schema_data/tv4-tests/05-objects/02-required.test.i +data/test/test_schema_data/tv4-tests/04-arrays/04-items-tuple-typing.yaml.i +data/CMakeLists.txt.i +data/test/test_schema_data/jsonschema-tests/pattern.test.i +data/test/test_schema_data/tv4-tests/Makefile.i +data/test/test_schema_data/jsonschema-tests/required.json.i +data/test/test_argparse.sh.in.i +data/test/test_schema_data/jsonschema-tests/maxLength.test.i +data/include/Variant/Parser.h.i +data/test/test_schema_data/tv4-tests/04-arrays/01-min-max-length.yaml.i +data/test/test_schema_data/tv4-tests/01-any-type/01-type.test.i +data/test/test_schema_data/jsonschema-tests/dependencies.json.i +data/test/test_schema_data/tv4-tests/05-objects/01-min-max-properties.test.i +data/examples/example1.cc.i +data/test/rand_test_json.cc.i +data/test/test_schema_data/tv4-tests/05-objects/04-patternproperties.yaml.i +data/test/test_schema_data/tv4-tests/05-objects/02-required.yaml.i +data/src/BundleHdrEmitter.cc.i +data/src/XMLPLISTParser.cc.i +data/test/test_numerics.cc.i +data/src/YAMLParser.cc.i +data/test/test_schema_data/tv4-tests/04-arrays/03-items-plain.test.i +data/test/prof_msgpack.cc.i +data/test/test_schema_data/tv4-tests/02-numeric/Makefile.i +data/src/XMLPLISTParser.h.i +data/src/gen-argparse-schema.i +data/test/test_schema_data/jsonschema-tests/convert.py.i +data/test/test_base64.cc.i +data/src/BlobMagic.h.i +data/src/JSONParser.cc.i +data/src/BundleHdrEmitter.h.i +data/src/BundleHdrParser.h.i +data/test/test_schema_data/tv4-tests/03-strings/01-min-max-length.test.i +data/test/test_schema_data/jsonschema-tests/maxProperties.test.i +data/test/test_schema_data/jsonschema-tests/items.test.i +data/test/test_schema_data/tv4-tests/03-strings/01-min-max-length.yaml.i +data/test/CMakeLists.txt.i +data/examples/CMakeLists.txt.i +data/test/test_schema_data/test_resolveuri.json.i +data/test/test_path.cc.i +data/test/test_schema_data/tv4-tests/04-arrays/02-uniqueitems.test.i +data/test/test_schema_data/tv4-tests/01-any-type/Makefile.i +data/test/test_schema_data/jsonschema-tests/maxLength.json.i +data/test/test_schema_data/jsonschema-tests/allOf.test.i +data/src/argparse-schema.yaml.i +data/test/rand_test_yaml.cc.i +data/include/Variant/ArgParse.h.i +data/test/test_schema_data/tv4-tests/05-objects/05-additionalproperties.test.i +data/cmake/Modules/FindLibYAML.cmake.i +data/test/test_schema_data/jsonschema-tests/README.i +data/test/test_guess.cc.i +data/test/test_schema_data/negative-unique-items.test.i +data/test/test_schema_data/tv4-tests/05-objects/03-properties.yaml.i +data/src/Schema.cc.i +data/src/YAMLEmitter.h.i +data/Config.h.in.i +data/test/test_schema_data/jsonschema-tests/multipleOf.test.i +data/src/StackTrace.cc.i +data/test/test_schema_data/jsonschema-tests/additionalItems.test.i +data/test/test_schema_data/tv4-tests/07-ref/Makefile.i +data/src/Blob.cc.i +data/test/test_schema_data/jsonschema-tests/additionalItems.json.i +data/test/test_schema.cc.i +data/src/VariantEmitting.cc.i +data/test/test_schema_data/tv4-tests/02-numeric/02-multipleOf.test.i +data/src/gen-json-schema.i +data/test/test_roundtrip.cc.i +data/test/test_schema_data/tv4-tests/README.i +data/test/test_schema_data/tv4-tests/07-ref/04-ref.yaml.i +data/test/test_schema_data/jsonschema-tests/minimum.json.i +data/include/Variant/Exceptions.h.i +data/test/test_schema_data/jsonschema-tests/dependencies.test.i +data/test/test_schema_data/tv4-tests/07-ref/04-ref.test.i +data/LibVariantConfig.cmake.in.i +data/.hgignore.i +data/test/test_xml_parser.cc.i +data/test/test_schema_data/simple-test-schema.json.i +data/test/TestAssert.h.i +data/test/test_schema_data/jsonschema-tests/maxProperties.json.i +data/src/Path.cc.i +data/test/test_schema_data/jsonschema-tests/definitions.test.i +data/test/test_schema_data/tv4-tests/05-objects/04-patternproperties.test.i +data/test/test_schema_data/tv4-tests/04-arrays/01-min-max-length.test.i +data/include/Variant/GuessFormat.h.i +data/src/SchemaLoader.cc.i +data/src/EventBuffer.h.i +data/test/test_schema_data/recursion.test.i +data/lib/json/JSON_PARSER_README.htm.i +data/test/test_schema_data/jsonschema-tests/minLength.test.i +data/test/test_schema_data/sample-test.test.i +data/README.md.i +data/test/test_yaml_parser.cc.i +data/include/Variant/VariantInternal.h.i +data/LibVariantBuildTreeSettings.cmake.in.i +data/test/rand_test_msgpack.cc.i +data/test/test_schema_data/jsonschema-tests/uniqueItems.json.i +data/src/CMakeLists.txt.i +data/test/test_schema_data/jsonschema-tests/minProperties.json.i +data/src/varsh.cc.i +data/test/test_schema_data/tv4-tests/02-numeric/01-min-max.test.i +data/test/test_schema_data/jsonschema-tests/not.json.i +data/include/Variant/Emitter.h.i +data/src/ParseBool.cc.i +data/test/test_schema_data/jsonschema-tests/patternProperties.json.i +data/README.i +data/test/test_schema_data/jsonschema-tests/minItems.test.i +data/test/test_schema_data/tv4-tests/06-combinations/02-anyOf.yaml.i +data/test/test_schema_data/jsonschema-tests/definitions.json.i +data/test/test_schema_data/tv4-tests/05-objects/06-dependencies.test.i +data/src/Base64.cc.i +data/test/rand_test_xml.cc.i +data/src/EmitterOutput.cc.i +data/src/GuessFormat.cc.i +data/test/test_schema_data/tv4-tests/05-objects/06-dependencies.yaml.i +data/test/test_schema_data/jsonschema-tests/anyOf.test.i +data/test/test_schema_data/tv4-tests/02-numeric/01-min-max.yaml.i +data/src/Extensions.cc.i +data/test/test_schema_data/jsonschema-tests/enum.json.i +data/test/test_schema_data/jsonschema-tests/uniqueItems.test.i +data/test/test_payload.cc.i +data/LICENSE.i +data/test/test_schema_data/jsonschema-tests/minLength.json.i +data/src/YAMLParser.h.i +data/test/test_schema_data/invalid-schema.test.i +data/test/test_memoryoutput.cc.i +data/test/test_schema_data/jsonschema-tests/items.json.i +data/test/test_schema_data/tv4-tests/03-strings/02-pattern.yaml.i +data/test/test_json_parser.cc.i +data/test/test_schema_data/tv4-tests/04-arrays/03-items-plain.yaml.i +data/test/test_schema_data/tv4-tests/06-combinations/02-anyOf.test.i +data/src/Exceptions.cc.i +data/src/MsgPackParser.h.i +data/src/Base64.h.i +data/src/json-schema-v4.json.i +data/src/MsgPackParser.cc.i +data/cmake/Modules/FindMsgPack.cmake.i +data/examples/example2.cc.i +data/src/Variant.cc.i +data/include/Variant/Path.h.i +data/src/GuessScalar.h.i +data/examples/list_example.cc.i +data/src/argparse-schema.cc.i +data/test/test_schema_data/jsonschema-tests/patternProperties.test.i +data/test/test_loadall.cc.i +data/test/test_schema_data/jsonschema-tests/minimum.test.i +data/test/test_schema_data/jsonschema-tests/ref.json.i +data/test/test_schema_data/tv4-tests/submakefile.i +data/include/Variant/ParserInput.h.i +data/test/test_schema_data/tv4-tests/05-objects/05-additionalproperties.yaml.i +data/src/ParserInput.cc.i +data/test/test_schema_data/tv4-tests/06-combinations/04-not.yaml.i +data/test/test_schema_data/tv4-tests/06-combinations/04-not.test.i +data/test/test_schema_data/tv4-tests/04-arrays/02-uniqueitems.yaml.i +data/src/XMLPLISTDefs.h.i +data/lib/json/JSON_parser.h.i +data/test/test_schema_data/tv4-tests/07-ref/05-inline-addressing.yaml.i +data/test/test_schema_data/invalid_path.test.i diff --git a/src/hos_libvariant/src/.hg/store/phaseroots b/src/hos_libvariant/src/.hg/store/phaseroots new file mode 100644 index 00000000..e69de29b diff --git a/src/hos_libvariant/src/.hg/store/undo b/src/hos_libvariant/src/.hg/store/undo new file mode 100644 index 00000000..94c1f7b9 Binary files /dev/null and b/src/hos_libvariant/src/.hg/store/undo differ diff --git a/src/hos_libvariant/src/.hg/store/undo.phaseroots b/src/hos_libvariant/src/.hg/store/undo.phaseroots new file mode 100644 index 00000000..e69de29b diff --git a/src/hos_libvariant/src/.hg/undo.bookmarks b/src/hos_libvariant/src/.hg/undo.bookmarks new file mode 100644 index 00000000..e69de29b diff --git a/src/hos_libvariant/src/.hg/undo.branch b/src/hos_libvariant/src/.hg/undo.branch new file mode 100644 index 00000000..331d858c --- /dev/null +++ b/src/hos_libvariant/src/.hg/undo.branch @@ -0,0 +1 @@ +default \ No newline at end of file diff --git a/src/hos_libvariant/src/.hg/undo.desc b/src/hos_libvariant/src/.hg/undo.desc new file mode 100644 index 00000000..f04ce07e --- /dev/null +++ b/src/hos_libvariant/src/.hg/undo.desc @@ -0,0 +1,3 @@ +0 +pull +https://bitbucket.org/gallen/libvariant diff --git a/src/hos_libvariant/src/.hg/undo.dirstate b/src/hos_libvariant/src/.hg/undo.dirstate new file mode 100644 index 00000000..e69de29b diff --git a/src/hos_libvariant/src/.hgignore b/src/hos_libvariant/src/.hgignore new file mode 100644 index 00000000..1e6ada79 --- /dev/null +++ b/src/hos_libvariant/src/.hgignore @@ -0,0 +1,10 @@ + +syntax: regexp +\.swp +\.swo +\.o +\.a +\.so +\.la +\._ +build diff --git a/src/hos_libvariant/src/.hgtags b/src/hos_libvariant/src/.hgtags new file mode 100644 index 00000000..bedfe9e7 --- /dev/null +++ b/src/hos_libvariant/src/.hgtags @@ -0,0 +1,4 @@ +fb0efab8850da0ff03051b4abae8e1bff1d4ca23 1.0.0 +edb423a0428e6a3744dbf0c4a9ae46e7165561a3 1.0.1 +0000000000000000000000000000000000000000 1.0.1 +40b8e618db81a21c1e363f7c1ee77b2e2c9cc717 1.0.1 diff --git a/src/hos_libvariant/src/CMakeLists.txt b/src/hos_libvariant/src/CMakeLists.txt new file mode 100644 index 00000000..a9ba68d9 --- /dev/null +++ b/src/hos_libvariant/src/CMakeLists.txt @@ -0,0 +1,244 @@ +project(LibVariant) + +cmake_minimum_required(VERSION 2.6) + +enable_testing() + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") + +include(CheckCXXSourceCompiles) +include(CheckIncludeFileCXX) + +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + set(EXAMPLES_AND_TESTS on) + set(LIBVARIANT_DOC_TARGET doc) + option(BUILD_SHARED_LIBS "Build shared libraries." OFF) +else() + set(EXAMPLES_AND_TESTS off) + set(LIBVARIANT_DOC_TARGET libvariant-doc) +endif() + +option(LIBVARIANT_BUILD_WALL "build Variant with the -Wall flag" ON) +option(LIBVARIANT_BUILD_DEBUG "build Variant with the additional debug flags" OFF) +option(LIBVARIANT_BUILD_TESTS "build the Variant tests" ${EXAMPLES_AND_TESTS}) +option(LIBVARIANT_BUILD_EXAMPLES "build the Variant examples" ${EXAMPLES_AND_TESTS}) +option(LIBVARIANT_BUILD_PROFILE "build Variant with profiling flags" OFF) +option(LIBVARIANT_ENABLE_YAML "Enable YAML encoding" ON) +option(LIBVARIANT_ENABLE_XML "Enable XML encoding" ON) +option(LIBVARIANT_ENABLE_MSGPACK "Enable msgpack encoding" OFF) +option(LIBVARIANT_ENABLE_CURL "Enable cURL related functionality in the SchemaLoader" ON) + +set(LIBVARIANT_MAJOR_VERSION 1) +set(LIBVARIANT_MINOR_VERSION 0) +set(LIBVARIANT_PATCH_VERSION 1) +set(LIBVARIANT_VERSION + ${LIBVARIANT_MAJOR_VERSION}.${LIBVARIANT_MINOR_VERSION}.${LIBVARIANT_PATCH_VERSION}) + +# Offer the user the choice of overriding the installation directories +set(INSTALL_LIB_DIR lib CACHE STRING "Installation directory for libraries") +set(INSTALL_BIN_DIR bin CACHE STRING "Installation directory for executables") +set(INSTALL_INCLUDE_DIR include CACHE STRING "Installation directory for header files") + +set(DEF_INSTALL_CMAKE_DIR "${INSTALL_LIB_DIR}/cmake/LibVariant") +set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE STRING + "Installation directory for CMake files") + +# Make relative paths absolute (needed later on) +foreach(p LIB BIN INCLUDE CMAKE) + set(var INSTALL_${p}_DIR) + if(NOT IS_ABSOLUTE "${${var}}") + set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") + endif() +endforeach() + +if(LIBVARIANT_BUILD_WALL) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +endif() + +if (LIBVARIANT_BUILD_DEBUG) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Winline -Wfatal-errors") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Winline -Wfatal-errors") +endif() + +if (LIBVARIANT_BUILD_PROFILE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fprofile-arcs -ftest-coverage") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fprofile-arcs -ftest-coverage") +endif() + +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DENABLE_STACKTRACE") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DENABLE_STACKTRACE") + +# setup include directories +include_directories("include") +include_directories("${CMAKE_CURRENT_BINARY_DIR}/include") + +# libraries to depends upon +if(LIBVARIANT_ENABLE_XML) + find_package(LibXml2) + if(LIBXML2_FOUND) + include_directories(${LIBXML2_INCLUDE_DIR}) + add_definitions(${LIBXML2_DEFINITIONS}) + add_definitions("-DENABLE_XML") + list(APPEND EXTRA_LIBS ${LIBXML2_LIBRARIES}) + else() + message(WARNING " Could not find libxml2, disabling.") + set(LIBVARIANT_ENABLE_XML OFF) + endif() +endif() + +if(LIBVARIANT_ENABLE_YAML) + find_package(LibYAML) + if(LIBYAML_FOUND) + include_directories(${LIBYAML_INCLUDE_DIR}) + add_definitions("-DENABLE_YAML") + list(APPEND EXTRA_LIBS ${LIBYAML_LIBRARIES}) + else() + message(WARNING " Could not find libyaml, disabling.") + set(LIBVARIANT_ENABLE_YAML OFF) + endif() +endif() + +if(LIBVARIANT_ENABLE_MSGPACK) + find_package(MsgPack) + if(MSGPACK_FOUND) + include_directories(${MSGPACK_INCLUDE_DIR}) + add_definitions("-DENABLE_MSGPACK") + list(APPEND EXTRA_LIBS ${MSGPACK_LIBRARIES}) + else() + message(WARNING " Could not find msgpack, disabling") + set(LIBVARIANT_ENABLE_MSGPACK OFF) + endif() +endif() + +if (LIBVARIANT_ENABLE_CURL) + find_package(CURL) + if (CURL_FOUND) + include_directories(${CURL_INCLUDE_DIR}) + add_definitions("-DENABLE_CURL") + list(APPEND EXTRA_LIBS ${CURL_LIBRARIES}) + else() + message(INFO " CURL not found, disabling CURL functionality.") + set(LIBVARIANT_ENABLE_CURL OFF) + endif() +endif() + +# We want to following checks to try compiling with the same flags that we +# have already setup +set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS}) + +check_cxx_source_compiles( " +\#include \n +int main() { + std::shared_ptr i; + return 0; +} +" + HAVE_CXX11_SHAREDPTR ) + +if (NOT HAVE_CXX11_SHAREDPTR) + check_include_file_cxx("tr1/memory" HAVE_TR1_SHAREDPTR) + + if (NOT HAVE_TR1_SHAREDPTR) + message(STATUS "Fallback to using boost shared_ptr") + find_package(Boost REQUIRED) + include_directories(${Boost_INCLUDE_DIRS}) + set(USE_BOOST_SHAREDPTR 1) + endif() +endif() + +check_cxx_source_compiles(" +int main() { + long long i = 0; + unsigned long long u = 0; + return i + u; +} +" + HAVE_LONG_LONG) + +if (HAVE_LONG_LONG) + add_definitions("-DHAVE_LONG_LONG=1") +endif() + +# add sub directories +add_subdirectory(src) +if (LIBVARIANT_BUILD_TESTS) + add_subdirectory(test) +endif() +if (LIBVARIANT_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() + + +# Build documentation +find_package(Doxygen) +if (DOXYGEN_FOUND) + configure_file(Doxyfile.in ${PROJECT_BINARY_DIR}/Doxyfile @ONLY IMMEDIATE) + add_custom_target(${LIBVARIANT_DOC_TARGET} + COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/Doxyfile + SOURCES ${PROJECT_BINARY_DIR}/Doxyfile) +endif() + + +# Add targets to the build-tree export set +set(LIBVARIANT_EXPORTED_LIBS Variant) + +export(TARGETS ${LIBVARIANT_EXPORTED_LIBS} + FILE "${PROJECT_BINARY_DIR}/LibVariantLibraryDepends.cmake") + +# Export the package for use from the build-tree +# (this registers the build-tree with a global CMake-registry) +#export(PACKAGE LibVariant) # NOT IMPLEMENTED IN cmake 2.6 on RHEL6 + + +# Create a LibVariantBuildTreeSettings.cmake file for the use from the build tree +configure_file(LibVariantBuildTreeSettings.cmake.in + "${PROJECT_BINARY_DIR}/LibVariantBuildTreeSettings.cmake" @ONLY) + +# Create the LibVariantConfig.cmake and LibVariantConfigVersion files +file(RELATIVE_PATH CONF_REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" + "${INSTALL_INCLUDE_DIR}") +configure_file(LibVariantConfig.cmake.in + "${PROJECT_BINARY_DIR}/LibVariantConfig.cmake" @ONLY) +configure_file(LibVariantConfigVersion.cmake.in + "${PROJECT_BINARY_DIR}/LibVariantConfigVersion.cmake" @ONLY) + +install(FILES + "${PROJECT_BINARY_DIR}/LibVariantConfig.cmake" + "${PROJECT_BINARY_DIR}/LibVariantConfigVersion.cmake" + DESTINATION "${INSTALL_CMAKE_DIR}") + +# Install the export set for use with the install-tree +install(EXPORT LibVariantLibraryDepends + DESTINATION "${INSTALL_CMAKE_DIR}" + COMPONENT dev) + +# Create the package config file +configure_file(libvariant.pc.in + "${PROJECT_BINARY_DIR}/libvariant.pc" @ONLY) + +install(FILES + "${PROJECT_BINARY_DIR}/libvariant.pc" + DESTINATION "${INSTALL_LIB_DIR}/pkgconfig") + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/Variant/Config.h) + +FILE(GLOB install_headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + include/Variant/*.h) +install(FILES ${install_headers} DESTINATION ${INSTALL_INCLUDE_DIR}/Variant/) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/Variant/Config.h DESTINATION + ${INSTALL_INCLUDE_DIR}/Variant/) + +# Am I the root CMakeLists.txt? +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + include(MakeTBZ2) + add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source) +else() + # set parent variables as if it used find_package(testlib2) + set(LIBVARIANT_LIBRARIES Variant PARENT_SCOPE) + get_directory_property(LIBVARIANT_INCLUDE_DIRS INCLUDE_DIRECTORIES) + set(LIBVARIANT_INCLUDE_DIRS ${LIBVARIANT_INCLUDE_DIRS} PARENT_SCOPE) + set(LIBVARIANT_FOUND TRUE PARENT_SCOPE) +endif() diff --git a/src/hos_libvariant/src/Config.h.in b/src/hos_libvariant/src/Config.h.in new file mode 100644 index 00000000..37ff2e74 --- /dev/null +++ b/src/hos_libvariant/src/Config.h.in @@ -0,0 +1,13 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_CONFIG_H +#define VARIANT_CONFIG_H +#pragma once + +#cmakedefine HAVE_CXX11_SHAREDPTR 1 +#cmakedefine HAVE_TR1_SHAREDPTR 1 +#cmakedefine USE_BOOST_SHAREDPTR 1 + +#endif diff --git a/src/hos_libvariant/src/Doxyfile.in b/src/hos_libvariant/src/Doxyfile.in new file mode 100644 index 00000000..82dfd8ac --- /dev/null +++ b/src/hos_libvariant/src/Doxyfile.in @@ -0,0 +1,1569 @@ +# Doxyfile 1.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = libvariant + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @VARIANT_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @PROJECT_BINARY_DIR@/doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@/src \ + @PROJECT_SOURCE_DIR@/include + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = @PROJECT_SOURCE_DIR@/include + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set +# FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = YES + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @PROJECT_SOURCE_DIR@/src +INPUT += @PROJECT_SOURCE_DIR@/include +INPUT += @PROJECT_SOURCE_DIR@/README.md + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# If the HTML_TIMESTAMP tag is set to YES then the generated HTML +# documentation will contain the timesstamp. + +HTML_TIMESTAMP = NO + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# When the SEARCHENGINE tag is enable doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) +# there is already a search function so this one should typically +# be disabled. + +SEARCHENGINE = YES + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +MARKDOWN_SUPPORT = YES + +USE_MDFILE_AS_MAINPAGE = README.md diff --git a/src/hos_libvariant/src/LICENSE b/src/hos_libvariant/src/LICENSE new file mode 100644 index 00000000..2fda3ee9 --- /dev/null +++ b/src/hos_libvariant/src/LICENSE @@ -0,0 +1,16 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= diff --git a/src/hos_libvariant/src/LibVariantBuildTreeSettings.cmake.in b/src/hos_libvariant/src/LibVariantBuildTreeSettings.cmake.in new file mode 100644 index 00000000..06629e75 --- /dev/null +++ b/src/hos_libvariant/src/LibVariantBuildTreeSettings.cmake.in @@ -0,0 +1,3 @@ + +set(LIBVARIANT_INCLUDE_DIRS + "@PROJECT_SOURCE_DIR@/include") diff --git a/src/hos_libvariant/src/LibVariantConfig.cmake.in b/src/hos_libvariant/src/LibVariantConfig.cmake.in new file mode 100644 index 00000000..e2383699 --- /dev/null +++ b/src/hos_libvariant/src/LibVariantConfig.cmake.in @@ -0,0 +1,25 @@ + +# - Config file for the Variant package +# It defines the following variables +# LIBVARIANT_INCLUDE_DIRS - include directories for Variant +# LIBVARIANT_LIBRARIES - libraries to link against +# LIBVARIANT_FOUND - library has been found + +# Compute paths +get_filename_component(LIBVARIANT_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +if(EXISTS "${LIBVARIANT_CMAKE_DIR}/CMakeCache.txt") + # In build tree + include("${LIBVARIANT_CMAKE_DIR}/LibVariantBuildTreeSettings.cmake") +else() + set(LIBVARIANT_INCLUDE_DIRS "${LIBVARIANT_CMAKE_DIR}/@CONF_REL_INCLUDE_DIR@") +endif() + +# Our library dependencies (contains defninitinos for IMPORTED targets) +include("${LIBVARIANT_CMAKE_DIR}/LibVariantLibraryDepends.cmake") + +# These are IMPORTANT targets created by VariantLibraryDepends.cmake +set(LIBVARIANT_LIBRARIES Variant) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibVariant DEFAULT_MSG + LIBVARIANT_LIBRARIES LIBVARIANT_INCLUDE_DIRS) diff --git a/src/hos_libvariant/src/LibVariantConfigVersion.cmake.in b/src/hos_libvariant/src/LibVariantConfigVersion.cmake.in new file mode 100644 index 00000000..ca388800 --- /dev/null +++ b/src/hos_libvariant/src/LibVariantConfigVersion.cmake.in @@ -0,0 +1,12 @@ + +set(PACKAGE_VERSION "@LIBVARIANT_VERSION@") + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/src/hos_libvariant/src/README.md b/src/hos_libvariant/src/README.md new file mode 100644 index 00000000..05c8da1d --- /dev/null +++ b/src/hos_libvariant/src/README.md @@ -0,0 +1,126 @@ + +Introduction +------------ + +This library, libvariant, provides a class called Variant. +This class is a discriminating union that can contain one of the following values: + + - a null, or no type + - a boolean value + - an unsigned integer + - a signed integer + - a floating point value + - a string value + - a reference to a map of string to Variant + - a reference to a list of Variant + - a reference to a iovec list (Blob) + +### Features + + - Scripting language like variable (Variant) in C++ (with all the upsides and downsides that implies). + - [JSON](http://www.json.org/) serialization. + - [YAML](http://yaml.org/) serialization. Deserialization ignores most tags. + - plist serialization. + - Schema validation based on [json-schema](http://json-schema.org/). + - Schema lookup can be set to use libcurl to fetch remote URLs. + - A simple argument parsing (ArgParse) class that produces a Variant from a programs arguments. + - Experimental [msgpack](http://msgpack.org/) serialization using [msgpack-c](https://github.com/msgpack/msgpack-c) (disabled by default). + - JSONPointer (RFC6901) and JSONPatch (RFC6902) implementations. + +### Changes for the 1.0.1 release + + - Cleaned up static data initialization, will no long call abort. + - Fixed a bug related to proxy resolution when performing additional path resolution. + - Added an ignore_payload and payload_length parameter to the payload serializer helpers. + - Implemented proper JSONPointer lookup routines and changed the schema lookup to use them. + - Modified ArgParse so that positional argument can be specified in loaded configuration files. + - Added a make dist build target. + - Other minor fixes. + +### Implementation details + +Under the hood, Variant uses an explicit vtable to implement the different +behaviors with the same interface. The vtable has more types than the standard +types listed above. The additional types are a reference and proxy type. +There is also a class that is exposed to the user as VariantRef. Several of +the functions that return a Variant return a VariantRef. A VariantRef is a +Variant so const Variant & can bind to a VariantRef. But, in general Variant& +cannot bind to VariantRef as all functions that return VariantRef, return it by +value. This means that if you want a function that takes a non-const Variant as +a parameter to be used as an output parameter, the function must take a +VariantRef by value. VariantRef can be constructed from a Variant as well, so +such a function can take either a VariantRef or Variant. + +libvariant is [publicly hosted here](https://bitbucket.org/gallen/libvariant). + +Building +-------- + +This project uses CMake to generate a build system. Consult the CMake +documentation for your preferred build system generation. + +### Building on unix + +The default build system generated by CMake on unix is to use make. +To build with make simply perform the following commands where you would like the build output: + + cmake /path/to/libvariant/sources/ + make + +And to install: + make install + +The cmake configuration files use the standard cmake variables. + +### Dependencies + +libvariant is optionally dependent on the following libraries + + - [libyaml](http://pyyaml.org/wiki/LibYAML) to provide yaml serialization + - [libxml2](http://xmlsoft.org/) to provide plist serialization + - [libcurl](http://curl.haxx.se/) to provide schema web lookup + - [msgpack-c](https://github.com/msgpack/msgpack-c) for the experimental msgpack serialization + +CMake variables are provided to override the default dependency behavior. + +Schemas +------- + +This library also contains a schema validator. The language of the schema when +serialized as JSON is json-schema. See json-schema.org for details about +json-schema. Note the validator in this library uses the version 4 dialect. +The schema for the version 4 dialect can be acquired from +http://json-schema.org/draft-04/schema + +Other than a validator, there is a function to add the schema defaults to a Variant. +This function goes through the schema and attempts to add the defaults +specified in it to the Variant provided if a value is not already present. +There are several constructs that it ignores such as not. + +### Data generation from schemas + +Generating a valid set of data from schema is an interesting idea, and can be +useful for testing purposes. But this problem is rather difficult in general. +For example, the anyOf, oneOf, allOf, and not constructs in a schema mean that +it is possible that the data generator must solve a satisfiability problem. +It is well known that non-trivial satisfiability problems are NP complete. +Despite this there does exists several random data generators (but they can +fail to produce output or can produce output that does not validate). The +following are links to two of the generators I was able to find. + + - [http://schematic-ipsum.herokuapp.com/] - a web app + - [https://github.com/andreineculau/json-schema-random] - requires nodejs + +API Documentation +----------------- + +The main API is documented in the source code using the Doxygen format. +The generated html documentation is served on the web at +http://gallen.bitbucket.org/libvariant-docs. + +If you have doxygen installed, you can generate html documentation of the +libvariant public interface from the source code with: + + cd /path/to/build_dir + cmake /path/to/libvariant + make doc diff --git a/src/hos_libvariant/src/cmake/Modules/FindLibYAML.cmake b/src/hos_libvariant/src/cmake/Modules/FindLibYAML.cmake new file mode 100644 index 00000000..26ce0ef2 --- /dev/null +++ b/src/hos_libvariant/src/cmake/Modules/FindLibYAML.cmake @@ -0,0 +1,18 @@ +# CMake module to search for the libyaml library +# (library for parsing YAML files) +# If it's found it sets LIBYAML_FOUND to TRUE +# and following variables are set: +# LIBYAML_INCLUDE_DIR +# LIBYAML_LIBRARY + +find_package(PkgConfig) +pkg_check_modules(PC_LIBYAML yaml-0.1) + +find_path(LIBYAML_INCLUDE_DIR NAMES yaml.h HINTS ${PC_LIBYAML_INCLUDEDIR} + ${PC_LIBYAML_INCLUDE_DIRS}) +find_library(LIBYAML_LIBRARIES NAMES yaml libyaml + HINTS ${PC_LIBYAML_LIBDIR} ${PC_LIBYAML_LIBRARY_DIR}) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibYAML DEFAULT_MSG LIBYAML_LIBRARIES LIBYAML_INCLUDE_DIR) +MARK_AS_ADVANCED(LIBYAML_INCLUDE_DIR LIBYAML_LIBRARIES) diff --git a/src/hos_libvariant/src/cmake/Modules/FindMsgPack.cmake b/src/hos_libvariant/src/cmake/Modules/FindMsgPack.cmake new file mode 100644 index 00000000..37871bdd --- /dev/null +++ b/src/hos_libvariant/src/cmake/Modules/FindMsgPack.cmake @@ -0,0 +1,17 @@ +# - Find msgpack +# Find the native Message Pack headers and libraries. +# +# MSGPACK_INCLUDE_DIRS - where to find msgpack.hpp, etc. +# MSGPACK_LIBRARIES - List of libraries when using MsgPack. +# MSGPACK_FOUND - True if MsgPack found. + + +# Look for the header file. +FIND_PATH(MSGPACK_INCLUDE_DIR NAMES msgpack.hpp) + +# Look for the library. +FIND_LIBRARY(MSGPACK_LIBRARY NAMES msgpack libmsgpack) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(MsgPack DEFAULT_MSG MSGPACK_LIBRARY MSGPACK_INCLUDE_DIR) +MARK_AS_ADVANCED(MSGPACK_INCLUDE_DIR MSGPACK_LIBRARY) diff --git a/src/hos_libvariant/src/cmake/Modules/MakeTBZ2.cmake b/src/hos_libvariant/src/cmake/Modules/MakeTBZ2.cmake new file mode 100644 index 00000000..ec160f9e --- /dev/null +++ b/src/hos_libvariant/src/cmake/Modules/MakeTBZ2.cmake @@ -0,0 +1,13 @@ +foreach(what MAJOR MINOR PATCH) + set(ivar ${PROJECT_NAME}_${what}_VERSION) + string(TOUPPER ${ivar} ivar) + set(CPACK_PACKAGE_VERSION_${what} ${${ivar}}) +endforeach() + +set(CPACK_SOURCE_GENERATOR "TBZ2") +set(CPACK_SOURCE_PACKAGE_FILE_NAME + "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") +string(TOLOWER ${CPACK_SOURCE_PACKAGE_FILE_NAME} CPACK_SOURCE_PACKAGE_FILE_NAME) +set(CPACK_SOURCE_IGNORE_FILES + "/build*/;/.hg*;~$;CMakeCache.txt;${CPACK_SOURCE_IGNORE_FILES}") +include(CPack) diff --git a/src/hos_libvariant/src/examples/CMakeLists.txt b/src/hos_libvariant/src/examples/CMakeLists.txt new file mode 100644 index 00000000..706bc685 --- /dev/null +++ b/src/hos_libvariant/src/examples/CMakeLists.txt @@ -0,0 +1,21 @@ + +add_executable(convert convert.cc) +target_link_libraries(convert Variant ${EXTRA_LIBS}) + +add_executable(example1 example1.cc) +target_link_libraries(example1 Variant ${EXTRA_LIBS}) + +add_executable(example2 example2.cc) +target_link_libraries(example2 Variant ${EXTRA_LIBS}) + +add_executable(map_example map_example.cc) +target_link_libraries(map_example Variant ${EXTRA_LIBS}) + +add_executable(list_example list_example.cc) +target_link_libraries(list_example Variant ${EXTRA_LIBS}) + +add_executable(pretty_print pretty_print.cc) +target_link_libraries(pretty_print Variant ${EXTRA_LIBS}) + +add_executable(arg_parse arg_parse.cc) +target_link_libraries(arg_parse Variant ${EXTRA_LIBS}) diff --git a/src/hos_libvariant/src/examples/README b/src/hos_libvariant/src/examples/README new file mode 100644 index 00000000..35bf4a31 --- /dev/null +++ b/src/hos_libvariant/src/examples/README @@ -0,0 +1,23 @@ + +convert.cc: + +This example is for a program to convert between different serialization +formats. It can load JSON, YAML or plist and then save it as any of those +formats. + +example1.cc: + +A quick example of how to load YAML and JSON with the convenience interface. + +example2.cc: + +Shows some basic ways of querying for information from a Variant. + +map_example.cc: + +Shows some basic operations that you can perform on the map types. + +pretty_print.cc: + +Shows some basic examples of how to pretty print a Variant into JSON and YAML +in several different formats. diff --git a/src/hos_libvariant/src/examples/arg_parse.cc b/src/hos_libvariant/src/examples/arg_parse.cc new file mode 100644 index 00000000..abe36849 --- /dev/null +++ b/src/hos_libvariant/src/examples/arg_parse.cc @@ -0,0 +1,101 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include +#include "../../src/include/Variant/ArgParse.h" +#include "../../src/include/Variant/Schema.h" +#include "../../src/include/Variant/Variant.h" + +using namespace libvariant; +using namespace std; + +void MoreOptions(ArgParse &opts) { + opts.AddOption("/abc/a", 0, "abc-a", "libabc a").Default("a"); + opts.AddOption("/abc/b", 0, "abc-b", "libabc b").Default("b"); + opts.AddOption("/abc/c", 0, "abc-c", "libabc c"); + opts.AddGroup("abc", "libabc", "Options for libabc").Add("/abc/a").Add("/abc/b") + .Add("/abc/c"); + opts.AddGroup("abc-exclusive").Add("/abc/b").Add("/abc/c").MutuallyExclusive(); +} + +int main(int argc, char **argv) { + + SerializeType stype = SERIALIZE_JSON; + Variant params = Variant().Set("pretty", true); + + ArgParse opts(argv[0]); + + opts.SetDescription("An example application that uses ArgParse."); + opts.SetEpilog("An epilog of the help text!"); + opts.AddConfigDefaults(); + + opts.AddOption("foo-key", 'f', "foo", "What to foo with.").Action(ARGACTION_APPEND) + .Type(ARGTYPE_FLOAT).Default(0.1234).Minimum(0); + // Defines an option --foo or -f that takes a number argument, which is 0.1234 + // if not specified and has a minimum value of 0 + + opts.AddOption("bar-key", 'b', "bar", "The bar.") + .Default("frobnar!").MaxLength(100).Pattern("[A-Za-z]*!") + .Env("BAR"); + // Defines an option --bar or -b that takes a string argument that + // may be any alphastring ending in an ! up to 100 characters in length. + + opts.AddOption("blurt-key", 0, "blurt", "BLURT!") + .AddChoice("furble").AddChoice("murble").AddChoice("durble") + .Default("durble"); + // Defines an option --blurt that can take the string values + // 'furble', 'murble', or 'durble' and will error on any other. + + opts.AddFlag("recursive", 'r', "recurse", "Do operation recursively"); + // Add an option -r that sets true if present and false if not + // Same as opts.AddOption("recursive, 'r', "recurse", "Do operation recursively") + // .Action(ARGACTION_STORE_TRUE).Type(ARGTYPE_BOOL).Default(false); + + opts.AddOption("verbose", 'v', "verbose", "Increase verbosity one level.") + .Action(ARGACTION_COUNT); + + opts.AddOption("quiet", 'q', "quiet", "Decrease verbosity one level.") + .Action(ARGACTION_COUNT); + + MoreOptions(opts); + + opts.AddArgument("host", "Hostname").Type(ARGTYPE_STRING).Action(ARGACTION_STORE); + opts.AddArgument("port", "Port number or name").Type(ARGTYPE_STRING).Action(ARGACTION_STORE); + opts.AddArgument("XXX", "Message IDs").Type(ARGTYPE_INT).Action(ARGACTION_APPEND) + .Minimum(0).MinArgs(1).MaxArgs(0); + // Define that the program takes at least 3 positional arguments, + // the first being a string which will be stored in host, a port name + // which will be a string stored in port and a list of positive integers + // which will be stored as a list in key XXX. + + // An example for a single positional optional argument (can have no + // required arguments after it): + // opts.AddArgument("msgid", "Message ID").Type(ARGTYPE_INT).Default(10) + // .Minimum(0).MinArgs(0); + + cout << "The description:\n"; + Serialize(cout.rdbuf(), opts.GetDescription(), stype, params); + cout << endl; + cout << "The generated schema for the parsed arguments:\n"; + Variant schema = opts.GenerateSchema(); + Serialize(cout.rdbuf(), schema, stype, params); + cout << endl; + + opts.Validate(); + cout << "Now parsing the arguments..." << endl; + Variant args = opts.Parse(argc, argv); + + int verbosity = 1 + args.Get("verbose", 0).As() - args.Get("quiet", 0).As(); + + cout << "Using verbosity " << verbosity << endl; + + cout << "The parsed arguments then look like:\n"; + Serialize(cout.rdbuf(), args, stype, params); + cout << endl; + SchemaResult validate_result = SchemaValidate(schema, args); + cout << "Does it validate? " << (validate_result.Error() ? "no" : "yes") << endl; + if (validate_result.Error()) { cout << validate_result << endl; } + return 0; +} diff --git a/src/hos_libvariant/src/examples/convert.cc b/src/hos_libvariant/src/examples/convert.cc new file mode 100644 index 00000000..5dfd9180 --- /dev/null +++ b/src/hos_libvariant/src/examples/convert.cc @@ -0,0 +1,99 @@ +/** \file + * \author John Bridgman + * \brief A simple convert utility that can read in + * the json, yaml or xml formats and then write out + * any of those formats. + */ +#include +#include +#include +#include "../../src/include/Variant/Variant.h" + +using namespace libvariant; + +int main(int argc, char **argv) { + enum Op { + NOOP, + JSON, YAML, XML + }; + SerializeType input = SERIALIZE_YAML; + SerializeType output = SERIALIZE_YAML; + Variant params = Variant::MapType; + params["pretty"] = true; + while (true) { + int c = getopt(argc, argv, "jyxJYXhp:"); + if (c == -1) { break; } + switch (c) { + case 'j': + input = SERIALIZE_JSON; + break; + case 'y': + input = SERIALIZE_YAML; + break; + case 'x': + input = SERIALIZE_XMLPLIST; + break; + case 'J': + output = SERIALIZE_JSON; + break; + case 'Y': + output = SERIALIZE_YAML; + break; + case 'X': + output = SERIALIZE_XMLPLIST; + break; + case 'p': + params["pretty"] = Variant(optarg).AsBool(); + break; + case 'h': + default: + printf("Usage: %s [options] infile outfile\n", *argv); + printf("Options:\n" + "\t-j|-y|-x Specify the input format, JSON, YAML or XML plist\n" + "\t-J|-Y|-X Specify the output format, JSON, YAML or XML plist\n" + "\t-p true|false Set pretty printing (default true)\n" + "Leaving out the input or putput file or specifying it as -\n" + "will use stdin or stdout instead.\n"); + return 0; + } + } + + FILE *in = stdin; + const char *in_file = 0; + if (optind < argc) { + in_file = argv[optind]; + if (strlen(in_file) == 1 && in_file[0] == '-') { + in_file = 0; + } + } + if (in_file) { + in = fopen(in_file, "r"); + if (!in) { + fprintf(stderr, "Unable to open %s\n", in_file); + return 1; + } + } + FILE *out = stdout; + const char *out_file = 0; + if (optind + 1 < argc) { + out_file = argv[optind + 1]; + if (strlen(out_file) == 1 && out_file[0] == '-') { + out_file = 0; + } + } + if (out_file) { + out = fopen(in_file, "w"); + if (!out) { + fprintf(stderr, "Unable to open %s\n", out_file); + return 1; + } + } + + Variant v; + v = DeserializeFile(in, input); + + Serialize(out, v, output, params); + + return 0; +} + diff --git a/src/hos_libvariant/src/examples/example1.cc b/src/hos_libvariant/src/examples/example1.cc new file mode 100644 index 00000000..d0c2dee2 --- /dev/null +++ b/src/hos_libvariant/src/examples/example1.cc @@ -0,0 +1,37 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include +#include "../../src/include/Variant/Variant.h" + +// Import Variant from libvariant +using libvariant::Variant; + +// Example strings to use +const char *example_json_string = +"{\"key1\": \"value1\",\"key2\":1.23,\"list\":[1,2,3,4]}"; + +const char *example_yaml_string = +"key1: value1\n" +"key2: 1.23\n" +"list: [ 1, 2, 3, 4]\n" +; + +int main(int argc, char **argv) { + // Load the example_json_string onto ex1 + Variant ex1 = libvariant::DeserializeJSON(example_json_string); + // Load the example yaml string + Variant ex2 = libvariant::DeserializeYAML(example_yaml_string); + // They are the same + if (ex1 != ex2) { + printf("Differ!\n"); + return 1; + } + + // Pretty print to stdout + libvariant::SerializeJSON(stdout, ex2, true); + + return 0; +} diff --git a/src/hos_libvariant/src/examples/example2.cc b/src/hos_libvariant/src/examples/example2.cc new file mode 100644 index 00000000..629349b9 --- /dev/null +++ b/src/hos_libvariant/src/examples/example2.cc @@ -0,0 +1,50 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include +#include "../../src/include/Variant/Variant.h" + +using libvariant::Variant; + +int main(int argc, char **argv) { + if (argc != 2) { + printf("Usage: %s input_file\n", *argv); + return 1; + } + const char *file_name = argv[1]; + Variant v = libvariant::DeserializeYAMLFile(file_name); + + // Now lets examine the variant + if (v.IsMap()) { + printf("The variant is a map of length %u with keys:\n", v.Size()); + bool contains_complex_type = false; + // Maps are internally just std::map + for (Variant::MapIterator i(v.MapBegin()), e(v.MapEnd()); i!=e; ++i) { + printf("\"%s\" ", i->first.c_str()); + switch (i->second.GetType()) { + case Variant::MapType: + case Variant::ListType: + contains_complex_type = true; + break; + default: + break; + } + } + printf("\n"); + if (contains_complex_type) { + printf("The map contains non scalar types.\n"); + } + } else if (v.IsList()) { + printf("The variant is a list of length %u\n", v.Size()); + // Lists are also internally std::vector + // Can use v.ListBegin and v.ListEnd for iterators + // and Variant::ListIterator for the iterator type + } else { + printf("The read in variant is neither a list nor a map.\nIts string value is: %s\n", v.AsString().c_str()); + } + + + return 0; +} diff --git a/src/hos_libvariant/src/examples/list_example.cc b/src/hos_libvariant/src/examples/list_example.cc new file mode 100644 index 00000000..52831ddd --- /dev/null +++ b/src/hos_libvariant/src/examples/list_example.cc @@ -0,0 +1,29 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include + +#include "../../src/include/Variant/Variant.h" +using libvariant::Variant; + +int main(int argc, char **argv) { + Variant list; + // Can assign the type to a variant to "force" it to be + // that type. The type will loose any value it had (i.e., + // a list will be empty, maps will be empty, numbers will have + // an indeterminate value, etc.) + list = Variant::ListType; + list[0] = true; + list[2] = "abc"; + // Note that now the list is [true, null, "abc"] + // Lists are extended automatically to the length that they are referred to. + list.Append(123); + // Appending to the list + + for (unsigned i = 0; i < list.Size(); ++i) { + std::cout << list[i].AsString() << std::endl; + } + return 0; +} + diff --git a/src/hos_libvariant/src/examples/map_example.cc b/src/hos_libvariant/src/examples/map_example.cc new file mode 100644 index 00000000..dabe886a --- /dev/null +++ b/src/hos_libvariant/src/examples/map_example.cc @@ -0,0 +1,48 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include +#include + +#include "../../src/include/Variant/Variant.h" +using libvariant::Variant; + +int main(int argc, char **argv) { + Variant map; + // The type of a Variant with the default constructor is the NullType + assert(map.IsNull()); + // Treating a NullType as some type converts it to that type + map["key"] = "value"; + map["doo"] = 1.2345; + map["bar"] = 123; + map["foo"] = true; + Variant map2; + map2["ubar"] = 12u; + + map.Merge(map2); + // Set all the key value pairs in map2 into map. + + + if (map.Contains("doo")) { + // the key "doo" is in the map + } + + Variant doodaa = map.Get("doodaa", true); + // Get checks if doodaa is in the map and if not it returns the second + // parameter. + assert(doodaa.IsTrue()); + + Variant val = map["blah"]; + // "blah" was not in the map so val is of NullType + // But "blah" has been added to the map as NullType because Variant can't + // tell if your assigning or referencing with the [] operator + assert(val.IsNull()); + // But then we can erase it + map.Erase("blah"); + + for (Variant::MapIterator i(map.MapBegin()), e(map.MapEnd()); i!=e; ++i) { + std::cout << i->first << ": " << i->second.AsString() << std::endl; + } + return 0; +} diff --git a/src/hos_libvariant/src/examples/pretty_print.cc b/src/hos_libvariant/src/examples/pretty_print.cc new file mode 100644 index 00000000..2bb04755 --- /dev/null +++ b/src/hos_libvariant/src/examples/pretty_print.cc @@ -0,0 +1,40 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include +#include +#include "../../src/include/Variant/Variant.h" + +using namespace libvariant; + +const char example_string[] = "--- { id: [ 1,2 ,3, 4], names: [ foo, bar, gar, mar ], twiddle: true, swizzle: 1.24456e-4," +" subs: [1, 2, [ 1, 2, [ {a: b}, 2 ]]] }"; + +const char styles[] = "any\0block\0flow\0"; + +int main(int argc, char **argv) { + Variant val = Deserialize(example_string, SERIALIZE_YAML); + std::cout << "--- Pretty printing JSON to stdout using generic serialize function\n"; + Variant param; + param["pretty"] = true; + param["indent"] = 2; + Serialize(std::cout.rdbuf(), val, SERIALIZE_JSON, param); + std::cout << std::endl; + param.Clear(); + //param["width"] = 10; + for (const char *mstyle = &styles[0];*mstyle; mstyle += strlen(mstyle) + 1) { + for (const char *lstyle = &styles[0];*lstyle; lstyle += strlen(lstyle) + 1) { + param["map_style"] = mstyle; + param["list_style"] = lstyle; + std::cout << "--- Pretty print YAML to stdout using generic serilize function\n" + << "With params: "; + Serialize(std::cout.rdbuf(), param, SERIALIZE_JSON); + std::cout << std::endl; + Serialize(std::cout.rdbuf(), val, SERIALIZE_YAML, param); + std::cout << std::endl; + } + } + + return 0; +} diff --git a/src/hos_libvariant/src/include/Variant/ArgParse.h b/src/hos_libvariant/src/include/Variant/ArgParse.h new file mode 100644 index 00000000..97e0a17b --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/ArgParse.h @@ -0,0 +1,301 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_ARGPARSER_H +#define VARIANT_ARGPARSER_H +#pragma once +#include +#include +#include +namespace libvariant { + + + enum ArgParseAction { + ARGACTION_UNKNOWN, // Unknown action (invalid) + ARGACTION_STORE, // Interpret the option argument and store it at the path + ARGACTION_STORE_CONST, // Store const into the path + ARGACTION_STORE_TRUE, // Store true into the path + ARGACTION_STORE_FALSE, // Store false into the path + ARGACTION_APPEND, // Append the option argument to the list at path + ARGACTION_COUNT, // Make the value at path be the count of this options occurrences + ARGACTION_HELP, // Print out the help text and exit + ARGACTION_ADVHELP, // Print the advanced help and exit + ARGACTION_CONFIG, // Consider the option argument a filename to be loaded and parsed as a config + ARGACTION_CONFIG_JSON, // force parser to use jscn + ARGACTION_CONFIG_YAML, // force parser to use yaml + ARGACTION_CONFIG_PLIST, // force parser to use xmlplist + ARGACTION_PRINT_CONFIG // At the end of parsing print out the resulting config and exit. + }; + + // A constrained list of only the valid types for ArgParse + enum ArgParseType { + ARGTYPE_GUESS = Variant::NullType, // No type specification, guess, uses deserialize machinery + ARGTYPE_INT = Variant::IntegerType, // Error if it cannot be turned into an integer + ARGTYPE_UINT = Variant::UnsignedType, // Error if it cannot be turned into a unsigned + ARGTYPE_FLOAT = Variant::FloatType, // Error if it cannot be turned into a float + ARGTYPE_STRING = Variant::StringType, // store as string + ARGTYPE_BOOL = Variant::BoolType // Error if it cannot be turned into a boolean type + // it treats 0 or the strings 'false' and 'no' or any substring ignoring case as false + // and everything else as true + }; + + //! Valid values are: + // This is used for converting the enum to a Variant and back for + // ArgParse::GetDescription and ArgParse::Merge + // store -- store the value into the key (default) + // store_const -- store const (see Const) into the key + // store_true -- store true into the key (i.e. no option argument) + // store_false -- store false into the key + // append -- make the value a list of instances of the option + // count -- count the number of instances of this argument + // help -- display the help text and exit + // config -- load a file and merge it into the result (uses GuessFormat) + // config_json -- same as config, force to use json parser + // config_yaml -- same as config, force to use yaml parser + // config_plist -- same as config, force to use xml-plist parser + // config_print -- when finished parsing, print out the config and exit + ArgParseAction ArgParseActionFromStr(const std::string &action); + std::string ArgParseActionToStr(ArgParseAction action); + + class ArgParse; + struct ArgParseImpl; + struct ArgParseOptImpl; + struct ArgParseGroupImpl; + + //! ArgParseOption is a part of class ArgParse. + // ArgParseOption is the interface that ArgParse provides to the user to be able + // to conveniently set the options for an option. + class ArgParseOption { + public: + + //! Set the title of this option. The title is used + // as an argument placeholder string. + ArgParseOption &Title(const std::string &title); + + //! What action to perform when this option is encountered. + // See ArgParseAction above for a list of actions. + ArgParseOption &Action(ArgParseAction action); + DEPRECATED ArgParseOption &Action(const std::string &action); + + //! Set the type parsing and validation. + // If set and the argument is not of this type, then it is invalid. + // Default: ARGTYPE_GUESS + // If type is ARGTYPE_GUESS then ArgParse attempts to parse the + // argument with the same machinery that is used by the deserializers + // to figure out the type of a scalar. + // ARGTYPE_UINT is the same as ARGTYPE_INT but with + // Minimum set to 0. + // See ArgParseType for the list of valid types. + ArgParseOption &Type(ArgParseType type); + // Same as above but throws on invalid type + DEPRECATED ArgParseOption &Type(Variant::Type_t type); + // String version of the above + // Valid types are "string", "number", "integer", "boolean", or "null". + // Default type is "null". + DEPRECATED ArgParseOption &Type(const std::string &type); + + //! Set the const value for "store_const" + ArgParseOption &Const(Variant val); + + //! Set the default value used when the option is not set. + ArgParseOption &Default(Variant val); + + //! Set the environment variable name to check for a value for this option. + // When the environment variable is present this acts like Default was set + // to the environment variable's value. I.e., this overrides default, + // command line arguments override this. + ArgParseOption &Env(const char *env); + + //! If the resulting value is a number, require to be at least this minimum. + ArgParseOption &Minimum(Variant val); + + //! If the resulting value is a number, require to be at most this maximum. + ArgParseOption &Maximum(Variant val); + + //! Add choices. + // If a choice is added, the value of the option must be one of the choices. + ArgParseOption &AddChoice(Variant val); + + //! Set choices (old ones forgotten) from a vector. + ArgParseOption &SetChoices(const std::vector &val); + + //! Return the vector of choices set. + const std::vector &GetChoices(); + + //! Is this option required? + ArgParseOption &Required(bool req=true); + + //! Set the help text for this option. + ArgParseOption &Help(const std::string &helptxt); + + //! If this option is a string, it must match the regex in pattern. + ArgParseOption &Pattern(const std::string &pattern); + + //! If this option is a string, it must be no longer than maxLength. + ArgParseOption &MaxLength(unsigned l); + + //! If this option is a string, it must be no shorter than minLength. + ArgParseOption &MinLength(unsigned l); + + //! If this option can be specified multiple times, it must be + // specified minArgs times at least. + // A value of 0 means zero arguments is valid. + ArgParseOption &MinArgs(unsigned l); + + //! If this option can be specified multiple times, it cannot be + // specified more than maxArgs. + // A value of 0 means any number + ArgParseOption &MaxArgs(unsigned l); + + //! Specify that this argument must be present l times. + // Sets both minArgs and maxArgs to l + ArgParseOption &NumArgs(unsigned l); + + //! Adds this option to group gname. If gname does not exist, + //it will be created with an empty title and description. + ArgParseOption &Group(const std::string &gname); + + //! Sets this argument to be an advanced option + // This hides the option when not printing advanced options + ArgParseOption &Advanced(bool adv = true); + + private: + ArgParseOption(ArgParseOptImpl *i) : impl(i) {} + ArgParseOptImpl *impl; + friend class ArgParse; + }; + + //! Groups are a way to organize the option and to provide mutual exclusion + //of option. An argument may be part of more than one group, but may only + //be part of one group that has a non-empty title and description. An + //attempt is made to order the help text so that options within the same + //group appear together and if a group has a title and/or description the + //options are placed within a subsection headed with the title and + //description. + class OptionGroup { + public: + //! Set the title for this group + OptionGroup &Title(const std::string &t); + //! Set the description for this group + OptionGroup &Description(const std::string &d); + //! Set that the options in this group are mutually exclusive + OptionGroup &MutuallyExclusive(bool exclusive=true); + //! Set that at least one option in this group is required. + //Has no meaning when the group is not mutually exclusive. + OptionGroup &Required(bool req=true); + + OptionGroup &Add(const std::string &keypath); + OptionGroup &Add(const Path &keypath); + + //! Sets this option group to be advanced + // Hide the group when not printing advanced options. + // This only hides the group when it has a title or description + OptionGroup &Advanced(bool adv=true); + private: + OptionGroup(ArgParseGroupImpl *i) : impl(i) {} + ArgParseGroupImpl *impl; + friend class ArgParse; + }; + + class ArgParse { + public: + //! addhelp true causes AddHelp to be called. + ArgParse(bool addhelp=true); + ArgParse(const std::string &pname, bool addhelp=true); + + //! Add the option and configure it as an option that takes an argument. + //The default action will be "store" and type will be unspecified + // + // keypath must be a valid path as defined in Path.h + // + // For no short option, shortOpt may be 0, and for no long option, longOpt may be + // the empty string. If both shortOpt is 0 and longOpt is empty then this option + // is hidden unless Env is also set for the option. + ArgParseOption AddOption(const std::string &keypath, int shortOpt, const std::string &longOpt="", + const std::string &helptxt=""); + + //! Convenience methods for getting an existing option. + // ArgParse args(argv[0]); + // args.AddOption("key1", 'k', "key1", "how many things").Type("integer"); + // args.AddOption("key2", 'K', "key2", "what to name it").Type("string"); + // (... some intermediate code ...) + // args.At("key1").Default(42); + // args["key2"].Default("foo"); + ArgParseOption At(const std::string &keypath); + ArgParseOption operator[](const std::string &keypath) { return At(keypath); } + + //! Add the option and configure it as an option that is default false and + //if present sets to true + //i.e., same as: + // AddOption(keypath, shortOpt, longOpt, helptxt).Type("boolean") + // .Action("store_true").Default(false); + ArgParseOption AddFlag(const std::string &keypath, int shortOpt, const std::string &longOpt="", + const std::string &helptxt=""); + + //! Adds the group name. + OptionGroup AddGroup(const std::string &name, const std::string &title="", const std::string &description=""); + //! Returns the group name. + OptionGroup GetGroup(const std::string &name); + + //! Add a positional argument. + // By default the new positional argument will have NumArgs as 1. + // Arguments are processed in the order they are added. + // If maxArgs is 0, then no positional arguments after this one will + // be processed. + // Default action is store. + ArgParseOption AddArgument(const std::string &keypath, const std::string &helptxt=""); + + //! Convenience methods for getting an existing argument. + // ArgParse args(argv[0]); + // args.AddArgument("arg0", "pick one").AddChoice("AAA").AddChoice("BBB"); + // args.AddArgument("arg1", "scale factor").Type("float"); + // (... some intermediate code ...) + // args.At(0).AddChoice("CCC"); + // args[1].Default(0.456); + ArgParseOption At(size_t argumentIndex); + ArgParseOption operator[](size_t argumentIndex) { return At(argumentIndex); } + + //! When this is on, trying to add a second option with the same short option + //will cause the second option to act as though it had no short option specified. + void ConflictResolution(bool resolve=true); + + //! Add a --config and --print-config option + // --config is set with action ARGACTION_CONFIG and + // --print-config is set with action ARGACTION_PRINT_CONFIG + void AddConfigDefaults(); + + //! Add -h,--help option with action ARGACTION_HELP + void AddHelp(); + + //! Set the description text that follows the usage message. + void SetDescription(const std::string &txt); + //! Set the epilog text at the end of help. + void SetEpilog(const std::string &txt); + //! Override the default program name. + void SetProgramName(const std::string &pname, bool do_basename=true); + std::string GetProgramName() const; + + void Merge(Variant newopts); + void Merge(const ArgParse &other); + + //! Validate the argparse description against the internal schema + void Validate() const; + + //! Parse the arguments with the internal description + Variant Parse(int argc, char *const *argv); + + //! Print the help message and exit. + void PrintHelp(bool advanced=false) const; + + //! Return the Variant that describes the arguments + Variant GetDescription() const; + + //! Generate a schema for the Variant returned by Parse from the argument description + Variant GenerateSchema() const; + + private: + shared_ptr impl; + }; +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/Blob.h b/src/hos_libvariant/src/include/Variant/Blob.h new file mode 100644 index 00000000..b2706e4d --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/Blob.h @@ -0,0 +1,63 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_BLOB_H +#define VARIANT_BLOB_H + +#pragma once +#include "../../../src/include/Variant/SharedPtr.h" +#include +#include + +namespace libvariant { + class Blob; + typedef shared_ptr BlobPtr; + typedef shared_ptr ConstBlobPtr; + + typedef void (*BlobFreeFunc)(void *ptr, void *ctx); + + class Blob { + public: + + /// Reference the buffer and call ffunc when Blob no longer references it + static BlobPtr Create(void *ptr, unsigned len, BlobFreeFunc ffunc, void *context); + /// Will call ffunc on each buffer in iov + static BlobPtr Create(struct iovec *iov, unsigned iov_len, BlobFreeFunc ffunc, void *context); + /// Copy the data into a newly allocatd buffer + static BlobPtr CreateCopy(const void *ptr, unsigned len); + static BlobPtr CreateCopy(const struct iovec *iov, unsigned iov_len); + /// Reference the buffer and when done call free to free the buffer + static BlobPtr CreateFree(void *ptr, unsigned len); + static BlobPtr CreateFree(struct iovec *iov, unsigned iov_len); + /// Reference the buffer, assume static or other allocation lifetime where + // calling a free function is not required + static BlobPtr CreateReferenced(void *ptr, unsigned len); + static BlobPtr CreateReferenced(struct iovec *iov, unsigned iov_len); + ~Blob(); + + BlobPtr Copy() const; + + void *GetPtr(unsigned i) { return iov[i].iov_base; } + const void *GetPtr(unsigned i) const { return iov[i].iov_base; } + unsigned GetLength(unsigned i) const { return iov[i].iov_len; } + struct iovec *GetIOVec() { return &iov[0]; } + const struct iovec *GetIOVec() const { return &iov[0]; } + unsigned GetNumBuffers() const { return iov.size(); } + unsigned GetTotalLength() const; + + int Compare(ConstBlobPtr other) const; + + private: + Blob(); + Blob(const Blob&); + Blob(struct iovec *v, unsigned l, BlobFreeFunc f, void *c); + Blob operator=(const Blob&); + + std::vector iov; + BlobFreeFunc free_func; + void *ctx; + }; + +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/Emitter.h b/src/hos_libvariant/src/include/Variant/Emitter.h new file mode 100644 index 00000000..1b113470 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/Emitter.h @@ -0,0 +1,226 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_EMITTER_H +#define VARIANT_EMITTER_H + +#pragma once +#include +#include +#include +#include +#include "../../../src/include/Variant/Variant.h" +#include "../../../src/include/Variant/Blob.h" +#include "../../../src/include/Variant/EmitterOutput.h" +#include +#include + +namespace libvariant { + + /** + * Class to override to implement an Emitter + */ + class EmitterImpl { + public: + virtual ~EmitterImpl(); + + virtual void BeginDocument() = 0; + virtual void EndDocument() = 0; + virtual void BeginMap(int length) = 0; + virtual void EndMap() = 0; + virtual void BeginList(int length) = 0; + virtual void EndList() = 0; + + virtual void EmitNull() = 0; + virtual void EmitTrue() = 0; + virtual void EmitFalse() = 0; + virtual void Emit(const char *v) = 0; + virtual void Emit(intmax_t v) = 0; + virtual void Emit(uintmax_t v) = 0; + virtual void Emit(double v) = 0; + virtual void Emit(ConstBlobPtr b) = 0; + + virtual void Flush() = 0; + virtual void Close() = 0; + + virtual Variant GetParam(const std::string &key) = 0; + virtual Variant GetParams() = 0; + virtual void SetParam(const std::string &key, Variant value) = 0; + virtual void SetParams(Variant params); + }; + + /** + * Actual emitter class. + */ + class Emitter { + public: + Emitter(); + Emitter(shared_ptr i); + ~Emitter(); + + Emitter &BeginDocument(); + Emitter &EndDocument(); + + //Some emitter implementations require the length of the map at the + //beginning. Such implementations should buffer events if length == -1 + //Implementations are free to ignore the length. + Emitter &BeginMap() { return BeginMap(-1); } + Emitter &BeginMap(int length); + Emitter &EndMap(); + //Some emitter implementations require the length of the list at the + //beginning. Such implementations should buffer events if length == -1 + Emitter &BeginList() { return BeginList(-1); } + Emitter &BeginList(int length); + Emitter &EndList(); + + Emitter &EmitNull(); + Emitter &EmitTrue(); + Emitter &EmitFalse(); + Emitter &Emit(bool v) { return (v ? EmitTrue() : EmitFalse()); } + Emitter &Emit(const std::string &v); + Emitter &Emit(const char *v); + Emitter &Emit(intmax_t v); + Emitter &Emit(uintmax_t v); + Emitter &Emit(double v); + Emitter &Emit(ConstBlobPtr b); + + void Flush(); + void Close(); + + /// Get the value of parameters of the parser (e.g. pretty printing, + // styles, etc.) + // See individual emitter below for supported values. + Variant GetParam(const std::string &key); + /// Get a dict of all parameters + Variant GetParams(); + /// Set the value of parameters. + // See individual emitter below for supported values. + void SetParam(const std::string &key, Variant value); + /// Set all parameters from a dict + void SetParams(Variant params); + /// Internal/advanced function to get the underlying implementation + shared_ptr GetImpl() { return impl; } + private: + shared_ptr impl; + }; + + template + inline Emitter &operator<<(Emitter &e, const std::vector &v) { + e.BeginList(v.size()); + for (typename std::vector::const_iterator i(v.begin()), end(v.end()); i!=end; i++) { + e << *i; + } + e.EndList(); + return e; + } + + template + inline Emitter &operator<<(Emitter &e, const std::map &v) { + e.BeginMap(v.size()); + for (typename std::map::const_iterator i(v.begin()), end(v.end()); i!=end; ++i) { + e.Emit(i->first); + e << i->second; + } + e.EndMap(); + return e; + } + inline Emitter &operator<<(Emitter &e, bool v) { e.Emit(v); return e; } + inline Emitter &operator<<(Emitter &e, char v) { e.Emit(intmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, short v) { e.Emit(intmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, int v) { e.Emit(intmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, long v) { e.Emit(intmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, long long v) { e.Emit(intmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, unsigned char v) { e.Emit(uintmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, unsigned short v) { e.Emit(uintmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, unsigned int v) { e.Emit(uintmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, unsigned long v) { e.Emit(uintmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, unsigned long long v) { e.Emit(uintmax_t(v)); return e; } + inline Emitter &operator<<(Emitter &e, const char *v) { e.Emit(v); return e; } + inline Emitter &operator<<(Emitter &e, const std::string &v) { e.Emit(v); return e; } + inline Emitter &operator<<(Emitter &e, float v) { e.Emit(double(v)); return e; } + inline Emitter &operator<<(Emitter &e, double v) { e.Emit(v); return e; } + inline Emitter &operator<<(Emitter &e, ConstBlobPtr v) { e.Emit(v); return e; } + + shared_ptr CreateEmitterOutput(void *ptr, unsigned len, unsigned *out_len=0); + shared_ptr CreateEmitterOutput(const char *filename); + shared_ptr CreateEmitterOutput(FILE *f); + shared_ptr CreateEmitterOutput(std::streambuf *sb); + + /** + * Create an Emiter that Emits the format specified by type. + * Supported parameters are dependent on type (see below). + */ + Emitter CreateEmitter(shared_ptr o, SerializeType type, Variant params = Variant::NullType); + + /** + * Create an Emitter that Emits the JSON format. + * + * Supported parameters are: + * "pretty": boolean + * "indent": integer (number of spaces to indent when pretty is on, + * default 4) + * "precision": integer (number of digits for floats) + * "strict": be more strict about emitting correct json + */ + Emitter JSONEmitter(shared_ptr o, Variant params = Variant::NullType); + + /** + * Supported parameters are (first is default): + * + * "scalar_style": "any"|"plain"|"single quoted"|"double + * quoted"|"literal"|"folded" + * + * "map_style": "any"|"block"|"flow" + * + * "list_style": "any"|"block"|"flow" + * + * "implicit_document_begin": false|true + * + * "implicit_document_end": false|true + * + * "indent": integer (number of spaces to indent) + * + * "width": integer (set prefered line width) + * + * "precision": integer (number of digits for floats) + */ + Emitter YAMLEmitter(shared_ptr o, Variant params = Variant::NullType); + + /** + * Supported params are: + * + * "pretty": true|false + * "indent": integer (amount to indent for pretty) + * "precision": integer (number of digits for floats) + */ + Emitter XMLPLISTEmitter(shared_ptr o, Variant params = Variant::NullType); + /** + * Supported params are: + * + * "precision": integer (number of digits for floats) + */ + Emitter BundleHdrEmitter(shared_ptr o, Variant params = Variant::NullType); + + /** + * No parameters supported. + */ + Emitter MsgPackEmitter(shared_ptr o, Variant params = Variant::NullType); +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/EmitterOutput.h b/src/hos_libvariant/src/include/Variant/EmitterOutput.h new file mode 100644 index 00000000..ffc5b1e8 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/EmitterOutput.h @@ -0,0 +1,87 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + * + * The end user should not need to look at this file unless they are + * creating custom outputs for the emitters. + */ +#ifndef VARIANT_EMITTEROUTPUT_H +#define VARIANT_EMITTEROUTPUT_H +#pragma once +#include +#include + +namespace libvariant { + + class EmitterOutput { + public: + virtual ~EmitterOutput(); + /// Return the number of bytes written, or throw an exception + virtual unsigned Write(const void *ptr, unsigned len) = 0; + virtual void Flush() {} + virtual unsigned NumBytesWritten() const = 0; + }; + + class EmitterFileOutput : public EmitterOutput { + public: + EmitterFileOutput(FILE *f, bool c); + ~EmitterFileOutput(); + virtual unsigned Write(const void *ptr, unsigned len); + virtual void Flush(); + virtual unsigned NumBytesWritten() const { return num_bytes; } + protected: + FILE *file; + unsigned num_bytes; + bool cls; + }; + + class EmitterFilenameOutput : public EmitterFileOutput { + public: + EmitterFilenameOutput(const char *filename, const char *mode="w"); + }; + + class EmitterStreambufOutput : public EmitterOutput { + public: + EmitterStreambufOutput(std::streambuf *sb, bool d); + ~EmitterStreambufOutput(); + virtual unsigned Write(const void *ptr, unsigned len); + virtual void Flush(); + virtual unsigned NumBytesWritten() const { return num_bytes; } + protected: + std::streambuf *streambuf; + unsigned num_bytes; + bool del; + }; + + class EmitterMemoryOutput : public EmitterOutput { + public: + EmitterMemoryOutput(void *ptr, unsigned len, unsigned *out_len = 0); + + virtual unsigned Write(const void *ptr, unsigned len); + + virtual unsigned NumBytesWritten() const { return *out_length; } + protected: + void *data_ptr; + unsigned length; + unsigned out_length_dummy; + unsigned *out_length; + }; + +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/Exceptions.h b/src/hos_libvariant/src/include/Variant/Exceptions.h new file mode 100644 index 00000000..20c33383 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/Exceptions.h @@ -0,0 +1,88 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_EXCEPTIONS_H +#define VARIANT_EXCEPTIONS_H +#include +#include +#include + +#include "../../../src/include/Variant/VariantDefines.h" +namespace libvariant { + + /// \brief Exception thrown when a key does not exist. + class KeyError : public std::runtime_error { + public: + KeyError(const std::string &key) throw(); + }; + + /// \brief Exception thrown when internal state is corrupt. + class UnknownTypeError : public std::runtime_error { + public: + UnknownTypeError(VariantDefines::Type_t type) throw(); + }; + + /// \brief Exception thrown when a function expects a specific type but the action type conflicts. + class UnexpectedTypeError : public std::runtime_error { + public: + UnexpectedTypeError(VariantDefines::Type_t expected, VariantDefines::Type_t value) throw(); + UnexpectedTypeError(const std::vector &expected, VariantDefines::Type_t value) throw(); + }; + + /// \brief Exception thrown when a function cannot convert the Variant to an acceptable type for the routine. + class UnableToConvertError : public std::runtime_error { + public: + UnableToConvertError(VariantDefines::Type_t sourcetype, const std::string &targettype) throw(); + }; + + /// \brief Exception thrown when trying to index a type other than map or list. + class TypeNotIndexableError : public std::runtime_error { + public: + TypeNotIndexableError(VariantDefines::Type_t type) throw(); + }; + + /// \brief Exception thrown when attempting a numeric operation on a non numeric type. + class NotNumericTypeError : public std::runtime_error { + public: + NotNumericTypeError(VariantDefines::Type_t type) throw(); + }; + + /// \brief Exception thrown from path functions + class BadPathError : public std::runtime_error { + public: + BadPathError(VariantDefines::Type_t type) throw(); + BadPathError(const std::string &msg) throw(); + }; + + class InvalidReferenceError : public std::runtime_error { + public: + InvalidReferenceError(const std::string &msg) throw(); + }; + + class InvalidOperationError : public std::runtime_error { + public: + InvalidOperationError(VariantDefines::Type_t type, const std::string &opname) throw(); + }; + + std::ostream &operator <<(std::ostream &os, VariantDefines::Type_t type); + + void AddStackTrace(std::ostream &os, int level); +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/Extensions.h b/src/hos_libvariant/src/include/Variant/Extensions.h new file mode 100644 index 00000000..a3f615bc --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/Extensions.h @@ -0,0 +1,92 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author Josh Staley + * \brief Useful extension functions for Variant + */ + +#ifndef VARIANT_EXTENSIONS_H +#define VARIANT_EXTENSIONS_H + +#include "../../../src/include/Variant/Variant.h" + +namespace libvariant { + + /// \brief Returns a default parameters for use with FlattenPath and ExpandPath functions. + Variant ExtensionParams(); + + /// \brief Sets any missing Extension parameters to 'params' for use with FlattenPath and ExpandPath functions. + void ExtensionParams( VariantRef params ); + + /// \brief Returns a version of 'var' with flat paths based on 'params' + Variant FlattenPath( const Variant &var, Variant params = ExtensionParams() ); + + /// \brief Returns a version of 'var' with expanded paths based on 'params' + Variant ExpandPath( const Variant &var, Variant params = ExtensionParams() ); + + /// \brief Flattens 'var' paths to 'flat' based on 'params' + void FlattenPathTo( VariantRef flat, const Variant &var, Variant params = ExtensionParams(), std::string prefix = "" ); + + /// \brief Expands 'var' paths to 'expand' based on 'params' + void ExpandPathTo( VariantRef expand, const Variant &var, Variant params = ExtensionParams() ); + + /// \brief Returns a string string map representation of 'var' based on 'params' + std::map + FlattenPathToStrStrMap( const Variant &var, Variant params = ExtensionParams() ); + + /// \brief Returns a variant representing elements in 'compare' that differ from 'base' recursively + Variant RDiff( const Variant &base, const Variant &compare ); + + /// \brief Sets elements into 'diff' from 'compare' that differ from 'base' recursively + void RDiff( VariantRef diff, const Variant &base, const Variant &compare ); + + /// \brief Updates 'base' with entries in 'update' recursively + void RUpdate( VariantRef base, const Variant &update ); + + /// Perform an operations on v according to RFC6901 and RFC6902. + // Note that JSON Pointer is ambiguous without the presence of a document. + // These function throw if the lookup fails because of incorrect types or + // on ambiguity. + // On return (or throw) the operation will have either succedded or no + // change will have been made. + + /// Add data to v at the spot specified by pointer + void JSONPointerAdd(const std::string &pointer, VariantRef v, Variant data); + /// Remove the element in v at the spot specified by pointer + void JSONPointerRemove(const std::string &pointer, VariantRef v); + /// Replace the value at pointer with data, error if the location does not already exist + void JSONPointerReplace(const std::string &pointer, VariantRef v, Variant data); + /// Move the value from src to dst (equivalent to get(src), remove(src), add(dst) + void JSONPointerMove(const std::string &src, const std::string &dst, VariantRef v); + /// Copy the value from src to dst (equivalent to add(dst, get(src).Copy())) + void JSONPointerCopy(const std::string &src, const std::string &dst, VariantRef v); + /// Perform a lookup into v according to RFC6901, return a reference to the value at the location + VariantRef JSONPointerLookup(const std::string &pointer, VariantRef v); + + std::string FormJSONPointer(const Path &path); + + /// Perform a patch operation on v with the patch as described by diff according to RFC6902 + // Returns true if the patch is applied and all tests pass, + // false if any tests failed and no patch is applied + std::pair JSONPatch(VariantRef v, const Variant &diff); + + /// Create a diff suitable to give to JSONPatch to transform src into dst. + Variant JSONDiff(const Variant &src, const Variant &dst); + +} // namespace libvariant + +#endif /*#ifndef VARIANT_EXTENSIONS_H*/ diff --git a/src/hos_libvariant/src/include/Variant/GuessFormat.h b/src/hos_libvariant/src/include/Variant/GuessFormat.h new file mode 100644 index 00000000..9687d863 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/GuessFormat.h @@ -0,0 +1,23 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_GUESSFORMAT_H +#define VARIANT_GUESSFORMAT_H + +#pragma once +#include "../../../src/include/Variant/Variant.h" +#include "../../../src/include/Variant/Parser.h" +namespace libvariant { + + /// + // Try to guess the format of the input without removing any + // input from the input object. + // + // Currently only looks at the first non-whitespace character + // and if it is '<' then says XMLPLIST, otherwise says YAML + // if enabled otherwise JSON. + // + SerializeType GuessFormat(ParserInput* in); +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/Parser.h b/src/hos_libvariant/src/include/Variant/Parser.h new file mode 100644 index 00000000..b430d835 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/Parser.h @@ -0,0 +1,158 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_PARSER_H +#define VARIANT_PARSER_H + +#pragma once +#include +#include +#include "../../../src/include/Variant/Blob.h" +#include "../../../src/include/Variant/ParserInput.h" +#include "../../../src/include/Variant/Variant.h" +#include + +namespace libvariant { + + class ParserImpl; + + class ParserActions { + public: + virtual ~ParserActions(); + virtual void BeginDocument(ParserImpl *p) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void EndDocument(ParserImpl *p) + { throw std::runtime_error("Parser: Unexpected event"); } + // If length < 0, unknown length + virtual void BeginMap(ParserImpl *p, int length, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void EndMap(ParserImpl *p) + { throw std::runtime_error("Parser: Unexpected event"); } + // If length < 0, unknown length + virtual void BeginList(ParserImpl *p, int length, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void EndList(ParserImpl *p) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Alias(ParserImpl *p, const char *anchor) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, double v, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, const char *str, unsigned length, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, bool v, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Null(ParserImpl *p, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, intmax_t v, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, uintmax_t v, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + virtual void Scalar(ParserImpl *p, BlobPtr b, const char *anchor, const char *tag) + { throw std::runtime_error("Parser: Unexpected event"); } + }; + + /// The class that parser implementations override + class ParserImpl { + public: + virtual ~ParserImpl(); + /** + * Attempt to parse some actions. + * At least one ParserActions should be on the action stack. + * + * Run is not guaranteed to be recursively callable from inside a + * ParserActions callback. Do not do that. + * + * return 0 on success + * return 1 when done + * return -1 if needing more data is detected (not all parsers support this; can be treated as an error) + * throw on error + */ + virtual int Run() = 0; + + /** + * Push a new ParserActions handler onto the action handler stack. + */ + virtual void PushAction(shared_ptr action) { action_stack.push_back(action); } + + /** + * Pop the top ParserActions handler off the action handler stack and + * return it. + */ + virtual shared_ptr PopAction() { + if (action_stack.empty()) + { throw std::runtime_error("Parser: Attempting to parse an actions without any action handlers"); } + shared_ptr ret = action_stack.back(); + action_stack.pop_back(); + return ret; + } + + /** + * Access the top ParserActions + */ + ParserActions *TopAction() { + if (action_stack.empty()) + { throw std::runtime_error("Parser: Attempting to parse an actions without any action handlers"); } + return action_stack.back().get(); + } + + /** These three functiosn can be used to query the state + * later. + * Done means that a call to Process will immediately return 1 + * Error if Process threw an exception last + * Ok if everything looks good (Process never been called, or last return 0 or possibly -1) + */ + virtual bool Done() const = 0; + virtual bool Error() const = 0; + virtual bool Ok() const = 0; + /// Return a string describing the last error suitable for presentation to a user + virtual std::string ErrorStr() const = 0; + /// Reset the parser + virtual void Reset() = 0; + protected: + std::deque< shared_ptr< ParserActions > > action_stack; + }; + + class Parser { + public: + Parser(); + Parser(shared_ptr pi); + ~Parser(); + /// 0 on success, 1 when done, -1 other problem, throw on error + int Run() { return impl->Run(); } + /// Push an action handler onto the action stack. + void PushAction(shared_ptr action) { impl->PushAction(action); } + /// Pop the top action handler off the stack. + shared_ptr PopAction() { return impl->PopAction(); } + + /// Query state + bool Done() const { return impl->Done(); } + bool Error() const { return impl->Error(); } + bool Ok() const { return impl->Ok(); } + /// Return a string describing the last error suitable for presentation to a user + std::string ErrorStr() const { return impl->ErrorStr(); } + /// Reset the parser if applicable (some types will throw) + void Reset() { impl->Reset(); } + + /// Internal/advanced function to get the underlying implementation + shared_ptr GetImpl() { return impl; } + private: + shared_ptr impl; + }; + + shared_ptr CreateParserInput(const std::string &str); + shared_ptr CreateParserInput(const char *str); + shared_ptr CreateParserInput(const void *ptr, unsigned len); + shared_ptr CreateParserInputFile(const char *filename); + shared_ptr CreateParserInputFile(FILE *f); + shared_ptr CreateParserInputFile(std::streambuf *sb); + + Parser CreateParser(shared_ptr i, SerializeType type); + Parser CreateParserGuess(shared_ptr i); + Parser JSONParser(shared_ptr i); + Parser YAMLParser(shared_ptr i); + Parser XMLPLISTParser(shared_ptr i); + Parser BundleHdrParser(shared_ptr i); + Parser MsgPackParser(shared_ptr i); +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/ParserInput.h b/src/hos_libvariant/src/include/Variant/ParserInput.h new file mode 100644 index 00000000..5fa66311 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/ParserInput.h @@ -0,0 +1,104 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_PARSERINPUT_H +#define VARIANT_PARSERINPUT_H +#pragma once +#include +#include +#include +#include + +namespace libvariant { + + class ParserInput { + public: + virtual ~ParserInput(); + // Get a pointer and length to the unprocessed data that is available + // (return null on end of data) len being an in/out parameter, + // the initial value of len is how much the parser wants. An input value of zero + // in means give whatever is currently available. + virtual const void *GetPtr(unsigned &len) = 0; + + // Tell the input that the parser is done with len bytes from the last + // GetPtr + virtual void Release(unsigned len) = 0; + }; + + class ParserStreamInput : public ParserInput { + public: + ParserStreamInput(unsigned buffer_len); + virtual const void *GetPtr(unsigned &len); + virtual void Release(unsigned len); + /// return number of bytes read into ptr, 0 on EOF + // and throw on error + virtual unsigned Read(void *ptr, unsigned len) = 0; + protected: + std::vector buffer; + unsigned num; + unsigned offset; + bool eof; + }; + + class ParserMemoryInput : public ParserInput { + public: + ParserMemoryInput(const void *ptr, unsigned len); + virtual const void *GetPtr(unsigned &len); + virtual void Release(unsigned len); + protected: + const void *data_ptr; + unsigned data_len; + unsigned offset; + }; + + class ParserStringInput : public ParserInput { + public: + ParserStringInput(const std::string &str); + virtual const void *GetPtr(unsigned &len); + virtual void Release(unsigned len); + protected: + const std::string val; + unsigned offset; + }; + + class ParserFileInput : public ParserStreamInput { + public: + ParserFileInput(FILE *f); + virtual unsigned Read(void *ptr, unsigned len); + protected: + FILE *file; + }; + + class ParserFilenameInput : public ParserFileInput { + public: + ParserFilenameInput(const char *filename, const char *mode = "r"); + ~ParserFilenameInput(); + }; + + class ParserStreambufInput : public ParserStreamInput { + public: + ParserStreambufInput(std::streambuf *sb); + unsigned Read(void *ptr, unsigned len); + protected: + std::streambuf *streambuf; + }; + +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/Path.h b/src/hos_libvariant/src/include/Variant/Path.h new file mode 100644 index 00000000..53426fd3 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/Path.h @@ -0,0 +1,100 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_PATH_H +#define VARIANT_PATH_H + +#pragma once +#include +#include +#include "../../../src/include/Variant/Exceptions.h" +namespace libvariant { + + // A simple xpath like path functionality for Variant + // + // Map keys are specified using a "/" then the key. + // List indeces are specified using [index] + // A "/" at the end of the path is ignored. + // Characters "\/[]" must all be escaped with "\" + // + // For example: + // { + // "key1": [ 1, 2, 3, { "blork": true } ], + // "key2": { + // "subkey": [ "a", { "furple": 1 }, 2 ], + // "sub/key2": true + // } + // } + // + // Then all paths enumerated are: + // Path Value + // "/" Identity + // "/key1" [ 1, 2, 3, { "blork": true } ], + // "/key1[0]" 1 + // "/key1[1]" 2 + // "/key1[2]" 3 + // "/key1[3]" { "blork": true } + // "/key1[3]/blork" true + // "/key2" { "subkey": [ "a", { "furple": 1 }, 2 ], "sub/key2": true } + // "/key2/subkey" [ "a", { "furple": 1 }, 2 ] + // "/key2/subkey[0]" "a" + // "/key2/subkey[1]" { "furple": 1 } + // "/key2/subkey[1]/furple" 1 + // "/key2/subkey[2]" 2 + // "/key2/sub\/key2" true + // + // For all these functions PathList must act like a vector + // It may be of some other type (like deque) + + class PathElement { + public: + enum Type_t { INDEX, KEY }; + PathElement(const std::string &k) : type(KEY), key(k) {} + PathElement(const char *k) : type(KEY), key(k) {} + PathElement(unsigned i) : type(INDEX), index(i) {} + + bool IsNumber() const { return type == INDEX; } + unsigned AsUnsigned() const { + if (type != INDEX) throw BadPathError("Variant path element is not a number"); + return index; + } + bool IsString() const { return type == KEY; } + const std::string &AsString() const { + if (type != KEY) throw BadPathError("Variant path element is not a key"); + return key; + } + private: + Type_t type; + unsigned index; + std::string key; + }; + + typedef std::deque Path; + + //! + // Parse the path string into path tokens. + void ParsePath(Path &parsed_path, const std::string &path); + Path ParsePath(const std::string &path); + + //! Take the set of path tokens and turn it into a path string + std::string PathString(const Path &path); + +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/Payload.h b/src/hos_libvariant/src/include/Variant/Payload.h new file mode 100644 index 00000000..bcb213b5 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/Payload.h @@ -0,0 +1,129 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_PAYLOAD_H +#define VARIANT_PAYLOAD_H +#pragma once +#include +#include +#include +namespace libvariant { + + // Serialize and Deserialize a header, null byte, and a binary payload + // + // All restrictions of the given serialization format are required. + // + // Parameters for payload data location: + // "length_path": path to where the payload length should be + // placed for serialization and where the payload length should be read + // from for deserialization + // Defaults to: +#define VARIANT_PAYLOAD_LENGTH_PATH "payload/length" +#define VARIANT_BUNDLE_PAYLOAD_LENGTH_PATH "payload.length" + // "data_path": path to where the payload is located for + // serialization and path to store payload for deserialization + // Defaults to: +#define VARIANT_PAYLOAD_DATA_PATH "payload/data" +#define VARIANT_BUNDLE_PAYLOAD_DATA_PATH "payload.data" + // The defaults are the values for compatibility with the bundle format. + // + // Serialize only parameters: + // "ignore_payload": true|false (default false) + // Don't output the payload, only the header, alignment and null byte. + // If the payload exists in the Variant, use the length for the payload length + // value, if not look in parameters for the payload length value, if not there + // look in the Variant for the payload length. + // "payload_length": num + // Payload length override, put this number in as the payload length + // regardless of what size the blob is. + // Note that unless ingnore_payload is true, the emitter will try to output the whole + // payload (and no more) regardless of what this number is. + + void SerializeWithPayload(shared_ptr out, Variant v, SerializeType type, + Variant params = Variant::NullType); + Variant DeserializeWithPayload(shared_ptr in, SerializeType type, + Variant params = Variant::NullType, bool be_safe=true); + + std::string SerializeWithPayload(Variant v, SerializeType type, Variant params = Variant::NullType); + void SerializeWithPayload(const std::string &filename, Variant v, SerializeType type, + Variant params = Variant::NullType); + void SerializeWithPayload(FILE *f, Variant v, SerializeType type, + Variant params = Variant::NullType); + void SerializeWithPayload(std::streambuf *sb, Variant v, SerializeType type, + Variant params = Variant::NullType); + unsigned SerializeWithPayload(void *ptr, unsigned len, Variant v, SerializeType type, + Variant params = Variant::NullType); + + Variant DeserializeWithPayload(const std::string &str, SerializeType type, + Variant params = Variant::NullType); + /// If the be_safe parameter is false, then it is considered OK + // to __/NOT/__ copy the payload and just reference it in the BlobPtr. + // This is only safe when you know your buffer is going to stick around + // until after your done with the resulting Variant. + // (This is to support zero copy) + // No null terminated string version provided as these formats contain nulls. + Variant DeserializeWithPayload(const void *ptr, unsigned len, SerializeType type, + Variant params = Variant::NullType, bool be_safe=true); + Variant DeserializeWithPayloadFile(const char *filename, SerializeType type, + Variant params = Variant::NullType); + Variant DeserializeWithPayloadFile(FILE *f, SerializeType type, + Variant params = Variant::NullType); + Variant DeserializeWithPayloadFile(std::streambuf *sb, SerializeType type, + Variant params = Variant::NullType); + + + /// Bundle is a simple format used internally at ARL for passing around + // a textual key value map plus a binary payload. The payload is often a very large + // array of numbers that would produce unacceptable overhead to serialize into text. + // These serialize routines assume that the passed in Variant is of MapType + // and if a key named "payload.data" exists it is to be written as the payload + // of the Bundle. + // + // If a key "payload.data" does not exist, these are almost the same as using the BundleHdrEmitter + // except it adds a null byte at the end. + inline std::string SerializeBundle(Variant v) + { return SerializeWithPayload(v, SERIALIZE_BUNDLEHDR); } + inline void SerializeBundle(const std::string &filename, Variant v) + { SerializeWithPayload(filename, v, SERIALIZE_BUNDLEHDR); } + inline void SerializeBundle(FILE *f, Variant v) + { SerializeWithPayload(f, v, SERIALIZE_BUNDLEHDR); } + inline void SerializeBundle(std::streambuf *sb, Variant v) + { SerializeWithPayload(sb, v, SERIALIZE_BUNDLEHDR); } + inline unsigned SerializeBundle(void *ptr, unsigned len, Variant v) + { return SerializeWithPayload(ptr, len, v, SERIALIZE_BUNDLEHDR); } + + inline Variant DeserializeBundle(const std::string &str) + { return DeserializeWithPayload(str, SERIALIZE_BUNDLEHDR); } + /// If the be_safe parameter is false, then it is considered OK + // to __/NOT/__ copy the payload and just reference it in the BlobPtr. + // This is only safe when you know your buffer is going to stick around + // until after your done with the resulting Variant. + // (This is to support zero copy) + // No null terminated string version provided as bundles contain nulls. + inline Variant DeserializeBundle(const void *ptr, unsigned len, bool be_safe=true) + { return DeserializeWithPayload(ptr, len, SERIALIZE_BUNDLEHDR, Variant::NullType, be_safe); } + inline Variant DeserializeBundleFile(const char *filename) + { return DeserializeWithPayloadFile(filename, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleFile(FILE *f) { return DeserializeWithPayloadFile(f, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleFile(std::streambuf *sb) + { return DeserializeWithPayloadFile(sb, SERIALIZE_BUNDLEHDR); } + +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/Schema.h b/src/hos_libvariant/src/include/Variant/Schema.h new file mode 100644 index 00000000..235627c2 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/Schema.h @@ -0,0 +1,175 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief A schema validator. + * + * This code is based on the public domain JSONv4 validator tv4. + * tv4 is available at http://geraintluff.github.com/tv4/ + */ +#ifndef VARIANT_SCHEMA_H +#define VARIANT_SCHEMA_H + +#pragma once +#include "../../../src/include/Variant/Variant.h" +#include +#include +#include +#include +namespace libvariant { + + class SchemaResult; + + class ValidationError { + public: + ValidationError(const std::string &m, const Path &dpath, + const Path &spath); + + void AddSubError(const SchemaResult &err); + + const std::string &GetMessage() const { return message; } + const Path &GetDataPath() const { return data_path; } + std::string GetDataPathStr() const; + const Path &GetSchemaPath() const { return schema_path; } + std::string GetSchemaPathStr() const; + const std::vector &GetSubErrors() const { return sub_errors; } + + std::string PrettyPrintMessage() const; + void PrettyPrintMessage(std::ostream &os, unsigned indent=0) const; + private: + std::string message; + Path data_path; + Path schema_path; + std::vector sub_errors; + }; + + class SchemaError { + public: + SchemaError(const std::string &m, const Path &spath); + + const std::string &GetMessage() const { return message; } + const Path &GetSchemaPath() const { return schema_path; } + std::string GetSchemaPathStr() const; + + std::string PrettyPrintMessage() const; + void PrettyPrintMessage(std::ostream &os, unsigned indent=0) const; + private: + std::string message; + Path schema_path; + }; + + class SchemaResult { + public: + SchemaResult(); + + void AddError(const ValidationError &err); + void AddSchemaError(const SchemaError &err); + + bool Error() const { return !errors.empty() || !schema_errors.empty(); } + bool ValidationErrors() const { return !errors.empty(); } + bool SchemaErrors() const { return !schema_errors.empty(); } + + const std::vector &GetErrors() const { return errors; } + const std::vector &GetSchemaErrors() const { return schema_errors; } + + std::string PrettyPrintMessage() const; + void PrettyPrintMessage(std::ostream &os, unsigned indent=0) const; + private: + std::vector errors; + std::vector schema_errors; + }; + + inline std::ostream &operator<<(std::ostream &os, const SchemaResult &sr) { + sr.PrettyPrintMessage(os); + return os; + } + + class SchemaLoader { + public: + class LoaderError { + public: + LoaderError(); + ~LoaderError(); + void AddError(const std::string &uri, const std::string &msg); + std::string GetErrorMessage() const { return erross.str(); } + private: + std::ostringstream erross; + }; + + typedef bool (*MissingHandlerType)(SchemaLoader*,const std::string&,LoaderError &,void*); + SchemaLoader(); + SchemaLoader(SchemaLoader *b); + virtual ~SchemaLoader(); + // Get the schema at the uri specified. + // Internal lookup first, then call HandleMissing if the uri is not internally available. + // If the schema then is still not available return Variant::NullType. + virtual Variant GetSchema(const std::string &uri); + // Add a schema to the loader at the uri specified. + // returns the schema(s) added with the corresponding uri(s) + virtual std::map AddSchema(const std::string &uri, Variant schema); + // Forget a schema with the specified uri. + virtual void ForgetSchema(const std::string &uri); + // Called when a schema is not in the loader. + // Default implementation is to call the missing handler + // or add a not found error to the LoaderError and return false + // Return true on success, otherwise false, any errors are filled into the LoaderError + virtual bool HandleMissing(const std::string &uri, LoaderError &error); + void SetMissingHandler(MissingHandlerType, void *ctx); + + static void NormSchema(Variant &schema, const std::string &uri); + //! + // A realpath function for schema URIs. + // href is the "current working directory" and base is + // possibly a relative path. + static std::string ResolveURI(const std::string &base, const std::string &href); + + struct URIInfo { + std::string href; // EX: the whole uri if matched + std::string protocol; // EX: http:// + std::string authority; // user:host@hostname:port + std::string pathname; // The path segment + std::string search; // ?q=234 + std::string hash; // #tag + }; + + //! Break a uri into its components and store them into the URIInfo struct + //! returns true if the parsing was successful + static bool ParseURI(URIInfo &info, const std::string &uri); + protected: + + static void SearchForTrustedSchemas(std::map &m, Variant schema, const std::string &uri); + MissingHandlerType missingHandler; + void *missingctx; + std::map schemas; + SchemaLoader *base; + }; + + //! Validate data against a schema. + //! + //! The schema parameter is either a schema, a string uri to a schema, or null. + //! If it is a schema then data is validated against it. + //! If it is a string then it calls loader->GetSchema() and validates data against the result. + //! If schema is null, then look for a key "$schema" in data, set schema to it and proceed as above. + SchemaResult SchemaValidate(Variant schema, Variant data, SchemaLoader *loader=0); + + //! Add the defaults specified in schema to data if they do not exist. + //! Ignores default in some combinations and types that could match multiple entries (not, + //! additionalProperties, patternProperties, etc.) + //! schema is processed the same as for SchemaValidate + void AddSchemaDefaults(Variant schema, VariantRef data, SchemaLoader *loader=0); +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/SchemaLoader.h b/src/hos_libvariant/src/include/Variant/SchemaLoader.h new file mode 100644 index 00000000..e4edd00b --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/SchemaLoader.h @@ -0,0 +1,54 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief An advanced schema loader. + */ +#ifndef VARIANT_SCHEMALOADER_H +#define VARIANT_SCHEMALOADER_H + +#pragma once + +#include "../../../src/include/Variant/Schema.h" + +namespace libvariant { + + //! The advanced schema loader will try to load missing schemas from + //! the file system and optionally curl if built. + //! If the url begins with file:// it will always use LoadFromFile + //! otherwise if the protocol is empty it will try loading from a file + //! then try loading from curl. Otherwise if the protocol is not file:// + //! it will try to load from curl. + class AdvSchemaLoader : public SchemaLoader { + public: + + //! The advanced schema loader will search for a schema in the paths + //! added to it on the file system. If the schema uri looks like a + //! relative path, then it will be searched for in the paths set with + //! this function. If no paths are added, then only absolute paths will + //! be looked up in the file system. + // + void AddPath(const std::string &path); + + virtual bool HandleMissing(const std::string &uri, LoaderError &error); + protected: + bool LoadFromFile(URIInfo &info, LoaderError &error); + bool LoadFromCurl(URIInfo &info, LoaderError &error); + std::vector< std::string > paths; + }; +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/SharedPtr.h b/src/hos_libvariant/src/include/Variant/SharedPtr.h new file mode 100644 index 00000000..ebefcef4 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/SharedPtr.h @@ -0,0 +1,41 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_SHAREDPTR_H +#define VARIANT_SHAREDPTR_H + +#pragma once +#include "../../../include/hos_libvariant/Config.h" + +#if defined(__GXX_EXPERIMENTAL_CXX0X) || __cplusplus >= 201103L || defined(HAVE_CXX11_SHAREDPTR) +// The C++11 implementation is available +#include +namespace libvariant { + using std::shared_ptr; + using std::dynamic_pointer_cast; +} + +#elif defined(HAVE_TR1_SHAREDPTR) +// Use the tr1 implementation +#include +namespace libvariant { + using std::tr1::shared_ptr; + using std::tr1::dynamic_pointer_cast; +} + +#elif defined(USE_BOOST_SHAREDPTR) +// Use the boost implementation +#include +namespace libvariant { + using boost::shared_ptr; + using boost::dynamic_pointer_cast; +} + +#else + +#error libvariant requires a shared_ptr implementation + +#endif + +#endif diff --git a/src/hos_libvariant/src/include/Variant/Variant.h b/src/hos_libvariant/src/include/Variant/Variant.h new file mode 100644 index 00000000..3b0173e6 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/Variant.h @@ -0,0 +1,816 @@ +// vim: foldmethod=marker +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= + +/** \file + * + * \brief Main implementation file for Variant and related functions + */ + + +#ifndef VARIANT_VARIANT_H +#define VARIANT_VARIANT_H + +#pragma once +#include "../../../src/include/Variant/Blob.h" +#include "../../../src/include/Variant/SharedPtr.h" +#include "../../../src/include/Variant/Exceptions.h" +#include "../../../src/include/Variant/VariantInternal.h" +#include +#include +#include +#include +#include +#include +#include + +namespace libvariant { + + /** \brief The Variant class. + * This is a variant type inspired by types from several different + * scripting languages. + * + * \author John Bridgman + * + * This class gives the power and convenience of a scripting language variable + * to C++ with all the same /downsides/ that such a variable has as well. The + * main idea is that things should be simple, lists are behind the scenes an + * std::vector and maps are an std::map. + * + * A Variant may be null, a number, a string, a boolean, a reference to a list, + * or a reference to a map. This means that const Variant of a map is not a + * const map but a const reference. Lists and maps are reference counted. If + * one wants to copy use the Copy member function. + * + * If you need a reference to a Variant to assign to it or change its type, + * use VariantRef. + * A const Variant & should be used for an immutable reference. + * E.g., void foo(VariantRef inout_param, const Variant &in_param); + * That is to say, if you think you want Variant &, you don't, you want + * VariantRef. + * The library is written so that: + * Variant v; + * void bar(Variant &); + * bar(v["foo"]); + * is a compile error. + * But + * Variant v; + * void moo(const Variant &); + * moo(v["moo"]); + * is correct. + * + * + * Note that this implementation will let you create a back reference (i.e., a + * map with itself as a member) but unless the user explicitly breaks it, it + * will result in a memory leak. Checking for this case was deemed too + * expensive. + * + * A Variant will only change its own type if the type is null. That is to say + * that a null Variant that gets treated as a map will become a map. But, a + * Variant of any other type will never automatically convert. + * + */ + class Variant : protected Internal::Data, public VariantDefines { + public: + + typedef VariantRefImpl VariantRef; + + typedef std::vector List; + typedef std::map Map; + + typedef Map::iterator MapIterator; + typedef Map::const_iterator ConstMapIterator; + typedef List::iterator ListIterator; + typedef List::const_iterator ConstListIterator; + + Variant() {} + Variant(VariantDefines::Type_t type) { Assign(type); } + Variant(bool v) { Assign(v); } + + Variant(int v) { Assign(v); } + Variant(unsigned v) { Assign(v); } + Variant(long v) { Assign(v); } + Variant(unsigned long v) { Assign(v); } + Variant(long long v) { Assign(v); } + Variant(unsigned long long v) { Assign(v); } + Variant(double v) { Assign(v); } + Variant(long double v) { Assign(v); } + + Variant(BlobPtr b) { Assign(b); } + + Variant(const std::string &v) { Assign(v); } + Variant(const char *v) { Assign(v); } + Variant(const Variant &v) { Assign(v); } + Variant(const VariantRefImpl &v) { Assign(v); } + + /// Construct a list from a std::vector. + template + Variant(const std::vector &v) { Assign(v); } + + /// Construct a map from a std::map. + template + Variant(const std::map &v) { Assign(v); } + + ~Variant(); + + Variant &operator=(const Variant &o) { Assign(o); return *this; } + + Variant &operator=(VariantDefines::Type_t v) { Assign(v); return *this; } + Variant &operator=(bool v) { Assign(v); return *this; } + Variant &operator=(int v) { Assign(v); return *this; } + Variant &operator=(unsigned v) { Assign(v); return *this; } + Variant &operator=(long v) { Assign(v); return *this; } + Variant &operator=(unsigned long v) { Assign(v); return *this; } + Variant &operator=(long long v) { Assign(v); return *this; } + Variant &operator=(unsigned long long v) { Assign(v); return *this; } + Variant &operator=(double v) { Assign(v); return *this; } + Variant &operator=(long double v) { Assign(v); return *this; } + Variant &operator=(BlobPtr v) { Assign(v); return *this; } + Variant &operator=(const std::string & v) { Assign(v); return *this; } + Variant &operator=(const char * v) { Assign(v); return *this; } + + template + Variant &operator=(const std::vector &v) { Assign(v); return *this; } + template + Variant &operator=(const std::map &v) { Assign(v); return *this; } + + // Type query functions + + Type_t GetType() const; ///< Return the type of this Variant + + bool IsNull() const { return NullType == GetType(); } + bool IsBool() const { return BoolType == GetType(); } + bool IsTrue() const { return (BoolType == GetType()) && AsBool(); } + bool IsFalse() const { return (BoolType == GetType()) && !AsBool(); } + bool IsNumber() const + { return IntegerType == GetType() || UnsignedType == GetType() || FloatType == GetType(); } + bool IsInt() const { return IntegerType == GetType(); } + bool IsUnsigned() const { return UnsignedType == GetType(); } + bool IsFloat() const { return FloatType == GetType(); } + bool IsString() const { return StringType == GetType(); } + bool IsList() const { return ListType == GetType(); } + bool IsMap() const { return MapType == GetType(); } + bool IsBlob() const { return BlobType == GetType(); } + + + // Accessor functions + + bool AsBool() const; ///< Return the value as a bool + long double AsLongDouble() const; ///< Return the value as a long double + double AsDouble() const { return (double)AsLongDouble(); } + uintmax_t AsUnsigned() const; ///< Return the value as an unsigned + intmax_t AsInt() const; ///< Return the value as an integer + template + T AsNumber() const { return static_cast(AsLongDouble()); } + std::string AsString() const; ///< Return the value as a string + BlobPtr AsBlob(); + ConstBlobPtr AsBlob() const; + + template + T As() const; + + /// \brief If the type is string, list, map or blob returns its size, + /// otherwise throws an exception + unsigned Size() const; + + /// \brief If the type is string, list or map return if size == 0 otherwise + /// throw an exception + bool Empty() const; + + /// \brief If the type is string, list or map, empty the container otherwise + /// set type to NullType + void Clear(); + + // List specific accessors + List &AsList(); + const List &AsList() const; + ListIterator ListBegin() ///< Equivalent to AsList().begin() + { return AsList().begin(); } + ConstListIterator ListBegin() const ///< Equivalent to AsList().begin() + { return AsList().begin(); } + ListIterator ListEnd() ///< Equivalent to AsList().end() + { return AsList().end(); } + ConstListIterator ListEnd() const ///< Equivalent to AsList().end() + { return AsList().end(); } + VariantRef At(unsigned i); //< Return a proxy/reference to the element at index i + VariantRef At(unsigned i, Variant def); //< sets to def if doesn't exist + const Variant &At(unsigned i) const; + Variant Get(unsigned i) const; //< Return the element at index i or throw + Variant Get(unsigned i, Variant def) const; //< Return the element at index i or return def + Variant &Set(unsigned i, Variant v); //< Set the element at index i to v + /// \brief Only valid when of type ListType Returns *this, so you can + /// do Variant().Append(v1).Append(v2)... + Variant &Append(Variant value); + + /// \brief If list return true if list is at least i in size, if map then convert i + /// to a string, otherwise throw + bool Contains(unsigned i) const; + /// \brief Return the index hat v is at. + /// If v is not contained in the list it return this->Size() + unsigned Index(Variant v) const; + + /// \brief If list set index i to null, if index at end, reduce size by 1 + /// throw if not a list + void Erase(unsigned i); + + // Map specific accessors + Map &AsMap(); + const Map &AsMap() const; + MapIterator MapBegin() ///< Equivalent to AsMap().begin() + { return AsMap().begin(); } + ConstMapIterator MapBegin() const ///< Equivalent to AsMap().begin() + { return AsMap().begin(); } + MapIterator MapEnd() ///< Equivalent to AsMap().end() + { return AsMap().end(); } + ConstMapIterator MapEnd() const ///< Equivalent to AsMap().end() + { return AsMap().end(); } + VariantRef At(const std::string &s); // Return a proxy/reference to the element at key s + VariantRef At(const std::string &s, Variant def); //< Sets to def if doesn't exist and return a reference to it + const Variant &At(const std::string &s) const; + + /// \brief If s in *this: return this->At(s); else throw; + Variant Get(const std::string &s) const; + /// \brief If s in *this: return this->At(s); else return def + /// Only works if type is map + Variant Get(const std::string &s, Variant def) const; + + /// \brief Set the key s to v + // returns *this + Variant &Set(const std::string &s, Variant v); + + /// \brief If map return true if s is a key in the map, if list then convert + /// s to an unsigned and the above Contains, otherwise throw + bool Contains(const std::string &s) const; + /// \brief Erase a key in a map, throws if type is not MapType + void Erase(const std::string &key); + + VariantRef operator[](int i) { return At(i); } + const Variant &operator[](int i) const { return At(i); } + + VariantRef operator[](unsigned i) { return At(i); } + const Variant &operator[](unsigned i) const { return At(i); } + + VariantRef operator[](const std::string &s) { return At(s); } + const Variant &operator[](const std::string &s) const { return At(s); } + + // Path related accessors + // These are the same as the non-path functions but take a path instead. + VariantRef AtPath(const Path &path); + VariantRef AtPath(const std::string &path) { return AtPath(ParsePath(path)); } + VariantRef AtPath(const Path &path, Variant def); + VariantRef AtPath(const std::string &path, Variant def) { return AtPath(ParsePath(path), def); } + const Variant &AtPath(const Path &path) const; + const Variant &AtPath(const std::string &path) const { return AtPath(ParsePath(path)); } + + /// \brief Like Variant::Get but it takes a path instead. + Variant GetPath(const Path &path) const; + Variant GetPath(const std::string &path) const { return GetPath(ParsePath(path)); } + /// \brief Like Variant::Get but it takes a path instead. The path is + /// very like xpath, /key[index]/key/key. See Variant/Path.h + Variant GetPath(const Path &path, Variant def) const; + Variant GetPath(const std::string &path, Variant def) const { return GetPath(ParsePath(path), def); } + + /// \brief Set the value at the path, creating elements if they do not + /// exist. throws if an intermediate path element exists but is not a + /// map or list. returns *this + Variant &SetPath(const Path &path, Variant val); + Variant &SetPath(const std::string &path, Variant val) { return SetPath(ParsePath(path), val); } + + /// \brief Erase a value at a path, if remove_empty is false only erase the very end + /// otherwise erase empty lists and maps in the path. returns *this + Variant &ErasePath(const Path &path, bool remove_empty=false); + Variant &ErasePath(const std::string &path, bool remove_empty=false) + { return ErasePath(ParsePath(path), remove_empty); } + + /// \brief Tester functions for paths, returns true if path is valid and exists. + bool HasPath(const Path &path) const; + bool HasPath(const std::string &path) const { return HasPath(ParsePath(path)); } + + /// \brief Just like Variant::Get except a reference to the value to + /// set is passed in and Variant does the casting. + template + void GetInto(T &lvalue, const std::string &s) const; + + /// \brief An into version of GetPath + template + void GetPathInto(T &lvalue, const Path &path) const; + template + void GetPathInto(T &lvalue, const std::string &path) const + { GetPathInto(lvalue, ParsePath(path)); } + + /// \brief Just like Variant::Get except a reference to the value to + /// set is passed in and Variant does the casting. + template + void GetInto(T &lvalue, const std::string &s, const T &def) const; + + /// \brief An into version of GetPath + template + void GetPathInto(T &lvalue, const Path &path, const T &def) const; + template + void GetPathInto(T &lvalue, const std::string &path, const T &def) const + { GetPathInto(lvalue, ParsePath(path), def); } + + /// \brief This type and other type must be MapType. + /// for (k, v) in other: this[k] = v + void Merge(Variant other); + + /// \brief Comparison operator + /// Returns -1 if we are less than other + /// 0 if we are equal + /// 1 if we are greater than + /// This function always returns 1 if Comparable returns false + /// This compare is not completely consistent + /// i.e. it can be such that two Variants are + /// both < and > (ex map and list types) + int Compare(const Variant &other) const; + + /// \brief Return true if this and other are comparable. Two types are + /// considered comparable if they have the same type or if they are both + /// number types. + bool Comparable(const Variant &other) const; + + void Incr(); + void Decr(); + void Add(const Variant &o); + void Sub(const Variant &o); + void Mul(const Variant &o); + void Div(const Variant &o); + void Rem(const Variant &o); + + Variant Neg() const; + + Variant &operator++() { Incr(); return *this; } + Variant &operator--() { Decr(); return *this; } + Variant operator++(int) { Variant tmp = *this; ++(*this); return tmp; } + Variant operator--(int) { Variant tmp = *this; --(*this); return tmp; } + Variant operator-() const { return Neg(); } + Variant operator+() const { return *this; } + + Variant &operator+=(const Variant &o) { Add(o); return *this; } + Variant &operator-=(const Variant &o) { Sub(o); return *this; } + Variant &operator*=(const Variant &o) { Mul(o); return *this; } + Variant &operator/=(const Variant &o) { Div(o); return *this; } + Variant &operator%=(const Variant &o) { Rem(o); return *this; } + + VariantRef Ref(); //< Return a new VariantRef to this Variant + Variant Copy() const; //< Return a copy of this Variant + Variant &Resolve(); //< Return *this or return the Variant this is a reference to + const Variant &Resolve() const; + /// Return *this or Variant referenced to if exists, otherwise create it with def. + Variant &Resolve(const Variant &def); + /// Return weather or not Resolve() const would throw. + bool Exists() const; + + /// Make this equal other. + void Assign(const Variant &other); + + void Assign(VariantDefines::Type_t type); + void Assign(bool v); + void Assign(int v); + void Assign(unsigned v); + void Assign(long v); + void Assign(unsigned long v); + void Assign(long long v); + void Assign(unsigned long long v); + void Assign(double v); + void Assign(long double v); + void Assign(BlobPtr b); + void Assign(const std::string &v); + void Assign(const char *v); + + template + void Assign(const std::vector &v) { + Assign(VariantDefines::ListType); + AsList().assign(v.begin(), v.end()); + } + + template + void Assign(const std::map &v) { + Assign(VariantDefines::MapType); + AsMap().insert(v.begin(), v.end()); + } + + protected: + Variant(const RefTag &, const Variant &o); + Variant(const RefTag &, Variant &o, Path::const_iterator b, Path::const_iterator e); + /// Reassing this reference, only available through the VariantRef interface. + /// The regular Assign makes what this is refering to equal the new value, this + /// function makes this reference refer to the new value. + void ReassignRef(const Variant &o); + friend class Internal::VTable; + }; + + typedef VariantRefImpl VariantRef; + + inline bool operator==(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) == 0; } + inline bool operator!=(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) != 0; } + inline bool operator<(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) < 0; } + inline bool operator>(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) > 0; } + inline bool operator<=(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) <= 0; } + inline bool operator>=(const Variant &lhs, const Variant &rhs) { return lhs.Compare(rhs) >= 0; } + + inline Variant operator+(const Variant &lhs, const Variant &rhs) { + Variant ret = lhs; + return ret += rhs; + } + inline Variant operator-(const Variant &lhs, const Variant &rhs) { + Variant ret = lhs; + return ret -= rhs; + } + inline Variant operator*(const Variant &lhs, const Variant &rhs) { + Variant ret = lhs; + return ret *= rhs; + } + inline Variant operator/(const Variant &lhs, const Variant &rhs) { + Variant ret = lhs; + return ret /= rhs; + } + inline Variant operator%(const Variant &lhs, const Variant &rhs) { + Variant ret = lhs; + return ret %= rhs; + } + + /// \defgroup variant_cast Template casting operators. + /// These are for use inside templates to extract the value of a Variant into + /// a templated type. + /// @{ + + template + struct VariantCaster { + static T Cast(const Variant &v); + }; + + // Default + template inline T VariantCaster::Cast(const Variant &v) { return T(v); } + + template + inline T variant_cast(const Variant &v) { return VariantCaster::Cast(v); } + + // Provide specializations for all the basic types + template<> inline bool VariantCaster::Cast(const Variant &v) { return v.AsBool(); } + template<> inline char VariantCaster::Cast(const Variant &v) { return (char)v.AsInt(); } + template<> inline unsigned char VariantCaster::Cast(const Variant &v) { return (unsigned char)v.AsUnsigned(); } + template<> inline signed char VariantCaster::Cast(const Variant &v) { return (signed char)v.AsUnsigned(); } + template<> inline short VariantCaster::Cast(const Variant &v) { return (short)v.AsInt(); } + template<> inline unsigned short VariantCaster::Cast(const Variant &v) { return (unsigned short)v.AsUnsigned(); } + template<> inline int VariantCaster::Cast(const Variant &v) { return (int)v.AsInt(); } + template<> inline unsigned VariantCaster::Cast(const Variant &v) { return (unsigned)v.AsUnsigned(); } + template<> inline long VariantCaster::Cast(const Variant &v) { return (long)v.AsInt(); } + template<> inline unsigned long VariantCaster::Cast(const Variant &v) { return (unsigned long)v.AsUnsigned(); } + template<> inline long long VariantCaster::Cast(const Variant &v) { return (long long)v.AsInt(); } + template<> inline unsigned long long VariantCaster::Cast(const Variant &v) { return (unsigned long long)v.AsUnsigned(); } + template<> inline float VariantCaster::Cast(const Variant &v) { return (float)v.AsDouble(); } + template<> inline double VariantCaster::Cast(const Variant &v) { return v.AsDouble(); } + template<> inline long double VariantCaster::Cast(const Variant &v) { return v.AsLongDouble(); } + template<> inline std::string VariantCaster::Cast(const Variant &v) { return v.AsString(); } + + // Allow things like variant_cast< std::vector >(v) to work + template + struct VariantCaster< std::vector > { + static std::vector Cast(const Variant &v); + }; + + template + inline std::vector VariantCaster< std::vector >::Cast(const Variant &v) { + std::vector ret; + for (Variant::ConstListIterator i(v.ListBegin()), e(v.ListEnd()); i != e; ++i) { + ret.push_back( variant_cast( *i ) ); + } + return ret; + } + + template<> inline Variant::List VariantCaster::Cast(const Variant &v) { return v.AsList(); } + + // allow things like variant_cast< std::map >(v) + // to work + template + struct VariantCaster< std::map > { + static std::map Cast(const Variant &v); + }; + + template + inline std::map VariantCaster< std::map >::Cast(const Variant &v) { + std::map ret; + for (Variant::ConstMapIterator i(v.MapBegin()), e(v.MapEnd()); i != e; ++i) { + ret.insert( std::make_pair( i->first, variant_cast( i->second ) ) ); + } + return ret; + } + + template<> inline Variant::Map VariantCaster::Cast(const Variant &v) { return v.AsMap(); } + + template + struct VariantCaster< std::complex > { + static std::complex Cast(const Variant &v); + }; + + template + std::complex VariantCaster< std::complex >::Cast(const Variant &v) { + if (v.IsNull()) { + return std::complex(); + } else if (v.IsNumber()) { + return std::complex(v.As(), T()); + } else if (v.IsMap()) { + T r = variant_cast(v.Get("real", T())); + T c = variant_cast(v.Get("imag", T())); + return std::complex(r, c); + } else if (v.IsList()) { + if (v.Size() > 1) { + return std::complex(v[0].As(), v[1].As()); + } else if (v.Size() > 0) { + return std::complex(v[0].As(), T()); + } else { + return std::complex(); + } + } + throw UnableToConvertError(v.GetType(), "std::complex"); + } + + /// @} + + template + T Variant::As() const { return variant_cast(*this); } + + template + void Variant::GetInto(T &lvalue, const std::string &s) const { + lvalue = variant_cast(Get(s)); + } + + template + void Variant::GetPathInto(T &lvalue, const Path &p) const { + lvalue = variant_cast(GetPath(p)); + } + + template + void Variant::GetInto(T &lvalue, const std::string &s, const T &def) const { + if (Contains(s)) { lvalue = variant_cast(Get(s)); } + else { lvalue = def; } + } + + template + void Variant::GetPathInto(T &lvalue, const Path &p, const T &def) const { + lvalue = variant_cast(GetPath(p, def)); + } + + class Parser; + /// \brief Takes a parser and produces a Variant from it. + Variant ParseVariant(Parser &p); + + class Emitter; + /// Takes a Variant and Emitter and emits the Variant. + Emitter &operator<<(Emitter &e, const Variant &v); + + /// \brief The different types of serialization supported. + enum SerializeType { + // Attempt to guess the format + // Cannot be specified as an output format. + SERIALIZE_GUESS = 0x0, + + // Built in text formats + SERIALIZE_JSON = 0x00000001, + SERIALIZE_YAML, + SERIALIZE_XMLPLIST, + SERIALIZE_BUNDLEHDR, + + // Built in binary formats + SERIALIZE_MSGPACK = 0x000000FF, + + }; + + + /// \brief An iterator that iterates over all documents that the parser will generate + class LoadAllIterator { + public: + typedef Variant value_type; + typedef ptrdiff_t difference_type; + typedef Variant* pointer; + typedef Variant& reference; + typedef std::forward_iterator_tag iterator_category; + + LoadAllIterator(); + explicit LoadAllIterator(Parser &parser); + Variant &operator*() { return Get(); } + Variant *operator->() { return &Get(); } + Variant &Get(); + void Next(); + LoadAllIterator &operator++() { + Next(); + return *this; + } + LoadAllIterator operator++(int) { + LoadAllIterator copy = *this; + Next(); + return copy; + } + bool operator==(const LoadAllIterator &that) const; + bool operator!=(const LoadAllIterator &that) const { return !(*this == that); } + private: + class Impl; + shared_ptr impl; + struct Value; + shared_ptr value; + }; + + // Some convenience functions + // A version is provided that will go to/from a string, + // a memory buffer, a file name, an open FILE*, and + // a streambuf* (usually acquired through iostream.rdbuf()). + + /// \brief Serialize a Variant to a string using format type. + std::string Serialize(Variant v, SerializeType type, Variant params = Variant::NullType); + /// \brief Serialize a Variant to a file using format type. + void Serialize(const std::string &filename, Variant v, SerializeType type, + Variant params = Variant::NullType); + /// \brief Serialize a Variant to a FILE pointer using format type. + void Serialize(FILE *f, Variant v, SerializeType type, + Variant params = Variant::NullType); + /// \brief Serialize a Variant to a streambuf* (iostrem.rdbuf()) using format type. + void Serialize(std::streambuf *sb, Variant v, SerializeType type, + Variant params = Variant::NullType); + /// \brief Serialize a Variant to a memory buffer of length len, using format type + //and return how many bytes produced. + unsigned Serialize(void *ptr, unsigned len, Variant v, SerializeType type, + Variant params = Variant::NullType); + + // The basic deserializing functions + + /// \brief Attempt to deserialize a string in format type to a Variant + Variant Deserialize(const std::string &str, SerializeType type); + /// \brief Attempt to deserialize a null terminated string in format type to a Variant + Variant Deserialize(const char *str, SerializeType type); + /// \brief Attempt to deserialize a pointer and length in format type to a Variant + Variant Deserialize(const void *ptr, unsigned len, SerializeType type); + /// \brief Attempt to deserialize the file to a Variant in format type + Variant DeserializeFile(const char *filename, SerializeType type); + /// \brief Deserialize from a FILE pointer to a Variant in format type + Variant DeserializeFile(FILE *f, SerializeType type); + /// \brief Deserialize from a streambuf to a Variant in format type + Variant DeserializeFile(std::streambuf *sb, SerializeType type); + + /// \defgroup deserialize_guess Guess format + /// These functions attempt to guess the type of the input. The guessing + /// function only looks at the first non-whitespace character to make the + /// decision. As such on sufficiently badly behaved input can select the + /// wrong format. + /// @{ + Variant DeserializeGuess(const std::string &str); + Variant DeserializeGuess(const char *str); + Variant DeserializeGuess(const void *ptr, unsigned len); + Variant DeserializeGuessFile(const char *filename); + Variant DeserializeGuessFile(FILE *f); + Variant DeserializeGuessFile(std::streambuf *sb); + /// @} + + /// \defgroup deserialize_all Deserialize all elements + /// These functions return an iterator. These are for format types that + /// support multiple documents in one stream. Otherwise same as Deserialize + /// functions above. + /// @{ + LoadAllIterator DeserializeAll(const std::string &str, SerializeType type); + LoadAllIterator DeserializeAll(const char *str, SerializeType type); + LoadAllIterator DeserializeAll(const void *ptr, unsigned len, SerializeType type); + LoadAllIterator DeserializeAllFile(const char *filename, SerializeType type); + /// File must remain open for as long as the iterator is referenced + LoadAllIterator DeserializeAllFile(FILE *f, SerializeType type); + /// Streambuf must exist for as long as the iterator is referenced + LoadAllIterator DeserializeAllFile(std::streambuf *sb, SerializeType type); + /// @} + + + // Serialize and Deserializing JSON + // + inline std::string SerializeJSON(Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + return Serialize(v, SERIALIZE_JSON, param); + } + inline void SerializeJSON(const std::string &filename, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(filename, v, SERIALIZE_JSON, param); + } + inline void SerializeJSON(FILE *f, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(f, v, SERIALIZE_JSON, param); + } + inline void SerializeJSON(std::streambuf *sb, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(sb, v, SERIALIZE_JSON, param); + } + inline unsigned SerializeJSON(void *ptr, unsigned len, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + return Serialize(ptr, len, v, SERIALIZE_JSON, param); + } + inline Variant DeserializeJSON(const std::string &str) { return Deserialize(str, SERIALIZE_JSON); } + inline Variant DeserializeJSON(const char *str) { return Deserialize(str, SERIALIZE_JSON); } + inline Variant DeserializeJSON(const void *ptr, unsigned len) { return Deserialize(ptr, len, SERIALIZE_JSON); } + inline Variant DeserializeJSONFile(const char *filename) { return DeserializeFile(filename, SERIALIZE_JSON); } + inline Variant DeserializeJSONFile(FILE *f) { return DeserializeFile(f, SERIALIZE_JSON); } + inline Variant DeserializeJSONFile(std::streambuf *sb) { return DeserializeFile(sb, SERIALIZE_JSON); } + + //Serialize and Deserialize YAML + // + inline std::string SerializeYAML(Variant v) { return Serialize(v, SERIALIZE_YAML); } + inline void SerializeYAML(const std::string &filename, Variant v) { Serialize(filename, v, SERIALIZE_YAML); } + inline void SerializeYAML(FILE *f, Variant v) { Serialize(f, v, SERIALIZE_YAML); } + inline void SerializeYAML(std::streambuf *sb, Variant v) { Serialize(sb, v, SERIALIZE_YAML); } + inline unsigned SerializeYAML(void *ptr, unsigned len, Variant v) { return Serialize(ptr, len, v, SERIALIZE_YAML); } + + inline Variant DeserializeYAML(const std::string &str) { return Deserialize(str, SERIALIZE_YAML); } + inline Variant DeserializeYAML(const char *str) { return Deserialize(str, SERIALIZE_YAML); } + inline Variant DeserializeYAML(const void *ptr, unsigned len) { return Deserialize(ptr, len, SERIALIZE_YAML); } + inline Variant DeserializeYAMLFile(const char *filename) { return DeserializeFile(filename, SERIALIZE_YAML); } + inline Variant DeserializeYAMLFile(FILE *f) { return DeserializeFile(f, SERIALIZE_YAML); } + inline Variant DeserializeYAMLFile(std::streambuf *sb) { return DeserializeFile(sb, SERIALIZE_YAML); } + + inline LoadAllIterator DeserializeYAMLAll(const std::string &str) { return DeserializeAll(str, SERIALIZE_YAML); } + inline LoadAllIterator DeserializeYAMLAll(const char *str) { return DeserializeAll(str, SERIALIZE_YAML); } + inline LoadAllIterator DeserializeYAMLAll(const void *ptr, unsigned len) { return DeserializeAll(ptr, len, SERIALIZE_YAML); } + inline LoadAllIterator DeserializeYAMLAllFile(const char *filename) { return DeserializeAllFile(filename, SERIALIZE_YAML); } + inline LoadAllIterator DeserializeYAMLAllFile(FILE *f) { return DeserializeAllFile(f, SERIALIZE_YAML); } + inline LoadAllIterator DeserializeYAMLAllFile(std::streambuf *sb) { return DeserializeAllFile(sb, SERIALIZE_YAML); } + + //Serialize and Deserialize XML plist + // + inline std::string SerializeXMLPLIST(Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + return Serialize(v, SERIALIZE_XMLPLIST, param); + } + inline void SerializeXMLPLIST(const std::string &filename, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(filename, v, SERIALIZE_XMLPLIST, param); + } + inline void SerializeXMLPLIST(FILE *f, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(f, v, SERIALIZE_XMLPLIST, param); + } + inline void SerializeXMLPLIST(std::streambuf *sb, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + Serialize(sb, v, SERIALIZE_XMLPLIST, param); + } + inline unsigned SerializeXMLPLIST(void *ptr, unsigned len, Variant v, bool pretty=false) { + Variant param = Variant::MapType; param["pretty"] = pretty; + return Serialize(ptr, len, v, SERIALIZE_XMLPLIST, param); + } + + inline Variant DeserializeXMLPLIST(const std::string &str) { return Deserialize(str, SERIALIZE_XMLPLIST); } + inline Variant DeserializeXMLPLIST(const char *str) { return Deserialize(str, SERIALIZE_XMLPLIST); } + inline Variant DeserializeXMLPLIST(const void *ptr, unsigned len) { return Deserialize(ptr, len, SERIALIZE_XMLPLIST); } + inline Variant DeserializeXMLPLISTFile(const char *filename) { return DeserializeFile(filename, SERIALIZE_XMLPLIST); } + inline Variant DeserializeXMLPLISTFile(FILE *f) { return DeserializeFile(f, SERIALIZE_XMLPLIST); } + inline Variant DeserializeXMLPLISTFile(std::streambuf *sb) { return DeserializeFile(sb, SERIALIZE_XMLPLIST); } + + //Serialize and Deserialize BundleHdr + // + // BundleHdr requires the root element to be of MapType and + // no submaps exist. + // + // Note that these do not add a null byte to the end. + // Use SerializeBundle for that. + + inline std::string SerializeBundleHdr(Variant v) { + Variant param = Variant::MapType; + return Serialize(v, SERIALIZE_BUNDLEHDR, param); + } + inline void SerializeBundleHdr(const std::string &filename, Variant v) { + Variant param = Variant::MapType; + Serialize(filename, v, SERIALIZE_BUNDLEHDR, param); + } + inline void SerializeBundleHdr(FILE *f, Variant v) { + Variant param = Variant::MapType; + Serialize(f, v, SERIALIZE_BUNDLEHDR, param); + } + inline void SerializeBundleHdr(std::streambuf *sb, Variant v) { + Variant param = Variant::MapType; + Serialize(sb, v, SERIALIZE_BUNDLEHDR, param); + } + inline unsigned SerializeBundleHdr(void *ptr, unsigned len, Variant v) { + Variant param = Variant::MapType; + return Serialize(ptr, len, v, SERIALIZE_BUNDLEHDR, param); + } + + inline Variant DeserializeBundleHdr(const std::string &str) { return Deserialize(str, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleHdr(const char *str) { return Deserialize(str, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleHdr(const void *ptr, unsigned len) { return Deserialize(ptr, len, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleHdrFile(const char *filename) { return DeserializeFile(filename, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleHdrFile(FILE *f) { return DeserializeFile(f, SERIALIZE_BUNDLEHDR); } + inline Variant DeserializeBundleHdrFile(std::streambuf *sb) { return DeserializeFile(sb, SERIALIZE_BUNDLEHDR); } + +} + +/// Debug function not inside the namespace to print out a variant (calls SerializeJSON) +void VariantPrint(const libvariant::Variant v); + +#endif diff --git a/src/hos_libvariant/src/include/Variant/VariantDefines.h b/src/hos_libvariant/src/include/Variant/VariantDefines.h new file mode 100644 index 00000000..6a6df997 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/VariantDefines.h @@ -0,0 +1,50 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_DEFINES_H +#define VARIANT_DEFINES_H + +#ifdef __GNUC__ +#define DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED __declspec(deprecated) +#else +#pragma message("WARNING: You need to implement DEPRECATED for this compiler") +#define DEPRECATED +#endif + +namespace libvariant { + class VariantDefines { + public: + enum Type_t { + NullType = 0, // Explicitly defined as 0 + BoolType, + IntegerType, + UnsignedType, + FloatType, + StringType, + ListType, + MapType, + BlobType + }; + + }; +} +#endif diff --git a/src/hos_libvariant/src/include/Variant/VariantInternal.h b/src/hos_libvariant/src/include/Variant/VariantInternal.h new file mode 100644 index 00000000..5d9ed0f3 --- /dev/null +++ b/src/hos_libvariant/src/include/Variant/VariantInternal.h @@ -0,0 +1,95 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_BASE_H +#define VARIANT_BASE_H +#include +#include +#include +#include +#include +#include +#include +#include +namespace libvariant { + + struct RefTag {}; + + class Variant; + template class VariantRefImpl; + + + /** + * Action implementation for the VariantRef class. + */ + template + class VariantRefImpl : public Base { + public: + VariantRefImpl(const Variant &o) : Base(RefTag(), o) {} + VariantRefImpl(Variant &o, const Path &path) + : Base(RefTag(), o, path.begin(), path.end()) {} + VariantRefImpl(Variant &o, Path::const_iterator b, Path::const_iterator e) + : Base(RefTag(), o, b, e) {} + VariantRefImpl(const VariantRefImpl &o) + : Base(RefTag(), o) {} + + using Base::operator=; + using Base::As; + using Base::AsNumber; + using Base::GetInto; + using Base::GetPathInto; + using Base::Assign; + + using Base::ReassignRef; + }; + + namespace Internal { + + class VTable; + struct Storage; + struct MapStorage; + struct ListStorage; + struct ProxyStorage; + struct RefData; + + struct Data { + Data(); + const VTable *vtable; + union { + bool b; + long double f; + intmax_t i; + uintmax_t u; + std::string *s; + MapStorage *m; + ListStorage *l; + BlobPtr *blob; + Data *ref; + ProxyStorage *proxy; + }; + shared_ptr ref_data; + shared_ptr storage; + }; + } + + + +} +#endif diff --git a/src/hos_libvariant/src/lib/json/JSON_PARSER_README.htm b/src/hos_libvariant/src/lib/json/JSON_PARSER_README.htm new file mode 100644 index 00000000..b4bfe0d9 --- /dev/null +++ b/src/hos_libvariant/src/lib/json/JSON_PARSER_README.htm @@ -0,0 +1,16 @@ +A JSON parser based on http://www.json.org's JSON_checker code. + +Copyright (c) 2007-2009 Jean Gressmann (jean@0x42.de). + +For license information, see JSON_parser.c. + +JSON parser features: +- arbitrary levels of JSON object/array nesting, +- C-style comments, +- UTF-16 & escape sequence (\uXXXX) decoding to UTF-8. +- Manual processing of floating point values. + +The parser processes UTF-8 encoded JSON only. +JSON object keys and JSON strings are returned as UTF-8 encoded C strings. + + diff --git a/src/hos_libvariant/src/lib/json/JSON_parser.c b/src/hos_libvariant/src/lib/json/JSON_parser.c new file mode 100644 index 00000000..b70c9ae0 --- /dev/null +++ b/src/hos_libvariant/src/lib/json/JSON_parser.c @@ -0,0 +1,1013 @@ +/* +Copyright (c) 2005 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/* + Callbacks, comments, Unicode handling by Jean Gressmann (jean@0x42.de), 2007-2009. + + Changelog: + 2009-10-19 + Replaced long double in JSON_value_struct with double after reports + of strtold being broken on some platforms (charles@transmissionbt.com). + + 2009-05-17 + Incorporated benrudiak@googlemail.com fix for UTF16 decoding. + + 2009-05-14 + Fixed float parsing bug related to a locale being set that didn't + use '.' as decimal point character (charles@transmissionbt.com). + + 2008-10-14 + Renamed states.IN to states.IT to avoid name clash which IN macro + defined in windef.h (alexey.pelykh@gmail.com) + + 2008-07-19 + Removed some duplicate code & debugging variable (charles@transmissionbt.com) + + 2008-05-28 + Made JSON_value structure ansi C compliant. This bug was report by + trisk@acm.jhu.edu + + 2008-05-20 + Fixed bug reported by charles@transmissionbt.com where the switching + from static to dynamic parse buffer did not copy the static parse + buffer's content. +*/ + + + +#include "../../../src/lib/json/JSON_parser.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef _MSC_VER +# if _MSC_VER >= 1400 /* Visual Studio 2005 and up */ +# pragma warning(disable:4996) // unsecure sscanf +# endif +#endif + + +#define true 1 +#define false 0 +#define __ -1 /* the universal error code */ + +/* values chosen so that the object size is approx equal to one page (4K) */ +#ifndef JSON_PARSER_STACK_SIZE +# define JSON_PARSER_STACK_SIZE 128 +#endif + +#ifndef JSON_PARSER_PARSE_BUFFER_SIZE +# define JSON_PARSER_PARSE_BUFFER_SIZE 3500 +#endif + +typedef unsigned short UTF16; + +struct JSON_parser_struct { + JSON_parser_callback callback; + void* ctx; + signed char state, before_comment_state, type, escaped, comment, allow_comments, handle_floats_manually; + UTF16 utf16_high_surrogate; + long depth; + long top; + signed char* stack; + long stack_capacity; + char decimal_point; + char* parse_buffer; + size_t parse_buffer_capacity; + size_t parse_buffer_count; + size_t comment_begin_offset; + signed char static_stack[JSON_PARSER_STACK_SIZE]; + char static_parse_buffer[JSON_PARSER_PARSE_BUFFER_SIZE]; +}; + +#define COUNTOF(x) (sizeof(x)/sizeof(x[0])) + +/* + Characters are mapped into these character classes. This allows for + a significant reduction in the size of the state transition table. +*/ + + + +enum classes { + C_SPACE, /* space */ + C_WHITE, /* other whitespace */ + C_LCURB, /* { */ + C_RCURB, /* } */ + C_LSQRB, /* [ */ + C_RSQRB, /* ] */ + C_COLON, /* : */ + C_COMMA, /* , */ + C_QUOTE, /* " */ + C_BACKS, /* \ */ + C_SLASH, /* / */ + C_PLUS, /* + */ + C_MINUS, /* - */ + C_POINT, /* . */ + C_ZERO , /* 0 */ + C_DIGIT, /* 123456789 */ + C_LOW_A, /* a */ + C_LOW_B, /* b */ + C_LOW_C, /* c */ + C_LOW_D, /* d */ + C_LOW_E, /* e */ + C_LOW_F, /* f */ + C_LOW_L, /* l */ + C_LOW_N, /* n */ + C_LOW_R, /* r */ + C_LOW_S, /* s */ + C_LOW_T, /* t */ + C_LOW_U, /* u */ + C_ABCDF, /* ABCDF */ + C_E, /* E */ + C_ETC, /* everything else */ + C_STAR, /* * */ + NR_CLASSES +}; + +static int ascii_class[128] = { +/* + This array maps the 128 ASCII characters into character classes. + The remaining Unicode characters should be mapped to C_ETC. + Non-whitespace control characters are errors. +*/ + __, __, __, __, __, __, __, __, + __, C_WHITE, C_WHITE, __, __, C_WHITE, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + + C_SPACE, C_ETC, C_QUOTE, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, + C_ETC, C_ETC, C_STAR, C_PLUS, C_COMMA, C_MINUS, C_POINT, C_SLASH, + C_ZERO, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, + C_DIGIT, C_DIGIT, C_COLON, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, + + C_ETC, C_ABCDF, C_ABCDF, C_ABCDF, C_ABCDF, C_E, C_ABCDF, C_ETC, + C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, + C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, + C_ETC, C_ETC, C_ETC, C_LSQRB, C_BACKS, C_RSQRB, C_ETC, C_ETC, + + C_ETC, C_LOW_A, C_LOW_B, C_LOW_C, C_LOW_D, C_LOW_E, C_LOW_F, C_ETC, + C_ETC, C_ETC, C_ETC, C_ETC, C_LOW_L, C_ETC, C_LOW_N, C_ETC, + C_ETC, C_ETC, C_LOW_R, C_LOW_S, C_LOW_T, C_LOW_U, C_ETC, C_ETC, + C_ETC, C_ETC, C_ETC, C_LCURB, C_ETC, C_RCURB, C_ETC, C_ETC +}; + + +/* + The state codes. +*/ +enum states { + GO, /* start */ + OK, /* ok */ + OB, /* object */ + KE, /* key */ + CO, /* colon */ + VA, /* value */ + AR, /* array */ + ST, /* string */ + ES, /* escape */ + U1, /* u1 */ + U2, /* u2 */ + U3, /* u3 */ + U4, /* u4 */ + MI, /* minus */ + ZE, /* zero */ + IT, /* integer */ + FR, /* fraction */ + E1, /* e */ + E2, /* ex */ + E3, /* exp */ + T1, /* tr */ + T2, /* tru */ + T3, /* true */ + F1, /* fa */ + F2, /* fal */ + F3, /* fals */ + F4, /* false */ + N1, /* nu */ + N2, /* nul */ + N3, /* null */ + C1, /* / */ + C2, /* / * */ + C3, /* * */ + FX, /* *.* *eE* */ + D1, /* second UTF-16 character decoding started by \ */ + D2, /* second UTF-16 character proceeded by u */ + NR_STATES +}; + +enum actions +{ + CB = -10, /* comment begin */ + CE = -11, /* comment end */ + FA = -12, /* false */ + TR = -13, /* false */ + NU = -14, /* null */ + DE = -15, /* double detected by exponent e E */ + DF = -16, /* double detected by fraction . */ + SB = -17, /* string begin */ + MX = -18, /* integer detected by minus */ + ZX = -19, /* integer detected by zero */ + IX = -20, /* integer detected by 1-9 */ + EX = -21, /* next char is escaped */ + UC = -22 /* Unicode character read */ +}; + + +static int state_transition_table[NR_STATES][NR_CLASSES] = { +/* + The state transition table takes the current state and the current symbol, + and returns either a new state or an action. An action is represented as a + negative number. A JSON text is accepted if at the end of the text the + state is OK and if the mode is MODE_DONE. + + white 1-9 ABCDF etc + space | { } [ ] : , " \ / + - . 0 | a b c d e f l n r s t u | E | * */ +/*start GO*/ {GO,GO,-6,__,-5,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*ok OK*/ {OK,OK,__,-8,__,-7,__,-3,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*object OB*/ {OB,OB,__,-9,__,__,__,__,SB,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*key KE*/ {KE,KE,__,__,__,__,__,__,SB,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*colon CO*/ {CO,CO,__,__,__,__,-2,__,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*value VA*/ {VA,VA,-6,__,-5,__,__,__,SB,__,CB,__,MX,__,ZX,IX,__,__,__,__,__,FA,__,NU,__,__,TR,__,__,__,__,__}, +/*array AR*/ {AR,AR,-6,__,-5,-7,__,__,SB,__,CB,__,MX,__,ZX,IX,__,__,__,__,__,FA,__,NU,__,__,TR,__,__,__,__,__}, +/*string ST*/ {ST,__,ST,ST,ST,ST,ST,ST,-4,EX,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST}, +/*escape ES*/ {__,__,__,__,__,__,__,__,ST,ST,ST,__,__,__,__,__,__,ST,__,__,__,ST,__,ST,ST,__,ST,U1,__,__,__,__}, +/*u1 U1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U2,U2,U2,U2,U2,U2,U2,U2,__,__,__,__,__,__,U2,U2,__,__}, +/*u2 U2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U3,U3,U3,U3,U3,U3,U3,U3,__,__,__,__,__,__,U3,U3,__,__}, +/*u3 U3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U4,U4,U4,U4,U4,U4,U4,U4,__,__,__,__,__,__,U4,U4,__,__}, +/*u4 U4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,UC,UC,UC,UC,UC,UC,UC,UC,__,__,__,__,__,__,UC,UC,__,__}, +/*minus MI*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ZE,IT,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*zero ZE*/ {OK,OK,__,-8,__,-7,__,-3,__,__,CB,__,__,DF,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*int IT*/ {OK,OK,__,-8,__,-7,__,-3,__,__,CB,__,__,DF,IT,IT,__,__,__,__,DE,__,__,__,__,__,__,__,__,DE,__,__}, +/*frac FR*/ {OK,OK,__,-8,__,-7,__,-3,__,__,CB,__,__,__,FR,FR,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__,__}, +/*e E1*/ {__,__,__,__,__,__,__,__,__,__,__,E2,E2,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*ex E2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*exp E3*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*tr T1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T2,__,__,__,__,__,__,__}, +/*tru T2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T3,__,__,__,__}, +/*true T3*/ {__,__,__,__,__,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__,__}, +/*fa F1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*fal F2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F3,__,__,__,__,__,__,__,__,__}, +/*fals F3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F4,__,__,__,__,__,__}, +/*false F4*/ {__,__,__,__,__,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__,__}, +/*nu N1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N2,__,__,__,__}, +/*nul N2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N3,__,__,__,__,__,__,__,__,__}, +/*null N3*/ {__,__,__,__,__,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__}, +/*/ C1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,C2}, +/*/* C2*/ {C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3}, +/** C3*/ {C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,CE,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3}, +/*_. FX*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,FR,FR,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__,__}, +/*\ D1*/ {__,__,__,__,__,__,__,__,__,D2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, +/*\ D2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,U1,__,__,__,__}, +}; + + +/* + These modes can be pushed on the stack. +*/ +enum modes { + MODE_ARRAY = 1, + MODE_DONE = 2, + MODE_KEY = 3, + MODE_OBJECT = 4 +}; + +static int +push(JSON_parser jc, int mode) +{ +/* + Push a mode onto the stack. Return false if there is overflow. +*/ + jc->top += 1; + if (jc->depth < 0) { + if (jc->top >= jc->stack_capacity) { + size_t bytes_to_allocate; + jc->stack_capacity *= 2; + bytes_to_allocate = jc->stack_capacity * sizeof(jc->static_stack[0]); + if (jc->stack == &jc->static_stack[0]) { + jc->stack = (signed char*)malloc(bytes_to_allocate); + memcpy(jc->stack, jc->static_stack, sizeof(jc->static_stack)); + } else { + jc->stack = (signed char*)realloc(jc->stack, bytes_to_allocate); + } + } + } else { + if (jc->top >= jc->depth) { + return false; + } + } + + jc->stack[jc->top] = mode; + return true; +} + + +static int +pop(JSON_parser jc, int mode) +{ +/* + Pop the stack, assuring that the current mode matches the expectation. + Return false if there is underflow or if the modes mismatch. +*/ + if (jc->top < 0 || jc->stack[jc->top] != mode) { + return false; + } + jc->top -= 1; + return true; +} + + +#define parse_buffer_clear(jc) \ + do {\ + jc->parse_buffer_count = 0;\ + jc->parse_buffer[0] = 0;\ + } while (0) + +#define parse_buffer_pop_back_char(jc)\ + do {\ + assert(jc->parse_buffer_count >= 1);\ + --jc->parse_buffer_count;\ + jc->parse_buffer[jc->parse_buffer_count] = 0;\ + } while (0) + +void delete_JSON_parser(JSON_parser jc) +{ + if (jc) { + if (jc->stack != &jc->static_stack[0]) { + free((void*)jc->stack); + } + if (jc->parse_buffer != &jc->static_parse_buffer[0]) { + free((void*)jc->parse_buffer); + } + free((void*)jc); + } +} + + +JSON_parser +new_JSON_parser(JSON_config* config) +{ +/* + new_JSON_parser starts the checking process by constructing a JSON_parser + object. It takes a depth parameter that restricts the level of maximum + nesting. + + To continue the process, call JSON_parser_char for each character in the + JSON text, and then call JSON_parser_done to obtain the final result. + These functions are fully reentrant. +*/ + + int depth = 0; + JSON_config default_config; + + JSON_parser jc = malloc(sizeof(struct JSON_parser_struct)); + + memset(jc, 0, sizeof(*jc)); + + + /* initialize configuration */ + init_JSON_config(&default_config); + + /* set to default configuration if none was provided */ + if (config == NULL) { + config = &default_config; + } + + depth = config->depth; + + /* We need to be able to push at least one object */ + if (depth == 0) { + depth = 1; + } + + jc->state = GO; + jc->top = -1; + + /* Do we want non-bound stack? */ + if (depth > 0) { + jc->stack_capacity = depth; + jc->depth = depth; + if (depth <= (int)COUNTOF(jc->static_stack)) { + jc->stack = &jc->static_stack[0]; + } else { + jc->stack = (signed char*)malloc(jc->stack_capacity * sizeof(jc->static_stack[0])); + } + } else { + jc->stack_capacity = COUNTOF(jc->static_stack); + jc->depth = -1; + jc->stack = &jc->static_stack[0]; + } + + /* set parser to start */ + push(jc, MODE_DONE); + + /* set up the parse buffer */ + jc->parse_buffer = &jc->static_parse_buffer[0]; + jc->parse_buffer_capacity = COUNTOF(jc->static_parse_buffer); + parse_buffer_clear(jc); + + /* set up callback, comment & float handling */ + jc->callback = config->callback; + jc->ctx = config->callback_ctx; + jc->allow_comments = config->allow_comments != 0; + jc->handle_floats_manually = config->handle_floats_manually != 0; + + /* set up decimal point */ + jc->decimal_point = *localeconv()->decimal_point; + + return jc; +} + +static void grow_parse_buffer(JSON_parser jc) +{ + size_t bytes_to_allocate; + jc->parse_buffer_capacity *= 2; + bytes_to_allocate = jc->parse_buffer_capacity * sizeof(jc->parse_buffer[0]); + if (jc->parse_buffer == &jc->static_parse_buffer[0]) { + jc->parse_buffer = (char*)malloc(bytes_to_allocate); + memcpy(jc->parse_buffer, jc->static_parse_buffer, jc->parse_buffer_count); + } else { + jc->parse_buffer = (char*)realloc(jc->parse_buffer, bytes_to_allocate); + } +} + +#define parse_buffer_push_back_char(jc, c)\ + do {\ + if (jc->parse_buffer_count + 1 >= jc->parse_buffer_capacity) grow_parse_buffer(jc);\ + jc->parse_buffer[jc->parse_buffer_count++] = c;\ + jc->parse_buffer[jc->parse_buffer_count] = 0;\ + } while (0) + +#define assert_is_non_container_type(jc) \ + assert( \ + jc->type == JSON_T_NULL || \ + jc->type == JSON_T_FALSE || \ + jc->type == JSON_T_TRUE || \ + jc->type == JSON_T_FLOAT || \ + jc->type == JSON_T_INTEGER || \ + jc->type == JSON_T_UNSIGNED || \ + jc->type == JSON_T_STRING) + + +static int parse_parse_buffer(JSON_parser jc) +{ + if (jc->callback) { + JSON_value value, *arg = NULL; + + if (jc->type != JSON_T_NONE) { + assert_is_non_container_type(jc); + + switch(jc->type) { + case JSON_T_FLOAT: + arg = &value; + if (jc->handle_floats_manually) { + value.vu.str.value = jc->parse_buffer; + value.vu.str.length = jc->parse_buffer_count; + } else { + /* not checking with end pointer b/c there may be trailing ws */ + value.vu.float_value = strtod(jc->parse_buffer, NULL); + } + break; + case JSON_T_INTEGER: + arg = &value; + sscanf(jc->parse_buffer, JSON_PARSER_INTEGER_SSCANF_TOKEN, &value.vu.integer_value); + break; + case JSON_T_UNSIGNED: + arg = &value; + sscanf(jc->parse_buffer, JSON_PARSER_UNSIGNED_SSCANF_TOKEN, &value.vu.unsigned_value); + break; + case JSON_T_STRING: + arg = &value; + value.vu.str.value = jc->parse_buffer; + value.vu.str.length = jc->parse_buffer_count; + break; + } + + if (!(*jc->callback)(jc->ctx, jc->type, arg)) { + return false; + } + } + } + + parse_buffer_clear(jc); + + return true; +} + +#define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800) +#define IS_LOW_SURROGATE(uc) (((uc) & 0xFC00) == 0xDC00) +#define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000) +static unsigned char utf8_lead_bits[4] = { 0x00, 0xC0, 0xE0, 0xF0 }; + +static int decode_unicode_char(JSON_parser jc) +{ + int i; + unsigned uc = 0; + char* p; + int trail_bytes; + + assert(jc->parse_buffer_count >= 6); + + p = &jc->parse_buffer[jc->parse_buffer_count - 4]; + + for (i = 12; i >= 0; i -= 4, ++p) { + unsigned x = *p; + + if (x >= 'a') { + x -= ('a' - 10); + } else if (x >= 'A') { + x -= ('A' - 10); + } else { + x &= ~0x30u; + } + + assert(x < 16); + + uc |= x << i; + } + + /* clear UTF-16 char from buffer */ + jc->parse_buffer_count -= 6; + jc->parse_buffer[jc->parse_buffer_count] = 0; + + /* attempt decoding ... */ + if (jc->utf16_high_surrogate) { + if (IS_LOW_SURROGATE(uc)) { + uc = DECODE_SURROGATE_PAIR(jc->utf16_high_surrogate, uc); + trail_bytes = 3; + jc->utf16_high_surrogate = 0; + } else { + /* high surrogate without a following low surrogate */ + return false; + } + } else { + if (uc < 0x80) { + trail_bytes = 0; + } else if (uc < 0x800) { + trail_bytes = 1; + } else if (IS_HIGH_SURROGATE(uc)) { + /* save the high surrogate and wait for the low surrogate */ + jc->utf16_high_surrogate = uc; + return true; + } else if (IS_LOW_SURROGATE(uc)) { + /* low surrogate without a preceding high surrogate */ + return false; + } else { + trail_bytes = 2; + } + } + + jc->parse_buffer[jc->parse_buffer_count++] = (char) ((uc >> (trail_bytes * 6)) | utf8_lead_bits[trail_bytes]); + + for (i = trail_bytes * 6 - 6; i >= 0; i -= 6) { + jc->parse_buffer[jc->parse_buffer_count++] = (char) (((uc >> i) & 0x3F) | 0x80); + } + + jc->parse_buffer[jc->parse_buffer_count] = 0; + + return true; +} + +static int add_escaped_char_to_parse_buffer(JSON_parser jc, int next_char) +{ + jc->escaped = 0; + /* remove the backslash */ + parse_buffer_pop_back_char(jc); + switch(next_char) { + case 'b': + parse_buffer_push_back_char(jc, '\b'); + break; + case 'f': + parse_buffer_push_back_char(jc, '\f'); + break; + case 'n': + parse_buffer_push_back_char(jc, '\n'); + break; + case 'r': + parse_buffer_push_back_char(jc, '\r'); + break; + case 't': + parse_buffer_push_back_char(jc, '\t'); + break; + case '"': + parse_buffer_push_back_char(jc, '"'); + break; + case '\\': + parse_buffer_push_back_char(jc, '\\'); + break; + case '/': + parse_buffer_push_back_char(jc, '/'); + break; + case 'u': + parse_buffer_push_back_char(jc, '\\'); + parse_buffer_push_back_char(jc, 'u'); + break; + default: + return false; + } + + return true; +} + +#define add_char_to_parse_buffer(jc, next_char, next_class) \ + do { \ + if (jc->escaped) { \ + if (!add_escaped_char_to_parse_buffer(jc, next_char)) \ + return false; \ + } else if (!jc->comment) { \ + if ((jc->type != JSON_T_NONE) | !((next_class == C_SPACE) | (next_class == C_WHITE)) /* non-white-space */) { \ + parse_buffer_push_back_char(jc, (char)next_char); \ + } \ + } \ + } while (0) + + +#define assert_type_isnt_string_null_or_bool(jc) \ + assert(jc->type != JSON_T_FALSE); \ + assert(jc->type != JSON_T_TRUE); \ + assert(jc->type != JSON_T_NULL); \ + assert(jc->type != JSON_T_STRING) + + +int +JSON_parser_char(JSON_parser jc, int next_char) +{ +/* + After calling new_JSON_parser, call this function for each character (or + partial character) in your JSON text. It can accept UTF-8, UTF-16, or + UTF-32. It returns true if things are looking ok so far. If it rejects the + text, it returns false. +*/ + int next_class, next_state; + +/* + Determine the character's class. +*/ + if (next_char < 0) { + return false; + } + if (next_char >= 128) { + next_class = C_ETC; + } else { + next_class = ascii_class[next_char]; + if (next_class <= __) { + return false; + } + } + + add_char_to_parse_buffer(jc, next_char, next_class); + +/* + Get the next state from the state transition table. +*/ + next_state = state_transition_table[jc->state][next_class]; + if (next_state >= 0) { +/* + Change the state. +*/ + jc->state = next_state; + } else { +/* + Or perform one of the actions. +*/ + switch (next_state) { +/* Unicode character */ + case UC: + if(!decode_unicode_char(jc)) { + return false; + } + /* check if we need to read a second UTF-16 char */ + if (jc->utf16_high_surrogate) { + jc->state = D1; + } else { + jc->state = ST; + } + break; +/* escaped char */ + case EX: + jc->escaped = 1; + jc->state = ES; + break; +/* integer detected by minus */ + case MX: + jc->type = JSON_T_INTEGER; + jc->state = MI; + break; +/* integer detected by zero */ + case ZX: + jc->type = JSON_T_UNSIGNED; + jc->state = ZE; + break; +/* integer detected by 1-9 */ + case IX: + jc->type = JSON_T_UNSIGNED; + jc->state = IT; + break; + +/* floating point number detected by exponent*/ + case DE: + assert_type_isnt_string_null_or_bool(jc); + jc->type = JSON_T_FLOAT; + jc->state = E1; + break; + +/* floating point number detected by fraction */ + case DF: + assert_type_isnt_string_null_or_bool(jc); + if (!jc->handle_floats_manually) { +/* + Some versions of strtod (which underlies sscanf) don't support converting + C-locale formated floating point values. +*/ + assert(jc->parse_buffer[jc->parse_buffer_count-1] == '.'); + jc->parse_buffer[jc->parse_buffer_count-1] = jc->decimal_point; + } + jc->type = JSON_T_FLOAT; + jc->state = FX; + break; +/* string begin " */ + case SB: + parse_buffer_clear(jc); + assert(jc->type == JSON_T_NONE); + jc->type = JSON_T_STRING; + jc->state = ST; + break; + +/* n */ + case NU: + assert(jc->type == JSON_T_NONE); + jc->type = JSON_T_NULL; + jc->state = N1; + break; +/* f */ + case FA: + assert(jc->type == JSON_T_NONE); + jc->type = JSON_T_FALSE; + jc->state = F1; + break; +/* t */ + case TR: + assert(jc->type == JSON_T_NONE); + jc->type = JSON_T_TRUE; + jc->state = T1; + break; + +/* closing comment */ + case CE: + jc->comment = 0; + assert(jc->parse_buffer_count == 0); + assert(jc->type == JSON_T_NONE); + jc->state = jc->before_comment_state; + break; + +/* opening comment */ + case CB: + if (!jc->allow_comments) { + return false; + } + parse_buffer_pop_back_char(jc); + if (!parse_parse_buffer(jc)) { + return false; + } + assert(jc->parse_buffer_count == 0); + assert(jc->type != JSON_T_STRING); + switch (jc->stack[jc->top]) { + case MODE_ARRAY: + case MODE_OBJECT: + switch(jc->state) { + case VA: + case AR: + jc->before_comment_state = jc->state; + break; + default: + jc->before_comment_state = OK; + break; + } + break; + default: + jc->before_comment_state = jc->state; + break; + } + jc->type = JSON_T_NONE; + jc->state = C1; + jc->comment = 1; + break; +/* empty } */ + case -9: + parse_buffer_clear(jc); + if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_OBJECT_END, NULL)) { + return false; + } + if (!pop(jc, MODE_KEY)) { + return false; + } + jc->state = OK; + break; + +/* } */ case -8: + parse_buffer_pop_back_char(jc); + if (!parse_parse_buffer(jc)) { + return false; + } + if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_OBJECT_END, NULL)) { + return false; + } + if (!pop(jc, MODE_OBJECT)) { + return false; + } + jc->type = JSON_T_NONE; + jc->state = OK; + break; + +/* ] */ case -7: + parse_buffer_pop_back_char(jc); + if (!parse_parse_buffer(jc)) { + return false; + } + if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_ARRAY_END, NULL)) { + return false; + } + if (!pop(jc, MODE_ARRAY)) { + return false; + } + + jc->type = JSON_T_NONE; + jc->state = OK; + break; + +/* { */ case -6: + parse_buffer_pop_back_char(jc); + if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_OBJECT_BEGIN, NULL)) { + return false; + } + if (!push(jc, MODE_KEY)) { + return false; + } + assert(jc->type == JSON_T_NONE); + jc->state = OB; + break; + +/* [ */ case -5: + parse_buffer_pop_back_char(jc); + if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_ARRAY_BEGIN, NULL)) { + return false; + } + if (!push(jc, MODE_ARRAY)) { + return false; + } + assert(jc->type == JSON_T_NONE); + jc->state = AR; + break; + +/* string end " */ case -4: + parse_buffer_pop_back_char(jc); + switch (jc->stack[jc->top]) { + case MODE_KEY: + assert(jc->type == JSON_T_STRING); + jc->type = JSON_T_NONE; + jc->state = CO; + + if (jc->callback) { + JSON_value value; + value.vu.str.value = jc->parse_buffer; + value.vu.str.length = jc->parse_buffer_count; + if (!(*jc->callback)(jc->ctx, JSON_T_KEY, &value)) { + return false; + } + } + parse_buffer_clear(jc); + break; + case MODE_ARRAY: + case MODE_OBJECT: + assert(jc->type == JSON_T_STRING); + if (!parse_parse_buffer(jc)) { + return false; + } + jc->type = JSON_T_NONE; + jc->state = OK; + break; + default: + return false; + } + break; + +/* , */ case -3: + parse_buffer_pop_back_char(jc); + if (!parse_parse_buffer(jc)) { + return false; + } + switch (jc->stack[jc->top]) { + case MODE_OBJECT: +/* + A comma causes a flip from object mode to key mode. +*/ + if (!pop(jc, MODE_OBJECT) || !push(jc, MODE_KEY)) { + return false; + } + assert(jc->type != JSON_T_STRING); + jc->type = JSON_T_NONE; + jc->state = KE; + break; + case MODE_ARRAY: + assert(jc->type != JSON_T_STRING); + jc->type = JSON_T_NONE; + jc->state = VA; + break; + default: + return false; + } + break; + +/* : */ case -2: +/* + A colon causes a flip from key mode to object mode. +*/ + parse_buffer_pop_back_char(jc); + if (!pop(jc, MODE_KEY) || !push(jc, MODE_OBJECT)) { + return false; + } + assert(jc->type == JSON_T_NONE); + jc->state = VA; + break; +/* + Bad action. +*/ + default: + return false; + } + } + return true; +} + + +int +JSON_parser_done(JSON_parser jc) +{ + const int result = jc->state == OK && pop(jc, MODE_DONE); + + return result; +} + + +int JSON_parser_is_legal_white_space_string(const char* s) +{ + int c, char_class; + + if (s == NULL) { + return false; + } + + for (; *s; ++s) { + c = *s; + + if (c < 0 || c >= 128) { + return false; + } + + char_class = ascii_class[c]; + + if (char_class != C_SPACE && char_class != C_WHITE) { + return false; + } + } + + return true; +} + + +void init_JSON_config(JSON_config* config) +{ + if (config) { + memset(config, 0, sizeof(*config)); + + config->depth = JSON_PARSER_STACK_SIZE - 1; + } +} diff --git a/src/hos_libvariant/src/lib/json/JSON_parser.h b/src/hos_libvariant/src/lib/json/JSON_parser.h new file mode 100644 index 00000000..93207a3f --- /dev/null +++ b/src/hos_libvariant/src/lib/json/JSON_parser.h @@ -0,0 +1,162 @@ +#ifndef JSON_PARSER_H +#define JSON_PARSER_H +#pragma once + +/* JSON_parser.h */ + + +#include + +/* Windows DLL stuff */ +#ifdef _WIN32 +# ifdef JSON_PARSER_DLL_EXPORTS +# define JSON_PARSER_DLL_API __declspec(dllexport) +# else +# define JSON_PARSER_DLL_API __declspec(dllimport) +# endif +#else +# define JSON_PARSER_DLL_API +#endif + +/* Determine the integer type use to parse non-floating point numbers */ +#if __STDC_VERSION__ >= 199901L || HAVE_LONG_LONG == 1 +typedef long long JSON_int_t; +typedef unsigned long long JSON_uint_t; +#define JSON_PARSER_INTEGER_SSCANF_TOKEN "%lld" +#define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%lld" +#define JSON_PARSER_UNSIGNED_SSCANF_TOKEN "%llu" +#define JSON_PARSER_UNSIGNED_SPRINTF_TOKEN "%llu" +#else +typedef long JSON_int_t; +typedef unsigned long JSON_uint_t; +#define JSON_PARSER_INTEGER_SSCANF_TOKEN "%ld" +#define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%ld" +#define JSON_PARSER_UNSIGNED_SSCANF_TOKEN "%lu" +#define JSON_PARSER_UNSIGNED_SPRINTF_TOKEN "%lu" +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + JSON_T_NONE = 0, + JSON_T_ARRAY_BEGIN, + JSON_T_ARRAY_END, + JSON_T_OBJECT_BEGIN, + JSON_T_OBJECT_END, + JSON_T_INTEGER, + JSON_T_UNSIGNED, + JSON_T_FLOAT, + JSON_T_NULL, + JSON_T_TRUE, + JSON_T_FALSE, + JSON_T_STRING, + JSON_T_KEY, + JSON_T_MAX +} JSON_type; + +typedef struct JSON_value_struct { + union { + JSON_int_t integer_value; + + JSON_uint_t unsigned_value; + + double float_value; + + struct { + const char* value; + size_t length; + } str; + } vu; +} JSON_value; + +typedef struct JSON_parser_struct* JSON_parser; + +/*! \brief JSON parser callback + + \param ctx The pointer passed to new_JSON_parser. + \param type An element of JSON_type but not JSON_T_NONE. + \param value A representation of the parsed value. This parameter is NULL for + JSON_T_ARRAY_BEGIN, JSON_T_ARRAY_END, JSON_T_OBJECT_BEGIN, JSON_T_OBJECT_END, + JSON_T_NULL, JSON_T_TRUE, and SON_T_FALSE. String values are always returned + as zero-terminated C strings. + + \return Non-zero if parsing should continue, else zero. +*/ +typedef int (*JSON_parser_callback)(void* ctx, int type, const struct JSON_value_struct* value); + + +/*! \brief The structure used to configure a JSON parser object + + \param depth If negative, the parser can parse arbitrary levels of JSON, otherwise + the depth is the limit + \param Pointer to a callback. This parameter may be NULL. In this case the input is merely checked for validity. + \param Callback context. This parameter may be NULL. + \param depth. Specifies the levels of nested JSON to allow. Negative numbers yield unlimited nesting. + \param allowComments. To allow C style comments in JSON, set to non-zero. + \param handleFloatsManually. To decode floating point numbers manually set this parameter to non-zero. + + \return The parser object. +*/ +typedef struct { + JSON_parser_callback callback; + void* callback_ctx; + int depth; + int allow_comments; + int handle_floats_manually; +} JSON_config; + + +/*! \brief Initializes the JSON parser configuration structure to default values. + + The default configuration is + - 127 levels of nested JSON (depends on JSON_PARSER_STACK_SIZE, see json_parser.c) + - no parsing, just checking for JSON syntax + - no comments + + \param config. Used to configure the parser. +*/ +JSON_PARSER_DLL_API void init_JSON_config(JSON_config* config); + +/*! \brief Create a JSON parser object + + \param config. Used to configure the parser. Set to NULL to use the default configuration. + See init_JSON_config + + \return The parser object. +*/ +JSON_PARSER_DLL_API extern JSON_parser new_JSON_parser(JSON_config* config); + +/*! \brief Destroy a previously created JSON parser object. */ +JSON_PARSER_DLL_API extern void delete_JSON_parser(JSON_parser jc); + +/*! \brief Parse a character. + + \return Non-zero, if all characters passed to this function are part of are valid JSON. +*/ +JSON_PARSER_DLL_API extern int JSON_parser_char(JSON_parser jc, int next_char); + +/*! \brief Finalize parsing. + + Call this method once after all input characters have been consumed. + + \return Non-zero, if all parsed characters are valid JSON, zero otherwise. +*/ +JSON_PARSER_DLL_API extern int JSON_parser_done(JSON_parser jc); + +/*! \brief Determine if a given string is valid JSON white space + + \return Non-zero if the string is valid, zero otherwise. +*/ +JSON_PARSER_DLL_API extern int JSON_parser_is_legal_white_space_string(const char* s); + + +#ifdef __cplusplus +} +#endif + + +#endif /* JSON_PARSER_H */ diff --git a/src/hos_libvariant/src/libvariant.pc.in b/src/hos_libvariant/src/libvariant.pc.in new file mode 100644 index 00000000..07372752 --- /dev/null +++ b/src/hos_libvariant/src/libvariant.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@INSTALL_BIN_DIR@ +libdir=@INSTALL_LIB_DIR@ +includedir=@INSTALL_INCLUDE_DIR@ + +Name: libvariant +Description: Scripting language like variable (Variant) in C++ with serializing, deserializing, schema and other features. +Version: @VARIANT_VERSION@ +Libs: -L${libdir} -lVariant +Cflags: -I${includedir} diff --git a/src/hos_libvariant/src/src/ArgParse.cc b/src/hos_libvariant/src/src/ArgParse.cc new file mode 100644 index 00000000..0c48a15a --- /dev/null +++ b/src/hos_libvariant/src/src/ArgParse.cc @@ -0,0 +1,1855 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include "../../src/include/Variant/ArgParse.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../src/include/Variant/Extensions.h" +#include "../../src/include/Variant/Path.h" +#include "../../src/include/Variant/Schema.h" +#include "../../src/src/GuessScalar.h" +#include "../../src/src/ParseBool.h" + +#if 0 +#define DBPRINT(x) std::cout << x +#else +#define DBPRINT(X) +#endif + +namespace libvariant { + + // ----------------- + // Static data + // ----------------- + + extern const char ARG_PARSE_SCHEMA_STR[]; + static const struct ArgParseStatic { + ArgParseStatic() { + schema = DeserializeJSON(ARG_PARSE_SCHEMA_STR); + } + Variant schema; + } arg_parse_static; + + + // ---------------- + // Static and global functions + // ---------------- + + ArgParseAction ArgParseActionFromStr(const std::string &action) { + if (action == "store") { + return ARGACTION_STORE; + } else if (action == "store_const") { + return ARGACTION_STORE_CONST; + } else if (action == "store_true") { + return ARGACTION_STORE_TRUE; + } else if (action == "store_false") { + return ARGACTION_STORE_FALSE; + } else if (action == "append") { + return ARGACTION_APPEND; + } else if (action == "count") { + return ARGACTION_COUNT; + } else if (action == "help") { + return ARGACTION_HELP; + } else if (action == "adv_help") { + return ARGACTION_ADVHELP; + } else if (action == "config") { + return ARGACTION_CONFIG; + } else if (action == "config_json") { + return ARGACTION_CONFIG_JSON; + } else if (action == "config_yaml") { + return ARGACTION_CONFIG_YAML; + } else if (action == "config_plist") { + return ARGACTION_CONFIG_PLIST; + } else if (action == "config_print") { + return ARGACTION_PRINT_CONFIG; + } else { + return ARGACTION_UNKNOWN; + } + } + + std::string ArgParseActionToStr(ArgParseAction action) { + switch (action) { + case ARGACTION_STORE: + return "store"; + case ARGACTION_STORE_CONST: + return "store_const"; + case ARGACTION_STORE_TRUE: + return "store_true"; + case ARGACTION_STORE_FALSE: + return "store_false"; + case ARGACTION_APPEND: + return "append"; + case ARGACTION_COUNT: + return "count"; + case ARGACTION_HELP: + return "help"; + case ARGACTION_ADVHELP: + return "adv_help"; + case ARGACTION_CONFIG: + return "config"; + case ARGACTION_CONFIG_JSON: + return "config_json"; + case ARGACTION_CONFIG_YAML: + return "config_yaml"; + case ARGACTION_CONFIG_PLIST: + return "config_plist"; + case ARGACTION_PRINT_CONFIG: + return "config_print"; + case ARGACTION_UNKNOWN: + default: + throw std::runtime_error("ArgParseActionToStr action enum an unknown value."); + } + } + + static bool ArgParseActionHasArg(ArgParseAction action) { + switch (action) { + case ARGACTION_STORE: + case ARGACTION_APPEND: + case ARGACTION_CONFIG: + case ARGACTION_CONFIG_JSON: + case ARGACTION_CONFIG_YAML: + case ARGACTION_CONFIG_PLIST: + return true; + case ARGACTION_STORE_CONST: + case ARGACTION_STORE_TRUE: + case ARGACTION_STORE_FALSE: + case ARGACTION_COUNT: + case ARGACTION_HELP: + case ARGACTION_ADVHELP: + return false; + default: + return false; + } + } + + static bool ArgParseActionHasResult(ArgParseAction action) { + switch (action) { + case ARGACTION_STORE: + case ARGACTION_APPEND: + case ARGACTION_STORE_CONST: + case ARGACTION_STORE_TRUE: + case ARGACTION_STORE_FALSE: + case ARGACTION_COUNT: + return true; + case ARGACTION_CONFIG: + case ARGACTION_CONFIG_JSON: + case ARGACTION_CONFIG_YAML: + case ARGACTION_CONFIG_PLIST: + case ARGACTION_HELP: + case ARGACTION_ADVHELP: + return false; + default: + return false; + } + } + + ArgParseType ParseType(const Variant &type) { + if (type.IsString()) { + if (type == "string") { return ARGTYPE_STRING; } + if (type == "number") { return ARGTYPE_FLOAT; } + if (type == "integer") { return ARGTYPE_INT; } + if (type == "boolean") { return ARGTYPE_BOOL; } + if (type == "null") { return ARGTYPE_GUESS; } + + std::ostringstream oss; + oss << "libvariant::ArgParse unrecognized type \"" << type.AsString() << "\""; + throw std::runtime_error(oss.str()); + } + return ARGTYPE_GUESS; + } + + std::string TypeString(Variant::Type_t type) { + switch (type) { + case Variant::NullType: + return "null"; + case Variant::BoolType: + return "boolean"; + case Variant::IntegerType: + case Variant::UnsignedType: + return "integer"; + case Variant::FloatType: + return "number"; + case Variant::StringType: + return "string"; + case Variant::ListType: + case Variant::MapType: + case Variant::BlobType: + default: + return "null"; + } + } + + //----------------- + // + + struct ArgParseOptImpl { + ArgParseOptImpl(ArgParseImpl *i, int id, const Path &p, int sOpt, const std::string &lOpt, + const std::string &htxt, ArgParseAction a); + void Set(const std::string &key, Variant v) { opt.Set(key, v); } + bool HasArg() const { return ArgParseActionHasArg(action); } + bool HasResult() { return ArgParseActionHasResult(action); } + void HandleOption(const char *arg) { Handle(ParseArg(arg)); } + void Handle(Variant arg); + void CheckRequirements(Variant val); + Variant ParseArg(const char *arg); + void Init(Variant o); + + void FinalizeResult(); + void FormResult(VariantRef res); + + std::ostream &MakeArgString(std::ostream &os) const; + void HelpLine(std::ostream &os, bool is_arg, bool adv, unsigned indent) const; + Variant GetDescription() const; + void GenerateSchema(VariantRef schema) const; + void GenerateSchema(VariantRef schema, Path::const_iterator i, Path::const_iterator e) const; + void GenerateObjectSchema(VariantRef schema, Path::const_iterator i, Path::const_iterator e) const; + void GenerateArraySchema(VariantRef schema, Path::const_iterator i, Path::const_iterator e) const; + Variant GenerateSchema() const; + + Variant::Type_t type; + Path path; + int id; + std::set groups; + int shortOpt; + std::string longOpt; + ArgParseAction action; + bool required; + bool advanced; + ArgParseImpl *impl; + Variant opt; + Variant result; + }; + + struct ArgString { + ArgString(const ArgParseOptImpl &o) : opt(o) {} + const ArgParseOptImpl &opt; + }; + static std::ostream &operator<<(std::ostream &os, const ArgString &as) { + return as.opt.MakeArgString(os); + } + + struct OptName { + OptName(ArgParseOptImpl *o, bool a=true) : opt(o), arg(a) {} + ArgParseOptImpl *opt; + bool arg; + }; + + static std::ostream &operator<<(std::ostream &os, const OptName &o) { + if (o.opt->longOpt != "") { + os << "option --" << o.opt->longOpt; + if (o.arg) os << " argument"; + } else if (o.opt->shortOpt != 0) { + os << "option -" << (char)o.opt->shortOpt; + if (o.arg) os << " argument"; + } else { + os << "argument " << o.opt->opt.Get("title").AsString(); + } + return os; + } + + struct ArgParseGroupImpl { + + ArgParseGroupImpl(ArgParseImpl *i, const std::string &name_) + : name(name_), + required(false), + mutually_exclusive(false), + advanced(false), + impl(i) + {} + + void Add(const Path &path); + void Add(ArgParseOptImpl *i); + void Init(Variant o); + void FinalizeResult(); + Variant GetDescription() const; + void GenerateSchema(VariantRef schema) const; + void GroupSchema(VariantRef schema, const ArgParseOptImpl *opt, + Path::const_iterator i, Path::const_iterator e) const; + + std::string name; + std::string title; + std::string description; + std::set members; + bool required; + bool mutually_exclusive; + bool advanced; + ArgParseImpl *impl; + }; + + struct ArgParseImpl { + + ArgParseImpl(const std::string &pname, bool addhelp) + : option_count(256), resolve_conflicts(false), have_advanced(false), + add_help(addhelp), print_help(false), + print_adv_help(false), print_config(false) + { + SetProgramName(pname); + } + + ArgParseOptImpl *AddOption(const std::string &keypath, int shortOpt, const std::string &longOpt, + const std::string &helptxt, ArgParseAction action) + { + Path path; + ParsePath(path, keypath); + int id = CheckExisting(path, shortOpt, longOpt); + if (longOpt.empty() && shortOpt == 0) { + throw std::runtime_error("ArgParse: Error attempting to add an option without" + " a short or long option."); + } + options.push_back(id); + optmap_iter i = option_map.insert(std::make_pair(id, + ArgParseOptImpl(this, id, path, shortOpt, longOpt, helptxt, action))).first; + if (!longOpt.empty()) { + longOpts.insert(std::make_pair(longOpt, id)); + } + if (shortOpt > 0) { + shortOpts.insert(std::make_pair((char)shortOpt, id)); + } + paths.insert(std::make_pair(PathString(path), id)); + return &i->second; + } + + ArgParseOptImpl *At(const std::string &keypath) { + Path path; + ParsePath(path, keypath); + return At(path); + } + + ArgParseOptImpl *At(const Path &path) { + std::map::iterator path_iter; + path_iter = paths.find(PathString(path)); + if (path_iter == paths.end()) { + throw std::runtime_error("ArgParse error, attempting to reference an non-existing option"); + } + return GetOpt(path_iter->second); + } + + ArgParseOptImpl *GetOpt(int id) { + return &option_map.find(id)->second; + } + + const ArgParseOptImpl *GetOpt(int id) const { + return &option_map.find(id)->second; + } + + ArgParseOptImpl *AddArgument(const std::string &keypath, const std::string &helptxt, + ArgParseAction action=ARGACTION_STORE) { + Path path; + ParsePath(path, keypath); + int sopt = 0; + int id = CheckExisting(path, sopt, ""); + arguments.push_back(id); + optmap_iter i = option_map.insert(std::make_pair(id, + ArgParseOptImpl(this, id, path, 0, "", helptxt, action) + )).first; + paths.insert(std::make_pair(PathString(path), id)); + i->second.Init(Variant().Set("maxArgs", 1).Set("minArgs", 1)); + return &i->second; + } + + ArgParseOptImpl *At(unsigned arg_index) { + return GetOpt(arguments.at(arg_index)); + } + + ArgParseGroupImpl *GetGroup(const std::string &name) { + return &groups.insert(std::make_pair(name, ArgParseGroupImpl(this, name))).first->second; + } + + void ConflictResolution(bool resolve) { + resolve_conflicts = resolve; + } + + void AddHelp() { + add_help = true; + } + + void AddConfigDefaults() { + AddOption("default-config-load", 0, "config", "Load options from file.", ARGACTION_CONFIG); + AddOption("default-config-print", 0, "print-config", "Print the configuration and exit.", + ARGACTION_PRINT_CONFIG); + } + + int CheckExisting(const Path &path, int &shortOpt, const std::string &longOpt) { + if (paths.find(PathString(path)) != paths.end()) { + std::ostringstream oss; + oss << "ArgParse option key \"" << PathString(path) << "\" already exists in options."; + throw std::runtime_error(oss.str()); + } + if (shortOpt > 0 && shortOpts.find(shortOpt) != shortOpts.end()) { + if (resolve_conflicts) { + shortOpt = 0; + } else { + std::ostringstream oss; + oss << "ArgParse duplicate short option \"" << std::string(1, (char)shortOpt) + << "\""; + throw std::runtime_error(oss.str()); + } + } + if (!longOpt.empty() && longOpts.find(longOpt) != longOpts.end()) { + std::ostringstream oss; + oss << "ArgParse duplicate long option \"" << longOpt << "\""; + throw std::runtime_error(oss.str()); + } + if (shortOpt > 0) { return shortOpt; } + else { return ++option_count; } + } + + void SetProgramName(const std::string &pname, bool do_basename=true); + + void Parse(int argc, char *const *argv); + Variant FormResult(); + + void PrintHelp(bool advanced) const; + void PrintConfig(); + + void MergeDescription(Variant desc); + void MergeOptions(Variant opts); + void MergeOptions(Variant opt, Path &path); + + void GenerateSchema(VariantRef schema) const; + Variant GetDescription() const; + + std::string title; + std::string description; + std::string epilog; + int option_count; + std::map option_map; + typedef std::map::iterator optmap_iter; + std::vector options; + typedef std::vector::iterator opt_iter; + typedef std::vector::const_iterator const_opt_iter; + std::map longOpts; + std::map shortOpts; + std::map paths; + std::vector arguments; + typedef std::vector::iterator arg_iter; + typedef std::vector::const_iterator const_arg_iter; + + std::map groups; + typedef std::map::iterator group_iter; + typedef std::map::const_iterator const_group_iter; + + bool resolve_conflicts; + bool have_advanced; + bool add_help; + bool print_help; + bool print_adv_help; + bool print_config; + }; + + + // ------------- + // ArgParseOption implemenatation + // ------------- + + ArgParseOption &ArgParseOption::Title(const std::string &title) { + impl->Set("title", title); + return *this; + } + + ArgParseOption &ArgParseOption::Action(const std::string &action) { + return Action(ArgParseActionFromStr(action)); + } + + ArgParseOption &ArgParseOption::Action(ArgParseAction action) { + if (action == ARGACTION_UNKNOWN) { + throw std::runtime_error("ArgParse: Unknown action"); + } + impl->action = action; + return *this; + } + + ArgParseOption &ArgParseOption::Type(ArgParseType type) { + switch (type) { + case ARGTYPE_GUESS: + case ARGTYPE_INT: + case ARGTYPE_UINT: + case ARGTYPE_STRING: + case ARGTYPE_BOOL: + case ARGTYPE_FLOAT: + impl->type = (Variant::Type_t)type; + return *this; + default: + throw std::runtime_error("ArgParse: Unknown argument type specified."); + } + } + + ArgParseOption &ArgParseOption::Type(const std::string &type) { + return Type(ParseType(type)); + } + + ArgParseOption &ArgParseOption::Type(Variant::Type_t type) { + if (type == Variant::MapType || type == Variant::ListType) { + std::ostringstream oss; + oss << "ArgParse: Type " << type << " cannot be specified as an option type."; + throw std::runtime_error(oss.str()); + } + impl->type = type; + return *this; + } + + ArgParseOption &ArgParseOption::Const(Variant val) { + impl->Set("const", val); + return *this; + } + + ArgParseOption &ArgParseOption::Default(Variant val) { + impl->Set("default", val); + return *this; + } + + ArgParseOption &ArgParseOption::Env(const char *env) { + impl->Set("env", env); + return *this; + } + + ArgParseOption &ArgParseOption::Minimum(Variant val) { + if (!val.IsNumber()) { + throw std::runtime_error("Minimum requires a number."); + } + if (impl->type == Variant::NullType) { impl->type = Variant::FloatType; } + impl->Set("minimum", val); + return *this; + } + + ArgParseOption &ArgParseOption::Maximum(Variant val) { + if (!val.IsNumber()) { + throw std::runtime_error("Maximum requires a number."); + } + if (impl->type == Variant::NullType) { impl->type = Variant::FloatType; } + impl->Set("maximum", val); + return *this; + } + + ArgParseOption &ArgParseOption::AddChoice(Variant val) { + if (!impl->opt.Contains("enum")) { impl->Set("enum", Variant::ListType); } + Variant e = impl->opt["enum"]; + if (std::find(e.ListBegin(), e.ListEnd(), val) == e.ListEnd()) { + e.Append(val); + } + return *this; + } + + ArgParseOption &ArgParseOption::SetChoices(const std::vector &val) { + impl->Set("enum", val); + return *this; + } + + const std::vector &ArgParseOption::GetChoices() { + return impl->opt["enum"].AsList(); + } + + ArgParseOption &ArgParseOption::Required(bool req) { + impl->required = true; + return *this; + } + + ArgParseOption &ArgParseOption::Help(const std::string &helptxt) { + impl->Set("description", helptxt); + return *this; + } + + ArgParseOption &ArgParseOption::Pattern(const std::string &pattern) { + if (impl->type == Variant::NullType) { impl->type = Variant::StringType; } + impl->Set("pattern", pattern); + return *this; + } + + ArgParseOption &ArgParseOption::MaxLength(unsigned l) { + if (impl->type == Variant::NullType) { impl->type = Variant::StringType; } + impl->Set("maxLength", l); + return *this; + } + + ArgParseOption &ArgParseOption::MinLength(unsigned l) { + if (impl->type == Variant::NullType) { impl->type = Variant::StringType; } + impl->Set("minLength", l); + return *this; + } + + ArgParseOption &ArgParseOption::MinArgs(unsigned l) { + impl->Set("minArgs", l); + if (l > 0 && !impl->required) { + impl->required = true; + } + return *this; + } + + ArgParseOption &ArgParseOption::MaxArgs(unsigned l) { + impl->Set("maxArgs", l); + return *this; + } + + ArgParseOption &ArgParseOption::NumArgs(unsigned l) { + MinArgs(l); + MaxArgs(l); + return *this; + } + + ArgParseOption &ArgParseOption::Group(const std::string &gname) { + impl->impl->GetGroup(gname)->Add(impl); + return *this; + } + + ArgParseOption &ArgParseOption::Advanced(bool adv) { + impl->advanced = adv; + impl->impl->have_advanced = true; + return *this; + } + + OptionGroup &OptionGroup::Title(const std::string &t) { + impl->title = t; + return *this; + } + + OptionGroup &OptionGroup::Description(const std::string &d) { + impl->description = d; + return *this; + } + + OptionGroup &OptionGroup::MutuallyExclusive(bool exclusive) { + impl->mutually_exclusive = exclusive; + return *this; + } + + OptionGroup &OptionGroup::Required(bool req) { + impl->required = req; + return *this; + } + + OptionGroup &OptionGroup::Add(const std::string &keypath) { + Path path; + ParsePath(path, keypath); + impl->Add(path); + return *this; + } + + OptionGroup &OptionGroup::Add(const Path &keypath) { + impl->Add(keypath); + return *this; + } + + OptionGroup &OptionGroup::Advanced(bool adv) { + impl->advanced = adv; + impl->impl->have_advanced = true; + return *this; + } + + // ----------------------- + // ArgParse implementation + // ----------------------- + + ArgParse::ArgParse(bool addhelp) + : impl(shared_ptr(new ArgParseImpl("", addhelp))) + {} + + ArgParse::ArgParse(const std::string &pname, bool addhelp) + : impl(shared_ptr(new ArgParseImpl(pname, addhelp))) + {} + + ArgParseOption ArgParse::AddOption(const std::string &keypath, int shortOpt, const std::string &longOpt, + const std::string &helptxt) + { + return ArgParseOption(impl->AddOption(keypath, shortOpt, longOpt, helptxt, ARGACTION_STORE)); + } + + ArgParseOption ArgParse::At(const std::string &keypath) { + return ArgParseOption(impl->At(keypath)); + } + + ArgParseOption ArgParse::AddFlag(const std::string &keypath, int shortOpt, const std::string &longOpt, + const std::string &helptxt) + { + return ArgParseOption(impl->AddOption(keypath, shortOpt, longOpt, helptxt, ARGACTION_STORE_TRUE)) + .Type(ARGTYPE_BOOL).Default(false); + } + + OptionGroup ArgParse::AddGroup(const std::string &name, const std::string &title, + const std::string &description) { + return OptionGroup(impl->GetGroup(name)).Title(title).Description(description); + } + + OptionGroup ArgParse::GetGroup(const std::string &name) { + return OptionGroup(impl->GetGroup(name)); + } + + ArgParseOption ArgParse::AddArgument(const std::string &keypath, const std::string &helptxt) + { + return ArgParseOption(impl->AddArgument(keypath, helptxt)); + } + + ArgParseOption ArgParse::At(size_t argumentIndex) { + return ArgParseOption(impl->At(argumentIndex)); + } + + void ArgParse::ConflictResolution(bool resolve) { + impl->ConflictResolution(resolve); + } + + void ArgParse::AddConfigDefaults() { + impl->AddConfigDefaults(); + } + + void ArgParse::AddHelp() { + impl->AddHelp(); + } + + void ArgParse::SetDescription(const std::string &txt) { + impl->description = txt; + } + + void ArgParse::SetEpilog(const std::string &txt) { + impl->epilog = txt; + } + + void ArgParse::SetProgramName(const std::string &pname, bool do_basename) { + impl->SetProgramName(pname, do_basename); + } + + std::string ArgParse::GetProgramName() const { + return impl->title; + } + + void ArgParse::Merge(Variant newopts) { + impl->MergeDescription(newopts); + } + + void ArgParse::Merge(const ArgParse &other) { + Merge(other.GetDescription()); + } + + void ArgParse::Validate() const { + SchemaResult result = SchemaValidate(arg_parse_static.schema, GetDescription()); + if (result.Error()) { + throw std::runtime_error(result.PrettyPrintMessage()); + } + } + + Variant ArgParse::Parse(int argc, char *const *argv) { + impl->Parse(argc, argv); + return impl->FormResult(); + } + + void ArgParse::PrintHelp(bool advanced) const { + impl->PrintHelp(advanced); + } + + Variant ArgParse::GetDescription() const { + return impl->GetDescription(); + } + + Variant ArgParse::GenerateSchema() const { + Variant schema = Variant::MapType; + impl->GenerateSchema(schema); + return schema; + } + + //------------------- + // ArgParseGroupImpl + //------------------- + + void ArgParseGroupImpl::Add(const Path &path) { + ArgParseOptImpl *o = impl->At(path); + Add(o); + } + + void ArgParseGroupImpl::Add(ArgParseOptImpl *o) { + members.insert(o); + o->groups.insert(name); + } + + void ArgParseGroupImpl::Init(Variant o) { + o.GetInto(title, "title", title); + o.GetInto(description, "description", description); + o.GetInto(required, "required", required); + o.GetInto(mutually_exclusive, "mutually exclusive", mutually_exclusive); + o.GetInto(advanced, "advanced", false); + if (advanced) { impl->have_advanced = true; } + if (o.Contains("members") && o["members"].IsList()) { + for (Variant::ListIterator i(o["members"].ListBegin()), e(o["members"].ListEnd()); + i != e; ++i) + { + Add(impl->At(i->AsString())); + } + } + } + + void ArgParseGroupImpl::FinalizeResult() { + if (mutually_exclusive) { + ArgParseOptImpl *last = 0; + for (std::set::iterator i(members.begin()), e(members.end()); + i != e; ++i) + { + ArgParseOptImpl *o = *i; + if (!o->result.IsNull()) { + if (!last) { + last = o; + } else { + std::ostringstream oss; + oss << "Error parsing arguments\n" + << OptName(last, false) << " and " << OptName(o, false) + << " are mutually exclusive."; + throw std::runtime_error(oss.str()); + } + } + } + if (required && !last) { + std::ostringstream oss; + oss << "Error parsing arguments\n" + << "One of the following options must be specified:\n"; + for (std::set::iterator i(members.begin()), e(members.end()); + i != e; ++i) + { + oss << "\t" << OptName(*i, false) << "\n"; + } + throw std::runtime_error(oss.str()); + } + } + } + + Variant ArgParseGroupImpl::GetDescription() const { + Variant desc = Variant::MapType; + if (!title.empty()) { desc.Set("title", title); } + if (!description.empty()) { desc.Set("description", description); } + desc.Set("required", required); + desc.Set("mutually exclusive", mutually_exclusive); + Variant mem = Variant::ListType; + for (std::set::iterator i(members.begin()), e(members.end()); + i != e; ++i) + { + mem.Append(PathString((*i)->path)); + } + desc.Set("advanced", advanced); + desc.Set("members", mem); + return desc; + } + + void ArgParseGroupImpl::GenerateSchema(VariantRef schema) const { + // The basic pattern for mutual exclusion with required is: + // "oneOf": [ + // { "required": [ "key" ] }, + // { "required": [ "key2" ] }, + // ] + // just mutual exclusion: + // "oneOf": [ + // { "required": [ "key" ] }, + // { "required": [ "key2" ] }, + // { "not": { "required": [ "key", "key2" ] } + // ] + // What makes things funny is paths. + if (mutually_exclusive) { + Variant oneof = Variant::ListType; + for (std::set::const_iterator i(members.begin()), e(members.end()); + i != e; ++i) + { + Variant instance; + GroupSchema(instance, *i, (*i)->path.begin(), (*i)->path.end()); + oneof.Append(instance); + } + if (!required) { + Variant anyof = Variant().Set("anyOf", oneof.Copy()); + oneof.Append(Variant().Set("not", anyof)); + } + if (!schema.Contains("allOf")) { schema["allOf"] = Variant::ListType; } + schema["allOf"].Append(Variant().Set("oneOf", oneof)); + } + } + + void ArgParseGroupImpl::GroupSchema(VariantRef schema, const ArgParseOptImpl *opt, + Path::const_iterator i, Path::const_iterator e) const + { + if (i != e) { + if (i->IsString()) { + schema["required"].Append(i->AsString()); + GroupSchema(schema["properties"][i->AsString()], opt, i+1, e); + } else if (i->IsNumber()) { + if (!schema.Contains("items")) { schema["items"] = Variant::ListType; } + if (schema["items"].Size() < i->AsUnsigned()) { + schema["items"].AsList().resize(i->AsUnsigned(), Variant::MapType); + } + GroupSchema(schema["items"][unsigned(i->AsUnsigned())], opt, i+1, e); + } + } else { + schema = Variant::MapType; + } + } + + //------------- + // ArgParseImpl + //------------- + +#if __APPLE__ +#include +#endif + void ArgParseImpl::SetProgramName(const std::string &pname, bool do_basename) { + if (pname.length() > 0) { + if (do_basename) { + char buf[pname.size()+1]; + strcpy(buf,pname.c_str()); + title = basename(buf); + } + else { + title = pname; + } + } + else { + // try to figure out the program name on our own + + char *progname = 0; + char buf[PATH_MAX*2]; + memset(buf, 0, PATH_MAX*2); + + #if __linux__ + if (!progname || !strlen(progname)) { + size_t bufsize = sizeof(buf); + if (0 == readlink("/proc/self/exe", buf, bufsize)) { + progname = buf; + } + } + #endif /* __linux__ */ + + #if __APPLE__ + if (!progname || !strlen(progname)) { + uint32_t bufsize = sizeof(buf); + if (0 == _NSGetExecutablePath(buf, &bufsize)) { + progname = buf; + } + } + #endif /* __APPLE__ */ + + if (!progname || !strlen(progname)) { + // Note: this is not accurate if the shell that set "_" + // called a program that called another program + progname = getenv("_"); + } + + if (!progname || !strlen(progname)) { + title = "ArgParse"; + } else { + title = std::string(basename(progname)); + } + } + } + + void ArgParseImpl::Parse(int argc, char *const *argv) { + + if (add_help) { + bool old_conflict = resolve_conflicts; + resolve_conflicts = true; + try { + AddOption("default-help-option", 'h', "help", "Print this message and exit.", ARGACTION_HELP); + if (have_advanced) { + AddOption("default-adv-help-option", 0, "adv-help", "Print help message" + " including options marked as advanced.", ARGACTION_ADVHELP); + } + } catch (const std::runtime_error &) {} + resolve_conflicts = old_conflict; + } + + try { + std::string shortOpts; + std::vector longOpts; + for (optmap_iter i(option_map.begin()), e(option_map.end()); i != e; ++i) { + ArgParseOptImpl &o = i->second; + int id = i->first; + if (o.shortOpt > 0) { + shortOpts.append(1, (char)o.shortOpt); + if (o.HasArg()) { shortOpts.append(1, ':'); } + } + if (!o.longOpt.empty()) { + struct option tmp_option = + { o.longOpt.c_str(), (o.HasArg() ? 1 : 0), 0, id }; + longOpts.push_back(tmp_option); + } + if (o.action == ARGACTION_COUNT) { o.result = 0u; } + // Handle environment variables + if (o.opt.Contains("env")) { + const char *env = getenv(o.opt["env"].AsString().c_str()); + if (env) { o.HandleOption(env); } + } + } + { + // End the option list + struct option tmp_option = {0, 0, 0, 0}; + longOpts.push_back(tmp_option); + } + + optind = 1; // Make sure getopt is in initial state + while (true) { + int c = getopt_long(argc, argv, shortOpts.c_str(), &longOpts[0], 0); + if (c == -1) { break; } + if (c == '?') { PrintHelp(false); } + optmap_iter o = option_map.find(c); + if (o == option_map.end()) { PrintHelp(false); } + ArgParseOptImpl &opt = o->second; + opt.HandleOption(optarg); + } + + // Handle arguments + unsigned minimum_arguments = 0; + for (arg_iter i(arguments.begin()), e(arguments.end()); i != e; ++i) { + ArgParseOptImpl *o = GetOpt(*i); + unsigned minarg; o->opt.GetInto(minarg, "minArgs", 0u); + if (minarg > 0) { minimum_arguments += minarg; } + else { break; } + } + unsigned numarg = argc - optind; + unsigned index = optind; + unsigned maximum_arguments = 0; + for (arg_iter i(arguments.begin()), e(arguments.end()); i != e; ++i) { + unsigned minarg, maxarg; + ArgParseOptImpl *o = GetOpt(*i); + o->opt.GetInto(minarg, "minArgs", 0u); + o->opt.GetInto(maxarg, "maxArgs", 0u); + if (maxarg != 0) { maximum_arguments += maxarg; } + else { maximum_arguments = 0; } + if (i + 1 == e && maxarg != 0 && argc - index > maxarg) { + std::ostringstream oss; + oss << "Error parsing arguments\nToo many arguments specified, " + << numarg << " given, maximum: " << maximum_arguments; + throw std::runtime_error(oss.str()); + } else { + unsigned num = 0; + while (index < (unsigned)argc && (maxarg == 0 || num < maxarg)) { + o->HandleOption(argv[index]); + ++index; + ++num; + } + } + } + if (index < (unsigned)argc) { + throw std::runtime_error("Error parsing arguments\nExtra arguments given."); + } + + for (optmap_iter i(option_map.begin()), e(option_map.end()); i != e; ++i) { + i->second.FinalizeResult(); + } + for (group_iter i(groups.begin()), e(groups.end()); i != e; ++i) { + i->second.FinalizeResult(); + } + if (print_adv_help) { PrintHelp(true); } + if (print_help) { PrintHelp(false); } + if (print_config) { PrintConfig(); } + } catch (const std::exception &e) { + if (print_adv_help) { PrintHelp(true); } + if (print_help) { PrintHelp(false); } + if (print_config) { PrintConfig(); } + std::cerr << e.what() << std::endl; + exit(1); + } + } + + Variant ArgParseImpl::FormResult() { + Variant ret = Variant::MapType; + for (optmap_iter i(option_map.begin()), e(option_map.end()); i != e; ++i) { + i->second.FormResult(ret); + } + return ret; + } + + + struct PrintHelpGroup { + std::string title; + std::string description; + bool advanced; + std::vector members; + }; + + void ArgParseImpl::PrintHelp(bool advanced) const { + std::cerr << title << ": [options]"; + for (const_arg_iter i(arguments.begin()), e(arguments.end()); i != e; ++i) { + const ArgParseOptImpl &arg = *GetOpt(*i); + unsigned minArgs, maxArgs; + arg.opt.GetInto(minArgs, "minArgs", 0u); + arg.opt.GetInto(maxArgs, "maxArgs", 0u); + if (minArgs == 0 && maxArgs == 0) { + std::cerr << " [" << ArgString(arg) << " [" << ArgString(arg) << " ...]]"; + } else { + for (unsigned i = 0; i < minArgs; ++i) { + std::cerr << " " << ArgString(arg); + } + if (maxArgs > minArgs) { + for (unsigned i = minArgs; i < maxArgs; ++i) { + std::cerr << " [" << ArgString(arg); + } + for (unsigned i = minArgs; i < maxArgs; ++i) { + std::cerr << "]"; + } + } else if (maxArgs < minArgs) { + std::cerr << " [" << ArgString(arg) << " ...]"; + } + } + } + std::cerr << "\n\n"; + if (!description.empty()) { + std::cerr << description << "\n\n"; + } + if (!arguments.empty()) { + std::cerr << "Arguments:\n"; + } + for (const_arg_iter i(arguments.begin()), e(arguments.end()); i != e; ++i) { + const ArgParseOptImpl &arg = *GetOpt(*i); + arg.HelpLine(std::cerr, false, true, 1); + } + if (!options.empty()) { + std::cerr << "Options:\n"; + } + std::vector ungrouped; + std::map groupings; + + for (const_opt_iter i(options.begin()), e(options.end()); i != e; ++i) { + bool in_group = false; + const ArgParseOptImpl &opt = *GetOpt(*i); + std::set::const_iterator g(opt.groups.begin()), gend(opt.groups.end()); + for (; g != gend; ++g) { + const_group_iter group_i = groups.find(*g); + if (group_i == groups.end()) { + std::cerr << "Group " << *g << " referenced but does not exist\n"; + continue; + } + const ArgParseGroupImpl *gimpl = &group_i->second; + if (!gimpl->title.empty() || !gimpl->description.empty()) { + in_group = true; + std::map::iterator giter; + giter = groupings.find(*g); + if (giter == groupings.end()) { + PrintHelpGroup group; + group.title = gimpl->title; + group.description = gimpl->description; + group.advanced = gimpl->advanced; + group.members.push_back(&opt); + groupings[*g] = group; + } else { + giter->second.members.push_back(&opt); + } + break; + } + } + if (!in_group) { + ungrouped.push_back(&opt); + } + } + for (std::vector::iterator i(ungrouped.begin()), e(ungrouped.end()); + i != e; ++i) + { + (*i)->HelpLine(std::cerr, true, advanced, 1); + } + for (std::map::iterator i(groupings.begin()), e(groupings.end()); + i != e; ++i) + { + if ( !(!i->second.advanced || advanced) ) { continue; } + std::cerr << "\n"; + if (! i->second.title.empty()) { + std::cerr << i->second.title << "\n"; + } + if (! i->second.description.empty()) { + std::cerr << i->second.description << "\n"; + } + for (std::vector::iterator j(i->second.members.begin()), + je(i->second.members.end()); + j != je; ++j) + { + (*j)->HelpLine(std::cerr, true, advanced, 1); + } + } + if (!epilog.empty()) { + std::cerr << "\n" << epilog << "\n" << std::endl; + } + exit(0); + } + + void ArgParseImpl::PrintConfig() { + Variant config = FormResult(); + Serialize(std::cout.rdbuf(), config, SERIALIZE_JSON, Variant().Set("pretty", true)); + std::cout << std::endl; + exit(0); + } + + void ArgParseImpl::MergeDescription(Variant desc) { + if (!desc.IsMap()) { return; } + if (desc.Contains("options") && desc["options"].IsMap()) { + Variant opts = desc["options"]; + for (Variant::MapIterator i(opts.MapBegin()), e(opts.MapEnd()); + i != e; ++i) + { + Variant o = i->second; + std::string keypath = i->first; + int shortOpt = 0; + if (o.Contains("shortOption")) { + shortOpt = o.Get("shortOption").AsString()[0]; + } + std::string longOpt = o.Get("longOption", "").AsString(); + std::string helptxt = o.Get("description", "").AsString(); + ArgParseAction action = ArgParseActionFromStr(o.Get("action", "store").AsString()); + AddOption(keypath, shortOpt, longOpt, helptxt, action)->Init(o); + } + } + if (desc.Contains("groups") && desc["groups"].IsMap()) { + Variant grps = desc["groups"]; + for (Variant::MapIterator i(grps.MapBegin()), e(grps.MapEnd()); + i != e; ++i) + { + Variant g = i->second; + std::string name = i->first; + GetGroup(name)->Init(g); + } + } + if (desc.Contains("arguments") && desc["arguments"].IsList()) { + Variant args = desc["arguments"]; + for (Variant::ListIterator i(args.ListBegin()), e(args.ListEnd()); + i != e; ++i) + { + Variant o = *i; + if (!o.Contains("keypath")) { continue; } + std::string keypath = o.Get("keypath").AsString(); + std::string helptxt = o.Get("description", "").AsString(); + ArgParseAction action = ArgParseActionFromStr(o.Get("action", "store").AsString()); + AddArgument(keypath, helptxt, action)->Init(o); + } + } + } + + void ArgParseImpl::MergeOptions(Variant opts) { + Path path; + MergeOptions(opts, path); + } + + void ArgParseImpl::MergeOptions(Variant opt, Path &path) { + switch (opt.GetType()) { + case Variant::NullType: + break; + case Variant::BoolType: + case Variant::IntegerType: + case Variant::UnsignedType: + case Variant::FloatType: + case Variant::StringType: + try { + At(path)->Handle(opt); + } catch (const std::runtime_error &) {} + break; + case Variant::ListType: + try { + At(path)->Handle(opt); + } catch (const std::runtime_error &) { + unsigned index = 0; + for (Variant::ListIterator i(opt.ListBegin()), e(opt.ListEnd()); + i != e; ++i, ++index) { + path.push_back(index); + MergeOptions(*i, path); + path.pop_back(); + } + } + break; + case Variant::MapType: + for (Variant::MapIterator i(opt.MapBegin()), e(opt.MapEnd()); i != e; ++i) { + path.push_back(i->first); + MergeOptions(i->second, path); + path.pop_back(); + } + break; + case Variant::BlobType: + break; + } + } + + void ArgParseImpl::GenerateSchema(VariantRef schema) const { + for (const_opt_iter i(options.begin()), e(options.end()); i != e; ++i) { + GetOpt(*i)->GenerateSchema(schema); + } + for (const_arg_iter i(arguments.begin()), e(arguments.end()); i != e; ++i) { + GetOpt(*i)->GenerateSchema(schema); + } + for (const_group_iter i(groups.begin()), e(groups.end()); i != e; ++i) { + i->second.GenerateSchema(schema); + } + } + + Variant ArgParseImpl::GetDescription() const { + Variant desc = Variant::MapType; + desc.Set("title", title); + desc.Set("description", description); + desc.Set("epilog", epilog); + for (const_opt_iter i(options.begin()), e(options.end()); i != e; ++i) { + const ArgParseOptImpl *opt = GetOpt(*i); + desc["options"].Set(PathString(opt->path), opt->GetDescription()); + } + for (const_arg_iter i(arguments.begin()), e(arguments.end()); i != e; ++i) { + const ArgParseOptImpl *opt = GetOpt(*i); + desc["arguments"].Append(opt->GetDescription()); + } + for (const_group_iter i(groups.begin()), e(groups.end()); i != e; ++i) { + desc["groups"].Set(i->first, i->second.GetDescription()); + } + return desc; + } + + // --------------- + // ArgParseOptImpl + // --------------- + + ArgParseOptImpl::ArgParseOptImpl(ArgParseImpl *i, int id_, const Path &p, + int sOpt, const std::string &lOpt, const std::string &htxt, ArgParseAction a) + : type(Variant::NullType), + path(p), + id(id_), + shortOpt(sOpt), + longOpt(lOpt), + action(a), + required(false), + advanced(false), + impl(i), + opt(Variant::MapType), + result(Variant::NullType) + { + if (path.back().IsString()) { + opt["title"] = path.back().AsString(); + } else { + opt["title"] = PathString(path); + } + opt["description"] = htxt; + } + + void ArgParseOptImpl::Handle(Variant arg) { + switch (action) { + case ARGACTION_STORE: + CheckRequirements(arg); + result = arg; + break; + case ARGACTION_STORE_CONST: + result = opt["const"]; + break; + case ARGACTION_STORE_TRUE: + if (arg.IsBool()) { + result = arg; + } else { + result = true; + } + break; + case ARGACTION_STORE_FALSE: + if (arg.IsBool()) { + result = arg; + } else { + result = false; + } + break; + case ARGACTION_APPEND: + if (arg.IsList()) { + for (Variant::ListIterator i(arg.ListBegin()), e(arg.ListEnd()); i != e; ++i) { + CheckRequirements(*i); + result.Append(*i); + } + } else { + CheckRequirements(arg); + result.Append(arg); + } + break; + case ARGACTION_COUNT: + if (arg.IsNumber()) { + result += arg.AsInt(); + } else { + result += 1; + } + break; + case ARGACTION_HELP: + impl->print_help = true; + break; + case ARGACTION_ADVHELP: + impl->print_adv_help = true; + break; + case ARGACTION_CONFIG: + impl->MergeOptions(DeserializeGuessFile(arg.AsString().c_str())); + break; + case ARGACTION_CONFIG_JSON: + impl->MergeOptions(DeserializeFile(arg.AsString().c_str(), SERIALIZE_JSON)); + break; + case ARGACTION_CONFIG_YAML: + impl->MergeOptions(DeserializeFile(arg.AsString().c_str(), SERIALIZE_YAML)); + break; + case ARGACTION_CONFIG_PLIST: + impl->MergeOptions(DeserializeFile(arg.AsString().c_str(), SERIALIZE_XMLPLIST)); + break; + case ARGACTION_PRINT_CONFIG: + impl->print_config = true; + break; + default: + break; + } + } + + void ArgParseOptImpl::CheckRequirements(Variant val) { + + switch (val.GetType()) { + case Variant::StringType: + if (opt.Contains("minLength") && val.Size() < opt["minLength"]) { + std::ostringstream oss; + oss << "Error parsing arguments\n" << OptName(this) << " is too short: " << val.Size() + << " chars, minimum " << opt["minLength"].AsUnsigned(); + throw std::runtime_error(oss.str()); + } + if (opt.Contains("maxLength") && val.Size() > opt["maxLength"]) { + std::ostringstream oss; + oss << "Error parsing arguments\n" << OptName(this) << " is too long: " << val.Size() + << " chars, maximum " << opt["maxLength"].AsUnsigned(); + throw std::runtime_error(oss.str()); + } + if (opt.Contains("pattern")) { + std::string pat = opt["pattern"].AsString(); + regex_t reg; + memset(®, 0, sizeof(regex_t)); + int err; + if ((err = regcomp(®, pat.c_str(), REG_EXTENDED | REG_NOSUB))) { + std::vector buffer(8192); + regerror(err, ®, &buffer[0], buffer.size()); + std::ostringstream oss; + oss << "Error parsing arguments\n"; + oss << "Failed to compile pattern regex \"" << pat << "\" with error: " + << &buffer[0]; + throw std::runtime_error(oss.str()); + } + if (regexec(®, val.AsString().c_str(), 0, 0, 0) != 0) { + regfree(®); + std::ostringstream oss; + oss << "Error parsing arguments\n"; + oss << OptName(this) << " failed to match pattern \"" + << pat << "\""; + throw std::runtime_error(oss.str()); + } + regfree(®); + } + break; + case Variant::IntegerType: case Variant::UnsignedType: case Variant::FloatType: + if (opt.Contains("minimum") && val < opt["minimum"]) { + std::ostringstream oss; + oss << "Error parsing arguments\n" << OptName(this) << " is too small: "; + SerializeJSON(oss.rdbuf(), val); + oss << ", minimum "; + SerializeJSON(oss.rdbuf(), opt["minimum"]); + throw std::runtime_error(oss.str()); + } + if (opt.Contains("maximum") && val > opt["maximum"]) { + std::ostringstream oss; + oss << "Error parsing arguments\n" << OptName(this) << " is too large: "; + SerializeJSON(oss.rdbuf(), val); + oss << ", maximum "; + SerializeJSON(oss.rdbuf(), opt["maximum"]); + throw std::runtime_error(oss.str()); + } + break; + default: + break; + } + + if (opt.Contains("enum")) { + Variant choices = opt["enum"]; + bool pass = false; + for (Variant::ListIterator i(choices.ListBegin()), e(choices.ListEnd()); i != e; ++i) + { + if (val == *i) { pass = true; break; } + } + if (!pass) { + std::ostringstream oss; + oss << "Error parsing arguments\n"; + SerializeJSON(oss.rdbuf(), val); + oss << "\nis not one of the allowed choices for " << OptName(this) << std::endl; + for (Variant::ListIterator i(choices.ListBegin()), e(choices.ListEnd()); i != e; ++i) + { + oss << " - "; + SerializeJSON(oss.rdbuf(), *i); + oss << std::endl; + } + throw std::runtime_error(oss.str()); + } + } + } + + + static void ParseArgIntError(const char *arg) { + std::ostringstream oss; + oss << "Error parsing arguments\nUnable to convert \"" << arg << "\" to an integer"; + throw std::runtime_error(oss.str()); + } + + Variant ArgParseOptImpl::ParseArg(const char *arg) { + + class PAction : public ParserActions { + public: + virtual void Scalar(ParserImpl *p, double v, const char *anchor, const char *tag) + { val = v; } + virtual void Scalar(ParserImpl *p, const char *str, unsigned length, const char *anchor, const char *tag) + { val = std::string(str, length); } + virtual void Scalar(ParserImpl *p, bool v, const char *anchor, const char *tag) + { val = v; } + virtual void Null(ParserImpl *p, const char *anchor, const char *tag) + { val = Variant::NullType; } + virtual void Scalar(ParserImpl *p, intmax_t v, const char *anchor, const char *tag) + { val = v; } + virtual void Scalar(ParserImpl *p, uintmax_t v, const char *anchor, const char *tag) + { val = v; } + Variant val; + }; + + if (!HasArg()) { + if (arg) { + std::ostringstream oss; + oss << "Error parsing arguments\n" + << OptName(this) << " does not take an argument, but argument \"" + << arg << "\" given."; + throw std::runtime_error(oss.str()); + } + return Variant::NullType; + } + + // Was type specified? + unsigned len = strlen(arg); + switch (type) { + case Variant::BoolType: + return Variant(ParseBool(arg)); + case Variant::IntegerType: + { + long long val; + char *end = 0; + val = strtoll(arg, &end, 10); + if (val == 0 && end == arg) { ParseArgIntError(arg); } + if (arg + len != end) { ParseArgIntError(arg); } + if (!(val == LLONG_MAX && errno == ERANGE)) { + return Variant(val); + } + } // Fall through + case Variant::UnsignedType: + { + char *end = 0; + unsigned long long val; + val = strtoull(arg, &end, 10); + if (val == 0 && end == arg) { ParseArgIntError(arg); } + if (arg + len != end) { ParseArgIntError(arg); } + return Variant(val); + } + case Variant::FloatType: + { + char *end = 0; + double val = strtod(arg, &end); + if ((val == 0 && end == arg) || (arg + len != end)) { + std::ostringstream oss; + oss << "Error parsing arguments\nUnable to convert \"" << arg << "\" to a number"; + throw std::runtime_error(oss.str()); + } + return Variant(val); + } + case Variant::StringType: + return Variant(arg); + + case Variant::NullType: case Variant::ListType: case Variant::MapType: case Variant::BlobType: default: + { + PAction a; + GuessScalar(arg, strlen(arg), 0, 0, 0, &a); + return a.val; + } + } + } + + std::ostream &ArgParseOptImpl::MakeArgString(std::ostream &os) const { + switch (action) { + case ARGACTION_STORE: + case ARGACTION_APPEND: + if (opt.Contains("enum") && opt["enum"].IsList()) { + for (Variant::ConstListIterator i(opt["enum"].ListBegin()), + e(opt["enum"].ListEnd()); i != e; ++i) + { + os << i->AsString(); + if (i + 1 != e) { + os << " | "; + } + } + } else { + switch (type) { + case Variant::BoolType: os << "yes|no"; break; + case Variant::IntegerType: case Variant::UnsignedType: + case Variant::NullType: case Variant::FloatType: default: + os << opt.Get("title", "XXX").AsString(); + } + } + break; + case ARGACTION_CONFIG: + case ARGACTION_CONFIG_JSON: + case ARGACTION_CONFIG_YAML: + case ARGACTION_CONFIG_PLIST: + os << "FILE"; + break; + case ARGACTION_PRINT_CONFIG: + default: + break; + } + return os; + } + + void ArgParseOptImpl::Init(Variant o) { + if (o.Contains("type")) { + type = (Variant::Type_t)ParseType(o["type"]); + } + o.GetInto(required, "required", required); + o.GetInto(advanced, "advanced", false); + if (advanced) { impl->have_advanced = true; } + opt.Merge(o); + } + + void ArgParseOptImpl::FinalizeResult() { + if (opt.Contains("default") && result.IsNull()) { + bool add_default = true; + for (std::set::iterator i(groups.begin()), e(groups.end()); + i != e; ++i) + { + ArgParseGroupImpl *g = impl->GetGroup(*i); + if (g->mutually_exclusive) { + for (std::set::iterator o(g->members.begin()), + oend(g->members.end()); o != oend; ++o) + { + ArgParseOptImpl *opt = *o; + if (!opt->result.IsNull()) { + add_default = false; + } + } + } + } + if (add_default) { + switch (action) { + case ARGACTION_STORE: + case ARGACTION_STORE_CONST: + case ARGACTION_STORE_TRUE: + case ARGACTION_STORE_FALSE: + result = opt["default"]; + break; + case ARGACTION_APPEND: + result.Append(opt["default"]); + case ARGACTION_COUNT: + case ARGACTION_HELP: + case ARGACTION_ADVHELP: + case ARGACTION_CONFIG: + case ARGACTION_CONFIG_JSON: + case ARGACTION_CONFIG_YAML: + case ARGACTION_CONFIG_PLIST: + case ARGACTION_PRINT_CONFIG: + default: + break; + } + } + } + if (!result.IsNull()) { + if (action == ARGACTION_APPEND) { + if (opt.Contains("maxArgs") && opt["maxArgs"] != 0) { + if (opt["maxArgs"] < result.Size()) { + std::ostringstream oss; + oss << "Error parsing arguments\n"; + oss << "More than maximum arguments specified for " << OptName(this) << ", "; + oss << result.Size() << " options, maximum: " << opt["maxArgs"].AsUnsigned(); + throw std::runtime_error(oss.str()); + } + } + if (opt.Contains("minArgs")) { + if (opt["minArgs"] > result.Size()) { + std::ostringstream oss; + oss << "Error parsing arguments\n"; + oss << "Less than minimum arguments specified for " << OptName(this) << ", "; + oss << result.Size() << " options, minimum: " << opt["minArgs"].AsUnsigned(); + throw std::runtime_error(oss.str()); + } + } + } + } else if (required) { + std::ostringstream oss; + oss << "Error parsing arguments\n"; + oss << "Required " << OptName(this) << " missing."; + throw std::runtime_error(oss.str()); + } + } + + void ArgParseOptImpl::FormResult(VariantRef res) { + if (!HasResult()) { return; } + if (result.IsNull()) { return; } + res.SetPath(path, result); + } + + void ArgParseOptImpl::HelpLine(std::ostream &os, bool is_arg, bool adv, unsigned indent) const { + if ( !(!advanced || adv) ) { return; } + os << "\t"; + if (shortOpt > 0) { + os << "-" << (char)shortOpt; + } + if (shortOpt > 0 && !longOpt.empty()) { + os << ", "; + } + if (!longOpt.empty()) { + os << "--" << longOpt; + } + if (HasArg()) { + os << " " << ArgString(*this); + } + if (opt.Contains("env")) { + if (shortOpt > 0 || !longOpt.empty()) { + os << "\n\t"; + } + os << "env: $" << opt["env"].AsString(); + if (HasArg()) { + os << "=" << ArgString(*this); + } + } + os << "\n\t\t" << opt["description"].AsString(); + + if (opt.Contains("default")) { + Variant def = opt["default"]; + if (!def.IsMap() && !def.IsList()) { + os << " (default: "; + SerializeJSON(os.rdbuf(), def); + os << ")"; + } + } + os << "\n"; + } + + Variant ArgParseOptImpl::GetDescription() const { + Variant desc; + desc.Merge(opt); + if (type == Variant::NullType) { + desc.Set("type", type); + } else { + desc.Set("type", TypeString(type)); + } + if (shortOpt > 0) { + desc.Set("shortOption", std::string(1, (char)shortOpt)); + } else { + desc.Erase("shortOption"); + } + if (!longOpt.empty()) { + desc.Set("longOption", longOpt); + } else { + desc.Erase("longOption"); + } + desc.Set("action", ArgParseActionToStr(action)); + desc.Set("required", required); + desc.Set("keypath", PathString(path)); + desc.Set("advanced", advanced); + return desc; + } + + void ArgParseOptImpl::GenerateSchema(VariantRef schema) const { + GenerateSchema(schema, path.begin(), path.end()); + } + + void ArgParseOptImpl::GenerateSchema(VariantRef schema, Path::const_iterator i, + Path::const_iterator e) const { + if (i == e) { + schema = GenerateSchema(); + } else { + if (schema.Get("type", "") == "object") { + GenerateObjectSchema(schema, i, e); + } else if (schema.Get("type", "") == "array") { + GenerateArraySchema(schema, i, e); + } else if (i->IsString()) { + GenerateObjectSchema(schema, i, e); + } else if (i->IsNumber()) { + GenerateArraySchema(schema, i, e); + } + } + } + + void ArgParseOptImpl::GenerateObjectSchema(VariantRef schema, Path::const_iterator i, + Path::const_iterator e) const + { + if (schema.IsNull()) { schema = Variant::MapType; } + std::string key = i->AsString(); + if (!schema.Contains("type")) { schema["type"] = "object"; } + if (!schema.Contains("properties")) { schema["properties"] = Variant::MapType; } + if (required) { + if (!schema.Contains("required")) { schema["required"] = Variant::ListType; } + if (std::find(schema["required"].ListBegin(), schema["required"].ListEnd(), Variant(key)) + == schema["required"].ListEnd()) + { + schema["required"].Append(key); + } + } + GenerateSchema(schema["properties"].At(key, Variant::MapType), i+1, e); + } + + void ArgParseOptImpl::GenerateArraySchema(VariantRef schema, Path::const_iterator i, + Path::const_iterator e) const + { + unsigned index = i->AsUnsigned(); + if (!schema.Contains("type")) { schema["type"] = "array"; } + if (!schema.Contains("items")) { schema["items"] = Variant::ListType; } + GenerateSchema(schema["items"].At(index, Variant::MapType), i+1, e); + } + + Variant ArgParseOptImpl::GenerateSchema() const { + Variant s = Variant::MapType; + if (opt.Contains("title")) { s["title"] = opt["title"]; } + if (opt.Contains("description")) { s["description"] = opt["description"]; } + switch (action) { + case ARGACTION_STORE: + if (type != Variant::NullType) { s["type"] = TypeString(type); } + if (opt.Contains("minimum")) { s["minimum"] = opt["minimum"]; } + if (opt.Contains("maximum")) { s["maximum"] = opt["maximum"]; } + if (opt.Contains("minLength")) { s["minLength"] = opt["minLength"]; } + if (opt.Contains("maxLength")) { s["maxLength"] = opt["maxLength"]; } + if (opt.Contains("pattern")) { s["pattern"] = opt["pattern"]; } + if (opt.Contains("enum")) { s["enum"] = opt["enum"].Copy(); } + if (opt.Contains("default")) { s["default"] = opt["default"]; } + break; + case ARGACTION_STORE_CONST: + s["enum"].Append(opt.Get("const")); + break; + case ARGACTION_STORE_TRUE: + case ARGACTION_STORE_FALSE: + s["type"] = "boolean"; + if (opt.Contains("default")) { s["default"] = opt["default"]; } + break; + case ARGACTION_APPEND: + { + Variant itemschema = Variant::MapType; + if (type != Variant::NullType) { itemschema["type"] = TypeString(type); } + if (opt.Contains("minimum")) { itemschema["minimum"] = opt["minimum"]; } + if (opt.Contains("maximum")) { itemschema["maximum"] = opt["maximum"]; } + if (opt.Contains("minLength")) { itemschema["minLength"] = opt["minLength"]; } + if (opt.Contains("maxLength")) { itemschema["maxLength"] = opt["maxLength"]; } + if (opt.Contains("pattern")) { itemschema["pattern"] = opt["pattern"]; } + if (opt.Contains("enum")) { itemschema["enum"] = opt["enum"].Copy(); } + if (opt.Contains("default")) { + s["default"] = Variant::ListType; + s["default"].Append(opt["default"]); + } + s["items"] = itemschema; + } + if (opt.Contains("minArgs") && opt["minArgs"] > 0) { s["minItems"] = opt["minArgs"]; } + if (opt.Contains("maxArgs") && opt["maxArgs"] > 0) { s["maxItems"] = opt["maxArgs"]; } + break; + case ARGACTION_COUNT: + s["type"] = "integer"; + s["minimum"] = 0; + break; + case ARGACTION_HELP: + case ARGACTION_ADVHELP: + case ARGACTION_CONFIG: + case ARGACTION_CONFIG_JSON: + case ARGACTION_CONFIG_YAML: + case ARGACTION_CONFIG_PLIST: + case ARGACTION_UNKNOWN: + default: + break; + } + return s; + } + +} diff --git a/src/hos_libvariant/src/src/Base64.cc b/src/hos_libvariant/src/src/Base64.cc new file mode 100644 index 00000000..99ccc50a --- /dev/null +++ b/src/hos_libvariant/src/src/Base64.cc @@ -0,0 +1,160 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "Base64.h" + +namespace libvariant { + + unsigned Base64Encode(char *outptr, const void *inptr, unsigned len, unsigned cpl) { + struct iovec iov = { (void*)inptr, len }; + return Base64Encode(outptr, &iov, 1, cpl); + } + + class iov_iterator { + public: + iov_iterator() : iov(0), len(0), slab(0), offset(0) {} + iov_iterator(const iov_iterator &o) : iov(o.iov), len(o.len), slab(o.slab), offset(o.offset) {} + iov_iterator(const struct iovec *v, unsigned l) : iov(v), len(l), slab(0), offset(0) {} + iov_iterator &operator++() { + ++offset; + if (offset >= iov[slab].iov_len) { + ++slab; + offset = 0; + } + return *this; + } + iov_iterator operator++(int) { + iov_iterator o = *this; + ++(*this); + return o; + } + + char operator *() { + return *((char*)(iov[slab].iov_base) + offset); + } + + bool operator==(const iov_iterator &o) { + return (slab == o.slab && offset == o.offset); + } + + bool is_end() { return slab >= len; } + iov_iterator end() { + iov_iterator o = *this; + while (!o.is_end()) { ++o; } + return o; + } + + private: + const struct iovec *iov; + unsigned len; + unsigned slab; + unsigned offset; + }; + + unsigned Base64Encode(char *outptr, const struct iovec *iov, unsigned iov_len, unsigned cpl) { + static const char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + iov_iterator i = iov_iterator(iov, iov_len); + iov_iterator e = i.end(); + unsigned step_count = 0; + char *o = outptr; +#define PUSH_VALUE()\ + do {\ + if (result > 63) { *o++ = '='; }\ + else { *o++ = encoding[(int)result]; }\ + } while (0) + + char result; + char fragment; + while (true) { + // Step A + if (i == e) { break; } + fragment = *i++; + result = (fragment & 0x0FC) >> 2; + PUSH_VALUE(); + result = (fragment & 0x003) << 4; + // Step B + if (i == e) { + PUSH_VALUE(); + *o++ = '='; + *o++ = '='; + break; + } + fragment = *i++; + result |= (fragment & 0x0f0) >> 4; + PUSH_VALUE(); + result = (fragment & 0x00f) << 2; + // Step C + if (i == e) { + PUSH_VALUE(); + *o++ = '='; + break; + } + fragment = *i++; + result |= (fragment & 0x0c0) >> 6; + PUSH_VALUE(); + result = (fragment & 0x03f) >> 0; + PUSH_VALUE(); + ++step_count; + if (cpl > 0 && step_count == cpl/4) { + *o++ = '\n'; + step_count = 0; + } + } +#undef PUSH_VALUE + if (cpl > 0) { *o++ = '\n'; } + *o = '\0'; + return o - outptr; + } + + unsigned Base64EncodeSize(unsigned len, unsigned cpl) { + // Every 3 bytes turns into 4 bytes + unsigned res = (len*4)/3+4; + // There are 2 extra bytes every CPL output bytes plus 2 extras at the end + if (cpl > 0) { res += 2*(res/cpl + 1); } + else { res+= 1; } + return res; + } + + unsigned Base64Decode(void *outptr, const char *inptr, unsigned len) { + static const signed char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; + static const signed char decoding_size = sizeof(decoding); + const signed char *i = (const signed char*)inptr; + const signed char *e = i + len; + signed char *o = (signed char*)outptr; + signed char fragment; + signed char result; +#define DECODE_VALUE()\ + do {\ + if (i == e) { return o - (signed char*)outptr; }\ + signed char val = *i++ - 43;\ + if (val < 0 || val > decoding_size) { fragment = -1; }\ + else { fragment = decoding[(int)val]; }\ + } while (fragment < 0) + + while (true) { + // Step A + DECODE_VALUE(); + result = (fragment & 0x03f) << 2; + // Step B + DECODE_VALUE(); + result |= (fragment & 0x030) >> 4; + *o++ = result; + result = (fragment & 0x00f) << 4; + // Step C + DECODE_VALUE(); + result |= (fragment & 0x03c) >> 2; + *o++ = result; + result = (fragment & 0x003) << 6; + // Step D + DECODE_VALUE(); + result |= (fragment & 0x03f); + *o++ = result; + } +#undef DECODE_VALUE + } + + unsigned Base64DecodeSize(unsigned len) { + return (len*3)/4 + 1; + } +} diff --git a/src/hos_libvariant/src/src/Base64.h b/src/hos_libvariant/src/src/Base64.h new file mode 100644 index 00000000..b340483a --- /dev/null +++ b/src/hos_libvariant/src/src/Base64.h @@ -0,0 +1,24 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_BASE64_H +#define VARIANT_BASE64_H +#pragma once +#include +namespace libvariant { + /// Encode the binary blob of len pointed to by inptr + //into a base64 string encoding in the buffer pointed to by + //outptr. The buffer for outptr should be at least Base64EncodeSize(len) + //in length, returns the actual length of the output + unsigned Base64Encode(char *outptr, const void *inptr, unsigned len, unsigned cpl = 72); + unsigned Base64Encode(char *outptr, const struct iovec *iov, unsigned iov_len, unsigned cpl = 72); + unsigned Base64EncodeSize(unsigned len, unsigned cpl=72); + /// Decode a base64 encoded string of length len to a binary blob + //The blob will be no larger than Base64DecodeSize(len) + //returns the actual size of the blob + unsigned Base64Decode(void *outptr, const char *inptr, unsigned len); + unsigned Base64DecodeSize(unsigned len); +} +#endif + diff --git a/src/hos_libvariant/src/src/Blob.cc b/src/hos_libvariant/src/src/Blob.cc new file mode 100644 index 00000000..59b9917a --- /dev/null +++ b/src/hos_libvariant/src/src/Blob.cc @@ -0,0 +1,123 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "../../src/include/Variant/Blob.h" + +#include +#include +#include +#include + +namespace libvariant { + + static void MallocFree(void *ptr, void *) { + free(ptr); + } + + shared_ptr Blob::Create(void *ptr, unsigned len, BlobFreeFunc ffunc, void *context) + { + struct iovec iov = { ptr, len }; + return shared_ptr(new Blob(&iov, 1, ffunc, context)); + } + + BlobPtr Blob::Create(struct iovec *iov, unsigned iov_len, BlobFreeFunc ffunc, void *context) { + return BlobPtr(new Blob(iov, iov_len, ffunc, context)); + } + + shared_ptr Blob::CreateCopy(const void *ptr, unsigned len) { + struct iovec iov = { (void*)ptr, len }; + return CreateCopy(&iov, 1); + } + + BlobPtr Blob::CreateCopy(const struct iovec *iov, unsigned iov_len) { + unsigned len = 0; + for (unsigned i = 0; i < iov_len; ++i) { len += iov[i].iov_len; } + void *data = 0; +#ifdef __APPLE__ + // TODO: Remove when apple fixes this error. + if (posix_memalign(&data, 64, std::max(len, 1u)) != 0) { + throw std::bad_alloc(); + } +#else + if (posix_memalign(&data, 64, len) != 0) { + throw std::bad_alloc(); + } +#endif + for (unsigned i = 0, copied = 0; i < iov_len; ++i) { + memcpy((char*)data + copied, iov[i].iov_base, iov[i].iov_len); + copied += iov[i].iov_len; + } + struct iovec v = { data, len }; + return shared_ptr(new Blob(&v, 1, MallocFree, 0)); + } + + shared_ptr Blob::CreateFree(void *ptr, unsigned len) { + struct iovec iov = { ptr, len }; + return CreateFree(&iov, 1); + } + + BlobPtr Blob::CreateFree(struct iovec *iov, unsigned iov_len) { + return shared_ptr(new Blob(iov, iov_len, MallocFree, 0)); + } + + shared_ptr Blob::CreateReferenced(void *ptr, unsigned len) { + struct iovec iov = { ptr, len }; + return CreateReferenced(&iov, 1); + } + + BlobPtr Blob::CreateReferenced(struct iovec *iov, unsigned iov_len) { + return shared_ptr(new Blob(iov, iov_len, 0, 0)); + } + + Blob::Blob(struct iovec *v, unsigned l, BlobFreeFunc f, void *c) + : iov(v, v+l), free_func(f), ctx(c) + { + } + + Blob::~Blob() { + if (free_func) { + for (unsigned i = 0; i < iov.size(); ++i) { + free_func(iov[i].iov_base, ctx); + } + } + iov.clear(); + free_func = 0; + ctx = 0; + } + + shared_ptr Blob::Copy() const { + return CreateCopy(&iov[0], iov.size()); + } + + unsigned Blob::GetTotalLength() const { + unsigned size = 0; + for (unsigned i = 0; i < iov.size(); ++i) { + size += iov[i].iov_len; + } + return size; + } + + int Blob::Compare(ConstBlobPtr other) const { + unsigned our_offset = 0; + unsigned oth_offset = 0; + unsigned i = 0, j = 0; + while (i < GetNumBuffers() && j < other->GetNumBuffers()) { + unsigned len = std::min(GetLength(i) - our_offset, other->GetLength(j) - oth_offset); + int res = memcmp((char*)(GetPtr(i)) + our_offset, (char*)(other->GetPtr(j)) + oth_offset, len); + if (res != 0) { return res; } + our_offset += len; + if (our_offset >= GetLength(i)) { + our_offset = 0; + ++i; + } + oth_offset += len; + if (oth_offset >= other->GetLength(j)) { + oth_offset = 0; + ++j; + } + } + return 0; + } +} + diff --git a/src/hos_libvariant/src/src/BlobMagic.h b/src/hos_libvariant/src/src/BlobMagic.h new file mode 100644 index 00000000..31ff9935 --- /dev/null +++ b/src/hos_libvariant/src/src/BlobMagic.h @@ -0,0 +1,20 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_BLOBMAGIC_H +#define VARIANT_BLOBMAGIC_H +#pragma once + +// We implement blobs by prepending the encoding with a special value +// of \0BLOB to identify it for those serialization formats that do not +// provide a method to distinguish strings and binary data. + +// Raw encoding +#define MAGIC_BLOB_TAG "\0BLOB" +// Length of raw encoding +#define MAGIC_BLOB_LENGTH 5 +// The string encoding for json +#define MAGIC_BLOB_JSONSTR "\\u0000BLOB" + +#endif diff --git a/src/hos_libvariant/src/src/BundleHdrEmitter.cc b/src/hos_libvariant/src/src/BundleHdrEmitter.cc new file mode 100644 index 00000000..ec791f81 --- /dev/null +++ b/src/hos_libvariant/src/src/BundleHdrEmitter.cc @@ -0,0 +1,126 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "../../src/src/BundleHdrEmitter.h" + +#include +#include +#include +#include + +#define BUNDLE_VERSION_KEY "bundle.version" +#define BUNDLE_VERSION "0.0" + +namespace libvariant { + + BundleHdrEmitterImpl::BundleHdrEmitterImpl(shared_ptr o, Variant params) + : output(o), + state(BHE_START), + numeric_precision(std::numeric_limits::digits10+2) + { + } + + + BundleHdrEmitterImpl::~BundleHdrEmitterImpl() { + Close(); + } + + + void BundleHdrEmitterImpl::BeginDocument() { + if (state != BHE_START) { + throw std::runtime_error("BundleHdrEmitter in invalid state for BeginDocument"); + } + Write(BUNDLE_VERSION_KEY ": " BUNDLE_VERSION "\n"); + state = BHE_BEGIN; + } + + void BundleHdrEmitterImpl::EndDocument() { + if (state == BHE_STOP) { + throw std::runtime_error("BundleHdrEmitter in invalid state for EndDocument"); + } + state = BHE_STOP; + Flush(); + } + + void BundleHdrEmitterImpl::BeginMap(int) { + if (state == BHE_START) { + BeginDocument(); + } + if (state != BHE_BEGIN) { + throw std::runtime_error("BundleHdrEmitter in invalid state for BeginDocument"); + } + state = BHE_KEY; + } + + void BundleHdrEmitterImpl::EndMap() { + if (state != BHE_KEY) { + throw std::runtime_error("BundleHdrEmitter in invalid state for EndMap"); + } + state = BHE_END; + } + + void BundleHdrEmitterImpl::BeginList(int) { + if (state != BHE_VALUE) { + throw std::runtime_error("BundleHdrEmitter in invalid state for BeginList"); + } + state = BHE_LIST_START; + } + + void BundleHdrEmitterImpl::EndList() { + if (state != BHE_LIST && state != BHE_LIST_START) { + throw std::runtime_error("BundleHdrEmitter in invalid state for EndList"); + } + Write("|\n"); + state = BHE_KEY; + } + + + void BundleHdrEmitterImpl::EmitNull() { + Value("", 0); + } + + void BundleHdrEmitterImpl::EmitTrue() { + Value("1", 1); + } + + void BundleHdrEmitterImpl::EmitFalse() { + Value("0", 1); + } + + void BundleHdrEmitterImpl::Emit(const char *v) { + Value(v, strlen(v)); + } + + void BundleHdrEmitterImpl::Emit(intmax_t v) { + std::ostringstream oss; + oss << v; + Value(oss.str().c_str(), oss.str().length()); + } + + void BundleHdrEmitterImpl::Emit(uintmax_t v) { + std::ostringstream oss; + oss << v; + Value(oss.str().c_str(), oss.str().length()); + } + + void BundleHdrEmitterImpl::Emit(double v) { + std::ostringstream oss; + oss << std::setprecision(numeric_precision) << std::showpoint << v; + Value(oss.str().c_str(), oss.str().length()); + } + + void BundleHdrEmitterImpl::Emit(ConstBlobPtr b) { + throw std::runtime_error("BundleHdr is not able to serialize the blob type"); + } + + void BundleHdrEmitterImpl::Flush() { output->Flush(); } + + void BundleHdrEmitterImpl::Close() { + if (state != BHE_STOP) { + EndDocument(); + } + Flush(); + } + +} diff --git a/src/hos_libvariant/src/src/BundleHdrEmitter.h b/src/hos_libvariant/src/src/BundleHdrEmitter.h new file mode 100644 index 00000000..277d17e1 --- /dev/null +++ b/src/hos_libvariant/src/src/BundleHdrEmitter.h @@ -0,0 +1,110 @@ +/** \file + * \author John Bridgman + * \brief A simple emitter that will emit a Bundle header + */ +#ifndef VARIANT_BUNDLEHDREMITTER_H +#define VARIANT_BUNDLEHDREMITTER_H + +#pragma once +#include "../../src/include/Variant/Emitter.h" +#include "../../src/include/Variant/EmitterOutput.h" +#include + +namespace libvariant { + + /** + * This emitter is designed so that its output gives predictable + * results for the original bundle parser. This means that the parser + * in this library will not produce identical results. I.e., + * boolian values will be converted to 0, 1. + * + * Parameters: + * "precision": number of digits for a float + */ + class BundleHdrEmitterImpl : public EmitterImpl { + enum BHEState_t { + BHE_START, + BHE_BEGIN, + BHE_KEY, + BHE_VALUE, + BHE_LIST_START, + BHE_LIST, + BHE_END, + BHE_STOP + }; + public: + BundleHdrEmitterImpl(shared_ptr o, Variant params); + + virtual ~BundleHdrEmitterImpl(); + + virtual void BeginDocument(); + virtual void EndDocument(); + virtual void BeginMap(int length); + virtual void EndMap(); + virtual void BeginList(int length); + virtual void EndList(); + + virtual void EmitNull(); + virtual void EmitTrue(); + virtual void EmitFalse(); + virtual void Emit(const char *v); + virtual void Emit(intmax_t v); + virtual void Emit(uintmax_t v); + virtual void Emit(double v); + virtual void Emit(ConstBlobPtr b); + + virtual void Flush(); + virtual void Close(); + + virtual Variant GetParam(const std::string &key) { + if (key == "precision") { return numeric_precision; } + return Variant::NullType; + } + virtual Variant GetParams() { return Variant().Set("precision", numeric_precision); } + virtual void SetParam(const std::string &key, Variant value) { + if (key == "precision") { numeric_precision = value.AsUnsigned(); } + } + private: + + void Value(const char *v, unsigned len) { + switch (state) { + case BHE_KEY: + Write(v, len); + Write(": "); + state = BHE_VALUE; + break; + case BHE_VALUE: + Write(v, len); + Write("\n"); + state = BHE_KEY; + break; + case BHE_LIST_START: + Write(v, len); + state = BHE_LIST; + break; + case BHE_LIST: + Write("|"); + Write(v, len); + break; + default: + throw std::runtime_error("BundleHdrEmitter in invalid state to emit a scalar value."); + } + } + + void Write(const char *str) { + Write(str, strlen(str)); + } + + void Write(const char *str, unsigned len) { + unsigned num_written = 0; + while (num_written < len) { + num_written += output->Write(str + num_written, len - num_written); + } + } + + shared_ptr output; + BHEState_t state; + unsigned numeric_precision; + }; +} +#endif diff --git a/src/hos_libvariant/src/src/BundleHdrParser.cc b/src/hos_libvariant/src/src/BundleHdrParser.cc new file mode 100644 index 00000000..60304495 --- /dev/null +++ b/src/hos_libvariant/src/src/BundleHdrParser.cc @@ -0,0 +1,217 @@ +/** \file + * \author John Bridgman + * \brief A parser for the Bundle header. + */ +#include "BundleHdrParser.h" +#include +#include +#include +#include +#include +#include "GuessScalar.h" + +#define BUNDLE_VERSION_KEY "bundle.version" + +namespace libvariant { + + void BundleHdrParserImpl::ReadLine() { + line_len = 0; + unsigned len = 0; + while (true) { + line = (const char *)input->GetPtr(len); + if (!line || line_len == len) { + line = 0; + return; + } + for (;line_len < len; ++line_len) { + if (line[line_len] == '\n') { + return; + } + } + len += 4096; + } + } + + void BundleHdrParserImpl::RetireLine() { + input->Release(line_len + 1); + line = 0; + line_len = 0; + } + + bool BundleHdrParserImpl::ScanLine() { + // Fill key and value + //if (sscanf(line, " %[^: \t#] : %[^#]", &key[0], &value[0]) >= 1) { + if (line_len == 0) { return false; } + bool loop = true; + const char *c = line; + const char *e = line + line_len; + key.clear(); + value.clear(); + while (isspace(*c) && c != e) { ++c; } + loop = true; + while (loop && c != e) { + switch (*c) { + case ':': + case ' ': + case '\t': + loop = false; + break; + case '#': + return false; + default: + key.push_back(*c); + ++c; + break; + } + } + key.push_back('\0'); + while (isspace(*c) && c != e) { ++c; } + if (*c != ':') { + return false; + } + ++c; + while (isspace(*c) && c != e) { ++c; } + while (c != e && *c != '#') { + value.push_back(*c); + ++c; + } + value.push_back('\0'); + return true; + } + + int BundleHdrParserImpl::Run() { + while (!action_stack.empty()) { + switch (state) { + case START: + { + unsigned len = 0; + const char *ptr = (const char*)input->GetPtr(len); + if (len == 0 || !ptr) { + state = STOP; + return 1; + } + state = BEGIN_MAP; + TopAction()->BeginDocument(this); + } + break; + case BEGIN_MAP: + state = KEY; + TopAction()->BeginMap(this, -1, 0, 0); + break; + case KEY: + while (true) { + ReadLine(); + if (!line) { + state = END_MAP; + break; + } + ++line_num; + bool success = ScanLine(); + RetireLine(); + if (success) { + // If it is the version key, ignore this line + if (strcmp(&key[0], BUNDLE_VERSION_KEY) == 0) { + continue; + } + // Remove whitespace from end of value + char *e = strchr(&value[0], '\0'); + while (--e >= &value[0] && isspace(*e)) { *e = '\0'; } + state = VALUE; + TopAction()->Scalar(this, &key[0], strlen(&key[0]), 0, 0); + key.clear(); + break; + } + } + break; + case VALUE: + { + char *list_context = 0; + int i = 0; + bool bar_at_end = (value.size() > 1 && value[value.size()-2] == '|'); + while (true) { + char *v = strtok_r((i == 0 ? &value[0] : 0), "|", &list_context); + if (!v) { + if (i <= 1 && !bar_at_end) { + state = KEY; + list.clear(); + GuessScalar(&value[0], strlen(&value[0]), 0, 0, this, TopAction()); + break; + } else { + state = LIST; + value.clear(); + TopAction()->BeginList(this, -1, 0, 0); + break; + } + } + list.push_back(v); + ++i; + } + } + break; + case LIST: + if (!list.empty()) { + char *v = list.front(); + list.pop_front(); + GuessScalar(v, strlen(v), 0, 0, this, TopAction()); + } else { + state = KEY; + TopAction()->EndList(this); + } + break; + case END_MAP: + state = END; + TopAction()->EndMap(this); + break; + case END: + state = STOP; + TopAction()->EndDocument(this); + break; + case STOP: + return 1; + default: + errorstr = "BundleHdrParser: Inconsistent state"; + throw std::runtime_error(errorstr); + } + } + return 0; + } + + void BundleHdrParserImpl::Reset() { + state = START; + line = 0; + line_len = 0; + key.clear(); + value.clear(); + list.clear(); + line_num = 0; + } + + BundleHdrParserImpl::BundleHdrParserImpl(shared_ptr i) + : input(i), + state(START), + line(0), + line_len(0), + line_num(0) + {} + + BundleHdrParserImpl::~BundleHdrParserImpl() {} + + unsigned BundleHdrParserImpl::GetLine() const { return line_num; } + + bool BundleHdrParserImpl::Done() const { + return state == STOP; + } + + bool BundleHdrParserImpl::Error() const { + return state > STOP; + } + + bool BundleHdrParserImpl::Ok() const { + return state != STOP; + } + + std::string BundleHdrParserImpl::ErrorStr() const { + return errorstr; + } + +} diff --git a/src/hos_libvariant/src/src/BundleHdrParser.h b/src/hos_libvariant/src/src/BundleHdrParser.h new file mode 100644 index 00000000..bebc57cd --- /dev/null +++ b/src/hos_libvariant/src/src/BundleHdrParser.h @@ -0,0 +1,66 @@ +/** \file + * \author John Bridgman + * \brief A parser for the Bundle header. + */ +#ifndef VARIANT_BUNDLEHDRPARSER_H +#define VARIANT_BUNDLEHDRPARSER_H + +#pragma once +#include "../../src/include/Variant/Parser.h" +#include "../../src/include/Variant/SharedPtr.h" +#include +namespace libvariant { + + /** + * A simple parser for the Bundle header. + * + * Maintanance programmer note: BundleParserImpl + * relies on a lot of the implementation details of this class. + */ + class BundleHdrParserImpl : public ParserImpl { + protected: + enum State_t { + START, + BEGIN_MAP, + KEY, + VALUE, + LIST, + END_MAP, + END, + STOP + }; + + public: + BundleHdrParserImpl(shared_ptr i); + virtual ~BundleHdrParserImpl(); + + virtual int Run(); + + unsigned GetLine() const; + /** + * Resets the parser to the state it was in when just constructed. + */ + virtual void Reset(); + + virtual bool Done() const; + virtual bool Error() const; + virtual bool Ok() const; + virtual std::string ErrorStr() const; + protected: + void ReadLine(); + void RetireLine(); + bool ScanLine(); + + shared_ptr input; + State_t state; + const char *line; + unsigned line_len; + std::vector key; + std::vector value; + std::deque list; + unsigned line_num; + std::string errorstr; + }; + +} +#endif diff --git a/src/hos_libvariant/src/src/CMakeLists.txt b/src/hos_libvariant/src/src/CMakeLists.txt new file mode 100644 index 00000000..f1ffaff9 --- /dev/null +++ b/src/hos_libvariant/src/src/CMakeLists.txt @@ -0,0 +1,60 @@ + +set(sources + Variant.cc + VariantEmitting.cc + VariantParsing.cc + Exceptions.cc + Extensions.cc + Blob.cc + Base64.cc + ParseBool.cc + Path.cc + Emitter.cc + EmitterOutput.cc + JSONEmitter.cc + Parser.cc + ParserInput.cc + JSONParser.cc + ../lib/json/JSON_parser.c + GuessScalar.cc + BundleHdrParser.cc + BundleHdrEmitter.cc + GuessFormat.cc + Payload.cc + ArgParse.cc + argparse-schema.cc + Schema.cc + SchemaLoader.cc + json-schema-v4.cc + StackTrace.cc + EventBuffer.cc + ) + +if(LIBVARIANT_ENABLE_XML) + list(APPEND sources XMLPLISTEmitter.cc XMLPLISTParser.cc) +endif() + +if(LIBVARIANT_ENABLE_YAML) + list(APPEND sources YAMLEmitter.cc YAMLParser.cc) +endif() + +if(LIBVARIANT_ENABLE_MSGPACK) + list(APPEND sources MsgPackEmitter.cc MsgPackParser.cc) +endif() + +include_directories("../lib/json/") + +add_library(Variant ${sources}) +set_target_properties(Variant PROPERTIES VERSION ${LIBVARIANT_VERSION}) +target_link_libraries(Variant ${EXTRA_LIBS}) + +add_executable(varsh varsh.cc) +target_link_libraries(varsh Variant) + +install(TARGETS Variant varsh + EXPORT LibVariantLibraryDepends + RUNTIME DESTINATION ${INSTALL_BIN_DIR} + LIBRARY DESTINATION ${INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${INSTALL_LIB_DIR}) + + diff --git a/src/hos_libvariant/src/src/Emitter.cc b/src/hos_libvariant/src/src/Emitter.cc new file mode 100644 index 00000000..e3f12963 --- /dev/null +++ b/src/hos_libvariant/src/src/Emitter.cc @@ -0,0 +1,219 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#include "../../src/include/Variant/Emitter.h" + +#include "../../src/src/JSONEmitter.h" +#ifdef ENABLE_YAML +#include "../../src/src/YAMLEmitter.h" +#endif +#ifdef ENABLE_XML +#include "../../src/src/XMLPLISTEmitter.h" +#endif +#ifdef ENABLE_MSGPACK +#include "../../src/src/MsgPackEmitter.h" +#endif +#include "../../src/src/BundleHdrEmitter.h" +#include "../../src/include/Variant/EmitterOutput.h" + +namespace libvariant { + EmitterImpl::~EmitterImpl() {} + + void EmitterImpl::SetParams(Variant params) { + if (params.IsMap()) { + for (Variant::MapIterator i(params.MapBegin()), e(params.MapEnd()); i != e; ++i) { + SetParam(i->first, i->second); + } + } + } + + Emitter::Emitter() {} + + Emitter::Emitter(shared_ptr i) + : impl(i) + {} + + Emitter::~Emitter() {} + + Emitter &Emitter::BeginDocument() { + impl->BeginDocument(); + return *this; + } + + Emitter &Emitter::EndDocument() { + impl->EndDocument(); + return *this; + } + + Emitter &Emitter::BeginMap(int length) { + impl->BeginMap(length); + return *this; + } + + Emitter &Emitter::EndMap() { + impl->EndMap(); + return *this; + } + + Emitter &Emitter::BeginList(int length) { + impl->BeginList(length); + return *this; + } + + Emitter &Emitter::EndList() { + impl->EndList(); + return *this; + } + + Emitter &Emitter::EmitNull() { + impl->EmitNull(); + return *this; + } + + Emitter &Emitter::EmitTrue() { + impl->EmitTrue(); + return *this; + } + + Emitter &Emitter::EmitFalse() { + impl->EmitFalse(); + return *this; + } + + Emitter &Emitter::Emit(const std::string &v) { + impl->Emit(v.c_str()); + return *this; + } + + Emitter &Emitter::Emit(const char *v) { + impl->Emit(v); + return *this; + } + + Emitter &Emitter::Emit(intmax_t v) { + impl->Emit(v); + return *this; + } + + Emitter &Emitter::Emit(uintmax_t v) { + impl->Emit(v); + return *this; + } + + Emitter &Emitter::Emit(double v) { + impl->Emit(v); + return *this; + } + + Emitter &Emitter::Emit(ConstBlobPtr b) { + impl->Emit(b); + return *this; + } + + void Emitter::Flush() { + impl->Flush(); + } + + void Emitter::Close() { + impl->Close(); + } + + Variant Emitter::GetParam(const std::string &key) { + return impl->GetParam(key); + } + + Variant Emitter::GetParams() { + return impl->GetParams(); + } + + void Emitter::SetParam(const std::string &key, Variant value) { + impl->SetParam(key, value); + } + + void Emitter::SetParams(Variant params) { + impl->SetParams(params); + } + + shared_ptr CreateEmitterOutput(void *ptr, unsigned len, unsigned *out_len) { + return shared_ptr(new EmitterMemoryOutput(ptr, len, out_len)); + } + + shared_ptr CreateEmitterOutput(const char *filename) { + return shared_ptr(new EmitterFilenameOutput(filename)); + } + + shared_ptr CreateEmitterOutput(FILE *f) { + return shared_ptr(new EmitterFileOutput(f, false)); + } + + shared_ptr CreateEmitterOutput(std::streambuf *sb) { + return shared_ptr(new EmitterStreambufOutput(sb, false)); + } + + + Emitter CreateEmitter(shared_ptr o, SerializeType type, Variant params) { + switch (type) { + case SERIALIZE_JSON: + return JSONEmitter(o, params); + case SERIALIZE_XMLPLIST: + return XMLPLISTEmitter(o, params); + case SERIALIZE_BUNDLEHDR: + return BundleHdrEmitter(o, params); + case SERIALIZE_YAML: + return YAMLEmitter(o, params); + case SERIALIZE_MSGPACK: + return MsgPackEmitter(o, params); + default: + throw std::runtime_error("libvariant: Unsupported emitter serialization type."); + } + } + + Emitter JSONEmitter(shared_ptr o, Variant params) { + return Emitter(shared_ptr(new JSONEmitterImpl(o, params))); + } + + Emitter YAMLEmitter(shared_ptr o, Variant params) { +#ifdef ENABLE_YAML + return Emitter(shared_ptr(new YAMLEmitterImpl(o, params))); +#else + throw std::runtime_error("libvariant not compiled with YAML support."); +#endif + } + + Emitter XMLPLISTEmitter(shared_ptr o, Variant params) { +#ifdef ENABLE_XML + return Emitter(shared_ptr(new XMLPLISTEmitterImpl(o, params))); +#else + throw std::runtime_error("libvariant not compiled with plist xml support."); +#endif + } + + Emitter BundleHdrEmitter(shared_ptr o, Variant params) { + return Emitter(shared_ptr(new BundleHdrEmitterImpl(o, params))); + } + + Emitter MsgPackEmitter(shared_ptr o, Variant params) { +#ifdef ENABLE_MSGPACK + return Emitter(shared_ptr(new MsgPackEmitterImpl(o, params))); +#else + throw std::runtime_error("libvariant not compiled with msgpack support."); +#endif + } +} diff --git a/src/hos_libvariant/src/src/EmitterOutput.cc b/src/hos_libvariant/src/src/EmitterOutput.cc new file mode 100644 index 00000000..609406c2 --- /dev/null +++ b/src/hos_libvariant/src/src/EmitterOutput.cc @@ -0,0 +1,100 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ + +#include "../../src/include/Variant/EmitterOutput.h" + +#include +#include +#include +#include + +namespace libvariant { + + EmitterOutput::~EmitterOutput() {} + + EmitterFileOutput::EmitterFileOutput(FILE *f, bool c) : file(f), num_bytes(0), cls(c) {} + + EmitterFileOutput::~EmitterFileOutput() { + if (cls && file) { + fclose(file); + } + file = 0; + } + + unsigned EmitterFileOutput::Write(const void *ptr, unsigned len) { + unsigned num = fwrite(ptr, 1, len, file); + num_bytes += num; + return num; + } + + void EmitterFileOutput::Flush() { + fflush(file); + } + + EmitterFilenameOutput::EmitterFilenameOutput(const char *filename, const char *mode) + : EmitterFileOutput(fopen(filename, mode), true) + { + if (!file) { + std::ostringstream oss; + oss << "Unable to open \"" << filename << "\" with mode \"" + << mode << "\""; + throw std::runtime_error(oss.str()); + } + } + + EmitterStreambufOutput::EmitterStreambufOutput(std::streambuf *sb, bool d) + : streambuf(sb), num_bytes(0), del(d) {} + + EmitterStreambufOutput::~EmitterStreambufOutput() { + if (del && streambuf) { + delete streambuf; + } + streambuf = 0; + } + + unsigned EmitterStreambufOutput::Write(const void *ptr, unsigned len) { + unsigned num = streambuf->sputn((const char*)ptr, len); + num_bytes += num; + return num; + } + + void EmitterStreambufOutput::Flush() { + streambuf->pubsync(); + } + + EmitterMemoryOutput::EmitterMemoryOutput(void *ptr, unsigned len, unsigned *out_len) + : data_ptr(ptr), length(len), out_length(out_len) + { + if (0 == out_length) { + out_length = &out_length_dummy; + } + } + + unsigned EmitterMemoryOutput::Write(const void *ptr, unsigned len) { + if (*out_length + len > length) { + throw std::length_error("Emitter memory output buffer to small."); + } + memcpy(((char*)data_ptr + *out_length), ptr, len); + *out_length += len; + return len; + } + +} diff --git a/src/hos_libvariant/src/src/EventBuffer.cc b/src/hos_libvariant/src/src/EventBuffer.cc new file mode 100644 index 00000000..43eb533c --- /dev/null +++ b/src/hos_libvariant/src/src/EventBuffer.cc @@ -0,0 +1,283 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include "../../src/src/EventBuffer.h" + +#include +#include +#include +#include + +namespace libvariant { + + EmitterParserActions::~EmitterParserActions() {} + + void EventBuffer::Event::Fire(ParserImpl *that, ParserActions *a) const { + switch (type) { + case BEGIN_DOCUMENT: + a->BeginDocument(that); + break; + case END_DOCUMENT: + a->EndDocument(that); + break; + case BEGIN_MAP: + a->BeginMap(that, val.len, 0, 0); + break; + case END_MAP: + a->EndMap(that); + break; + case BEGIN_LIST: + a->BeginList(that, val.len, 0, 0); + break; + case END_LIST: + a->EndList(that); + break; + case SCALAR_NULL: + a->Null(that, 0, 0); + break; + case SCALAR_BOOL: + a->Scalar(that, val.b, 0, 0); + break; + case SCALAR_STRING: + a->Scalar(that, s.c_str(), s.length(), 0, 0); + break; + case SCALAR_INT: + a->Scalar(that, val.i, 0, 0); + break; + case SCALAR_UINT: + a->Scalar(that, val.u, 0, 0); + break; + case SCALAR_FLOAT: + a->Scalar(that, val.d, 0, 0); + break; + case SCALAR_BLOB: + a->Scalar(that, blob->Copy(), 0, 0); + break; + default: + throw std::runtime_error("EventBuffer::Event::Fire Encountered an incorrect event."); + } + } + + bool EventBuffer::Event::operator==(const Event &o) const { + switch (type) { + case SCALAR_BOOL: + return val.b == o.val.b; + case SCALAR_FLOAT: + return val.d == o.val.d || (val.d != val.d && o.val.d != o.val.d); + case SCALAR_STRING: + return s == o.s; + case SCALAR_INT: + return val.i == o.val.i; + case SCALAR_UINT: + return val.u == o.val.u; + default: + if (type != o.type) { return false; } + break; + } + return true; + } + + void EventBuffer::Event::Print(std::ostream &os) const { + switch (type) { + case BEGIN_DOCUMENT: + os << "Event(BEGIN_DOCUMENT)"; + break; + case END_DOCUMENT: + os << "Event(END_DOCUMENT)"; + break; + case BEGIN_MAP: + os << "Event(BEGIN_MAP, " << val.len << ")"; + break; + case END_MAP: + os << "Event(END_MAP)"; + break; + case BEGIN_LIST: + os << "Event(BEGIN_LIST, " << val.len << ")"; + break; + case END_LIST: + os << "Event(END_LIST)"; + break; + case SCALAR_BOOL: + os << "Event(SCALAR_BOOL, " << std::boolalpha << val.b << ")"; + break; + case SCALAR_FLOAT: + os << "Event(SCALAR_FLOAT, " << val.d << ")"; + break; + case SCALAR_STRING: + os << "Event(SCALAR_STRING, " << s << ")"; + break; + case SCALAR_NULL: + os << "Event(SCALAR_NULL)"; + break; + case SCALAR_INT: + os << "Event(SCALAR_INT, " << val.i << ")"; + break; + case SCALAR_UINT: + os << "Event(SCALAR_UINT, " << val.u << ")"; + break; + case SCALAR_BLOB: + os << "Event(SCALAR_BLOB)"; + break; + default: + os << "Unknown event (" << (int)type << ")"; + break; + } + } + + EventBuffer::EventBuffer(const EventBuffer &eb) + : level(eb.level), events(eb.events) + { + + } + + EventBuffer::~EventBuffer() {} + + + void EventBuffer::FillRandom(EventType_t disallowed_events, int max_level, bool allow_nan) { + bool begin_document = false; + if (!(BEGIN_DOCUMENT & disallowed_events)) { + BeginDocument(); + begin_document = true; + } + disallowed_events = disallowed_events | BEGIN_DOCUMENT; + EventType_t next_event = RandomEventType(disallowed_events | SCALAR_EVENTS | END_EVENTS, max_level); + switch (next_event) { + case BEGIN_MAP: + MapRandomEvent(disallowed_events, max_level, allow_nan); + break; + case BEGIN_LIST: + ListRandomEvent(disallowed_events, max_level, allow_nan); + break; + default: + // should not be reachable + throw std::runtime_error("EventBuffer::FillRandom reached code that should be not reachable"); + } + + if (begin_document) { + EndDocument(); + } + } + + EventBuffer::EventType_t EventBuffer::RandomEventType(EventBuffer::EventType_t disallowed, int max_level) + { + if (level >= max_level) { + disallowed = disallowed | BEGIN_EVENTS; + } + while (true) { + int bit = rand() % 32; + int val = 1<::infinity(); + if ((type&0x4) == 0) { + val = -val; + } + } else if ((type&0x4) == 0) { + val = std::numeric_limits::quiet_NaN(); + } else { + val = std::numeric_limits::signaling_NaN(); + } + Emit(val); + } + break; + case SCALAR_BLOB: + Emit((ConstBlobPtr)GenerateRandomBlob()); + break; + default: + // should not be reachable + throw std::runtime_error("EventBuffer::BasicRandomEvent reached code that should be not reachable"); + } + } + + void EventBuffer::MapRandomEvent(EventType_t disallowed, int max_level, bool allow_nan) { + int map_len = rand()%10; + BeginMap(map_len); + for (int i = 0; i < map_len; ++i) { + std::string key = GenerateRandomString(); + Emit(key.c_str()); + BasicRandomEvent(disallowed, max_level, allow_nan); + } + EndMap(); + } + + void EventBuffer::ListRandomEvent(EventType_t disallowed, int max_level, bool allow_nan) { + int list_len = rand()%10; + BeginList(list_len); + for (int i = 0; i < list_len; ++i) { + BasicRandomEvent(disallowed, max_level, allow_nan); + } + EndList(); + } +} diff --git a/src/hos_libvariant/src/src/EventBuffer.h b/src/hos_libvariant/src/src/EventBuffer.h new file mode 100644 index 00000000..1ef34bfb --- /dev/null +++ b/src/hos_libvariant/src/src/EventBuffer.h @@ -0,0 +1,269 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_EVENTBUFFER_H +#define VARIANT_EVENTBUFFER_H + +#pragma once +#include "../../src/include/Variant/Emitter.h" +#include "../../src/include/Variant/Parser.h" +#include +#include +namespace libvariant { + + class EmitterParserActions : public ParserActions { + public: + EmitterParserActions(EmitterImpl *i) : impl(i) {} + EmitterParserActions(Emitter i) : impl_ptr(i.GetImpl()) { impl = impl_ptr.get(); } + virtual ~EmitterParserActions(); + + virtual void BeginDocument(ParserImpl *p) + { impl->BeginDocument(); } + virtual void EndDocument(ParserImpl *p) + { impl->EndDocument(); } + virtual void BeginMap(ParserImpl *p, int length, const char *anchor, const char *tag) + { impl->BeginMap(length); } + virtual void EndMap(ParserImpl *p) + { impl->EndMap(); } + virtual void BeginList(ParserImpl *p, int length, const char *anchor, const char *tag) + { impl->BeginList(length); } + virtual void EndList(ParserImpl *p) + { impl->EndList(); } + //virtual void Alias(ParserImpl *p, const char *anchor) + virtual void Scalar(ParserImpl *p, double v, const char *anchor, const char *tag) + { impl->Emit(v); } + virtual void Scalar(ParserImpl *p, const char *str, unsigned length, const char *anchor, const char *tag) + { + std::string v(str, length); + impl->Emit(v.c_str()); + } + virtual void Scalar(ParserImpl *p, bool v, const char *anchor, const char *tag) { + if (v) { impl->EmitTrue(); } + else { impl->EmitFalse(); } + } + virtual void Null(ParserImpl *p, const char *anchor, const char *tag) + { impl->EmitNull(); } + virtual void Scalar(ParserImpl *p, intmax_t v, const char *anchor, const char *tag) + { impl->Emit(v); } + virtual void Scalar(ParserImpl *p, uintmax_t v, const char *anchor, const char *tag) + { impl->Emit(v); } + virtual void Scalar(ParserImpl *p, BlobPtr b, const char *anchor, const char *tag) + { impl->Emit((ConstBlobPtr)b); } + private: + EmitterImpl *impl; + shared_ptr impl_ptr; + }; + + class EventBuffer : public EmitterImpl, public ParserImpl { + public: + enum EventType_t { + NO_EVENT = 0, + BEGIN_DOCUMENT = 1, + END_DOCUMENT = 1<<1, + BEGIN_MAP = 1<<2, + END_MAP = 1<<3, + BEGIN_LIST = 1<<4, + END_LIST = 1<<5, + SCALAR_NULL = 1<<6, + SCALAR_BOOL = 1<<7, + SCALAR_STRING = 1<<8, + SCALAR_INT = 1<<9, + SCALAR_UINT = 1<<10, + SCALAR_FLOAT = 1<<11, + SCALAR_BLOB = 1<<12, + NON_SCALARS = BEGIN_DOCUMENT | END_DOCUMENT | BEGIN_MAP | END_MAP | BEGIN_LIST | END_LIST, + BEGIN_EVENTS = BEGIN_DOCUMENT | BEGIN_MAP | BEGIN_LIST, + END_EVENTS = END_DOCUMENT | END_MAP | END_LIST, + SCALAR_EVENTS = SCALAR_NULL | SCALAR_BOOL | SCALAR_STRING | SCALAR_INT | SCALAR_UINT | + SCALAR_FLOAT | SCALAR_BLOB, + ALL_EVENTS = 0x0FFF + }; + + struct Event { + Event(EventType_t t, Event *p) : type(t), parent(p), key(true) { val.len = 0; } + + Event(Event *p, const char *str) : type(SCALAR_STRING), parent(p), s(str) {} + Event(Event *p, intmax_t v) : type(SCALAR_INT), parent(p) { val.i = v; } + Event(Event *p, uintmax_t v) : type(SCALAR_UINT), parent(p) { val.u = v; } + Event(Event *p, double v) : type(SCALAR_FLOAT), parent(p) { val.d = v; } + Event(Event *p, bool v) : type(SCALAR_BOOL), parent(p) { val.b = v; } + Event(Event *p, ConstBlobPtr b) : type(SCALAR_BLOB), parent(p), blob(b) {} + + private: + void Update() { + if (type == BEGIN_MAP) { + if (key) { + key = false; + } else { + key = true; + val.len++; + } + } else if (type == BEGIN_LIST) { + val.len++; + } + } + + Event *Parent() { + if (type == BEGIN_MAP) { return this; } + if (type == BEGIN_LIST) { return this; } + return parent; + } + public: + void Fire(ParserImpl *that, ParserActions *a) const; + bool operator==(const Event &o) const; + void Print(std::ostream &os) const; + private: + friend class EventBuffer; + EventType_t type; + Event *parent; + union { + bool b; + double d; + intmax_t i; + uintmax_t u; + uintmax_t len; + } val; + bool key; + std::string s; + libvariant::ConstBlobPtr blob; + }; + + private: + Event *Parent() { + if (events.empty()) { return 0; } + else { return events.back().Parent(); } + } + + Event *ParentUpdate() { + Event *p = Parent(); + if (p) { p->Update(); } + return p; + } + + Event *GrandParent() { + Event *p = Parent(); + if (p) { return p->parent; } + else { return 0; } + } + public: + + EventBuffer() : level(0) {} + EventBuffer(const EventBuffer &eb); + virtual ~EventBuffer(); + + virtual void BeginDocument() { + events.push_back(Event(BEGIN_DOCUMENT, Parent())); + level++; + } + + virtual void EndDocument() { + events.push_back(Event(END_DOCUMENT, GrandParent())); + level--; + } + + virtual void BeginMap(int) { + events.push_back(Event(BEGIN_MAP, ParentUpdate())); + level++; + } + + virtual void EndMap() { + events.push_back(Event(END_MAP, GrandParent())); + level--; + } + + virtual void BeginList(int) { + events.push_back(Event(BEGIN_LIST, ParentUpdate())); + level++; + } + + virtual void EndList() { + events.push_back(Event(END_LIST, GrandParent())); + level--; + } + + virtual void EmitNull() { events.push_back(Event(SCALAR_NULL, ParentUpdate())); } + virtual void EmitTrue() { events.push_back(Event(ParentUpdate(), true)); } + virtual void EmitFalse() { events.push_back(Event(ParentUpdate(), false)); } + virtual void Emit(const char *v) { events.push_back(Event(ParentUpdate(), v)); } + virtual void Emit(intmax_t v) { events.push_back(Event(ParentUpdate(), v)); } + virtual void Emit(uintmax_t v) { events.push_back(Event(ParentUpdate(), v)); } + virtual void Emit(double v) { events.push_back(Event(ParentUpdate(), v)); } + virtual void Emit(ConstBlobPtr b) { events.push_back(Event(ParentUpdate(), b)); } + + virtual void Flush() {} + virtual void Close() {} + + virtual Variant GetParam(const std::string &key) { return Variant::NullType; } + virtual Variant GetParams() { return Variant::NullType; } + virtual void SetParam(const std::string &key, Variant value) {} + + void Playback(Emitter e) { + Playback(e.GetImpl().get()); + } + + void Playback(EmitterImpl *e) { + shared_ptr action(new EmitterParserActions(e)); + PushAction(action); + while (!Done()) { Run(); } + PopAction(); + } + + void Fill(Parser p) { + shared_ptr action(new EmitterParserActions(this)); + p.PushAction(action); + unsigned start_events = events.size(); + while (!p.Done() && (level > 0 || start_events == events.size()) && p.Run() == 0); + p.PopAction(); + } + + void FillRandom(EventType_t disallowed_events, int max_level, bool allow_nan); + + virtual int Run() { + while (!events.empty() && !action_stack.empty()) { + ParserActions *a = TopAction(); + events.front().Fire(this, a); + events.pop_front(); + } + return 0; + } + + virtual bool Done() const { return events.empty(); } + virtual bool Error() const { return false; } + virtual bool Ok() const { return !events.empty(); } + virtual std::string ErrorStr() const { return ""; } + virtual void Reset() { events.clear(); } + + bool Equal(const EventBuffer &o) const { + return events == o.events; + } + + unsigned NumEvents() const { return events.size(); } + const Event &GetEvent(int i) const { return events[i]; } + int GetLevel() const { return level; } + + private: + EventType_t RandomEventType(EventType_t disallowed, int max_level); + void BasicRandomEvent(EventType_t disallowed, int max_level, bool allow_nan); + void MapRandomEvent(EventType_t disallowed, int max_level, bool allow_nan); + void ListRandomEvent(EventType_t disallowed, int max_level, bool allow_nan); + + int level; + std::deque events; + }; + + inline EventBuffer::EventType_t operator|(EventBuffer::EventType_t lhs, EventBuffer::EventType_t rhs) { + return (EventBuffer::EventType_t)((int)lhs | (int)rhs); + } + + inline EventBuffer::EventType_t operator&(EventBuffer::EventType_t lhs, EventBuffer::EventType_t rhs) { + return (EventBuffer::EventType_t)((int)lhs & (int)rhs); + } + + inline std::ostream &operator<<(std::ostream &os, const EventBuffer::Event &e) { + e.Print(os); + return os; + } + +} +#endif diff --git a/src/hos_libvariant/src/src/Exceptions.cc b/src/hos_libvariant/src/src/Exceptions.cc new file mode 100644 index 00000000..1669eb75 --- /dev/null +++ b/src/hos_libvariant/src/src/Exceptions.cc @@ -0,0 +1,201 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#include "../../src/include/Variant/Exceptions.h" + +#include + +#include "../../src/src/StackTrace.h" + +namespace libvariant { + + std::ostream &operator <<(std::ostream &os, VariantDefines::Type_t type) { + switch (type) { + case VariantDefines::NullType: + os << "NullType"; + break; + case VariantDefines::BoolType: + os << "BoolType"; + break; + case VariantDefines::IntegerType: + os << "IntegerType"; + break; + case VariantDefines::UnsignedType: + os << "UnsignedType"; + break; + case VariantDefines::FloatType: + os << "FloatType"; + break; + case VariantDefines::StringType: + os << "StringType"; + break; + case VariantDefines::ListType: + os << "ListType"; + break; + case VariantDefines::MapType: + os << "MapType"; + break; + case VariantDefines::BlobType: + os << "BlobType"; + break; + default: + os << "Unknown(" << (int)type << ")"; + break; + } + return os; + } + + void AddStackTrace(std::ostream &os, int level) { +#ifdef ENABLE_STACKTRACE + os << "\nBacktrace:\n" << GetStack(level + 2) << "\n"; +#endif + } + + static inline std::string UnknownTypeErrorMessage(VariantDefines::Type_t type) { + std::ostringstream oss; + oss << "Unknown variant type \"" << type << "\""; + AddStackTrace(oss, 2); + return oss.str(); + } + + UnknownTypeError::UnknownTypeError(VariantDefines::Type_t type) throw() + : std::runtime_error(UnknownTypeErrorMessage(type)) + {} + + static inline std::string UnexpectedTypeErrorMessage(VariantDefines::Type_t expected, VariantDefines::Type_t value) { + std::ostringstream oss; + oss << "Unexpected variant type " << value << " expected " << expected; + AddStackTrace(oss, 2); + return oss.str(); + } + + static inline std::string UnexpectedTypeErrorMessage(const std::vector &expected, + VariantDefines::Type_t value) { + std::ostringstream oss; + oss << "Unexpected variant type " << value << " expected one of "; + for (unsigned i = 0; i < expected.size(); ++i) { + if (i != 0) { oss << ", "; } + oss << expected[i]; + } + AddStackTrace(oss, 2); + return oss.str(); + } + + UnexpectedTypeError::UnexpectedTypeError(VariantDefines::Type_t expected, VariantDefines::Type_t value) throw() + : std::runtime_error(UnexpectedTypeErrorMessage(expected, value)) + {} + + UnexpectedTypeError::UnexpectedTypeError(const std::vector &expected, + VariantDefines::Type_t value) throw() + : std::runtime_error(UnexpectedTypeErrorMessage(expected, value)) + {} + + static inline std::string UnableToConvertErrorMessage(VariantDefines::Type_t sourcetype, + const std::string &targettype) { + std::ostringstream oss; + oss << "Unable to convert variant " << sourcetype << " to " << targettype; + AddStackTrace(oss, 2); + return oss.str(); + } + + UnableToConvertError::UnableToConvertError(VariantDefines::Type_t sourcetype, + const std::string &targettype) throw() + : std::runtime_error(UnableToConvertErrorMessage(sourcetype, targettype)) + {} + + static inline std::string TypeNotIndexableErrorMessage(VariantDefines::Type_t type) { + std::ostringstream oss; + oss << "Variant type " << type << " is not an indexable type."; + AddStackTrace(oss, 2); + return oss.str(); + } + + TypeNotIndexableError::TypeNotIndexableError(VariantDefines::Type_t type) throw() + : std::runtime_error(TypeNotIndexableErrorMessage(type)) + {} + + static inline std::string NotNumericTypeErrorMessage(VariantDefines::Type_t type) { + std::ostringstream oss; + oss << "Variant type " << type << " not a numeric type."; + AddStackTrace(oss, 2); + return oss.str(); + } + + NotNumericTypeError::NotNumericTypeError(VariantDefines::Type_t type) throw() + : std::runtime_error(NotNumericTypeErrorMessage(type)) + {} + + static inline std::string KeyErrorMessage(const std::string &key) { + std::ostringstream oss; + oss << "Key \"" << key << "\" not contained in map."; + AddStackTrace(oss, 2); + return oss.str(); + } + + KeyError::KeyError(const std::string &key) throw() + : std::runtime_error(KeyErrorMessage(key)) + {} + + static inline std::string BadPathErrorMessage(VariantDefines::Type_t type) { + std::ostringstream oss; + oss << "Variant paths do not allow " << type << " as a path element."; + AddStackTrace(oss, 2); + return oss.str(); + } + + static inline std::string BadPathErrorMessage(const std::string &msg) { + std::ostringstream oss; + oss << msg; + AddStackTrace(oss, 2); + return oss.str(); + } + + BadPathError::BadPathError(VariantDefines::Type_t type) throw() + : std::runtime_error(BadPathErrorMessage(type)) + {} + + BadPathError::BadPathError(const std::string &msg) throw() + : std::runtime_error(BadPathErrorMessage(msg)) + {} + + static inline std::string InvalidReferenceErrorMessage(const std::string &msg) { + std::ostringstream oss; + oss << msg; + AddStackTrace(oss, 2); + return oss.str(); + } + + InvalidReferenceError::InvalidReferenceError(const std::string &msg) throw() + : std::runtime_error(InvalidReferenceErrorMessage(msg)) + {} + + static inline std::string InvalidOperationErrorMessage(VariantDefines::Type_t type, const std::string &opname) + { + std::ostringstream oss; + oss << "Variant cannot perform operation " << opname << " on type " << type; + AddStackTrace(oss, 2); + return oss.str(); + } + + InvalidOperationError::InvalidOperationError(VariantDefines::Type_t type, const std::string &opname) throw() + : std::runtime_error(InvalidOperationErrorMessage(type, opname)) + {} +} + diff --git a/src/hos_libvariant/src/src/Extensions.cc b/src/hos_libvariant/src/src/Extensions.cc new file mode 100644 index 00000000..22203caa --- /dev/null +++ b/src/hos_libvariant/src/src/Extensions.cc @@ -0,0 +1,797 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author Josh Staley + * \brief Useful extension functions for Variants + */ + +#include "../../src/include/Variant/Extensions.h" + +#include +#include +#include +#include +#include +#include "../../src/include/Variant/Path.h" +#include "../../src/include/Variant/Variant.h" + +using namespace std; + +#if 0 +#include +#define DBPRINT(x) cout << x +#else +#define DBPRINT(x) +#endif + +namespace libvariant { + + bool SimpleList( const Variant & var ) { + if ( !var.IsList() ) + return false; + for ( unsigned i = 0; i < var.Size(); ++i ) + if ( var[i].IsMap() | var[i].IsList() ) + return false; + return true; + } + + Variant ExtensionParams() { + Variant v; + ExtensionParams(v); + return v; + } + + void ExtensionParams( VariantRef params ) { + if ( params.IsNull() ) { + params = Variant::MapType; + } + + if ( !params.IsMap() ) { + throw runtime_error("# ExtensionParams() - params must be a map"); + } + + if ( !(params.Contains("noSimpleLists") && params["noSimpleLists"].IsBool()) ) { + params["noSimpleLists"] = true; + } + + if ( !params.Contains("pathPrefix") ) { + params["pathPrefix"] = ""; + } + if ( !(params["pathPrefix"].IsString() && params["pathPrefix"].Size() <= 1) ) { + throw runtime_error("# ExtensionParams() - Invalid pathPrefix"); + } + + if ( !params.Contains("pathDelimiter") ) { + params["pathDelimiter"] = "/"; + } + // Must have a delimiter + if ( !(params["pathDelimiter"].IsString() && params["pathDelimiter"].Size() == 1) ) { + throw runtime_error("# ExtensionParams() - Invalid pathDelimiter"); + } + + if ( !params.Contains("indexPrefix") ) { + params["indexPrefix"] = "["; + } + // Must have a prefix + if ( !(params["indexPrefix"].IsString() && params["indexPrefix"].Size() == 1) ) { + throw runtime_error("# ExtensionParams() - Invalid indexPrefix"); + } + + if ( !params.Contains("indexSuffix") ) { + params["indexSuffix"] = "]"; + } + if ( !(params["indexSuffix"].IsString() && params["indexSuffix"].Size() <= 1) ) { + throw runtime_error("# ExtensionParams() - Invalid indexSuffix"); + } + + if ( !params.Contains("listDelimiter") ) { + params["listDelimiter"] = ","; + } + // Must have a delimiter + if ( !(params["listDelimiter"].IsString() && params["listDelimiter"].Size() == 1)) { + throw runtime_error("# ExtensionParams() - Invalid listDelimiter"); + } + } + + Variant FlattenPath( const Variant &var, Variant params ) { + Variant flat; + FlattenPathTo( flat, var, params ); + return flat; + } + + Variant ExpandPath( const Variant &var, Variant params ) { + Variant expand; + ExpandPathTo( expand, var, params ); + return expand; + } + + void FlattenPathTo( VariantRef flat, const Variant &var, Variant params, string prefix ) { + switch ( var.GetType() ) { + case Variant::ListType: + if ( (!params["noSimpleLists"].AsBool()) && SimpleList(var) ) { + if( prefix.size() ) { + flat[prefix] = var.Copy(); + } else { + flat = var.Copy(); + } + } else { + for( unsigned i=0; i < var.Size(); ++i ) { + stringstream tmp; + if ( prefix.size() ) { + tmp << prefix; + } + tmp << params["indexPrefix"].AsString(); + tmp << i; + tmp << params["indexSuffix"].AsString(); + FlattenPathTo( flat, var[i], params, tmp.str() ); + } + } + break; + case Variant::MapType: + for( Variant::ConstMapIterator i(var.MapBegin()), e(var.MapEnd()); i != e; ++i ) { + stringstream tmp; + if ( prefix.size() ) { + tmp << prefix + params["pathDelimiter"].AsString(); + } else { + tmp << params["pathPrefix"].AsString(); + } + tmp << i->first; + FlattenPathTo( flat, i->second, params, tmp.str()); + } + break; + default: + if( prefix.size() ) { + flat[ prefix ] = var.Copy(); + } else { + flat = var.Copy(); + } + } + } + + /// The current version of this funtion is fairly simple and cannot fully + /// reverse the operation FlattenPathTo does on a variant with the same params + /// argument. This primarily has to do with lists. + void ExpandPathTo( VariantRef expand, const Variant &var, Variant params ) { + if ( !var.IsMap() ) { + expand = var; + return; + } + + for ( Variant::ConstMapIterator i(var.MapBegin()), e(var.MapEnd()); i != e; ++i ) { + string path = i->first; + string delimiter = params["pathDelimiter"].AsString(); + if ( delimiter.length() != 1 ) { + throw runtime_error("# ExpandPathTo() - Delimiter is not a single char"); + } + for ( unsigned ii = 0; ii < path.length(); ++ii ) { + if (path[ii] == delimiter[0]) { + path[ii] = '/'; + } + } + expand.SetPath( path, i->second ); + } + } + + map< string, string > FlattenPathToStrStrMap ( const Variant &var, Variant params ) { + map< string, string > flatMap; + Variant flat = FlattenPath( var, params ); + + for ( Variant::MapIterator i(flat.MapBegin()), e(flat.MapEnd()); i != e; ++i ) { + stringstream tmp; + + switch (i->second.GetType()) { + case Variant::ListType: + for ( unsigned j = 0; j < i->second.Size(); ++j ) { + if (j != 0){ + tmp << params["listDelimiter"].AsString(); + } + tmp << i->second[j].AsString(); + } + flatMap[i->first] = tmp.str(); + break; + case Variant::BlobType: + throw runtime_error("# FlattenToStrStrMap() - BlobType not supported"); + default: + flatMap[i->first] = i->second.AsString(); + } + } + + return flatMap; + } + + Variant RDiff ( const Variant &base, const Variant &compare ) { + Variant diff(Variant::MapType); + RDiff( diff, base, compare ); + return diff; + } + + void RDiff ( VariantRef diff, const Variant &base, const Variant &compare ) { + switch ( compare.GetType() ) { + case Variant::MapType: + DBPRINT("Start of map" << endl); + + // Replace and break + if ( !base.IsMap() ) { + diff = compare.Copy(); + break; + } + + for ( Variant::ConstMapIterator i(compare.MapBegin()), e(compare.MapEnd()); i != e; ++i ) { + DBPRINT(i->first << endl); + + // Replace and continue + if ( !base.Contains(i->first) ) { + diff[i->first] = i->second.Copy(); + continue; + } + + // Recurse into map + if ( base[i->first] != i->second ) { + diff[i->first] = Variant::MapType; + DBPRINT("recurse for " << i->first << endl); + RDiff( diff[i->first], base[i->first], compare[i->first] ); + } + + // If map diff became null or an empty map, remove - TODO: should this be an option? + if ( diff.Contains(i->first) ) { + if ( (diff[ i->first ].GetType() == Variant::NullType) || + (diff[ i->first ].GetType() == Variant::MapType && diff[ i->first ].Size() == 0) ) { + diff.Erase(i->first); + } + } + } + break; + default: + if( base != compare ) { + diff = compare.Copy(); + } + } + } + + void RUpdate( VariantRef base, const Variant &update ) { + switch ( update.GetType() ) { + case Variant::NullType: + return; + case Variant::MapType: + if ( !base.Exists() || base.IsMap() ) { + for ( Variant::ConstMapIterator i(update.MapBegin()), e(update.MapEnd()); i != e; ++i ) { + RUpdate(base.At( i->first, Variant::MapType ), update[ i->first ]); + } + break; + } + // else we go to default + default: + base = update.Copy(); + } + } + + std::string JSONPointerUnescape(const std::string &fragment) { + std::string ret; + const char *c = fragment.c_str(); + const char *e = c + fragment.size(); + while (c != e) { + switch (*c) { + case '~': + ++c; + if (c != e) { + if (*c == '0') { + ret.append("~"); + } else if (*c == '1') { + ret.append("/"); + } else { + ret.append("~"); + ret.append(c, 1); + } + ++c; + } + break; + default: + ret.append(c, 1); + ++c; + break; + } + } + return ret; + } + + enum Operations_e { + OP_ADD, + OP_REMOVE, + OP_TEST, + OP_GET + }; + + struct Operation_t { + Operation_t() {} + Operation_t(Operations_e o, const std::string &p) + : op(o), success(false), guess(false), replaced(false), pointer(p) {} + + Operations_e op; + Path path; // path that modification /starts at/ + Variant value; + Variant old_value; + bool success; + bool guess; + bool replaced; + std::string pointer; + }; + + static bool IsIndex(const std::string &str, uintmax_t &index) { + const char *b = str.c_str(); + char *e = 0; + unsigned long long v = strtoull(b, &e, 10); + if (e == b) { return false; } + while (e != 0 && *e != '\0' && isspace(*e)) { ++e; } + if (e == 0 || *e != '\0') { return false; } + index = v; + return true; + } + + VariantRef JSONPointerOp(const std::string &pointer, VariantRef v, Operation_t &op) { + if (pointer.empty()) { + switch (op.op) { + case OP_ADD: + if (v.Exists()) { + op.replaced = true; + op.old_value = v; + } + v = op.value; + op.success = true; + return v; + case OP_REMOVE: + op.value = v; + v = Variant::NullType; + op.success = true; + return v; + case OP_TEST: + op.success = (v == op.value); + return v; + case OP_GET: + op.value = v; + op.success = true; + return v; + } + } + if (pointer[0] != '/') { + throw std::runtime_error("JSON Pointer is required to start with '/'"); + } + std::string::size_type nindex = pointer.find('/', 1); + std::string component = JSONPointerUnescape(pointer.substr(1, nindex - 1)); + bool is_last = (nindex >= pointer.size()); + if (!v.Exists()) { + if (op.guess) { + // Best guess + uintmax_t index = 0; + if (IsIndex(component, index)) { + return JSONPointerOp(pointer.substr(nindex), v.At(index), op); + } else { + return JSONPointerOp(pointer.substr(nindex), v.At(component), op); + } + } else { + throw std::runtime_error("Unable to resolve the JSON Pointer."); + } + } else if (v.IsMap()) { + op.path.push_back(component); + if (is_last) { + switch (op.op) { + case OP_ADD: + if (v.Contains(component)) { + op.replaced = true; + op.old_value = v.Get(component); + } + v.Set(component, op.value); + op.success = true; + return v.At(component); + case OP_REMOVE: + op.value = v.At(component); + v.Erase(component); + op.success = true; + return v.At(component); + case OP_TEST: + { + VariantRef ret = v.At(component); + op.success = (ret == op.value); + return ret; + } + case OP_GET: + { + VariantRef ret = v.At(component); + op.value = ret; + op.success = true; + return ret; + } + } + } else { + return JSONPointerOp(pointer.substr(nindex), v.At(component), op); + } + } else if (v.IsList()) { + if (is_last && component == "-") { + op.path.push_back(v.Size()); + if (op.op == OP_ADD) { + v.Append(op.value); + op.success = true; + return v.At(v.Size()); + } + throw std::runtime_error("Attempting to reference past the end of an array"); + } + uintmax_t index = 0; + if (!IsIndex(component, index)) { + throw std::runtime_error("Attempting to index an array with a string"); + } + op.path.push_back(index); + if (is_last) { + switch (op.op) { + case OP_ADD: + if (v.Contains(index)) { + op.old_value = v.Get(index); + op.replaced = true; + } + v.AsList().insert(v.ListBegin()+index, op.value); + op.success = true; + return v.At(index); + case OP_REMOVE: + op.value = v.At(component); + v.Erase(index); + op.success = true; + return v.At(index); + case OP_TEST: + { + VariantRef ret = v.At(index); + op.success = (ret == op.value); + return ret; + } + case OP_GET: + { + VariantRef ret = v.At(index); + op.value = ret; + op.success = true; + return ret; + } + } + } else { + return JSONPointerOp(pointer.substr(nindex), v.At(index), op); + } + } + std::ostringstream oss; + oss << "The JSON Pointer does not match the document, " + << v.GetType() << " is not a indexable type"; + throw std::runtime_error(oss.str()); + } + + void JSONPointerAdd(const std::string &pointer, VariantRef v, Variant data) { + Operation_t op(OP_ADD, pointer); + op.value = data; + try { + JSONPointerOp(op.pointer, v, op); + } catch (const std::exception &e) { + std::ostringstream oss; + oss << "Error adding a value with the JSON Pointer \"" + << op.pointer << "\" at path \"" + << PathString(op.path) << "\": " << e.what(); + throw std::runtime_error(oss.str()); + } + } + + void JSONPointerRemove(const std::string &pointer, VariantRef v) { + Operation_t op(OP_REMOVE, pointer); + try { + JSONPointerOp(op.pointer, v, op); + } catch (const std::exception &e) { + std::ostringstream oss; + oss << "Error removing a value with the JSON Pointer \"" + << op.pointer << "\" at path \"" + << PathString(op.path) << "\": " << e.what(); + throw std::runtime_error(oss.str()); + } + } + + void JSONPointerReplace(const std::string &pointer, VariantRef v, Variant data) { + Operation_t op(OP_GET, pointer); + try { + if (JSONPointerOp(op.pointer, v, op).Exists()) { + v.SetPath(op.path, data); + } else { + throw std::runtime_error("The target does not exist"); + } + } catch (const std::exception &e) { + std::ostringstream oss; + oss << "Error replacing a value with the JSON Pointer \"" + << op.pointer << "\" at path \"" + << PathString(op.path) << "\": " << e.what(); + throw std::runtime_error(oss.str()); + } + } + + void JSONPointerMove(const std::string &src, const std::string &dst, VariantRef v) { + Operation_t op(OP_REMOVE, src); + try { + JSONPointerOp(op.pointer, v, op); + Variant data = op.value; + Path path = op.path; + try { + op = Operation_t(OP_ADD, dst); + op.value = data; + JSONPointerOp(op.pointer, v, op); + } catch (const std::exception &e) { + v.SetPath(path, data); + throw e; + } + } catch (const std::exception &e) { + std::ostringstream oss; + oss << "Error moving a value with the JSON Pointer \"" + << op.pointer << "\" at path \"" + << PathString(op.path) << "\": " << e.what(); + throw std::runtime_error(oss.str()); + } + } + + void JSONPointerCopy(const std::string &src, const std::string &dst, VariantRef v) { + Operation_t op(OP_GET, src); + try { + VariantRef s = JSONPointerOp(op.pointer, v, op); + if (s.Exists()) { + op = Operation_t(OP_ADD, dst); + op.value = s.Copy(); + JSONPointerOp(op.pointer, v, op); + } else { + throw std::runtime_error("The src does not exist"); + } + } catch (const std::exception &e) { + std::ostringstream oss; + oss << "Error copying a value with the JSON Pointer \"" + << op.pointer << "\" at path \"" + << PathString(op.path) << "\": " << e.what(); + throw std::runtime_error(oss.str()); + } + } + + VariantRef JSONPointerLookup(const std::string &pointer, VariantRef v) { + Operation_t op(OP_GET, pointer); + try { + return JSONPointerOp(op.pointer, v, op); + } catch (const std::exception &e) { + std::ostringstream oss; + oss << "Error looking up a value with the JSON Pointer \"" + << op.pointer << "\" at path \"" + << PathString(op.path) << "\": " << e.what(); + throw std::runtime_error(oss.str()); + } + } + + std::string FormJSONPointer(const Path &path) { + std::ostringstream ret; + for (Path::const_iterator i(path.begin()), e(path.end()); i != e; ++i) { + if (i->IsNumber()) { + ret << "/" << i->AsUnsigned(); + } else { + ret << "/" << i->AsString(); + } + } + return ret.str(); + } + + struct Patch_t { + Patch_t(Operations_e o, Path p, Variant v) : op(o), path(p), value(v) {} + Patch_t(Operations_e o, Path p) : op(o), path(p) {} + Operations_e op; + Path path; + Variant value; + }; + + void JSONPatchUndo(VariantRef v, std::deque *undo) { + while (!undo->empty()) { + const Patch_t &p = undo->back(); + switch (p.op) { + case OP_ADD: + { + Path path = p.path; + if (path.size() > 0) { + PathElement elem = path.back(); + path.pop_back(); + VariantRef r = v.AtPath(path); + if (r.IsList()) { + r.AsList().insert(r.ListBegin()+elem.AsUnsigned(), p.value); + } else { + r.Set(elem.AsString(), p.value); + } + } else { + v = p.value; + } + } + break; + case OP_REMOVE: + v.ErasePath(p.path); + break; + case OP_TEST: + case OP_GET: + throw std::runtime_error("Unable to perform operation here"); + } + undo->pop_back(); + } + } + + + bool JSONPatchOp(VariantRef v, const Variant &diff, std::deque *undo) { + std::string oper = diff.Get("op").AsString(); + Operation_t op; + try { + if (oper == "add") { + op = Operation_t(OP_ADD, diff.Get("path").AsString()); + op.value = diff.Get("value"); + JSONPointerOp(op.pointer, v, op); + if (op.replaced) { + undo->push_back(Patch_t(OP_ADD, op.path, op.old_value)); + } else { + undo->push_back(Patch_t(OP_REMOVE, op.path)); + } + return op.success; + } else if (oper == "remove") { + op = Operation_t(OP_REMOVE, diff.Get("path").AsString()); + JSONPointerOp(op.pointer, v, op); + undo->push_back(Patch_t(OP_ADD, op.path, op.value)); + return op.success; + } else if (oper == "replace") { + op = Operation_t(OP_GET, diff.Get("path").AsString()); + VariantRef r = JSONPointerOp(op.pointer, v, op); + if (r.Exists()) { + r = diff.Get("value"); + } else { + return false; + } + undo->push_back(Patch_t(OP_ADD, op.path, op.value)); + return op.success; + } else if (oper == "move") { + op = Operation_t(OP_REMOVE, diff.Get("from").AsString()); + JSONPointerOp(op.pointer, v, op); + Variant data = op.value; + undo->push_back(Patch_t(OP_ADD, op.path, data)); + op = Operation_t(OP_ADD, diff.Get("path").AsString()); + op.value = data; + JSONPointerOp(op.pointer, v, op); + if (op.replaced) { + undo->push_back(Patch_t(OP_ADD, op.path, op.old_value)); + } else { + undo->push_back(Patch_t(OP_REMOVE, op.path)); + } + return op.success; + } else if (oper == "copy") { + op = Operation_t(OP_GET, diff.Get("from").AsString()); + JSONPointerOp(op.pointer, v, op); + Variant data = op.value; + op = Operation_t(OP_ADD, diff.Get("path").AsString()); + op.value = data; + JSONPointerOp(op.pointer, v, op); + if (op.replaced) { + undo->push_back(Patch_t(OP_ADD, op.path, op.old_value)); + } else { + undo->push_back(Patch_t(OP_REMOVE, op.path)); + } + return op.success; + } else if (oper == "test") { + op = Operation_t(OP_TEST, diff.Get("path").AsString()); + op.value = diff.Get("value"); + JSONPointerOp(op.pointer, v, op); + return op.success; + } + } catch (const std::exception &e) { + std::ostringstream oss; + oss << "Error executing patch op \"" << oper << "\" for pointer: " << op.pointer + << " stopped at: " << PathString(op.path) << "\n\twhat:\n" << e.what(); + throw std::runtime_error(oss.str()); + } + throw std::runtime_error("Unknown JSON Patch operation: " + oper); + } + + std::pair JSONPatch(VariantRef v, const Variant &diff) { + std::deque undo; + try { + bool success = true; + if (diff.IsList()) { + Variant::ConstListIterator i(diff.ListBegin()), e(diff.ListEnd()); + for (;i != e && success; ++i) { + success = JSONPatchOp(v, *i, &undo); + } + } else { + success = JSONPatchOp(v, diff, &undo); + } + std::string msg; + if (!success) { + JSONPatchUndo(v, &undo); + msg = "Failure"; + } + return std::make_pair(success, msg); + } catch (const std::exception &e) { + JSONPatchUndo(v, &undo); + return std::make_pair(false, std::string(e.what())); + } + } + + void JSONDiffRef(VariantRef src, VariantRef dst, VariantRef diff, Path &path) { + if (!dst.Exists()) { + diff.Append( + Variant() + .Set("op", "remove") + .Set("path", FormJSONPointer(path)) + ); + return; + } + if (!src.Exists()) { + diff.Append( + Variant() + .Set("op", "add") + .Set("path", FormJSONPointer(path)) + .Set("value", dst) + ); + return; + } + if (src.GetType() != dst.GetType()) { + diff.Append( + Variant() + .Set("op", "replace") + .Set("path", FormJSONPointer(path)) + .Set("value", dst) + ); + return; + } + if (src != dst) { + switch (src.GetType()) { + case Variant::ListType: + { + uintmax_t len = std::max(src.Size(), dst.Size()); + for (uintmax_t i = 0; i < len; ++i) { + path.push_back(PathElement(i)); + JSONDiffRef(src.At(i), dst.At(i), diff, path); + path.pop_back(); + } + } + break; + case Variant::MapType: + { + std::set keys; + Variant::ConstMapIterator i, e; + for (i = dst.MapBegin(), e = dst.MapEnd(); i != e; ++i) { + keys.insert(i->first); + } + for (i = src.MapBegin(), e = src.MapEnd(); i != e; ++i) { + keys.insert(i->first); + } + for (std::set::iterator i(keys.begin()), e(keys.end()); i != e; ++i) { + path.push_back(PathElement(*i)); + JSONDiffRef(src.At(*i), dst.At(*i), diff, path); + path.pop_back(); + } + } + break; + default: + diff.Append( + Variant() + .Set("op", "replace") + .Set("path", FormJSONPointer(path)) + .Set("value", dst) + ); + break; + } + } + } + + Variant JSONDiff(const Variant &src, const Variant &dst) { + Path path; + Variant diff = Variant::ListType; + JSONDiffRef(src, dst, diff, path); + return diff; + } +} diff --git a/src/hos_libvariant/src/src/GuessFormat.cc b/src/hos_libvariant/src/src/GuessFormat.cc new file mode 100644 index 00000000..51543fc7 --- /dev/null +++ b/src/hos_libvariant/src/src/GuessFormat.cc @@ -0,0 +1,54 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "../../src/include/Variant/GuessFormat.h" + +#include + +namespace libvariant { + SerializeType GuessFormat(ParserInput* in) { + unsigned len = 0; + const char *ptr = (const char*)in->GetPtr(len); + if (!ptr) { +#ifdef ENABLE_YAML + return SERIALIZE_YAML; +#endif + throw std::runtime_error( + "libvariant::GuessFormat: Unable to guess input format, unexpected end of input." + ); + } + unsigned i = 0; + while (true) { + if (i >= len) { + unsigned l = i+1; + ptr = (const char*)in->GetPtr(l); + if (!ptr) { + throw std::runtime_error( + "libvariant::GuessFormat: Unable to guess input format, unexpected end of input." + ); + } + len = l; + } + if (!isspace(ptr[i])) { + if (ptr[i] == '<') { +#ifdef ENABLE_XML + return SERIALIZE_XMLPLIST; +#else + throw std::runtime_error("libvariant::GuessFormat: Input looks like XML but XML support is not available."); +#endif + } else { + // Even if the start looks like JSON it could still be YAML. + // YAML can also deserialize everything the JSON parser can, + // so choose YAML over JSON. +#ifdef ENABLE_YAML + return SERIALIZE_YAML; +#else + return SERIALIZE_JSON; +#endif + } + } + ++i; + } + } +} diff --git a/src/hos_libvariant/src/src/GuessScalar.cc b/src/hos_libvariant/src/src/GuessScalar.cc new file mode 100644 index 00000000..ccedb43d --- /dev/null +++ b/src/hos_libvariant/src/src/GuessScalar.cc @@ -0,0 +1,120 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "../../src/src/GuessScalar.h" + +#include +#include +#include +#include +#include +#include + +namespace libvariant { + + namespace { + // Apparently the first match result is the match of the entire pattern + static const char *match_string = "^[[:space:]\n]*(" + "(null|Null|NULL|~)" // Null 2 + "|(true|True|TRUE)" // True 3 + "|(false|False|FALSE)" // False 4 + "|([-+]?[0-9]+)" // int10 5 + "|0o([0-7]+)" // int8 6 + "|0x([0-9a-fA-F]+)" // int16 7 + "|([-+]?((\\.[0-9]+)|([0-9]+(\\.[0-9]*)?))([eE][-+]?[0-9]+)?)" // float 8 (9,10,11,12,13) + "|([-+]?\\.inf|\\.Inf|\\.INF)" // inf 14 + "|(\\.nan|\\.Nan|\\.NAN)" // nan 15 + ")[[:space:]\n]*$"; + enum { + MATCH_NULL = 2, + MATCH_TRUE = 3, + MATCH_FALSE = 4, + MATCH_INT10 = 5, + MATCH_INT8 = 6, + MATCH_INT16 = 7, + MATCH_FLOAT = 8, + MATCH_INF = 14, + MATCH_NAN = 15, + MATCH_MAX = 16 + }; + + class GuessRegex { + public: + GuessRegex(); + ~GuessRegex(); + regex_t guessregex; + + }; + + GuessRegex::GuessRegex() { + int err = 0; + memset(&guessregex, 0, sizeof(regex_t)); + err = regcomp(&guessregex, match_string, REG_EXTENDED); + if (err) { + std::vector buffer(8192); + regerror(err, &guessregex, &buffer[0], buffer.size()); + std::ostringstream oss; + oss << "libvariant library initialization failure: Failed to initialize type guessing regex with error: " + << &buffer[0]; + fputs(oss.str().c_str(), stderr); + throw std::runtime_error(oss.str()); + } + } + + + GuessRegex::~GuessRegex() { + regfree(&guessregex); + } + } + + void GuessScalar(const char *value, unsigned length, const char *anchor, const char *tag, + ParserImpl *p, ParserActions *action) { + static GuessRegex guessregex; + regmatch_t match[MATCH_MAX]; + if (regexec(&guessregex.guessregex, value, MATCH_MAX, &match[0], 0) == 0) { + if (match[MATCH_NULL].rm_so != -1) { + action->Null(p, anchor, tag); + } else if (match[MATCH_TRUE].rm_so != -1) { + action->Scalar(p, true, anchor, tag); + } else if (match[MATCH_FALSE].rm_so != -1) { + action->Scalar(p, false, anchor, tag); + } else if (match[MATCH_INT10].rm_so != -1) { + long long val; + val = strtoll(&value[match[MATCH_INT10].rm_so], 0, 10); + if (val == LLONG_MAX && errno == ERANGE) { + unsigned long long v; + v = strtoull(&value[match[MATCH_INT10].rm_so], 0, 10); + action->Scalar(p, uintmax_t(v), anchor, tag); + } else { + action->Scalar(p, intmax_t(val), anchor, tag); + } + } else if (match[MATCH_INT8].rm_so != -1) { + unsigned long long val; + val = strtoull(&value[match[MATCH_INT8].rm_so], 0, 8); + action->Scalar(p, uintmax_t(val), anchor, tag); + } else if (match[MATCH_INT16].rm_so != -1) { + unsigned long long val; + val = strtoull(&value[match[MATCH_INT16].rm_so], 0, 16); + action->Scalar(p, uintmax_t(val), anchor, tag); + } else if (match[MATCH_FLOAT].rm_so != -1) { + double val = strtod(&value[match[MATCH_FLOAT].rm_so], 0); + action->Scalar(p, val, anchor, tag); + } else if (match[MATCH_INF].rm_so != -1) { + double val = std::numeric_limits::infinity(); + if (value[match[MATCH_INF].rm_so] == '-') { + val = -val; + } + action->Scalar(p, val, anchor, tag); + } else if (match[MATCH_NAN].rm_so != -1) { + double val = std::numeric_limits::quiet_NaN(); + action->Scalar(p, val, anchor, tag); + } else { + action->Scalar(p, value, length, anchor, tag); + } + } else { + action->Scalar(p, value, length, anchor, tag); + } + } + +} diff --git a/src/hos_libvariant/src/src/GuessScalar.h b/src/hos_libvariant/src/src/GuessScalar.h new file mode 100644 index 00000000..88e654c8 --- /dev/null +++ b/src/hos_libvariant/src/src/GuessScalar.h @@ -0,0 +1,14 @@ +/** \file + * \author John Bridgman + * \brief A simple routine that "guesses" what type a scalar is. + */ +#ifndef VARIANT_GUESSSCALAR_H +#define VARIANT_GUESSSCALAR_H + +#pragma once +#include "../../src/include/Variant/Parser.h" +namespace libvariant { + void GuessScalar(const char *value, unsigned length, const char *anchor, const char *tag, + ParserImpl *p, ParserActions *action); +} +#endif diff --git a/src/hos_libvariant/src/src/JSONEmitter.cc b/src/hos_libvariant/src/src/JSONEmitter.cc new file mode 100644 index 00000000..7b9a8ec0 --- /dev/null +++ b/src/hos_libvariant/src/src/JSONEmitter.cc @@ -0,0 +1,299 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= + +#include "../../src/src/JSONEmitter.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../src/include/Variant/EmitterOutput.h" +#include "../../src/src/Base64.h" +#include "../../src/src/BlobMagic.h" + +using namespace std; + +// We do some small buffering optimizations so that we aren't calling +// Write over and over again with very small amounts. + +#define MAX_BUFFER_LEN 512u +#define BUFFER_THRESHOLD 128u + +namespace libvariant { + + JSONEmitterImpl::JSONEmitterImpl(shared_ptr o, Variant params) + : output(o), pretty(false), strict(false), num_indent(4), + numeric_precision(std::numeric_limits::digits10+2), + buffer(MAX_BUFFER_LEN, 0), buffer_len(0) + { + if (params.IsMap()) { + params.GetInto(pretty, "pretty", pretty); + params.GetInto(strict, "strict", strict); + params.GetInto(num_indent, "indent", num_indent); + params.GetInto(numeric_precision, "precision", numeric_precision); + } + } + + JSONEmitterImpl::~JSONEmitterImpl() { + Close(); + } + + void JSONEmitterImpl::BeginDocument() { + } + + void JSONEmitterImpl::EndDocument() { + } + + void JSONEmitterImpl::BeginMap(int length) { + CheckSeparator(); + EmitRaw("{"); + state.push_back(MAP_FIRST); + } + + void JSONEmitterImpl::EndMap() { + state.pop_back(); + EmitIndent(); + EmitRaw("}"); + Flush(); + } + + void JSONEmitterImpl::BeginList(int length) { + CheckSeparator(); + EmitRaw("["); + state.push_back(LIST_FIRST); + } + + void JSONEmitterImpl::EndList() { + state.pop_back(); + EmitIndent(); + EmitRaw("]"); + Flush(); + } + + void JSONEmitterImpl::EmitNull() { + CheckSeparator(); + EmitRaw("null"); + } + + void JSONEmitterImpl::EmitTrue() { + CheckSeparator(); + EmitRaw("true"); + } + + void JSONEmitterImpl::EmitFalse() { + CheckSeparator(); + EmitRaw("false"); + } + + void JSONEmitterImpl::Emit(const char *v) { + CheckSeparator(); + EmitString(v, strlen(v)); + } + + void JSONEmitterImpl::Emit(intmax_t v) { + CheckSeparator(); + std::ostringstream oss; + oss << v; + EmitRaw(oss.str().c_str(), oss.str().length()); + } + + void JSONEmitterImpl::Emit(uintmax_t v) { + CheckSeparator(); + std::ostringstream oss; + oss << v; + EmitRaw(oss.str().c_str(), oss.str().length()); + } + + void JSONEmitterImpl::Emit(double v) { + CheckSeparator(); + std::ostringstream oss; + if (strict && (std::isnan(v) || std::isinf(v))) { + throw std::runtime_error("JSONEmitter: The JSON specification does not permit" + " numeric types that cannot be represented as a series of digits."); + } else if (std::isnan(v) || std::isinf(v)) { + oss << "null"; + } else { + oss << std::setprecision(numeric_precision) << std::showpoint << v; + } + EmitRaw(oss.str().c_str(), oss.str().length()); + } + + void JSONEmitterImpl::Emit(ConstBlobPtr b) { + if (strict) { + throw std::runtime_error("JSONEmitter: Cannot serialize a BlobType" + " in strict JSON mode."); + } + CheckSeparator(); + EmitRaw("\""); + EmitRaw(MAGIC_BLOB_JSONSTR); + std::vector buf(Base64EncodeSize(b->GetTotalLength(), 0)); + unsigned len = Base64Encode(&buf[0], b->GetIOVec(), b->GetNumBuffers(), 0); + EmitRaw(&buf[0], len); + EmitRaw("\""); + } + + void JSONEmitterImpl::Flush() { + if (buffer_len > 0) { + unsigned num_written = 0; + while (num_written < buffer_len) { + num_written += output->Write(&buffer[num_written], buffer_len - num_written); + } + buffer_len = 0; + } + output->Flush(); + } + + void JSONEmitterImpl::Close() { + Flush(); + } + + Variant JSONEmitterImpl::GetParam(const std::string &key) { + if (key == "pretty") { return pretty; } + if (key == "indent") { return num_indent; } + if (key == "precision") { return numeric_precision; } + return Variant::NullType; + } + + Variant JSONEmitterImpl::GetParams() { + Variant ret; + ret["pretty"] = pretty; + ret["indent"] = num_indent; + ret["precision"] = numeric_precision; + return ret; + } + + void JSONEmitterImpl::SetParam(const std::string &key, Variant value) { + if (key == "pretty") { + pretty = value.AsBool(); + } + if (key == "indent") { + num_indent = value.AsUnsigned(); + } + if (key == "precision") { + numeric_precision = value.AsUnsigned(); + } + } + + void JSONEmitterImpl::CheckSeparator() { + if (state.empty()) return; + switch (state.back()) { + case MAP_FIRST: + state.back() = IN_MAP_VALUE; + EmitIndent(); + break; + case IN_MAP_KEY: + state.back() = IN_MAP_VALUE; + EmitRaw(","); + EmitIndent(); + break; + case IN_MAP_VALUE: + state.back() = IN_MAP_KEY; + EmitRaw(": "); + break; + case LIST_FIRST: + state.back() = IN_LIST; + EmitIndent(); + break; + case IN_LIST: + EmitRaw(","); + EmitIndent(); + break; + default: + break; + } + } + + void JSONEmitterImpl::EmitIndent() { + if (!pretty) return; + EmitRaw("\n"); + unsigned indent = state.size() * num_indent; + if (indent > BUFFER_THRESHOLD) { + Flush(); + memset(&buffer[buffer_len], ' ', BUFFER_THRESHOLD); + unsigned num_written = 0; + while (num_written < indent) { + num_written += output->Write(&buffer[buffer_len], min(indent - num_written, BUFFER_THRESHOLD)); + } + } else { + if (indent + buffer_len > MAX_BUFFER_LEN) { + Flush(); + } + memset(&buffer[buffer_len], ' ', indent); + buffer_len += indent; + } + } + + void JSONEmitterImpl::EmitString(const char *text, unsigned len) { + EmitRaw("\""); + const char *end = text + len; + while (text != end) { + if (*text == '\\') { + EmitRaw("\\\\"); + } else if (*text == '\"') { + EmitRaw("\\\""); + //} else if (*text == '/') { + //EmitRaw("\\/"); + } else if (*text == '\b') { + EmitRaw("\\b"); + } else if (*text == '\f') { + EmitRaw("\\f"); + } else if (*text == '\n') { + EmitRaw("\\n"); + } else if (*text == '\r') { + EmitRaw("\\r"); + } else if (*text == '\t') { + EmitRaw("\\t"); + } else if (*text < 0) { + EmitRaw(text, 1); + } else if (*text < 0x20) { + char buffer[7]; + int val = (unsigned char)*text; + snprintf(buffer, sizeof(buffer), "\\u%4.4x", val); + EmitRaw(&buffer[0]); + } else { + EmitRaw(text, 1); + } + ++text; + } + EmitRaw("\""); + } + + void JSONEmitterImpl::EmitRaw(const char *text) { + EmitRaw(text, strlen(text)); + } + void JSONEmitterImpl::EmitRaw(const char *text, unsigned len) { + if (len > BUFFER_THRESHOLD) { + Flush(); + unsigned num_written = 0; + while (num_written < len) { + num_written += output->Write(&text[num_written], len - num_written); + } + } else { + if (len + buffer_len > MAX_BUFFER_LEN) { + Flush(); + } + memcpy(&buffer[buffer_len], text, len); + buffer_len += len; + } + } + +} diff --git a/src/hos_libvariant/src/src/JSONEmitter.h b/src/hos_libvariant/src/src/JSONEmitter.h new file mode 100644 index 00000000..c6707089 --- /dev/null +++ b/src/hos_libvariant/src/src/JSONEmitter.h @@ -0,0 +1,105 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * A simple JSON emitter class to emit valid JSON. + */ +#ifndef VARIANT_JSONEMITTER_H +#define VARIANT_JSONEMITTER_H + +#pragma once +#include +#include +#include +#include +#include "../../src/include/Variant/Emitter.h" + +namespace libvariant { + + /** + * A simple JSON emitter class to make it simple to emit + * valid JSON in a program. + * Does minimal error checking. + * All strings are assumed to be UTF-8 encoded. + * + * This class buffers with a small buffer otherwise it would internally + * perform many calls to write with 1 or 2 bytes. + * Flush automatically happens on EndMap and EndList. + * + * Supported parameters are: + * "pretty": boolean + * "indent": integer (number of spaces to indent when pretty is on, + * default 4) + * "precision": integer (number of digits for a float) + * "strict": be more strict about emitting correct json + */ + class JSONEmitterImpl : public EmitterImpl { + enum State_t { + NONE, + MAP_FIRST, + IN_MAP_KEY, + IN_MAP_VALUE, + LIST_FIRST, + IN_LIST + }; + public: + JSONEmitterImpl(shared_ptr o, Variant params); + + ~JSONEmitterImpl(); + + virtual void BeginDocument(); + virtual void EndDocument(); + virtual void BeginMap(int length); + virtual void EndMap(); + virtual void BeginList(int length); + virtual void EndList(); + + virtual void EmitNull(); + virtual void EmitTrue(); + virtual void EmitFalse(); + virtual void Emit(const char *v); + virtual void Emit(intmax_t v); + virtual void Emit(uintmax_t v); + virtual void Emit(double v); + virtual void Emit(ConstBlobPtr b); + + virtual void Flush(); + virtual void Close(); + + virtual Variant GetParam(const std::string &key); + virtual Variant GetParams(); + virtual void SetParam(const std::string &key, Variant value); + private: + + void CheckSeparator(); + void EmitIndent(); + void EmitString(const char *text, unsigned len); + void EmitRaw(const char *text); + void EmitRaw(const char *text, unsigned len); + + shared_ptr output; + bool pretty; + bool strict; + unsigned num_indent; + unsigned numeric_precision; + std::deque state; + std::vector buffer; + unsigned buffer_len; + }; + +} +#endif diff --git a/src/hos_libvariant/src/src/JSONParser.cc b/src/hos_libvariant/src/src/JSONParser.cc new file mode 100644 index 00000000..5ae0785b --- /dev/null +++ b/src/hos_libvariant/src/src/JSONParser.cc @@ -0,0 +1,214 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + */ +#include "../../src/src/JSONParser.h" + +#include "../../src/src/BlobMagic.h" + +namespace libvariant { + + int JSONParserImpl::StaticCallback(void *ctx, int type, const struct JSON_value_struct* value) { + JSONParserImpl *impl = (JSONParserImpl*)ctx; + if (impl->status == S_BEGIN) { + impl->status = S_OK; + } + // If an exception is thrown from here, the parser will be in an + // inconsistent state. So, set our state to error. + try { + switch(type) { + case JSON_T_ARRAY_BEGIN: + ++impl->depth; + impl->TopAction()->BeginList(impl, -1, 0, 0); + break; + case JSON_T_ARRAY_END: + --impl->depth; + impl->TopAction()->EndList(impl); + break; + case JSON_T_OBJECT_BEGIN: + ++impl->depth; + impl->TopAction()->BeginMap(impl, -1, 0, 0); + break; + case JSON_T_OBJECT_END: + --impl->depth; + impl->TopAction()->EndMap(impl); + break; + case JSON_T_INTEGER: + impl->TopAction()->Scalar(impl, intmax_t(value->vu.integer_value), 0, 0); + break; + case JSON_T_UNSIGNED: + impl->TopAction()->Scalar(impl, uintmax_t(value->vu.unsigned_value), 0, 0); + break; + case JSON_T_FLOAT: + impl->TopAction()->Scalar(impl, value->vu.float_value, 0, 0); + break; + case JSON_T_NULL: + impl->TopAction()->Null(impl, 0, 0); + break; + case JSON_T_TRUE: + impl->TopAction()->Scalar(impl, true, 0, 0); + break; + case JSON_T_FALSE: + impl->TopAction()->Scalar(impl, false, 0, 0); + break; + case JSON_T_KEY: + impl->TopAction()->Scalar(impl, value->vu.str.value, value->vu.str.length, 0, 0); + break; + case JSON_T_STRING: + if (value->vu.str.length >= MAGIC_BLOB_LENGTH && + memcmp(value->vu.str.value, MAGIC_BLOB_TAG, MAGIC_BLOB_LENGTH) == 0) { + void *ptr = 0; + if (posix_memalign(&ptr, 64, Base64DecodeSize(value->vu.str.length)) != 0) { + throw std::bad_alloc(); + } + unsigned len = Base64Decode(ptr, value->vu.str.value+MAGIC_BLOB_LENGTH, + value->vu.str.length-MAGIC_BLOB_LENGTH); + BlobPtr blob = Blob::CreateFree(ptr, len); + impl->TopAction()->Scalar(impl, blob, 0, 0); + } else { + impl->TopAction()->Scalar(impl, value->vu.str.value, value->vu.str.length, 0, 0); + } + break; + default: + break; + } + } catch (...) { + impl->status = S_ERROR; + throw; + } + return true; + } + + JSONParserImpl::JSONParserImpl(shared_ptr i) + : parser(0), + status(S_START), + line(1), + column(0), + charcount(0), + depth(0), + input(i) + { + AllocParser(); + } + + JSONParserImpl::~JSONParserImpl() { + delete_JSON_parser(parser); + parser = 0; + } + + void JSONParserImpl::Reset() { + if (parser) { delete_JSON_parser(parser); } + parser = 0; + status = S_START; + line = 1; + column = 0; + charcount = 0; + depth = 0; + AllocParser(); + } + + void JSONParserImpl::AllocParser() { + JSON_config config; + init_JSON_config(&config); + config.callback = StaticCallback; + config.callback_ctx = this; + config.depth = -1; + config.allow_comments = 1; + parser = new_JSON_parser(&config); + } + + void JSONParserImpl::Parse() { + while ( (status == S_OK || status == S_BEGIN) && !action_stack.empty() ) { + unsigned len = 0; + const unsigned char *ptr = (const unsigned char*)input->GetPtr(len); + const unsigned char *c = ptr; + const unsigned char *end = ptr + len; + if (len == 0 || !ptr) { + if (JSON_parser_done(parser)) { status = S_END; } + else { status = S_ERROR; } + return; + } + while ( c != end && ( status == S_OK || status == S_BEGIN) && !action_stack.empty() ) { + ++charcount; + if (*c == '\n') { + column = 0; + ++line; + } else { ++column; } + if (JSON_parser_char(parser, *c)) { + if (depth == 0) { + if (status == S_OK) { + if (JSON_parser_done(parser)) { status = S_END; } + else { status = S_ERROR; } + } + } + } else if (status == S_OK) { status = S_ERROR; } + ++c; + } + input->Release(c - ptr); + } + } + + int JSONParserImpl::Run() { + while (!action_stack.empty()) { + switch (status) { + case S_START: + TopAction()->BeginDocument(this); + status = S_BEGIN; + return 0; + case S_BEGIN: + Parse(); + break; + case S_OK: + Parse(); + break; + case S_ERROR: + { + std::ostringstream oss; + oss << "JSONParser: An error occurred on line " << line << " column " << column; + errorstr = oss.str(); + throw std::runtime_error(errorstr); + } + case S_END: + status = S_DONE; + TopAction()->EndDocument(this); + return 1; + case S_DONE: + return 1; + default: + { + std::ostringstream oss; + oss << "JSONParser in inconsistent state (line: " << line << " column: " << column << ")"; + errorstr = oss.str(); + throw std::runtime_error("JSONParser in inconsistent state."); + } + } + } + return 0; + } + + JSONParserImpl::Status_t JSONParserImpl::GetStatus() const { return status; } + bool JSONParserImpl::Done() const { return status == S_DONE; } + bool JSONParserImpl::Error() const { return status == S_ERROR; } + bool JSONParserImpl::Ok() const { return status == S_OK; } + + std::string JSONParserImpl::ErrorStr() const { return errorstr; } + + unsigned JSONParserImpl::GetLine() const { return line; } + unsigned JSONParserImpl::GetColumn() const { return column; } + unsigned JSONParserImpl::GetByteCount() const { return charcount; } +} diff --git a/src/hos_libvariant/src/src/JSONParser.h b/src/hos_libvariant/src/src/JSONParser.h new file mode 100644 index 00000000..8fba1a5d --- /dev/null +++ b/src/hos_libvariant/src/src/JSONParser.h @@ -0,0 +1,90 @@ +//============================================================================= +// Computational Process Networks class library +// Copyright (C) 1997-2006 Gregory E. Allen and The University of Texas +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + */ +#ifndef JSON_PARSER_HPP +#define JSON_PARSER_HPP +#pragma once +#include "Base64.h" +#include +#include "JSON_parser.h" +#include +#include +#include +#include +#include +#include +#include + + +namespace libvariant { + /** + * A class that encapsulates the JSON_parser with the Parser interface + */ + class JSONParserImpl : public ParserImpl { + public: + enum Status_t { + S_START, + S_BEGIN, + S_OK, + S_ERROR, + S_END, + S_DONE + }; + JSONParserImpl(shared_ptr i); + virtual ~JSONParserImpl(); + + virtual int Run(); + + /** + * \return the status of the parser. + */ + Status_t GetStatus() const; + virtual bool Done() const; + virtual bool Error() const; + virtual bool Ok() const; + virtual std::string ErrorStr() const; + unsigned GetLine() const; + unsigned GetColumn() const; + unsigned GetByteCount() const; + /** + * Resets the parser to the state it was in when just constructed. + */ + virtual void Reset(); + private: + + void AllocParser(); + + void Parse(); + + static int StaticCallback(void *ctx, int type, const struct JSON_value_struct* value); + + JSON_parser_struct *parser; + Status_t status; + unsigned line; + unsigned column; + unsigned charcount; + unsigned depth; + shared_ptr input; + std::string errorstr; + }; +} +#endif diff --git a/src/hos_libvariant/src/src/MsgPackEmitter.cc b/src/hos_libvariant/src/src/MsgPackEmitter.cc new file mode 100644 index 00000000..6c679af1 --- /dev/null +++ b/src/hos_libvariant/src/src/MsgPackEmitter.cc @@ -0,0 +1,135 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include "../../src/src/MsgPackEmitter.h" + +#include "../../src/src/BlobMagic.h" + +static void msgpack_pack_string(msgpack_packer *packer, const char *str, unsigned len) { + msgpack_pack_raw(packer, len); + msgpack_pack_raw_body(packer, str, len); +} + +namespace libvariant { + + int MsgPackPackerWrite(void* data, const char* buf, unsigned int len) { + return static_cast(data)->Write(buf, len); + } + + MsgPackEmitterImpl::MsgPackEmitterImpl(shared_ptr out, Variant params) + : output(out) + { + msgpack_packer_init(&packer, output.get(), MsgPackPackerWrite); + } + + MsgPackEmitterImpl::~MsgPackEmitterImpl() { + Close(); + } + + + void MsgPackEmitterImpl::BeginDocument() { + } + + void MsgPackEmitterImpl::EndDocument() { + Flush(); + } + + void MsgPackEmitterImpl::BeginMap(int length) { + if (buffer) { buffer->BeginMap(length); } + else if (length < 0) { + buffer.reset(new EventBuffer); + buffer->BeginMap(length); + } else { + msgpack_pack_map(&packer, length); + } + } + + void MsgPackEmitterImpl::EndMap() { + if (buffer) { + buffer->EndMap(); + if (buffer->GetLevel() <= 0) { + shared_ptr buf = buffer; + buffer.reset(); + buf->Playback(this); + } + } + } + + void MsgPackEmitterImpl::BeginList(int length) { + if (buffer) { buffer->BeginList(length); } + else if (length < 0) { + buffer.reset(new EventBuffer); + buffer->BeginList(length); + } else { + msgpack_pack_array(&packer, length); + } + } + + void MsgPackEmitterImpl::EndList() { + if (buffer) { + buffer->EndList(); + if (buffer->GetLevel() <= 0) { + shared_ptr buf = buffer; + buffer.reset(); + buf->Playback(this); + } + } + } + + void MsgPackEmitterImpl::EmitNull() { + if (buffer) { buffer->EmitNull(); } + else { msgpack_pack_nil(&packer); } + } + + void MsgPackEmitterImpl::EmitTrue() { + if (buffer) { buffer->EmitTrue(); } + else { msgpack_pack_true(&packer); } + } + + void MsgPackEmitterImpl::EmitFalse() { + if (buffer) { buffer->EmitFalse(); } + else { msgpack_pack_false(&packer); } + } + + void MsgPackEmitterImpl::Emit(const char *v) { + if (buffer) { buffer->Emit(v); } + else { msgpack_pack_string(&packer, v, strlen(v)); } + } + + void MsgPackEmitterImpl::Emit(intmax_t v) { + if (buffer) { buffer->Emit(v); } + else { msgpack_pack_int64(&packer, v); } + } + + void MsgPackEmitterImpl::Emit(uintmax_t v) { + if (buffer) { buffer->Emit(v); } + else { msgpack_pack_uint64(&packer, v); } + } + + void MsgPackEmitterImpl::Emit(double v) { + if (buffer) { buffer->Emit(v); } + else { msgpack_pack_double(&packer, v); } + } + + void MsgPackEmitterImpl::Emit(ConstBlobPtr b) { + if (buffer) { buffer->Emit(b); } + else { + msgpack_pack_raw(&packer, b->GetTotalLength() + MAGIC_BLOB_LENGTH); + msgpack_pack_raw_body(&packer, MAGIC_BLOB_TAG, MAGIC_BLOB_LENGTH); + for (int i = 0, num = b->GetNumBuffers(); i < num; ++i) { + msgpack_pack_raw_body(&packer, b->GetPtr(i), b->GetLength(i)); + } + } + } + + void MsgPackEmitterImpl::Flush() { + output->Flush(); + } + + void MsgPackEmitterImpl::Close() { + output->Flush(); + } + +} diff --git a/src/hos_libvariant/src/src/MsgPackEmitter.h b/src/hos_libvariant/src/src/MsgPackEmitter.h new file mode 100644 index 00000000..08a80877 --- /dev/null +++ b/src/hos_libvariant/src/src/MsgPackEmitter.h @@ -0,0 +1,51 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_MSGPACK_H +#define VARIANT_MSGPACK_H + +#pragma once +#include "../../src/include/Variant/Variant.h" +#include "../../src/include/Variant/EmitterOutput.h" +#include "../../src/include/Variant/ParserInput.h" +#include "../../src/include/Variant/Parser.h" +#include "../../src/include/Variant/Emitter.h" +#include "../../src/src/EventBuffer.h" +#include +namespace libvariant { + + class MsgPackEmitterImpl : public EmitterImpl { + public: + MsgPackEmitterImpl(shared_ptr out, Variant params); + ~MsgPackEmitterImpl(); + virtual void BeginDocument(); + virtual void EndDocument(); + virtual void BeginMap(int length); + virtual void EndMap(); + virtual void BeginList(int length); + virtual void EndList(); + + virtual void EmitNull(); + virtual void EmitTrue(); + virtual void EmitFalse(); + virtual void Emit(const char *v); + virtual void Emit(intmax_t v); + virtual void Emit(uintmax_t v); + virtual void Emit(double v); + virtual void Emit(ConstBlobPtr b); + + virtual void Flush(); + virtual void Close(); + + virtual Variant GetParam(const std::string &key) { return Variant::NullType; } + virtual Variant GetParams() { return Variant::NullType; } + virtual void SetParam(const std::string &key, Variant value) {} + private: + shared_ptr output; + shared_ptr buffer; + msgpack_packer packer; + }; + +} +#endif diff --git a/src/hos_libvariant/src/src/MsgPackParser.cc b/src/hos_libvariant/src/src/MsgPackParser.cc new file mode 100644 index 00000000..636ceb00 --- /dev/null +++ b/src/hos_libvariant/src/src/MsgPackParser.cc @@ -0,0 +1,250 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include "../../src/src/MsgPackParser.h" + +#include +#include +#include "../../src/src/BlobMagic.h" + +// vmpu = variant msg pack unpack + +struct vmpu_user { + libvariant::MsgPackParserImpl *impl; +}; + +struct vmpu_object { + vmpu_object() : count(0) {} + uint64_t count; +}; + +#define msgpack_unpack_struct(name) \ +struct vmpu ## name + +#define msgpack_unpack_func(ret, name) \ +ret vmpu ## name + +#define msgpack_unpack_callback(name) \ +vmpu_callback ## name + +#define msgpack_unpack_object vmpu_object + +#define msgpack_unpack_user vmpu_user + + +typedef struct vmpu_context vmpu_context; + +static void vmpu_init(vmpu_context* ctx); + +//static vmpu_object vmpu_data(vmpu_context* ctx); + +static int vmpu_execute(vmpu_context* ctx, + const char* data, size_t len, size_t* off); + + +static inline vmpu_object vmpu_callback_root(vmpu_user* u) +{ return vmpu_object(); } + +static inline int vmpu_callback_uint8(vmpu_user* u, uint8_t d, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, uint64_t(d), 0, 0); + return 0; +} + +static inline int vmpu_callback_uint16(vmpu_user* u, uint16_t d, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, uint64_t(d), 0, 0); + return 0; +} + +static inline int vmpu_callback_uint32(vmpu_user* u, uint32_t d, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, uint64_t(d), 0, 0); + return 0; +} + +static inline int vmpu_callback_uint64(vmpu_user* u, uint64_t d, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, uint64_t(d), 0, 0); + return 0; +} + +static inline int vmpu_callback_int8(vmpu_user* u, int8_t d, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, int64_t(d), 0, 0); + return 0; +} + +static inline int vmpu_callback_int16(vmpu_user* u, int16_t d, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, int64_t(d), 0, 0); + return 0; +} + +static inline int vmpu_callback_int32(vmpu_user* u, int32_t d, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, int64_t(d), 0, 0); + return 0; +} + +static inline int vmpu_callback_int64(vmpu_user* u, int64_t d, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, int64_t(d), 0, 0); + return 0; +} + +static inline int vmpu_callback_float(vmpu_user* u, float d, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, double(d), 0, 0); + return 0; +} + +static inline int vmpu_callback_double(vmpu_user* u, double d, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, double(d), 0, 0); + return 0; +} + +static inline int vmpu_callback_nil(vmpu_user* u, vmpu_object* o) +{ + u->impl->TopAction()->Null(u->impl, 0, 0); + return 0; +} + +static inline int vmpu_callback_true(vmpu_user* u, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, true, 0, 0); + return 0; +} + +static inline int vmpu_callback_false(vmpu_user* u, vmpu_object* o) +{ + u->impl->TopAction()->Scalar(u->impl, false, 0, 0); + return 0; +} + +static inline int vmpu_callback_array(vmpu_user* u, unsigned int n, vmpu_object* o) +{ + u->impl->TopAction()->BeginList(u->impl, n, 0, 0); + o->count = n; + if (n == 0) { + u->impl->TopAction()->EndList(u->impl); + } + return 0; +} + +static inline int vmpu_callback_array_item(vmpu_user* u, vmpu_object* c, vmpu_object o) +{ + c->count--; + if (c->count == 0) { + u->impl->TopAction()->EndList(u->impl); + } + return 0; +} + +static inline int vmpu_callback_map(vmpu_user* u, unsigned int n, vmpu_object* o) +{ + u->impl->TopAction()->BeginMap(u->impl, n, 0, 0); + o->count = n; + if (n == 0) { + u->impl->TopAction()->EndMap(u->impl); + } + return 0; +} + +static inline int vmpu_callback_map_item(vmpu_user* u, vmpu_object* c, + vmpu_object k, vmpu_object v) +{ + c->count--; + if (c->count == 0) { + u->impl->TopAction()->EndMap(u->impl); + } + return 0; +} + +static inline int vmpu_callback_raw(vmpu_user* u, const char* b, const char* p, + unsigned int l, vmpu_object* o) +{ + if (l >= MAGIC_BLOB_LENGTH && memcmp(MAGIC_BLOB_TAG, p, MAGIC_BLOB_LENGTH) == 0) { + u->impl->TopAction()->Scalar(u->impl, + libvariant::Blob::CreateCopy(p + MAGIC_BLOB_LENGTH, l - MAGIC_BLOB_LENGTH), 0, 0); + } else { + u->impl->TopAction()->Scalar(u->impl, p, l, 0, 0); + } + return 0; +} + +#include + +namespace libvariant { + + MsgPackParserImpl::MsgPackParserImpl(shared_ptr in) + : state(START), input(in), + ctx(new vmpu_context), + bytecount(0) + { + vmpu_init(ctx.get()); + ctx->user.impl = this; + } + + MsgPackParserImpl::~MsgPackParserImpl() + {} + + int MsgPackParserImpl::Run() { + while (!action_stack.empty()) { + unsigned len = 0; + const char *ptr = 0; + size_t off = 0; + int ret = 0; + switch (state) { + case START: + TopAction()->BeginDocument(this); + state = OK; + break; + case OK: + while (state == OK) { + if (off > 0) { len = 0; } + else { len += 1; } + ptr = (const char *)input->GetPtr(len); + if (!ptr || len == 0) { + throw std::runtime_error("unexpected end of data"); + } + off = 0; + ret = vmpu_execute(ctx.get(), ptr, len, &off); + if (ret < 0) { + std::ostringstream oss; + oss << "MsgPack: A parse error occured at byte offset " + << off + bytecount; + errorstr = oss.str(); + state = ERROR; + throw std::runtime_error(errorstr); + } else { + bytecount += off; + input->Release(off); + if (ret > 0) { + state = END; + } + } + } + break; + case END: + TopAction()->EndDocument(this); + state = DONE; + break; + case DONE: + return 1; + case ERROR: + throw std::runtime_error(errorstr); + } + } + return 0; + } + + void MsgPackParserImpl::Reset() { + state = START; + vmpu_init(ctx.get()); + ctx->user.impl = this; + } +} diff --git a/src/hos_libvariant/src/src/MsgPackParser.h b/src/hos_libvariant/src/src/MsgPackParser.h new file mode 100644 index 00000000..6ac54e3c --- /dev/null +++ b/src/hos_libvariant/src/src/MsgPackParser.h @@ -0,0 +1,49 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#ifndef VARIANT_MSGPACKPARSER_H +#define VARIANT_MSGPACKPARSER_H + +#pragma once +#include "../../src/include/Variant/ParserInput.h" +#include "../../src/include/Variant/Parser.h" +#include + +struct vmpu_context; + +namespace libvariant { + + class MsgPackParserImpl : public ParserImpl { + public: + enum State_t { + START, + OK, + END, + DONE, + ERROR + }; + + MsgPackParserImpl(shared_ptr in); + virtual ~MsgPackParserImpl(); + + virtual int Run(); + + virtual bool Done() const { return state == DONE; } + virtual bool Error() const { return state == ERROR; } + virtual bool Ok() const { return state == OK; } + /// Return a string describing the last error suitable for presentation to a user + virtual std::string ErrorStr() const { return errorstr; } + /// Reset the parser + virtual void Reset(); + private: + State_t state; + shared_ptr input; + shared_ptr ctx; + std::string errorstr; + unsigned bytecount; + }; +} + +#endif diff --git a/src/hos_libvariant/src/src/ParseBool.cc b/src/hos_libvariant/src/src/ParseBool.cc new file mode 100644 index 00000000..c57fdfcb --- /dev/null +++ b/src/hos_libvariant/src/src/ParseBool.cc @@ -0,0 +1,55 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + */ +#include "../../src/src/ParseBool.h" + +#include + + +bool ParseBool(const std::string &str) { + static const char NO_STR[] = "no"; + static const char FALSE_STR[] = "false"; + bool result = true; + std::string::const_iterator cur = str.begin(); + const std::string::const_iterator end = str.end(); + while (cur != end && isspace(*cur)) { ++cur; } + if (cur == end) return result; + const char *cmpstr = 0; + if (tolower(*cur) == NO_STR[0]) { + cmpstr = &NO_STR[1]; + } else if (tolower(*cur) == FALSE_STR[0]) { + cmpstr = &FALSE_STR[1]; + } else if (*cur == '0') { + ++cur; + while (cur != end && *cur == '0') { ++cur; } + while (cur != end && isspace(*cur)) { ++cur; } + if (cur == end) { result = false; } + return result; + } + if (cmpstr != 0) { + ++cur; + int i = 0; + while (cur != end && cmpstr[i] != '\0' && tolower(*cur) == cmpstr[i]) { + ++cur; ++i; + } + while (cur != end && isspace(*cur)) { ++cur; } + if (cur == end) { result = false; } + } + return result; +} diff --git a/src/hos_libvariant/src/src/ParseBool.h b/src/hos_libvariant/src/src/ParseBool.h new file mode 100644 index 00000000..f6773f8e --- /dev/null +++ b/src/hos_libvariant/src/src/ParseBool.h @@ -0,0 +1,37 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + */ +#ifndef PARSEBOOL_H +#define PARSEBOOL_H +#pragma once +#include +/** + * \brief Parses string for a boolean value. + * + * Considers no, false, 0 and any abreviation + * like " f" to be false + * and everything else to be true (including + * the empty string). + * Ignores whitespace. + * Note "false blah" is true! + * \return true or false + * \param str the string to parse + */ +bool ParseBool(const std::string &str); +#endif diff --git a/src/hos_libvariant/src/src/Parser.cc b/src/hos_libvariant/src/src/Parser.cc new file mode 100644 index 00000000..a0cdb393 --- /dev/null +++ b/src/hos_libvariant/src/src/Parser.cc @@ -0,0 +1,127 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ + +#include "../../src/include/Variant/Parser.h" + +#include + +#include "../../src/include/Variant/ParserInput.h" +#include "../../src/src/JSONParser.h" +#ifdef ENABLE_YAML +#include "../../src/src/YAMLParser.h" +#endif +#ifdef ENABLE_XML +#include "../../src/src/XMLPLISTParser.h" +#endif +#ifdef ENABLE_MSGPACK +#include "../../src/src/MsgPackParser.h" +#endif +#include "../../src/src/BundleHdrParser.h" +#include "../../src/include/Variant/GuessFormat.h" +namespace libvariant { + + ParserActions::~ParserActions() {} + + ParserImpl::~ParserImpl() {} + + void ParserImpl::Reset() { + throw std::runtime_error("Parser does not support reset."); + } + + Parser::Parser() {} + Parser::Parser(shared_ptr pi) : impl(pi) {} + Parser::~Parser() {} + + shared_ptr CreateParserInput(const std::string &str) { + return CreateParserInput(str.c_str(), str.length()); + } + + shared_ptr CreateParserInput(const char *str) { + return shared_ptr(new ParserMemoryInput(str, strlen(str))); + } + shared_ptr CreateParserInput(const void *ptr, unsigned len) { + return shared_ptr(new ParserMemoryInput(ptr, len)); + } + shared_ptr CreateParserInputFile(const char *filename) { + return shared_ptr(new ParserFilenameInput(filename)); + } + + shared_ptr CreateParserInputFile(FILE *f) { + return shared_ptr(new ParserFileInput(f)); + } + + shared_ptr CreateParserInputFile(std::streambuf *sb) { + return shared_ptr(new ParserStreambufInput(sb)); + } + + Parser CreateParser(shared_ptr i, SerializeType type) { + switch (type) { + case SERIALIZE_XMLPLIST: + return XMLPLISTParser(i); + case SERIALIZE_JSON: + return JSONParser(i); + case SERIALIZE_BUNDLEHDR: + return BundleHdrParser(i); + case SERIALIZE_GUESS: + return CreateParserGuess(i); + case SERIALIZE_MSGPACK: + return MsgPackParser(i); + case SERIALIZE_YAML: + default: + return YAMLParser(i); + } + } + + Parser CreateParserGuess(shared_ptr i) { + SerializeType type = GuessFormat(i.get()); + return CreateParser(i, type); + } + + Parser JSONParser(shared_ptr i) { + return Parser(shared_ptr(new JSONParserImpl(i))); + } + Parser YAMLParser(shared_ptr i) { +#ifdef ENABLE_YAML + return Parser(shared_ptr(new YAMLParserImpl(i))); +#else + throw std::runtime_error("libvariant not compiled with YAML support."); +#endif + } + Parser XMLPLISTParser(shared_ptr i) { +#ifdef ENABLE_XML + return Parser(shared_ptr(new XMLPLISTParserImpl(i))); +#else + throw std::runtime_error("libvariant not compiled with plist xml support."); +#endif + } + + Parser BundleHdrParser(shared_ptr i) { + return Parser(shared_ptr(new BundleHdrParserImpl(i))); + } + + Parser MsgPackParser(shared_ptr i) { +#ifdef ENABLE_MSGPACK + return Parser(shared_ptr(new MsgPackParserImpl(i))); +#else + throw std::runtime_error("libvariant not compiled with msgpack support."); +#endif + } +} diff --git a/src/hos_libvariant/src/src/ParserInput.cc b/src/hos_libvariant/src/src/ParserInput.cc new file mode 100644 index 00000000..ff8329ca --- /dev/null +++ b/src/hos_libvariant/src/src/ParserInput.cc @@ -0,0 +1,164 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ + +#include "../../src/include/Variant/ParserInput.h" + +#include +#include +#include +#include +#include + +namespace libvariant { + + //---------------------------------------------------------------------- + // ParserInput + + ParserInput::~ParserInput() {} + + //---------------------------------------------------------------------- + // ParserStreamInput + + ParserStreamInput::ParserStreamInput(unsigned buffer_len) + : buffer(buffer_len), + num(0), + offset(0), + eof(false) + { + + } + + const void *ParserStreamInput::GetPtr(unsigned &len) { + if (eof) { + len = num; + if (num == 0) { return 0; } + return &buffer[offset]; + } + if (len <= num && num > 0) { + len = num; + return &buffer[offset]; + } + if (len + offset > buffer.size()) { + if (len > buffer.size()) { + std::vector newbuffer(len); + memmove(&newbuffer[0], &buffer[offset], num); + std::swap(newbuffer, buffer); + } else { + memmove(&buffer[0], &buffer[offset], num); + } + offset = 0; + } + while (!eof && (num < len || num == 0)) { + unsigned to_read = buffer.size() - num - offset; + unsigned num_read = Read(&buffer[num + offset], to_read); + if (num_read < to_read) { eof = true; } + num += num_read; + } + len = num; + if (num == 0 && eof) { return 0; } + return &buffer[offset]; + } + + void ParserStreamInput::Release(unsigned len) { + if (len > num) { + throw std::runtime_error("ParserStreamInput: trying to release more than was aquired."); + } else if (len == num) { + num = 0; + offset = 0; + } else { + offset += len; + num -= len; + } + } + + //---------------------------------------------------------------------- + // ParserMemoryInput + + ParserMemoryInput::ParserMemoryInput(const void *ptr, unsigned len) + : data_ptr(ptr), data_len(len), offset(0) {} + + const void *ParserMemoryInput::GetPtr(unsigned &len) { + if (offset > data_len) { + throw std::length_error("Parser input buffer underflow."); + } + len = data_len - offset; + if (len > 0) { + return (const void*)((char*)data_ptr + offset); + } else { + return 0; + } + } + + void ParserMemoryInput::Release(unsigned len) { + offset += len; + } + + //---------------------------------------------------------------------- + // ParserFileInput + + ParserFileInput::ParserFileInput(FILE *f) + : ParserStreamInput(8192), file(f) + { + } + + unsigned ParserFileInput::Read(void *ptr, unsigned len) { + unsigned num_read = fread(ptr, 1, len, file); + int error = errno; + if (num_read) return num_read; + if (ferror(file)) { + std::ostringstream oss; + oss << "Error reading from file: "; + oss << strerror(error); + throw std::runtime_error(oss.str()); + } + return 0; + } + + //---------------------------------------------------------------------- + // ParserFilenameInput + + ParserFilenameInput::ParserFilenameInput(const char *filename, const char *mode) + : ParserFileInput(fopen(filename, mode)) + { + if (!file) { + std::ostringstream oss; + oss << "Unable to open " << filename; + throw std::runtime_error(oss.str()); + } + } + + ParserFilenameInput::~ParserFilenameInput() { + fclose(file); + } + + //---------------------------------------------------------------------- + // ParserStreambufInput + + ParserStreambufInput::ParserStreambufInput(std::streambuf *sb) + : ParserStreamInput(8192), streambuf(sb) + { + } + + unsigned ParserStreambufInput::Read(void *ptr, unsigned len) { + return streambuf->sgetn((char*)ptr, len); + } +} + diff --git a/src/hos_libvariant/src/src/Path.cc b/src/hos_libvariant/src/src/Path.cc new file mode 100644 index 00000000..715fe8be --- /dev/null +++ b/src/hos_libvariant/src/src/Path.cc @@ -0,0 +1,117 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "../../src/include/Variant/Path.h" + +#include + +namespace libvariant { + + void ParsePath(Path &parsed_path, const std::string &path) { + const char *c = path.c_str(); + const char *e = c + path.length(); + std::string frag; + bool escape = false; + bool index = false; + bool key = false; + while (c != e) { + if (escape) { + frag.append(c, 1); + escape = false; + } else if (index) { + if (*c == ']') { + std::istringstream iss(frag); + unsigned long long i = 0; + if (!(iss >> i)) { + throw std::runtime_error("Error parsing Variant path: \"" + frag + "\" is not a number."); + } + parsed_path.push_back(i); + frag.clear(); + index = false; + } else { + frag.append(c, 1); + } + } else if (key) { + switch (*c) { + case '/': + parsed_path.push_back(frag); + frag.clear(); + break; + case '[': + parsed_path.push_back(frag); + frag.clear(); + key = false; + index = true; + break; + case '\\': + escape = true; + break; + default: + frag.append(c, 1); + break; + } + } else { + switch (*c) { + case '/': + frag.clear(); + key = true; + break; + case '[': + frag.clear(); + index = true; + break; + default: + frag.clear(); + key = true; + frag.append(c, 1); + break; + } + } + ++c; + } + if (!frag.empty()) { parsed_path.push_back(frag); } + } + + Path ParsePath(const std::string &path) { + Path parsed_path; + ParsePath(parsed_path, path); + return parsed_path; + } + + std::string PathString(const Path &path) { + if (path.empty()) { return "/"; } + std::ostringstream oss; + for (Path::const_iterator i(path.begin()), e(path.end()); i != e; ++i) { + if (i->IsString()) { + std::string fragment = i->AsString(); + oss << "/"; + for (unsigned i = 0; i < fragment.size(); ++i) { + switch (fragment[i]) { + case '/': + oss << "\\/"; + break; + case '[': + oss << "\\["; + break; + case ']': + oss << "\\]"; + break; + case '\\': + oss << "\\\\"; + break; + default: + oss << fragment[i]; + break; + } + } + } else if (i->IsNumber()) { + oss << "[" << i->AsUnsigned() << "]"; + } else { + throw BadPathError("Unknown path element type"); + } + } + return oss.str(); + } + +} diff --git a/src/hos_libvariant/src/src/Payload.cc b/src/hos_libvariant/src/src/Payload.cc new file mode 100644 index 00000000..8ed64df4 --- /dev/null +++ b/src/hos_libvariant/src/src/Payload.cc @@ -0,0 +1,347 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "../../src/include/Variant/Payload.h" + +#include +#include +#include +#include "../../src/include/Variant/Path.h" + +#define PADDING_MOD 32 + +namespace libvariant { + + struct PayloadEmitState { + Emitter e; + Path::iterator len_end; + Path::iterator data_end; + uintmax_t payload_len; + }; + + void PayloadEmit( + const Variant &v, + Path::iterator len_i, + bool on_len_path, + Path::iterator data_i, + bool on_data_path, + PayloadEmitState &state) + { + if (on_len_path && len_i == state.len_end) { + state.e.Emit(state.payload_len); + return; + } + if (on_data_path && data_i == state.data_end) { + state.e.EmitNull(); + return; + } + + bool output_len = false; + unsigned index = 0; + unsigned length = 0; + + switch (v.GetType()) { + case Variant::NullType: + state.e.EmitNull(); + break; + case Variant::BoolType: + if (v.AsBool()) { + state.e.EmitTrue(); + } else { + state.e.EmitFalse(); + } + break; + case Variant::IntegerType: + state.e.Emit(v.AsInt()); + break; + case Variant::UnsignedType: + state.e.Emit(v.AsUnsigned()); + break; + case Variant::FloatType: + state.e.Emit(v.AsDouble()); + break; + case Variant::StringType: + state.e.Emit(v.AsString()); + break; + case Variant::ListType: + length = v.Size(); + if (on_len_path && length <= len_i->AsUnsigned()) { length = len_i->AsUnsigned() + 1; } + state.e.BeginList(length); + for (Variant::ConstListIterator i(v.ListBegin()), e(v.ListEnd()); i != e; ++i, ++index) { + bool on_len = on_len_path && index == len_i->AsUnsigned(); + bool on_data = on_data_path && index == data_i->AsUnsigned(); + PayloadEmit(*i, + (on_len ? len_i + 1 : len_i), on_len, + (on_data ? data_i + 1 : data_i), on_data, + state); + } + if (on_len_path && len_i->AsUnsigned() < index) { + while (len_i->AsUnsigned() < index) { + state.e.EmitNull(); + ++index; + } + if (len_i+1 != state.len_end) { + Variant tmp; + Path newpath(len_i+1, state.len_end); + tmp.SetPath(newpath, state.payload_len); + state.e << tmp; + } else { + state.e.Emit(state.payload_len); + } + } + state.e.EndList(); + break; + case Variant::MapType: + length = v.Size(); + if (on_len_path && !v.Contains(len_i->AsString())) { length++; } + if (on_data_path && v.Contains(data_i->AsString())) { length--; } + state.e.BeginMap(length); + for (Variant::ConstMapIterator i(v.MapBegin()), e(v.MapEnd()); i != e; ++i) { + bool on_len = on_len_path && i->first == len_i->AsString(); + if (on_len) { output_len = true; } + bool on_data = on_data_path && i->first == data_i->AsString(); + if ( !(on_data && data_i + 1 == state.data_end) ) { + state.e.Emit(i->first); + PayloadEmit(i->second, + (on_len ? len_i + 1 : len_i), on_len, + (on_data ? data_i + 1 : data_i), on_data, + state); + } + } + if (on_len_path && !output_len) { + state.e.Emit(len_i->AsString()); + if (len_i+1 != state.len_end) { + Variant tmp; + Path newpath(len_i+1, state.len_end); + tmp.SetPath(newpath, state.payload_len); + state.e << tmp; + } else { + state.e.Emit(state.payload_len); + } + } + state.e.EndMap(); + break; + case Variant::BlobType: + state.e << v.AsBlob(); + break; + default: + throw UnknownTypeError(v.GetType()); + } + } + + void SerializeWithPayload(shared_ptr out, Variant v, SerializeType type, Variant params) + { + if (!v.IsMap()) { + throw std::runtime_error("libvariant: Serializing with payload requires root element to be a map."); + } + + Path dpath; + Path lpath; + if (type == SERIALIZE_BUNDLEHDR) { + ParsePath(dpath, params.Get("data_path", VARIANT_BUNDLE_PAYLOAD_DATA_PATH).AsString()); + ParsePath(lpath, params.Get("length_path", VARIANT_BUNDLE_PAYLOAD_LENGTH_PATH).AsString()); + } else { + ParsePath(dpath, params.Get("data_path", VARIANT_PAYLOAD_DATA_PATH).AsString()); + ParsePath(lpath, params.Get("length_path", VARIANT_PAYLOAD_LENGTH_PATH).AsString()); + } + bool ignore_payload = params.Get("ignore_payload", false).AsBool(); + uintmax_t payload_length = 0; + + bool payload_exists = v.HasPath(dpath); + BlobPtr blob; + if (payload_exists) { + blob = v.GetPath(dpath).AsBlob(); + payload_length = blob->GetTotalLength(); + } else if (ignore_payload) { + payload_length = v.GetPath(lpath, 0).AsUnsigned(); + } + payload_length = params.Get("payload_length", payload_length).AsUnsigned(); + + + Emitter emitter = CreateEmitter(out, type, params); + PayloadEmitState state; + state.e = emitter; + state.len_end = lpath.end(); + state.data_end = dpath.end(); + state.payload_len = payload_length; + + emitter.BeginDocument(); + PayloadEmit(v, lpath.begin(), true, dpath.begin(), true, state); + emitter.EndDocument(); + emitter.Flush(); + + // plus 1 because we want a payload to be aligned when adding 1 null byte + unsigned num = PADDING_MOD - (out->NumBytesWritten() + 1) % PADDING_MOD; + std::vector buf(num, '\n'); + buf.push_back('\0'); + unsigned written = 0; + while (written < num) { + written += out->Write(&buf[written], buf.size() - written); + } + + if (payload_exists && !ignore_payload) { + unsigned num_slabs = blob->GetNumBuffers(); + for (unsigned slab = 0; slab < num_slabs; ++slab) { + unsigned to_write = blob->GetLength(slab); + char *ptr = (char*)blob->GetPtr(slab); + while (to_write > 0) { + unsigned num = out->Write(ptr, to_write); + ptr += num; + to_write -= num; + } + } + out->Flush(); + } + } + + class ProxyInput : public ParserInput { + public: + ProxyInput(shared_ptr i); + virtual ~ProxyInput(); + virtual const void *GetPtr(unsigned &len); + virtual void Release(unsigned len); + private: + shared_ptr base_input; + unsigned scanned_to; + }; + + ProxyInput::ProxyInput(shared_ptr i) + : base_input(i), scanned_to(0) + {} + + ProxyInput::~ProxyInput() {} + + const void *ProxyInput::GetPtr(unsigned &len) { + const void *retptr = base_input->GetPtr(len); + if (retptr) { + const char *ptr = (const char*)retptr; + if (ptr[scanned_to] != '\0') { + scanned_to += strnlen(&ptr[scanned_to], len-scanned_to); + + } + len = std::min(len, scanned_to); + } + return retptr; + } + + void ProxyInput::Release(unsigned len) { + scanned_to -= len; + base_input->Release(len); + } + + Variant DeserializeWithPayload(shared_ptr in, SerializeType type, Variant params, bool be_safe) + { + Path dpath; + Path lpath; + if (type == SERIALIZE_BUNDLEHDR) { + ParsePath(dpath, params.Get("data_path", VARIANT_BUNDLE_PAYLOAD_DATA_PATH).AsString()); + ParsePath(lpath, params.Get("length_path", VARIANT_BUNDLE_PAYLOAD_LENGTH_PATH).AsString()); + } else { + ParsePath(dpath, params.Get("data_path", VARIANT_PAYLOAD_DATA_PATH).AsString()); + ParsePath(lpath, params.Get("length_path", VARIANT_PAYLOAD_LENGTH_PATH).AsString()); + } + + shared_ptr input(new ProxyInput(in)); + Parser parser = CreateParser(input, type); + Variant ret = ParseVariant(parser); + + // Read any remaining bytes up to and including a terminating null if present. + bool loop = true; + while (loop) { + unsigned len = 1; + const char *ptr = (const char *)in->GetPtr(len); + if (len > 0) { + unsigned i; + for (i = 0; i < len && loop; ++i) { + if (ptr[i] == '\0') { + loop = false; + } + } + in->Release(i); + } else { loop = false; } + } + + uintmax_t payload_length = ret.GetPath(lpath, 0u).AsUnsigned(); + + if (payload_length > 0) { + // Note: make a copy when be_safe is true, otherwise just + // reference the buffer that the input returns. This is only + // a valid thing to do when the input is a memory buffer input + unsigned len = payload_length; + const void *ptr = in->GetPtr(len); + if (len < payload_length) { + throw std::runtime_error("libvariant: Error parsing payload, " + "unexpected EOF encountered when reading payload"); + } + BlobPtr payload; + if (be_safe) { + payload = Blob::CreateCopy(ptr, payload_length); + } else { + payload = Blob::CreateReferenced((void*)ptr, payload_length); + } + in->Release(payload_length); + ret.SetPath(dpath, payload); + } + return ret; + } + + std::string SerializeWithPayload(Variant v, SerializeType type, Variant params) { + std::ostringstream oss; + SerializeWithPayload(oss.rdbuf(), v, type, params); + return oss.str(); + } + + void SerializeWithPayload(const std::string &filename, Variant v, SerializeType type, + Variant params) { + shared_ptr o = CreateEmitterOutput(filename.c_str()); + SerializeWithPayload(o, v, type, params); + } + + void SerializeWithPayload(FILE *f, Variant v, SerializeType type, + Variant params) { + shared_ptr o = CreateEmitterOutput(f); + SerializeWithPayload(o, v, type, params); + } + + void SerializeWithPayload(std::streambuf *sb, Variant v, SerializeType type, + Variant params) { + shared_ptr o = CreateEmitterOutput(sb); + SerializeWithPayload(o, v, type, params); + } + + unsigned SerializeWithPayload(void *ptr, unsigned len, Variant v, SerializeType type, + Variant params) { + unsigned out_len = 0; + shared_ptr o = CreateEmitterOutput(ptr, len, &out_len); + SerializeWithPayload(o, v, type, params); + return out_len; + } + + Variant DeserializeWithPayload(const std::string &str, SerializeType type, Variant params) { + return DeserializeWithPayload(str.c_str(), str.length(), type, params); + } + + Variant DeserializeWithPayload(const void *ptr, unsigned len, SerializeType type, + Variant params, bool be_safe) + { + shared_ptr i = CreateParserInput(ptr, len); + return DeserializeWithPayload(i, type, params, be_safe); + } + + Variant DeserializeWithPayloadFile(const char *filename, SerializeType type, Variant params) { + shared_ptr i = CreateParserInputFile(filename); + return DeserializeWithPayload(i, type, params); + } + + Variant DeserializeWithPayloadFile(FILE *f, SerializeType type, Variant params) { + shared_ptr i = CreateParserInputFile(f); + return DeserializeWithPayload(i, type, params); + } + + Variant DeserializeWithPayloadFile(std::streambuf *sb, SerializeType type, Variant params) { + shared_ptr i = CreateParserInputFile(sb); + return DeserializeWithPayload(i, type, params); + } + +} diff --git a/src/hos_libvariant/src/src/Schema.cc b/src/hos_libvariant/src/src/Schema.cc new file mode 100644 index 00000000..8ff405cb --- /dev/null +++ b/src/hos_libvariant/src/src/Schema.cc @@ -0,0 +1,995 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + * + * This code is based on the public domain JSONv4 validator tv4. + * tv4 is available at http://geraintluff.github.com/tv4/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FLOAT_TOLERANCE 100*std::numeric_limits::epsilon() +#define RECURSION_LIMIT 100 + +namespace libvariant { + + struct StopValidation : public std::exception { + virtual const char *what() const throw() { return "stop validation"; } + }; + + struct SchemaContext { + SchemaContext(const SchemaContext &o) + : data_path(o.data_path), + schema_path(o.schema_path), + depth(o.depth), + loader(o.loader) + {} + + SchemaContext(SchemaLoader *l) + : depth(0), + loader(l) + {} + + void AddError(const std::string &m) { AddError(ValidationError(m, data_path, schema_path)); } + void AddError(const std::string &m, const SchemaContext &o) { + ValidationError err(m, data_path, schema_path); + err.AddSubError(o.result); + AddError(err); + } + + void AddError(const ValidationError &err) { + result.AddError(err); + throw StopValidation(); + } + + void AddSchemaError(const std::string &m) { AddSchemaError(SchemaError(m, schema_path)); } + void AddSchemaError(const SchemaError &err) { result.AddSchemaError(err); } + + void IncrDepth() { + depth += 1; + if (depth > RECURSION_LIMIT) { + std::ostringstream oss; + oss << "SchemaValidate reached recursion limit."; + AddSchemaError(oss.str()); + throw StopValidation(); + } + } + + void DecrDepth() { + depth -= 1; + } + + Path data_path; + Path schema_path; + unsigned depth; + SchemaResult result; + SchemaLoader *loader; + }; + + struct AutoDataPath { + AutoDataPath(SchemaContext &c, const PathElement &p) : ctx(c) { ctx.data_path.push_back(p); } + ~AutoDataPath() { ctx.data_path.pop_back(); } + SchemaContext &ctx; + }; + + struct AutoSchemaPath { + AutoSchemaPath(SchemaContext &c, const PathElement &p) : ctx(c) { ctx.schema_path.push_back(p); } + ~AutoSchemaPath() { ctx.schema_path.pop_back(); } + SchemaContext &ctx; + }; + + struct AutoDepth { + AutoDepth(SchemaContext &c) : ctx(c) { ctx.IncrDepth(); } + ~AutoDepth() { ctx.DecrDepth(); } + SchemaContext &ctx; + }; + + void SchemaValidate(SchemaContext &ctx, Variant schema, Variant data); + + void ValidateNot(SchemaContext &ctx, Variant schema, Variant data) { + if (!schema.Contains("not")) { return; } + AutoSchemaPath spath(ctx, "not"); + SchemaContext notctx(ctx); + try { + SchemaValidate(notctx, schema["not"], data); + } catch (const StopValidation &) { + return; + } + if (notctx.result.Error()) { return; } + ctx.AddError("Data matches schema from \"not\""); + } + + void ValidateOneOf(SchemaContext &ctx, Variant schema, Variant data) { + if (!schema.Contains("oneOf")) { return; } + AutoSchemaPath spath(ctx, "oneOf"); + if (!schema["oneOf"].IsList()) { + ctx.AddSchemaError("\"oneOf\" must be a list of schemas"); + return; + } + ValidationError error("Data does not match any schemas from \"oneOf\"", + ctx.data_path, ctx.schema_path); + unsigned num_validates = 0; + unsigned index = 0; + unsigned validIndex = 0; + for (Variant::ListIterator i(schema["oneOf"].ListBegin()), e(schema["oneOf"].ListEnd()); + i != e; ++i, ++index) + { + SchemaContext subctx(ctx); + try { + AutoSchemaPath spath(subctx, index); + SchemaValidate(subctx, *i, data); + if (!subctx.result.Error()) { num_validates++; } + } catch (const StopValidation &) {} + if (subctx.result.Error()) { error.AddSubError(subctx.result); } + if (num_validates == 1) { + validIndex = index; + } else if (num_validates > 1) { + std::ostringstream oss; + oss << "Data is valid against more than one schema from \"oneOf\": indeces " + << validIndex << " and " << index; + ctx.AddError(oss.str()); + } + } + if (num_validates == 0) { + ctx.AddError(error); + } + } + + void ValidateAnyOf(SchemaContext &ctx, Variant schema, Variant data) { + if (!schema.Contains("anyOf")) { return; } + AutoSchemaPath spath(ctx, "anyOf"); + if (!schema["anyOf"].IsList()) { + ctx.AddSchemaError("\"anyOf\" must be a list of schemas"); + return; + } + ValidationError error("Data does not match any schema from \"anyOf\"", + ctx.data_path, ctx.schema_path); + unsigned index = 0; + for (Variant::ListIterator i(schema["anyOf"].ListBegin()), e(schema["anyOf"].ListEnd()); + i != e; ++i, ++index) + { + SchemaContext subctx(ctx); + try { + AutoSchemaPath spath(subctx, index); + SchemaValidate(subctx, *i, data); + if (!subctx.result.Error()) { return; } + } catch (const StopValidation &) {} + error.AddSubError(subctx.result); + } + ctx.AddError(error); + } + + void ValidateAllOf(SchemaContext &ctx, Variant schema, Variant data) { + if (!schema.Contains("allOf")) { return; } + AutoSchemaPath spath(ctx, "allOf"); + if (!schema["allOf"].IsList()) { + ctx.AddSchemaError("\"allOf\" must be a list of schemas"); + return; + } + unsigned index = 0; + for (Variant::ListIterator i(schema["allOf"].ListBegin()), e(schema["allOf"].ListEnd()); + i != e; ++i, ++index) + { + AutoSchemaPath spath(ctx, index); + SchemaValidate(ctx, *i, data); + } + } + + void ValidateCombinations(SchemaContext &ctx, Variant schema, Variant data) { + ValidateAllOf(ctx, schema, data); + ValidateAnyOf(ctx, schema, data); + ValidateOneOf(ctx, schema, data); + ValidateNot(ctx, schema, data); + } + + void ValidateObjectDependenciesHelper(SchemaContext &ctx, const std::string &dep, Variant data) { + if (!data.Contains(dep)) { + std::ostringstream oss; + oss << "Dependency failed - key must exist: " << dep; + ctx.AddError(oss.str()); + } + } + + void ValidateObjectDependencies(SchemaContext &ctx, Variant schema, Variant data) { + if (schema.Contains("dependencies")) { + Variant deps = schema["dependencies"]; + AutoSchemaPath spath(ctx, "dependencies"); + if (!deps.IsMap()) { + ctx.AddSchemaError("Schema key \"dependencies\" must be an object."); + return; + } + for (Variant::MapIterator i(deps.MapBegin()), e(deps.MapEnd()); i != e; ++i) { + if (data.Contains(i->first)) { + AutoSchemaPath spath(ctx, i->first); + if (i->second.IsString()) { + ValidateObjectDependenciesHelper(ctx, i->second.AsString(), data); + } else if (i->second.IsList()) { + for (unsigned j = 0; j < i->second.Size(); ++j) { + AutoSchemaPath spath(ctx, j); + ValidateObjectDependenciesHelper(ctx, i->second[j].AsString(), data); + } + } else if (i->second.IsMap()) { + SchemaValidate(ctx, i->second, data); + } else { + ctx.AddSchemaError("Values for dependencies must be either a key, a list of" + " keys, or a schema."); + } + } + } + } + } + + // Helper class for ValidateObjectProperties + class PatternProperty { + public: + PatternProperty(const std::string &patternkey, Variant schm) + : key(patternkey), schema(schm) + { + memset(&pattern, 0, sizeof(regex_t)); + int err; + if ((err = regcomp(&pattern, key.c_str(), REG_EXTENDED | REG_NOSUB))) { + std::vector buffer(8192); + regerror(err, &pattern, &buffer[0], buffer.size()); + std::ostringstream oss; + oss << "Failed to compile patternProperty regex \"" << key << "\" with error: " + << &buffer[0]; + throw std::runtime_error(oss.str()); + } + } + ~PatternProperty() { + regfree(&pattern); + } + bool Test(const std::string &k) { + return regexec(&pattern, k.c_str(), 0, 0, 0) == 0; + } + Variant GetSchema() { return schema; } + std::string GetKey() { return key; } + private: + // Can't tell if it is safe to copy regex_t structures... + PatternProperty(const PatternProperty &); + std::string key; + regex_t pattern; + Variant schema; + }; + + void ValidateObjectProperties(SchemaContext &ctx, Variant schema, Variant data) { + // Precompile because we always match against all of them for every key + std::vector< shared_ptr > patternProperties; + if (schema.Contains("patternProperties")) { + AutoSchemaPath spath(ctx, "patternProperties"); + if (schema["patternProperties"].IsMap()) { + for (Variant::MapIterator i(schema["patternProperties"].MapBegin()), + e(schema["patternProperties"].MapEnd()); i != e; ++i) + { + try { + patternProperties.push_back( + shared_ptr( + new PatternProperty(i->first, i->second) + ) + ); + } catch (const std::runtime_error &e) { + AutoSchemaPath spath(ctx, i->first); + ctx.AddSchemaError(e.what()); + } + } + } else { + ctx.AddSchemaError("\"patternProperties\" must be an object"); + } + } + Variant properties = schema.Get("properties", Variant::MapType); + if (!properties.IsMap()) { + ctx.AddSchemaError("\"properties\" must be an object"); + properties = Variant::MapType; + } + for (Variant::MapIterator i(data.MapBegin()), e(data.MapEnd()); + i != e; ++i) + { + bool matchFound = false; + AutoDataPath dpath(ctx, i->first); + // Validate against property declarations + if (properties.Contains(i->first)) { + AutoSchemaPath spath(ctx, "properties"); + AutoSchemaPath spath2(ctx, i->first); + matchFound = true; + SchemaValidate(ctx, properties[i->first], i->second); + } + // Validate against all matching patternProperties declarations + for (unsigned j = 0; j < patternProperties.size(); ++j) { + if (patternProperties[j]->Test(i->first)) { + AutoSchemaPath spath(ctx, "patternProperties"); + AutoSchemaPath spath2(ctx, patternProperties[j]->GetKey()); + matchFound = true; + SchemaValidate(ctx, patternProperties[j]->GetSchema(), i->second); + } + } + // If no match was found for either of the previous cases validate + // against additionalProperties + if (!matchFound && schema.Contains("additionalProperties")) { + Variant additionalProps = schema["additionalProperties"]; + AutoSchemaPath spath(ctx, "additionalProperties"); + if (additionalProps.IsBool()) { + if (!additionalProps.AsBool()) { + ctx.AddError("Additional properties not allowed."); + } + } else { + SchemaValidate(ctx, additionalProps, i->second); + } + } + } + } + + void ValidateObjectRequiredProperties(SchemaContext &ctx, Variant schema, Variant data) { + if (schema.Contains("required")) { + unsigned index = 0; + Variant required = schema["required"]; + AutoSchemaPath spath(ctx, "required"); + if (!required.IsList()) { + ctx.AddSchemaError("\"required\" must be a list of required keys"); + return; + } + for (Variant::ListIterator i(required.ListBegin()), e(required.ListEnd()); + i != e; ++i, ++index) + { + AutoSchemaPath spath(ctx, index); + if (i->IsString()) { + std::string key = i->AsString(); + if (!data.Contains(key)) { + std::ostringstream oss; + oss << "Missing required property: " << key; + ctx.AddError(oss.str()); + } + } else { + ctx.AddSchemaError("Elements of the \"required\" list must be strings"); + } + } + } + // TODO: Add v3 compatibility by checking required keys in properties? + } + + void ValidateObjectMinMaxProperties(SchemaContext &ctx, Variant schema, Variant data) { + if (schema.Contains("minProperties")) { + AutoSchemaPath spath(ctx, "minProperties"); + if (schema["minProperties"].IsNumber()) { + uintmax_t minprops = schema["minProperties"].AsUnsigned(); + if (data.Size() < minprops) { + std::ostringstream oss; + oss << "Too few properties defined (" << data.Size() << "), minimum " << minprops; + ctx.AddError(oss.str()); + } + } else { + ctx.AddSchemaError("\"minProperties\" must be a number"); + } + } + if (schema.Contains("maxProperties")) { + AutoSchemaPath spath(ctx, "maxProperties"); + if (schema["maxProperties"].IsNumber()) { + uintmax_t maxprops = schema["maxProperties"].AsUnsigned(); + if (data.Size() > maxprops) { + std::ostringstream oss; + oss << "Too many properties defined (" << data.Size() << "), maximum " << maxprops; + ctx.AddError(oss.str()); + } + } else { + ctx.AddSchemaError("\"minProperties\" must be a number"); + } + } + } + + void ValidateObject(SchemaContext &ctx, Variant schema, Variant data) { + if (!data.IsMap() || data.IsNull()) { return; } + ValidateObjectMinMaxProperties(ctx, schema, data); + ValidateObjectRequiredProperties(ctx, schema, data); + ValidateObjectProperties(ctx, schema, data); + ValidateObjectDependencies(ctx, schema, data); + } + + void ValidateArrayItems(SchemaContext &ctx, Variant schema, Variant data) { + if (!schema.Contains("items")) { return; } + if (!data.IsList()) { return; } + if (schema["items"].IsList()) { + Variant items = schema["items"]; + unsigned datalength = data.Size(); + unsigned itemlength = items.Size(); + for (unsigned i(0); i < datalength; ++i) { + AutoDataPath dpath(ctx, i); + if (i < itemlength) { + AutoSchemaPath spath(ctx, "items"); + AutoSchemaPath spath2(ctx, i); + SchemaValidate(ctx, items[i], data[i]); + } else if (schema.Contains("additionalItems")) { + AutoSchemaPath spath(ctx, "additionalItems"); + if (schema["additionalItems"].IsBool()) { + if (!schema["additionalItems"].AsBool()) { + ctx.AddError("Additional items not allowed"); + } + } else { + SchemaValidate(ctx, schema["additionalItems"], data[i]); + } + } + } + } else { + unsigned datalength = data.Size(); + AutoSchemaPath spath(ctx, "items"); + for (unsigned i(0); i < datalength; ++i) { + AutoDataPath dpath(ctx, i); + SchemaValidate(ctx, schema["items"], data[i]); + } + } + } + + void ValidateArrayUniqueItems(SchemaContext &ctx, Variant schema, Variant data) { + if (!schema.Contains("uniqueItems")) { return; } + AutoSchemaPath spath(ctx, "uniqueItems"); + if (!schema["uniqueItems"].IsBool()) { + ctx.AddSchemaError("\"uniqueItems\" must be a boolean"); + return; + } + if (!schema["uniqueItems"].AsBool()) { return; } + unsigned length = data.Size(); + for (unsigned i(0); i < length; ++i) { + for (unsigned j(i+1); j < length; ++j) { + if (data[i].Comparable(data[j]) && data[i] == data[j]) { + std::ostringstream oss; + oss << "Array items are not unique (indices " << i << " and " << j << ")"; + ctx.AddError(oss.str()); + } + } + } + } + + void ValidateArrayLength(SchemaContext &ctx, Variant schema, Variant data) { + if (schema.Contains("minItems")) { + AutoSchemaPath spath(ctx, "minItems"); + if (schema["minItems"].IsNumber()) { + uintmax_t minItems = schema["minItems"].AsUnsigned(); + if (data.Size() < minItems) { + std::ostringstream oss; + oss << "Array is to short (" << data.Size() << "), minimum " << minItems; + ctx.AddError(oss.str()); + } + } else { + ctx.AddSchemaError("\"minItems\" must be a number"); + } + } + if (schema.Contains("maxItems")) { + AutoSchemaPath spath(ctx, "maxItems"); + if (schema["maxItems"].IsNumber()) { + uintmax_t maxItems = schema["maxItems"].AsUnsigned(); + if (data.Size() > maxItems) { + std::ostringstream oss; + oss << "Array is to long (" << data.Size() << "), maximum " << maxItems; + ctx.AddError(oss.str()); + } + } else { + ctx.AddSchemaError("\"maxItems\" must be a number"); + } + } + } + + void ValidateArray(SchemaContext &ctx, Variant schema, Variant data) { + if (!data.IsList()) { return; } + ValidateArrayLength(ctx, schema, data); + ValidateArrayUniqueItems(ctx, schema, data); + ValidateArrayItems(ctx, schema, data); + } + + void ValidateStringFormat(SchemaContext &ctx, Variant schema, Variant data) { + if (!schema.Contains("format")) { return; } + AutoSchemaPath spath(ctx, "format"); + if (!schema["format"].IsString()) { return; } + std::string format = schema["format"].AsString(); + regex_t pattern; + memset(&pattern, 0, sizeof(regex_t)); + std::string patternstr; + int err; + if (format == "regex") { + // From V3 spec + err = regcomp(&pattern, data.AsString().c_str(), REG_EXTENDED | REG_NOSUB); + if (err) { + std::ostringstream oss; + oss << "String \"" << data.AsString() << "\" not a valid regular expression."; + ctx.AddError(oss.str()); + } + regfree(&pattern); + } else { + if (format == "date-time") { + // From V4 spec + // RFC 3339, section 5.6 + patternstr = "^[0-9][0-9][0-9][0-9](-[0-1][0-9](-[0-3][0-9]" + "(T[0-9][0-9](:[0-9][0-9](:[0-9][0-9])?)?)?)?)?Z?$"; + } else if (format == "date") { + // From V3 spec: should be format of YYYY-MM-DD + patternstr = "^[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]$"; + } else if (format == "time") { + // From V3 spec: should be format of hh:mm:ss + patternstr = "^[0-2][0-9]:[0-5][0-9]:[0-5][0-9]$"; + } else if (format == "email") { + // RFC 5322, section 3.4.1 + // TODO + } else if (format == "hostname") { + // RFC 1034, section 3.1 + // TODO + } else if (format == "ipv4") { + // RFC 2676, section 3.2 + // TODO + } else if (format == "ipv6") { + // RFC 2373, section 2.2 + // TODO + } else if (format == "uri") { + // RFC 3986 + // TODO + } + + if (!patternstr.empty()) { + if ((err = regcomp(&pattern, patternstr.c_str(), REG_EXTENDED | REG_NOSUB))) { + std::vector buffer(8192); + regerror(err, &pattern, &buffer[0], buffer.size()); + std::ostringstream oss; + oss << "Failed to compile format regex \"" << patternstr << "\" with error: " + << &buffer[0]; + ctx.AddSchemaError(oss.str()); + return; + } + try { + if (regexec(&pattern, data.AsString().c_str(), 0, 0, 0)) { + ctx.AddError("String does not match format " + format); + } + } catch (...) { + regfree(&pattern); + throw; + } + regfree(&pattern); + } + } + } + + void ValidateStringPattern(SchemaContext &ctx, Variant schema, Variant data) { + if (!schema.Contains("pattern")) { return; } + AutoSchemaPath spath(ctx, "pattern"); + if (!schema["pattern"].IsString()) { + ctx.AddSchemaError("\"pattern\" must be a string"); + return; + } + regex_t pattern; + memset(&pattern, 0, sizeof(regex_t)); + std::string patternstr = schema["pattern"].AsString(); + int err; + if ((err = regcomp(&pattern, patternstr.c_str(), REG_EXTENDED | REG_NOSUB))) { + std::vector buffer(8192); + regerror(err, &pattern, &buffer[0], buffer.size()); + std::ostringstream oss; + oss << "Failed to compile pattern regex \"" << patternstr << "\" with error: " + << &buffer[0]; + ctx.AddSchemaError(oss.str()); + return; + } + try { + if (regexec(&pattern, data.AsString().c_str(), 0, 0, 0)) { + std::ostringstream oss; + oss << "String does not match pattern \"" + << patternstr << "\""; + ctx.AddError(oss.str()); + } + } catch (...) { + regfree(&pattern); + throw; + } + regfree(&pattern); + } + + void ValidateStringLength(SchemaContext &ctx, Variant schema, Variant data) { + if (schema.Contains("minLength")) { + AutoSchemaPath spath(ctx, "minLength"); + if (schema["minLength"].IsNumber()) { + // TODO: Get encoded length rather than byte length? + if (data.Size() < schema["minLength"].AsUnsigned()) { + std::ostringstream oss; + oss << "String is too short (" << data.Size() << " chars), minimum " + << schema["minLength"].AsUnsigned(); + ctx.AddError(oss.str()); + } + } else { + ctx.AddSchemaError("\"minLength\" must be a number"); + } + } + if (schema.Contains("maxLength")) { + AutoSchemaPath spath(ctx, "maxLength"); + if (schema["maxLength"].IsNumber()) { + // TODO: Get encoded length rather than byte length? + if (data.Size() > schema["maxLength"].AsUnsigned()) { + std::ostringstream oss; + oss << "String is too long (" << data.Size() << " chars), maximum " + << schema["maxLength"].AsUnsigned(); + ctx.AddError(oss.str()); + } + } else { + ctx.AddSchemaError("\"maxLength\" must be a number"); + } + } + } + + void ValidateString(SchemaContext &ctx, Variant schema, Variant data) { + if (!data.IsString()) { return; } + ValidateStringLength(ctx, schema, data); + ValidateStringPattern(ctx, schema, data); + ValidateStringFormat(ctx, schema, data); + } + + void ValidateMinMax(SchemaContext &ctx, Variant schema, Variant data) { + if (schema.Contains("minimum")) { + if (schema["minimum"].IsNumber()) { + if (data < schema["minimum"]) { + AutoSchemaPath spath(ctx, "minimum"); + std::ostringstream oss; + oss << "Value " << data.AsString() + << " is less than minimum " << schema["minimum"].AsString(); + ctx.AddError(oss.str()); + } + if (schema.Contains("exclusiveMinimum") && schema["exclusiveMinimum"].AsBool() + && data == schema["minimum"]) { + AutoSchemaPath spath(ctx, "exclusiveMinimum"); + std::ostringstream oss; + oss << "Value " << data.AsString() << " is equal to exclusive minimum " + << schema["minimum"].AsString(); + ctx.AddError(oss.str()); + } + } else { + AutoSchemaPath spath(ctx, "minimum"); + ctx.AddSchemaError("\"minimum\" must be a number"); + } + } + if (schema.Contains("maximum")) { + if (schema["maximum"].IsNumber()) { + if (data > schema["maximum"]) { + AutoSchemaPath spath(ctx, "maximum"); + std::ostringstream oss; + oss << "Value " << data.AsString() + << " is greater than maximum " << schema["maximum"].AsString(); + ctx.AddError(oss.str()); + } + if (schema.Contains("exclusiveMaximum") && schema["exclusiveMaximum"].AsBool() + && data == schema["maximum"]) { + AutoSchemaPath spath(ctx, "exclusiveMaximum"); + std::ostringstream oss; + oss << "Value " << data.AsString() + << " is equal to exclusive maximum " << schema["maximum"].AsString(); + ctx.AddError(oss.str()); + } + } else { + AutoSchemaPath spath(ctx, "maximum"); + ctx.AddSchemaError("\"maximum\" must be a number"); + } + } + } + + void ValidateMultipleOf(SchemaContext &ctx, Variant schema, Variant data) { + std::string multkey; + if (schema.Contains("multipleOf")) { + multkey = "multipleOf"; + } else if (schema.Contains("divisibleBy")) { + multkey = "divisibleBy"; + } else { + return; + } + AutoSchemaPath spath(ctx, multkey); + Variant multipleof = schema[multkey]; + if (!multipleof.IsNumber() || multipleof < 0) { + std::ostringstream oss; + oss << "\"" << multkey << "\" must be a positive number"; + ctx.AddSchemaError(oss.str()); + return; + } + Variant mod = data % multipleof; + if (data.IsFloat() || multipleof.IsFloat()) { + // We have an issue here of the fact that many numeric values in base 10 are + // not exactly represented in binary floating point. + // So, we need to check if it is within epsilon of 0 + long double m = mod.AsLongDouble(); + long double divisor = multipleof.AsLongDouble(); + long double tolerance = FLOAT_TOLERANCE; + + if (m > tolerance && std::abs(m - divisor) > tolerance) { + std::ostringstream oss; + oss << "Value " << data.AsString() << " is not a multiple of " << multipleof.AsString(); + //oss << "\nmodulus: " << m << "\n|modulus-divisor|: " << std::abs(m - divisor) + // << "\ntolerance " << tolerance; + ctx.AddError(oss.str()); + } + } else if (mod != 0) { + std::ostringstream oss; + oss << "Value " << data.AsString() << " is not a multiple of " << multipleof.AsString(); + ctx.AddError(oss.str()); + } + } + + void ValidateNumeric(SchemaContext &ctx, Variant schema, Variant data) { + if (!data.IsNumber()) { return; } + ValidateMultipleOf(ctx, schema, data); + ValidateMinMax(ctx, schema, data); + } + + void ValidateEnum(SchemaContext &ctx, Variant schema, Variant data) { + if (!schema.Contains("enum")) { return; } + Variant enm = schema["enum"]; + AutoSchemaPath spath(ctx, "enum"); + if (!enm.IsList()) { + ctx.AddSchemaError("\"enum\" must be an array"); + return; + } + for (Variant::ListIterator i(enm.ListBegin()), e(enm.ListEnd()); i!=e; ++i) { + if (i->Comparable(data) && *i == data) { return; } + } + std::ostringstream oss; + oss << "No enum match for: "; + SerializeJSON(oss.rdbuf(), data); + ctx.AddError(oss.str()); + } + + void ValidateType(SchemaContext &ctx, Variant schema, Variant data) { + if (!schema.Contains("type")) { return; } + AutoSchemaPath spath(ctx, "type"); + std::vector allowed_types; + if (schema["type"].IsList()) { + allowed_types = schema["type"].AsList(); + } else { + // TODO: v3 compatibility + // if (schema["type"] == "any") { return; } + allowed_types.push_back(schema["type"]); + } + std::ostringstream oss; + unsigned index = 0; + for (Variant::ListIterator i(allowed_types.begin()), e(allowed_types.end()); + i != e; ++i, ++index) { + if (*i == "array") { + if (data.IsList()) { return; } + } else if (*i == "boolean") { + if (data.IsBool()) { return; } + } else if (*i == "integer") { + if (data.IsInt() || data.IsUnsigned()) { return; } + if (data.IsFloat() && data % 1 == 0) { return; } + } else if (*i == "null") { + if (data.IsNull()) { return; } + } else if (*i == "number") { + if (data.IsNumber()) { return; } + } else if (*i == "object") { + if (data.IsMap()) { return; } + } else if (*i == "string") { + if (data.IsString()) { return; } + } else { + AutoSchemaPath spath(ctx, index); + std::ostringstream oss; + oss << "Invalid schema type: \"" << i->AsString() << "\""; + ctx.AddSchemaError(oss.str()); + } + } + oss << "invalid data type: \"" << data.GetType() << "\" expected"; + if (allowed_types.size() == 1) { + oss << ": \"" << allowed_types.front().AsString() << "\""; + } else { + oss << " one of: ["; + for (Variant::ListIterator i(allowed_types.begin()), e(allowed_types.end()); + i != e; ++i) { + oss << "\"" << i->AsString() << "\""; + if (i+1 != e) { oss << ", "; } + } + oss << "]"; + } + ctx.AddError(oss.str()); + } + + void ValidateBasic(SchemaContext &ctx, Variant schema, Variant data) { + ValidateType(ctx, schema, data); + ValidateEnum(ctx, schema, data); + } + + void SchemaValidate(SchemaContext &ctx, Variant schema, Variant data) { + AutoDepth depth(ctx); + // Empty schema always validates + if (!schema.IsMap()) { return; } + if (schema.Contains("$ref") && schema["$ref"].IsString()) { + SchemaValidate(ctx, ctx.loader->GetSchema(schema["$ref"].AsString()), data); + } + ValidateBasic(ctx, schema, data); + ValidateNumeric(ctx, schema, data); + ValidateString(ctx, schema, data); + ValidateArray(ctx, schema, data); + ValidateObject(ctx, schema, data); + ValidateCombinations(ctx, schema, data); + } + + SchemaResult SchemaValidate(Variant schema, Variant data, SchemaLoader *loader) + { + SchemaLoader lloader(loader); + if (schema.IsNull() && data.IsMap() && data.Contains("$schema")) { + schema["$ref"] = data["$schema"]; + } + if (schema.IsString()) { + schema = lloader.GetSchema(schema.AsString()); + } + lloader.AddSchema("", schema); + SchemaContext ctx(&lloader); + try { + SchemaValidate(ctx, schema, data); + } catch (const StopValidation &) {} + return ctx.result; + } + + void AddSchemaDefaultsImpl(Variant schema, VariantRef data, SchemaLoader *loader); + + void AddSchemaListDefaultsImpl(VariantRef slist, VariantRef data, SchemaLoader *loader) { + if (slist.Exists() && slist.IsList()) { + for (Variant::ListIterator i(slist.ListBegin()), e(slist.ListEnd()); i != e; ++i) { + AddSchemaDefaultsImpl(*i, data, loader); + } + } + } + + void AddSchemaDefaultsImpl(Variant schema, VariantRef data, SchemaLoader *loader) { + if (!schema.IsMap()) { return; } + if (schema.Contains("$ref") && schema["$ref"].IsString()) { + AddSchemaDefaultsImpl(loader->GetSchema(schema["$ref"].AsString()), data, loader); + } + if (schema.Contains("default") && (!data.Exists() || data.IsNull())) { + data = schema["default"].Copy(); + return; + } + if (schema.Contains("properties") && (!data.Exists() || data.IsMap())) { + for (Variant::MapIterator i(schema["properties"].MapBegin()), e(schema["properties"].MapEnd()); + i != e; ++i) + { + AddSchemaDefaultsImpl(i->second, data.At(i->first), loader); + } + } + if (schema.Contains("items") && (!data.Exists() || data.IsList())) { + if (schema["items"].IsList()) { + for (unsigned i = 0; i < schema["items"].Size(); ++i) + { + AddSchemaDefaultsImpl(schema["items"][i], data[i], loader); + } + } else { + AddSchemaDefaultsImpl(schema["items"], data[0], loader); + } + } + AddSchemaListDefaultsImpl(schema["allOf"], data, loader); + AddSchemaListDefaultsImpl(schema["oneOf"], data, loader); + AddSchemaListDefaultsImpl(schema["anyOf"], data, loader); + } + + void AddSchemaDefaults(Variant schema, VariantRef data, SchemaLoader *loader) { + SchemaLoader lloader(loader); + if (schema.IsNull() && data.IsMap() && data.Contains("$schema")) { + schema["$ref"] = data["$schema"]; + } + if (schema.IsString()) { + schema = lloader.GetSchema(schema.AsString()); + } + lloader.AddSchema("", schema); + AddSchemaDefaultsImpl(schema, data, &lloader); + } + + void InsertIndent(std::ostream &os, unsigned indent) { + for (unsigned i = 0; i < indent; ++i) { os << "\t"; } + } + + ValidationError::ValidationError(const std::string &m, const Path &dpath, + const Path &spath) + : message(m), + data_path(dpath), + schema_path(spath) + {} + + void ValidationError::AddSubError(const SchemaResult &err) { + sub_errors.push_back(err); + } + + std::string ValidationError::GetDataPathStr() const { + return PathString(data_path); + } + + std::string ValidationError::GetSchemaPathStr() const { + return PathString(schema_path); + } + + std::string ValidationError::PrettyPrintMessage() const { + std::ostringstream oss; + PrettyPrintMessage(oss); + return oss.str(); + } + + void ValidationError::PrettyPrintMessage(std::ostream &os, unsigned indent) const { + InsertIndent(os, indent); + os << "validation error: " << message << "\n"; + InsertIndent(os, indent); + os << "data path: " << GetDataPathStr() << "\n"; + InsertIndent(os, indent); + os << "schema path: " << GetSchemaPathStr() << "\n"; + if (!sub_errors.empty()) { + InsertIndent(os, indent); + os << "sub errors:\n"; + for (unsigned i = 0; i < sub_errors.size(); ++i) { + sub_errors[i].PrettyPrintMessage(os, indent+1); + } + } + } + + SchemaError::SchemaError(const std::string &m, const Path &spath) + : message(m), + schema_path(spath) + { + } + + std::string SchemaError::GetSchemaPathStr() const { + return PathString(schema_path); + } + + std::string SchemaError::PrettyPrintMessage() const { + std::ostringstream oss; + PrettyPrintMessage(oss); + return oss.str(); + } + + void SchemaError::PrettyPrintMessage(std::ostream &os, unsigned indent) const { + InsertIndent(os, indent); + os << "schema error: " << message << "\n"; + InsertIndent(os, indent); + os << "schema path: " << GetSchemaPathStr() << "\n"; + } + + SchemaResult::SchemaResult() + { + } + + void SchemaResult::AddError(const ValidationError &err) { + errors.push_back(err); + } + + void SchemaResult::AddSchemaError(const SchemaError &err) { + schema_errors.push_back(err); + } + + std::string SchemaResult::PrettyPrintMessage() const { + std::ostringstream oss; + PrettyPrintMessage(oss); + return oss.str(); + } + + void SchemaResult::PrettyPrintMessage(std::ostream &os, unsigned indent) const { + if (!errors.empty()) { + for (unsigned i = 0; i < errors.size(); ++i) { + errors[i].PrettyPrintMessage(os, indent); + } + } + if (!schema_errors.empty()) { + for (unsigned i = 0; i < schema_errors.size(); ++i) { + schema_errors[i].PrettyPrintMessage(os, indent); + } + } + } + +} diff --git a/src/hos_libvariant/src/src/SchemaLoader.cc b/src/hos_libvariant/src/src/SchemaLoader.cc new file mode 100644 index 00000000..f6884271 --- /dev/null +++ b/src/hos_libvariant/src/src/SchemaLoader.cc @@ -0,0 +1,570 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef ENABLE_CURL +#include +#endif + +#if 0 +#include +#define DBPRINT(a) std::cerr << a +#else +#define DBPRINT(a) +#endif + +namespace libvariant { + + extern const char JSON_SCHEMA_V4_SCHEMA[]; + class SchemaStaticData { + public: + SchemaStaticData() { + JSON_SCHEMA_SCHEMA = DeserializeJSON(JSON_SCHEMA_V4_SCHEMA); + SCHEMA_URI = SchemaLoader::ResolveURI(JSON_SCHEMA_SCHEMA["id"].AsString(), ""); + SchemaLoader::NormSchema(JSON_SCHEMA_SCHEMA, SCHEMA_URI); + } + Variant JSON_SCHEMA_SCHEMA; + std::string SCHEMA_URI; + }; + shared_ptr schema_static_data; + + SchemaStaticData *GetSchemaStaticData() { + // This is actually a race condition when multithreading is used, but + // every thread will write the same data, so this is "OK" as long as + // the CPU cache coherency is reasonable. + if (!schema_static_data.get()) { + shared_ptr new_schema_static_data; + new_schema_static_data.reset(new SchemaStaticData); + schema_static_data = new_schema_static_data; + } + return schema_static_data.get(); + } + + SchemaLoader::SchemaLoader() + : missingHandler(0), + missingctx(0), + base(0) + { + SchemaStaticData *d = GetSchemaStaticData(); + schemas[d->SCHEMA_URI] = d->JSON_SCHEMA_SCHEMA; + } + + SchemaLoader::SchemaLoader(SchemaLoader *b) + : missingHandler(0), + missingctx(0), + base(b) + { + DBPRINT("schema loader\n"); + SchemaStaticData *d = GetSchemaStaticData(); + schemas[d->SCHEMA_URI] = d->JSON_SCHEMA_SCHEMA; + } + + SchemaLoader::~SchemaLoader() {} + + std::string UnescapeURI(const std::string &uri) { + std::string ret; + const char *c = uri.c_str(); + const char *e = c + uri.size(); + while (c != e) { + switch (*c) { + case '%': + if (c + 1 == e || c + 2 == e) { + ret.append(c); + c = e; + } else { + char hex[3] = { *(c+1), *(c+2), 0 }; + char *endp = 0; + long hexv = strtol(hex, &endp, 16); + if (*endp != 0) { + ret.append(c, 3); + } else { + ret.append(1, (char)hexv); + } + c += 3; + } + break; + default: + ret.append(c, 1); + ++c; + break; + } + } + return ret; + } + + Variant SchemaLoader::GetSchema(const std::string &uri) { + Variant::MapIterator iter = schemas.find(uri); + if (iter != schemas.end()) { + return iter->second; + } + std::string baseuri = ResolveURI(uri, ""); + std::string fragment; + std::string::size_type hashIndex = uri.find("#"); + if (hashIndex != std::string::npos) { + fragment = uri.substr(hashIndex + 1); + baseuri = uri.substr(0, hashIndex); + } + iter = schemas.find(baseuri); + if (iter == schemas.end()) { + if (base) { + return base->GetSchema(uri); + } + LoaderError err; + if (!HandleMissing(baseuri, err)) { + throw std::runtime_error(err.GetErrorMessage()); + } + iter = schemas.find(baseuri); + } + if (iter == schemas.end()) { + return Variant::NullType; + } + + Variant schema = iter->second; + return JSONPointerLookup(UnescapeURI(fragment), schema); + } + + std::map SchemaLoader::AddSchema(const std::string &uri, Variant schema) { + std::string luri = ResolveURI(uri, ""); + std::map m; + m[luri] = schema; + NormSchema(schema, luri); + SearchForTrustedSchemas(m, schema, luri); + schemas.insert(m.begin(), m.end()); + return m; + } + + void SchemaLoader::ForgetSchema(const std::string &uri) { + schemas.erase(uri); + } + + bool SchemaLoader::HandleMissing(const std::string &uri, LoaderError &error) { + if (missingHandler) { + return missingHandler(this, uri, error, missingctx); + } else if (base) { + return base->HandleMissing(uri, error); + } else { + error.AddError(uri, "SchemaLoader missing schema"); + return false; + } + } + + void SchemaLoader::SetMissingHandler(MissingHandlerType f, void *ctx) { + missingHandler = f; + missingctx = ctx; + } + + // The following two functions are adapted from two functions in tv4 with the following comment: + // parseURI() and resolveUrl() are from https://gist.github.com/1088850 + // - released as public domain by author ("Yaffle") - see comments on gist + + bool SchemaLoader::ParseURI(URIInfo &info, const std::string &uri) { + enum { + HREF=0, PROTOCOL, AUTHORITY, USERHOST, HOST, + HOSTNAME, PORT, PATHNAME, SEARCH, HASH, MATCHLEN + }; + static const struct RegexHelper { + RegexHelper() { + memset(®ex, 0, sizeof(regex_t)); + int ret = regcomp(®ex, +"^[[:space:]]*([^:\\/?#]+:)?" // PROTOCOL +"(//([^:@]*(:[^:@]*)?@)?([^:/?#]*)(:[0-9]*)?)?" // (//((user(:host)@)(hostname)(:port))) +"([^?#]*)" // PATHNAME +"(\\?[^#]*)?" // SEARCH +"(#[^[:space:]]*)?[[:space:]]*$" // HASH + , REG_EXTENDED); + if (ret) { + std::vector buffer(8192); + regerror(ret, ®ex, &buffer[0], buffer.size()); + std::ostringstream oss; + oss << "libvariant library initialization failure: Failed to initialize schema uri handling regex with error: " + << &buffer[0]; + fputs(oss.str().c_str(), stderr); + throw std::runtime_error(oss.str()); + } + } + ~RegexHelper() { regfree(®ex); } + regex_t regex; + } regex; + regmatch_t match[MATCHLEN]; + DBPRINT(std::endl << "Matching against \"" << uri << "\"\n"); + int err = regexec(®ex.regex, uri.c_str(), MATCHLEN, &match[0], 0); + if (err != 0) { + DBPRINT("Match failed\n"); + return false; + } + for (int i = 0; i < MATCHLEN; ++i) { + int so, eo, len; + if (match[i].rm_so >= 0) { + so = match[i].rm_so; + eo = match[i].rm_eo; + len = eo - so; + DBPRINT("Match "); + switch (i) { + case HREF: + info.href = uri.substr(so, len); + DBPRINT("href\t"); + break; + case PROTOCOL: + info.protocol = uri.substr(so, len); + DBPRINT("protocol\t"); + break; + case AUTHORITY: + info.authority = uri.substr(so, len); + DBPRINT("authority\t"); + break; + case PATHNAME: + info.pathname = uri.substr(so, len); + DBPRINT("pathname\t"); + break; + case SEARCH: + info.search = uri.substr(so, len); + DBPRINT("search\t"); + break; + case HASH: + info.hash = uri.substr(so, len); + DBPRINT("hash\t"); + break; + default: + break; + } + DBPRINT(i << " matched \"" << uri.substr(so, len) << "\"" << std::endl); + } else { + DBPRINT(i << " did not match" << std::endl); + } + } + return true; + } + + std::string RemoveDotSegments(const std::string &input) { + //^(\.\.?(\/|$))+/, '' -- ignore leading ../ removed + //\/(\.(\/|$))+/g, '/' -- remove /./ + //\/\.\.$/, '/../' -- normalize last /.. to /../ + //\/?[^\/]*/g, function (p) { + std::vector output; + std::string::size_type i = 0; + std::string::size_type next = input.find("/"); + bool firstslash = false; + DBPRINT("Processing \"" << input << "\"\n"); + unsigned lastdot = 0; + if (next == 0) { + // First was a slash, make sure to add it back + firstslash = true; + DBPRINT("firstslash\n"); + } else if (next >= input.size()) { + // No slashes + DBPRINT("no slashes\n"); + if (input == ".") { return ""; } + else { return input; } + //} else if (next + 1 == input.size()) { + // only slash at end + //if (input == "../" || input == "./") { return ""; } + //else { return input; } + } else { + std::string sub = input.substr(i, next - i); + if (sub != ".") { + output.push_back(sub); + if (sub == "..") { lastdot = output.size(); } + DBPRINT("leading: \"" << output.back() << "\"\n"); + } + } + while (next < input.size()) { + i = next; + next = input.find("/", i + 1); + // Get the string between the slashes + std::string sub = input.substr(i + 1, next - 1 - i); + if (sub == ".") { + lastdot = output.size(); + } else if (sub == "..") { + DBPRINT("pop\n"); + if (!output.empty()) { output.pop_back(); } + else { output.push_back(sub); } + lastdot = output.size(); + } else { + output.push_back(sub); + DBPRINT("push back: \"" << output.back() << "\"\n"); + } + } + std::ostringstream oss; + for (std::vector::iterator iv(output.begin()), ie(output.end()); iv != ie; ++iv) { + if (firstslash) { + oss << "/"; + } else { + firstslash = true; + } + oss << *iv; + } + if (output.empty() && firstslash) { oss << "/"; } + if (lastdot > 0 && lastdot == output.size()) { oss << "/"; } + DBPRINT("ret: \"" << oss.str() << "\""); + return oss.str(); + } + + std::string SchemaLoader::ResolveURI(const std::string &base, const std::string &href) { + URIInfo b, h; + bool base_parsed = ParseURI(b, base); + bool href_parsed = ParseURI(h, href); + std::string ret = ""; + if (!base_parsed || !href_parsed) { + return ret; + } + + ret += (h.protocol != "" ? h.protocol : b.protocol); + ret += (h.protocol != "" || h.authority != "" ? h.authority : b.authority); + if (h.protocol != "" || h.authority != "" || h.pathname[0] == '/') { + ret += RemoveDotSegments(h.pathname); + } else { + if (h.pathname == "") { + ret += RemoveDotSegments(b.pathname); + } else { + ret += RemoveDotSegments( + (b.authority != "" && b.pathname == "" ? "/" : "") + + b.pathname.substr(0, b.pathname.rfind("/") + 1) + + h.pathname + ); + } + } + if (h.protocol != "" || h.authority != "" || h.pathname != "" || h.search != "") { + ret += h.search; + } else { + ret += b.search; + } + ret += h.hash; + return ret; + } + + void SchemaLoader::NormSchema(Variant &schema, const std::string &uri) { + std::string baseuri = uri; + if (schema.IsMap()) { + if (schema.Contains("id") && schema["id"].IsString()) { + baseuri = ResolveURI(baseuri, schema["id"].AsString()); + schema["id"] = baseuri; + } + if (schema.Contains("$ref") && schema["$ref"].IsString()) { + schema["$ref"] = ResolveURI(baseuri, schema["$ref"].AsString()); + } else { + for (Variant::MapIterator i(schema.MapBegin()), e(schema.MapEnd()); i != e; ++i) { + if (i->first != "enum") { + NormSchema(i->second, baseuri); + } + } + } + } else if (schema.IsList()) { + for (Variant::ListIterator i(schema.ListBegin()), e(schema.ListEnd()); i != e; ++i) { + NormSchema(*i, baseuri); + } + } + } + + void SchemaLoader::SearchForTrustedSchemas(std::map &m, + Variant schema, const std::string &uri) + { + if (schema.IsMap()) { + if (schema.Contains("id") && schema["id"].IsString()) { + std::string id = schema["id"].AsString(); + if (id.substr(0, uri.length()) == uri) { + std::string remainder = id.substr(uri.length()); + if ((uri.length() > 0 && uri[uri.length()-1] == '/') + || remainder[0] == '#' + || remainder[0] == '?') + { + if (m.find(id) == m.end()) { + m[id] = schema; + } + } + } + } + + for (Variant::MapIterator i(schema.MapBegin()), e(schema.MapEnd()); i != e; ++i) { + if (i->first != "enum" && i->second.IsMap()) { + SearchForTrustedSchemas(m, i->second, uri); + } + } + } + } + + SchemaLoader::LoaderError::LoaderError() { + erross << "SchemaLoader error:\n"; + } + + SchemaLoader::LoaderError::~LoaderError() {} + + void SchemaLoader::LoaderError::AddError(const std::string &uri, const std::string &msg) { + erross << "\t" << uri << ": " << msg << "\n"; + } + + void AdvSchemaLoader::AddPath(const std::string &path) { + paths.push_back(path); + } + + bool AdvSchemaLoader::HandleMissing(const std::string &uri, LoaderError &error) { + URIInfo info; + if (uri.empty()) { + return SchemaLoader::HandleMissing(uri, error); + } else if (ParseURI(info, uri)) { + if (info.href[0] == '/' || info.href[0] == '.') { + // Assume file system path. + if (!LoadFromFile(info, error)) { + return SchemaLoader::HandleMissing(uri, error); + } + return true; + } else if (info.protocol.empty()) { + if (!LoadFromFile(info, error) && !LoadFromCurl(info, error)) { + return SchemaLoader::HandleMissing(uri, error); + } + return true; + } else if (info.protocol == "file:") { + if (!LoadFromFile(info, error)) { + return SchemaLoader::HandleMissing(uri, error); + } + return true; + } else { + if (!LoadFromCurl(info, error)) { + return SchemaLoader::HandleMissing(uri, error); + } + return true; + } + } + return SchemaLoader::HandleMissing(uri, error); + } + + bool AdvSchemaLoader::LoadFromFile(URIInfo &info, LoaderError &error) { + // Normalize the path.. + std::string path; + if (!info.authority.empty()) { + if ( + !info.protocol.empty() + && info.authority.size() >= 2 + && info.authority[0] == '/' + && info.authority[1] == '/' + ) + { + path = info.authority.substr(2); + } else { + path = info.authority; + } + } + path += info.pathname; + if (path[0] == '/') { + // Absolute path + try { + AddSchema(info.href, DeserializeGuessFile(path.c_str())); + return true; + } catch (const std::exception &e) { + error.AddError(path.c_str(), e.what()); + return false; + } + } + // Not absolute + for (std::vector::iterator i(paths.begin()), e(paths.end()); i != e; ++i) { + std::string uri = *i + "/" + path; + try { + AddSchema(info.href, DeserializeGuessFile(uri.c_str())); + return true; + } catch (const std::exception &e) { + error.AddError(uri, e.what()); + } + } + return false; + } + +#ifdef ENABLE_CURL + + size_t CurlContextWrite(char *ptr, size_t size, size_t nmemb, void *userdata); + + class CurlContext { + public: + + CurlContext(SchemaLoader::URIInfo &info) + : self(curl_easy_init()) + { + if (!self) { + std::ostringstream oss; + oss << "Unable to initialize curl to fetch uri: " << info.href; + throw std::runtime_error(oss.str()); + } + CURLcode err = curl_easy_setopt(self, CURLOPT_NOSIGNAL, 1); + if (err != CURLE_OK) { Error(err); } + err = curl_easy_setopt(self, CURLOPT_WRITEFUNCTION, &CurlContextWrite); + if (err != CURLE_OK) { Error(err); } + err = curl_easy_setopt(self, CURLOPT_WRITEDATA, (void*)this); + if (err != CURLE_OK) { Error(err); } + uri = info.protocol + info.authority + info.pathname + info.search; + err = curl_easy_setopt(self, CURLOPT_URL, uri.c_str()); + if (err != CURLE_OK) { Error(err); } + } + + ~CurlContext() { + curl_easy_cleanup(self); + } + + size_t Write(char *ptr, size_t len) { + data_buff.insert(data_buff.end(), ptr, ptr + len); + return len; + } + + void Perform() { + CURLcode err = curl_easy_perform(self); + if (err != CURLE_OK) { Error(err); } + } + + void Error(CURLcode err) { + std::ostringstream oss; + oss << "Error attempting to fetch uri: " << uri << "\n"; + oss << curl_easy_strerror(err); + throw std::runtime_error(oss.str()); + } + + CURL *self; + std::string uri; + std::vector data_buff; + std::vector err_buff; + }; + + size_t CurlContextWrite(char *ptr, size_t size, size_t nmemb, void *userdata) { + return ((CurlContext*)userdata)->Write(ptr, size*nmemb); + } + + bool AdvSchemaLoader::LoadFromCurl(URIInfo &info, LoaderError &error) { + try { + CurlContext ctx(info); + ctx.Perform(); + AddSchema(ctx.uri, DeserializeGuess(&ctx.data_buff[0], ctx.data_buff.size())); + return true; + } catch (const std::exception &e) { + error.AddError(info.href, e.what()); + return false; + } + } + +#else + bool AdvSchemaLoader::LoadFromCurl(URIInfo &info, LoaderError &error) { + error.AddError(info.href, "Curl support not compiled in to load urls."); + return false; + } +#endif +} diff --git a/src/hos_libvariant/src/src/StackTrace.cc b/src/hos_libvariant/src/src/StackTrace.cc new file mode 100644 index 00000000..641587af --- /dev/null +++ b/src/hos_libvariant/src/src/StackTrace.cc @@ -0,0 +1,51 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \brief functino for printing out a stack trace + * lookup the backtrace etc. in the man pages. + * \author John Bridgman + */ +#include "StackTrace.h" +#include +#include +#include +#include +#include + +void PrintStack() { + void* stack[STACKTRACE_MAXTRACE]; + size_t size = backtrace(stack, STACKTRACE_MAXTRACE); + backtrace_symbols_fd(stack, size, 2); +} + +std::string GetStack(unsigned ignore) { + void* stack[STACKTRACE_MAXTRACE]; + size_t size = backtrace(stack, STACKTRACE_MAXTRACE); + char **bt = backtrace_symbols(stack, size); + if (!bt) { + perror("backtrace_symbols"); + return ""; + } + std::ostringstream oss; + for (unsigned i = ignore; i < size; ++i) { + oss << bt[i] << '\n'; + } + free(bt); + return oss.str(); +} + + diff --git a/src/hos_libvariant/src/src/StackTrace.h b/src/hos_libvariant/src/src/StackTrace.h new file mode 100644 index 00000000..50047a0b --- /dev/null +++ b/src/hos_libvariant/src/src/StackTrace.h @@ -0,0 +1,48 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \brief function for printing out a stack trace + * Note that we need to pass -rdynamic to the linker to + * be able to see the function names with these functions. + * \author John Bridgman + */ + +#ifndef STACKTRACE_H +#define STACKTRACE_H +#pragma once +#include +#ifndef STACKTRACE_MAXTRACE +#define STACKTRACE_MAXTRACE 100 +#endif +/** + * Prints the stack trace to stderr + * Should work even if we are out of memory + */ +void PrintStack(); + +/** + * Returns a std::string to the stack trace. + * May fail if out of memory. + * \param ignore the number of top stacks to ignore. This is + * useful because this function is often used in error messages + * and it is useless garbage to report the stack from the error + * handler. + */ +std::string GetStack(unsigned ignore = 0); + +#endif + diff --git a/src/hos_libvariant/src/src/Variant.cc b/src/hos_libvariant/src/src/Variant.cc new file mode 100644 index 00000000..9afe8525 --- /dev/null +++ b/src/hos_libvariant/src/src/Variant.cc @@ -0,0 +1,2257 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= + +/** \file + * \author John Bridgman + * Variant implementation + */ +#include +#include "ParseBool.h" +#include +#include +#include +#include +#include +#include + +template +class my_modulus { +public: + T operator()(const T &lhs, const T &rhs) { return lhs % rhs; } +}; + +template<> +class my_modulus { +public: + long double operator()(const long double &lhs, const long double &rhs) { return fmod(lhs, rhs); } +}; + +namespace libvariant { + + static inline Variant::Type_t NumericUpcast(Variant::Type_t t1, Variant::Type_t t2) { + switch (t1) { + case Variant::IntegerType: + switch (t2) { + case Variant::IntegerType: + return Variant::IntegerType; + case Variant::UnsignedType: + return Variant::UnsignedType; + case Variant::FloatType: + return Variant::FloatType; + case Variant::NullType: + case Variant::BoolType: + case Variant::StringType: + case Variant::ListType: + case Variant::MapType: + throw UnableToConvertError(t2, "a numeric type."); + default: + throw UnknownTypeError(t2); + } + case Variant::UnsignedType: + switch (t2) { + case Variant::IntegerType: + return Variant::UnsignedType; + case Variant::UnsignedType: + return Variant::UnsignedType; + case Variant::FloatType: + return Variant::FloatType; + case Variant::NullType: + case Variant::BoolType: + case Variant::StringType: + case Variant::ListType: + case Variant::MapType: + throw UnableToConvertError(t2, "a numeric type."); + default: + throw UnknownTypeError(t2); + } + case Variant::FloatType: + switch (t2) { + case Variant::IntegerType: + return Variant::FloatType; + case Variant::UnsignedType: + return Variant::FloatType; + case Variant::FloatType: + return Variant::FloatType; + case Variant::NullType: + case Variant::BoolType: + case Variant::StringType: + case Variant::ListType: + case Variant::MapType: + throw UnableToConvertError(t2, "a numeric type."); + default: + throw UnknownTypeError(t2); + } + case Variant::NullType: + case Variant::BoolType: + case Variant::StringType: + case Variant::ListType: + case Variant::MapType: + throw UnableToConvertError(t1, "a numeric type."); + default: + throw UnknownTypeError(t1); + } + } + + + namespace Internal { + + struct RefData { + RefData() : valid(true) {} + bool valid; + }; + + struct Storage { + Storage() {} + + virtual ~Storage() {} + + }; + + struct MapStorage : public Storage { + MapStorage(const Variant::Map &m) : map(m) {} + Variant::Map map; + }; + + struct ListStorage : public Storage { + ListStorage(const Variant::List &l) : list(l) {} + Variant::List list; + }; + + struct StringStorage : public Storage { + StringStorage(const std::string &s) : str(s) {} + std::string str; + }; + + struct BlobStorage : public Storage { + BlobStorage(BlobPtr b) : blob(b) {} + BlobPtr blob; + }; + + struct RefStorage : public Storage { + shared_ptr storage; + }; + + struct ProxyStorage : public Storage { + ProxyStorage(Data *ref_, Path::const_iterator b, Path::const_iterator e) + : ref(ref_), storage(ref_->storage), path(b, e) + {} + Data *ref; + shared_ptr storage; + Path path; + }; + + + // Three ways to look up a value in a map or list: + // Get a reference/proxy -> GetRef + // Get pointer/throw -> Get checked=true + // Get pointer/null -> Get checked=false + + class VTable { + public: + static inline Data *GetData(Variant *v) { return v; } + static inline const Data *GetData(const Variant *v) { return v; } + static inline Variant *GetVar(Data *d) { return static_cast(d); } + static inline const Variant *GetVar(const Data *d) { return static_cast(d); } + + virtual ~VTable() {} + virtual void Copy(const Data *that, Data *other) const = 0; + virtual void Assign(const Data *that, Data *other) const; + virtual void MakeRef(const Data *that, Data *ref) const; + virtual void MakeProxy(Data *that, Data *ref, Path::const_iterator b, Path::const_iterator e) const; + virtual Variant::Type_t GetType(const Data *that) const = 0; + virtual bool AsBool(const Data *that) const; + virtual long double AsLongDouble(const Data *that) const; + virtual uintmax_t AsUnsigned(const Data *that) const; + virtual intmax_t AsInt(const Data *that) const; + virtual std::string AsString(const Data *that) const; + virtual BlobPtr AsBlob(Data *that) const; + virtual ConstBlobPtr AsBlobConst(const Data *that) const; + virtual unsigned Size(const Data *that) const; + virtual bool Empty(const Data *that) const; + virtual void Clear(Data *that) const; + virtual Variant::List &AsList(Data *that) const; + virtual const Variant::List &AsListConst(const Data *that) const; + virtual bool ContainsIndex(const Data *that, unsigned i) const; + virtual unsigned Index(const Data *that, Variant v) const; + virtual void EraseIndex(Data *that, unsigned i) const; + virtual VariantRef GetRefIndex(Data *that, unsigned i, Variant *def) const; + virtual const Variant *GetConstIndex(const Data *that, unsigned i, bool checked) const; + virtual Variant *GetIndex(Data *that, unsigned i, bool checked) const; + virtual void SetIndex(Data *that, unsigned i, const Data *other) const; + virtual Variant::Map &AsMap(Data *that) const; + virtual const Variant::Map &AsMapConst(const Data *that) const; + virtual bool ContainsKey(const Data *that, const std::string &s) const; + virtual void EraseKey(Data *that, const std::string &key) const; + virtual VariantRef GetRefKey(Data *that, const std::string &s, Variant *def) const; + virtual const Variant *GetConstKey(const Data *that, const std::string &s, bool checked) const; + virtual Variant *GetKey(Data *that, const std::string &s, bool checked) const; + virtual void SetKey(Data *that, const std::string &s, const Data *other) const; + VariantRef GetPathRef(Data *that, Path::const_iterator b, Path::const_iterator e, Variant *def) const; + const Variant *GetPathConst(const Data *that, Path::const_iterator b, Path::const_iterator e, bool checked) const; + void SetPath(Data *that, Path::const_iterator b, Path::const_iterator e, const Variant *other) const; + void ErasePath(Data *that, Path::const_iterator b, Path::const_iterator e, bool recursive) const; + bool Comparable(const Data *that, const Data *other) const; + virtual int Compare(const Data *that, const Data *other) const = 0; + virtual void Incr(Data *that) const; + virtual void Decr(Data *that) const; + virtual Variant Neg(const Data *that) const; + virtual void Add(Data *that, const Data *other) const; + virtual void Sub(Data *that, const Data *other) const; + virtual void Mul(Data *that, const Data *other) const; + virtual void Div(Data *that, const Data *other) const; + virtual void Rem(Data *that, const Data *other) const; + shared_ptr EnsureRef(Data *that) const; + virtual void Destroy(Data *that) const; + virtual void Destruct(Data *that) const; + virtual Variant *Resolve(Data *that) const; + virtual const Variant *ResolveConst(const Data *that) const; + virtual Variant *ResolveDefault(Data *that, const Data *def) const; + virtual bool Exists(const Data *that) const; + }; + + void DefaultInit(Data *that, VariantDefines::Type_t type); + + void NullInit(Data *that); + + void BoolInit(Data *that, bool b); + + void IntegerInit(Data *that, intmax_t i); + + void UnsignedInit(Data *that, uintmax_t u); + + void FloatInit(Data *that, long double f); + + void StringInit(Data *that, const std::string &s); + + void ListInit(Data *that, const Variant::List &l); + + void MapInit(Data *that, const Variant::Map &m); + + void BlobInit(Data *that, BlobPtr blob); + + void RefInit(Data *that, const Data *other); + + void ProxyInit(Data *that, Data *ref, Path::const_iterator b, Path::const_iterator e); + + //-------------------- + // VTable + //-------------------- + + void VTable::Assign(const Data *that, Data *other) const + { that->vtable->Copy(that, VTable::GetData(other->vtable->Resolve(other))); } + + void VTable::MakeRef(const Data *that, Data *ref) const { + RefInit(ref, that); + } + void VTable::MakeProxy(Data *that, Data *ref, Path::const_iterator b, Path::const_iterator e) const + { ProxyInit(ref, that, b, e); } + + bool VTable::AsBool(const Data *that) const + { throw UnableToConvertError(that->vtable->GetType(that), "a bool"); } + + long double VTable::AsLongDouble(const Data *that) const + { throw UnableToConvertError(that->vtable->GetType(that), "a float"); } + + uintmax_t VTable::AsUnsigned(const Data *that) const + { throw UnableToConvertError(that->vtable->GetType(that), "a unsigned"); } + + intmax_t VTable::AsInt(const Data *that) const + { throw UnableToConvertError(that->vtable->GetType(that), "a int"); } + + std::string VTable::AsString(const Data *that) const + { throw UnableToConvertError(that->vtable->GetType(that), "a string"); } + + BlobPtr VTable::AsBlob(Data *that) const + { throw UnexpectedTypeError(VariantDefines::BlobType, that->vtable->GetType(that)); } + + ConstBlobPtr VTable::AsBlobConst(const Data *that) const + { throw UnexpectedTypeError(VariantDefines::BlobType, that->vtable->GetType(that)); } + + unsigned VTable::Size(const Data *that) const + { throw InvalidOperationError(that->vtable->GetType(that), "Size"); } + + bool VTable::Empty(const Data *that) const + { throw InvalidOperationError(that->vtable->GetType(that), "Empty"); } + + void VTable::Clear(Data *that) const { NullInit(that); } + + Variant::List &VTable::AsList(Data *that) const + { throw UnableToConvertError(that->vtable->GetType(that), "a list"); } + + const Variant::List &VTable::AsListConst(const Data *that) const + { throw UnexpectedTypeError(VariantDefines::ListType, that->vtable->GetType(that)); } + + bool VTable::ContainsIndex(const Data *that, unsigned i) const + { return false; } + + unsigned VTable::Index(const Data *that, Variant o) const + { throw UnexpectedTypeError(VariantDefines::ListType, that->vtable->GetType(that)); } + + void VTable::EraseIndex(Data *that, unsigned i) const + { throw UnexpectedTypeError(VariantDefines::ListType, that->vtable->GetType(that)); } + + VariantRef VTable::GetRefIndex(Data *that, unsigned i, Variant *def) const + { throw UnexpectedTypeError(VariantDefines::ListType, that->vtable->GetType(that)); } + + const Variant *VTable::GetConstIndex(const Data *that, unsigned i, bool checked) const { + if (!checked) { return 0; } + throw UnexpectedTypeError(VariantDefines::ListType, that->vtable->GetType(that)); + } + + Variant *VTable::GetIndex(Data *that, unsigned i, bool checked) const { + if (!checked) { return 0; } + throw UnexpectedTypeError(VariantDefines::ListType, that->vtable->GetType(that)); + } + + void VTable::SetIndex(Data *that, unsigned i, const Data *other) const + { throw UnexpectedTypeError(VariantDefines::ListType, that->vtable->GetType(that)); } + + Variant::Map &VTable::AsMap(Data *that) const + { throw UnableToConvertError(that->vtable->GetType(that), "a map"); } + + const Variant::Map &VTable::AsMapConst(const Data *that) const + { throw UnexpectedTypeError(VariantDefines::MapType, that->vtable->GetType(that)); } + + bool VTable::ContainsKey(const Data *that, const std::string &s) const + { return false; } + + void VTable::EraseKey(Data *that, const std::string &key) const + { throw UnexpectedTypeError(VariantDefines::MapType, that->vtable->GetType(that)); } + + VariantRef VTable::GetRefKey(Data *that, const std::string &s, Variant *def) const + { throw UnexpectedTypeError(VariantDefines::MapType, that->vtable->GetType(that)); } + + const Variant *VTable::GetConstKey(const Data *that, const std::string &s, bool checked) const { + if (!checked) { return 0; } + throw UnexpectedTypeError(VariantDefines::MapType, that->vtable->GetType(that)); + } + + Variant *VTable::GetKey(Data *that, const std::string &s, bool checked) const { + if (!checked) { return 0; } + throw UnexpectedTypeError(VariantDefines::MapType, that->vtable->GetType(that)); + } + + void VTable::SetKey(Data *that, const std::string &s, const Data *other) const + { throw UnexpectedTypeError(VariantDefines::MapType, that->vtable->GetType(that)); } + + const Variant *GetPathElem(const Data *that, const PathElement &elem, bool checked) { + if (elem.IsString()) { + return that->vtable->GetConstKey(that, elem.AsString(), checked); + } else /* if (elem.IsNumber()) */ { + return that->vtable->GetConstIndex(that, elem.AsUnsigned(), checked); + } + } + + Variant *GetPathElem(Data *that, const PathElement &elem, bool checked) { + if (elem.IsString()) { + return that->vtable->GetKey(that, elem.AsString(), checked); + } else /* if (elem.IsNumber()) */ { + return that->vtable->GetIndex(that, elem.AsUnsigned(), checked); + } + } + + VariantRef GetRefPathElem(Data *that, const PathElement &elem, Variant *def) { + if (elem.IsString()) { + return that->vtable->GetRefKey(that, elem.AsString(), def); + } else /* if (elem.IsNumber()) */ { + return that->vtable->GetRefIndex(that, elem.AsUnsigned(), def); + } + } + + void SetPathElem(Data *that, const PathElement &elem, const Variant *other) { + if (elem.IsString()) { + that->vtable->SetKey(that, elem.AsString(), VTable::GetData(other)); + } else /* if (elem.IsNumber()) */ { + that->vtable->SetIndex(that, elem.AsUnsigned(), VTable::GetData(other)); + } + } + + VariantRef VTable::GetPathRef(Data *that, Path::const_iterator b, + Path::const_iterator e, Variant *def) const + { + if (b == e) { return VariantRef(*GetVar(that)); } + Variant *ref = 0; + ref = GetPathElem(that, *b, false); + if (!ref) { + if (!def) { + return VariantRef(*GetVar(that), b, e); + } + if (b + 1 == e) { + return GetRefPathElem(that, *b, def); + } else { + Variant null_value; + SetPathElem(that, *b, &null_value); + return that->vtable->GetPathRef(that, b, e, def); + } + } + if (b + 1 == e) { + return VariantRef(*ref); + } else { + Data *ref_data = VTable::GetData(ref); + return ref_data->vtable->GetPathRef(ref_data, b + 1, e, def); + } + } + + const Variant *VTable::GetPathConst(const Data *that, Path::const_iterator b, Path::const_iterator e, bool checked) const + { + if (b == e) { return that->vtable->ResolveConst(that); } + const Variant *ref = 0; + ref = GetPathElem(that, *b, checked); + if (!ref) { + if (checked) { + if (b->IsString()) { + throw KeyError(b->AsString()); + } else { + throw std::out_of_range("Variant::List index out of range."); + } + } + return 0; + } + if (b + 1 == e) { + return ref; + } else { + const Data *ref_data = VTable::GetData(ref); + return ref_data->vtable->GetPathConst(ref_data, b + 1, e, checked); + } + } + + void VTable::SetPath(Data *that, Path::const_iterator b, Path::const_iterator e, const Variant *other) const + { + if (b == e) { + const Data *other_data = VTable::GetData(other); + other_data->vtable->Assign(other_data, that); + return; + } + Variant *ref = 0; + ref = GetPathElem(that, *b, false); + if (!ref) { + if (b + 1 == e) { + SetPathElem(that, *b, other); + return; + } else { + Variant null_value; + SetPathElem(that, *b, &null_value); + that->vtable->SetPath(that, b, e, other); + return; + } + } + Data *ref_data = VTable::GetData(ref); + ref_data->vtable->SetPath(ref_data, b + 1, e, other); + } + + void ErasePathElem(Data *that, const PathElement &elem) { + if (elem.IsString()) { + return that->vtable->EraseKey(that, elem.AsString()); + } else /* if (elem.IsNumber()) */ { + return that->vtable->EraseIndex(that, elem.AsUnsigned()); + } + } + + void VTable::ErasePath(Data *that, Path::const_iterator b, Path::const_iterator e, bool remove_empty) const + { + if (b == e) { return; } + if (b + 1 == e) { + ErasePathElem(that, *b); + return; + } + Variant *ref = 0; + ref = GetPathElem(that, *b, false); + if (!ref) { return; } + Data *ref_data = VTable::GetData(ref); + ref_data->vtable->ErasePath(ref_data, b + 1, e, remove_empty); + if (remove_empty && ref_data->vtable->Empty(ref_data)) { + ErasePathElem(that, *b); + } + } + + bool VTable::Comparable(const Data *that, const Data *other) const { + VariantDefines::Type_t ltype = that->vtable->GetType(that), otype = other->vtable->GetType(other); + return ( ltype == otype ) + || ( + ( ltype == VariantDefines::IntegerType + || ltype == VariantDefines::UnsignedType + || ltype == VariantDefines::FloatType ) + && ( otype == VariantDefines::IntegerType + || otype == VariantDefines::UnsignedType + || otype == VariantDefines::FloatType ) + ); + } + + void VTable::Incr(Data *that) const + { throw NotNumericTypeError(that->vtable->GetType(that)); } + + void VTable::Decr(Data *that) const + { throw NotNumericTypeError(that->vtable->GetType(that)); } + + Variant VTable::Neg(const Data *that) const + { throw NotNumericTypeError(that->vtable->GetType(that)); } + + void VTable::Add(Data *that, const Data *other) const + { throw NotNumericTypeError(that->vtable->GetType(that)); } + + void VTable::Sub(Data *that, const Data *other) const + { throw NotNumericTypeError(that->vtable->GetType(that)); } + + void VTable::Mul(Data *that, const Data *other) const + { throw NotNumericTypeError(that->vtable->GetType(that)); } + + void VTable::Div(Data *that, const Data *other) const + { throw NotNumericTypeError(that->vtable->GetType(that)); } + + void VTable::Rem(Data *that, const Data *other) const + { throw NotNumericTypeError(that->vtable->GetType(that)); } + + shared_ptr VTable::EnsureRef(Data *that) const { + if (!that->ref_data) { + that->ref_data.reset(new RefData()); + } + return that->ref_data; + } + + void VTable::Destroy(Data *that) const { + assert(that->vtable); + that->storage.reset(); + that->vtable = 0; + } + + void VTable::Destruct(Data *that) const { + that->vtable->Destroy(that); + if (that->ref_data) { + that->ref_data->valid = false; + that->ref_data.reset(); + } + } + + Variant *VTable::Resolve(Data *that) const + { return VTable::GetVar(that); } + + const Variant *VTable::ResolveConst(const Data *that) const + { return VTable::GetVar(that); } + + Variant *VTable::ResolveDefault(Data *that, const Data *) const + { return VTable::GetVar(that); } + + bool VTable::Exists(const Data *that) const { return true; } + + //-------------------- + // NullVTable + //-------------------- + + class Null : public VTable { + public: + Null() {} + virtual void Copy(const Data *that, Data *other) const; + virtual Variant::Type_t GetType(const Data *that) const; + virtual bool AsBool(const Data *that) const; + virtual long double AsLongDouble(const Data *that) const; + virtual uintmax_t AsUnsigned(const Data *that) const; + virtual intmax_t AsInt(const Data *that) const; + virtual std::string AsString(const Data *that) const; + virtual unsigned Size(const Data *that) const; + virtual bool Empty(const Data *that) const; + virtual void Clear(Data *that) const; + virtual Variant::List &AsList(Data *that) const; + virtual void EraseIndex(Data *that, unsigned i) const; + virtual VariantRef GetRefIndex(Data *that, unsigned i, Variant *def) const; + virtual const Variant *GetConstIndex(const Data *that, unsigned i, bool checked) const; + virtual Variant *GetIndex(Data *that, unsigned i, bool checked) const; + virtual void SetIndex(Data *that, unsigned i, const Data *other) const; + virtual Variant::Map &AsMap(Data *that) const; + virtual void EraseKey(Data *that, const std::string &key) const; + virtual VariantRef GetRefKey(Data *that, const std::string &s, Variant *def) const; + virtual const Variant *GetConstKey(const Data *that, const std::string &s, bool checked) const; + virtual Variant *GetKey(Data *that, const std::string &s, bool checked) const; + virtual void SetKey(Data *that, const std::string &s, const Data *other) const; + virtual int Compare(const Data *that, const Data *other) const; + virtual Variant *ResolveDefault(Data *that, const Data *def) const; + }; + + const VTable *NullVTable() { + static const Null null_vtable; + return &null_vtable; + } + + void Null::Copy(const Data *that, Data *other) const { NullInit(other); } + + VariantDefines::Type_t Null::GetType(const Data *that) const + { return VariantDefines::NullType; } + + bool Null::AsBool(const Data *that) const { return false; } + + long double Null::AsLongDouble(const Data *that) const { return 0.0; } + + uintmax_t Null::AsUnsigned(const Data *that) const { return 0; } + + intmax_t Null::AsInt(const Data *that) const { return 0; } + + std::string Null::AsString(const Data *that) const { return ""; } + + unsigned Null::Size(const Data *that) const { return 0; } + + bool Null::Empty(const Data *that) const { return true; } + + void Null::Clear(Data *that) const {} + + Variant::List &Null::AsList(Data *that) const { + ListInit(that, Variant::List()); + return that->vtable->AsList(that); + } + void Null::EraseIndex(Data *that, unsigned i) const {} + + VariantRef Null::GetRefIndex(Data *that, unsigned i, Variant *def) const { + if (def) { + ListInit(that, Variant::List()); + return that->vtable->GetRefIndex(that, i, def); + } + return VariantRef(*that->vtable->Resolve(that), Path(1, i)); + } + + const Variant *Null::GetConstIndex(const Data *that, unsigned i, bool checked) const { + if (!checked) { return 0; } + throw std::out_of_range("Variant::List index out of range."); + } + + Variant *Null::GetIndex(Data *that, unsigned i, bool checked) const { + if (!checked) { return 0; } + throw std::out_of_range("Variant::List index out of range."); + } + + void Null::SetIndex(Data *that, unsigned i, const Data *other) const { + ListInit(that, Variant::List()); + that->vtable->SetIndex(that, i, other); + } + + Variant::Map &Null::AsMap(Data *that) const { + MapInit(that, Variant::Map()); + return that->vtable->AsMap(that); + } + + + void Null::EraseKey(Data *that, const std::string &) const {} + + VariantRef Null::GetRefKey(Data *that, const std::string &s, Variant *def) const { + if (def) { + MapInit(that, Variant::Map()); + return that->vtable->GetRefKey(that, s, def); + } + return VariantRef(*that->vtable->Resolve(that), Path(1, s)); + } + + const Variant *Null::GetConstKey(const Data *that, const std::string &s, bool checked) const { + if (!checked) { return 0; } + throw KeyError(s); + } + + Variant *Null::GetKey(Data *that, const std::string &s, bool checked) const { + if (!checked) { return 0; } + throw KeyError(s); + } + + void Null::SetKey(Data *that, const std::string &s, const Data *other) const { + MapInit(that, Variant::Map()); + that->vtable->SetKey(that, s, other); + } + + int Null::Compare(const Data *that, const Data *other) const { + return (Comparable(that, other) ? 0 : 1); + } + + Variant *Null::ResolveDefault(Data *that, const Data *def) const { + def->vtable->Assign(def, that); + return that->vtable->Resolve(that); + } + + void NullInit(Data *that) { + if (that->vtable) that->vtable->Destroy(that); + that->vtable = NullVTable(); + } + + //-------------------- + // BoolVTable + //-------------------- + + class Bool : public VTable { + public: + Bool() {} + virtual void Copy(const Data *that, Data *other) const; + virtual Variant::Type_t GetType(const Data *that) const; + virtual bool AsBool(const Data *that) const; + virtual long double AsLongDouble(const Data *that) const; + virtual uintmax_t AsUnsigned(const Data *that) const; + virtual intmax_t AsInt(const Data *that) const; + virtual std::string AsString(const Data *that) const; + virtual int Compare(const Data *that, const Data *other) const; + }; + + void Bool::Copy(const Data *that, Data *other) const + { BoolInit(other, that->b); } + + VariantDefines::Type_t Bool::GetType(const Data *that) const + { return VariantDefines::BoolType; } + + bool Bool::AsBool(const Data *that) const + { return that->b; } + + long double Bool::AsLongDouble(const Data *that) const + { return that->b; } + + uintmax_t Bool::AsUnsigned(const Data *that) const + { return that->b; } + + intmax_t Bool::AsInt(const Data *that) const + { return that->b; } + + std::string Bool::AsString(const Data *that) const { + if (that->b) { return "true"; } + else { return "false"; } + } + + int Bool::Compare(const Data *that, const Data *other) const { + if (Comparable(that, other)) { + other = VTable::GetData(other->vtable->ResolveConst(other)); + return (that->b == other->b ? 0 : 1); + } + return 1; + } + + void BoolInit(Data *that, bool b) { + static const Bool bool_vtable; + if (that->vtable) that->vtable->Destroy(that); + that->vtable = &bool_vtable; + that->b = b; + } + + //-------------------- + // NumericVTable + //-------------------- + + class Numeric : public VTable { + public: + virtual int Compare(const Data *that, const Data *other) const; + virtual void Add(Data *that, const Data *other) const; + virtual void Sub(Data *that, const Data *other) const; + virtual void Mul(Data *that, const Data *other) const; + virtual void Div(Data *that, const Data *other) const; + virtual void Rem(Data *that, const Data *other) const; + }; + + int Numeric::Compare(const Data *that, const Data *other) const { + if (Comparable(that, other)) { + long double us = that->vtable->AsLongDouble(that); + long double o = other->vtable->AsLongDouble(other); + if (us < o) { return -1; } + else if (us > o) { return 1; } + else { return 0; } + } + return 1; + } + + template< template class Op > + void NumericOperation(Data *that, const Data *other) { + VariantDefines::Type_t ntype = NumericUpcast(that->vtable->GetType(that), + other->vtable->GetType(other)); + switch (ntype) { + case VariantDefines::IntegerType: + { + Op op; + IntegerInit(that, + op(that->vtable->AsInt(that), other->vtable->AsInt(other))); + } + break; + case VariantDefines::UnsignedType: + { + Op op; + UnsignedInit(that, + op(that->vtable->AsUnsigned(that), other->vtable->AsUnsigned(other))); + } + break; + case VariantDefines::FloatType: + { + Op op; + FloatInit(that, + op(that->vtable->AsLongDouble(that), other->vtable->AsLongDouble(other))); + } + break; + default: + throw NotNumericTypeError(ntype); + } + } + + void Numeric::Add(Data *that, const Data *other) const + { NumericOperation(that, other); } + + void Numeric::Sub(Data *that, const Data *other) const + { NumericOperation(that, other); } + + void Numeric::Mul(Data *that, const Data *other) const + { NumericOperation(that, other); } + + void Numeric::Div(Data *that, const Data *other) const + { NumericOperation(that, other); } + + void Numeric::Rem(Data *that, const Data *other) const + { NumericOperation(that, other); } + + //-------------------- + // IntegerVTable + //-------------------- + + class Integer : public Numeric { + public: + Integer() {} + virtual void Copy(const Data *that, Data *other) const; + virtual Variant::Type_t GetType(const Data *that) const; + virtual bool AsBool(const Data *that) const; + virtual long double AsLongDouble(const Data *that) const; + virtual uintmax_t AsUnsigned(const Data *that) const; + virtual intmax_t AsInt(const Data *that) const; + virtual std::string AsString(const Data *that) const; + virtual void Incr(Data *that) const; + virtual void Decr(Data *that) const; + virtual Variant Neg(const Data *that) const; + }; + + void Integer::Copy(const Data *that, Data *other) const + { IntegerInit(other, that->i); } + + VariantDefines::Type_t Integer::GetType(const Data *that) const + { return VariantDefines::IntegerType; } + + bool Integer::AsBool(const Data *that) const + { return that->i != 0; } + + long double Integer::AsLongDouble(const Data *that) const + { return (long double)that->i; } + + uintmax_t Integer::AsUnsigned(const Data *that) const + { return (uintmax_t)that->i; } + + intmax_t Integer::AsInt(const Data *that) const + { return that->i; } + + std::string Integer::AsString(const Data *that) const { + std::ostringstream oss; + oss << that->i; + return oss.str(); + } + + void Integer::Incr(Data *that) const + { ++that->i; } + + void Integer::Decr(Data *that) const + { --that->i; } + + Variant Integer::Neg(const Data *that) const + { return Variant(-that->i); } + + void IntegerInit(Data *that, intmax_t i) { + static const Integer integer_vtable; + if (that->vtable) that->vtable->Destroy(that); + that->vtable = &integer_vtable; + that->i = i; + } + + //-------------------- + // UnsignedVTable + //-------------------- + + class Unsigned : public Numeric { + public: + Unsigned() {} + virtual void Copy(const Data *that, Data *other) const; + virtual Variant::Type_t GetType(const Data *that) const; + virtual bool AsBool(const Data *that) const; + virtual long double AsLongDouble(const Data *that) const; + virtual uintmax_t AsUnsigned(const Data *that) const; + virtual intmax_t AsInt(const Data *that) const; + virtual std::string AsString(const Data *that) const; + virtual void Incr(Data *that) const; + virtual void Decr(Data *that) const; + virtual Variant Neg(const Data *that) const; + }; + + void Unsigned::Copy(const Data *that, Data *other) const + { UnsignedInit(other, that->u); } + + VariantDefines::Type_t Unsigned::GetType(const Data *that) const + { return VariantDefines::UnsignedType; } + + bool Unsigned::AsBool(const Data *that) const + { return that->u != 0; } + + long double Unsigned::AsLongDouble(const Data *that) const + { return (long double)that->u; } + + uintmax_t Unsigned::AsUnsigned(const Data *that) const + { return that->u; } + + intmax_t Unsigned::AsInt(const Data *that) const + { return (intmax_t)that->u; } + + std::string Unsigned::AsString(const Data *that) const { + std::ostringstream oss; + oss << that->u; + return oss.str(); + } + + void Unsigned::Incr(Data *that) const + { ++that->u; } + + void Unsigned::Decr(Data *that) const + { --that->u; } + + Variant Unsigned::Neg(const Data *that) const { + return Variant(-that->u); + } + + void UnsignedInit(Data *that, uintmax_t u) { + static const Unsigned unsigned_vtable; + if (that->vtable) that->vtable->Destroy(that); + that->vtable = &unsigned_vtable; + that->u = u; + } + + //-------------------- + // FloatVTable + //-------------------- + + class Float : public Numeric { + public: + Float() {} + virtual void Copy(const Data *that, Data *other) const; + virtual Variant::Type_t GetType(const Data *that) const; + virtual bool AsBool(const Data *that) const; + virtual long double AsLongDouble(const Data *that) const; + virtual uintmax_t AsUnsigned(const Data *that) const; + virtual intmax_t AsInt(const Data *that) const; + virtual std::string AsString(const Data *that) const; + virtual void Incr(Data *that) const; + virtual void Decr(Data *that) const; + virtual Variant Neg(const Data *that) const; + }; + + void Float::Copy(const Data *that, Data *other) const { + FloatInit(other, that->f); + } + + VariantDefines::Type_t Float::GetType(const Data *that) const + { return VariantDefines::FloatType; } + + bool Float::AsBool(const Data *that) const + { return that->f != 0; } + + long double Float::AsLongDouble(const Data *that) const + { return that->f; } + + uintmax_t Float::AsUnsigned(const Data *that) const + { return (uintmax_t)that->f; } + + intmax_t Float::AsInt(const Data *that) const + { return (intmax_t)that->f; } + + std::string Float::AsString(const Data *that) const { + std::ostringstream oss; + oss << that->f; + return oss.str(); + } + + void Float::Incr(Data *that) const + { ++that->f; } + + void Float::Decr(Data *that) const + { --that->f; } + + Variant Float::Neg(const Data *that) const { + return Variant(-that->f); + } + + void FloatInit(Data *that, long double f) { + static const Float float_vtable; + if (that->vtable) that->vtable->Destroy(that); + that->vtable = &float_vtable; + that->f = f; + } + + //-------------------- + // StringVTable + //-------------------- + + class String : public VTable { + public: + String() {} + virtual void Copy(const Data *that, Data *other) const; + virtual void Assign(const Data *that, Data *other) const; + virtual Variant::Type_t GetType(const Data *that) const; + virtual bool AsBool(const Data *that) const; + virtual long double AsLongDouble(const Data *that) const; + virtual uintmax_t AsUnsigned(const Data *that) const; + virtual intmax_t AsInt(const Data *that) const; + virtual std::string AsString(const Data *that) const; + virtual unsigned Size(const Data *that) const; + virtual bool Empty(const Data *that) const; + virtual void Clear(Data *that) const; + virtual int Compare(const Data *that, const Data *other) const; + virtual void Destroy(Data *that) const; + }; + + const VTable *StringVTable() { + static const String string_vtable; + return &string_vtable; + } + + void String::Copy(const Data *that, Data *other) const + { StringInit(other, *that->s); } + + void String::Assign(const Data *that, Data *other) const { + assert(that->vtable); + shared_ptr storage = that->storage; + std::string *s = that->s; + if (other->vtable) { other = VTable::GetData(other->vtable->Resolve(other)); } + if (other->vtable) { other->vtable->Destroy(other); } + other->vtable = StringVTable(); + other->s = s; + other->storage = storage; + } + + VariantDefines::Type_t String::GetType(const Data *that) const + { return VariantDefines::StringType; } + + bool String::AsBool(const Data *that) const + { return ParseBool(*that->s); } + + long double String::AsLongDouble(const Data *that) const { + std::istringstream iss(*that->s); + long double val = 0; + iss >> val; + if (iss.fail()) { throw UnableToConvertError(that->vtable->GetType(that), "a float"); } + return val; + } + + uintmax_t String::AsUnsigned(const Data *that) const { + std::istringstream iss(*that->s); + uintmax_t val = 0; + iss >> val; + if (iss.fail()) { throw UnableToConvertError(that->vtable->GetType(that), "an unsigned"); } + return val; + } + + intmax_t String::AsInt(const Data *that) const { + std::istringstream iss(*that->s); + intmax_t val = 0; + iss >> val; + if (iss.fail()) { throw UnableToConvertError(that->vtable->GetType(that), "an int"); } + return val; + } + + std::string String::AsString(const Data *that) const + { return *that->s; } + + unsigned String::Size(const Data *that) const { return that->s->size(); } + + bool String::Empty(const Data *that) const { return that->s->empty(); } + + void String::Clear(Data *that) const { return that->s->clear(); } + + int String::Compare(const Data *that, const Data *other) const { + if (Comparable(that, other)) { + other = VTable::GetData(other->vtable->ResolveConst(other)); + return that->s->compare(*other->s); + } + return 1; + } + + void String::Destroy(Data *that) const { + VTable::Destroy(that); + that->s = 0; + } + + void StringInit(Data *that, const std::string &s) { + if (that->vtable) that->vtable->Destroy(that); + that->vtable = StringVTable(); + shared_ptr storage(new StringStorage(s)); + that->s = &storage->str; + that->storage = storage; + } + + //-------------------- + // ListVTable + //-------------------- + + class List : public VTable { + public: + List() {} + virtual void Copy(const Data *that, Data *other) const; + virtual void Assign(const Data *that, Data *other) const; + virtual Variant::Type_t GetType(const Data *that) const; + virtual unsigned Size(const Data *that) const; + virtual bool Empty(const Data *that) const; + virtual void Clear(Data *that) const; + virtual Variant::List &AsList(Data *that) const; + virtual const Variant::List &AsListConst(const Data *that) const; + virtual bool ContainsIndex(const Data *that, unsigned i) const; + virtual unsigned Index(const Data *that, Variant v) const; + virtual void EraseIndex(Data *that, unsigned i) const; + virtual VariantRef GetRefIndex(Data *that, unsigned i, Variant *def) const; + virtual const Variant *GetConstIndex(const Data *that, unsigned i, bool checked) const; + virtual Variant *GetIndex(Data *that, unsigned i, bool checked) const; + virtual void SetIndex(Data *that, unsigned i, const Data *other) const; + virtual int Compare(const Data *that, const Data *other) const; + virtual void Destroy(Data *that) const; + }; + + const VTable *ListVTable() { + static const List list_vtable; + return &list_vtable; + } + + void List::Copy(const Data *that, Data *other) const { + ListInit(other, Variant::List()); + for (Variant::ConstListIterator i(that->l->list.begin()), e(that->l->list.end()); + i != e; ++i) { + other->l->list.push_back(i->Copy()); + } + } + + void List::Assign(const Data *that, Data *other) const { + assert(that->vtable); + shared_ptr storage = that->storage; + ListStorage *l = that->l; + if (other->vtable) { other = VTable::GetData(other->vtable->Resolve(other)); } + if (other->vtable) { other->vtable->Destroy(other); } + other->vtable = ListVTable(); + other->l = l; + other->storage = storage; + } + + VariantDefines::Type_t List::GetType(const Data *that) const { return VariantDefines::ListType; } + + unsigned List::Size(const Data *that) const { return that->l->list.size(); } + + bool List::Empty(const Data *that) const { return that->l->list.empty(); } + + void List::Clear(Data *that) const { return that->l->list.clear(); } + + Variant::List &List::AsList(Data *that) const { return that->l->list; } + + const Variant::List &List::AsListConst(const Data *that) const { return that->l->list; } + + bool List::ContainsIndex(const Data *that, unsigned i) const { return i < that->l->list.size(); } + + unsigned List::Index(const Data *that, Variant v) const { + Variant::ListIterator begin = that->l->list.begin(), + end = that->l->list.end(); + return std::distance(begin, std::find(begin, end, v)); + } + + void List::EraseIndex(Data *that, unsigned i) const + { + unsigned size = that->l->list.size(); + if (i + 1 < size) { + that->l->list.at(i).Assign(Variant::NullType); + } else if (i < size) { + that->l->list.pop_back(); + } + } + + VariantRef List::GetRefIndex(Data *that, unsigned i, Variant *def) const { + if (i < that->l->list.size()) { + return VariantRef(that->l->list.at(i)); + } else if (def) { + that->l->list.resize(i + 1); + that->l->list.at(i) = *def; + return VariantRef(that->l->list.at(i)); + } else { + return VariantRef(*that->vtable->Resolve(that), Path(1, i)); + } + } + + const Variant *List::GetConstIndex(const Data *that, unsigned i, bool checked) const { + if (i < that->l->list.size()) { + return &that->l->list.at(i); + } else if (!checked) { + return 0; + } else { + throw std::out_of_range("Variant::List index out of range."); + } + } + + Variant *List::GetIndex(Data *that, unsigned i, bool checked) const { + if (i < that->l->list.size()) { + return &that->l->list.at(i); + } else if (!checked) { + return 0; + } else { + throw std::out_of_range("Variant::List index out of range."); + } + } + + void List::SetIndex(Data *that, unsigned i, const Data *other) const { + if ( ! (i < that->l->list.size()) ) { + that->l->list.resize(i + 1); + } + other->vtable->Assign(other, VTable::GetData(&that->l->list.at(i))); + } + + int List::Compare(const Data *that, const Data *other) const { + if (Comparable(that, other)) { + other = VTable::GetData(other->vtable->ResolveConst(other)); + return (that->l->list != other->l->list ? 1 : 0); + } + return 1; + } + + void List::Destroy(Data *that) const { + VTable::Destroy(that); + that->l = 0; + } + + void ListInit(Data *that, const Variant::List &l) { + if (that->vtable) that->vtable->Destroy(that); + that->vtable = ListVTable(); + shared_ptr storage(new ListStorage(l)); + that->l = storage.get(); + that->storage = storage; + } + + //-------------------- + // MapVTable + //-------------------- + + class Map : public VTable { + public: + Map() {} + virtual void Copy(const Data *that, Data *other) const; + virtual void Assign(const Data *that, Data *other) const; + virtual Variant::Type_t GetType(const Data *that) const; + virtual unsigned Size(const Data *that) const; + virtual bool Empty(const Data *that) const; + virtual void Clear(Data *that) const; + virtual Variant::Map &AsMap(Data *that) const; + virtual const Variant::Map &AsMapConst(const Data *that) const; + virtual bool ContainsKey(const Data *that, const std::string &s) const; + virtual void EraseKey(Data *that, const std::string &key) const; + virtual VariantRef GetRefKey(Data *that, const std::string &s, Variant *def) const; + virtual const Variant *GetConstKey(const Data *that, const std::string &s, bool checked) const; + virtual Variant *GetKey(Data *that, const std::string &s, bool checked) const; + virtual void SetKey(Data *that, const std::string &s, const Data *other) const; + virtual int Compare(const Data *that, const Data *other) const; + virtual void Destroy(Data *that) const; + }; + + const VTable *MapVTable() { + static const Map map_vtable; + return &map_vtable; + } + + void Map::Copy(const Data *that, Data *other) const { + MapInit(other, Variant::Map()); + for (Variant::ConstMapIterator i(that->m->map.begin()), e(that->m->map.end()); + i != e; ++i) { + other->m->map.insert(std::make_pair(i->first, i->second.Copy())); + } + } + + void Map::Assign(const Data *that, Data *other) const { + assert(that->vtable); + shared_ptr storage = that->storage; + MapStorage *m = that->m; + if (other->vtable) { other = VTable::GetData(other->vtable->Resolve(other)); } + if (other->vtable) { other->vtable->Destroy(other); } + other->vtable = MapVTable(); + other->m = m; + other->storage = storage; + } + + VariantDefines::Type_t Map::GetType(const Data *that) const { return VariantDefines::MapType; } + + unsigned Map::Size(const Data *that) const { return that->m->map.size(); } + + bool Map::Empty(const Data *that) const { return that->m->map.empty(); } + + void Map::Clear(Data *that) const { return that->m->map.clear(); } + + Variant::Map &Map::AsMap(Data *that) const { return that->m->map; } + + const Variant::Map &Map::AsMapConst(const Data *that) const { return that->m->map; } + + bool Map::ContainsKey(const Data *that, const std::string &s) const + { return that->m->map.find(s) != that->m->map.end(); } + + void Map::EraseKey(Data *that, const std::string &key) const { that->m->map.erase(key); } + + VariantRef Map::GetRefKey(Data *that, const std::string &s, Variant *def) const { + Variant::MapIterator entry = that->m->map.find(s); + if (entry != that->m->map.end()) { + return VariantRef(entry->second); + } else if (def) { + return VariantRef(that->m->map.insert(std::make_pair(s, *def)).first->second); + } else { + return VariantRef(*that->vtable->Resolve(that), Path(1, s)); + } + } + + const Variant *Map::GetConstKey(const Data *that, const std::string &s, bool checked) const { + Variant::MapIterator entry = that->m->map.find(s); + if (entry != that->m->map.end()) { + return &entry->second; + } else if (!checked) { + return 0; + } else { + throw KeyError(s); + } + } + + Variant *Map::GetKey(Data *that, const std::string &s, bool checked) const { + Variant::MapIterator entry = that->m->map.find(s); + if (entry != that->m->map.end()) { + return &entry->second; + } else if (!checked) { + return 0; + } else { + throw KeyError(s); + } + } + + void Map::SetKey(Data *that, const std::string &s, const Data *other) const { + Variant::MapIterator entry = that->m->map.insert(std::make_pair(s, Variant())).first; + other->vtable->Assign(other, VTable::GetData(&entry->second)); + } + + + int Map::Compare(const Data *that, const Data *other) const { + if (Comparable(that, other)) { + other = VTable::GetData(other->vtable->ResolveConst(other)); + return (that->m->map != other->m->map ? 1 : 0); + } + return 1; + } + + void Map::Destroy(Data *that) const { + VTable::Destroy(that); + that->m = 0; + } + + void MapInit(Data *that, const Variant::Map &m) { + if (that->vtable) that->vtable->Destroy(that); + that->vtable = MapVTable(); + shared_ptr storage(new MapStorage(m)); + that->m = storage.get(); + that->storage = storage; + } + + //-------------------- + // BlobVTable + //-------------------- + + class Blob : public VTable { + public: + Blob() {} + virtual void Copy(const Data *that, Data *other) const; + virtual void Assign(const Data *that, Data *other) const; + virtual Variant::Type_t GetType(const Data *that) const; + virtual BlobPtr AsBlob(Data *that) const; + virtual ConstBlobPtr AsBlobConst(const Data *that) const; + virtual unsigned Size(const Data *that) const; + virtual int Compare(const Data *that, const Data *other) const; + }; + + const VTable *BlobVTable() { + static const Blob blob_vtable; + return &blob_vtable; + } + + void Blob::Copy(const Data *that, Data *other) const + { BlobInit(other, ( (*that->blob) ? (*that->blob)->Copy() : BlobPtr() )); } + + void Blob::Assign(const Data *that, Data *other) const { + assert(that->vtable); + shared_ptr storage = that->storage; + BlobPtr *b = that->blob; + if (other->vtable) { other = VTable::GetData(other->vtable->Resolve(other)); } + if (other->vtable) { other->vtable->Destroy(other); } + other->vtable = BlobVTable(); + other->blob = b; + other->storage = storage; + } + + VariantDefines::Type_t Blob::GetType(const Data *that) const + { return VariantDefines::BlobType; } + + BlobPtr Blob::AsBlob(Data *that) const + { return *(that->blob); } + + ConstBlobPtr Blob::AsBlobConst(const Data *that) const + { return *(that->blob); } + + unsigned Blob::Size(const Data *that) const + { return (*that->blob)->GetTotalLength(); } + + int Blob::Compare(const Data *that, const Data *other) const { + if (Comparable(that, other)) { + ConstBlobPtr us = (*that->blob); + ConstBlobPtr o = other->vtable->AsBlobConst(other); + if (us == o) { return 0; } + if (us && o) { return us->Compare(o); } + } + return 1; + } + + void BlobInit(Data *that, BlobPtr blob) { + if (that->vtable) that->vtable->Destroy(that); + that->vtable = BlobVTable(); + shared_ptr storage(new BlobStorage(blob)); + that->blob = &storage->blob; + that->storage = storage; + } + + //-------------------- + // RefVTable + //-------------------- + + class Ref : public VTable { + public: + Ref() {} + virtual void Copy(const Data *that, Data *other) const; + virtual void Assign(const Data *that, Data *other) const; + virtual void MakeRef(const Data *that, Data *ref) const; + virtual void MakeProxy(Data *that, Data *ref, Path::const_iterator b, Path::const_iterator e) const; + virtual Variant::Type_t GetType(const Data *that) const; + virtual bool AsBool(const Data *that) const; + virtual long double AsLongDouble(const Data *that) const; + virtual uintmax_t AsUnsigned(const Data *that) const; + virtual intmax_t AsInt(const Data *that) const; + virtual std::string AsString(const Data *that) const; + virtual BlobPtr AsBlob(Data *that) const; + virtual ConstBlobPtr AsBlobConst(const Data *that) const; + virtual unsigned Size(const Data *that) const; + virtual bool Empty(const Data *that) const; + virtual void Clear(Data *that) const; + virtual Variant::List &AsList(Data *that) const; + virtual const Variant::List &AsListConst(const Data *that) const; + virtual bool ContainsIndex(const Data *that, unsigned i) const; + virtual unsigned Index(const Data *that, Variant v) const; + virtual void EraseIndex(Data *that, unsigned i) const; + virtual VariantRef GetRefIndex(Data *that, unsigned i, Variant *def) const; + virtual const Variant *GetConstIndex(const Data *that, unsigned i, bool checked) const; + virtual Variant *GetIndex(Data *that, unsigned i, bool checked) const; + virtual void SetIndex(Data *that, unsigned i, const Data *other) const; + virtual Variant::Map &AsMap(Data *that) const; + virtual const Variant::Map &AsMapConst(const Data *that) const; + virtual bool ContainsKey(const Data *that, const std::string &s) const; + virtual void EraseKey(Data *that, const std::string &key) const; + virtual VariantRef GetRefKey(Data *that, const std::string &s, Variant *def) const; + virtual const Variant *GetConstKey(const Data *that, const std::string &s, bool checked) const; + virtual Variant *GetKey(Data *that, const std::string &s, bool checked) const; + virtual void SetKey(Data *that, const std::string &s, const Data *other) const; + virtual int Compare(const Data *that, const Data *other) const; + virtual void Incr(Data *that) const; + virtual void Decr(Data *that) const; + virtual Variant Neg(const Data *that) const; + virtual void Add(Data *that, const Data *other) const; + virtual void Sub(Data *that, const Data *other) const; + virtual void Mul(Data *that, const Data *other) const; + virtual void Div(Data *that, const Data *other) const; + virtual void Rem(Data *that, const Data *other) const; + virtual void Destroy(Data *that) const; + virtual void Destruct(Data *that) const; + virtual Variant *Resolve(Data *that) const; + virtual const Variant *ResolveConst(const Data *that) const; + virtual Variant *ResolveDefault(Data *that, const Data *def) const; + virtual bool Exists(const Data *that) const; + }; + + static inline void CheckRef(const Data *that) { + if (!that->ref_data || !that->ref_data->valid) { + throw InvalidReferenceError("Error attempting to access an invalid VariantRef"); + } + } + + void Ref::Copy(const Data *that, Data *other) const + { CheckRef(that); that->ref->vtable->Copy(that->ref, other); } + + void Ref::Assign(const Data *that, Data *other) const + { CheckRef(that); that->ref->vtable->Assign(that->ref, other); } + + void Ref::MakeRef(const Data *that, Data *ref) const + { CheckRef(that); that->ref->vtable->MakeRef(that->ref, ref); } + + void Ref::MakeProxy(Data *that, Data *ref, Path::const_iterator b, Path::const_iterator e) const + { CheckRef(that); that->ref->vtable->MakeProxy(that->ref, ref, b, e); } + + VariantDefines::Type_t Ref::GetType(const Data *that) const + { CheckRef(that); return that->ref->vtable->GetType(that->ref); } + + bool Ref::AsBool(const Data *that) const + { CheckRef(that); return that->ref->vtable->AsBool(that->ref); } + + long double Ref::AsLongDouble(const Data *that) const + { CheckRef(that); return that->ref->vtable->AsLongDouble(that->ref); } + + uintmax_t Ref::AsUnsigned(const Data *that) const + { CheckRef(that); return that->ref->vtable->AsUnsigned(that->ref); } + + intmax_t Ref::AsInt(const Data *that) const + { CheckRef(that); return that->ref->vtable->AsInt(that->ref); } + + std::string Ref::AsString(const Data *that) const + { CheckRef(that); return that->ref->vtable->AsString(that->ref); } + + BlobPtr Ref::AsBlob(Data *that) const + { CheckRef(that); return that->ref->vtable->AsBlob(that->ref); } + + ConstBlobPtr Ref::AsBlobConst(const Data *that) const + { CheckRef(that); return that->ref->vtable->AsBlobConst(that->ref); } + + unsigned Ref::Size(const Data *that) const + { CheckRef(that); return that->ref->vtable->Size(that->ref); } + + bool Ref::Empty(const Data *that) const + { CheckRef(that); return that->ref->vtable->Empty(that->ref); } + + void Ref::Clear(Data *that) const + { CheckRef(that); return that->ref->vtable->Clear(that->ref); } + + Variant::List &Ref::AsList(Data *that) const + { CheckRef(that); return that->ref->vtable->AsList(that->ref); } + + const Variant::List &Ref::AsListConst(const Data *that) const + { CheckRef(that); return that->ref->vtable->AsListConst(that->ref); } + + bool Ref::ContainsIndex(const Data *that, unsigned i) const + { CheckRef(that); return that->ref->vtable->ContainsIndex(that->ref, i); } + + unsigned Ref::Index(const Data *that, Variant v) const + { CheckRef(that); return that->ref->vtable->Index(that->ref, v); } + + void Ref::EraseIndex(Data *that, unsigned i) const + { CheckRef(that); return that->ref->vtable->EraseIndex(that->ref, i); } + + VariantRef Ref::GetRefIndex(Data *that, unsigned i, Variant *def) const + { CheckRef(that); return that->ref->vtable->GetRefIndex(that->ref, i , def); } + + const Variant *Ref::GetConstIndex(const Data *that, unsigned i, bool checked) const + { CheckRef(that); return that->ref->vtable->GetConstIndex(that->ref, i, checked); } + + Variant *Ref::GetIndex(Data *that, unsigned i, bool checked) const + { CheckRef(that); return that->ref->vtable->GetIndex(that->ref, i, checked); } + + void Ref::SetIndex(Data *that, unsigned i, const Data *other) const + { CheckRef(that); that->ref->vtable->SetIndex(that->ref, i, other); } + + Variant::Map &Ref::AsMap(Data *that) const + { CheckRef(that); return that->ref->vtable->AsMap(that->ref); } + + const Variant::Map &Ref::AsMapConst(const Data *that) const + { CheckRef(that); return that->ref->vtable->AsMapConst(that->ref); } + + bool Ref::ContainsKey(const Data *that, const std::string &s) const + { CheckRef(that); return that->ref->vtable->ContainsKey(that->ref, s); } + + void Ref::EraseKey(Data *that, const std::string &key) const + { CheckRef(that); return that->ref->vtable->EraseKey(that->ref, key); } + + VariantRef Ref::GetRefKey(Data *that, const std::string &s, Variant *def) const + { CheckRef(that); return that->ref->vtable->GetRefKey(that->ref, s, def); } + + const Variant *Ref::GetConstKey(const Data *that, const std::string &s, bool checked) const + { CheckRef(that); return that->ref->vtable->GetConstKey(that->ref, s, checked); } + + Variant *Ref::GetKey(Data *that, const std::string &s, bool checked) const + { CheckRef(that); return that->ref->vtable->GetKey(that->ref, s, checked); } + + void Ref::SetKey(Data *that, const std::string &s, const Data *other) const + { CheckRef(that); that->ref->vtable->SetKey(that->ref, s, other); } + + int Ref::Compare(const Data *that, const Data *other) const + { CheckRef(that); return that->ref->vtable->Compare(that->ref, other); } + + void Ref::Incr(Data *that) const + { CheckRef(that); that->ref->vtable->Incr(that->ref); } + + void Ref::Decr(Data *that) const + { CheckRef(that); that->ref->vtable->Decr(that->ref); } + + Variant Ref::Neg(const Data *that) const + { CheckRef(that); return that->ref->vtable->Neg(that->ref); } + + void Ref::Add(Data *that, const Data *other) const + { CheckRef(that); that->ref->vtable->Add(that->ref, other); } + + void Ref::Sub(Data *that, const Data *other) const + { CheckRef(that); that->ref->vtable->Sub(that->ref, other); } + + void Ref::Mul(Data *that, const Data *other) const + { CheckRef(that); that->ref->vtable->Mul(that->ref, other); } + + void Ref::Div(Data *that, const Data *other) const + { CheckRef(that); that->ref->vtable->Div(that->ref, other); } + + void Ref::Rem(Data *that, const Data *other) const + { CheckRef(that); that->ref->vtable->Rem(that->ref, other); } + + void Ref::Destroy(Data *that) const { + VTable::Destroy(that); + that->ref = 0; + } + + void Ref::Destruct(Data *that) const { + Destroy(that); + that->ref_data.reset(); + } + + Variant *Ref::Resolve(Data *that) const + { CheckRef(that); return that->ref->vtable->Resolve(that->ref); } + + const Variant *Ref::ResolveConst(const Data *that) const + { CheckRef(that); return that->ref->vtable->ResolveConst(that->ref); } + + Variant *Ref::ResolveDefault(Data *that, const Data *def) const + { CheckRef(that); return that->ref->vtable->ResolveDefault(that->ref, def); } + + bool Ref::Exists(const Data *that) const { + return (that->ref != 0) && (that->ref_data->valid == true); + } + + void RefInit(Data *that, const Data *other) { + static const Ref ref_vtable; + if (that->vtable) that->vtable->Destroy(that); + that->vtable = &ref_vtable; + // XXX: const cast.. double ICKY! + that->ref = const_cast(other); + that->ref_data = that->ref->vtable->EnsureRef(that->ref); + } + + //-------------------- + // ProxyVTable + //-------------------- + + class Proxy : public VTable { + public: + Proxy() {} + virtual void Copy(const Data *that, Data *other) const; + virtual void Assign(const Data *that, Data *other) const; + virtual void MakeRef(const Data *that, Data *ref) const; + virtual void MakeProxy(Data *that, Data *ref, Path::const_iterator b, Path::const_iterator e) const; + virtual Variant::Type_t GetType(const Data *that) const; + virtual bool AsBool(const Data *that) const; + virtual long double AsLongDouble(const Data *that) const; + virtual uintmax_t AsUnsigned(const Data *that) const; + virtual intmax_t AsInt(const Data *that) const; + virtual std::string AsString(const Data *that) const; + virtual BlobPtr AsBlob(Data *that) const; + virtual ConstBlobPtr AsBlobConst(const Data *that) const; + virtual unsigned Size(const Data *that) const; + virtual bool Empty(const Data *that) const; + virtual void Clear(Data *that) const; + virtual Variant::List &AsList(Data *that) const; + virtual const Variant::List &AsListConst(const Data *that) const; + virtual bool ContainsIndex(const Data *that, unsigned i) const; + virtual unsigned Index(const Data *that, Variant v) const; + virtual void EraseIndex(Data *that, unsigned i) const; + virtual VariantRef GetRefIndex(Data *that, unsigned i, Variant *def) const; + virtual const Variant *GetConstIndex(const Data *that, unsigned i, bool checked) const; + virtual Variant *GetIndex(Data *that, unsigned i, bool checked) const; + virtual void SetIndex(Data *that, unsigned i, const Data *other) const; + virtual Variant::Map &AsMap(Data *that) const; + virtual const Variant::Map &AsMapConst(const Data *that) const; + virtual bool ContainsKey(const Data *that, const std::string &s) const; + virtual void EraseKey(Data *that, const std::string &key) const; + virtual VariantRef GetRefKey(Data *that, const std::string &s, Variant *def) const; + virtual const Variant *GetConstKey(const Data *that, const std::string &s, bool checked) const; + virtual Variant *GetKey(Data *that, const std::string &s, bool checked) const; + virtual void SetKey(Data *that, const std::string &s, const Data *other) const; + virtual int Compare(const Data *that, const Data *other) const; + virtual void Incr(Data *that) const; + virtual void Decr(Data *that) const; + virtual Variant Neg(const Data *that) const; + virtual void Add(Data *that, const Data *other) const; + virtual void Sub(Data *that, const Data *other) const; + virtual void Mul(Data *that, const Data *other) const; + virtual void Div(Data *that, const Data *other) const; + virtual void Rem(Data *that, const Data *other) const; + virtual void Destroy(Data *that) const; + virtual void Destruct(Data *that) const; + virtual Variant *Resolve(Data *that) const; + virtual const Variant *ResolveConst(const Data *that) const; + virtual Variant *ResolveDefault(Data *that, const Data *def) const; + virtual bool Exists(const Data *that) const; + }; + + bool ProxyResolveCheck(const Data *that) { + CheckRef(that); + Data *ref = that->proxy->ref; + const Variant *result = ref->vtable->GetPathConst(ref, that->proxy->path.begin(), + that->proxy->path.end(), false); + if (result) { + const Data *res = VTable::GetData(result); + // XXX: Const cast, ICKY! I don't know how to do this without making all of Data mutable... + res->vtable->MakeRef(res, const_cast(that)); + return true; + } + return false; + } + + void ProxyResolveThrow(const Data *that) { + CheckRef(that); + Data *ref = that->proxy->ref; + const Variant *result = ref->vtable->GetPathConst(ref, that->proxy->path.begin(), + that->proxy->path.end(), true); + const Data *res = VTable::GetData(result); + // XXX: Const cast, ICKY! I don't know how to do this without making all of Data mutable... + res->vtable->MakeRef(res, const_cast(that)); + } + + void ProxyResolveCreate(Data *that) { + CheckRef(that); + Variant tmp_null; + Data *ref = that->proxy->ref; + VariantRef result = ref->vtable->GetPathRef(ref, that->proxy->path.begin(), + that->proxy->path.end(), &tmp_null); + Data *res = VTable::GetData(&result); + res->vtable->MakeRef(res, that); + } + + + void Proxy::Copy(const Data *that, Data *other) const + { ProxyResolveThrow(that); that->vtable->Copy(that, other); } + + void Proxy::Assign(const Data *that, Data *other) const + { ProxyResolveThrow(that); that->vtable->Assign(that, other); } + + void Proxy::MakeRef(const Data *that, Data *ref) const { + CheckRef(that); + ProxyInit(ref, that->proxy->ref, that->proxy->path.begin(), that->proxy->path.end()); + } + + void Proxy::MakeProxy(Data *that, Data *ref, Path::const_iterator b, Path::const_iterator e) const + { + CheckRef(that); + Path newpath = that->proxy->path; + newpath.insert(newpath.end(), b, e); + ProxyInit(ref, that->proxy->ref, newpath.begin(), newpath.end()); + } + + VariantDefines::Type_t Proxy::GetType(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->GetType(that); } + + bool Proxy::AsBool(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->AsBool(that); } + + long double Proxy::AsLongDouble(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->AsLongDouble(that); } + + uintmax_t Proxy::AsUnsigned(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->AsUnsigned(that); } + + intmax_t Proxy::AsInt(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->AsInt(that); } + + std::string Proxy::AsString(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->AsString(that); } + + BlobPtr Proxy::AsBlob(Data *that) const + { ProxyResolveThrow(that); return that->vtable->AsBlob(that); } + + ConstBlobPtr Proxy::AsBlobConst(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->AsBlobConst(that); } + + unsigned Proxy::Size(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->Size(that); } + + bool Proxy::Empty(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->Empty(that); } + + void Proxy::Clear(Data *that) const + { ProxyResolveThrow(that); return that->vtable->Clear(that); } + + Variant::List &Proxy::AsList(Data *that) const + { ProxyResolveCreate(that); return that->vtable->AsList(that); } + + const Variant::List &Proxy::AsListConst(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->AsListConst(that); } + + bool Proxy::ContainsIndex(const Data *that, unsigned i) const + { ProxyResolveThrow(that); return that->vtable->ContainsIndex(that, i); } + + unsigned Proxy::Index(const Data *that, Variant v) const + { ProxyResolveThrow(that); return that->vtable->Index(that, v); } + + void Proxy::EraseIndex(Data *that, unsigned i) const + { ProxyResolveThrow(that); return that->vtable->EraseIndex(that, i); } + + VariantRef Proxy::GetRefIndex(Data *that, unsigned i, Variant *def) const + { + if (def) { + ProxyResolveCreate(that); + return that->vtable->GetRefIndex(that, i, def); + } + if (ProxyResolveCheck(that)) { + return that->vtable->GetRefIndex(that, i, def); + } else { + Path path = that->proxy->path; + path.push_back(i); + return VariantRef(*VTable::GetVar(that->proxy->ref), path); + } + } + + const Variant *Proxy::GetConstIndex(const Data *that, unsigned i, bool checked) const + { ProxyResolveThrow(that); return that->vtable->GetConstIndex(that, i, checked); } + + Variant *Proxy::GetIndex(Data *that, unsigned i, bool checked) const + { + if (ProxyResolveCheck(that)) { + return that->vtable->GetIndex(that, i, checked); + } else if (checked) { + throw std::out_of_range("Variant::List index out of range."); + } else { + return 0; + } + } + + void Proxy::SetIndex(Data *that, unsigned i, const Data *other) const + { ProxyResolveCreate(that); return that->vtable->SetIndex(that, i, other); } + + Variant::Map &Proxy::AsMap(Data *that) const + { ProxyResolveCreate(that); return that->vtable->AsMap(that); } + + const Variant::Map &Proxy::AsMapConst(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->AsMapConst(that); } + + bool Proxy::ContainsKey(const Data *that, const std::string &s) const + { ProxyResolveThrow(that); return that->vtable->ContainsKey(that, s); } + + void Proxy::EraseKey(Data *that, const std::string &key) const + { ProxyResolveThrow(that); return that->vtable->EraseKey(that, key); } + + VariantRef Proxy::GetRefKey(Data *that, const std::string &s, Variant *def) const + { + if (def) { + ProxyResolveCreate(that); + return that->vtable->GetRefKey(that, s, def); + } + if (ProxyResolveCheck(that)) { + return that->vtable->GetRefKey(that, s, def); + } else { + Path path = that->proxy->path; + path.push_back(s); + return VariantRef(*VTable::GetVar(that->proxy->ref), path); + } + } + + const Variant *Proxy::GetConstKey(const Data *that, const std::string &s, bool checked) const + { ProxyResolveThrow(that); return that->vtable->GetConstKey(that, s, checked); } + + Variant *Proxy::GetKey(Data *that, const std::string &s, bool checked) const + { + if (ProxyResolveCheck(that)) { + return that->vtable->GetKey(that, s, checked); + } else if (checked) { + throw KeyError(s); + } else { + return 0; + } + } + + void Proxy::SetKey(Data *that, const std::string &s, const Data *other) const + { ProxyResolveCreate(that); return that->vtable->SetKey(that, s, other); } + + int Proxy::Compare(const Data *that, const Data *other) const + { ProxyResolveThrow(that); return that->vtable->Compare(that, other); } + + void Proxy::Incr(Data *that) const + { ProxyResolveThrow(that); return that->vtable->Incr(that); } + + void Proxy::Decr(Data *that) const + { ProxyResolveThrow(that); return that->vtable->Decr(that); } + + Variant Proxy::Neg(const Data *that) const + { ProxyResolveThrow(that); return that->vtable->Neg(that); } + + void Proxy::Add(Data *that, const Data *other) const + { ProxyResolveThrow(that); return that->vtable->Add(that, other); } + + void Proxy::Sub(Data *that, const Data *other) const + { ProxyResolveThrow(that); return that->vtable->Sub(that, other); } + + void Proxy::Mul(Data *that, const Data *other) const + { ProxyResolveThrow(that); return that->vtable->Mul(that, other); } + + void Proxy::Div(Data *that, const Data *other) const + { ProxyResolveThrow(that); return that->vtable->Div(that, other); } + + void Proxy::Rem(Data *that, const Data *other) const + { ProxyResolveThrow(that); return that->vtable->Rem(that, other); } + + void Proxy::Destroy(Data *that) const { + VTable::Destroy(that); + that->proxy = 0; + } + + void Proxy::Destruct(Data *that) const { + Destroy(that); + that->ref_data.reset(); + } + + Variant *Proxy::Resolve(Data *that) const { + ProxyResolveCreate(that); + return that->vtable->Resolve(that); + } + + const Variant *Proxy::ResolveConst(const Data *that) const { + ProxyResolveThrow(that); + return that->vtable->ResolveConst(that); + } + + Variant *Proxy::ResolveDefault(Data *that, const Data *def) const { + ProxyResolveCreate(that); + return that->vtable->ResolveDefault(that, def); + } + + bool Proxy::Exists(const Data *that) const { + if (!that->ref_data || !that->ref_data->valid) { + return false; + } + Data *ref = that->proxy->ref; + const Variant *result = ref->vtable->GetPathConst(ref, that->proxy->path.begin(), + that->proxy->path.end(), false); + return result != 0; + } + + void ProxyInit(Data *that, Data *ref, Path::const_iterator b, Path::const_iterator e) { + static const Proxy proxy_vtable; + if (that->vtable) that->vtable->Destroy(that); + that->vtable = &proxy_vtable; + that->ref_data = ref->vtable->EnsureRef(ref); + shared_ptr storage(new ProxyStorage(ref, b, e)); + that->proxy = storage.get(); + that->storage = storage; + } + + + //------------------- + + void DefaultInit(Data *that, VariantDefines::Type_t type) { + switch (type) { + case VariantDefines::NullType: + NullInit(that); + break; + case VariantDefines::BoolType: + BoolInit(that, false); + break; + case VariantDefines::IntegerType: + IntegerInit(that, 0); + break; + case VariantDefines::UnsignedType: + UnsignedInit(that, 0u); + break; + case VariantDefines::FloatType: + FloatInit(that, 0.0); + break; + case VariantDefines::StringType: + StringInit(that, ""); + break; + case VariantDefines::ListType: + ListInit(that, Variant::List()); + break; + case VariantDefines::MapType: + MapInit(that, Variant::Map()); + break; + case VariantDefines::BlobType: + BlobInit(that, BlobPtr()); + break; + } + } + + Data::Data() : vtable(NullVTable()) {} + } + + //-------------------- + // Variant + //-------------------- + + Variant::Variant(const RefTag &, const Variant &o) + { + o.vtable->MakeRef(&o, this); + } + + Variant::Variant(const RefTag &, Variant &o, Path::const_iterator b, Path::const_iterator e) + { + o.vtable->MakeProxy(&o, this, b, e); + } + + Variant::~Variant() { + vtable->Destruct(this); + } + + VariantDefines::Type_t Variant::GetType() const + { return vtable->GetType(this); } + + bool Variant::AsBool() const + { return vtable->AsBool(this); } + + long double Variant::AsLongDouble() const + { return vtable->AsLongDouble(this); } + + uintmax_t Variant::AsUnsigned() const + { return vtable->AsUnsigned(this); } + + intmax_t Variant::AsInt() const + { return vtable->AsInt(this); } + + std::string Variant::AsString() const + { return vtable->AsString(this); } + + BlobPtr Variant::AsBlob() + { return vtable->AsBlob(this); } + + ConstBlobPtr Variant::AsBlob() const + { return vtable->AsBlobConst(this); } + + unsigned Variant::Size() const + { return vtable->Size(this); } + + bool Variant::Empty() const + { return vtable->Empty(this); } + + void Variant::Clear() + { vtable->Clear(this); } + + Variant::List &Variant::AsList() + { return vtable->AsList(this); } + + const Variant::List &Variant::AsList() const + { return vtable->AsListConst(this); } + + VariantRef Variant::At(unsigned i) + { return vtable->GetRefIndex(this, i, 0); } + + VariantRef Variant::At(unsigned i, Variant def) + { return vtable->GetRefIndex(this, i, &def); } + + const Variant &Variant::At(unsigned i) const + { return *vtable->GetConstIndex(this, i, true); } + + Variant Variant::Get(unsigned i) const + { return *vtable->GetConstIndex(this, i, true); } + + Variant Variant::Get(unsigned i, Variant def) const { + const Variant *ret = vtable->GetConstIndex(this, i, false); + if (ret) { return *ret; } + else { return def; } + } + + Variant &Variant::Set(unsigned i, Variant v) { + vtable->SetIndex(this, i, &v); + return *this; + } + + Variant &Variant::Append(Variant value) { + vtable->AsList(this).push_back(value); + return *this; + } + + bool Variant::Contains(unsigned i) const + { return vtable->ContainsIndex(this, i); } + + unsigned Variant::Index(Variant v) const + { return vtable->Index(this, v); } + + void Variant::Erase(unsigned i) + { vtable->EraseIndex(this, i); } + + Variant::Map &Variant::AsMap() + { return vtable->AsMap(this); } + + const Variant::Map &Variant::AsMap() const + { return vtable->AsMapConst(this); } + + VariantRef Variant::At(const std::string &s) + { return vtable->GetRefKey(this, s, 0); } + + VariantRef Variant::At(const std::string &s, Variant def) + { return vtable->GetRefKey(this, s, &def); } + + const Variant &Variant::At(const std::string &s) const + { return *vtable->GetConstKey(this, s, true); } + + Variant Variant::Get(const std::string &s) const + { return *vtable->GetConstKey(this, s, true); } + + Variant Variant::Get(const std::string &s, Variant def) const { + const Variant *ret = vtable->GetConstKey(this, s, false); + if (ret) { return *ret; } + else { return def; } + } + + Variant &Variant::Set(const std::string &s, Variant v) { + vtable->SetKey(this, s, &v); + return *this; + } + + bool Variant::Contains(const std::string &s) const + { return vtable->ContainsKey(this, s); } + + void Variant::Erase(const std::string &key) + { vtable->EraseKey(this, key); } + + VariantRef Variant::AtPath(const Path &path) + { return vtable->GetPathRef(this, path.begin(), path.end(), 0); } + + VariantRef Variant::AtPath(const Path &path, Variant def) + { return vtable->GetPathRef(this, path.begin(), path.end(), &def); } + + const Variant &Variant::AtPath(const Path &path) const + { return *vtable->GetPathConst(this, path.begin(), path.end(), true); } + + Variant Variant::GetPath(const Path &path) const + { return *vtable->GetPathConst(this, path.begin(), path.end(), true); } + + Variant Variant::GetPath(const Path &path, Variant def) const { + const Variant *ret = vtable->GetPathConst(this, path.begin(), path.end(), false); + if (ret) { return *ret; } + else { return def; } + } + + Variant &Variant::SetPath(const Path &path, Variant val) { + vtable->SetPath(this, path.begin(), path.end(), &val); + return *this; + } + + Variant &Variant::ErasePath(const Path &path, bool remove_empty) { + vtable->ErasePath(this, path.begin(), path.end(), remove_empty); + return *this; + } + + bool Variant::HasPath(const Path &path) const { + return vtable->GetPathConst(this, path.begin(), path.end(), false) != 0; + } + + void Variant::Merge(Variant other) { + for (ConstMapIterator i(other.MapBegin()), e(other.MapEnd()); i != e; ++i) { + this->Set(i->first, i->second); + } + } + + int Variant::Compare(const Variant &other) const + { return vtable->Compare(this, &other); } + + bool Variant::Comparable(const Variant &other) const + { return vtable->Comparable(this, &other); } + + void Variant::Incr() { + vtable->Incr(this); + } + + void Variant::Decr() { + vtable->Decr(this); + } + + void Variant::Add(const Variant &o){ + vtable->Add(this, &o); + } + + void Variant::Sub(const Variant &o){ + vtable->Sub(this, &o); + } + + void Variant::Mul(const Variant &o){ + vtable->Mul(this, &o); + } + + void Variant::Div(const Variant &o){ + vtable->Div(this, &o); + } + + void Variant::Rem(const Variant &o){ + vtable->Rem(this, &o); + } + + Variant Variant::Neg() const + { return vtable->Neg(this); } + + VariantRef Variant::Ref() { + return VariantRef(*this); + } + + Variant Variant::Copy() const { + Variant result; + vtable->Copy(this, &result); + return result; + } + + Variant &Variant::Resolve() { + return *vtable->Resolve(this); + } + + const Variant &Variant::Resolve() const { + return *vtable->ResolveConst(this); + } + + Variant &Variant::Resolve(const Variant &def) { + return *vtable->ResolveDefault(this, &def); + } + + bool Variant::Exists() const { + return vtable->Exists(this); + } + + void Variant::Assign(const Variant &other) + { other.vtable->Assign(&other, this); } + + void Variant::Assign(VariantDefines::Type_t type) + { DefaultInit(vtable->Resolve(this), type); } + + void Variant::Assign(bool v) + { Internal::BoolInit(vtable->Resolve(this), v); } + + void Variant::Assign(int v) + { Internal::IntegerInit(vtable->Resolve(this), v); } + + void Variant::Assign(unsigned v) + { Internal::UnsignedInit(vtable->Resolve(this), v); } + + void Variant::Assign(long v) + { Internal::IntegerInit(vtable->Resolve(this), v); } + + void Variant::Assign(unsigned long v) + { Internal::UnsignedInit(vtable->Resolve(this), v); } + + void Variant::Assign(long long v) + { Internal::IntegerInit(vtable->Resolve(this), v); } + + void Variant::Assign(unsigned long long v) + { Internal::UnsignedInit(vtable->Resolve(this), v); } + + void Variant::Assign(double v) + { Internal::FloatInit(vtable->Resolve(this), v); } + + void Variant::Assign(long double v) + { Internal::FloatInit(vtable->Resolve(this), v); } + + void Variant::Assign(BlobPtr b) + { Internal::BlobInit(vtable->Resolve(this), b); } + + void Variant::Assign(const std::string &v) + { Internal::StringInit(vtable->Resolve(this), v); } + + void Variant::Assign(const char *v) + { Internal::StringInit(vtable->Resolve(this), v); } + + void Variant::ReassignRef(const Variant &o) { + o.vtable->MakeRef(&o, this); + } +} diff --git a/src/hos_libvariant/src/src/VariantEmitting.cc b/src/hos_libvariant/src/src/VariantEmitting.cc new file mode 100644 index 00000000..5429e0ca --- /dev/null +++ b/src/hos_libvariant/src/src/VariantEmitting.cc @@ -0,0 +1,110 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#include +#include +#include +#include +#include + +namespace libvariant { + + Emitter &operator<<(Emitter &e, const Variant &v) { + switch (v.GetType()) { + case Variant::NullType: + e.EmitNull(); + break; + case Variant::BoolType: + if (v.AsBool()) { + e.EmitTrue(); + } else { + e.EmitFalse(); + } + break; + case Variant::IntegerType: + e.Emit(v.AsInt()); + break; + case Variant::UnsignedType: + e.Emit(v.AsUnsigned()); + break; + case Variant::FloatType: + e.Emit(v.AsDouble()); + break; + case Variant::StringType: + e.Emit(v.AsString()); + break; + case Variant::ListType: + e << v.AsList(); + break; + case Variant::MapType: + e << v.AsMap(); + break; + case Variant::BlobType: + e << v.AsBlob(); + break; + default: + throw UnknownTypeError(v.GetType()); + } + return e; + } + + std::string Serialize(Variant v, SerializeType type, Variant params) { + std::ostringstream oss; + Serialize(oss.rdbuf(), v, type, params); + return oss.str(); + + } + + void Serialize(const std::string &filename, Variant v, SerializeType type, + Variant params) { + Emitter emitter = CreateEmitter(CreateEmitterOutput(filename.c_str()), type, params); + emitter << v; + emitter.Close(); + } + + void Serialize(FILE *f, Variant v, SerializeType type, + Variant params) { + Emitter emitter = CreateEmitter(CreateEmitterOutput(f), type, params); + emitter << v; + emitter.Close(); + } + + void Serialize(std::streambuf *sb, Variant v, SerializeType type, + Variant params) { + Emitter emitter = CreateEmitter(CreateEmitterOutput(sb), type, params); + emitter << v; + emitter.Close(); + + } + + unsigned Serialize(void *ptr, unsigned len, Variant v, SerializeType type, + Variant params) { + unsigned out_len = 0; + Emitter emitter = CreateEmitter(CreateEmitterOutput(ptr, len, &out_len), type, params); + emitter << v; + emitter.Close(); + return out_len; + } +} + +void VariantPrint(const libvariant::Variant v) { + libvariant::SerializeJSON(stderr, v, true); + fprintf(stderr, "\n"); +} diff --git a/src/hos_libvariant/src/src/VariantParsing.cc b/src/hos_libvariant/src/src/VariantParsing.cc new file mode 100644 index 00000000..4bb32f07 --- /dev/null +++ b/src/hos_libvariant/src/src/VariantParsing.cc @@ -0,0 +1,345 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#include +#include +#include +#include +#include +#include + +#if 0 +#include +#include +#define ANCHOR (anchor ? anchor : "") +#define TAG (tag ? tag : "") +#define DBTRACE(args) do {\ + for (int i = Level(); i > 0; --i) { std::cerr << ". "; }\ + std::cerr << args << std::endl;\ +} while (false) +#else +#define DBTRACE(args) +#endif + +namespace libvariant { + + typedef std::map AnchorMap; + + class ParserState { + public: + + ParserState() + {} + + void Anchor(const char *anchor, Variant v) { + if (anchor) { anchors.insert(std::make_pair(std::string(anchor), v)); } + } + + Variant Anchor(const char *anchor) { + return anchors.at(anchor); + } + + AnchorMap anchors; + Variant result; + }; + + class VariantBaseParserActions : public ParserActions { + public: + VariantBaseParserActions(ParserState *s, VariantBaseParserActions *b) + : done(false), seen_begin_document(false), state(s), base(b) + {} + + virtual void BeginDocument(ParserImpl *p) { + DBTRACE("BeginDocument"); + seen_begin_document = true; + } + virtual void EndDocument(ParserImpl *p) { + DBTRACE("EndDocument"); + Finish(p); + } + + virtual void BeginMap(ParserImpl *p, int length, const char *anchor, const char *tag); + virtual void BeginList(ParserImpl *p, int length, const char *anchor, const char *tag); + + virtual void Alias(ParserImpl *p, const char *anchor) { + DBTRACE("Alias (" << ANCHOR << ")"); + SetValue(p, state->Anchor(anchor), 0); + } + virtual void Scalar(ParserImpl *p, double v, const char *anchor, const char *tag) { + DBTRACE("Scalar(" << v << ", " << ANCHOR << ", " << TAG << ")"); + SetValue(p, v, anchor); + } + virtual void Scalar(ParserImpl *p, const char *str, unsigned length, const char *anchor, const char *tag) { + DBTRACE("Scalar(" << std::string(str, length) << ", " << ANCHOR << ", " << TAG << ")"); + SetValue(p, std::string(str, length), anchor); + } + virtual void Scalar(ParserImpl *p, bool v, const char *anchor, const char *tag) { + DBTRACE("Scalar(" << v << ", " << ANCHOR << ", " << TAG << ")"); + SetValue(p, v, anchor); + } + virtual void Null(ParserImpl *p, const char *anchor, const char *tag) { + DBTRACE("Scalar( null, " << ANCHOR << ", " << TAG << ")"); + SetValue(p, Variant::NullType, anchor); + } + virtual void Scalar(ParserImpl *p, intmax_t v, const char *anchor, const char *tag) { + DBTRACE("Scalar(" << v << ", " << ANCHOR << ", " << TAG << ")"); + SetValue(p, v, anchor); + } + virtual void Scalar(ParserImpl *p, uintmax_t v, const char *anchor, const char *tag) { + DBTRACE("Scalar(" << v << ", " << ANCHOR << ", " << TAG << ")"); + SetValue(p, v, anchor); + } + virtual void Scalar(ParserImpl *p, BlobPtr b, const char *anchor, const char *tag) { + DBTRACE("Scalar(blob, " << ANCHOR << ", " << TAG << ")"); + SetValue(p, b, anchor); + } + + virtual void SetValue(ParserImpl *p, Variant v, const char *anchor) { + state->Anchor(anchor, v); + result = v; + if (anchor) { this->anchor = anchor; } + if (!seen_begin_document) { + Finish(p); + } + } + + void Finish(ParserImpl *p) { + if (base) { + base->SetValue(p, result, (anchor.empty() ? 0 : anchor.c_str())); + } else { + state->result = result; + } + done = true; + p->PopAction(); + } + + int Level() { + if (base) { return base->Level() + 1; } + else { return 1; } + } + + Variant result; + bool done; + bool seen_begin_document; + ParserState *state; + VariantBaseParserActions *base; + std::string anchor; + }; + + class VariantMapParserActions : public VariantBaseParserActions { + public: + VariantMapParserActions(ParserState *s, VariantBaseParserActions *b) + : VariantBaseParserActions(s, b), expect_key(true) + { + result = Variant::MapType; + } + + virtual void EndMap(ParserImpl *p) { + DBTRACE("EndMap"); + Finish(p); + } + + virtual void SetValue(ParserImpl *p, Variant v, const char *anchor) { + if (expect_key) { + key = v.AsString(); + expect_key = false; + } else { + state->Anchor(anchor, v); + result[key] = v; + expect_key = true; + } + } + + bool expect_key; + std::string key; + }; + + void VariantBaseParserActions::BeginMap(ParserImpl *p, int length, const char *anchor, const char *tag) { + DBTRACE("BeginMap(" << ANCHOR << ", " << TAG << ")"); + shared_ptr actions(new VariantMapParserActions(state, this)); + if (anchor) { actions->anchor = anchor; } + p->PushAction(actions); + } + + class VariantListParserActions : public VariantBaseParserActions { + public: + VariantListParserActions(ParserState *s, VariantBaseParserActions *b) + : VariantBaseParserActions(s, b) + { + result = Variant::ListType; + } + + virtual void EndList(ParserImpl *p) { + DBTRACE("EndList"); + Finish(p); + } + + virtual void SetValue(ParserImpl *p, Variant v, const char *anchor) { + state->Anchor(anchor, v); + result.Append(v); + } + + }; + + void VariantBaseParserActions::BeginList(ParserImpl *p, int length, const char *anchor, const char *tag) { + DBTRACE("BeginList(" << ANCHOR << ", " << TAG << ")"); + shared_ptr actions(new VariantListParserActions(state, this)); + if (anchor) { actions->anchor = anchor; } + p->PushAction(actions); + } + + Variant ParseVariant(Parser &p) { + ParserState state; + shared_ptr actions(new VariantBaseParserActions(&state, 0)); + p.PushAction(actions); + while (p.Run() == 0 && !actions->done); + return state.result; + } + + Variant Deserialize(const std::string &str, SerializeType type) { + return Deserialize(str.c_str(), str.length(), type); + } + + Variant Deserialize(const char *str, SerializeType type) { + return Deserialize(str, strlen(str), type); + } + + Variant Deserialize(const void *ptr, unsigned len, SerializeType type) { + Parser parser = CreateParser(CreateParserInput(ptr, len), type); + return ParseVariant(parser); + } + + Variant DeserializeFile(const char *filename, SerializeType type) { + Parser parser = CreateParser(CreateParserInputFile(filename), type); + return ParseVariant(parser); + } + + Variant DeserializeFile(FILE *f, SerializeType type) { + Parser parser = CreateParser(CreateParserInputFile(f), type); + return ParseVariant(parser); + } + + Variant DeserializeFile(std::streambuf *sb, SerializeType type) { + Parser parser = CreateParser(CreateParserInputFile(sb), type); + return ParseVariant(parser); + } + + Variant DeserializeGuess(const std::string &str) { + return DeserializeGuess(str.c_str(), str.length()); + } + Variant DeserializeGuess(const char *str) { + return DeserializeGuess(str, strlen(str)); + } + Variant DeserializeGuess(const void *ptr, unsigned len) { + Parser parser = CreateParserGuess(CreateParserInput(ptr, len) ); + return ParseVariant(parser); + } + Variant DeserializeGuessFile(const char *filename) { + Parser parser = CreateParserGuess(CreateParserInputFile(filename)); + return ParseVariant(parser); + } + Variant DeserializeGuessFile(FILE *f) { + Parser parser = CreateParserGuess(CreateParserInputFile(f)); + return ParseVariant(parser); + } + Variant DeserializeGuessFile(std::streambuf *sb) { + Parser parser = CreateParserGuess(CreateParserInputFile(sb)); + return ParseVariant(parser); + } + + LoadAllIterator DeserializeAll(const std::string &str, SerializeType type) { + return DeserializeAll(str.c_str(), str.length(), type); + } + + LoadAllIterator DeserializeAll(const char *str, SerializeType type) { + return DeserializeAll(str, strlen(str), type); + } + + LoadAllIterator DeserializeAll(const void *ptr, unsigned len, SerializeType type) { + Parser parser = CreateParser(CreateParserInput(ptr, len), type); + return LoadAllIterator(parser); + } + + LoadAllIterator DeserializeAllFile(const char *filename, SerializeType type) { + Parser parser = CreateParser(CreateParserInputFile(filename), type); + return LoadAllIterator(parser); + } + + LoadAllIterator DeserializeAllFile(FILE *f, SerializeType type) { + Parser parser = CreateParser(CreateParserInputFile(f), type); + return LoadAllIterator(parser); + } + + LoadAllIterator DeserializeAllFile(std::streambuf *sb, SerializeType type) { + Parser parser = CreateParser(CreateParserInputFile(sb), type); + return LoadAllIterator(parser); + } + + + class LoadAllIterator::Impl { + public: + Impl(Parser p) : parser(p) {} + Parser parser; + }; + + struct LoadAllIterator::Value { + Value(Variant v_) :v(v_) {} + Variant v; + shared_ptr next; + }; + + LoadAllIterator::LoadAllIterator() + {} + + LoadAllIterator::LoadAllIterator(Parser &parser) + : impl(new Impl(parser)) + { + Next(); + } + + Variant &LoadAllIterator::Get() { + if (!value) { throw std::out_of_range("LoadAllIterator: Trying to reach past the end."); } + return value->v; + } + + void LoadAllIterator::Next() { + if (!value) { + if (!impl->parser.Done()) { + value = shared_ptr(new Value(ParseVariant(impl->parser))); + } + } else if (value->next) { + value = value->next; + } else { + if (!impl->parser.Done()) { + value->next = shared_ptr(new Value(ParseVariant(impl->parser))); + if (impl->parser.Done() && value->next->v.IsNull()) { + value->next.reset(); + } + } + value = value->next; + } + } + bool LoadAllIterator::operator==(const LoadAllIterator &that) const { + if (value && that.value) { + return value == that.value; + } + return (!value && !that.value); + } +} diff --git a/src/hos_libvariant/src/src/XMLPLISTDefs.h b/src/hos_libvariant/src/src/XMLPLISTDefs.h new file mode 100644 index 00000000..ef7ebe45 --- /dev/null +++ b/src/hos_libvariant/src/src/XMLPLISTDefs.h @@ -0,0 +1,37 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_XMLPLISTDEFS_H +#define VARIANT_XMLPLISTDEFS_H +#pragma once + +#define MAP_NAME "dict" +#define STRING_NAME "string" +#define TRUE_NAME "true" +#define FALSE_NAME "false" +#define INTEGER_NAME "integer" +#define FLOAT_NAME "real" +#define ROOT_NAME "plist" +#define LIST_NAME "array" +#define NULL_NAME "null" +#define KEY_NAME "key" +#define BLOB_NAME "data" + +#endif diff --git a/src/hos_libvariant/src/src/XMLPLISTEmitter.cc b/src/hos_libvariant/src/src/XMLPLISTEmitter.cc new file mode 100644 index 00000000..015b6ed6 --- /dev/null +++ b/src/hos_libvariant/src/src/XMLPLISTEmitter.cc @@ -0,0 +1,217 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ + +#include "XMLPLISTEmitter.h" +#include +#include +#include +#include +#include "XMLPLISTDefs.h" +#include "Base64.h" + +namespace libvariant { + + int XMLPLISTEmitterImpl::DoWrite(void *ctx, const char *buffer, int len) { + XMLPLISTEmitterImpl *impl = (XMLPLISTEmitterImpl*)ctx; + return impl->output->Write(buffer, len); + } + + int XMLPLISTEmitterImpl::DoClose(void *ctx) { + XMLPLISTEmitterImpl *impl = (XMLPLISTEmitterImpl*)ctx; + impl->output->Flush(); + return 0; + } + + XMLPLISTEmitterImpl::XMLPLISTEmitterImpl(shared_ptr out, Variant params) + : output(out), pretty(false), indent(4), + precision(std::numeric_limits::digits10+2), closed(false) + { + if (params.IsMap()) { + params.GetInto(pretty, "pretty", pretty); + params.GetInto(indent, "indent", indent); + params.GetInto(precision, "precision", precision); + } + xmlOutputBufferPtr xmloutput = xmlOutputBufferCreateIO(&XMLPLISTEmitterImpl::DoWrite, + &XMLPLISTEmitterImpl::DoClose, + (void*)this, 0); + if (xmloutput == 0) { + HandleError("xmlOutputBufferCreateIO"); + } + writer = xmlNewTextWriter(xmloutput); + if (writer == 0) { + xmlOutputBufferClose(xmloutput); + HandleError("xmlNewTextWriter"); + } + UpdateParams(); + if (xmlTextWriterStartDocument(writer, 0, 0, "yes") < 0) { + xmlFreeTextWriter(writer); + writer = 0; + HandleError("xmlTextWriterStartDocument"); + } + state.push_back(NONE); + } + + XMLPLISTEmitterImpl::~XMLPLISTEmitterImpl() { + if (!closed) { + xmlTextWriterEndDocument(writer); + xmlTextWriterFlush(writer); + closed = true; + } + xmlFreeTextWriter(writer); + writer = 0; + } + + void XMLPLISTEmitterImpl::BeginDocument() { + StartElement(ROOT_NAME); + } + + void XMLPLISTEmitterImpl::EndDocument() { + CloseElement(); + } + + void XMLPLISTEmitterImpl::BeginMap(int) { + StartElement(MAP_NAME); + state.push_back(EXPECT_MAP_KEY); + } + + void XMLPLISTEmitterImpl::EndMap() { + CloseElement(); + state.pop_back(); + } + + void XMLPLISTEmitterImpl::BeginList(int) { + StartElement(LIST_NAME); + state.push_back(IN_LIST); + } + + void XMLPLISTEmitterImpl::EndList() { + CloseElement(); + state.pop_back(); + } + + void XMLPLISTEmitterImpl::EmitNull() { + StartElement(NULL_NAME); + CloseElement(); + } + + void XMLPLISTEmitterImpl::EmitTrue() { + StartElement(TRUE_NAME); + CloseElement(); + } + + void XMLPLISTEmitterImpl::EmitFalse() { + StartElement(FALSE_NAME); + CloseElement(); + } + + void XMLPLISTEmitterImpl::Emit(const char *v) { + if (state.back() == EXPECT_MAP_KEY) { + StartElement(KEY_NAME, false); + WriteText(v); + CloseElement(); + } else { + StartElement(STRING_NAME); + WriteText(v); + CloseElement(); + } + } + + void XMLPLISTEmitterImpl::Emit(intmax_t v) { + StartElement(INTEGER_NAME); + std::ostringstream oss; + oss << v; + WriteText(oss.str().c_str()); + CloseElement(); + } + + void XMLPLISTEmitterImpl::Emit(uintmax_t v) { + StartElement(INTEGER_NAME); + std::ostringstream oss; + oss << v; + WriteText(oss.str().c_str()); + CloseElement(); + } + + void XMLPLISTEmitterImpl::Emit(double v) { + StartElement(FLOAT_NAME); + std::ostringstream oss; + oss << std::setprecision(precision) << std::showpoint << v; + WriteText(oss.str().c_str()); + CloseElement(); + } + + void XMLPLISTEmitterImpl::Emit(ConstBlobPtr b) { + StartElement(BLOB_NAME); + std::vector buf(Base64EncodeSize(b->GetTotalLength())); + Base64Encode(&buf[0], b->GetIOVec(), b->GetNumBuffers()); + WriteText(&buf[0]); + CloseElement(); + } + + void XMLPLISTEmitterImpl::Flush() { + CheckClosed(); + if (xmlTextWriterFlush(writer) < 0) { + HandleError("xmlTextWriterFlush"); + } + output->Flush(); + } + + void XMLPLISTEmitterImpl::Close() { + if (!closed) { + if (xmlTextWriterEndDocument(writer) < 0) { + HandleError("xmlTextWriterEndDocument"); + } + Flush(); + closed = true; + } + } + + Variant XMLPLISTEmitterImpl::GetParam(const std::string &key) { + if (key == "pretty") { return pretty; } + if (key == "indent") { return indent; } + if (key == "precision") { return precision; } + return Variant::NullType; + } + + Variant XMLPLISTEmitterImpl::GetParams() { + Variant ret; + ret["pretty"] = pretty; + ret["indent"] = indent; + ret["precision"] = precision; + return ret; + } + + void XMLPLISTEmitterImpl::SetParam(const std::string &key, Variant value) { + if (key == "pretty") { pretty = value.AsBool(); } + else if (key == "indent") { indent = value.AsUnsigned(); } + else if (key == "precision") { precision = value.AsUnsigned(); } + UpdateParams(); + } + + void XMLPLISTEmitterImpl::UpdateParams() { + if (pretty) { + xmlTextWriterSetIndent(writer, indent); + } else { + xmlTextWriterSetIndent(writer, 0); + } + } + +} diff --git a/src/hos_libvariant/src/src/XMLPLISTEmitter.h b/src/hos_libvariant/src/src/XMLPLISTEmitter.h new file mode 100644 index 00000000..217d2711 --- /dev/null +++ b/src/hos_libvariant/src/src/XMLPLISTEmitter.h @@ -0,0 +1,133 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief An emitter for the XMLPLIST subset that Variant supports. + * Depends on libxml2. + */ +#ifndef VARIANT_XMLPLISTEMITTER_H +#define VARIANT_XMLPLISTEMITTER_H + +#pragma once +#include "../../src/include/Variant/Emitter.h" +#include +#include +#include + +namespace libvariant { + + /** + * Supported params are: + * + * "pretty": true|false + * "indent": integer (amount to indent for pretty) + * "precision": number of digits for a float + */ + class XMLPLISTEmitterImpl : public EmitterImpl { + enum State { + NONE, + EXPECT_MAP_KEY, + EXPECT_MAP_VALUE, + IN_LIST + }; + public: + + XMLPLISTEmitterImpl(shared_ptr out, Variant params); + ~XMLPLISTEmitterImpl(); + + virtual void BeginDocument(); + virtual void EndDocument(); + virtual void BeginMap(int length); + virtual void EndMap(); + virtual void BeginList(int length); + virtual void EndList(); + + virtual void EmitNull(); + virtual void EmitTrue(); + virtual void EmitFalse(); + virtual void Emit(const char *v); + virtual void Emit(intmax_t v); + virtual void Emit(uintmax_t v); + virtual void Emit(double v); + virtual void Emit(ConstBlobPtr b); + + virtual void Flush(); + virtual void Close(); + + virtual Variant GetParam(const std::string &key); + virtual Variant GetParams(); + virtual void SetParam(const std::string &key, Variant value); + private: + static int DoWrite(void *ctx, const char *buffer, int len); + static int DoClose(void *ctx); + + void HandleError(const char *fnname) { + xmlErrorPtr error = xmlGetLastError(); + if (error) { + throw std::runtime_error(error->message); + } else { + throw std::runtime_error(fnname); + } + } + + void CheckClosed() { + if (closed) { throw std::runtime_error("Cannot operate on a closed XMLPLISTEmitter."); } + } + + void CheckMapKey(bool complex_type) { + if (state.back() == EXPECT_MAP_VALUE) { + state.back() = EXPECT_MAP_KEY; + } else if (state.back() == EXPECT_MAP_KEY) { + if (complex_type) { + throw std::runtime_error("XMLPLISTEmitter does not support non trivial types as keys"); + } + state.back() = EXPECT_MAP_VALUE; + } + } + + void StartElement(const char *name, bool complex_type=true) { + CheckClosed(); + if (xmlTextWriterStartElement(writer, (const xmlChar*)name) < 0) { + HandleError("xmlTextWriterStartElement"); + } + CheckMapKey(complex_type); + } + + void CloseElement() { + CheckClosed(); + if (xmlTextWriterEndElement(writer) < 0) { + HandleError("xmlTextWriterEndElement"); + } + } + + void WriteText(const char *ptr) { + if (xmlTextWriterWriteString(writer, (const xmlChar*)ptr) < 0) { + HandleError("xmlTextWriterWriteString"); + } + } + + void UpdateParams(); + xmlTextWriterPtr writer; + shared_ptr output; + bool pretty; + unsigned indent; + unsigned precision; + bool closed; + std::deque state; + }; +} +#endif diff --git a/src/hos_libvariant/src/src/XMLPLISTParser.cc b/src/hos_libvariant/src/src/XMLPLISTParser.cc new file mode 100644 index 00000000..cfbaf335 --- /dev/null +++ b/src/hos_libvariant/src/src/XMLPLISTParser.cc @@ -0,0 +1,423 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#include "XMLPLISTParser.h" +#include +#include +#include +#include +#include +#include "XMLPLISTDefs.h" +#include "Base64.h" + +namespace libvariant { + + XMLPLISTParserImpl::State_t XMLPLISTParserImpl::StringToNode(const char *name) { + if (!name) { + return StringNode; + } else if (strcasecmp(name, STRING_NAME) == 0) { + return StringNode; + } else if (strcasecmp(name, TRUE_NAME) == 0) { + return TrueNode; + } else if (strcasecmp(name, ROOT_NAME) == 0) { + return RootNode; + } else if (strcasecmp(name, LIST_NAME) == 0) { + return ListNode; + } else if (strcasecmp(name, FALSE_NAME) == 0) { + return FalseNode; + } else if (strcasecmp(name, INTEGER_NAME) == 0) { + return IntegerNode; + } else if (strcasecmp(name, FLOAT_NAME) == 0) { + return FloatNode; + } else if (strcasecmp(name, NULL_NAME) == 0) { + return NullNode; + } else if (strcasecmp(name, MAP_NAME) == 0) { + return MapNode; + } else if (strcasecmp(name, KEY_NAME) == 0) { + return KeyNode; + } else if (strcasecmp(name, BLOB_NAME) == 0) { + return BlobNode; + } else { + return StringNode; + } + } + + int XMLPLISTParserImpl::Run() { + while (!action_stack.empty()) { + if (closed) { return 1; } + bool loop = true; + switch (statestack.back()) { + case StartState: + statestack.back() = EndState; + break; + case EndState: + return 1; + case EmptyMapNode: + statestack.pop_back(); + TopAction()->EndMap(this); + return 0; + case EmptyListNode: + statestack.pop_back(); + TopAction()->EndList(this); + return 0; + case RootNode: + case MapNode: + case ListNode: + break; + default: + err = true; + errorstr = "libvariant XML PLIST parser in an inconsistent state"; + throw std::runtime_error(errorstr); + } + while (loop) { + int ret = xmlTextReaderRead(reader); + if (ret == 1) { + int node_type = xmlTextReaderNodeType(reader); + const char *name = (const char*)xmlTextReaderConstName(reader); + switch (node_type) { + case XML_READER_TYPE_ELEMENT: + loop = BeginElement(TopAction(), StringToNode(name)); + break; + case XML_READER_TYPE_END_ELEMENT: + loop = EndElement(TopAction(), StringToNode(name)); + break; + case XML_READER_TYPE_TEXT: + loop = ProcessText(TopAction()); + break; + case XML_READER_TYPE_END_ENTITY: + case XML_READER_TYPE_ATTRIBUTE: + case XML_READER_TYPE_CDATA: + case XML_READER_TYPE_ENTITY_REFERENCE: + case XML_READER_TYPE_ENTITY: + case XML_READER_TYPE_PROCESSING_INSTRUCTION: + case XML_READER_TYPE_COMMENT: + case XML_READER_TYPE_DOCUMENT: + case XML_READER_TYPE_DOCUMENT_TYPE: + case XML_READER_TYPE_DOCUMENT_FRAGMENT: + case XML_READER_TYPE_NOTATION: + case XML_READER_TYPE_WHITESPACE: + case XML_READER_TYPE_SIGNIFICANT_WHITESPACE: + case XML_READER_TYPE_XML_DECLARATION: + case XML_READER_TYPE_NONE: + default: + break; + } + } else if (ret == 0) { + if (statestack.back() != EndState) { + err = true; + errorstr = "libvariant XML PLIST parser in inconsistent state"; + throw std::runtime_error(errorstr); + } + return 1; + } else { + HandleError("xmlTextReaderRead"); + } + } + } + return 0; + } + + bool XMLPLISTParserImpl::BeginElement(ParserActions *action, State_t nodetype) { + bool empty_node = xmlTextReaderIsEmptyElement(reader) != 0; + switch (nodetype) { + case NullNode: + if (!empty_node) { statestack.push_back(nodetype); } + action->Null(this, 0, 0); + return !empty_node; + case RootNode: + statestack.push_back(nodetype); + action->BeginDocument(this); + return !empty_node; + case TrueNode: + if (!empty_node) { statestack.push_back(nodetype); } + action->Scalar(this, true, 0, 0); + return !empty_node; + case FalseNode: + if (!empty_node) { statestack.push_back(nodetype); } + action->Scalar(this, false, 0, 0); + return !empty_node; + case IntegerNode: + if (!empty_node) { + statestack.push_back(nodetype); + empty = true; + } else { + err = true; + errorstr = "libvariant XML PLIST does not allow empty interger elements"; + throw std::runtime_error(errorstr); + } + return true; + case FloatNode: + if (!empty_node) { + statestack.push_back(nodetype); + empty = true; + } else { + err = true; + errorstr = "libvariant XML PLIST does not allow empty real elements"; + throw std::runtime_error(errorstr); + } + return true; + case StringNode: + if (!empty_node) { + statestack.push_back(nodetype); + empty = true; + } else { + err = true; + errorstr = "libvariant XML PLIST does not allow empty string elements"; + throw std::runtime_error(errorstr); + } + return true; + case BlobNode: + if (!empty_node) { + statestack.push_back(nodetype); + empty = true; + } else { + err = true; + errorstr = "libvariant XML PLIST does not allow empty data elements"; + throw std::runtime_error(errorstr); + } + return true; + case MapNode: + if (empty_node) { statestack.push_back(EmptyMapNode); } + else { statestack.push_back(nodetype); } + action->BeginMap(this, -1, 0, 0); + return false; + case KeyNode: + { + if (empty_node) { + err = true; + errorstr = "libvariant XML PLIST does not allow empty key elements"; + throw std::runtime_error(errorstr); + } + statestack.push_back(nodetype); + empty = true; + } + return true; + case ListNode: + if (empty_node) { statestack.push_back(EmptyListNode); } + else { statestack.push_back(nodetype); } + action->BeginList(this, -1, 0, 0); + return false; + default: + err = true; + errorstr = "Invalid libvariant XML PLIST parser state"; + throw std::runtime_error(errorstr); + } + } + + bool XMLPLISTParserImpl::ProcessText(ParserActions *action) { + switch (statestack.back()) { + case NullNode: + case RootNode: + case TrueNode: + case FalseNode: + case MapNode: + case ListNode: + return true; + case IntegerNode: + { + empty = false; + const char *value = (const char*)xmlTextReaderConstValue(reader); + intmax_t val; + val = strtoll(value, 0, 0); + if (val == LLONG_MAX && errno == ERANGE) { + uintmax_t v; + v = strtoull(value, 0, 0); + action->Scalar(this, v, 0, 0); + } else { + action->Scalar(this, val, 0, 0); + } + } + return true; + case FloatNode: + { + empty = false; + const char *value = (const char*)xmlTextReaderConstValue(reader); + double val = strtod(value, 0); + action->Scalar(this, val, 0, 0); + } + return true; + case StringNode: + { + empty = false; + const char *value = (const char*)xmlTextReaderConstValue(reader); + action->Scalar(this, value, strlen(value), 0, 0); + } + return true; + case BlobNode: + { + empty = false; + const char *value = (const char*)xmlTextReaderConstValue(reader); + unsigned length = strlen(value); + void *data = 0; + if (posix_memalign(&data, 64, Base64DecodeSize(length)) != 0) { + err = true; + errorstr = "memory allocation failure"; + throw std::bad_alloc(); + } + unsigned len = Base64Decode(data, value, length); + action->Scalar(this, Blob::CreateFree(data, len), 0, 0); + } + return true; + case KeyNode: + { + empty = false; + const char *value = (const char*)xmlTextReaderConstValue(reader); + action->Scalar(this, value, strlen(value), 0, 0); + } + return true; + default: + err = true; + errorstr = "Invalid libvariant XML PLIST parser state"; + throw std::runtime_error(errorstr); + } + + } + + bool XMLPLISTParserImpl::EndElement(ParserActions *action, State_t nodetype) { + if (statestack.back() != nodetype) { + err = true; + errorstr = "libvariant XML PLIST parser in inconsistent state"; + throw std::runtime_error(errorstr); + } + statestack.pop_back(); + switch (nodetype) { + case NullNode: + case TrueNode: + case FalseNode: + return false; + case IntegerNode: + case FloatNode: + if (empty) { + err = true; + errorstr = "libvariant XML PLIST parser cannot have empty numeric nodes"; + throw std::runtime_error(errorstr); + } + return false; + case BlobNode: + if (empty) { + err = true; + errorstr = "libvariant XML PLIST parser cannot have empty data nodes"; + throw std::runtime_error(errorstr); + } + return false; + case StringNode: + case KeyNode: + if (empty) { action->Scalar(this, "", 0, 0, 0); } + return false; + case RootNode: + action->EndDocument(this); + return false; + case MapNode: + action->EndMap(this); + return false; + case ListNode: + action->EndList(this); + return false; + default: + err = true; + errorstr = "Invalid libvariant XML PLIST parser state"; + throw std::runtime_error(errorstr); + } + } + + void XMLPLISTParserImpl::Close() { + if (!closed) { + closed = true; + xmlTextReaderClose(reader); + } + } + + void XMLPLISTParserImpl::HandleError(const char *fnname) { + xmlErrorPtr error = xmlGetLastError(); + err = true; + if (error) { + errorstr = error->message; + throw std::runtime_error(error->message); + } else { + errorstr = fnname; + throw std::runtime_error(fnname); + } + } + + int XMLPLISTParserImpl::do_read(void *ctx, char *buffer, int len) { + XMLPLISTParserImpl *impl = (XMLPLISTParserImpl*)ctx; + unsigned l = len; + const void *ptr = impl->input->GetPtr(l); + if (!ptr) { return 0; } + l = std::min(len, l); + memcpy(buffer, ptr, l); + impl->input->Release(l); + return l; + } + + int XMLPLISTParserImpl::do_close(void *ctx) { + XMLPLISTParserImpl *impl = (XMLPLISTParserImpl*)ctx; + impl->Close(); + return 0; + } + + XMLPLISTParserImpl::XMLPLISTParserImpl(shared_ptr in) + : input(in), closed(false), err(false) + { + reader = xmlReaderForIO(do_read, do_close, this, 0, 0, + XML_PARSE_NOENT|XML_PARSE_NOCDATA); + if (!reader) { + HandleError("xmlReaderForIO"); + } + statestack.push_back(StartState); + } + + XMLPLISTParserImpl::~XMLPLISTParserImpl() { + Close(); + xmlFreeTextReader(reader); + reader = 0; + } + + bool XMLPLISTParserImpl::Done() const { + return closed; + } + + bool XMLPLISTParserImpl::Error() const { + return err; + } + + bool XMLPLISTParserImpl::Ok() const { + return !closed && !err; + } + + std::string XMLPLISTParserImpl::ErrorStr() const { + return errorstr; + } + + void XMLPLISTParserImpl::Reset() { + Close(); + xmlFreeTextReader(reader); + reader = 0; + reader = xmlReaderForIO(do_read, do_close, this, 0, 0, + XML_PARSE_NOENT|XML_PARSE_NOCDATA); + if (!reader) { + HandleError("xmlReaderForIO"); + } + statestack.push_back(StartState); + closed = false; + err = false; + + } +} diff --git a/src/hos_libvariant/src/src/XMLPLISTParser.h b/src/hos_libvariant/src/src/XMLPLISTParser.h new file mode 100644 index 00000000..ade5e376 --- /dev/null +++ b/src/hos_libvariant/src/src/XMLPLISTParser.h @@ -0,0 +1,81 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#ifndef VARIANT_XMLPLISTPARSER_H +#define VARIANT_XMLPLISTPARSER_H + +#pragma once +#include +#include +#include "../../src/include/Variant/Parser.h" +#include "../../src/include/Variant/ParserInput.h" +#include "../../src/include/Variant/SharedPtr.h" + + +namespace libvariant { + + class XMLPLISTParserImpl : public ParserImpl { + enum State_t { + StartState, + NullNode, + RootNode, + TrueNode, + FalseNode, + IntegerNode, + FloatNode, + StringNode, + BlobNode, + MapNode, + EmptyMapNode, + KeyNode, + ListNode, + EmptyListNode, + EndState + }; + public: + XMLPLISTParserImpl(shared_ptr in); + virtual ~XMLPLISTParserImpl(); + virtual int Run(); + virtual bool Done() const; + virtual bool Error() const; + virtual bool Ok() const; + virtual std::string ErrorStr() const; + virtual void Reset(); + private: + bool BeginElement(ParserActions *action, State_t nodetype); + bool ProcessText(ParserActions *action); + bool EndElement(ParserActions *action, State_t nodetype); + void Close(); + void HandleError(const char *fnname); + + static int do_read(void *ctx, char *buffer, int len); + static int do_close(void *ctx); + static State_t StringToNode(const char *name); + + std::deque statestack; + xmlTextReaderPtr reader; + shared_ptr input; + bool closed; + bool empty; + bool err; + std::string errorstr; + }; +} +#endif diff --git a/src/hos_libvariant/src/src/YAMLEmitter.cc b/src/hos_libvariant/src/src/YAMLEmitter.cc new file mode 100644 index 00000000..ecbe8c4b --- /dev/null +++ b/src/hos_libvariant/src/src/YAMLEmitter.cc @@ -0,0 +1,410 @@ +//============================================================================= +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief A wrapper class around a libyaml emitter + */ +#include "YAMLEmitter.h" +#include +#include +#include +#include +#include +#include "Base64.h" + +namespace libvariant { + + static int WriteHandler(void *data, unsigned char *buffer, size_t size) { + EmitterOutput *out = (EmitterOutput*)data; + return out->Write((const void*)buffer, size); + } + + static const char *param_keys[] = { "scalar_style", "map_style", "list_style", + "implicit_document_begin", "implicit_document_end", "indent", "width", + "precision", 0 }; + static const char *scalar_style_str[] = { "any", "plain", "single quoted", + "double quoted", "literal", "folded", 0 }; + static const char *style_str[] = { "any", "block", "flow", 0 }; + + YAMLEmitterImpl::Config::Config(Variant params) + : default_scalar_style(ANY_SCALAR_STYLE), + default_map_style(ANY_STYLE), + default_list_style(ANY_STYLE), + implicit_begin_document(false), + implicit_end_document(false), + indent(-1), + width(-1), + precision(std::numeric_limits::digits10+2) + { + SetParams(params); + } + + void YAMLEmitterImpl::Config::SetParams(Variant params) { + if (params.IsMap()) { + for (int i = 0; param_keys[i]; ++i) { + const char *key = param_keys[i]; + if (params.Contains(key)) { + SetParam((ConfigKeys)i, params[key]); + } + } + } + } + + void YAMLEmitterImpl::Config::SetParam(const std::string &key, Variant value) { + for (int i = 0; param_keys[i]; ++i) { + if (param_keys[i] == key) { + SetParam((ConfigKeys)i, value); + break; + } + } + } + + void YAMLEmitterImpl::Config::SetParam(ConfigKeys index, Variant value) { + switch (index) { + case SCALAR_STYLE: + { + std::string v = value.AsString(); + for (int i = 0; scalar_style_str[i]; ++i) { + const char *style = scalar_style_str[i]; + if (v == style) { + default_scalar_style = (ScalarStyle)i; + break; + } + } + } + break; + case MAP_STYLE: + { + std::string v = value.AsString(); + for (int i = 0; style_str[i]; ++i) { + const char *style = style_str[i]; + if (v == style) { + default_map_style = (Style)i; + break; + } + } + } + break; + case LIST_STYLE: + { + std::string v = value.AsString(); + for (int i = 0; style_str[i]; ++i) { + const char *style = style_str[i]; + if (v == style) { + default_list_style = (Style)i; + break; + } + } + } + break; + case IMPLICIT_DOCUMENT_BEGIN: + implicit_begin_document = value.AsBool(); + break; + case IMPLICIT_DOCUMENT_END: + implicit_end_document = value.AsBool(); + break; + case INDENT: + indent = value.AsInt(); + break; + case WIDTH: + width = value.AsInt(); + break; + case PRECISION: + precision = value.AsUnsigned(); + break; + default: + break; + } + } + + Variant YAMLEmitterImpl::Config::GetParams() { + Variant ret = Variant::MapType; + for (int i = 0; param_keys[i]; ++i) { + const char *key = param_keys[i]; + ret[key] = GetParam((ConfigKeys)i); + } + return ret; + } + + Variant YAMLEmitterImpl::Config::GetParam(const std::string &key) { + for (int i = 0; param_keys[i]; ++i) { + if (param_keys[i] == key) { + return GetParam((ConfigKeys)i); + } + } + return Variant::NullType; + } + + Variant YAMLEmitterImpl::Config::GetParam(ConfigKeys index) { + switch (index) { + case SCALAR_STYLE: + return scalar_style_str[index]; + case MAP_STYLE: + return style_str[index]; + case LIST_STYLE: + return style_str[index]; + case IMPLICIT_DOCUMENT_BEGIN: + return implicit_begin_document; + case IMPLICIT_DOCUMENT_END: + return implicit_end_document; + case INDENT: + return indent; + case WIDTH: + return width; + case PRECISION: + return precision; + default: + return Variant::NullType; + } + } + + + YAMLEmitterImpl::YAMLEmitterImpl(shared_ptr o, Variant params) + :out(o), closed(false), in_document(false), conf(params) + { + if (yaml_emitter_initialize(&emitter) == 0) { + throw std::runtime_error("Unable to initialize YAMLEmitter."); + } + yaml_emitter_set_output(&emitter, WriteHandler, out.get()); + if (conf.indent > 0) { + yaml_emitter_set_indent(&emitter, conf.indent); + } + if (conf.width > 0) { + yaml_emitter_set_width(&emitter, conf.width); + } + try { EmitStreamStart(); } + catch (...) { + yaml_emitter_delete(&emitter); + throw; + } + } + + YAMLEmitterImpl::~YAMLEmitterImpl() { + try { Close(); } + catch (const std::runtime_error &) {} + } + + void YAMLEmitterImpl::BeginDocument() { + BeginDocument(conf.implicit_begin_document); + } + + void YAMLEmitterImpl::BeginDocument(bool implicit) { + CheckClosed(); + CheckOutDocument(); + yaml_event_t event; + if (yaml_document_start_event_initialize(&event, 0, 0, 0, implicit ? 1 : 0) == 0) { + throw std::runtime_error("Error initializing document start event."); + } + Emit(event); + in_document = true; + } + + void YAMLEmitterImpl::EndDocument() { + EndDocument(conf.implicit_end_document); + } + + void YAMLEmitterImpl::EndDocument(bool implicit) { + CheckClosed(); + CheckInDocument(); + yaml_event_t event; + if (yaml_document_end_event_initialize(&event, implicit ? 1 : 0) == 0) { + throw std::runtime_error("Error initializing document end event."); + } + Emit(event); + in_document = false; + } + + void YAMLEmitterImpl::BeginMap(int length) { + BeginMap(length, conf.default_map_style); + } + + void YAMLEmitterImpl::BeginMap(int, Style style) { + CheckClosed(); + CheckInDocument(); + yaml_event_t event; + if (yaml_mapping_start_event_initialize(&event, 0, 0, 1, + (yaml_mapping_style_t)style) == 0) { + throw std::runtime_error("Unable to initialize mapping start event"); + } + Emit(event); + } + + void YAMLEmitterImpl::EndMap() { + CheckClosed(); + CheckInDocument(); + yaml_event_t event; + if (yaml_mapping_end_event_initialize(&event) == 0) { + throw std::runtime_error("Unable to initialize mapping end event."); + } + Emit(event); + } + + void YAMLEmitterImpl::BeginList(int length) { + BeginList(length, conf.default_list_style); + } + + void YAMLEmitterImpl::BeginList(int, Style style) { + CheckClosed(); + CheckInDocument(); + yaml_event_t event; + if (yaml_sequence_start_event_initialize(&event, 0, 0, 1, + (yaml_sequence_style_t)style) == 0) { + throw std::runtime_error("Unable to initialize sequence start event"); + } + Emit(event); + } + + void YAMLEmitterImpl::EndList() { + CheckClosed(); + CheckInDocument(); + yaml_event_t event; + if (yaml_sequence_end_event_initialize(&event) == 0) { + throw std::runtime_error("Unable to initialize sequence end event."); + } + Emit(event); + } + + void YAMLEmitterImpl::EmitNull() { + Emit("null", PLAIN_SCALAR_STYLE); + } + + void YAMLEmitterImpl::EmitTrue() { + Emit("true", PLAIN_SCALAR_STYLE); + } + + void YAMLEmitterImpl::EmitFalse() { + Emit("false", PLAIN_SCALAR_STYLE); + } + + void YAMLEmitterImpl::Emit(const std::string &v, ScalarStyle style) { + CheckClosed(); + CheckInDocument(); + yaml_event_t event; + if (yaml_scalar_event_initialize(&event, 0, 0, (yaml_char_t*)v.c_str(), v.length(), 1, 1, + (yaml_scalar_style_t)style) == 0) { + throw std::runtime_error("Unable to initialize scalar event."); + } + Emit(event); + } + + void YAMLEmitterImpl::Emit(const char *v) { + Emit(v, ANY_SCALAR_STYLE); + } + + void YAMLEmitterImpl::Emit(const char *v, ScalarStyle style) { + CheckClosed(); + CheckInDocument(); + yaml_event_t event; + if (yaml_scalar_event_initialize(&event, 0, 0, (yaml_char_t*)v, strlen(v), 1, 1, + (yaml_scalar_style_t)style) == 0) { + throw std::runtime_error("Unable to initialize scalar event."); + } + Emit(event); + } + + void YAMLEmitterImpl::Emit(intmax_t v) { + std::ostringstream oss; + oss << v; + Emit(oss.str(), PLAIN_SCALAR_STYLE); + } + + void YAMLEmitterImpl::Emit(uintmax_t v) { + std::ostringstream oss; + oss << v; + Emit(oss.str(), PLAIN_SCALAR_STYLE); + } + + void YAMLEmitterImpl::Emit(double v) { + std::ostringstream oss; + if (v != v) { + oss << ".nan"; + } else if (std::abs(v) == std::numeric_limits::infinity()) { + oss << (v < 0 ? "-" : "") << ".inf"; + } else { + oss << std::setprecision(conf.precision) << std::showpoint << v; + } + Emit(oss.str(), PLAIN_SCALAR_STYLE); + } + + void YAMLEmitterImpl::Emit(ConstBlobPtr b) { + CheckClosed(); + CheckInDocument(); + yaml_event_t event; + std::vector buf(Base64EncodeSize(b->GetTotalLength())); + unsigned len = Base64Encode(&buf[0], b->GetIOVec(), b->GetNumBuffers(), 0); + if (yaml_scalar_event_initialize(&event, 0, (yaml_char_t*)"tag:yaml.org,2002:binary", (yaml_char_t*)&buf[0], len, 0, 0, + (yaml_scalar_style_t)ANY_SCALAR_STYLE) == 0) { + throw std::runtime_error("Unable to initialize scalar event."); + } + Emit(event); + } + + void YAMLEmitterImpl::Flush() { + CheckClosed(); + if (yaml_emitter_flush(&emitter) == 0) { + throw std::runtime_error(emitter.problem); + } + } + + void YAMLEmitterImpl::Close() { + if (!closed) { + CheckOutDocument(); + yaml_event_t event; + if (yaml_stream_end_event_initialize(&event) == 0) { + throw std::runtime_error("Unable to initialize stream end event."); + } + Emit(event); + Flush(); + yaml_emitter_delete(&emitter); + out.reset(); + closed = true; + } + } + + Variant YAMLEmitterImpl::GetParam(const std::string &key) { + return conf.GetParam(key); + } + + Variant YAMLEmitterImpl::GetParams() { + return conf.GetParams(); + } + + void YAMLEmitterImpl::SetParam(const std::string &key, Variant value) { + conf.SetParam(key, value); + } + + void YAMLEmitterImpl::SetParams(Variant params) { + conf.SetParams(params); + } + + void YAMLEmitterImpl::EmitStreamStart() { + yaml_event_t event; + if (yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING) == 0) { + throw std::runtime_error("Unable to initialize stream start event"); + } + Emit(event); + } + + void YAMLEmitterImpl::Emit(yaml_event_t &event) { + if (yaml_emitter_emit(&emitter, &event) == 0) { + yaml_event_delete(&event); + throw std::runtime_error(emitter.problem); + } + } + +} diff --git a/src/hos_libvariant/src/src/YAMLEmitter.h b/src/hos_libvariant/src/src/YAMLEmitter.h new file mode 100644 index 00000000..a83fc5b8 --- /dev/null +++ b/src/hos_libvariant/src/src/YAMLEmitter.h @@ -0,0 +1,170 @@ +//============================================================================= +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief A wrapper class around a libyaml emitter + */ + +#ifndef YAMLEMITTER_INC +#define YAMLEMITTER_INC + +#pragma once +#include +#include +#include +#include +#include +#include "../../src/include/Variant/Emitter.h" +#include +#include + +namespace libvariant { + + /** + * Supported parameters are (first is default): + * "scalar_style": "any"|"plain"|"single quoted"|"double + * quoted"|"literal"|"folded" + * "map_style": "any"|"block"|"flow" + * "list_style": "any"|"block"|"flow" + * "implicit_document_begin": false|true + * "implicit_document_end": false|true + * These two parameters are only settable on creation. + * Resetting afterwards has no effect. + * "indent": integer (number of spaces to indent) + * "width": integer (set prefered line width) + * "precision": number of digits for a float + */ + class YAMLEmitterImpl : public EmitterImpl { + public: + enum ConfigKeys { + SCALAR_STYLE, + MAP_STYLE, + LIST_STYLE, + IMPLICIT_DOCUMENT_BEGIN, + IMPLICIT_DOCUMENT_END, + INDENT, + WIDTH, + PRECISION + }; + + enum ScalarStyle { + ANY_SCALAR_STYLE, + PLAIN_SCALAR_STYLE, + SINGLE_QUOTED_SCALAR_STYLE, + DOUBLE_QUOTED_SCALAR_STYLE, + LITERAL_SCALAR_STYLE, + FOLDED_SCALAR_STYLE + }; + + enum Style { + ANY_STYLE, + BLOCK_STYLE, + FLOW_STYLE + }; + + struct Config { + Config(Variant params); + void SetParams(Variant params); + void SetParam(const std::string &key, Variant value); + void SetParam(ConfigKeys index, Variant value); + Variant GetParams(); + Variant GetParam(const std::string &key); + Variant GetParam(ConfigKeys index); + + ScalarStyle default_scalar_style; + Style default_map_style; + Style default_list_style; + bool implicit_begin_document; + bool implicit_end_document; + int indent; + int width; + unsigned precision; + }; + + /** + * Create a YAMLEmitter that uses output to write. + * The output object will be deleted when YAMLEmitter + * is destroyed. + */ + YAMLEmitterImpl(shared_ptr output, Variant params); + virtual ~YAMLEmitterImpl(); + + virtual void BeginDocument(); + void BeginDocument(bool implicit); + virtual void EndDocument(); + void EndDocument(bool implicit); + virtual void BeginMap(int length); + void BeginMap(int length, Style style); + virtual void EndMap(); + virtual void BeginList(int length); + void BeginList(int length, Style style); + virtual void EndList(); + + virtual void EmitNull(); + virtual void EmitTrue(); + virtual void EmitFalse(); + void Emit(const std::string &v, ScalarStyle style); + virtual void Emit(const char *v); + void Emit(const char *v, ScalarStyle style); + virtual void Emit(intmax_t v); + virtual void Emit(uintmax_t v); + virtual void Emit(double v); + virtual void Emit(ConstBlobPtr b); + + virtual void Flush(); + /** Flush, release all resources and clean up. + * Doing anything other than deleting this object + * will result in a std::runtime_error */ + virtual void Close(); + + virtual Variant GetParam(const std::string &key); + virtual Variant GetParams(); + virtual void SetParam(const std::string &key, Variant value); + virtual void SetParams(Variant params); + + private: + void EmitStreamStart(); + void Emit(yaml_event_t &event); + + void CheckClosed() { + if (closed) { + throw std::runtime_error("YAMLEmitter is closed"); + } + } + + void CheckInDocument() { + if (!in_document) { + BeginDocument(); + } + } + + void CheckOutDocument() { + if (in_document) { + EndDocument(); + } + } + + shared_ptr out; + yaml_emitter_t emitter; + bool closed; + bool in_document; + Config conf; + }; + +} +#endif diff --git a/src/hos_libvariant/src/src/YAMLParser.cc b/src/hos_libvariant/src/src/YAMLParser.cc new file mode 100644 index 00000000..73a03d7d --- /dev/null +++ b/src/hos_libvariant/src/src/YAMLParser.cc @@ -0,0 +1,194 @@ +//============================================================================= +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ +#include "YAMLParser.h" +#include +#include "Base64.h" +#include "GuessScalar.h" +#include +#include +#include + +namespace libvariant { + + int YAMLParserImpl::ParserReadHandler(void *data, unsigned char *buffer, size_t size, size_t *sizein) { + YAMLParserImpl *impl = (YAMLParserImpl*)data; + unsigned len = size; + const void *ptr = impl->input->GetPtr(len); + if (!ptr) { + *sizein = 0; + return 1; + } + *sizein = std::min(size, len); + memcpy(buffer, ptr, *sizein); + impl->input->Release(*sizein); + return 1; + } + + YAMLParserImpl::YAMLParserImpl(shared_ptr in) + : input(in), eof(false), err(false) + { + yaml_parser_initialize(&parser); + yaml_parser_set_input(&parser, &ParserReadHandler, this); + } + + YAMLParserImpl::~YAMLParserImpl() { + yaml_parser_delete(&parser); + } + + void ParseScalar(yaml_event_t &event, ParserImpl *p, ParserActions *action) { + const char *value = (const char *)event.data.scalar.value; + const char *anchor = (const char *)event.data.scalar.anchor; + const char *tag = (const char *)event.data.scalar.tag; + unsigned length = event.data.scalar.length; + yaml_scalar_style_t style = event.data.scalar.style; + if (tag && strcmp(tag, "tag:yaml.org,2002:binary") == 0) { + void *data = 0; + if (posix_memalign(&data, 64, Base64DecodeSize(length)) != 0) { + throw std::bad_alloc(); + } + unsigned len = Base64Decode(data, value, length); + action->Scalar(p, Blob::CreateFree(data, len), anchor, tag); + return; + } + switch (style) { + case YAML_ANY_SCALAR_STYLE: + case YAML_PLAIN_SCALAR_STYLE: + break; + case YAML_SINGLE_QUOTED_SCALAR_STYLE: + case YAML_DOUBLE_QUOTED_SCALAR_STYLE: + case YAML_LITERAL_SCALAR_STYLE: + case YAML_FOLDED_SCALAR_STYLE: + action->Scalar(p, value, length, anchor, tag); + return; + } + if (tag) { + action->Scalar(p, value, length, anchor, tag); + } else { + GuessScalar(value, length, anchor, tag, p, action); + } + } + + int YAMLParserImpl::Run() { + bool loop = true; + while (loop && !eof && !action_stack.empty()) { + yaml_event_t event; + if (yaml_parser_parse(&parser, &event) == 0) { + err = true; + std::ostringstream oss; + oss << "Error parsing YAML: " << parser.problem << " " + << (parser.context ? parser.context : "") + << " at line " << parser.problem_mark.line << " column " + << parser.problem_mark.column << "\n"; + errorstr = oss.str(); + throw std::runtime_error(errorstr); + } + + try { + switch (event.type) { + /** An empty event. */ + case YAML_NO_EVENT: + break; + + /** A STREAM-START event. */ + case YAML_STREAM_START_EVENT: + break; + /** A STREAM-END event. */ + case YAML_STREAM_END_EVENT: + eof = true; + loop = false; + break; + + /** A DOCUMENT-START event. */ + case YAML_DOCUMENT_START_EVENT: + TopAction()->BeginDocument(this); + break; + /** A DOCUMENT-END event. */ + case YAML_DOCUMENT_END_EVENT: + TopAction()->EndDocument(this); + loop = false; + break; + + /** An ALIAS event. */ + case YAML_ALIAS_EVENT: + TopAction()->Alias(this, (const char*)event.data.alias.anchor); + break; + /** A SCALAR event. */ + case YAML_SCALAR_EVENT: + ParseScalar(event, this, TopAction()); + break; + + /** A SEQUENCE-START event. */ + case YAML_SEQUENCE_START_EVENT: + TopAction()->BeginList(this, -1, (const char*)event.data.sequence_start.anchor, + (const char*)event.data.sequence_start.tag); + break; + /** A SEQUENCE-END event. */ + case YAML_SEQUENCE_END_EVENT: + TopAction()->EndList(this); + break; + + /** A MAPPING-START event. */ + case YAML_MAPPING_START_EVENT: + TopAction()->BeginMap(this, -1, (const char*)event.data.mapping_start.anchor, + (const char*)event.data.mapping_start.tag); + break; + /** A MAPPING-END event. */ + case YAML_MAPPING_END_EVENT: + TopAction()->EndMap(this); + break; + + } + } catch (...) { + err = true; + errorstr = "Exception from action..."; + yaml_event_delete(&event); + throw; + } + yaml_event_delete(&event); + } + return eof ? 1 : 0; + } + + bool YAMLParserImpl::Done() const { + return eof; + } + + bool YAMLParserImpl::Error() const { + return err; + } + + bool YAMLParserImpl::Ok() const { + return !err && !eof; + } + + std::string YAMLParserImpl::ErrorStr() const { + return errorstr; + } + + void YAMLParserImpl::Reset() { + eof = false; + err = false; + yaml_parser_delete(&parser); + yaml_parser_initialize(&parser); + yaml_parser_set_input(&parser, &ParserReadHandler, this); + } +} diff --git a/src/hos_libvariant/src/src/YAMLParser.h b/src/hos_libvariant/src/src/YAMLParser.h new file mode 100644 index 00000000..351d0e87 --- /dev/null +++ b/src/hos_libvariant/src/src/YAMLParser.h @@ -0,0 +1,62 @@ +//============================================================================= +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief + */ + + +#ifndef YAMLPARSER_INC +#define YAMLPARSER_INC + +#pragma once +#include "../../src/include/Variant/Parser.h" +#include "../../src/include/Variant/ParserInput.h" +#include "../../src/include/Variant/SharedPtr.h" +#include + +namespace libvariant { + + + /** + * \brief + */ + class YAMLParserImpl : public ParserImpl { + public: + YAMLParserImpl(shared_ptr in); + virtual ~YAMLParserImpl(); + + virtual int Run(); + + virtual bool Done() const; + virtual bool Error() const; + virtual bool Ok() const; + virtual std::string ErrorStr() const; + virtual void Reset(); + private: + static int ParserReadHandler(void *data, unsigned char *buffer, size_t size, size_t *sizein); + yaml_parser_t parser; + shared_ptr input; + bool eof; + bool err; + std::string errorstr; + }; + +} + +#endif diff --git a/src/hos_libvariant/src/src/argparse-schema.cc b/src/hos_libvariant/src/src/argparse-schema.cc new file mode 100644 index 00000000..93d131f0 --- /dev/null +++ b/src/hos_libvariant/src/src/argparse-schema.cc @@ -0,0 +1,184 @@ +// This file was generated using gen-argparse-schema and argparse-schema.yaml +// To change edit those files and regenarate. +namespace libvariant { +extern const char ARG_PARSE_SCHEMA_STR[]; +const char ARG_PARSE_SCHEMA_STR[] = { + 0x7b, 0x22, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x65, 0x6e, 0x75, 0x6d, 0x22, 0x3a, + 0x20, 0x5b, 0x22, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x2c, 0x20, 0x22, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x22, + 0x2c, 0x20, 0x22, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x74, 0x72, 0x75, + 0x65, 0x22, 0x2c, 0x20, 0x22, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x66, + 0x61, 0x6c, 0x73, 0x65, 0x22, 0x2c, 0x20, 0x22, 0x61, 0x70, 0x70, 0x65, + 0x6e, 0x64, 0x22, 0x2c, 0x20, 0x22, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, + 0x2c, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x70, 0x22, 0x2c, 0x20, 0x22, 0x61, + 0x64, 0x76, 0x5f, 0x68, 0x65, 0x6c, 0x70, 0x22, 0x2c, 0x20, 0x22, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x2c, 0x20, 0x22, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0x2c, 0x20, 0x22, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x79, 0x61, 0x6d, 0x6c, 0x22, + 0x2c, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x6c, + 0x69, 0x73, 0x74, 0x22, 0x2c, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x22, 0x5d, 0x7d, 0x2c, 0x20, + 0x22, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x65, + 0x6e, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, + 0x6e, 0x22, 0x2c, 0x20, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x22, 0x2c, 0x20, 0x22, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x2c, + 0x20, 0x22, 0x6e, 0x75, 0x6c, 0x6c, 0x22, 0x2c, 0x20, 0x6e, 0x75, 0x6c, + 0x6c, 0x5d, 0x7d, 0x2c, 0x20, 0x22, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x42, 0x61, 0x73, 0x65, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x72, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x74, 0x69, + 0x74, 0x6c, 0x65, 0x22, 0x2c, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x20, 0x22, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x2c, 0x20, 0x22, 0x70, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x6d, + 0x69, 0x6e, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x7b, + 0x22, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x30, + 0x2c, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x6d, + 0x61, 0x78, 0x41, 0x72, 0x67, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x6d, + 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x30, 0x2c, 0x20, + 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x65, 0x6e, 0x75, + 0x6d, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x6d, 0x69, 0x6e, 0x49, 0x74, 0x65, + 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x31, 0x2c, 0x20, 0x22, 0x75, 0x6e, 0x69, + 0x71, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x74, + 0x72, 0x75, 0x65, 0x2c, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, + 0x20, 0x22, 0x61, 0x72, 0x72, 0x61, 0x79, 0x22, 0x2c, 0x20, 0x22, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, + 0x6e, 0x22, 0x2c, 0x20, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x22, 0x2c, 0x20, 0x22, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x2c, + 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x5d, 0x7d, 0x7d, + 0x2c, 0x20, 0x22, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, + 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x6d, 0x61, + 0x78, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x7b, 0x22, + 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x30, 0x2c, + 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x6d, 0x69, + 0x6e, 0x41, 0x72, 0x67, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x6d, 0x69, + 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x30, 0x2c, 0x20, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x61, 0x64, 0x76, 0x61, + 0x6e, 0x63, 0x65, 0x64, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, + 0x2c, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x62, + 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x63, + 0x6f, 0x6e, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x7b, 0x7d, 0x2c, 0x20, 0x22, + 0x74, 0x69, 0x74, 0x6c, 0x65, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x22, 0x3a, 0x20, 0x7b, 0x7d, 0x2c, 0x20, 0x22, 0x70, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x6e, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x2c, + 0x20, 0x22, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x3a, 0x20, 0x22, + 0x72, 0x65, 0x67, 0x65, 0x78, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x72, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x64, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, + 0x73, 0x65, 0x2c, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, + 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x7d, 0x2c, 0x20, + 0x22, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x7b, + 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, + 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, + 0x7b, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x2f, + 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0x7d, 0x7d, 0x7d, 0x7d, 0x2c, 0x20, + 0x22, 0x24, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0x3a, 0x20, 0x22, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x2d, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x64, + 0x72, 0x61, 0x66, 0x74, 0x2d, 0x30, 0x34, 0x2f, 0x73, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x23, 0x22, 0x2c, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x3a, 0x20, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2c, 0x20, + 0x22, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, + 0x3a, 0x20, 0x7b, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, + 0x2c, 0x20, 0x22, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x3a, 0x20, + 0x7b, 0x22, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, + 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2c, 0x20, 0x22, 0x70, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, + 0x7d, 0x2c, 0x20, 0x22, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x22, 0x3a, + 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x3a, 0x20, 0x22, 0x61, 0x72, 0x72, 0x61, 0x79, 0x22, 0x7d, 0x2c, + 0x20, 0x22, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x22, 0x3a, 0x20, 0x7b, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x64, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x3a, 0x20, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, + 0x7d, 0x2c, 0x20, 0x22, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x64, + 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x20, 0x22, 0x74, + 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, + 0x61, 0x6e, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x6d, 0x75, 0x74, 0x75, 0x61, + 0x6c, 0x6c, 0x79, 0x20, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, + 0x65, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, + 0x20, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x7d, 0x7d, + 0x7d, 0x2c, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, + 0x7d, 0x2c, 0x20, 0x22, 0x65, 0x70, 0x69, 0x6c, 0x6f, 0x67, 0x22, 0x3a, + 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x61, 0x64, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, + 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x22, 0x2c, 0x20, 0x22, 0x61, 0x6e, 0x79, 0x4f, 0x66, 0x22, 0x3a, + 0x20, 0x5b, 0x7b, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, + 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x7d, 0x2c, 0x20, 0x7b, 0x22, 0x72, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3a, 0x20, 0x5b, 0x22, + 0x6c, 0x6f, 0x6e, 0x67, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5d, + 0x7d, 0x5d, 0x2c, 0x20, 0x22, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, + 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x6c, 0x6f, 0x6e, 0x67, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, + 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x22, 0x7d, 0x2c, 0x20, 0x22, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x6d, 0x69, + 0x6e, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x31, 0x2c, + 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x20, 0x22, 0x6d, 0x61, 0x78, 0x4c, + 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x31, 0x7d, 0x2c, 0x20, + 0x22, 0x65, 0x6e, 0x76, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, + 0x7d, 0x7d, 0x2c, 0x20, 0x22, 0x61, 0x6c, 0x6c, 0x4f, 0x66, 0x22, 0x3a, + 0x20, 0x5b, 0x7b, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, + 0x23, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x61, 0x73, 0x65, + 0x22, 0x7d, 0x5d, 0x7d, 0x2c, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x3a, 0x20, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x7d, 0x2c, + 0x20, 0x22, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, + 0x3a, 0x20, 0x7b, 0x22, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, + 0x7b, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3a, + 0x20, 0x5b, 0x22, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x74, 0x68, 0x22, 0x5d, + 0x2c, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2c, 0x20, 0x22, 0x70, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x22, + 0x6b, 0x65, 0x79, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x7b, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x22, 0x7d, 0x7d, 0x2c, 0x20, 0x22, 0x61, 0x6c, 0x6c, 0x4f, + 0x66, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, + 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x61, 0x73, 0x65, 0x22, 0x7d, 0x5d, 0x7d, 0x2c, 0x20, 0x22, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x72, 0x72, 0x61, 0x79, 0x22, + 0x7d, 0x7d, 0x7d +, 0 }; } diff --git a/src/hos_libvariant/src/src/argparse-schema.yaml b/src/hos_libvariant/src/src/argparse-schema.yaml new file mode 100644 index 00000000..43417a4d --- /dev/null +++ b/src/hos_libvariant/src/src/argparse-schema.yaml @@ -0,0 +1,91 @@ + +"$schema": "http://json-schema.org/draft-04/schema#" +definitions: + actions: + enum: + - store + - store_const + - store_true + - store_false + - append + - count + - help + - adv_help + - config + - config_json + - config_yaml + - config_plist + - config_print + types: + enum: + - string + - boolean + - integer + - number + - 'null' + - null + + optionBase: + properties: + title: { type: string } + description: { type: string } + action: { "$ref": '#/definitions/actions' } + type: { "$ref": '#/definitions/types' } + default: {} + const: {} + required: { type: boolean, default: false } + advanced: { type: boolean, default: false } + enum: + type: array + minItems: 1 + uniqueItems: true + items: { type: [ boolean, integer, number, string ] } +# Specific to type "number" and "integer" + minimum: { type: number } + maximum: { type: number } +# Specific to type "string" + minLength: { type: integer, minimum: 0 } + maxLength: { type: integer, minimum: 0 } + pattern: { type: string, format: regex } +# Specific to action "append" + minArgs: { type: integer, minimum: 0 } + maxArgs: { type: integer, minimum: 0 } + required: [ title, description, action ] + +type: object +properties: + title: { type: string } + description: { type: string } + epilog: { type: string } + options: + type: object + additionalProperties: + type: object + properties: + longOption: { type: string } + shortOption: { type: string, maxLength: 1, minLength: 1 } + env: { type: string } + allOf: [ { "$ref": '#/definitions/optionBase' } ] + anyOf: + - { required: [ shortOption ] } + - { required: [ longOption ] } + groups: + type: object + additionalProperties: + type: object + properties: + title: { type: string } + description: { type: string } + mutually exclusive: { type: boolean } + required: { type: boolean } + advanced: { type: boolean, default: false } + members: { type: array, unique: true, items: { type: string } } + arguments: + type: array + items: + type: object + properties: + keypath: { type: string } + allOf: [ { "$ref": '#/definitions/optionBase' } ] + required: [ keypath ] + diff --git a/src/hos_libvariant/src/src/gen-argparse-schema b/src/hos_libvariant/src/src/gen-argparse-schema new file mode 100644 index 00000000..04b0b09f --- /dev/null +++ b/src/hos_libvariant/src/src/gen-argparse-schema @@ -0,0 +1,9 @@ +#!/bin/sh + +(echo "// This file was generated using gen-argparse-schema and argparse-schema.yaml"; +echo "// To change edit those files and regenarate."; +echo "namespace libvariant {"; +echo "extern const char ARG_PARSE_SCHEMA_STR[];"; +echo "const char ARG_PARSE_SCHEMA_STR[] = {"; +python -c 'import json,yaml,sys; json.dump(yaml.load(sys.stdin), sys.stdout);' < argparse-schema.yaml | xxd -i; +echo ", 0 }; }") > argparse-schema.cc diff --git a/src/hos_libvariant/src/src/gen-json-schema b/src/hos_libvariant/src/src/gen-json-schema new file mode 100644 index 00000000..0d5e17d8 --- /dev/null +++ b/src/hos_libvariant/src/src/gen-json-schema @@ -0,0 +1,9 @@ +#!/bin/sh + +(echo "// This file was generated using gen-json-schema and json-schema-v4.json"; +echo "// To change edit those files and regenarate."; +echo "namespace libvariant {"; +echo "extern const char JSON_SCHEMA_V4_SCHEMA[];"; +echo "const char JSON_SCHEMA_V4_SCHEMA[] = {"; +xxd -i < json-schema-v4.json; +echo ", 0 }; }") > json-schema-v4.cc diff --git a/src/hos_libvariant/src/src/json-schema-v4.cc b/src/hos_libvariant/src/src/json-schema-v4.cc new file mode 100644 index 00000000..87deb5fb --- /dev/null +++ b/src/hos_libvariant/src/src/json-schema-v4.cc @@ -0,0 +1,371 @@ +// This file was generated using gen-json-schema and json-schema-v4.json +// To change edit those files and regenarate. +namespace libvariant { +extern const char JSON_SCHEMA_V4_SCHEMA[]; +const char JSON_SCHEMA_V4_SCHEMA[] = { + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x64, 0x22, 0x3a, 0x20, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, + 0x2d, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x2f, + 0x64, 0x72, 0x61, 0x66, 0x74, 0x2d, 0x30, 0x34, 0x2f, 0x73, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x23, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x24, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0x3a, 0x20, 0x22, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x2d, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x64, 0x72, + 0x61, 0x66, 0x74, 0x2d, 0x30, 0x34, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x23, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, + 0x22, 0x43, 0x6f, 0x72, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x20, 0x6d, 0x65, 0x74, 0x61, 0x2d, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x41, 0x72, 0x72, 0x61, 0x79, 0x22, 0x3a, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x69, 0x6e, 0x49, 0x74, + 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x31, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x74, + 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, 0x65, + 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x22, 0x20, 0x7d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x3a, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x69, + 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x30, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x30, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, + 0x6c, 0x6c, 0x4f, 0x66, 0x22, 0x3a, 0x20, 0x5b, 0x20, 0x7b, 0x20, 0x22, + 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, 0x65, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, + 0x72, 0x22, 0x20, 0x7d, 0x2c, 0x20, 0x7b, 0x20, 0x22, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x20, 0x30, 0x20, 0x7d, 0x20, 0x5d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x65, 0x6e, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x5b, 0x20, 0x22, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6f, 0x6f, + 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x2c, 0x20, 0x22, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x22, 0x2c, 0x20, 0x22, 0x6e, 0x75, 0x6c, 0x6c, 0x22, + 0x2c, 0x20, 0x22, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x2c, 0x20, + 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2c, 0x20, 0x22, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x20, 0x5d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, + 0x72, 0x72, 0x61, 0x79, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x72, 0x72, 0x61, 0x79, 0x22, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x7b, + 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x22, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x69, + 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x31, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, + 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, + 0x20, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x69, 0x64, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x22, 0x3a, 0x20, 0x22, 0x75, 0x72, 0x69, 0x22, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, + 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x75, 0x72, + 0x69, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, + 0x20, 0x7b, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x4f, 0x66, + 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, + 0x20, 0x22, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x30, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, + 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, + 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x61, + 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, + 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, + 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x78, 0x69, + 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x3a, 0x20, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, + 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, + 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x22, + 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, + 0x22, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, + 0x76, 0x65, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x62, + 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, + 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x61, + 0x78, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x7b, 0x20, + 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, + 0x65, 0x72, 0x22, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x6d, 0x69, 0x6e, 0x4c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, + 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x30, 0x22, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x6e, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x3a, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x72, + 0x65, 0x67, 0x65, 0x78, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, + 0x6e, 0x79, 0x4f, 0x66, 0x22, 0x3a, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7b, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, + 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x20, 0x7d, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, + 0x3a, 0x20, 0x22, 0x23, 0x22, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x20, 0x7b, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x74, 0x65, + 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x6e, 0x79, 0x4f, + 0x66, 0x22, 0x3a, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x20, + 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x22, 0x20, + 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, + 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x73, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x41, 0x72, 0x72, 0x61, 0x79, 0x22, 0x20, 0x7d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, + 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x7b, + 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x2f, + 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x49, 0x6e, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x22, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x69, 0x6e, 0x49, 0x74, 0x65, 0x6d, + 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, + 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x30, 0x22, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, + 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, + 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, + 0x61, 0x6e, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x20, + 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, + 0x65, 0x72, 0x22, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x24, + 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, 0x65, 0x66, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x30, 0x22, 0x20, 0x7d, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, + 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, 0x65, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x41, 0x72, 0x72, 0x61, 0x79, 0x22, 0x20, 0x7d, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, + 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x50, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x61, 0x6e, 0x79, 0x4f, 0x66, 0x22, 0x3a, 0x20, 0x5b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7b, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, + 0x20, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x20, 0x7d, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, 0x65, + 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x22, 0x20, 0x7d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x20, + 0x7b, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x64, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, + 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x22, 0x20, 0x7d, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, + 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x64, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, + 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x22, 0x20, 0x7d, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, + 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, + 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, + 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, + 0x3a, 0x20, 0x22, 0x23, 0x22, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x20, 0x7b, 0x7d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x70, 0x65, 0x6e, + 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x64, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, + 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x61, 0x6e, 0x79, 0x4f, 0x66, 0x22, 0x3a, 0x20, 0x5b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, + 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x22, 0x20, 0x7d, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x20, 0x22, 0x24, + 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, 0x65, 0x66, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x41, 0x72, 0x72, 0x61, 0x79, 0x22, 0x20, 0x7d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x65, 0x6e, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x69, 0x6e, 0x49, 0x74, + 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x31, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x6e, + 0x69, 0x71, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, + 0x74, 0x72, 0x75, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, + 0x6e, 0x79, 0x4f, 0x66, 0x22, 0x3a, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, + 0x23, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2f, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x73, 0x22, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x72, 0x72, 0x61, 0x79, 0x22, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x74, + 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, 0x65, + 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x73, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, 0x20, 0x7d, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x69, 0x6e, 0x49, + 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x31, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x6e, 0x69, 0x71, 0x75, + 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, + 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x6c, 0x6c, 0x4f, 0x66, 0x22, + 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, + 0x22, 0x23, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x41, 0x72, 0x72, + 0x61, 0x79, 0x22, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x61, 0x6e, 0x79, 0x4f, 0x66, 0x22, 0x3a, 0x20, + 0x7b, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, + 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x22, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x6f, 0x6e, 0x65, 0x4f, 0x66, 0x22, 0x3a, 0x20, 0x7b, 0x20, + 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x2f, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x41, 0x72, 0x72, 0x61, 0x79, 0x22, 0x20, + 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x6e, 0x6f, 0x74, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x24, 0x72, 0x65, + 0x66, 0x22, 0x3a, 0x20, 0x22, 0x23, 0x22, 0x20, 0x7d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, + 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x22, 0x3a, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x78, + 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x3a, 0x20, 0x5b, 0x20, 0x22, 0x6d, 0x61, + 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x22, 0x20, 0x5d, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x78, 0x63, 0x6c, 0x75, + 0x73, 0x69, 0x76, 0x65, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x22, + 0x3a, 0x20, 0x5b, 0x20, 0x22, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, + 0x22, 0x20, 0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, + 0x3a, 0x20, 0x7b, 0x7d, 0x0a, 0x7d, 0x0a +, 0 }; } diff --git a/src/hos_libvariant/src/src/json-schema-v4.json b/src/hos_libvariant/src/src/json-schema-v4.json new file mode 100644 index 00000000..85eb502a --- /dev/null +++ b/src/hos_libvariant/src/src/json-schema-v4.json @@ -0,0 +1,150 @@ +{ + "id": "http://json-schema.org/draft-04/schema#", + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "positiveInteger": { + "type": "integer", + "minimum": 0 + }, + "positiveIntegerDefault0": { + "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] + }, + "simpleTypes": { + "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true + } + }, + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uri" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": {}, + "multipleOf": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "boolean", + "default": false + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "boolean", + "default": false + }, + "maxLength": { "$ref": "#/definitions/positiveInteger" }, + "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": {} + }, + "maxItems": { "$ref": "#/definitions/positiveInteger" }, + "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxProperties": { "$ref": "#/definitions/positiveInteger" }, + "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "enum": { + "type": "array", + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "dependencies": { + "exclusiveMaximum": [ "maximum" ], + "exclusiveMinimum": [ "minimum" ] + }, + "default": {} +} diff --git a/src/hos_libvariant/src/src/varsh.cc b/src/hos_libvariant/src/src/varsh.cc new file mode 100644 index 00000000..3595288e --- /dev/null +++ b/src/hos_libvariant/src/src/varsh.cc @@ -0,0 +1,233 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief Variant tool + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace libvariant; + +struct State { + SerializeType stype; + AdvSchemaLoader loader; + Variant conf; +}; + +void Process(State &state, ostream &out, istream &in) { + Variant data; + SerializeType itype; + if (state.conf.Get("guess-in", false).AsBool()) { itype = SERIALIZE_GUESS; } + if (state.conf.Get("json-in", false).AsBool()) { itype = SERIALIZE_JSON; } + if (state.conf.Get("yaml-in", false).AsBool()) { itype = SERIALIZE_YAML; } + if (state.conf.Get("plist-in", false).AsBool()) { itype = SERIALIZE_XMLPLIST; } + if (state.conf.Get("bundlehdr-in", false).AsBool()) { itype = SERIALIZE_BUNDLEHDR; } + + if (state.conf.Get("payload-in", false).AsBool()) { + data = DeserializeWithPayloadFile(in.rdbuf(), itype); + } else { + data = DeserializeFile(in.rdbuf(), itype); + } + + if (state.conf.GetPath("extension/flatten", false).AsBool()) { + data = FlattenPath( data, state.conf.GetPath("extension/params") ); + } + else if (state.conf.GetPath("extension/expand", false).AsBool()) { + data = ExpandPath( data, state.conf.GetPath("extension/params") ); + } + + Variant conf = state.conf; + if (conf.Contains("schemas")) { + for (Variant::ListIterator i(conf["schemas"].ListBegin()), e(conf["schemas"].ListEnd()); i != e; ++i) { + SchemaResult result = SchemaValidate(*i, data, &state.loader); + if (result.Error()) { + cerr << result << endl; + exit(1); + } + } + } + if (conf.Contains("set")) { + if (!conf.Contains("path")) { + data = conf["set"]; + } else { + data.SetPath(conf["path"].AsString(), conf["set"]); + } + } else { + if (conf.Contains("path")) { + data = data.GetPath(conf["path"].AsString()); + } + } + if (conf.Contains("list") && conf["list"].AsBool()) { + for (Variant::MapIterator i(data.MapBegin()), e(data.MapEnd()); i != e; ++i) { + out << i->first << endl; + } + } else if (conf.Contains("len") && conf["len"].AsBool()) { + out << data.Size() << endl; + } else { + if (state.conf.Get("payload", false).AsBool()) { + SerializeWithPayload(out.rdbuf(), data, state.stype, conf["sparams"]); + } else { + Serialize(out.rdbuf(), data, state.stype, conf["sparams"]); + out << endl; + } + } +} + +int main(int argc, char **argv) { + ArgParse opts(*argv); + opts.AddOption("schema_path", 0, "schema-path", "Add a search path for schemas.") + .Action(ARGACTION_APPEND).Type(ARGTYPE_STRING); + opts.AddOption("schemas", 0, "schema", "Add a schema uri to verify against.") + .Action(ARGACTION_APPEND).Type(ARGTYPE_STRING); + opts.AddOption("path", 0, "path", "Set a path name to operate on rather than the whole document.") + .Type(ARGTYPE_STRING); + + opts.AddOption("set", 0, "set", "Specify the value to set at the acting path."); + opts.AddOption("set-file", 0, "set-file", "Specify a file that should be read to set at the acting path.") + .Type(ARGTYPE_STRING); + opts.AddFlag("list", 0, "list", "Print a list of keys at the acting path."); + opts.AddFlag("len", 0, "length", "Print the length of the object at the acting path."); + opts.AddGroup("set").Add("set").Add("set-file").Add("list").Add("len").MutuallyExclusive(); + + opts.AddOption("output", 'o', "out", "Specify a file to output rather than standard out.") + .Type(ARGTYPE_STRING); + + opts.AddOption("guess-in", 'G', "guess", "Specify input format should be guessed (only guesses between json/yaml/plist)").Type(ARGTYPE_BOOL).Action(ARGACTION_STORE_TRUE) + .Default(true); + opts.AddOption("json-in", 'J', "json-in", "Specify input to be JSON").Type(ARGTYPE_BOOL).Action(ARGACTION_STORE_TRUE); +#ifdef ENABLE_YAML + opts.AddOption("yaml-in", 'Y', "yaml-in", "Specify input to be YAML").Type(ARGTYPE_BOOL).Action(ARGACTION_STORE_TRUE).Group("type-in"); +#endif +#ifdef ENABLE_XML + opts.AddOption("plist-in", 'X', "xml-in", "Specify input to be XML-PLIST").Type(ARGTYPE_BOOL).Action(ARGACTION_STORE_TRUE).Group("type-in"); +#endif + opts.AddOption("bundlehdr-in", 'B', "bundlehdr-in", "Specify input to be bundle header").Type(ARGTYPE_BOOL).Action(ARGACTION_STORE_TRUE) + .Group("type-in"); + opts.AddGroup("type-in").Add("guess-in").Add("json-in").MutuallyExclusive(); + + opts.AddFlag("payload-in", 'P', "payload-in", "Run input through the WithPayload functions instead of regular"); + + opts.AddOption("json", 'j', "json", "Specify output to be JSON").Default(true).Type(ARGTYPE_BOOL).Action(ARGACTION_STORE_TRUE); +#ifdef ENABLE_YAML + opts.AddOption("yaml", 'y', "yaml", "Specify output to be YAML").Type(ARGTYPE_BOOL).Action(ARGACTION_STORE_TRUE).Group("type"); +#endif +#ifdef ENABLE_XML + opts.AddOption("plist", 'x', "xml", "Specify output to be XML-PLIST").Type(ARGTYPE_BOOL).Action(ARGACTION_STORE_TRUE).Group("type"); +#endif + opts.AddOption("bundlehdr", 'b', "bundlehdr", "Specify output to be bundle header").Type(ARGTYPE_BOOL).Action(ARGACTION_STORE_TRUE) + .Group("type"); + opts.AddGroup("type").Add("json").MutuallyExclusive(); + + opts.AddFlag("payload", 'p', "payload", "Run output through the WithPayload functions instead of regular"); + + opts.AddGroup("format", "Format specifiers"); + opts.AddOption("sparams/pretty", 0, "pretty", "Pretty print.").Default(true).Type(ARGTYPE_BOOL).Group("format"); + opts.AddOption("sparams/indent", 0, "indent", "Set indent.").Type(ARGTYPE_INT).Minimum(0).Group("format"); + opts.AddOption("sparams/precision", 0, "precision", "Floating point precision.").Type(ARGTYPE_INT).Minimum(0).Group("format"); + + opts.AddOption("sparams/width", 0, "width", "Set prefered line width (YAML only)").Type(ARGTYPE_INT).Minimum(0).Group("format"); + + opts.AddOption("sparams/scalar_style", 0, "scalar-style", "Set default scalar style (YAML only)").Type(ARGTYPE_STRING).Group("format") + .AddChoice("any").AddChoice("plain").AddChoice("single quoted").AddChoice("double quoted").AddChoice("folded"); + + opts.AddOption("sparams/map_style", 0, "map-style", "Set default map style (YAML only)").Type(ARGTYPE_STRING).Group("format") + .AddChoice("any").AddChoice("block").AddChoice("flow"); + + opts.AddOption("sparams/list_style", 0, "list-style", "Set default list style (YAML only)").Type(ARGTYPE_STRING).Group("format") + .AddChoice("any").AddChoice("block").AddChoice("flow"); + + opts.AddOption("sparams/implicit_document_begin", 0, "implicit-document-begin", "Set to let the emitter omit the document begin tag (YAML only)") + .Group("format") .Type(ARGTYPE_BOOL); + + opts.AddOption("sparams/implicit_document_end", 0, "implicit-document-end", "Set to let the emitter omit the document end tag (YAML only)") + .Group("format") .Type(ARGTYPE_BOOL); + + opts.AddFlag("extension/flatten", 'f', "flatten-path", "Flatten the paths using Flatten/Expand path format specifiers"); + opts.AddFlag("extension/expand", 'e', "expand-path", "Expand the paths using Flatten/Expand path format specifiers"); + + opts.AddGroup("extension-format", "Flatten/Expand path format specifiers"); + + opts.AddOption("extension/params/noSimpleLists", 0, "no-simple-lists") + .Type(ARGTYPE_BOOL).Default(false).Group("extension-format"); + + opts.AddOption("extension/params/pathPrefix", 0, "path-prefix") + .Type(ARGTYPE_STRING).Default("").Group("extension-format").MaxLength(1); + + opts.AddOption("extension/params/pathDelimiter", 0, "path-delimiter") + .Type(ARGTYPE_STRING).Default("/").Group("extension-format").MaxLength(1); + + opts.AddOption("extension/params/indexPrefix", 0, "index-prefix") + .Type(ARGTYPE_STRING).Default("[").Group("extension-format").MaxLength(1); + + opts.AddOption("extension/params/indexSuffix", 0, "index-suffix") + .Type(ARGTYPE_STRING).Default("]").Group("extension-format").MaxLength(1); + + opts.AddOption("extension/params/listDelimiter", 0, "list-delimiter") + .Type(ARGTYPE_STRING).Default(",").Group("extension-format").MaxLength(1); + + opts.AddArgument("input", "The files to read in, if absent read stdin.").Action(ARGACTION_APPEND).MinArgs(0).MaxArgs(0); + + State state; + state.conf = opts.Parse(argc, argv); + + if (state.conf.Get("json", false).AsBool()) { state.stype = SERIALIZE_JSON; } + if (state.conf.Get("yaml", false).AsBool()) { state.stype = SERIALIZE_YAML; } + if (state.conf.Get("plist", false).AsBool()) { state.stype = SERIALIZE_XMLPLIST; } + if (state.conf.Get("bundlehdr", false).AsBool()) { state.stype = SERIALIZE_BUNDLEHDR; } + + state.loader.AddPath("."); + + if (state.conf.Contains("schema_path")) { + for (Variant::ListIterator i(state.conf["schema_path"].ListBegin()), e(state.conf["schema_path"].ListEnd()); i != e; ++i) { + state.loader.AddPath(i->AsString()); + } + } + + if (state.conf.Contains("set-file")) { + state.conf["set"] = DeserializeGuessFile(state.conf["set-file"].AsString().c_str()); + } + + ofstream output_file; + ostream *output = &cout; + if (state.conf.Contains("output")) { + output_file.open(state.conf["output"].AsString().c_str()); + output = &output_file; + } + + if (state.conf.Contains("input")) { + for (Variant::ListIterator i(state.conf["input"].ListBegin()), e(state.conf["input"].ListEnd()); i != e; ++i) { + ifstream input(i->AsString().c_str()); + Process(state, *output, input); + } + } else { + Process(state, *output, cin); + } + return 0; +} + + diff --git a/src/hos_libvariant/src/test/CMakeLists.txt b/src/hos_libvariant/src/test/CMakeLists.txt new file mode 100644 index 00000000..484f7875 --- /dev/null +++ b/src/hos_libvariant/src/test/CMakeLists.txt @@ -0,0 +1,114 @@ + +include_directories ("../src") + +add_executable(rand_test_json rand_test_json.cc) +target_link_libraries(rand_test_json Variant) +add_test(rand_test_json ${CMAKE_CURRENT_BINARY_DIR}/rand_test_json) + +if(LIBVARIANT_ENABLE_YAML) + add_executable(rand_test_yaml rand_test_yaml.cc) + target_link_libraries(rand_test_yaml Variant) + add_test(rand_test_yaml ${CMAKE_CURRENT_BINARY_DIR}/rand_test_yaml) + + add_executable(test_yaml_parser test_yaml_parser.cc) + target_link_libraries(test_yaml_parser Variant) + add_test(test_yaml_parser ${CMAKE_CURRENT_BINARY_DIR}/test_yaml_parser) + + add_executable(test_loadall test_loadall.cc) + target_link_libraries(test_loadall Variant) + add_test(test_loadall ${CMAKE_CURRENT_BINARY_DIR}/test_loadall) +endif() + +if(LIBVARIANT_ENABLE_XML) + add_executable(rand_test_xml rand_test_xml.cc) + target_link_libraries(rand_test_xml Variant) + add_test(rand_test_xml ${CMAKE_CURRENT_BINARY_DIR}/rand_test_xml) + + add_executable(test_xml_parser test_xml_parser.cc) + target_link_libraries(test_xml_parser Variant) + add_test(test_xml_parser ${CMAKE_CURRENT_BINARY_DIR}/test_xml_parser) +endif() + +add_executable(test_variant test_variant.cc) +target_link_libraries(test_variant Variant) +add_test(test_variant ${CMAKE_CURRENT_BINARY_DIR}/test_variant) + +add_executable(test_empty test_empty.cc) +target_link_libraries(test_empty Variant) +add_test(test_empty ${CMAKE_CURRENT_BINARY_DIR}/test_empty) + +add_executable(test_base64 test_base64.cc) +target_link_libraries(test_base64 Variant) +add_test(test_base64 ${CMAKE_CURRENT_BINARY_DIR}/test_base64) + +add_executable(test_memoryoutput test_memoryoutput.cc) +target_link_libraries(test_memoryoutput Variant) +add_test(test_memoryoutput ${CMAKE_CURRENT_BINARY_DIR}/test_memoryoutput) + +add_executable(test_bundlehdr test_bundlehdr.cc) +target_link_libraries(test_bundlehdr Variant) +add_test(test_bundlehdr ${CMAKE_CURRENT_BINARY_DIR}/test_bundlehdr) + +add_executable(test_bundleparser test_bundleparser.cc) +target_link_libraries(test_bundleparser Variant) +add_test(test_bundleparser ${CMAKE_CURRENT_BINARY_DIR}/test_bundleparser) + +add_executable(test_bundleemitter test_bundleemitter.cc) +target_link_libraries(test_bundleemitter Variant) +add_test(test_bundleemitter ${CMAKE_CURRENT_BINARY_DIR}/test_bundleemitter) + +add_executable(test_guess test_guess.cc) +target_link_libraries(test_guess Variant) +add_test(test_guess ${CMAKE_CURRENT_BINARY_DIR}/test_guess) + +add_executable(test_numerics test_numerics.cc) +target_link_libraries(test_numerics Variant) +add_test(test_numerics ${CMAKE_CURRENT_BINARY_DIR}/test_numerics) + +add_definitions("-DTEST_SCHEMA_DATA=\"${CMAKE_CURRENT_SOURCE_DIR}/test_schema_data/\"") +add_executable(test_schema test_schema.cc) +target_link_libraries(test_schema Variant) +add_test(test_schema ${CMAKE_CURRENT_BINARY_DIR}/test_schema) + +add_executable(test_path test_path.cc) +target_link_libraries(test_path Variant) +add_test(test_path ${CMAKE_CURRENT_BINARY_DIR}/test_path) + +add_executable(test_extensions test_extensions.cc) +target_link_libraries(test_extensions Variant) +add_test(test_extensions ${CMAKE_CURRENT_BINARY_DIR}/test_extensions) + +add_executable(test_argparse test_argparse.cc) +target_link_libraries(test_argparse Variant) +configure_file(test_argparse.sh.in + "${CMAKE_CURRENT_BINARY_DIR}/test_argparse.sh" @ONLY) +add_test(test_argparse sh ${CMAKE_CURRENT_BINARY_DIR}/test_argparse.sh) + + +add_executable(test_payload test_payload.cc) +target_link_libraries(test_payload Variant) +add_test(test_payload ${CMAKE_CURRENT_BINARY_DIR}/test_payload) + +add_executable(test_roundtrip test_roundtrip.cc) +target_link_libraries(test_roundtrip Variant) +add_test(test_roundtrip ${CMAKE_CURRENT_BINARY_DIR}/test_roundtrip) + +add_executable(test_argparse_merge test_argparse_merge.cc) +target_link_libraries(test_argparse_merge Variant) +add_test(test_argparse_merge ${CMAKE_CURRENT_BINARY_DIR}/test_argparse_merge) + +add_executable(test_json_parser test_json_parser.cc) +target_link_libraries(test_json_parser Variant) +add_test(test_json_parser ${CMAKE_CURRENT_BINARY_DIR}/test_json_parser) + +if(LIBVARIANT_ENABLE_MSGPACK) + + add_executable(prof_msgpack prof_msgpack.cc) + target_link_libraries(prof_msgpack Variant) + add_test(prof_msgpack ${CMAKE_CURRENT_BINARY_DIR}/prof_msgpack) + + add_executable(rand_test_msgpack rand_test_msgpack.cc) + target_link_libraries(rand_test_msgpack Variant) + add_test(rand_test_msgpack ${CMAKE_CURRENT_BINARY_DIR}/rand_test_msgpack) + +endif() diff --git a/src/hos_libvariant/src/test/TestAssert.h b/src/hos_libvariant/src/test/TestAssert.h new file mode 100644 index 00000000..7c5db218 --- /dev/null +++ b/src/hos_libvariant/src/test/TestAssert.h @@ -0,0 +1,20 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#ifndef TEST_ASSERT_H +#define TEST_ASSERT_H +#include +#include + +inline void test_assert_throw(const char *file, unsigned line, const char *expression) { + std::ostringstream oss; + oss << "Assert failed in " << file << " line " << line + << "\nExpression: " << expression; + throw std::runtime_error(oss.str()); +} + +#define ASSERT(x) if (!(x)) { test_assert_throw(__FILE__, __LINE__, #x); } else (void)0 + +#endif diff --git a/src/hos_libvariant/src/test/TestCommon.h b/src/hos_libvariant/src/test/TestCommon.h new file mode 100644 index 00000000..110c5b2e --- /dev/null +++ b/src/hos_libvariant/src/test/TestCommon.h @@ -0,0 +1,103 @@ +/** \file + * \author John Bridgman + * \brief + */ +#ifndef TESTCOMMON_H +#define TESTCOMMON_H + +#pragma once +#include "../../src/src/EventBuffer.h" +#include "../../src/include/Variant/Variant.h" +#include "../../src/include/Variant/Parser.h" +#include "../../src/include/Variant/Emitter.h" +#include +#include +#include +#include + +namespace libvariant { + +inline bool ErrorCheckEventBuffer(shared_ptr expected, shared_ptr result) { + if (!result->Equal(*expected)) { + if (result->NumEvents() != expected->NumEvents()) { + std::cout << "Error size of action are different, got " << result->NumEvents() << " expected " << expected->NumEvents() << "\n"; + } + for (unsigned i = 0; i < std::max(expected->NumEvents(), result->NumEvents()); ++i) { + if (i < expected->NumEvents() && i < result->NumEvents()) { + if (!(expected->GetEvent(i) == result->GetEvent(i))) { + std::cout << "Action number " << i << " not expected action\nExpected: " << expected->GetEvent(i) + << "\nGot: " << result->GetEvent(i) << "\n"; + } + } else if (i < expected->NumEvents()) { + std::cout << "Action in original not in result: " << expected->GetEvent(i) << "\n"; + } else if (i < result->NumEvents()) { + std::cout << "Action in result not in original: " << result->GetEvent(i) << "\n"; + } + } + return false; + } + return true; +} + +inline int DoRandomTest(int argc, char **argv, +libvariant::Emitter (*Emitter_t)(libvariant::shared_ptr, libvariant::Variant), +libvariant::Parser (*Parser_t)(libvariant::shared_ptr), bool allow_nan) { + int verbose = 0; + int num_tests = 100; + while (true) { + int c = getopt(argc, argv, "n:v:s:h"); + if (c == -1) break; + switch (c) { + case 'n': + num_tests = atoi(optarg); + break; + case 'v': + verbose = atoi(optarg); + break; + case 's': + srand(strtoll(optarg, 0, 0)); + break; + default: + std::cout << *argv << " -s seed -v verbosity -n num_tests\n"; + return 0; + } + } + for (int test = 0; test < num_tests; ++test) { + if (verbose > 0) { std::cout << "Performing test " << test << "\n"; } + shared_ptr expected(new EventBuffer); + expected->FillRandom(EventBuffer::NO_EVENT, 10, allow_nan); + if (verbose > 0) { std::cout << "Generated " << expected->NumEvents() << " events\n"; } + std::ostringstream oss; + libvariant::Variant params; + libvariant::Emitter emitter = Emitter_t(libvariant::CreateEmitterOutput(oss.rdbuf()), params); + shared_ptr event_copy(new EventBuffer(*expected)); + event_copy->Playback(emitter); + emitter.Close(); + std::string val = oss.str(); + if (verbose > 1) { + std::cout << val; + std::cout.flush(); + } + std::istringstream iss(val); + libvariant::Parser parser = Parser_t(libvariant::CreateParserInputFile(iss.rdbuf())); + shared_ptr result(new EventBuffer); + result->Fill(parser); + + bool err = !ErrorCheckEventBuffer(expected, result); + if (err) return 1; + if (verbose > 0) { printf("End test %d\n\n", test); } + } + + return 0; +} + +inline Variant GenerateRandomVariant(bool allow_nan) { + shared_ptr events(new EventBuffer); + events->FillRandom(EventBuffer::NO_EVENT, 10, allow_nan); + Parser p(events); + return ParseVariant(p); +} + +} + +#endif diff --git a/src/hos_libvariant/src/test/prof_msgpack.cc b/src/hos_libvariant/src/test/prof_msgpack.cc new file mode 100644 index 00000000..4336b3c3 --- /dev/null +++ b/src/hos_libvariant/src/test/prof_msgpack.cc @@ -0,0 +1,129 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include "TestCommon.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace libvariant; +using namespace std; + +static double getTime() { + timeval tv; + if (gettimeofday(&tv, 0) != 0) { + throw std::runtime_error(strerror(errno)); + } + return static_cast(tv.tv_sec) + 1e-6 * static_cast(tv.tv_usec); +} + +ostream &operator<<(ostream &os, Variant v) { + SerializeJSON(os.rdbuf(), v, true); + return os; +} + +static const char *suffix[] = { "y", "z", "a", "f", "p", "n", "u", "m", "", +"k", "M", "G", "T", "P", "E", "Z", "Y" }; +static const int suffix_len = sizeof(suffix)/sizeof(char *); + +class engrfmt { +public: + engrfmt(double v) + : value(v){} + + void Print(std::ostream &os) const { + double v = value; + int suffix_off = 8; + while (v >= 1e3 && suffix_off < suffix_len) { + v /= 1e3; + suffix_off++; + } + while (v < 1.0 && suffix_off > 0) { + v /= 1e-3; + suffix_off--; + } + os << v << suffix[suffix_off]; + } +private: + double value; +}; + +ostream &operator<<(ostream &os, const engrfmt &fmt) { + fmt.Print(os); + return os; +} + +std::vector msgpack_serialize_time; +std::vector msgpack_deserialize_time; +std::vector json_serialize_time; +std::vector json_deserialize_time; + +int DoTest(Variant v) { + stringstream ss_msgpack; + //cout << "Testing...\n" << v << endl; + double start = getTime(); + Serialize(ss_msgpack.rdbuf(), v, SERIALIZE_MSGPACK); + msgpack_serialize_time.push_back(getTime() - start); + start = getTime(); + Variant v2 = DeserializeFile(ss_msgpack.rdbuf(), SERIALIZE_MSGPACK); + msgpack_deserialize_time.push_back(getTime() - start); + if (v2 != v) { + cout << "Msgpack: Error not equal:\n"; + cout << "Expected: " << v << endl << "Got: " << v2 << endl; + return 1; + } + stringstream ss_json; + start = getTime(); + Serialize(ss_json.rdbuf(), v, SERIALIZE_JSON); + json_serialize_time.push_back(getTime() - start); + start = getTime(); + v2 = DeserializeFile(ss_json.rdbuf(), SERIALIZE_JSON); + json_deserialize_time.push_back(getTime() - start); + if (v2 != v) { + cout << "JSON: Error not equal:\n"; + cout << "Expected: " << v << endl << "Got: " << v2 << endl; + return 1; + } + return 0; +} + +int main(int argc, char **argv) { + int iterations = 100; + if (argc > 1) { + iterations = 1; + Variant v = DeserializeGuessFile(argv[1]); + if (DoTest(v)) { return 1; } + } else { + for (int i = 0; i < iterations; ++i) { + Variant v = GenerateRandomVariant(false); + if (DoTest(v)) { return 1; } + } + } + double mp_s_avg = 0, mp_d_avg = 0, j_s_avg = 0, j_d_avg = 0; + for (int i = 0; i < iterations; ++i) { + mp_s_avg += msgpack_serialize_time[i]; + mp_d_avg += msgpack_deserialize_time[i]; + j_s_avg += json_serialize_time[i]; + j_d_avg += json_deserialize_time[i]; + } + mp_s_avg /= iterations; + mp_d_avg /= iterations; + j_s_avg /= iterations; + j_d_avg /= iterations; + cout << "msgpack serialize avg time: " << engrfmt(mp_s_avg) << endl; + cout << "msgpack deserialize avg time: " << engrfmt(mp_d_avg) << endl; + cout << "msgpack avg time: " << engrfmt(mp_s_avg + mp_d_avg) << endl; + cout << "json serialize avg time: " << engrfmt(j_s_avg) << endl; + cout << "json deserialize avg time: " << engrfmt(j_d_avg) << endl; + cout << "json avg time: " << engrfmt(j_s_avg + j_d_avg) << endl; + cout << "serialize msgpack/json: " << (mp_s_avg/j_s_avg) << "\tjson/msgpack: " << (j_s_avg/mp_s_avg) << endl; + cout << "deserialize msgpack/json: " << (mp_d_avg/j_d_avg) << "\tjson/msgpack: " << (j_d_avg/mp_d_avg) << endl; + cout << "msgpack/json: " << ((mp_s_avg+mp_d_avg)/(j_s_avg+j_d_avg)) << "\tjson/msgpack: " << (j_s_avg+j_d_avg)/(mp_s_avg+mp_d_avg) << endl; + return 0; +} diff --git a/src/hos_libvariant/src/test/rand_test_json.cc b/src/hos_libvariant/src/test/rand_test_json.cc new file mode 100644 index 00000000..e7192310 --- /dev/null +++ b/src/hos_libvariant/src/test/rand_test_json.cc @@ -0,0 +1,12 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include "TestCommon.h" + +using namespace libvariant; + +int main(int argc, char **argv) { + return DoRandomTest(argc, argv, JSONEmitter, JSONParser, false); +} diff --git a/src/hos_libvariant/src/test/rand_test_msgpack.cc b/src/hos_libvariant/src/test/rand_test_msgpack.cc new file mode 100644 index 00000000..b57d664b --- /dev/null +++ b/src/hos_libvariant/src/test/rand_test_msgpack.cc @@ -0,0 +1,12 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include "TestCommon.h" + +using namespace libvariant; + +int main(int argc, char **argv) { + return DoRandomTest(argc, argv, MsgPackEmitter, MsgPackParser, true); +} diff --git a/src/hos_libvariant/src/test/rand_test_xml.cc b/src/hos_libvariant/src/test/rand_test_xml.cc new file mode 100644 index 00000000..0278dfd0 --- /dev/null +++ b/src/hos_libvariant/src/test/rand_test_xml.cc @@ -0,0 +1,11 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "TestCommon.h" + +using namespace libvariant; + +int main(int argc, char **argv) { + return DoRandomTest(argc, argv, XMLPLISTEmitter, XMLPLISTParser, true); +} diff --git a/src/hos_libvariant/src/test/rand_test_yaml.cc b/src/hos_libvariant/src/test/rand_test_yaml.cc new file mode 100644 index 00000000..841245c7 --- /dev/null +++ b/src/hos_libvariant/src/test/rand_test_yaml.cc @@ -0,0 +1,11 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "TestCommon.h" + +using namespace libvariant; + +int main(int argc, char **argv) { + return DoRandomTest(argc, argv, YAMLEmitter, YAMLParser, true); +} diff --git a/src/hos_libvariant/src/test/test_argparse.cc b/src/hos_libvariant/src/test/test_argparse.cc new file mode 100644 index 00000000..e8ce82b1 --- /dev/null +++ b/src/hos_libvariant/src/test/test_argparse.cc @@ -0,0 +1,181 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include +#include +#include +#include +#include + +using namespace libvariant; +using namespace std; + +SerializeType stype = SERIALIZE_JSON; +Variant sparams = Variant::MapType; + +Variant OtherConfig() { + ArgParse args; + args.AddOption("adv-option1", 's', "adv1", "adv1").Advanced(true); + args.AddOption("adv-option2", 0, "adv2", "adv2").Group("adv"); + args.AddGroup("adv", "adv group").Advanced(true); + return args.GetDescription(); +} + +int Compare(Variant exp, Variant opts) { + for (Variant::MapIterator ci(exp.MapBegin()), ce(exp.MapEnd()); ci != ce; ++ci) { + if (!opts.Contains(ci->first)) { + cout << "Missing key " << ci->first << endl; + return 1; + } + if (ci->second.IsMap()) { + if (Compare(ci->second, opts[ci->first])) { + cout << "In sub map: \"" << ci->first << "\"\n"; + return 1; + } + } else if (opts[ci->first] != ci->second) { + cout << "Value at key \"" << ci->first << "\" differs\n"; + cout << "Got:\n"; + Serialize(cout.rdbuf(), opts[ci->first], stype, sparams); + cout << "\nExpected:\n"; + Serialize(cout.rdbuf(), ci->second, stype, sparams); + cout << endl; + return 1; + } + } + return 0; +} + +int main(int argc, char **argv) { + sparams["pretty"] = true; + + ArgParse args(*argv); + // store -- store the value into the key (default) + args.AddOption("store", 's', "store", "Test store number").Action(ARGACTION_STORE) + .Type(ARGTYPE_FLOAT).Env("TEST_STORE").Minimum(0).Maximum(1) + .Default(0.54321); + args.AddOption("store_bool", 0, "store_bool", "Test store boolean").Action(ARGACTION_STORE) + .Type(ARGTYPE_BOOL).Env("TEST_STORE_BOOLEAN"); + args.AddOption("store_int", 0, "store_int", "Test store int").Action(ARGACTION_STORE) + .Type(ARGTYPE_INT).Minimum(-10).Maximum(10).Default(0); + args.AddOption("store_string", 0, "store_string", "Test store string").Action(ARGACTION_STORE) + .Type(ARGTYPE_STRING).MinLength(4).MaxLength(10).Pattern("^[0-9a-zA-Z]*$") + .Default("abc123"); + try { + args.AddOption("store", 0, "blahblah", ""); + cerr << "Duplicate path successfully added." << endl; + return 1; + } catch (const std::runtime_error&) {} + try { + args.AddOption("blahblah", 0, "store", ""); + cerr << "Duplicate long option successfully added." << endl; + return 1; + } catch (const std::runtime_error&) {} + try { + args.AddOption("blahblah", 's', "", ""); + cerr << "Duplicate short option successfully added." << endl; + return 1; + } catch (const std::runtime_error&) {} + try { + args.AddOption("store", 0, "", ""); + cerr << "Option with no short or long opt sucessfully added." << endl; + return 1; + } catch (const std::runtime_error&) {} + try { + //args.AddOption("abc", 0, "abc", "").Type("abc"); + args.AddOption("abc", 0, "abc", "").Type((ArgParseType)Variant::MapType); + cerr << "Option with invalid type successfully added." << endl; + return 1; + } catch (const std::runtime_error&) {} + + //cerr << "Turning conflict resolution on" << endl; + args.ConflictResolution(true); + try { + args.AddOption("blahblah", 's', "", ""); + cerr << "Duplicate short option with no long option succesfully added" << endl; + return 1; + } catch (const std::runtime_error&) {} + try { + args.AddOption("blahblah", 's', "blahblah", ""); + } catch (const std::runtime_error&) { + cerr << "Failed to add duplicate short option with long option with conflict resolution on." << endl; + return 1; + } + + args.AddOption("store_undef", 0, "store_undef", "Test store").Action(ARGACTION_STORE); + // store_const -- store const (see Const) into the key + args.AddOption("store_const", 0, "store_const", "Test store const").Action(ARGACTION_STORE_CONST) + .Const(123); + // store_true -- store true into the key (i.e. no option argument) + args.AddOption("store_true", 0, "store_true", "Test store_true").Action(ARGACTION_STORE_TRUE) + .Default(false).Type(ARGTYPE_BOOL); + // store_false -- store false into the key + args.AddOption("store_false", 0, "store_false", "Test store_false").Action(ARGACTION_STORE_FALSE) + .Default(true).Type(ARGTYPE_BOOL); + // append -- make the value a list of instances of the option + args.AddOption("append", 0, "append", "Test append").Action(ARGACTION_APPEND) + .Type(ARGTYPE_FLOAT).Minimum(0).Maximum(1).MinArgs(1).MaxArgs(10); + // count -- count the number of instances of this argument + args.AddOption("count", 0, "count", "Test count").Action(ARGACTION_COUNT); + // config -- load a file and merge it into the result (uses GuessFormat) + args.AddOption("load", 0, "load", "Test config").Action(ARGACTION_CONFIG); + + args.AddOption("choice", 0, "choice", "Test choices").AddChoice("a").AddChoice("b"); + + args.AddOption("abc/a", 0, "abc-a", "abc-a"); + args.AddOption("abc/b", 0, "abc-b", "abc-b"); + args.AddGroup("abc", "abc").Add("abc/a").Add("abc/b").MutuallyExclusive(); + args.AddOption("abc/c", 0, "abc-c", "Test group mutual exclusion with default").Default(123); + args.AddOption("abc/d", 0, "abc-d", "Mutually exclusive wth abc-c"); + args.AddGroup("abc-m").Add("abc/c").Add("abc/d").MutuallyExclusive(); + + args.AddArgument("comp", "Comparison file for options") + .Action(ARGACTION_APPEND).Type(ARGTYPE_STRING).MinArgs(0); + + args.AddOption("shortonly", 'a', "", "short only option").Type(ARGTYPE_GUESS); + + args.AddOption("list[0]", 0, "list0", "List zero option").Title("ListOp1"); + args.AddOption("list[1]", 0, "list1", "List one option"); + args.AddOption("list[2]", 0, "list2", "List two option"); + + args.Merge(OtherConfig()); + args.AddConfigDefaults(); + + args.Validate(); + + Variant opts = args.Parse(argc, argv); + + ArgParse arg2; + arg2.Merge(args); + + Variant opt2 = arg2.Parse(argc, argv); + if (opts != opt2) { + cout << "Second parsing of option failed...\n"; + cout << "First pass gave:\n\n"; + Serialize(cout.rdbuf(), opts, stype, sparams); + cout << "\n\nsecond pass gave:\n\n"; + Serialize(cout.rdbuf(), opt2, stype, sparams); + cout << endl; + return 1; + } + + cout << "parsed arguments:\n\n"; + Serialize(cout.rdbuf(), opts, stype, sparams); + cout << "\n\n"; + cout << "Validating..."; + SchemaResult valres = SchemaValidate(args.GenerateSchema(), opts); + if (valres.Error()) { + cout << endl << valres << endl << endl; + return 1; + } else { cout << " passed\n\n"; } + + Variant::ListIterator i(opts["comp"].ListBegin()), + e(opts["comp"].ListEnd()); + while (i != e) { + Variant comp = DeserializeGuessFile(i->AsString().c_str()); + if (Compare(comp, opts)) { return 1; } + ++i; + } + return 0; +} diff --git a/src/hos_libvariant/src/test/test_argparse.sh.in b/src/hos_libvariant/src/test/test_argparse.sh.in new file mode 100644 index 00000000..a6ac5243 --- /dev/null +++ b/src/hos_libvariant/src/test/test_argparse.sh.in @@ -0,0 +1,104 @@ +#!/bin/sh + +ex=@CMAKE_CURRENT_BINARY_DIR@/test_argparse + +echo "Test required argument" +if $ex; then exit 1; fi +echo "Test append argument minimum" +if $ex --append -1; then exit 1; fi +echo "Test append argument maximum" +if $ex --append 2; then exit 1; fi +echo "Test store minimum" +if $ex -s'-1' --append 1; then exit 1; fi +echo "Test store maximum" +if $ex -s'2' --append 1; then exit 1; fi + +echo "Testing store boolean" +if ! echo '{ "store_bool": true }' | $ex --append 1 --store_bool=yes /dev/stdin; then exit 1; fi +if ! echo '{ "store_bool": true }' | $ex --append 1 --store_bool=Y /dev/stdin; then exit 1; fi +if ! echo '{ "store_bool": true }' | $ex --append 1 --store_bool=t /dev/stdin; then exit 1; fi +if ! echo '{ "store_bool": true }' | $ex --append 1 --store_bool=1 /dev/stdin; then exit 1; fi +if ! echo '{ "store_bool": false }' | $ex --append 1 --store_bool=N /dev/stdin; then exit 1; fi +if ! echo '{ "store_bool": false }' | $ex --append 1 --store_bool=no /dev/stdin; then exit 1; fi +if ! echo '{ "store_bool": false }' | $ex --append 1 --store_bool=0 /dev/stdin; then exit 1; fi +if ! echo '{ "store_bool": false }' | $ex --append 1 --store_bool=f /dev/stdin; then exit 1; fi +if ! echo '{ "store_bool": true }' | TEST_STORE_BOOLEAN=yes $ex --append 1 /dev/stdin; then exit 1; fi + +echo "Test store integer" + +if $ex --append 1 --store_int -11; then exit 1; fi +if $ex --append 1 --store_int 11; then exit 1; fi +if $ex --append 1 --store_int 'abc'; then exit 1; fi +if $ex --append 1 --store_int 1.4; then exit 1; fi +if ! echo '{ "store_int": 4}' | $ex --append 1 --store_int 4 /dev/stdin; then exit 1; fi + +echo "Test store string" +if $ex --append 1 --store_string "@#$^aaa"; then exit 1; fi +if $ex --append 1 --store_string "a"; then exit 1; fi +if $ex --append 1 --store_string "0123456789aaaaaa"; then exit 1; fi +if ! echo '{ "store_string": "abc123" }' | $ex --append 1 /dev/stdin; then exit 1; fi +if ! echo '{ "store_string": "7j34d" }' | $ex --append 1 --store_string 7j34d /dev/stdin; then exit 1; fi + +if $ex --append 1 --choice "aaaa"; then exit 1; fi +if ! echo '{ "choice": "a" }' | $ex --append 1 --choice "a" /dev/stdin; then exit 1; fi +if ! echo '{ "choice": "b" }' | $ex --append 1 --choice "b" /dev/stdin; then exit 1; fi + +echo "Test group mutual exclusion" +if $ex --append 1 --abc-a=1 --abc-b=2; then exit 1; fi +if ! echo '{ "abc": { "a": 1 } }' | $ex --append 1 --abc-a=1 /dev/stdin; then + exit 1 +fi +if ! echo '{ "abc": { "b": 1 } }' | $ex --append 1 --abc-b=1 /dev/stdin; then + exit 1 +fi + +if $ex --append 1 --abc-c=1 --abc-d=2; then exit 1; fi +if ! echo '{ "abc": { "c": 1 } }' | $ex --append 1 --abc-c=1 /dev/stdin; then + exit 1 +fi +if ! echo '{ "abc": { "d": 1 } }' | $ex --append 1 --abc-d=1 /dev/stdin; then + exit 1 +fi +if ! echo '{ "abc": { "c": 123 } }' | $ex --append 1 /dev/stdin; then exit 1; fi + +echo "Generic tests" +expected=' +{ + "append": [ 0.1 ], + "store": 0.54321, + "store_int": 0, + "store_string": "abc123", + "store_true": false, + "store_false": true +}'; + +if ! echo $expected | $ex --append 0.1 /dev/stdin; then exit 1; fi + +expected=' +{ + "store": 0.5, + "append": [ 1, 0.4 ], + "store_bool": true, + "store_int": 5, + "store_string": "zxcv098784", + "store_undef": true, + "store_true": true, + "store_const": 123, + "store_false": false, + "count": 3, + "comp": [ "/dev/stdin" ] +} +'; +echo $expected | $ex --store 0.5 --append 1 --append 0.4 --store_bool yes --store_int 5 --store_string "zxcv098784" \ + --store_undef true --store_true --store_false --count --store_const --count --count /dev/stdin; +if [[ $? != 0 ]]; then exit 1; fi; + +tmpfile=$(mktemp) +echo $expected >$tmpfile +echo $expected | $ex --config $tmpfile; +if [[ $? != 0 ]]; then exit 1; fi; +rm $tmpfile + +echo "PASS!!"; +exit 0; + diff --git a/src/hos_libvariant/src/test/test_argparse_merge.cc b/src/hos_libvariant/src/test/test_argparse_merge.cc new file mode 100644 index 00000000..fd8c33d1 --- /dev/null +++ b/src/hos_libvariant/src/test/test_argparse_merge.cc @@ -0,0 +1,109 @@ +//============================================================================= +//! \file main.cc +//! \author Josh Staley +//============================================================================= + +//=== Includes ================================================================ + +#include +#include +#include + +#include + +using namespace std; +using namespace libvariant; + +//=== Foo ===================================================================== + +class Foo { + +public: + + Foo ( Variant opts = Variant::MapType ): + mOpts ( opts ) + { + SchemaResult result = SchemaValidate( Foo::GetArgParse().GenerateSchema(), mOpts ); + if ( result.Error() ) + cerr << "# Foo: " << result.PrettyPrintMessage() << endl; + } + + static ArgParse GetArgParse () + { + ArgParse argParse; + + // -v --verbose + argParse.AddOption( "foo/verbosity", 'v', "foo-verbose", + "Set foo verbosity level" + ).Action( ARGACTION_COUNT ).Default(0); + + argParse.AddOption( "list[0]/foo", 'f', "foo", "FoOOooOooOoo!" ); + + return argParse; + } + +private: + + Variant mOpts; + +}; + +//=== Bar ===================================================================== + +class Bar { + +public: + + Bar ( Variant opts = Variant::MapType ): + mOpts ( opts ) + { + SchemaResult result = SchemaValidate( Bar::GetArgParse().GenerateSchema(), mOpts ); + if ( result.Error() ) + cerr << "# Bar: " << result.PrettyPrintMessage() << endl; + } + + static ArgParse GetArgParse () + { + ArgParse argParse; + + // -v --verbose + argParse.AddOption( "bar/verbosity", 'v', "bar-verbose", + "Set bar verbosity level" + ).Action( ARGACTION_COUNT ).Default(0); + + argParse.AddOption( "list[1]/bar", 'b', "bar", "BaaaaAAAaaar!" ); + + return argParse; + } + +private: + + Variant mOpts; + +}; + +//=== Main ==================================================================== + +int main ( int argc, char *argv[] ) +{ + ArgParse argParse( "Test" ); + argParse.ConflictResolution(); + argParse.Merge( Foo::GetArgParse() ); + argParse.Merge( Bar::GetArgParse() ); + Variant opts = argParse.Parse( argc, argv ); + + Foo foo( opts ); + Bar bar( opts ); + + cout << "--- Foo ---" << endl; + cout << Serialize( Foo::GetArgParse().GenerateSchema(), SERIALIZE_JSON, Variant().Set( "pretty", true ) ) << endl; + + cout << "--- Bar ---" << endl; + cout << Serialize( Bar::GetArgParse().GenerateSchema(), SERIALIZE_JSON, Variant().Set( "pretty", true ) ) << endl; + + cout << "--- Merged ---" << endl; + cout << Serialize( argParse.GenerateSchema(), SERIALIZE_JSON, Variant().Set( "pretty", true ) ) << endl; + return 0; +} + +//============================================================================= diff --git a/src/hos_libvariant/src/test/test_base64.cc b/src/hos_libvariant/src/test/test_base64.cc new file mode 100644 index 00000000..5bc66f81 --- /dev/null +++ b/src/hos_libvariant/src/test/test_base64.cc @@ -0,0 +1,1032 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "Base64.h" +#include +#include +#include +using namespace libvariant; + +unsigned char test_data[] = { + 0xde, 0xc1, 0x9a, 0x7c, 0xc6, 0xdb, 0xda, 0x3d, 0x77, 0xc5, 0x37, 0xf7, + 0x2c, 0xf1, 0x15, 0x47, 0xe4, 0x63, 0xe5, 0x68, 0x62, 0x8e, 0x6c, 0x09, + 0xbd, 0xd7, 0x74, 0xfc, 0x73, 0x00, 0xe8, 0x82, 0xc2, 0x7c, 0x73, 0x1b, + 0x26, 0xe5, 0x73, 0x6b, 0xf7, 0xcc, 0x15, 0xf6, 0xc2, 0x21, 0x8f, 0x3e, + 0x28, 0xd9, 0xb2, 0x96, 0xaf, 0x96, 0xef, 0xfe, 0xcd, 0x3a, 0x55, 0x68, + 0xc6, 0xaa, 0xe7, 0xfa, 0x36, 0x34, 0x34, 0xa9, 0xa7, 0xd9, 0x1f, 0x10, + 0x85, 0x98, 0xd5, 0x4a, 0x7b, 0x88, 0x04, 0xba, 0x6c, 0x36, 0xdb, 0x69, + 0x31, 0xbd, 0x06, 0x70, 0xfb, 0x06, 0x3a, 0x4b, 0x4f, 0xc2, 0x11, 0xca, + 0x5d, 0x3a, 0x11, 0x0d, 0x39, 0x40, 0x18, 0xa7, 0x5a, 0xd2, 0x7f, 0x85, + 0x4a, 0xcf, 0x3e, 0x9f, 0x02, 0x24, 0x07, 0x9b, 0x67, 0x1e, 0x09, 0x54, + 0xcf, 0xab, 0xb5, 0x18, 0xaa, 0xd3, 0xc7, 0xbd, 0x48, 0xd5, 0x17, 0xe6, + 0x16, 0x93, 0x8d, 0x2e, 0x84, 0xc0, 0x97, 0x71, 0xb4, 0x6a, 0xae, 0x2e, + 0x0b, 0x0c, 0x04, 0xad, 0xae, 0x28, 0x4e, 0x63, 0x22, 0x9b, 0x52, 0xfd, + 0x9e, 0xf3, 0xac, 0x54, 0x8d, 0xaa, 0xe4, 0x15, 0x68, 0x25, 0x6b, 0x3e, + 0x07, 0xd6, 0x0a, 0x15, 0x8f, 0x37, 0xa0, 0xb1, 0xbf, 0xd0, 0x24, 0xff, + 0x58, 0x73, 0xd6, 0xcd, 0xca, 0xc2, 0x32, 0x34, 0xb4, 0x09, 0x8d, 0xf8, + 0xf8, 0xa1, 0xa9, 0xba, 0xcc, 0xde, 0x1b, 0x79, 0x62, 0xd7, 0x47, 0xcf, + 0x32, 0x48, 0xbc, 0xc1, 0x66, 0xf5, 0x87, 0xf8, 0xcd, 0xa0, 0x5a, 0xee, + 0x4f, 0x8b, 0xf1, 0x68, 0xf8, 0xf4, 0x63, 0x19, 0x4c, 0xe0, 0x3c, 0x3b, + 0x1a, 0x69, 0x8f, 0xf6, 0x17, 0xe2, 0x38, 0x6c, 0x53, 0x9b, 0x90, 0x73, + 0x1f, 0xd6, 0x5d, 0x7d, 0xfa, 0xb7, 0x80, 0x83, 0xe8, 0x7a, 0xbd, 0x84, + 0x0a, 0xff, 0xdf, 0x02, 0xee, 0x29, 0x75, 0x6e, 0x25, 0x9d, 0x37, 0x90, + 0x62, 0x53, 0x5a, 0x88, 0xb9, 0x8e, 0x5a, 0xfa, 0x5f, 0x6c, 0x1f, 0xed, + 0x9a, 0x4b, 0x69, 0x0e, 0xd2, 0x61, 0xd3, 0x17, 0x57, 0x0c, 0x52, 0x32, + 0x43, 0x83, 0x6a, 0x3b, 0x41, 0x43, 0xa4, 0xbe, 0xb9, 0xbd, 0xd5, 0xe7, + 0xe5, 0xb2, 0x16, 0x59, 0xba, 0xb0, 0xf5, 0xbc, 0xe2, 0x5b, 0x79, 0x96, + 0xd2, 0xa0, 0xa3, 0x08, 0x76, 0xa8, 0xbb, 0xff, 0xcb, 0xf2, 0x15, 0x66, + 0x6c, 0x49, 0x9b, 0xcb, 0xc5, 0x8d, 0xb2, 0xc6, 0xea, 0xaa, 0x17, 0x09, + 0x1b, 0x1c, 0x87, 0xb9, 0x67, 0xc7, 0x85, 0xc1, 0x38, 0xe6, 0x2c, 0xd3, + 0x09, 0x97, 0xf8, 0xe0, 0xd2, 0xb1, 0x62, 0x72, 0xfc, 0x79, 0x77, 0x35, + 0xbb, 0x6e, 0x54, 0xdc, 0xdf, 0x9b, 0xcf, 0x46, 0xdb, 0xb2, 0xbb, 0xf9, + 0xb9, 0x7c, 0xa8, 0xeb, 0x01, 0x2e, 0x37, 0xb4, 0xfd, 0x3e, 0xa1, 0x82, + 0x6b, 0x31, 0x18, 0x72, 0x3a, 0x55, 0x7e, 0xc9, 0xb9, 0xc8, 0x1b, 0xdc, + 0xd9, 0xa0, 0x16, 0x4c, 0xfd, 0x6d, 0xfe, 0xf0, 0x6a, 0x66, 0x88, 0xb9, + 0x20, 0x6e, 0xb5, 0x4f, 0xbc, 0xdb, 0x94, 0xbb, 0x00, 0x4a, 0xa3, 0x3f, + 0x79, 0xc0, 0xf4, 0x18, 0x93, 0xa1, 0x2d, 0xec, 0xae, 0x5e, 0x42, 0xca, + 0x15, 0x01, 0x40, 0xd7, 0x59, 0x90, 0x0e, 0x92, 0x33, 0x98, 0x8f, 0xe0, + 0x68, 0xe4, 0xea, 0x8e, 0x37, 0x70, 0x3f, 0x4a, 0x83, 0x27, 0x08, 0xf0, + 0xc7, 0x39, 0x0f, 0x1c, 0x21, 0xb7, 0x6b, 0x2f, 0x9e, 0x73, 0x21, 0x23, + 0x16, 0x15, 0xdd, 0xc4, 0xbe, 0xef, 0x35, 0xea, 0xd8, 0x5e, 0xad, 0x83, + 0xa9, 0x13, 0xeb, 0x40, 0x94, 0x77, 0x9f, 0xdb, 0xdc, 0x97, 0x54, 0x01, + 0x15, 0x58, 0x09, 0x8d, 0x21, 0x1c, 0xe0, 0x3a, 0xc4, 0xbd, 0x75, 0x1b, + 0xef, 0x8a, 0xb5, 0x78, 0xaa, 0x23, 0x79, 0x69, 0xcc, 0x15, 0x43, 0xfa, + 0x65, 0xf5, 0x6a, 0xca, 0x23, 0x42, 0x7e, 0x8e, 0x19, 0xfb, 0x05, 0x43, + 0xae, 0x4c, 0x8a, 0xe6, 0xdb, 0x05, 0xc1, 0xbe, 0xd5, 0x31, 0x61, 0xab, + 0xd4, 0x8e, 0x89, 0x21, 0xe2, 0x1b, 0xa8, 0xcd, 0xa0, 0xf5, 0x9e, 0xd1, + 0x00, 0x3c, 0x05, 0xb6, 0x42, 0xba, 0x53, 0x8b, 0x52, 0x6b, 0x75, 0x99, + 0x76, 0x31, 0x09, 0x7f, 0x9d, 0xa5, 0xa3, 0xe4, 0x2f, 0x45, 0x8d, 0x7e, + 0x32, 0xd0, 0x33, 0xd3, 0xa4, 0xd2, 0x01, 0x67, 0x75, 0x08, 0xf7, 0x69, + 0x8e, 0x9d, 0xec, 0x63, 0x71, 0xa8, 0x3c, 0xcc, 0x2c, 0x15, 0x24, 0x3e, + 0x66, 0xcd, 0x24, 0xee, 0x78, 0xbc, 0x60, 0x4c, 0xd4, 0x4b, 0xc1, 0x50, + 0x44, 0xbe, 0xb4, 0x60, 0xb9, 0x22, 0x1b, 0x12, 0x33, 0x34, 0x1b, 0xa9, + 0x04, 0x9f, 0x01, 0x6b, 0xdd, 0x1f, 0x4c, 0x64, 0x98, 0x05, 0xb8, 0x7f, + 0xb3, 0x41, 0xd1, 0xee, 0xd8, 0xef, 0xb6, 0x61, 0x37, 0x22, 0x39, 0xa5, + 0x16, 0x0e, 0x9d, 0x93, 0x74, 0x6f, 0x32, 0xf0, 0xb1, 0x13, 0x00, 0x78, + 0x25, 0x96, 0x90, 0xcf, 0x8f, 0xe1, 0x1a, 0xa0, 0x81, 0xc5, 0x96, 0x1a, + 0x9c, 0x89, 0x94, 0xc7, 0xc3, 0x4c, 0xec, 0xe5, 0xa5, 0xb2, 0x4d, 0x6c, + 0x0f, 0x8d, 0x09, 0x34, 0x8e, 0x54, 0xc3, 0xbb, 0x51, 0xb7, 0x3e, 0x82, + 0xda, 0x5f, 0x21, 0x8f, 0xf3, 0x68, 0x82, 0x33, 0xcb, 0x64, 0x71, 0x9c, + 0xdf, 0xab, 0xfa, 0xb4, 0x57, 0xd9, 0x07, 0x78, 0xa2, 0xe8, 0xa6, 0xba, + 0x8c, 0x48, 0x2f, 0xb3, 0x96, 0x1c, 0x1d, 0xa4, 0x1c, 0xe0, 0x15, 0x6e, + 0xc4, 0x80, 0xd7, 0x4d, 0x78, 0xce, 0x9a, 0x77, 0x2a, 0x90, 0xe4, 0xde, + 0x66, 0x88, 0x54, 0xda, 0x14, 0x3f, 0x02, 0x30, 0x67, 0x23, 0x94, 0x76, + 0xc3, 0x28, 0xe4, 0x1b, 0xbf, 0x37, 0x13, 0x0f, 0xc9, 0xa9, 0xdd, 0x75, + 0x63, 0x41, 0x07, 0x7c, 0xad, 0xda, 0xb2, 0x62, 0x9c, 0xaf, 0x1d, 0x4b, + 0x46, 0x71, 0x16, 0xc8, 0xb4, 0x04, 0x62, 0xa3, 0x1c, 0x06, 0xdd, 0x58, + 0x3a, 0xb8, 0x83, 0x4b, 0x1c, 0xa8, 0x7b, 0xa8, 0x9c, 0x36, 0x1a, 0x01, + 0x23, 0x99, 0x10, 0xf6, 0x1d, 0x1e, 0x2e, 0x80, 0xe4, 0x46, 0x8a, 0x30, + 0x42, 0xc2, 0x48, 0x18, 0x70, 0x2a, 0x60, 0x52, 0xc0, 0x55, 0xc0, 0xef, + 0x2a, 0x2d, 0x44, 0x5e, 0xea, 0x77, 0x74, 0x81, 0xde, 0xed, 0x74, 0x48, + 0xac, 0x27, 0xf9, 0x5d, 0xff, 0xb2, 0xab, 0xd9, 0x6b, 0x03, 0x5a, 0x9f, + 0x6a, 0x7d, 0x7b, 0x05, 0xad, 0x76, 0x51, 0x9c, 0xc1, 0x46, 0x86, 0x9b, + 0x7b, 0x7d, 0x90, 0x57, 0x14, 0x35, 0xf8, 0xa4, 0xb6, 0xb7, 0xcd, 0x19, + 0x0a, 0x86, 0x37, 0x6a, 0xc3, 0xe9, 0xeb, 0x78, 0x77, 0x4d, 0x06, 0x0a, + 0xad, 0x0a, 0xec, 0xdb, 0x6e, 0xe5, 0xdc, 0x58, 0xba, 0x65, 0xbf, 0x01, + 0x76, 0x8a, 0xed, 0x0a, 0x88, 0x24, 0x95, 0x91, 0x14, 0x47, 0x52, 0x77, + 0xb1, 0x02, 0x19, 0x79, 0x78, 0xaf, 0x73, 0x37, 0x8c, 0xed, 0x07, 0x6e, + 0x64, 0xfe, 0xde, 0x29, 0x2d, 0x29, 0x95, 0x4e, 0xc8, 0x12, 0x65, 0x8c, + 0x93, 0x7f, 0xa7, 0xde, 0x88, 0x03, 0xb9, 0x14, 0x5e, 0xc2, 0x8c, 0x97, + 0x88, 0xe4, 0x30, 0x3a, 0xc8, 0x00, 0x52, 0x26, 0x61, 0x98, 0x8a, 0xdc, + 0x59, 0x1b, 0xc9, 0x98, 0x75, 0xf1, 0xbf, 0xc0, 0x79, 0xe0, 0x65, 0x29, + 0xd2, 0xc6, 0x51, 0x33, 0x67, 0xaf, 0x0f, 0xcb, 0x1a, 0x89, 0xce, 0xf9, + 0x27, 0x2d, 0x23, 0xc3, 0x56, 0x07, 0xb6, 0xb9, 0x74, 0x0a, 0x90, 0xcc, + 0x47, 0x53, 0xcf, 0x77, 0xa7, 0x9d, 0x03, 0xc6, 0x73, 0xce, 0x3e, 0xc5, + 0x5b, 0xfc, 0xc8, 0x6a, 0x18, 0x09, 0xac, 0x27, 0x66, 0x18, 0x7a, 0xba, + 0x9e, 0x3d, 0xd1, 0x0a, 0xdd, 0xc2, 0x1e, 0x40, 0x20, 0xf1, 0x05, 0x66, + 0xbb, 0x4c, 0xa0, 0x2b, 0xd0, 0x8b, 0x53, 0xcb, 0x35, 0x45, 0xa3, 0x0e, + 0x75, 0x8b, 0xea, 0x27, 0xcc, 0xb2, 0xa3, 0xd7, 0x7d, 0xaf, 0x60, 0xcb, + 0x62, 0xab, 0x2c, 0x24, 0x93, 0x29, 0xa7, 0x71, 0xed, 0x66, 0x26, 0x98, + 0xaf, 0xc9, 0x6b, 0x7d, 0x57, 0xc4, 0x4f, 0xb7, 0x48, 0x81, 0x0c, 0x1a, + 0xc3, 0x7e, 0xde, 0x33, 0xff, 0x12, 0xec, 0xe9, 0x6c, 0x2f, 0xcd, 0x67, + 0x16, 0x80, 0x67, 0x21, 0x6b, 0x09, 0x8d, 0x1b, 0xa4, 0xd0, 0xec, 0x63, + 0x07, 0xc2, 0x38, 0x50, 0xcd, 0x7a, 0xc3, 0xe5, 0x43, 0x1d, 0xd0, 0x22, + 0x86, 0x4f, 0xa3, 0x84, 0x07, 0xb2, 0xc3, 0x7d, 0x8e, 0xb4, 0xb1, 0x1d, + 0xe0, 0x73, 0x1b, 0xf9, 0x6f, 0xc9, 0x60, 0xa6, 0x78, 0x34, 0x60, 0x66, + 0xd1, 0x47, 0x26, 0x78, 0x11, 0x24, 0x39, 0x27, 0x33, 0xae, 0x38, 0x96, + 0x97, 0x7c, 0x14, 0x7d, 0xc5, 0x74, 0xd4, 0xaf, 0xb3, 0x7d, 0x28, 0x61, + 0xe5, 0x21, 0xc0, 0xba, 0xdc, 0xcf, 0x55, 0xba, 0x2a, 0x6f, 0xcc, 0x29, + 0x96, 0x5e, 0xca, 0x35, 0x7c, 0xbc, 0x93, 0xf0, 0xa8, 0xf8, 0x09, 0xc1, + 0xa5, 0xf1, 0xb2, 0x05, 0x64, 0xa1, 0xf8, 0x43, 0x62, 0xea, 0xce, 0x2a, + 0xc2, 0x95, 0xcc, 0x11, 0x0b, 0xf6, 0xff, 0x66, 0x50, 0xf0, 0xfe, 0xd1, + 0x95, 0xa5, 0xd1, 0x8a, 0x95, 0x00, 0x6b, 0x4a, 0x1c, 0x14, 0xdd, 0x7d, + 0xf6, 0x97, 0x07, 0xbe, 0x3b, 0x7d, 0x58, 0x4e, 0x09, 0xed, 0x9b, 0x13, + 0x6e, 0xca, 0xca, 0xf9, 0x66, 0x0f, 0xc3, 0x2a, 0xed, 0xd1, 0xe7, 0x3e, + 0x52, 0x0c, 0xde, 0x0d, 0xe3, 0x02, 0x4d, 0x29, 0xac, 0xae, 0x9f, 0xb8, + 0xb1, 0x46, 0x3c, 0xa4, 0xad, 0x27, 0x77, 0x39, 0x42, 0xc7, 0x09, 0x0a, + 0x12, 0x91, 0xfd, 0x3e, 0xd4, 0x00, 0x13, 0x9b, 0xd6, 0xe7, 0xc8, 0x88, + 0x35, 0x7b, 0x65, 0x26, 0x94, 0x74, 0x59, 0x1a, 0x9f, 0xc1, 0x3a, 0xa4, + 0x4a, 0x2b, 0xf0, 0xaa, 0x7e, 0xc9, 0x7c, 0x8f, 0xbf, 0x15, 0x32, 0xbd, + 0x8d, 0xb3, 0xa4, 0x8e, 0x1f, 0x15, 0x1d, 0x4b, 0xda, 0xf4, 0x20, 0xa5, + 0xcc, 0x09, 0xc3, 0x18, 0x18, 0x7e, 0xcb, 0xb3, 0x38, 0x56, 0x07, 0x67, + 0x75, 0x5d, 0x53, 0xde, 0x8f, 0xc9, 0x45, 0xac, 0x9e, 0xb2, 0xa9, 0x47, + 0xb0, 0x61, 0x87, 0xa0, 0x39, 0x8f, 0x86, 0xde, 0xa3, 0xc3, 0xc8, 0x76, + 0x9c, 0xc2, 0x75, 0x02, 0x81, 0x7c, 0xcf, 0x20, 0x98, 0xc7, 0x05, 0xfd, + 0xa6, 0x2f, 0x28, 0xdb, 0x96, 0xa4, 0xad, 0x05, 0xd7, 0xb2, 0x55, 0xef, + 0x3b, 0xa3, 0x30, 0x7a, 0x32, 0x34, 0x4e, 0x6c, 0xd3, 0x63, 0x9c, 0x85, + 0x88, 0xa3, 0x9a, 0x14, 0xdb, 0x6d, 0xa5, 0xaa, 0xa2, 0x45, 0x3e, 0xca, + 0x95, 0x96, 0x5d, 0x26, 0xd0, 0x8b, 0x1e, 0xf3, 0x1a, 0x3f, 0xe1, 0xca, + 0x24, 0x09, 0xc1, 0x9a, 0x1a, 0xbb, 0xba, 0x84, 0x70, 0x1b, 0x9b, 0x30, + 0xdc, 0x33, 0x16, 0xb5, 0x17, 0x37, 0x90, 0x78, 0x16, 0x2c, 0x09, 0x24, + 0x4e, 0xdc, 0x83, 0x55, 0x13, 0xe8, 0x19, 0x49, 0xfa, 0xb8, 0x19, 0x8e, + 0x80, 0x18, 0xe7, 0x89, 0xa7, 0xe1, 0x88, 0x31, 0x14, 0xd5, 0xc6, 0xdf, + 0xe7, 0x5e, 0x95, 0x9e, 0x48, 0x24, 0xdd, 0x09, 0x28, 0xd1, 0xbb, 0xe0, + 0x61, 0xbb, 0x2a, 0x76, 0xbf, 0xe5, 0x28, 0x21, 0x0e, 0x6f, 0x6c, 0x96, + 0xbb, 0xf0, 0x25, 0x66, 0xfe, 0xb2, 0x22, 0x07, 0x77, 0xf5, 0x11, 0x3e, + 0xa7, 0x1d, 0x12, 0x55, 0x03, 0x48, 0xc9, 0xae, 0xb4, 0x86, 0x44, 0xf1, + 0x37, 0xe6, 0x92, 0xc8, 0x4d, 0xc6, 0xb4, 0xa9, 0x12, 0xc6, 0xe8, 0x10, + 0x48, 0x91, 0xea, 0xe3, 0x38, 0x40, 0x86, 0x27, 0x43, 0x1d, 0xdf, 0x34, + 0xbb, 0x7a, 0x64, 0xf0, 0x7e, 0x00, 0x79, 0x24, 0x3b, 0x6b, 0x16, 0x2b, + 0x1d, 0x94, 0xb5, 0xc5, 0xe7, 0x16, 0x62, 0xac, 0x10, 0xba, 0xe0, 0x83, + 0x7e, 0xd7, 0x40, 0xd2, 0x6f, 0x3c, 0x49, 0x22, 0x4f, 0x34, 0x82, 0x55, + 0xd6, 0xb1, 0x56, 0x4a, 0x8d, 0x8f, 0x34, 0x82, 0x66, 0x92, 0x58, 0xf1, + 0x01, 0x67, 0x0d, 0xac, 0xdb, 0x5b, 0xcb, 0xbc, 0xe7, 0xd7, 0x68, 0x42, + 0xb7, 0x47, 0x3c, 0x63, 0x8c, 0x33, 0x94, 0x36, 0xfa, 0x5a, 0x0c, 0x1d, + 0x7a, 0x46, 0x26, 0x6c, 0xb4, 0x12, 0x01, 0x89, 0xab, 0x36, 0x78, 0x05, + 0x75, 0xda, 0x63, 0xf4, 0xe6, 0x20, 0x37, 0x6e, 0x51, 0xea, 0x7a, 0xa5, + 0xdd, 0xde, 0xc8, 0x74, 0x66, 0x27, 0x05, 0x56, 0x9b, 0xbf, 0x05, 0x31, + 0x77, 0x0f, 0x93, 0xb7, 0x15, 0xb8, 0x20, 0x13, 0x83, 0x0b, 0xe2, 0xe6, + 0x36, 0x3e, 0x89, 0xf0, 0x3b, 0xe3, 0x5b, 0xbf, 0x8e, 0xb8, 0x33, 0x5e, + 0x43, 0xc9, 0xc1, 0xdd, 0x9a, 0xcd, 0x9b, 0x5a, 0x58, 0x2e, 0x6e, 0x50, + 0xd4, 0x13, 0x64, 0x07, 0x46, 0x7e, 0x83, 0x80, 0x33, 0x43, 0xd3, 0xa7, + 0x1e, 0x07, 0x2c, 0xaf, 0x03, 0xd5, 0x1f, 0x7d, 0x95, 0xf4, 0x70, 0x08, + 0xab, 0xa9, 0x36, 0xff, 0xf2, 0xc5, 0xbc, 0x82, 0x5e, 0x75, 0x8a, 0xd0, + 0x32, 0xfb, 0xf4, 0x34, 0x44, 0x42, 0x42, 0x76, 0xce, 0x27, 0x42, 0x93, + 0x29, 0x54, 0x21, 0x14, 0x2a, 0x2f, 0x93, 0xd8, 0x2a, 0xe8, 0xf8, 0x44, + 0xec, 0x4c, 0x8b, 0xdb, 0xe9, 0xdc, 0x38, 0x35, 0xca, 0xb8, 0x34, 0x9f, + 0xec, 0x32, 0x24, 0xda, 0x45, 0x6f, 0x74, 0x4d, 0x42, 0xa3, 0x9c, 0x18, + 0xee, 0x91, 0x25, 0x11, 0xae, 0xbc, 0x94, 0x48, 0x0e, 0x9a, 0x4f, 0x5b, + 0x60, 0x41, 0x76, 0x1a, 0x06, 0xae, 0x1a, 0x0f, 0x57, 0x23, 0xe8, 0xcd, + 0x00, 0xc6, 0xc2, 0x83, 0xa2, 0x36, 0x90, 0x4d, 0xf1, 0xe3, 0x7e, 0xda, + 0xf6, 0xff, 0x36, 0x37, 0x10, 0x78, 0xe2, 0x5f, 0x59, 0x7c, 0x07, 0xe9, + 0xe6, 0x3c, 0x7a, 0x3c, 0xbf, 0x89, 0x80, 0xce, 0x07, 0xca, 0xbc, 0xee, + 0x54, 0x09, 0x12, 0xa1, 0x0f, 0x34, 0xe3, 0xde, 0x8e, 0x96, 0xdf, 0xe5, + 0x36, 0x68, 0xb4, 0x3a, 0x6d, 0x51, 0x96, 0x9b, 0x10, 0xdb, 0x7e, 0x31, + 0x22, 0xd2, 0x60, 0x3e, 0x2f, 0x63, 0xb8, 0x40, 0x56, 0x4c, 0x3d, 0xae, + 0xba, 0x3b, 0x06, 0x66, 0x31, 0xc8, 0xa7, 0x2b, 0xea, 0xa1, 0xc4, 0x8c, + 0x80, 0x5f, 0xcc, 0x85, 0xc4, 0xd4, 0xc5, 0x77, 0xb3, 0x30, 0x1f, 0xfe, + 0xe6, 0x19, 0x4a, 0x95, 0x41, 0x57, 0x5c, 0xb4, 0x73, 0x5d, 0x78, 0x47, + 0x02, 0x28, 0x91, 0x67, 0x3a, 0xd0, 0x86, 0x23, 0xa9, 0x74, 0x10, 0x15, + 0x79, 0x71, 0x36, 0x6d, 0xf4, 0xb3, 0x89, 0xb3, 0x77, 0xa5, 0xf0, 0x5f, + 0x37, 0x89, 0xc3, 0xec, 0xcf, 0x80, 0x2b, 0x0b, 0x99, 0xd3, 0xe5, 0x19, + 0x23, 0x94, 0x85, 0x1f, 0x07, 0x3d, 0x19, 0x3a, 0x60, 0xaa, 0x71, 0xfb, + 0xf1, 0x17, 0x3d, 0xd9, 0x07, 0x42, 0x92, 0xf5, 0xc5, 0xb2, 0x53, 0x50, + 0x7c, 0x00, 0x45, 0xb5, 0x05, 0xa1, 0xf8, 0x02, 0x91, 0x6e, 0x9e, 0x2f, + 0x5b, 0x42, 0x48, 0x01, 0x12, 0x53, 0x79, 0xbe, 0x2f, 0x18, 0x0e, 0xa0, + 0x8d, 0x22, 0x1b, 0xfd, 0x51, 0x33, 0x56, 0x16, 0x2f, 0x2e, 0x38, 0x75, + 0x5f, 0xcd, 0x58, 0xa1, 0x0c, 0x27, 0x35, 0x0c, 0x27, 0x6d, 0xfa, 0x57, + 0x99, 0x14, 0xee, 0xe1, 0xcb, 0x52, 0xd7, 0xee, 0x0f, 0x24, 0xf0, 0x32, + 0xf3, 0x6f, 0x82, 0x63, 0x99, 0xa3, 0xd7, 0xd7, 0x82, 0xff, 0xc2, 0xd9, + 0x66, 0x69, 0x27, 0x73, 0x24, 0x37, 0xac, 0xff, 0x21, 0x97, 0x4a, 0xf9, + 0xba, 0x75, 0x2d, 0x89, 0x49, 0x35, 0x4a, 0x07, 0x19, 0xd7, 0x83, 0xc1, + 0x89, 0x67, 0x6a, 0x57, 0x7a, 0xf8, 0x28, 0x62, 0xd3, 0xa6, 0x26, 0x8d, + 0x85, 0xe6, 0xb0, 0x91, 0x10, 0xf4, 0xbd, 0x65, 0x5a, 0x9e, 0x62, 0x30, + 0x07, 0x5d, 0x73, 0xbd, 0x29, 0xaf, 0x68, 0xbf, 0x8d, 0x6f, 0xab, 0xab, + 0xf9, 0x3e, 0x8e, 0x6a, 0xe4, 0xfb, 0x0f, 0xb9, 0xc9, 0xe9, 0xe8, 0xbe, + 0xb1, 0x6e, 0x81, 0xc7, 0xb7, 0xaf, 0xc7, 0xf7, 0xc4, 0x07, 0x2c, 0x15, + 0xaf, 0xb4, 0x10, 0xf5, 0x78, 0x0f, 0x52, 0x1d, 0x2c, 0xd4, 0xb7, 0x08, + 0xc9, 0xba, 0x9a, 0xfa, 0x46, 0x86, 0x16, 0x7a, 0x8d, 0x21, 0xb6, 0xb1, + 0xb5, 0xd4, 0x8a, 0xcc, 0x16, 0x2a, 0x17, 0xeb, 0xcd, 0xb3, 0xb0, 0xb0, + 0xe1, 0x75, 0x09, 0x15, 0x65, 0xd8, 0x6c, 0x73, 0xfc, 0xed, 0x2f, 0x24, + 0xbb, 0xfb, 0xbc, 0xaa, 0xf4, 0xf5, 0x2e, 0xf9, 0x0b, 0xbe, 0xb8, 0x49, + 0x7d, 0xf4, 0x85, 0xae, 0x2a, 0xb8, 0x06, 0x33, 0x73, 0x5f, 0x30, 0x62, + 0xdb, 0xc0, 0xb3, 0x21, 0xeb, 0x4b, 0x33, 0x08, 0x52, 0x91, 0xdc, 0x9d, + 0xf1, 0x70, 0x02, 0x47, 0x84, 0x1a, 0xa5, 0xdd, 0x9c, 0x69, 0x8f, 0xf1, + 0x97, 0x92, 0xd8, 0xbe, 0x22, 0xf2, 0x91, 0x0e, 0xca, 0x46, 0xc1, 0x21, + 0x9f, 0x93, 0xb9, 0x89, 0xb7, 0xbb, 0x88, 0x10, 0xa3, 0x78, 0xa7, 0x41, + 0xea, 0x13, 0x7f, 0x6a, 0x62, 0xc4, 0x52, 0x4f, 0xf2, 0x8c, 0x16, 0xf0, + 0x32, 0x08, 0x6c, 0x58, 0xd8, 0xb9, 0x9d, 0x02, 0x68, 0x59, 0x26, 0x2f, + 0xb1, 0x70, 0x6c, 0xc1, 0x8c, 0xbc, 0xa3, 0x7e, 0x0f, 0x7c, 0xb2, 0x4f, + 0xc5, 0x3e, 0xef, 0xec, 0xa1, 0xc6, 0x8a, 0x35, 0x19, 0xcc, 0x24, 0xdc, + 0xbe, 0x24, 0x30, 0x8c, 0xf2, 0x1a, 0x88, 0x8d, 0xe6, 0x7a, 0xd0, 0xc5, + 0x17, 0x3c, 0x1d, 0xe6, 0xb4, 0xdf, 0x62, 0xec, 0xfc, 0x14, 0xb3, 0x2f, + 0x03, 0xd6, 0xc8, 0x73, 0x43, 0x12, 0x15, 0x44, 0x52, 0xeb, 0xc9, 0x2a, + 0x7b, 0x6c, 0x3e, 0x82, 0x52, 0xaf, 0x2f, 0xf8, 0xa8, 0xd5, 0xcc, 0xc7, + 0x8f, 0xfd, 0xbd, 0xb7, 0xbe, 0xd2, 0x94, 0x6a, 0x01, 0x7c, 0xae, 0xf1, + 0x2a, 0xab, 0x0c, 0xc2, 0x7a, 0x62, 0x7a, 0x57, 0x73, 0x2e, 0x6c, 0x1c, + 0x25, 0x17, 0xd8, 0x47, 0x92, 0x9b, 0xec, 0xcd, 0x73, 0x58, 0x0c, 0x9b, + 0x4d, 0x79, 0x97, 0x10, 0xa7, 0x47, 0xe3, 0x33, 0xba, 0xf8, 0x9d, 0xec, + 0x4a, 0xce, 0xf7, 0xab, 0x78, 0x9a, 0x5e, 0x51, 0x63, 0x1a, 0xd5, 0x47, + 0x10, 0x1f, 0x29, 0x6d, 0x54, 0x06, 0xb9, 0xb9, 0xd8, 0xd5, 0x60, 0x88, + 0xc3, 0x84, 0x96, 0x09, 0x18, 0xd6, 0x20, 0xa5, 0xda, 0x2b, 0x9d, 0xca, + 0xeb, 0x69, 0x54, 0x50, 0xae, 0x97, 0x02, 0x4c, 0x14, 0x85, 0x89, 0x46, + 0x4e, 0xfc, 0x0c, 0x71, 0x77, 0x88, 0xb3, 0x0c, 0xfc, 0x50, 0xff, 0xf5, + 0xa9, 0x8f, 0x5f, 0xe9, 0x1d, 0x07, 0xed, 0xf6, 0xdd, 0xe0, 0xeb, 0xc1, + 0x4a, 0x25, 0xc7, 0xca, 0x7b, 0x10, 0x8f, 0x9c, 0x11, 0xf3, 0x23, 0xe6, + 0x20, 0xe2, 0x13, 0x34, 0xe2, 0x88, 0x54, 0x77, 0xbb, 0x9a, 0x37, 0xa5, + 0x47, 0xde, 0x30, 0xa0, 0x1e, 0xd9, 0x88, 0x73, 0x4c, 0x05, 0xce, 0x58, + 0xeb, 0x32, 0x87, 0x67, 0x5a, 0x57, 0xc2, 0x38, 0x0e, 0xc6, 0x00, 0xa4, + 0x37, 0x8d, 0x89, 0x7f, 0xa9, 0xba, 0x09, 0x9f, 0x40, 0x74, 0x61, 0xe5, + 0x61, 0x3a, 0xee, 0xb4, 0x75, 0x16, 0x13, 0x9e, 0x98, 0x1b, 0x9f, 0x92, + 0x14, 0xd0, 0x09, 0x9f, 0x33, 0xc3, 0x29, 0xda, 0xac, 0x5b, 0x3d, 0xac, + 0xf5, 0x73, 0x89, 0xf7, 0xa0, 0x21, 0xab, 0xf1, 0x3b, 0x95, 0xff, 0x24, + 0x76, 0xa6, 0xe6, 0x06, 0xec, 0xfe, 0xce, 0x57, 0xb8, 0x68, 0x5d, 0x73, + 0xa5, 0xa9, 0x00, 0xed, 0x66, 0xd7, 0x05, 0x8b, 0x28, 0xff, 0xf1, 0x91, + 0x67, 0x21, 0xe1, 0xe7, 0xcd, 0x65, 0x20, 0x22, 0x4e, 0x5d, 0x1b, 0x7b, + 0x2d, 0x9d, 0x2d, 0xc9, 0xb5, 0xee, 0xaf, 0x55, 0xa0, 0x18, 0xf5, 0xd7, + 0xd8, 0x1e, 0xf0, 0x3a, 0xe6, 0x27, 0xd4, 0x1a, 0x93, 0x39, 0xbb, 0x19, + 0x2d, 0xae, 0xf0, 0xf0, 0xee, 0x34, 0x12, 0xfc, 0x48, 0xb0, 0x97, 0xce, + 0x7c, 0x52, 0xdd, 0xf7, 0x2a, 0x9b, 0x15, 0xb4, 0xf5, 0xf3, 0x13, 0x16, + 0x2d, 0x0f, 0x30, 0xbf, 0x7b, 0xdf, 0xca, 0x44, 0xd4, 0x46, 0x27, 0x47, + 0xcd, 0x3c, 0xbf, 0xd6, 0x1b, 0xc4, 0x24, 0x4b, 0x1e, 0xf5, 0x50, 0x55, + 0xcd, 0x84, 0x85, 0x71, 0x46, 0xd4, 0xac, 0x6f, 0xbf, 0x2c, 0x80, 0xb8, + 0x8e, 0x54, 0xf1, 0x0d, 0xd8, 0x07, 0x77, 0xbc, 0xad, 0x84, 0x9e, 0xcd, + 0xc0, 0xb8, 0x61, 0x73, 0x08, 0x41, 0xfd, 0x4f, 0xb3, 0xe3, 0xdc, 0x5b, + 0x3e, 0xfe, 0xe5, 0xbd, 0xf4, 0xcb, 0xab, 0x85, 0x1a, 0x1d, 0x4e, 0x3b, + 0xa9, 0x0e, 0xdd, 0xff, 0x8b, 0x07, 0xcf, 0x5b, 0x32, 0x2b, 0xb9, 0x4c, + 0x2c, 0x3e, 0xe9, 0x43, 0x5d, 0x32, 0x69, 0xa2, 0xc9, 0xb0, 0x4f, 0x14, + 0x07, 0x28, 0xa0, 0x2e, 0xa5, 0x6d, 0x13, 0x07, 0x96, 0x90, 0xb1, 0x55, + 0x33, 0x43, 0x23, 0x53, 0x9d, 0x6b, 0x8a, 0xb5, 0xa9, 0x46, 0xe6, 0xeb, + 0x19, 0xd4, 0x85, 0xb1, 0x70, 0xe5, 0xd4, 0xdd, 0x56, 0x4a, 0x07, 0xa8, + 0xd1, 0x9b, 0xae, 0xec, 0x02, 0x5d, 0xb4, 0x10, 0xa1, 0x77, 0x56, 0xe6, + 0x4b, 0xff, 0x55, 0xf4, 0x70, 0xa2, 0x04, 0x5c, 0xb7, 0xa8, 0x10, 0xbe, + 0xdc, 0xac, 0xb8, 0xa0, 0xd3, 0x24, 0x94, 0xb1, 0x68, 0x4e, 0x85, 0xf0, + 0xdf, 0x67, 0x02, 0xd7, 0x4e, 0x3d, 0x70, 0x88, 0x86, 0xe6, 0x1e, 0xe4, + 0xe1, 0x3d, 0x1f, 0x04, 0x7b, 0xae, 0x17, 0x10, 0x73, 0xa8, 0xdd, 0x60, + 0xe0, 0x48, 0x29, 0xbd, 0x38, 0xa8, 0x45, 0x0a, 0x13, 0x6d, 0x88, 0xe7, + 0x96, 0x92, 0x4f, 0x8e, 0x1b, 0xb1, 0x43, 0xc0, 0x76, 0xc5, 0x0c, 0x3c, + 0xe3, 0xd8, 0xf1, 0xe2, 0x80, 0xc3, 0x72, 0xb4, 0x1d, 0x7f, 0x79, 0x0b, + 0x3e, 0xba, 0x3c, 0x8b, 0xf1, 0xd0, 0x06, 0x05, 0x3c, 0x83, 0x33, 0xe6, + 0x88, 0x0a, 0x10, 0x60, 0xe4, 0x40, 0x56, 0x68, 0x46, 0xec, 0x43, 0xbc, + 0x29, 0x9b, 0x7c, 0x2e, 0xbb, 0xd1, 0xc0, 0x82, 0x10, 0x26, 0xfa, 0x59, + 0x76, 0x83, 0xca, 0x93, 0xcf, 0x42, 0x84, 0x7b, 0x0d, 0x1f, 0x32, 0x65, + 0xe6, 0xac, 0x11, 0x37, 0x67, 0xc0, 0xb1, 0xe4, 0x74, 0xca, 0x22, 0x8f, + 0xd1, 0xd2, 0x55, 0x3f, 0x33, 0x10, 0x2d, 0x9e, 0xa3, 0x0a, 0xcd, 0x2e, + 0x5a, 0x19, 0xeb, 0xb9, 0x53, 0xd6, 0x09, 0xe3, 0x4c, 0xca, 0x40, 0x06, + 0xb7, 0xde, 0x26, 0x90, 0xab, 0xe3, 0xc6, 0x49, 0x14, 0x6d, 0xbf, 0x59, + 0x4b, 0xb7, 0x3d, 0x64, 0xe6, 0x6a, 0xc0, 0x1b, 0xe8, 0x5a, 0x09, 0xd3, + 0x07, 0x39, 0xaa, 0x69, 0x35, 0xf2, 0xc0, 0x2d, 0xe1, 0x8b, 0xc0, 0xb4, + 0x2d, 0x46, 0x34, 0x5d, 0xeb, 0x1e, 0x5b, 0x09, 0x69, 0x34, 0x8f, 0xe4, + 0xed, 0x40, 0x4c, 0xf5, 0xc1, 0x28, 0xa4, 0x31, 0x45, 0xf3, 0xe7, 0x11, + 0x8e, 0x02, 0x5c, 0xd7, 0x47, 0x4d, 0x02, 0x84, 0x11, 0xbf, 0xc7, 0xba, + 0xd1, 0x6b, 0x6c, 0x99, 0x71, 0x39, 0x2d, 0x52, 0x7b, 0x7c, 0xd5, 0x9d, + 0x4e, 0x2c, 0xc6, 0x56, 0x72, 0xf3, 0x72, 0x61, 0xbc, 0xc4, 0x44, 0x4d, + 0x3f, 0x4c, 0xd9, 0x31, 0x45, 0xcd, 0x9f, 0xf5, 0xf8, 0xcc, 0x5b, 0xbd, + 0x42, 0xe8, 0xc3, 0x9e, 0x76, 0x2e, 0x7b, 0x99, 0x4f, 0x10, 0xea, 0x22, + 0xad, 0x81, 0x42, 0x49, 0xe3, 0x69, 0xa9, 0x76, 0xd2, 0x42, 0xec, 0xae, + 0x69, 0x81, 0x1c, 0x9b, 0x25, 0xab, 0xca, 0xed, 0x5c, 0x56, 0x84, 0x2b, + 0xee, 0xfc, 0x12, 0xc5, 0x65, 0xbf, 0x7d, 0xb2, 0x2a, 0x65, 0x56, 0xaf, + 0xf7, 0x02, 0x9b, 0x74, 0x7f, 0x13, 0x56, 0xf5, 0x51, 0x84, 0xd9, 0x02, + 0xeb, 0x23, 0xa8, 0xa5, 0x41, 0xca, 0xea, 0xb6, 0xcc, 0x73, 0xb3, 0x67, + 0x0b, 0xb3, 0x6f, 0x1e, 0xce, 0x08, 0xcf, 0x4b, 0xb7, 0xad, 0x6d, 0x4a, + 0x44, 0x04, 0x94, 0x15, 0x59, 0x1d, 0x04, 0xcf, 0x2b, 0x45, 0x93, 0x29, + 0x3e, 0xe6, 0x1f, 0xe3, 0x69, 0x81, 0x81, 0x56, 0x1c, 0x61, 0xe5, 0xcb, + 0xd8, 0x13, 0x97, 0x8e, 0xf2, 0x01, 0x2f, 0xb6, 0x41, 0x1f, 0xfa, 0x28, + 0x7f, 0x92, 0xc8, 0x52, 0x38, 0x7c, 0x2a, 0x1f, 0x89, 0x07, 0xcf, 0xf5, + 0xc8, 0x1d, 0x57, 0x81, 0xa3, 0x1a, 0x48, 0xd8, 0x7e, 0xdb, 0xc3, 0x1f, + 0xbb, 0xcc, 0xf2, 0xc8, 0x17, 0xa9, 0xaf, 0xb7, 0x0b, 0xbd, 0x6e, 0xf0, + 0xcd, 0x96, 0x22, 0x00, 0xda, 0x10, 0x39, 0xd2, 0xc5, 0xc3, 0x92, 0x9c, + 0xc0, 0x61, 0x22, 0x43, 0x9d, 0x17, 0x0f, 0x22, 0x37, 0x22, 0xe1, 0x6b, + 0xd2, 0x05, 0xd7, 0xf2, 0xdb, 0xec, 0x3f, 0x99, 0xe7, 0x86, 0x45, 0x1a, + 0x4e, 0xf7, 0x33, 0xef, 0xf1, 0x11, 0xad, 0xb7, 0x72, 0x95, 0x73, 0x78, + 0x52, 0x2c, 0x83, 0x6f, 0x19, 0x0d, 0x9e, 0xfa, 0x20, 0x6a, 0x82, 0xbe, + 0x9f, 0x7a, 0xe5, 0x47, 0x29, 0xf6, 0xfd, 0xbf, 0xd5, 0x3d, 0x2f, 0x89, + 0xac, 0xd3, 0xae, 0xad, 0x15, 0x21, 0xed, 0x72, 0x38, 0x25, 0x8e, 0x68, + 0xd8, 0xf0, 0x72, 0xd6, 0xde, 0x30, 0x60, 0x42, 0x1d, 0x20, 0x13, 0x29, + 0xf8, 0x6c, 0x50, 0xe2, 0x06, 0xa6, 0xae, 0xdc, 0x1b, 0x34, 0x8c, 0x3e, + 0xe2, 0xd8, 0x8a, 0x09, 0x9a, 0x99, 0x7a, 0xb0, 0xf9, 0x38, 0xb0, 0xf5, + 0x68, 0x97, 0xfd, 0x4d, 0x9c, 0xfd, 0xa1, 0x97, 0x57, 0xfc, 0x79, 0x8d, + 0x47, 0xca, 0x2b, 0xba, 0x68, 0x42, 0xfe, 0x1a, 0x84, 0xd4, 0x93, 0x99, + 0x51, 0x8f, 0xe3, 0xb1, 0x76, 0x86, 0xd0, 0x24, 0x66, 0x18, 0x88, 0xfb, + 0x18, 0x17, 0x46, 0x30, 0xf9, 0x4d, 0xe4, 0x7a, 0x45, 0x52, 0x78, 0xee, + 0xa1, 0x41, 0xa5, 0xd6, 0x5d, 0x54, 0x39, 0xdd, 0xba, 0x31, 0x5c, 0x92, + 0xcc, 0xc5, 0xe8, 0xcb, 0xac, 0x5a, 0xbf, 0x36, 0xde, 0xe6, 0xbe, 0x5c, + 0xef, 0xa3, 0x24, 0x46, 0x23, 0x92, 0xd2, 0x96, 0xe8, 0x8b, 0x89, 0xae, + 0x01, 0xde, 0xfc, 0xe3, 0xde, 0xb2, 0x04, 0xab, 0x27, 0x82, 0xec, 0xd4, + 0xdf, 0x0f, 0xb7, 0xa3, 0x5d, 0xb9, 0x61, 0x37, 0x60, 0x7c, 0xb1, 0x4d, + 0x51, 0xec, 0xc7, 0xbe, 0xf3, 0x00, 0xa2, 0xdb, 0x01, 0x42, 0x02, 0x45, + 0x77, 0x12, 0xe1, 0xc1, 0x22, 0xd8, 0x21, 0x91, 0x90, 0x12, 0x41, 0x60, + 0x45, 0xfd, 0x6a, 0x2d, 0x79, 0x1b, 0x4e, 0xcb, 0x33, 0xc4, 0x0f, 0x7e, + 0x5b, 0xb3, 0xec, 0x13, 0x22, 0xad, 0x79, 0x5f, 0x89, 0x1c, 0xeb, 0xcb, + 0x82, 0x0a, 0x6d, 0xbc, 0x6c, 0xea, 0x06, 0x7d, 0x3d, 0xea, 0x48, 0xd8, + 0x62, 0x1f, 0x1d, 0x09, 0xe6, 0xab, 0x69, 0xbd, 0x88, 0x4f, 0x68, 0x3e, + 0x34, 0x80, 0xcf, 0x0c, 0x15, 0x20, 0x5d, 0xae, 0x75, 0x6b, 0xc5, 0xef, + 0x66, 0xfc, 0x67, 0xac, 0x85, 0x7a, 0x30, 0xac, 0xb8, 0x61, 0xfc, 0x4b, + 0x48, 0xa4, 0xcb, 0x6b, 0x98, 0x02, 0x3c, 0x56, 0xff, 0xb0, 0xbb, 0x59, + 0x41, 0x00, 0xd4, 0x6b, 0x21, 0xef, 0x32, 0x86, 0x25, 0x9d, 0xf2, 0xc4, + 0x98, 0x38, 0xea, 0x20, 0x39, 0x9f, 0x97, 0xae, 0xe1, 0x63, 0xf6, 0x5e, + 0x2d, 0x3a, 0x0d, 0xb6, 0xf6, 0x01, 0xec, 0x8c, 0x87, 0x8d, 0x45, 0x00, + 0xa0, 0xa3, 0xfa, 0xe8, 0xf6, 0x60, 0xaa, 0xe9, 0xab, 0xff, 0xfc, 0x6c, + 0x82, 0xcc, 0x8a, 0x57, 0x82, 0x23, 0xf3, 0x26, 0x80, 0xfb, 0xac, 0x42, + 0xc1, 0xc8, 0xe8, 0x99, 0x21, 0xf3, 0xff, 0x61, 0x02, 0xb6, 0xb7, 0x59, + 0x14, 0xd2, 0xb2, 0x5b, 0xae, 0x7e, 0xa6, 0xf0, 0xed, 0x75, 0xdc, 0xe3, + 0x3f, 0x29, 0xed, 0x48, 0x29, 0x2b, 0x7c, 0xdb, 0x50, 0x85, 0x5f, 0xa9, + 0x6f, 0x8c, 0x0a, 0xf5, 0x0e, 0x29, 0x31, 0xc3, 0x7c, 0xb2, 0xe0, 0xf1, + 0x7f, 0x13, 0xa9, 0x13, 0x8b, 0x4d, 0xfb, 0x06, 0x95, 0x32, 0x61, 0xd1, + 0xd5, 0x62, 0xc5, 0x4f, 0xb1, 0xa5, 0xcf, 0xae, 0x46, 0x87, 0xf5, 0xb9, + 0xf9, 0x43, 0x6c, 0x95, 0x5d, 0x79, 0x1e, 0x6c, 0xec, 0x5c, 0x9a, 0x87, + 0x27, 0x1a, 0x00, 0xe1, 0x53, 0x7c, 0x9c, 0xa8, 0xab, 0xa4, 0x1a, 0x35, + 0x63, 0x60, 0x46, 0x95, 0xf3, 0xc1, 0xa2, 0xa5, 0x65, 0xf8, 0xd3, 0xdd, + 0xba, 0x3f, 0x4e, 0x12, 0xd2, 0xab, 0xba, 0xaf, 0x22, 0x2b, 0xe7, 0x54, + 0x61, 0xab, 0x5d, 0xe8, 0xb6, 0xa2, 0xf9, 0x02, 0x16, 0xc8, 0x31, 0x81, + 0xa4, 0xa5, 0x7a, 0x73, 0xea, 0x41, 0x13, 0x7f, 0x44, 0x06, 0x89, 0x38, + 0xd3, 0x1d, 0xaa, 0xb9, 0x4b, 0xd4, 0x61, 0xb0, 0xf2, 0x19, 0x66, 0x1b, + 0xa0, 0x15, 0xbe, 0xac, 0xb2, 0x93, 0x5c, 0x49, 0x6b, 0x3c, 0x89, 0xad, + 0x19, 0x19, 0xf5, 0x16, 0x46, 0xd7, 0x86, 0x77, 0x4a, 0xc7, 0x55, 0xcf, + 0x7a, 0x9b, 0xb4, 0xa5, 0x8a, 0xdd, 0xcf, 0x55, 0xe6, 0xc0, 0x8b, 0x59, + 0x4a, 0x57, 0xd1, 0x14, 0x76, 0x0b, 0xe5, 0xa5, 0xbc, 0xf3, 0xb4, 0x0a, + 0x93, 0xdf, 0x12, 0x44, 0xd9, 0xf8, 0x57, 0x9d, 0x99, 0xc0, 0x39, 0xe0, + 0xab, 0xa7, 0xcf, 0xe5, 0xa6, 0xd4, 0xd9, 0xcf, 0xf0, 0xc6, 0x0c, 0x15, + 0x23, 0x0c, 0x3f, 0xb5, 0xdd, 0xc9, 0x6b, 0xac, 0x06, 0x0c, 0x12, 0x1c, + 0x32, 0x13, 0x2e, 0x4b, 0x30, 0x7d, 0x1e, 0x5a, 0x22, 0x7a, 0x6a, 0x9b, + 0x09, 0xbb, 0x0c, 0xfd, 0x27, 0x02, 0xc9, 0x3d, 0x2c, 0x1b, 0xf6, 0x8a, + 0xbf, 0x99, 0x4b, 0x7b, 0xa6, 0xfd, 0x60, 0x43, 0xfd, 0x7e, 0x61, 0x0e, + 0xc6, 0x6b, 0x8d, 0xa2, 0x36, 0x06, 0xea, 0xf3, 0x72, 0x0b, 0x11, 0xd1, + 0x2f, 0xd6, 0x09, 0x00, 0x0f, 0xd7, 0x98, 0xd7, 0x76, 0x08, 0xa6, 0x01, + 0x13, 0x25, 0x5b, 0x34, 0x33, 0x4f, 0x78, 0x22, 0x60, 0x7f, 0x9d, 0x68, + 0x31, 0xbc, 0x34, 0x6a, 0xb7, 0xbc, 0x5e, 0x47, 0xdb, 0x57, 0xae, 0x08, + 0x10, 0x30, 0x84, 0x2b, 0xf5, 0x63, 0x85, 0x85, 0x90, 0xb8, 0x14, 0xa5, + 0x4d, 0x59, 0x05, 0x91, 0x75, 0xa0, 0xdb, 0x50, 0x04, 0x82, 0xdc, 0x72, + 0x57, 0x3c, 0x65, 0xd6, 0x75, 0x62, 0x02, 0x3b, 0x67, 0xd6, 0xbf, 0x18, + 0xae, 0xc1, 0x07, 0xde, 0xd4, 0x2c, 0x1b, 0x67, 0x78, 0x1f, 0x67, 0x83, + 0x2e, 0x2e, 0x88, 0xf7, 0x3c, 0x87, 0xc2, 0x6a, 0x55, 0x2b, 0x74, 0x32, + 0x7e, 0xa0, 0x46, 0x7d, 0xcb, 0x5d, 0x77, 0x16, 0x45, 0xa2, 0xd9, 0xc9, + 0xfa, 0xcb, 0x25, 0xef, 0x8d, 0x77, 0xd0, 0xe9, 0x9c, 0x81, 0x8b, 0x79, + 0x9a, 0x9e, 0x56, 0x2f, 0xf2, 0x8e, 0x5c, 0x02, 0xdc, 0x51, 0xde, 0x04, + 0x60, 0xf2, 0x17, 0x59, 0xfa, 0xa3, 0x37, 0x09, 0xb1, 0x2a, 0xec, 0x2d, + 0x9c, 0xf3, 0xe7, 0xab, 0x68, 0x2e, 0x50, 0x50, 0xf6, 0x06, 0x90, 0x79, + 0xc3, 0xf1, 0x22, 0x7a, 0xa3, 0xf6, 0x7f, 0xf9, 0x33, 0x5f, 0x0c, 0xb7, + 0x35, 0x60, 0x4c, 0xca, 0x92, 0x8f, 0x2b, 0x21, 0x4e, 0xcf, 0x6c, 0xe3, + 0x47, 0x46, 0x95, 0x03, 0x9b, 0x31, 0x00, 0x1f, 0xe6, 0xc3, 0xc6, 0x10, + 0x2d, 0x4e, 0x25, 0x4e, 0xce, 0xbd, 0xfc, 0x3e, 0x6d, 0x2b, 0x95, 0x09, + 0x0f, 0xd1, 0x58, 0x44, 0xe9, 0x9f, 0x5a, 0xe9, 0x01, 0x6b, 0x8b, 0xca, + 0xdf, 0xda, 0xd6, 0x47, 0x8c, 0x74, 0x90, 0x6a, 0xf1, 0x1a, 0xfe, 0x79, + 0x91, 0x3d, 0x68, 0x9d, 0x56, 0xb1, 0x53, 0x44, 0x9f, 0x7d, 0x5a, 0x31, + 0x85, 0xab, 0xab, 0xa0, 0x3e, 0x3a, 0xdf, 0x0e, 0xcf, 0x06, 0x97, 0xe2, + 0x04, 0x57, 0x3a, 0x6f, 0xde, 0x15, 0x7f, 0x8b, 0x72, 0x40, 0x2c, 0xc9, + 0xf0, 0xa8, 0x73, 0x73, 0x3c, 0x1b, 0x5d, 0x85, 0x85, 0x15, 0x7e, 0x7a, + 0x52, 0x07, 0x4d, 0xa3, 0xac, 0x30, 0xac, 0x65, 0xb3, 0x5b, 0xd0, 0x81, + 0xe1, 0x42, 0x38, 0xb8, 0x30, 0x9d, 0x50, 0xe6, 0x6e, 0x71, 0x8d, 0x01, + 0xc2, 0x44, 0xd7, 0x52, 0xb9, 0xdb, 0x84, 0x2a, 0xdf, 0xc4, 0x1c, 0xf3, + 0xfb, 0xb3, 0x9d, 0x09, 0x47, 0xab, 0x8b, 0x5c, 0x9c, 0x62, 0xd1, 0xd3, + 0xf0, 0x68, 0x00, 0x4f, 0x42, 0x09, 0x94, 0xe8, 0xcb, 0x56, 0x23, 0x48, + 0xe4, 0x99, 0xfc, 0x23, 0xa5, 0xad, 0x5f, 0x9a, 0x07, 0xcf, 0x99, 0x77, + 0x08, 0x10, 0xd7, 0x76, 0xeb, 0x24, 0x53, 0x0d, 0xd3, 0x25, 0xc0, 0x6f, + 0xcf, 0x57, 0x19, 0x36, 0x2d, 0x69, 0xfa, 0x59, 0xc2, 0x4c, 0x35, 0xa2, + 0xc8, 0x6a, 0x8f, 0xe7, 0x9e, 0x3c, 0x72, 0x12, 0xd3, 0x1a, 0x89, 0xc1, + 0xc8, 0xff, 0x6d, 0xf4, 0x58, 0x36, 0x78, 0xb8, 0x1a, 0xa6, 0x84, 0x6b, + 0x5f, 0xad, 0x10, 0x37, 0xec, 0xe1, 0x1b, 0xe4, 0x0c, 0xa3, 0x45, 0xc9, + 0x0e, 0xa9, 0x7c, 0xc9, 0x5e, 0x1c, 0xb3, 0xfa, 0xd9, 0x8d, 0x44, 0x8a, + 0x6e, 0x45, 0x3b, 0x68, 0x51, 0x5a, 0xb2, 0x64, 0x5b, 0x94, 0x4b, 0x9a, + 0xd9, 0xa1, 0x94, 0xc0, 0xff, 0xe5, 0x89, 0x75, 0x4a, 0x63, 0xa0, 0x6b, + 0x9b, 0x6a, 0x96, 0xb8, 0x8b, 0xbe, 0x6e, 0x10, 0x3e, 0x6e, 0xf9, 0x27, + 0xdc, 0x10, 0x5a, 0xc0, 0x5e, 0x51, 0x0a, 0x25, 0x11, 0x6e, 0xf4, 0x91, + 0x4e, 0xb1, 0x4b, 0x3d, 0xcc, 0x62, 0x92, 0x54, 0xb1, 0x96, 0xbb, 0x68, + 0xe2, 0x1f, 0x1c, 0x2a, 0x33, 0xb7, 0xf0, 0xc8, 0x7e, 0x47, 0xfd, 0x76, + 0x95, 0x41, 0x1b, 0xcc, 0x70, 0x1d, 0x40, 0xfc, 0x16, 0x91, 0xf1, 0xa9, + 0xc1, 0x76, 0xd1, 0x85, 0xa0, 0x95, 0xf2, 0xdb, 0x76, 0xb8, 0x8c, 0xf2, + 0x18, 0x62, 0x9f, 0x9e, 0xe2, 0xff, 0x84, 0x3c, 0x3f, 0xdc, 0x75, 0x3b, + 0x49, 0x6b, 0xd4, 0xd9, 0xa6, 0x17, 0x86, 0x53, 0x26, 0x59, 0x78, 0x12, + 0x40, 0x96, 0x88, 0x82, 0xae, 0xdf, 0x84, 0x26, 0xfc, 0xac, 0x50, 0x28, + 0xc1, 0xdd, 0x87, 0x9e, 0xfa, 0x52, 0xda, 0x12, 0x89, 0x83, 0x49, 0x16, + 0x67, 0xf4, 0xc3, 0x25, 0x48, 0x82, 0x64, 0xb4, 0x1b, 0x83, 0xff, 0xc3, + 0x0f, 0xac, 0x5b, 0xde, 0x07, 0x80, 0x77, 0x3c, 0xcd, 0x4e, 0x17, 0xeb, + 0x5c, 0x01, 0x73, 0x46, 0xc8, 0xce, 0xb3, 0xba, 0xb1, 0xf5, 0x8e, 0xc6, + 0xf7, 0x87, 0xd3, 0x8e, 0x6e, 0x2d, 0x20, 0xad, 0xda, 0x7a, 0xbd, 0xb2, + 0x22, 0xb0, 0xcc, 0xef, 0x38, 0x11, 0xe9, 0x52, 0x38, 0x09, 0x5d, 0x63, + 0xfc, 0xd9, 0xce, 0xfc, 0xc5, 0x12, 0x83, 0x1a, 0x49, 0xb5, 0xb0, 0x19, + 0x86, 0x05, 0x04, 0xed, 0xb0, 0x8e, 0xe4, 0x80, 0x37, 0xf4, 0x74, 0x38, + 0x85, 0x3e, 0xc5, 0x99, 0x57, 0xed, 0xfb, 0xee, 0x52, 0x35, 0x6d, 0x69, + 0x64, 0xe9, 0xc0, 0xfe, 0x35, 0xa3, 0xcd, 0x18, 0x4e, 0xe4, 0x94, 0xe4, + 0xf3, 0x66, 0xe2, 0x76, 0x89, 0xf0, 0xe9, 0xcf, 0xce, 0x3b, 0xc3, 0xcd, + 0x8b, 0x7a, 0x1d, 0x36, 0x9c, 0x05, 0xb8, 0x87, 0xd2, 0x13, 0xe6, 0x13, + 0xec, 0xdc, 0x73, 0x2b, 0x90, 0x21, 0x03, 0x24, 0x8a, 0xe5, 0xf9, 0x30, + 0x6f, 0xd9, 0xa1, 0x4c, 0xea, 0xd9, 0xf2, 0x97, 0xfa, 0x2b, 0x0c, 0x51, + 0xd0, 0x63, 0x83, 0x09, 0x57, 0xdf, 0x48, 0xa8, 0x91, 0x83, 0x9d, 0xc9, + 0xe4, 0xa8, 0xee, 0x11, 0xed, 0x03, 0xa4, 0xab, 0x45, 0x4b, 0x45, 0x97, + 0xd0, 0x9c, 0x19, 0xe1, 0xef, 0x72, 0xec, 0x56, 0xdf, 0x9c, 0xb4, 0xcc, + 0xb4, 0x42, 0x5a, 0x85, 0xcb, 0x3e, 0xfe, 0x3c, 0xdc, 0xbf, 0x39, 0xf3, + 0xdb, 0xb0, 0x10, 0xf9, 0x31, 0xa7, 0x17, 0xf6, 0x23, 0xe4, 0xa7, 0xaf, + 0xab, 0x0d, 0xc1, 0x85, 0x18, 0xa3, 0x18, 0xb8, 0x5b, 0x24, 0x85, 0xb4, + 0xcc, 0xca, 0x93, 0x10, 0x60, 0x1b, 0x92, 0x97, 0x09, 0x3c, 0x92, 0x4f, + 0x27, 0x20, 0x04, 0x1d, 0x49, 0x9a, 0x2c, 0xf2, 0xf1, 0xd3, 0x89, 0x96, + 0x49, 0xe0, 0x44, 0x5c, 0x21, 0x20, 0xf0, 0xec, 0x49, 0xc8, 0xcf, 0x7b, + 0x78, 0x38, 0xaf, 0x0a, 0x63, 0x7a, 0x97, 0x70, 0x73, 0xcc, 0x8e, 0x10, + 0x3a, 0xea, 0xfb, 0x23, 0xe2, 0x01, 0x03, 0x67, 0x05, 0x60, 0xe2, 0xf3, + 0x94, 0x91, 0x6d, 0x1e, 0x26, 0xd0, 0xff, 0x12, 0x21, 0x81, 0xd6, 0xd0, + 0x84, 0x3c, 0x28, 0x9a, 0xbe, 0xdc, 0xce, 0xc4, 0x5c, 0xe1, 0xcd, 0x9e, + 0xaf, 0xce, 0x1a, 0x60, 0x67, 0xf8, 0xbf, 0xb5, 0x60, 0x6d, 0x64, 0x2a, + 0x02, 0xa1, 0xe1, 0x43, 0x52, 0x08, 0xbf, 0xd3, 0x2e, 0xfc, 0xeb, 0x9a, + 0x0d, 0xb2, 0x31, 0xea, 0xf4, 0xf1, 0x86, 0x5c, 0x4a, 0x0f, 0x10, 0x29, + 0x9f, 0x39, 0x25, 0x7a, 0xf9, 0x47, 0xa5, 0x88, 0x3b, 0x46, 0xe9, 0xe7, + 0x7f, 0xff, 0xb9, 0x09, 0x4d, 0x55, 0x6f, 0x81, 0x9b, 0xea, 0x2b, 0x10, + 0xca, 0x6d, 0x0b, 0x0e, 0xda, 0x69, 0x69, 0x87, 0x51, 0x00, 0x1a, 0xd2, + 0x34, 0xa8, 0x2d, 0x9f, 0xc3, 0x14, 0x51, 0x97, 0x99, 0xa3, 0x55, 0x31, + 0x02, 0x89, 0x6f, 0x72, 0xb5, 0x3a, 0xcc, 0x2d, 0xd3, 0x25, 0xb2, 0xfa, + 0xf2, 0x03, 0xc9, 0x4d, 0x78, 0x8b, 0xed, 0x02, 0x05, 0x5f, 0x21, 0x17, + 0x07, 0x41, 0xed, 0x53, 0x61, 0xa4, 0xe5, 0x7c, 0x84, 0x78, 0xfb, 0xde, + 0xde, 0xe0, 0x09, 0x2f, 0xcb, 0xc2, 0x47, 0xdd, 0x64, 0x41, 0x6c, 0xe5, + 0x35, 0xb0, 0xb1, 0x14, 0x81, 0x85, 0xb5, 0xe4, 0xa1, 0xaf, 0x3f, 0xe5, + 0x5a, 0x85, 0x4e, 0x38, 0x83, 0x03, 0x98, 0x1b, 0xb3, 0x7c, 0xb7, 0xf8, + 0x3d, 0x7d, 0x23, 0xf7, 0xa0, 0x22, 0xe4, 0x69, 0x37, 0xe9, 0xf0, 0x19, + 0xed, 0xdb, 0xc3, 0x7d, 0x65, 0x98, 0x1d, 0xe8, 0x3a, 0x33, 0xfa, 0x4f, + 0x95, 0xa9, 0x91, 0x03, 0xfd, 0x5c, 0x41, 0x7c, 0x27, 0x8b, 0xe3, 0xf8, + 0x48, 0x2b, 0xa0, 0x13, 0x68, 0x97, 0x5f, 0x33, 0x90, 0x80, 0xac, 0x19, + 0x68, 0x4b, 0x45, 0x88, 0x22, 0x55, 0xab, 0x77, 0x6c, 0x1d, 0x61, 0x23, + 0x31, 0xdd, 0xd7, 0x60, 0xda, 0x9e, 0x52, 0xc1, 0x29, 0xe7, 0xbd, 0xcb, + 0x36, 0xed, 0xa0, 0x83, 0x6e, 0xbc, 0x28, 0x11 +}; +unsigned int test_data_len = 5000; + +unsigned char test_data_enc[] = { + 0x33, 0x73, 0x47, 0x61, 0x66, 0x4d, 0x62, 0x62, 0x32, 0x6a, 0x31, 0x33, + 0x78, 0x54, 0x66, 0x33, 0x4c, 0x50, 0x45, 0x56, 0x52, 0x2b, 0x52, 0x6a, + 0x35, 0x57, 0x68, 0x69, 0x6a, 0x6d, 0x77, 0x4a, 0x76, 0x64, 0x64, 0x30, + 0x2f, 0x48, 0x4d, 0x41, 0x36, 0x49, 0x4c, 0x43, 0x66, 0x48, 0x4d, 0x62, + 0x4a, 0x75, 0x56, 0x7a, 0x61, 0x2f, 0x66, 0x4d, 0x46, 0x66, 0x62, 0x43, + 0x49, 0x59, 0x38, 0x2b, 0x4b, 0x4e, 0x6d, 0x79, 0x6c, 0x71, 0x2b, 0x57, + 0x37, 0x2f, 0x37, 0x4e, 0x0a, 0x4f, 0x6c, 0x56, 0x6f, 0x78, 0x71, 0x72, + 0x6e, 0x2b, 0x6a, 0x59, 0x30, 0x4e, 0x4b, 0x6d, 0x6e, 0x32, 0x52, 0x38, + 0x51, 0x68, 0x5a, 0x6a, 0x56, 0x53, 0x6e, 0x75, 0x49, 0x42, 0x4c, 0x70, + 0x73, 0x4e, 0x74, 0x74, 0x70, 0x4d, 0x62, 0x30, 0x47, 0x63, 0x50, 0x73, + 0x47, 0x4f, 0x6b, 0x74, 0x50, 0x77, 0x68, 0x48, 0x4b, 0x58, 0x54, 0x6f, + 0x52, 0x44, 0x54, 0x6c, 0x41, 0x47, 0x4b, 0x64, 0x61, 0x30, 0x6e, 0x2b, + 0x46, 0x53, 0x73, 0x38, 0x2b, 0x6e, 0x77, 0x49, 0x6b, 0x0a, 0x42, 0x35, + 0x74, 0x6e, 0x48, 0x67, 0x6c, 0x55, 0x7a, 0x36, 0x75, 0x31, 0x47, 0x4b, + 0x72, 0x54, 0x78, 0x37, 0x31, 0x49, 0x31, 0x52, 0x66, 0x6d, 0x46, 0x70, + 0x4f, 0x4e, 0x4c, 0x6f, 0x54, 0x41, 0x6c, 0x33, 0x47, 0x30, 0x61, 0x71, + 0x34, 0x75, 0x43, 0x77, 0x77, 0x45, 0x72, 0x61, 0x34, 0x6f, 0x54, 0x6d, + 0x4d, 0x69, 0x6d, 0x31, 0x4c, 0x39, 0x6e, 0x76, 0x4f, 0x73, 0x56, 0x49, + 0x32, 0x71, 0x35, 0x42, 0x56, 0x6f, 0x4a, 0x57, 0x73, 0x2b, 0x42, 0x39, + 0x59, 0x4b, 0x0a, 0x46, 0x59, 0x38, 0x33, 0x6f, 0x4c, 0x47, 0x2f, 0x30, + 0x43, 0x54, 0x2f, 0x57, 0x48, 0x50, 0x57, 0x7a, 0x63, 0x72, 0x43, 0x4d, + 0x6a, 0x53, 0x30, 0x43, 0x59, 0x33, 0x34, 0x2b, 0x4b, 0x47, 0x70, 0x75, + 0x73, 0x7a, 0x65, 0x47, 0x33, 0x6c, 0x69, 0x31, 0x30, 0x66, 0x50, 0x4d, + 0x6b, 0x69, 0x38, 0x77, 0x57, 0x62, 0x31, 0x68, 0x2f, 0x6a, 0x4e, 0x6f, + 0x46, 0x72, 0x75, 0x54, 0x34, 0x76, 0x78, 0x61, 0x50, 0x6a, 0x30, 0x59, + 0x78, 0x6c, 0x4d, 0x34, 0x44, 0x77, 0x37, 0x0a, 0x47, 0x6d, 0x6d, 0x50, + 0x39, 0x68, 0x66, 0x69, 0x4f, 0x47, 0x78, 0x54, 0x6d, 0x35, 0x42, 0x7a, + 0x48, 0x39, 0x5a, 0x64, 0x66, 0x66, 0x71, 0x33, 0x67, 0x49, 0x50, 0x6f, + 0x65, 0x72, 0x32, 0x45, 0x43, 0x76, 0x2f, 0x66, 0x41, 0x75, 0x34, 0x70, + 0x64, 0x57, 0x34, 0x6c, 0x6e, 0x54, 0x65, 0x51, 0x59, 0x6c, 0x4e, 0x61, + 0x69, 0x4c, 0x6d, 0x4f, 0x57, 0x76, 0x70, 0x66, 0x62, 0x42, 0x2f, 0x74, + 0x6d, 0x6b, 0x74, 0x70, 0x44, 0x74, 0x4a, 0x68, 0x30, 0x78, 0x64, 0x58, + 0x0a, 0x44, 0x46, 0x49, 0x79, 0x51, 0x34, 0x4e, 0x71, 0x4f, 0x30, 0x46, + 0x44, 0x70, 0x4c, 0x36, 0x35, 0x76, 0x64, 0x58, 0x6e, 0x35, 0x62, 0x49, + 0x57, 0x57, 0x62, 0x71, 0x77, 0x39, 0x62, 0x7a, 0x69, 0x57, 0x33, 0x6d, + 0x57, 0x30, 0x71, 0x43, 0x6a, 0x43, 0x48, 0x61, 0x6f, 0x75, 0x2f, 0x2f, + 0x4c, 0x38, 0x68, 0x56, 0x6d, 0x62, 0x45, 0x6d, 0x62, 0x79, 0x38, 0x57, + 0x4e, 0x73, 0x73, 0x62, 0x71, 0x71, 0x68, 0x63, 0x4a, 0x47, 0x78, 0x79, + 0x48, 0x75, 0x57, 0x66, 0x48, 0x0a, 0x68, 0x63, 0x45, 0x34, 0x35, 0x69, + 0x7a, 0x54, 0x43, 0x5a, 0x66, 0x34, 0x34, 0x4e, 0x4b, 0x78, 0x59, 0x6e, + 0x4c, 0x38, 0x65, 0x58, 0x63, 0x31, 0x75, 0x32, 0x35, 0x55, 0x33, 0x4e, + 0x2b, 0x62, 0x7a, 0x30, 0x62, 0x62, 0x73, 0x72, 0x76, 0x35, 0x75, 0x58, + 0x79, 0x6f, 0x36, 0x77, 0x45, 0x75, 0x4e, 0x37, 0x54, 0x39, 0x50, 0x71, + 0x47, 0x43, 0x61, 0x7a, 0x45, 0x59, 0x63, 0x6a, 0x70, 0x56, 0x66, 0x73, + 0x6d, 0x35, 0x79, 0x42, 0x76, 0x63, 0x32, 0x61, 0x41, 0x57, 0x0a, 0x54, + 0x50, 0x31, 0x74, 0x2f, 0x76, 0x42, 0x71, 0x5a, 0x6f, 0x69, 0x35, 0x49, + 0x47, 0x36, 0x31, 0x54, 0x37, 0x7a, 0x62, 0x6c, 0x4c, 0x73, 0x41, 0x53, + 0x71, 0x4d, 0x2f, 0x65, 0x63, 0x44, 0x30, 0x47, 0x4a, 0x4f, 0x68, 0x4c, + 0x65, 0x79, 0x75, 0x58, 0x6b, 0x4c, 0x4b, 0x46, 0x51, 0x46, 0x41, 0x31, + 0x31, 0x6d, 0x51, 0x44, 0x70, 0x49, 0x7a, 0x6d, 0x49, 0x2f, 0x67, 0x61, + 0x4f, 0x54, 0x71, 0x6a, 0x6a, 0x64, 0x77, 0x50, 0x30, 0x71, 0x44, 0x4a, + 0x77, 0x6a, 0x77, 0x0a, 0x78, 0x7a, 0x6b, 0x50, 0x48, 0x43, 0x47, 0x33, + 0x61, 0x79, 0x2b, 0x65, 0x63, 0x79, 0x45, 0x6a, 0x46, 0x68, 0x58, 0x64, + 0x78, 0x4c, 0x37, 0x76, 0x4e, 0x65, 0x72, 0x59, 0x58, 0x71, 0x32, 0x44, + 0x71, 0x52, 0x50, 0x72, 0x51, 0x4a, 0x52, 0x33, 0x6e, 0x39, 0x76, 0x63, + 0x6c, 0x31, 0x51, 0x42, 0x46, 0x56, 0x67, 0x4a, 0x6a, 0x53, 0x45, 0x63, + 0x34, 0x44, 0x72, 0x45, 0x76, 0x58, 0x55, 0x62, 0x37, 0x34, 0x71, 0x31, + 0x65, 0x4b, 0x6f, 0x6a, 0x65, 0x57, 0x6e, 0x4d, 0x0a, 0x46, 0x55, 0x50, + 0x36, 0x5a, 0x66, 0x56, 0x71, 0x79, 0x69, 0x4e, 0x43, 0x66, 0x6f, 0x34, + 0x5a, 0x2b, 0x77, 0x56, 0x44, 0x72, 0x6b, 0x79, 0x4b, 0x35, 0x74, 0x73, + 0x46, 0x77, 0x62, 0x37, 0x56, 0x4d, 0x57, 0x47, 0x72, 0x31, 0x49, 0x36, + 0x4a, 0x49, 0x65, 0x49, 0x62, 0x71, 0x4d, 0x32, 0x67, 0x39, 0x5a, 0x37, + 0x52, 0x41, 0x44, 0x77, 0x46, 0x74, 0x6b, 0x4b, 0x36, 0x55, 0x34, 0x74, + 0x53, 0x61, 0x33, 0x57, 0x5a, 0x64, 0x6a, 0x45, 0x4a, 0x66, 0x35, 0x32, + 0x6c, 0x0a, 0x6f, 0x2b, 0x51, 0x76, 0x52, 0x59, 0x31, 0x2b, 0x4d, 0x74, + 0x41, 0x7a, 0x30, 0x36, 0x54, 0x53, 0x41, 0x57, 0x64, 0x31, 0x43, 0x50, + 0x64, 0x70, 0x6a, 0x70, 0x33, 0x73, 0x59, 0x33, 0x47, 0x6f, 0x50, 0x4d, + 0x77, 0x73, 0x46, 0x53, 0x51, 0x2b, 0x5a, 0x73, 0x30, 0x6b, 0x37, 0x6e, + 0x69, 0x38, 0x59, 0x45, 0x7a, 0x55, 0x53, 0x38, 0x46, 0x51, 0x52, 0x4c, + 0x36, 0x30, 0x59, 0x4c, 0x6b, 0x69, 0x47, 0x78, 0x49, 0x7a, 0x4e, 0x42, + 0x75, 0x70, 0x42, 0x4a, 0x38, 0x42, 0x0a, 0x61, 0x39, 0x30, 0x66, 0x54, + 0x47, 0x53, 0x59, 0x42, 0x62, 0x68, 0x2f, 0x73, 0x30, 0x48, 0x52, 0x37, + 0x74, 0x6a, 0x76, 0x74, 0x6d, 0x45, 0x33, 0x49, 0x6a, 0x6d, 0x6c, 0x46, + 0x67, 0x36, 0x64, 0x6b, 0x33, 0x52, 0x76, 0x4d, 0x76, 0x43, 0x78, 0x45, + 0x77, 0x42, 0x34, 0x4a, 0x5a, 0x61, 0x51, 0x7a, 0x34, 0x2f, 0x68, 0x47, + 0x71, 0x43, 0x42, 0x78, 0x5a, 0x59, 0x61, 0x6e, 0x49, 0x6d, 0x55, 0x78, + 0x38, 0x4e, 0x4d, 0x37, 0x4f, 0x57, 0x6c, 0x73, 0x6b, 0x31, 0x73, 0x0a, + 0x44, 0x34, 0x30, 0x4a, 0x4e, 0x49, 0x35, 0x55, 0x77, 0x37, 0x74, 0x52, + 0x74, 0x7a, 0x36, 0x43, 0x32, 0x6c, 0x38, 0x68, 0x6a, 0x2f, 0x4e, 0x6f, + 0x67, 0x6a, 0x50, 0x4c, 0x5a, 0x48, 0x47, 0x63, 0x33, 0x36, 0x76, 0x36, + 0x74, 0x46, 0x66, 0x5a, 0x42, 0x33, 0x69, 0x69, 0x36, 0x4b, 0x61, 0x36, + 0x6a, 0x45, 0x67, 0x76, 0x73, 0x35, 0x59, 0x63, 0x48, 0x61, 0x51, 0x63, + 0x34, 0x42, 0x56, 0x75, 0x78, 0x49, 0x44, 0x58, 0x54, 0x58, 0x6a, 0x4f, + 0x6d, 0x6e, 0x63, 0x71, 0x0a, 0x6b, 0x4f, 0x54, 0x65, 0x5a, 0x6f, 0x68, + 0x55, 0x32, 0x68, 0x51, 0x2f, 0x41, 0x6a, 0x42, 0x6e, 0x49, 0x35, 0x52, + 0x32, 0x77, 0x79, 0x6a, 0x6b, 0x47, 0x37, 0x38, 0x33, 0x45, 0x77, 0x2f, + 0x4a, 0x71, 0x64, 0x31, 0x31, 0x59, 0x30, 0x45, 0x48, 0x66, 0x4b, 0x33, + 0x61, 0x73, 0x6d, 0x4b, 0x63, 0x72, 0x78, 0x31, 0x4c, 0x52, 0x6e, 0x45, + 0x57, 0x79, 0x4c, 0x51, 0x45, 0x59, 0x71, 0x4d, 0x63, 0x42, 0x74, 0x31, + 0x59, 0x4f, 0x72, 0x69, 0x44, 0x53, 0x78, 0x79, 0x6f, 0x0a, 0x65, 0x36, + 0x69, 0x63, 0x4e, 0x68, 0x6f, 0x42, 0x49, 0x35, 0x6b, 0x51, 0x39, 0x68, + 0x30, 0x65, 0x4c, 0x6f, 0x44, 0x6b, 0x52, 0x6f, 0x6f, 0x77, 0x51, 0x73, + 0x4a, 0x49, 0x47, 0x48, 0x41, 0x71, 0x59, 0x46, 0x4c, 0x41, 0x56, 0x63, + 0x44, 0x76, 0x4b, 0x69, 0x31, 0x45, 0x58, 0x75, 0x70, 0x33, 0x64, 0x49, + 0x48, 0x65, 0x37, 0x58, 0x52, 0x49, 0x72, 0x43, 0x66, 0x35, 0x58, 0x66, + 0x2b, 0x79, 0x71, 0x39, 0x6c, 0x72, 0x41, 0x31, 0x71, 0x66, 0x61, 0x6e, + 0x31, 0x37, 0x0a, 0x42, 0x61, 0x31, 0x32, 0x55, 0x5a, 0x7a, 0x42, 0x52, + 0x6f, 0x61, 0x62, 0x65, 0x33, 0x32, 0x51, 0x56, 0x78, 0x51, 0x31, 0x2b, + 0x4b, 0x53, 0x32, 0x74, 0x38, 0x30, 0x5a, 0x43, 0x6f, 0x59, 0x33, 0x61, + 0x73, 0x50, 0x70, 0x36, 0x33, 0x68, 0x33, 0x54, 0x51, 0x59, 0x4b, 0x72, + 0x51, 0x72, 0x73, 0x32, 0x32, 0x37, 0x6c, 0x33, 0x46, 0x69, 0x36, 0x5a, + 0x62, 0x38, 0x42, 0x64, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x67, 0x6b, 0x6c, + 0x5a, 0x45, 0x55, 0x52, 0x31, 0x4a, 0x33, 0x0a, 0x73, 0x51, 0x49, 0x5a, + 0x65, 0x58, 0x69, 0x76, 0x63, 0x7a, 0x65, 0x4d, 0x37, 0x51, 0x64, 0x75, + 0x5a, 0x50, 0x37, 0x65, 0x4b, 0x53, 0x30, 0x70, 0x6c, 0x55, 0x37, 0x49, + 0x45, 0x6d, 0x57, 0x4d, 0x6b, 0x33, 0x2b, 0x6e, 0x33, 0x6f, 0x67, 0x44, + 0x75, 0x52, 0x52, 0x65, 0x77, 0x6f, 0x79, 0x58, 0x69, 0x4f, 0x51, 0x77, + 0x4f, 0x73, 0x67, 0x41, 0x55, 0x69, 0x5a, 0x68, 0x6d, 0x49, 0x72, 0x63, + 0x57, 0x52, 0x76, 0x4a, 0x6d, 0x48, 0x58, 0x78, 0x76, 0x38, 0x42, 0x35, + 0x0a, 0x34, 0x47, 0x55, 0x70, 0x30, 0x73, 0x5a, 0x52, 0x4d, 0x32, 0x65, + 0x76, 0x44, 0x38, 0x73, 0x61, 0x69, 0x63, 0x37, 0x35, 0x4a, 0x79, 0x30, + 0x6a, 0x77, 0x31, 0x59, 0x48, 0x74, 0x72, 0x6c, 0x30, 0x43, 0x70, 0x44, + 0x4d, 0x52, 0x31, 0x50, 0x50, 0x64, 0x36, 0x65, 0x64, 0x41, 0x38, 0x5a, + 0x7a, 0x7a, 0x6a, 0x37, 0x46, 0x57, 0x2f, 0x7a, 0x49, 0x61, 0x68, 0x67, + 0x4a, 0x72, 0x43, 0x64, 0x6d, 0x47, 0x48, 0x71, 0x36, 0x6e, 0x6a, 0x33, + 0x52, 0x43, 0x74, 0x33, 0x43, 0x0a, 0x48, 0x6b, 0x41, 0x67, 0x38, 0x51, + 0x56, 0x6d, 0x75, 0x30, 0x79, 0x67, 0x4b, 0x39, 0x43, 0x4c, 0x55, 0x38, + 0x73, 0x31, 0x52, 0x61, 0x4d, 0x4f, 0x64, 0x59, 0x76, 0x71, 0x4a, 0x38, + 0x79, 0x79, 0x6f, 0x39, 0x64, 0x39, 0x72, 0x32, 0x44, 0x4c, 0x59, 0x71, + 0x73, 0x73, 0x4a, 0x4a, 0x4d, 0x70, 0x70, 0x33, 0x48, 0x74, 0x5a, 0x69, + 0x61, 0x59, 0x72, 0x38, 0x6c, 0x72, 0x66, 0x56, 0x66, 0x45, 0x54, 0x37, + 0x64, 0x49, 0x67, 0x51, 0x77, 0x61, 0x77, 0x33, 0x37, 0x65, 0x0a, 0x4d, + 0x2f, 0x38, 0x53, 0x37, 0x4f, 0x6c, 0x73, 0x4c, 0x38, 0x31, 0x6e, 0x46, + 0x6f, 0x42, 0x6e, 0x49, 0x57, 0x73, 0x4a, 0x6a, 0x52, 0x75, 0x6b, 0x30, + 0x4f, 0x78, 0x6a, 0x42, 0x38, 0x49, 0x34, 0x55, 0x4d, 0x31, 0x36, 0x77, + 0x2b, 0x56, 0x44, 0x48, 0x64, 0x41, 0x69, 0x68, 0x6b, 0x2b, 0x6a, 0x68, + 0x41, 0x65, 0x79, 0x77, 0x33, 0x32, 0x4f, 0x74, 0x4c, 0x45, 0x64, 0x34, + 0x48, 0x4d, 0x62, 0x2b, 0x57, 0x2f, 0x4a, 0x59, 0x4b, 0x5a, 0x34, 0x4e, + 0x47, 0x42, 0x6d, 0x0a, 0x30, 0x55, 0x63, 0x6d, 0x65, 0x42, 0x45, 0x6b, + 0x4f, 0x53, 0x63, 0x7a, 0x72, 0x6a, 0x69, 0x57, 0x6c, 0x33, 0x77, 0x55, + 0x66, 0x63, 0x56, 0x30, 0x31, 0x4b, 0x2b, 0x7a, 0x66, 0x53, 0x68, 0x68, + 0x35, 0x53, 0x48, 0x41, 0x75, 0x74, 0x7a, 0x50, 0x56, 0x62, 0x6f, 0x71, + 0x62, 0x38, 0x77, 0x70, 0x6c, 0x6c, 0x37, 0x4b, 0x4e, 0x58, 0x79, 0x38, + 0x6b, 0x2f, 0x43, 0x6f, 0x2b, 0x41, 0x6e, 0x42, 0x70, 0x66, 0x47, 0x79, + 0x42, 0x57, 0x53, 0x68, 0x2b, 0x45, 0x4e, 0x69, 0x0a, 0x36, 0x73, 0x34, + 0x71, 0x77, 0x70, 0x58, 0x4d, 0x45, 0x51, 0x76, 0x32, 0x2f, 0x32, 0x5a, + 0x51, 0x38, 0x50, 0x37, 0x52, 0x6c, 0x61, 0x58, 0x52, 0x69, 0x70, 0x55, + 0x41, 0x61, 0x30, 0x6f, 0x63, 0x46, 0x4e, 0x31, 0x39, 0x39, 0x70, 0x63, + 0x48, 0x76, 0x6a, 0x74, 0x39, 0x57, 0x45, 0x34, 0x4a, 0x37, 0x5a, 0x73, + 0x54, 0x62, 0x73, 0x72, 0x4b, 0x2b, 0x57, 0x59, 0x50, 0x77, 0x79, 0x72, + 0x74, 0x30, 0x65, 0x63, 0x2b, 0x55, 0x67, 0x7a, 0x65, 0x44, 0x65, 0x4d, + 0x43, 0x0a, 0x54, 0x53, 0x6d, 0x73, 0x72, 0x70, 0x2b, 0x34, 0x73, 0x55, + 0x59, 0x38, 0x70, 0x4b, 0x30, 0x6e, 0x64, 0x7a, 0x6c, 0x43, 0x78, 0x77, + 0x6b, 0x4b, 0x45, 0x70, 0x48, 0x39, 0x50, 0x74, 0x51, 0x41, 0x45, 0x35, + 0x76, 0x57, 0x35, 0x38, 0x69, 0x49, 0x4e, 0x58, 0x74, 0x6c, 0x4a, 0x70, + 0x52, 0x30, 0x57, 0x52, 0x71, 0x66, 0x77, 0x54, 0x71, 0x6b, 0x53, 0x69, + 0x76, 0x77, 0x71, 0x6e, 0x37, 0x4a, 0x66, 0x49, 0x2b, 0x2f, 0x46, 0x54, + 0x4b, 0x39, 0x6a, 0x62, 0x4f, 0x6b, 0x0a, 0x6a, 0x68, 0x38, 0x56, 0x48, + 0x55, 0x76, 0x61, 0x39, 0x43, 0x43, 0x6c, 0x7a, 0x41, 0x6e, 0x44, 0x47, + 0x42, 0x68, 0x2b, 0x79, 0x37, 0x4d, 0x34, 0x56, 0x67, 0x64, 0x6e, 0x64, + 0x56, 0x31, 0x54, 0x33, 0x6f, 0x2f, 0x4a, 0x52, 0x61, 0x79, 0x65, 0x73, + 0x71, 0x6c, 0x48, 0x73, 0x47, 0x47, 0x48, 0x6f, 0x44, 0x6d, 0x50, 0x68, + 0x74, 0x36, 0x6a, 0x77, 0x38, 0x68, 0x32, 0x6e, 0x4d, 0x4a, 0x31, 0x41, + 0x6f, 0x46, 0x38, 0x7a, 0x79, 0x43, 0x59, 0x78, 0x77, 0x58, 0x39, 0x0a, + 0x70, 0x69, 0x38, 0x6f, 0x32, 0x35, 0x61, 0x6b, 0x72, 0x51, 0x58, 0x58, + 0x73, 0x6c, 0x58, 0x76, 0x4f, 0x36, 0x4d, 0x77, 0x65, 0x6a, 0x49, 0x30, + 0x54, 0x6d, 0x7a, 0x54, 0x59, 0x35, 0x79, 0x46, 0x69, 0x4b, 0x4f, 0x61, + 0x46, 0x4e, 0x74, 0x74, 0x70, 0x61, 0x71, 0x69, 0x52, 0x54, 0x37, 0x4b, + 0x6c, 0x5a, 0x5a, 0x64, 0x4a, 0x74, 0x43, 0x4c, 0x48, 0x76, 0x4d, 0x61, + 0x50, 0x2b, 0x48, 0x4b, 0x4a, 0x41, 0x6e, 0x42, 0x6d, 0x68, 0x71, 0x37, + 0x75, 0x6f, 0x52, 0x77, 0x0a, 0x47, 0x35, 0x73, 0x77, 0x33, 0x44, 0x4d, + 0x57, 0x74, 0x52, 0x63, 0x33, 0x6b, 0x48, 0x67, 0x57, 0x4c, 0x41, 0x6b, + 0x6b, 0x54, 0x74, 0x79, 0x44, 0x56, 0x52, 0x50, 0x6f, 0x47, 0x55, 0x6e, + 0x36, 0x75, 0x42, 0x6d, 0x4f, 0x67, 0x42, 0x6a, 0x6e, 0x69, 0x61, 0x66, + 0x68, 0x69, 0x44, 0x45, 0x55, 0x31, 0x63, 0x62, 0x66, 0x35, 0x31, 0x36, + 0x56, 0x6e, 0x6b, 0x67, 0x6b, 0x33, 0x51, 0x6b, 0x6f, 0x30, 0x62, 0x76, + 0x67, 0x59, 0x62, 0x73, 0x71, 0x64, 0x72, 0x2f, 0x6c, 0x0a, 0x4b, 0x43, + 0x45, 0x4f, 0x62, 0x32, 0x79, 0x57, 0x75, 0x2f, 0x41, 0x6c, 0x5a, 0x76, + 0x36, 0x79, 0x49, 0x67, 0x64, 0x33, 0x39, 0x52, 0x45, 0x2b, 0x70, 0x78, + 0x30, 0x53, 0x56, 0x51, 0x4e, 0x49, 0x79, 0x61, 0x36, 0x30, 0x68, 0x6b, + 0x54, 0x78, 0x4e, 0x2b, 0x61, 0x53, 0x79, 0x45, 0x33, 0x47, 0x74, 0x4b, + 0x6b, 0x53, 0x78, 0x75, 0x67, 0x51, 0x53, 0x4a, 0x48, 0x71, 0x34, 0x7a, + 0x68, 0x41, 0x68, 0x69, 0x64, 0x44, 0x48, 0x64, 0x38, 0x30, 0x75, 0x33, + 0x70, 0x6b, 0x0a, 0x38, 0x48, 0x34, 0x41, 0x65, 0x53, 0x51, 0x37, 0x61, + 0x78, 0x59, 0x72, 0x48, 0x5a, 0x53, 0x31, 0x78, 0x65, 0x63, 0x57, 0x59, + 0x71, 0x77, 0x51, 0x75, 0x75, 0x43, 0x44, 0x66, 0x74, 0x64, 0x41, 0x30, + 0x6d, 0x38, 0x38, 0x53, 0x53, 0x4a, 0x50, 0x4e, 0x49, 0x4a, 0x56, 0x31, + 0x72, 0x46, 0x57, 0x53, 0x6f, 0x32, 0x50, 0x4e, 0x49, 0x4a, 0x6d, 0x6b, + 0x6c, 0x6a, 0x78, 0x41, 0x57, 0x63, 0x4e, 0x72, 0x4e, 0x74, 0x62, 0x79, + 0x37, 0x7a, 0x6e, 0x31, 0x32, 0x68, 0x43, 0x0a, 0x74, 0x30, 0x63, 0x38, + 0x59, 0x34, 0x77, 0x7a, 0x6c, 0x44, 0x62, 0x36, 0x57, 0x67, 0x77, 0x64, + 0x65, 0x6b, 0x59, 0x6d, 0x62, 0x4c, 0x51, 0x53, 0x41, 0x59, 0x6d, 0x72, + 0x4e, 0x6e, 0x67, 0x46, 0x64, 0x64, 0x70, 0x6a, 0x39, 0x4f, 0x59, 0x67, + 0x4e, 0x32, 0x35, 0x52, 0x36, 0x6e, 0x71, 0x6c, 0x33, 0x64, 0x37, 0x49, + 0x64, 0x47, 0x59, 0x6e, 0x42, 0x56, 0x61, 0x62, 0x76, 0x77, 0x55, 0x78, + 0x64, 0x77, 0x2b, 0x54, 0x74, 0x78, 0x57, 0x34, 0x49, 0x42, 0x4f, 0x44, + 0x0a, 0x43, 0x2b, 0x4c, 0x6d, 0x4e, 0x6a, 0x36, 0x4a, 0x38, 0x44, 0x76, + 0x6a, 0x57, 0x37, 0x2b, 0x4f, 0x75, 0x44, 0x4e, 0x65, 0x51, 0x38, 0x6e, + 0x42, 0x33, 0x5a, 0x72, 0x4e, 0x6d, 0x31, 0x70, 0x59, 0x4c, 0x6d, 0x35, + 0x51, 0x31, 0x42, 0x4e, 0x6b, 0x42, 0x30, 0x5a, 0x2b, 0x67, 0x34, 0x41, + 0x7a, 0x51, 0x39, 0x4f, 0x6e, 0x48, 0x67, 0x63, 0x73, 0x72, 0x77, 0x50, + 0x56, 0x48, 0x33, 0x32, 0x56, 0x39, 0x48, 0x41, 0x49, 0x71, 0x36, 0x6b, + 0x32, 0x2f, 0x2f, 0x4c, 0x46, 0x0a, 0x76, 0x49, 0x4a, 0x65, 0x64, 0x59, + 0x72, 0x51, 0x4d, 0x76, 0x76, 0x30, 0x4e, 0x45, 0x52, 0x43, 0x51, 0x6e, + 0x62, 0x4f, 0x4a, 0x30, 0x4b, 0x54, 0x4b, 0x56, 0x51, 0x68, 0x46, 0x43, + 0x6f, 0x76, 0x6b, 0x39, 0x67, 0x71, 0x36, 0x50, 0x68, 0x45, 0x37, 0x45, + 0x79, 0x4c, 0x32, 0x2b, 0x6e, 0x63, 0x4f, 0x44, 0x58, 0x4b, 0x75, 0x44, + 0x53, 0x66, 0x37, 0x44, 0x49, 0x6b, 0x32, 0x6b, 0x56, 0x76, 0x64, 0x45, + 0x31, 0x43, 0x6f, 0x35, 0x77, 0x59, 0x37, 0x70, 0x45, 0x6c, 0x0a, 0x45, + 0x61, 0x36, 0x38, 0x6c, 0x45, 0x67, 0x4f, 0x6d, 0x6b, 0x39, 0x62, 0x59, + 0x45, 0x46, 0x32, 0x47, 0x67, 0x61, 0x75, 0x47, 0x67, 0x39, 0x58, 0x49, + 0x2b, 0x6a, 0x4e, 0x41, 0x4d, 0x62, 0x43, 0x67, 0x36, 0x49, 0x32, 0x6b, + 0x45, 0x33, 0x78, 0x34, 0x33, 0x37, 0x61, 0x39, 0x76, 0x38, 0x32, 0x4e, + 0x78, 0x42, 0x34, 0x34, 0x6c, 0x39, 0x5a, 0x66, 0x41, 0x66, 0x70, 0x35, + 0x6a, 0x78, 0x36, 0x50, 0x4c, 0x2b, 0x4a, 0x67, 0x4d, 0x34, 0x48, 0x79, + 0x72, 0x7a, 0x75, 0x0a, 0x56, 0x41, 0x6b, 0x53, 0x6f, 0x51, 0x38, 0x30, + 0x34, 0x39, 0x36, 0x4f, 0x6c, 0x74, 0x2f, 0x6c, 0x4e, 0x6d, 0x69, 0x30, + 0x4f, 0x6d, 0x31, 0x52, 0x6c, 0x70, 0x73, 0x51, 0x32, 0x33, 0x34, 0x78, + 0x49, 0x74, 0x4a, 0x67, 0x50, 0x69, 0x39, 0x6a, 0x75, 0x45, 0x42, 0x57, + 0x54, 0x44, 0x32, 0x75, 0x75, 0x6a, 0x73, 0x47, 0x5a, 0x6a, 0x48, 0x49, + 0x70, 0x79, 0x76, 0x71, 0x6f, 0x63, 0x53, 0x4d, 0x67, 0x46, 0x2f, 0x4d, + 0x68, 0x63, 0x54, 0x55, 0x78, 0x58, 0x65, 0x7a, 0x0a, 0x4d, 0x42, 0x2f, + 0x2b, 0x35, 0x68, 0x6c, 0x4b, 0x6c, 0x55, 0x46, 0x58, 0x58, 0x4c, 0x52, + 0x7a, 0x58, 0x58, 0x68, 0x48, 0x41, 0x69, 0x69, 0x52, 0x5a, 0x7a, 0x72, + 0x51, 0x68, 0x69, 0x4f, 0x70, 0x64, 0x42, 0x41, 0x56, 0x65, 0x58, 0x45, + 0x32, 0x62, 0x66, 0x53, 0x7a, 0x69, 0x62, 0x4e, 0x33, 0x70, 0x66, 0x42, + 0x66, 0x4e, 0x34, 0x6e, 0x44, 0x37, 0x4d, 0x2b, 0x41, 0x4b, 0x77, 0x75, + 0x5a, 0x30, 0x2b, 0x55, 0x5a, 0x49, 0x35, 0x53, 0x46, 0x48, 0x77, 0x63, + 0x39, 0x0a, 0x47, 0x54, 0x70, 0x67, 0x71, 0x6e, 0x48, 0x37, 0x38, 0x52, + 0x63, 0x39, 0x32, 0x51, 0x64, 0x43, 0x6b, 0x76, 0x58, 0x46, 0x73, 0x6c, + 0x4e, 0x51, 0x66, 0x41, 0x42, 0x46, 0x74, 0x51, 0x57, 0x68, 0x2b, 0x41, + 0x4b, 0x52, 0x62, 0x70, 0x34, 0x76, 0x57, 0x30, 0x4a, 0x49, 0x41, 0x52, + 0x4a, 0x54, 0x65, 0x62, 0x34, 0x76, 0x47, 0x41, 0x36, 0x67, 0x6a, 0x53, + 0x49, 0x62, 0x2f, 0x56, 0x45, 0x7a, 0x56, 0x68, 0x59, 0x76, 0x4c, 0x6a, + 0x68, 0x31, 0x58, 0x38, 0x31, 0x59, 0x0a, 0x6f, 0x51, 0x77, 0x6e, 0x4e, + 0x51, 0x77, 0x6e, 0x62, 0x66, 0x70, 0x58, 0x6d, 0x52, 0x54, 0x75, 0x34, + 0x63, 0x74, 0x53, 0x31, 0x2b, 0x34, 0x50, 0x4a, 0x50, 0x41, 0x79, 0x38, + 0x32, 0x2b, 0x43, 0x59, 0x35, 0x6d, 0x6a, 0x31, 0x39, 0x65, 0x43, 0x2f, + 0x38, 0x4c, 0x5a, 0x5a, 0x6d, 0x6b, 0x6e, 0x63, 0x79, 0x51, 0x33, 0x72, + 0x50, 0x38, 0x68, 0x6c, 0x30, 0x72, 0x35, 0x75, 0x6e, 0x55, 0x74, 0x69, + 0x55, 0x6b, 0x31, 0x53, 0x67, 0x63, 0x5a, 0x31, 0x34, 0x50, 0x42, 0x0a, + 0x69, 0x57, 0x64, 0x71, 0x56, 0x33, 0x72, 0x34, 0x4b, 0x47, 0x4c, 0x54, + 0x70, 0x69, 0x61, 0x4e, 0x68, 0x65, 0x61, 0x77, 0x6b, 0x52, 0x44, 0x30, + 0x76, 0x57, 0x56, 0x61, 0x6e, 0x6d, 0x49, 0x77, 0x42, 0x31, 0x31, 0x7a, + 0x76, 0x53, 0x6d, 0x76, 0x61, 0x4c, 0x2b, 0x4e, 0x62, 0x36, 0x75, 0x72, + 0x2b, 0x54, 0x36, 0x4f, 0x61, 0x75, 0x54, 0x37, 0x44, 0x37, 0x6e, 0x4a, + 0x36, 0x65, 0x69, 0x2b, 0x73, 0x57, 0x36, 0x42, 0x78, 0x37, 0x65, 0x76, + 0x78, 0x2f, 0x66, 0x45, 0x0a, 0x42, 0x79, 0x77, 0x56, 0x72, 0x37, 0x51, + 0x51, 0x39, 0x58, 0x67, 0x50, 0x55, 0x68, 0x30, 0x73, 0x31, 0x4c, 0x63, + 0x49, 0x79, 0x62, 0x71, 0x61, 0x2b, 0x6b, 0x61, 0x47, 0x46, 0x6e, 0x71, + 0x4e, 0x49, 0x62, 0x61, 0x78, 0x74, 0x64, 0x53, 0x4b, 0x7a, 0x42, 0x59, + 0x71, 0x46, 0x2b, 0x76, 0x4e, 0x73, 0x37, 0x43, 0x77, 0x34, 0x58, 0x55, + 0x4a, 0x46, 0x57, 0x58, 0x59, 0x62, 0x48, 0x50, 0x38, 0x37, 0x53, 0x38, + 0x6b, 0x75, 0x2f, 0x75, 0x38, 0x71, 0x76, 0x54, 0x31, 0x0a, 0x4c, 0x76, + 0x6b, 0x4c, 0x76, 0x72, 0x68, 0x4a, 0x66, 0x66, 0x53, 0x46, 0x72, 0x69, + 0x71, 0x34, 0x42, 0x6a, 0x4e, 0x7a, 0x58, 0x7a, 0x42, 0x69, 0x32, 0x38, + 0x43, 0x7a, 0x49, 0x65, 0x74, 0x4c, 0x4d, 0x77, 0x68, 0x53, 0x6b, 0x64, + 0x79, 0x64, 0x38, 0x58, 0x41, 0x43, 0x52, 0x34, 0x51, 0x61, 0x70, 0x64, + 0x32, 0x63, 0x61, 0x59, 0x2f, 0x78, 0x6c, 0x35, 0x4c, 0x59, 0x76, 0x69, + 0x4c, 0x79, 0x6b, 0x51, 0x37, 0x4b, 0x52, 0x73, 0x45, 0x68, 0x6e, 0x35, + 0x4f, 0x35, 0x0a, 0x69, 0x62, 0x65, 0x37, 0x69, 0x42, 0x43, 0x6a, 0x65, + 0x4b, 0x64, 0x42, 0x36, 0x68, 0x4e, 0x2f, 0x61, 0x6d, 0x4c, 0x45, 0x55, + 0x6b, 0x2f, 0x79, 0x6a, 0x42, 0x62, 0x77, 0x4d, 0x67, 0x68, 0x73, 0x57, + 0x4e, 0x69, 0x35, 0x6e, 0x51, 0x4a, 0x6f, 0x57, 0x53, 0x59, 0x76, 0x73, + 0x58, 0x42, 0x73, 0x77, 0x59, 0x79, 0x38, 0x6f, 0x33, 0x34, 0x50, 0x66, + 0x4c, 0x4a, 0x50, 0x78, 0x54, 0x37, 0x76, 0x37, 0x4b, 0x48, 0x47, 0x69, + 0x6a, 0x55, 0x5a, 0x7a, 0x43, 0x54, 0x63, 0x0a, 0x76, 0x69, 0x51, 0x77, + 0x6a, 0x50, 0x49, 0x61, 0x69, 0x49, 0x33, 0x6d, 0x65, 0x74, 0x44, 0x46, + 0x46, 0x7a, 0x77, 0x64, 0x35, 0x72, 0x54, 0x66, 0x59, 0x75, 0x7a, 0x38, + 0x46, 0x4c, 0x4d, 0x76, 0x41, 0x39, 0x62, 0x49, 0x63, 0x30, 0x4d, 0x53, + 0x46, 0x55, 0x52, 0x53, 0x36, 0x38, 0x6b, 0x71, 0x65, 0x32, 0x77, 0x2b, + 0x67, 0x6c, 0x4b, 0x76, 0x4c, 0x2f, 0x69, 0x6f, 0x31, 0x63, 0x7a, 0x48, + 0x6a, 0x2f, 0x32, 0x39, 0x74, 0x37, 0x37, 0x53, 0x6c, 0x47, 0x6f, 0x42, + 0x0a, 0x66, 0x4b, 0x37, 0x78, 0x4b, 0x71, 0x73, 0x4d, 0x77, 0x6e, 0x70, + 0x69, 0x65, 0x6c, 0x64, 0x7a, 0x4c, 0x6d, 0x77, 0x63, 0x4a, 0x52, 0x66, + 0x59, 0x52, 0x35, 0x4b, 0x62, 0x37, 0x4d, 0x31, 0x7a, 0x57, 0x41, 0x79, + 0x62, 0x54, 0x58, 0x6d, 0x58, 0x45, 0x4b, 0x64, 0x48, 0x34, 0x7a, 0x4f, + 0x36, 0x2b, 0x4a, 0x33, 0x73, 0x53, 0x73, 0x37, 0x33, 0x71, 0x33, 0x69, + 0x61, 0x58, 0x6c, 0x46, 0x6a, 0x47, 0x74, 0x56, 0x48, 0x45, 0x42, 0x38, + 0x70, 0x62, 0x56, 0x51, 0x47, 0x0a, 0x75, 0x62, 0x6e, 0x59, 0x31, 0x57, + 0x43, 0x49, 0x77, 0x34, 0x53, 0x57, 0x43, 0x52, 0x6a, 0x57, 0x49, 0x4b, + 0x58, 0x61, 0x4b, 0x35, 0x33, 0x4b, 0x36, 0x32, 0x6c, 0x55, 0x55, 0x4b, + 0x36, 0x58, 0x41, 0x6b, 0x77, 0x55, 0x68, 0x59, 0x6c, 0x47, 0x54, 0x76, + 0x77, 0x4d, 0x63, 0x58, 0x65, 0x49, 0x73, 0x77, 0x7a, 0x38, 0x55, 0x50, + 0x2f, 0x31, 0x71, 0x59, 0x39, 0x66, 0x36, 0x52, 0x30, 0x48, 0x37, 0x66, + 0x62, 0x64, 0x34, 0x4f, 0x76, 0x42, 0x53, 0x69, 0x58, 0x48, 0x0a, 0x79, + 0x6e, 0x73, 0x51, 0x6a, 0x35, 0x77, 0x52, 0x38, 0x79, 0x50, 0x6d, 0x49, + 0x4f, 0x49, 0x54, 0x4e, 0x4f, 0x4b, 0x49, 0x56, 0x48, 0x65, 0x37, 0x6d, + 0x6a, 0x65, 0x6c, 0x52, 0x39, 0x34, 0x77, 0x6f, 0x42, 0x37, 0x5a, 0x69, + 0x48, 0x4e, 0x4d, 0x42, 0x63, 0x35, 0x59, 0x36, 0x7a, 0x4b, 0x48, 0x5a, + 0x31, 0x70, 0x58, 0x77, 0x6a, 0x67, 0x4f, 0x78, 0x67, 0x43, 0x6b, 0x4e, + 0x34, 0x32, 0x4a, 0x66, 0x36, 0x6d, 0x36, 0x43, 0x5a, 0x39, 0x41, 0x64, + 0x47, 0x48, 0x6c, 0x0a, 0x59, 0x54, 0x72, 0x75, 0x74, 0x48, 0x55, 0x57, + 0x45, 0x35, 0x36, 0x59, 0x47, 0x35, 0x2b, 0x53, 0x46, 0x4e, 0x41, 0x4a, + 0x6e, 0x7a, 0x50, 0x44, 0x4b, 0x64, 0x71, 0x73, 0x57, 0x7a, 0x32, 0x73, + 0x39, 0x58, 0x4f, 0x4a, 0x39, 0x36, 0x41, 0x68, 0x71, 0x2f, 0x45, 0x37, + 0x6c, 0x66, 0x38, 0x6b, 0x64, 0x71, 0x62, 0x6d, 0x42, 0x75, 0x7a, 0x2b, + 0x7a, 0x6c, 0x65, 0x34, 0x61, 0x46, 0x31, 0x7a, 0x70, 0x61, 0x6b, 0x41, + 0x37, 0x57, 0x62, 0x58, 0x42, 0x59, 0x73, 0x6f, 0x0a, 0x2f, 0x2f, 0x47, + 0x52, 0x5a, 0x79, 0x48, 0x68, 0x35, 0x38, 0x31, 0x6c, 0x49, 0x43, 0x4a, + 0x4f, 0x58, 0x52, 0x74, 0x37, 0x4c, 0x5a, 0x30, 0x74, 0x79, 0x62, 0x58, + 0x75, 0x72, 0x31, 0x57, 0x67, 0x47, 0x50, 0x58, 0x58, 0x32, 0x42, 0x37, + 0x77, 0x4f, 0x75, 0x59, 0x6e, 0x31, 0x42, 0x71, 0x54, 0x4f, 0x62, 0x73, + 0x5a, 0x4c, 0x61, 0x37, 0x77, 0x38, 0x4f, 0x34, 0x30, 0x45, 0x76, 0x78, + 0x49, 0x73, 0x4a, 0x66, 0x4f, 0x66, 0x46, 0x4c, 0x64, 0x39, 0x79, 0x71, + 0x62, 0x0a, 0x46, 0x62, 0x54, 0x31, 0x38, 0x78, 0x4d, 0x57, 0x4c, 0x51, + 0x38, 0x77, 0x76, 0x33, 0x76, 0x66, 0x79, 0x6b, 0x54, 0x55, 0x52, 0x69, + 0x64, 0x48, 0x7a, 0x54, 0x79, 0x2f, 0x31, 0x68, 0x76, 0x45, 0x4a, 0x45, + 0x73, 0x65, 0x39, 0x56, 0x42, 0x56, 0x7a, 0x59, 0x53, 0x46, 0x63, 0x55, + 0x62, 0x55, 0x72, 0x47, 0x2b, 0x2f, 0x4c, 0x49, 0x43, 0x34, 0x6a, 0x6c, + 0x54, 0x78, 0x44, 0x64, 0x67, 0x48, 0x64, 0x37, 0x79, 0x74, 0x68, 0x4a, + 0x37, 0x4e, 0x77, 0x4c, 0x68, 0x68, 0x0a, 0x63, 0x77, 0x68, 0x42, 0x2f, + 0x55, 0x2b, 0x7a, 0x34, 0x39, 0x78, 0x62, 0x50, 0x76, 0x37, 0x6c, 0x76, + 0x66, 0x54, 0x4c, 0x71, 0x34, 0x55, 0x61, 0x48, 0x55, 0x34, 0x37, 0x71, + 0x51, 0x37, 0x64, 0x2f, 0x34, 0x73, 0x48, 0x7a, 0x31, 0x73, 0x79, 0x4b, + 0x37, 0x6c, 0x4d, 0x4c, 0x44, 0x37, 0x70, 0x51, 0x31, 0x30, 0x79, 0x61, + 0x61, 0x4c, 0x4a, 0x73, 0x45, 0x38, 0x55, 0x42, 0x79, 0x69, 0x67, 0x4c, + 0x71, 0x56, 0x74, 0x45, 0x77, 0x65, 0x57, 0x6b, 0x4c, 0x46, 0x56, 0x0a, + 0x4d, 0x30, 0x4d, 0x6a, 0x55, 0x35, 0x31, 0x72, 0x69, 0x72, 0x57, 0x70, + 0x52, 0x75, 0x62, 0x72, 0x47, 0x64, 0x53, 0x46, 0x73, 0x58, 0x44, 0x6c, + 0x31, 0x4e, 0x31, 0x57, 0x53, 0x67, 0x65, 0x6f, 0x30, 0x5a, 0x75, 0x75, + 0x37, 0x41, 0x4a, 0x64, 0x74, 0x42, 0x43, 0x68, 0x64, 0x31, 0x62, 0x6d, + 0x53, 0x2f, 0x39, 0x56, 0x39, 0x48, 0x43, 0x69, 0x42, 0x46, 0x79, 0x33, + 0x71, 0x42, 0x43, 0x2b, 0x33, 0x4b, 0x79, 0x34, 0x6f, 0x4e, 0x4d, 0x6b, + 0x6c, 0x4c, 0x46, 0x6f, 0x0a, 0x54, 0x6f, 0x58, 0x77, 0x33, 0x32, 0x63, + 0x43, 0x31, 0x30, 0x34, 0x39, 0x63, 0x49, 0x69, 0x47, 0x35, 0x68, 0x37, + 0x6b, 0x34, 0x54, 0x30, 0x66, 0x42, 0x48, 0x75, 0x75, 0x46, 0x78, 0x42, + 0x7a, 0x71, 0x4e, 0x31, 0x67, 0x34, 0x45, 0x67, 0x70, 0x76, 0x54, 0x69, + 0x6f, 0x52, 0x51, 0x6f, 0x54, 0x62, 0x59, 0x6a, 0x6e, 0x6c, 0x70, 0x4a, + 0x50, 0x6a, 0x68, 0x75, 0x78, 0x51, 0x38, 0x42, 0x32, 0x78, 0x51, 0x77, + 0x38, 0x34, 0x39, 0x6a, 0x78, 0x34, 0x6f, 0x44, 0x44, 0x0a, 0x63, 0x72, + 0x51, 0x64, 0x66, 0x33, 0x6b, 0x4c, 0x50, 0x72, 0x6f, 0x38, 0x69, 0x2f, + 0x48, 0x51, 0x42, 0x67, 0x55, 0x38, 0x67, 0x7a, 0x50, 0x6d, 0x69, 0x41, + 0x6f, 0x51, 0x59, 0x4f, 0x52, 0x41, 0x56, 0x6d, 0x68, 0x47, 0x37, 0x45, + 0x4f, 0x38, 0x4b, 0x5a, 0x74, 0x38, 0x4c, 0x72, 0x76, 0x52, 0x77, 0x49, + 0x49, 0x51, 0x4a, 0x76, 0x70, 0x5a, 0x64, 0x6f, 0x50, 0x4b, 0x6b, 0x38, + 0x39, 0x43, 0x68, 0x48, 0x73, 0x4e, 0x48, 0x7a, 0x4a, 0x6c, 0x35, 0x71, + 0x77, 0x52, 0x0a, 0x4e, 0x32, 0x66, 0x41, 0x73, 0x65, 0x52, 0x30, 0x79, + 0x69, 0x4b, 0x50, 0x30, 0x64, 0x4a, 0x56, 0x50, 0x7a, 0x4d, 0x51, 0x4c, + 0x5a, 0x36, 0x6a, 0x43, 0x73, 0x30, 0x75, 0x57, 0x68, 0x6e, 0x72, 0x75, + 0x56, 0x50, 0x57, 0x43, 0x65, 0x4e, 0x4d, 0x79, 0x6b, 0x41, 0x47, 0x74, + 0x39, 0x34, 0x6d, 0x6b, 0x4b, 0x76, 0x6a, 0x78, 0x6b, 0x6b, 0x55, 0x62, + 0x62, 0x39, 0x5a, 0x53, 0x37, 0x63, 0x39, 0x5a, 0x4f, 0x5a, 0x71, 0x77, + 0x42, 0x76, 0x6f, 0x57, 0x67, 0x6e, 0x54, 0x0a, 0x42, 0x7a, 0x6d, 0x71, + 0x61, 0x54, 0x58, 0x79, 0x77, 0x43, 0x33, 0x68, 0x69, 0x38, 0x43, 0x30, + 0x4c, 0x55, 0x59, 0x30, 0x58, 0x65, 0x73, 0x65, 0x57, 0x77, 0x6c, 0x70, + 0x4e, 0x49, 0x2f, 0x6b, 0x37, 0x55, 0x42, 0x4d, 0x39, 0x63, 0x45, 0x6f, + 0x70, 0x44, 0x46, 0x46, 0x38, 0x2b, 0x63, 0x52, 0x6a, 0x67, 0x4a, 0x63, + 0x31, 0x30, 0x64, 0x4e, 0x41, 0x6f, 0x51, 0x52, 0x76, 0x38, 0x65, 0x36, + 0x30, 0x57, 0x74, 0x73, 0x6d, 0x58, 0x45, 0x35, 0x4c, 0x56, 0x4a, 0x37, + 0x0a, 0x66, 0x4e, 0x57, 0x64, 0x54, 0x69, 0x7a, 0x47, 0x56, 0x6e, 0x4c, + 0x7a, 0x63, 0x6d, 0x47, 0x38, 0x78, 0x45, 0x52, 0x4e, 0x50, 0x30, 0x7a, + 0x5a, 0x4d, 0x55, 0x58, 0x4e, 0x6e, 0x2f, 0x58, 0x34, 0x7a, 0x46, 0x75, + 0x39, 0x51, 0x75, 0x6a, 0x44, 0x6e, 0x6e, 0x59, 0x75, 0x65, 0x35, 0x6c, + 0x50, 0x45, 0x4f, 0x6f, 0x69, 0x72, 0x59, 0x46, 0x43, 0x53, 0x65, 0x4e, + 0x70, 0x71, 0x58, 0x62, 0x53, 0x51, 0x75, 0x79, 0x75, 0x61, 0x59, 0x45, + 0x63, 0x6d, 0x79, 0x57, 0x72, 0x0a, 0x79, 0x75, 0x31, 0x63, 0x56, 0x6f, + 0x51, 0x72, 0x37, 0x76, 0x77, 0x53, 0x78, 0x57, 0x57, 0x2f, 0x66, 0x62, + 0x49, 0x71, 0x5a, 0x56, 0x61, 0x76, 0x39, 0x77, 0x4b, 0x62, 0x64, 0x48, + 0x38, 0x54, 0x56, 0x76, 0x56, 0x52, 0x68, 0x4e, 0x6b, 0x43, 0x36, 0x79, + 0x4f, 0x6f, 0x70, 0x55, 0x48, 0x4b, 0x36, 0x72, 0x62, 0x4d, 0x63, 0x37, + 0x4e, 0x6e, 0x43, 0x37, 0x4e, 0x76, 0x48, 0x73, 0x34, 0x49, 0x7a, 0x30, + 0x75, 0x33, 0x72, 0x57, 0x31, 0x4b, 0x52, 0x41, 0x53, 0x55, 0x0a, 0x46, + 0x56, 0x6b, 0x64, 0x42, 0x4d, 0x38, 0x72, 0x52, 0x5a, 0x4d, 0x70, 0x50, + 0x75, 0x59, 0x66, 0x34, 0x32, 0x6d, 0x42, 0x67, 0x56, 0x59, 0x63, 0x59, + 0x65, 0x58, 0x4c, 0x32, 0x42, 0x4f, 0x58, 0x6a, 0x76, 0x49, 0x42, 0x4c, + 0x37, 0x5a, 0x42, 0x48, 0x2f, 0x6f, 0x6f, 0x66, 0x35, 0x4c, 0x49, 0x55, + 0x6a, 0x68, 0x38, 0x4b, 0x68, 0x2b, 0x4a, 0x42, 0x38, 0x2f, 0x31, 0x79, + 0x42, 0x31, 0x58, 0x67, 0x61, 0x4d, 0x61, 0x53, 0x4e, 0x68, 0x2b, 0x32, + 0x38, 0x4d, 0x66, 0x0a, 0x75, 0x38, 0x7a, 0x79, 0x79, 0x42, 0x65, 0x70, + 0x72, 0x37, 0x63, 0x4c, 0x76, 0x57, 0x37, 0x77, 0x7a, 0x5a, 0x59, 0x69, + 0x41, 0x4e, 0x6f, 0x51, 0x4f, 0x64, 0x4c, 0x46, 0x77, 0x35, 0x4b, 0x63, + 0x77, 0x47, 0x45, 0x69, 0x51, 0x35, 0x30, 0x58, 0x44, 0x79, 0x49, 0x33, + 0x49, 0x75, 0x46, 0x72, 0x30, 0x67, 0x58, 0x58, 0x38, 0x74, 0x76, 0x73, + 0x50, 0x35, 0x6e, 0x6e, 0x68, 0x6b, 0x55, 0x61, 0x54, 0x76, 0x63, 0x7a, + 0x37, 0x2f, 0x45, 0x52, 0x72, 0x62, 0x64, 0x79, 0x0a, 0x6c, 0x58, 0x4e, + 0x34, 0x55, 0x69, 0x79, 0x44, 0x62, 0x78, 0x6b, 0x4e, 0x6e, 0x76, 0x6f, + 0x67, 0x61, 0x6f, 0x4b, 0x2b, 0x6e, 0x33, 0x72, 0x6c, 0x52, 0x79, 0x6e, + 0x32, 0x2f, 0x62, 0x2f, 0x56, 0x50, 0x53, 0x2b, 0x4a, 0x72, 0x4e, 0x4f, + 0x75, 0x72, 0x52, 0x55, 0x68, 0x37, 0x58, 0x49, 0x34, 0x4a, 0x59, 0x35, + 0x6f, 0x32, 0x50, 0x42, 0x79, 0x31, 0x74, 0x34, 0x77, 0x59, 0x45, 0x49, + 0x64, 0x49, 0x42, 0x4d, 0x70, 0x2b, 0x47, 0x78, 0x51, 0x34, 0x67, 0x61, + 0x6d, 0x0a, 0x72, 0x74, 0x77, 0x62, 0x4e, 0x49, 0x77, 0x2b, 0x34, 0x74, + 0x69, 0x4b, 0x43, 0x5a, 0x71, 0x5a, 0x65, 0x72, 0x44, 0x35, 0x4f, 0x4c, + 0x44, 0x31, 0x61, 0x4a, 0x66, 0x39, 0x54, 0x5a, 0x7a, 0x39, 0x6f, 0x5a, + 0x64, 0x58, 0x2f, 0x48, 0x6d, 0x4e, 0x52, 0x38, 0x6f, 0x72, 0x75, 0x6d, + 0x68, 0x43, 0x2f, 0x68, 0x71, 0x45, 0x31, 0x4a, 0x4f, 0x5a, 0x55, 0x59, + 0x2f, 0x6a, 0x73, 0x58, 0x61, 0x47, 0x30, 0x43, 0x52, 0x6d, 0x47, 0x49, + 0x6a, 0x37, 0x47, 0x42, 0x64, 0x47, 0x0a, 0x4d, 0x50, 0x6c, 0x4e, 0x35, + 0x48, 0x70, 0x46, 0x55, 0x6e, 0x6a, 0x75, 0x6f, 0x55, 0x47, 0x6c, 0x31, + 0x6c, 0x31, 0x55, 0x4f, 0x64, 0x32, 0x36, 0x4d, 0x56, 0x79, 0x53, 0x7a, + 0x4d, 0x58, 0x6f, 0x79, 0x36, 0x78, 0x61, 0x76, 0x7a, 0x62, 0x65, 0x35, + 0x72, 0x35, 0x63, 0x37, 0x36, 0x4d, 0x6b, 0x52, 0x69, 0x4f, 0x53, 0x30, + 0x70, 0x62, 0x6f, 0x69, 0x34, 0x6d, 0x75, 0x41, 0x64, 0x37, 0x38, 0x34, + 0x39, 0x36, 0x79, 0x42, 0x4b, 0x73, 0x6e, 0x67, 0x75, 0x7a, 0x55, 0x0a, + 0x33, 0x77, 0x2b, 0x33, 0x6f, 0x31, 0x32, 0x35, 0x59, 0x54, 0x64, 0x67, + 0x66, 0x4c, 0x46, 0x4e, 0x55, 0x65, 0x7a, 0x48, 0x76, 0x76, 0x4d, 0x41, + 0x6f, 0x74, 0x73, 0x42, 0x51, 0x67, 0x4a, 0x46, 0x64, 0x78, 0x4c, 0x68, + 0x77, 0x53, 0x4c, 0x59, 0x49, 0x5a, 0x47, 0x51, 0x45, 0x6b, 0x46, 0x67, + 0x52, 0x66, 0x31, 0x71, 0x4c, 0x58, 0x6b, 0x62, 0x54, 0x73, 0x73, 0x7a, + 0x78, 0x41, 0x39, 0x2b, 0x57, 0x37, 0x50, 0x73, 0x45, 0x79, 0x4b, 0x74, + 0x65, 0x56, 0x2b, 0x4a, 0x0a, 0x48, 0x4f, 0x76, 0x4c, 0x67, 0x67, 0x70, + 0x74, 0x76, 0x47, 0x7a, 0x71, 0x42, 0x6e, 0x30, 0x39, 0x36, 0x6b, 0x6a, + 0x59, 0x59, 0x68, 0x38, 0x64, 0x43, 0x65, 0x61, 0x72, 0x61, 0x62, 0x32, + 0x49, 0x54, 0x32, 0x67, 0x2b, 0x4e, 0x49, 0x44, 0x50, 0x44, 0x42, 0x55, + 0x67, 0x58, 0x61, 0x35, 0x31, 0x61, 0x38, 0x58, 0x76, 0x5a, 0x76, 0x78, + 0x6e, 0x72, 0x49, 0x56, 0x36, 0x4d, 0x4b, 0x79, 0x34, 0x59, 0x66, 0x78, + 0x4c, 0x53, 0x4b, 0x54, 0x4c, 0x61, 0x35, 0x67, 0x43, 0x0a, 0x50, 0x46, + 0x62, 0x2f, 0x73, 0x4c, 0x74, 0x5a, 0x51, 0x51, 0x44, 0x55, 0x61, 0x79, + 0x48, 0x76, 0x4d, 0x6f, 0x59, 0x6c, 0x6e, 0x66, 0x4c, 0x45, 0x6d, 0x44, + 0x6a, 0x71, 0x49, 0x44, 0x6d, 0x66, 0x6c, 0x36, 0x37, 0x68, 0x59, 0x2f, + 0x5a, 0x65, 0x4c, 0x54, 0x6f, 0x4e, 0x74, 0x76, 0x59, 0x42, 0x37, 0x49, + 0x79, 0x48, 0x6a, 0x55, 0x55, 0x41, 0x6f, 0x4b, 0x50, 0x36, 0x36, 0x50, + 0x5a, 0x67, 0x71, 0x75, 0x6d, 0x72, 0x2f, 0x2f, 0x78, 0x73, 0x67, 0x73, + 0x79, 0x4b, 0x0a, 0x56, 0x34, 0x49, 0x6a, 0x38, 0x79, 0x61, 0x41, 0x2b, + 0x36, 0x78, 0x43, 0x77, 0x63, 0x6a, 0x6f, 0x6d, 0x53, 0x48, 0x7a, 0x2f, + 0x32, 0x45, 0x43, 0x74, 0x72, 0x64, 0x5a, 0x46, 0x4e, 0x4b, 0x79, 0x57, + 0x36, 0x35, 0x2b, 0x70, 0x76, 0x44, 0x74, 0x64, 0x64, 0x7a, 0x6a, 0x50, + 0x79, 0x6e, 0x74, 0x53, 0x43, 0x6b, 0x72, 0x66, 0x4e, 0x74, 0x51, 0x68, + 0x56, 0x2b, 0x70, 0x62, 0x34, 0x77, 0x4b, 0x39, 0x51, 0x34, 0x70, 0x4d, + 0x63, 0x4e, 0x38, 0x73, 0x75, 0x44, 0x78, 0x0a, 0x66, 0x78, 0x4f, 0x70, + 0x45, 0x34, 0x74, 0x4e, 0x2b, 0x77, 0x61, 0x56, 0x4d, 0x6d, 0x48, 0x52, + 0x31, 0x57, 0x4c, 0x46, 0x54, 0x37, 0x47, 0x6c, 0x7a, 0x36, 0x35, 0x47, + 0x68, 0x2f, 0x57, 0x35, 0x2b, 0x55, 0x4e, 0x73, 0x6c, 0x56, 0x31, 0x35, + 0x48, 0x6d, 0x7a, 0x73, 0x58, 0x4a, 0x71, 0x48, 0x4a, 0x78, 0x6f, 0x41, + 0x34, 0x56, 0x4e, 0x38, 0x6e, 0x4b, 0x69, 0x72, 0x70, 0x42, 0x6f, 0x31, + 0x59, 0x32, 0x42, 0x47, 0x6c, 0x66, 0x50, 0x42, 0x6f, 0x71, 0x56, 0x6c, + 0x0a, 0x2b, 0x4e, 0x50, 0x64, 0x75, 0x6a, 0x39, 0x4f, 0x45, 0x74, 0x4b, + 0x72, 0x75, 0x71, 0x38, 0x69, 0x4b, 0x2b, 0x64, 0x55, 0x59, 0x61, 0x74, + 0x64, 0x36, 0x4c, 0x61, 0x69, 0x2b, 0x51, 0x49, 0x57, 0x79, 0x44, 0x47, + 0x42, 0x70, 0x4b, 0x56, 0x36, 0x63, 0x2b, 0x70, 0x42, 0x45, 0x33, 0x39, + 0x45, 0x42, 0x6f, 0x6b, 0x34, 0x30, 0x78, 0x32, 0x71, 0x75, 0x55, 0x76, + 0x55, 0x59, 0x62, 0x44, 0x79, 0x47, 0x57, 0x59, 0x62, 0x6f, 0x42, 0x57, + 0x2b, 0x72, 0x4c, 0x4b, 0x54, 0x0a, 0x58, 0x45, 0x6c, 0x72, 0x50, 0x49, + 0x6d, 0x74, 0x47, 0x52, 0x6e, 0x31, 0x46, 0x6b, 0x62, 0x58, 0x68, 0x6e, + 0x64, 0x4b, 0x78, 0x31, 0x58, 0x50, 0x65, 0x70, 0x75, 0x30, 0x70, 0x59, + 0x72, 0x64, 0x7a, 0x31, 0x58, 0x6d, 0x77, 0x49, 0x74, 0x5a, 0x53, 0x6c, + 0x66, 0x52, 0x46, 0x48, 0x59, 0x4c, 0x35, 0x61, 0x57, 0x38, 0x38, 0x37, + 0x51, 0x4b, 0x6b, 0x39, 0x38, 0x53, 0x52, 0x4e, 0x6e, 0x34, 0x56, 0x35, + 0x32, 0x5a, 0x77, 0x44, 0x6e, 0x67, 0x71, 0x36, 0x66, 0x50, 0x0a, 0x35, + 0x61, 0x62, 0x55, 0x32, 0x63, 0x2f, 0x77, 0x78, 0x67, 0x77, 0x56, 0x49, + 0x77, 0x77, 0x2f, 0x74, 0x64, 0x33, 0x4a, 0x61, 0x36, 0x77, 0x47, 0x44, + 0x42, 0x49, 0x63, 0x4d, 0x68, 0x4d, 0x75, 0x53, 0x7a, 0x42, 0x39, 0x48, + 0x6c, 0x6f, 0x69, 0x65, 0x6d, 0x71, 0x62, 0x43, 0x62, 0x73, 0x4d, 0x2f, + 0x53, 0x63, 0x43, 0x79, 0x54, 0x30, 0x73, 0x47, 0x2f, 0x61, 0x4b, 0x76, + 0x35, 0x6c, 0x4c, 0x65, 0x36, 0x62, 0x39, 0x59, 0x45, 0x50, 0x39, 0x66, + 0x6d, 0x45, 0x4f, 0x0a, 0x78, 0x6d, 0x75, 0x4e, 0x6f, 0x6a, 0x59, 0x47, + 0x36, 0x76, 0x4e, 0x79, 0x43, 0x78, 0x48, 0x52, 0x4c, 0x39, 0x59, 0x4a, + 0x41, 0x41, 0x2f, 0x58, 0x6d, 0x4e, 0x64, 0x32, 0x43, 0x4b, 0x59, 0x42, + 0x45, 0x79, 0x56, 0x62, 0x4e, 0x44, 0x4e, 0x50, 0x65, 0x43, 0x4a, 0x67, + 0x66, 0x35, 0x31, 0x6f, 0x4d, 0x62, 0x77, 0x30, 0x61, 0x72, 0x65, 0x38, + 0x58, 0x6b, 0x66, 0x62, 0x56, 0x36, 0x34, 0x49, 0x45, 0x44, 0x43, 0x45, + 0x4b, 0x2f, 0x56, 0x6a, 0x68, 0x59, 0x57, 0x51, 0x0a, 0x75, 0x42, 0x53, + 0x6c, 0x54, 0x56, 0x6b, 0x46, 0x6b, 0x58, 0x57, 0x67, 0x32, 0x31, 0x41, + 0x45, 0x67, 0x74, 0x78, 0x79, 0x56, 0x7a, 0x78, 0x6c, 0x31, 0x6e, 0x56, + 0x69, 0x41, 0x6a, 0x74, 0x6e, 0x31, 0x72, 0x38, 0x59, 0x72, 0x73, 0x45, + 0x48, 0x33, 0x74, 0x51, 0x73, 0x47, 0x32, 0x64, 0x34, 0x48, 0x32, 0x65, + 0x44, 0x4c, 0x69, 0x36, 0x49, 0x39, 0x7a, 0x79, 0x48, 0x77, 0x6d, 0x70, + 0x56, 0x4b, 0x33, 0x51, 0x79, 0x66, 0x71, 0x42, 0x47, 0x66, 0x63, 0x74, + 0x64, 0x0a, 0x64, 0x78, 0x5a, 0x46, 0x6f, 0x74, 0x6e, 0x4a, 0x2b, 0x73, + 0x73, 0x6c, 0x37, 0x34, 0x31, 0x33, 0x30, 0x4f, 0x6d, 0x63, 0x67, 0x59, + 0x74, 0x35, 0x6d, 0x70, 0x35, 0x57, 0x4c, 0x2f, 0x4b, 0x4f, 0x58, 0x41, + 0x4c, 0x63, 0x55, 0x64, 0x34, 0x45, 0x59, 0x50, 0x49, 0x58, 0x57, 0x66, + 0x71, 0x6a, 0x4e, 0x77, 0x6d, 0x78, 0x4b, 0x75, 0x77, 0x74, 0x6e, 0x50, + 0x50, 0x6e, 0x71, 0x32, 0x67, 0x75, 0x55, 0x46, 0x44, 0x32, 0x42, 0x70, + 0x42, 0x35, 0x77, 0x2f, 0x45, 0x69, 0x0a, 0x65, 0x71, 0x50, 0x32, 0x66, + 0x2f, 0x6b, 0x7a, 0x58, 0x77, 0x79, 0x33, 0x4e, 0x57, 0x42, 0x4d, 0x79, + 0x70, 0x4b, 0x50, 0x4b, 0x79, 0x46, 0x4f, 0x7a, 0x32, 0x7a, 0x6a, 0x52, + 0x30, 0x61, 0x56, 0x41, 0x35, 0x73, 0x78, 0x41, 0x42, 0x2f, 0x6d, 0x77, + 0x38, 0x59, 0x51, 0x4c, 0x55, 0x34, 0x6c, 0x54, 0x73, 0x36, 0x39, 0x2f, + 0x44, 0x35, 0x74, 0x4b, 0x35, 0x55, 0x4a, 0x44, 0x39, 0x46, 0x59, 0x52, + 0x4f, 0x6d, 0x66, 0x57, 0x75, 0x6b, 0x42, 0x61, 0x34, 0x76, 0x4b, 0x0a, + 0x33, 0x39, 0x72, 0x57, 0x52, 0x34, 0x78, 0x30, 0x6b, 0x47, 0x72, 0x78, + 0x47, 0x76, 0x35, 0x35, 0x6b, 0x54, 0x31, 0x6f, 0x6e, 0x56, 0x61, 0x78, + 0x55, 0x30, 0x53, 0x66, 0x66, 0x56, 0x6f, 0x78, 0x68, 0x61, 0x75, 0x72, + 0x6f, 0x44, 0x34, 0x36, 0x33, 0x77, 0x37, 0x50, 0x42, 0x70, 0x66, 0x69, + 0x42, 0x46, 0x63, 0x36, 0x62, 0x39, 0x34, 0x56, 0x66, 0x34, 0x74, 0x79, + 0x51, 0x43, 0x7a, 0x4a, 0x38, 0x4b, 0x68, 0x7a, 0x63, 0x7a, 0x77, 0x62, + 0x58, 0x59, 0x57, 0x46, 0x0a, 0x46, 0x58, 0x35, 0x36, 0x55, 0x67, 0x64, + 0x4e, 0x6f, 0x36, 0x77, 0x77, 0x72, 0x47, 0x57, 0x7a, 0x57, 0x39, 0x43, + 0x42, 0x34, 0x55, 0x49, 0x34, 0x75, 0x44, 0x43, 0x64, 0x55, 0x4f, 0x5a, + 0x75, 0x63, 0x59, 0x30, 0x42, 0x77, 0x6b, 0x54, 0x58, 0x55, 0x72, 0x6e, + 0x62, 0x68, 0x43, 0x72, 0x66, 0x78, 0x42, 0x7a, 0x7a, 0x2b, 0x37, 0x4f, + 0x64, 0x43, 0x55, 0x65, 0x72, 0x69, 0x31, 0x79, 0x63, 0x59, 0x74, 0x48, + 0x54, 0x38, 0x47, 0x67, 0x41, 0x54, 0x30, 0x49, 0x4a, 0x0a, 0x6c, 0x4f, + 0x6a, 0x4c, 0x56, 0x69, 0x4e, 0x49, 0x35, 0x4a, 0x6e, 0x38, 0x49, 0x36, + 0x57, 0x74, 0x58, 0x35, 0x6f, 0x48, 0x7a, 0x35, 0x6c, 0x33, 0x43, 0x42, + 0x44, 0x58, 0x64, 0x75, 0x73, 0x6b, 0x55, 0x77, 0x33, 0x54, 0x4a, 0x63, + 0x42, 0x76, 0x7a, 0x31, 0x63, 0x5a, 0x4e, 0x69, 0x31, 0x70, 0x2b, 0x6c, + 0x6e, 0x43, 0x54, 0x44, 0x57, 0x69, 0x79, 0x47, 0x71, 0x50, 0x35, 0x35, + 0x34, 0x38, 0x63, 0x68, 0x4c, 0x54, 0x47, 0x6f, 0x6e, 0x42, 0x79, 0x50, + 0x39, 0x74, 0x0a, 0x39, 0x46, 0x67, 0x32, 0x65, 0x4c, 0x67, 0x61, 0x70, + 0x6f, 0x52, 0x72, 0x58, 0x36, 0x30, 0x51, 0x4e, 0x2b, 0x7a, 0x68, 0x47, + 0x2b, 0x51, 0x4d, 0x6f, 0x30, 0x58, 0x4a, 0x44, 0x71, 0x6c, 0x38, 0x79, + 0x56, 0x34, 0x63, 0x73, 0x2f, 0x72, 0x5a, 0x6a, 0x55, 0x53, 0x4b, 0x62, + 0x6b, 0x55, 0x37, 0x61, 0x46, 0x46, 0x61, 0x73, 0x6d, 0x52, 0x62, 0x6c, + 0x45, 0x75, 0x61, 0x32, 0x61, 0x47, 0x55, 0x77, 0x50, 0x2f, 0x6c, 0x69, + 0x58, 0x56, 0x4b, 0x59, 0x36, 0x42, 0x72, 0x0a, 0x6d, 0x32, 0x71, 0x57, + 0x75, 0x49, 0x75, 0x2b, 0x62, 0x68, 0x41, 0x2b, 0x62, 0x76, 0x6b, 0x6e, + 0x33, 0x42, 0x42, 0x61, 0x77, 0x46, 0x35, 0x52, 0x43, 0x69, 0x55, 0x52, + 0x62, 0x76, 0x53, 0x52, 0x54, 0x72, 0x46, 0x4c, 0x50, 0x63, 0x78, 0x69, + 0x6b, 0x6c, 0x53, 0x78, 0x6c, 0x72, 0x74, 0x6f, 0x34, 0x68, 0x38, 0x63, + 0x4b, 0x6a, 0x4f, 0x33, 0x38, 0x4d, 0x68, 0x2b, 0x52, 0x2f, 0x31, 0x32, + 0x6c, 0x55, 0x45, 0x62, 0x7a, 0x48, 0x41, 0x64, 0x51, 0x50, 0x77, 0x57, + 0x0a, 0x6b, 0x66, 0x47, 0x70, 0x77, 0x58, 0x62, 0x52, 0x68, 0x61, 0x43, + 0x56, 0x38, 0x74, 0x74, 0x32, 0x75, 0x49, 0x7a, 0x79, 0x47, 0x47, 0x4b, + 0x66, 0x6e, 0x75, 0x4c, 0x2f, 0x68, 0x44, 0x77, 0x2f, 0x33, 0x48, 0x55, + 0x37, 0x53, 0x57, 0x76, 0x55, 0x32, 0x61, 0x59, 0x58, 0x68, 0x6c, 0x4d, + 0x6d, 0x57, 0x58, 0x67, 0x53, 0x51, 0x4a, 0x61, 0x49, 0x67, 0x71, 0x37, + 0x66, 0x68, 0x43, 0x62, 0x38, 0x72, 0x46, 0x41, 0x6f, 0x77, 0x64, 0x32, + 0x48, 0x6e, 0x76, 0x70, 0x53, 0x0a, 0x32, 0x68, 0x4b, 0x4a, 0x67, 0x30, + 0x6b, 0x57, 0x5a, 0x2f, 0x54, 0x44, 0x4a, 0x55, 0x69, 0x43, 0x5a, 0x4c, + 0x51, 0x62, 0x67, 0x2f, 0x2f, 0x44, 0x44, 0x36, 0x78, 0x62, 0x33, 0x67, + 0x65, 0x41, 0x64, 0x7a, 0x7a, 0x4e, 0x54, 0x68, 0x66, 0x72, 0x58, 0x41, + 0x46, 0x7a, 0x52, 0x73, 0x6a, 0x4f, 0x73, 0x37, 0x71, 0x78, 0x39, 0x59, + 0x37, 0x47, 0x39, 0x34, 0x66, 0x54, 0x6a, 0x6d, 0x34, 0x74, 0x49, 0x4b, + 0x33, 0x61, 0x65, 0x72, 0x32, 0x79, 0x49, 0x72, 0x44, 0x4d, 0x0a, 0x37, + 0x7a, 0x67, 0x52, 0x36, 0x56, 0x49, 0x34, 0x43, 0x56, 0x31, 0x6a, 0x2f, + 0x4e, 0x6e, 0x4f, 0x2f, 0x4d, 0x55, 0x53, 0x67, 0x78, 0x70, 0x4a, 0x74, + 0x62, 0x41, 0x5a, 0x68, 0x67, 0x55, 0x45, 0x37, 0x62, 0x43, 0x4f, 0x35, + 0x49, 0x41, 0x33, 0x39, 0x48, 0x51, 0x34, 0x68, 0x54, 0x37, 0x46, 0x6d, + 0x56, 0x66, 0x74, 0x2b, 0x2b, 0x35, 0x53, 0x4e, 0x57, 0x31, 0x70, 0x5a, + 0x4f, 0x6e, 0x41, 0x2f, 0x6a, 0x57, 0x6a, 0x7a, 0x52, 0x68, 0x4f, 0x35, + 0x4a, 0x54, 0x6b, 0x0a, 0x38, 0x32, 0x62, 0x69, 0x64, 0x6f, 0x6e, 0x77, + 0x36, 0x63, 0x2f, 0x4f, 0x4f, 0x38, 0x50, 0x4e, 0x69, 0x33, 0x6f, 0x64, + 0x4e, 0x70, 0x77, 0x46, 0x75, 0x49, 0x66, 0x53, 0x45, 0x2b, 0x59, 0x54, + 0x37, 0x4e, 0x78, 0x7a, 0x4b, 0x35, 0x41, 0x68, 0x41, 0x79, 0x53, 0x4b, + 0x35, 0x66, 0x6b, 0x77, 0x62, 0x39, 0x6d, 0x68, 0x54, 0x4f, 0x72, 0x5a, + 0x38, 0x70, 0x66, 0x36, 0x4b, 0x77, 0x78, 0x52, 0x30, 0x47, 0x4f, 0x44, + 0x43, 0x56, 0x66, 0x66, 0x53, 0x4b, 0x69, 0x52, 0x0a, 0x67, 0x35, 0x33, + 0x4a, 0x35, 0x4b, 0x6a, 0x75, 0x45, 0x65, 0x30, 0x44, 0x70, 0x4b, 0x74, + 0x46, 0x53, 0x30, 0x57, 0x58, 0x30, 0x4a, 0x77, 0x5a, 0x34, 0x65, 0x39, + 0x79, 0x37, 0x46, 0x62, 0x66, 0x6e, 0x4c, 0x54, 0x4d, 0x74, 0x45, 0x4a, + 0x61, 0x68, 0x63, 0x73, 0x2b, 0x2f, 0x6a, 0x7a, 0x63, 0x76, 0x7a, 0x6e, + 0x7a, 0x32, 0x37, 0x41, 0x51, 0x2b, 0x54, 0x47, 0x6e, 0x46, 0x2f, 0x59, + 0x6a, 0x35, 0x4b, 0x65, 0x76, 0x71, 0x77, 0x33, 0x42, 0x68, 0x52, 0x69, + 0x6a, 0x0a, 0x47, 0x4c, 0x68, 0x62, 0x4a, 0x49, 0x57, 0x30, 0x7a, 0x4d, + 0x71, 0x54, 0x45, 0x47, 0x41, 0x62, 0x6b, 0x70, 0x63, 0x4a, 0x50, 0x4a, + 0x4a, 0x50, 0x4a, 0x79, 0x41, 0x45, 0x48, 0x55, 0x6d, 0x61, 0x4c, 0x50, + 0x4c, 0x78, 0x30, 0x34, 0x6d, 0x57, 0x53, 0x65, 0x42, 0x45, 0x58, 0x43, + 0x45, 0x67, 0x38, 0x4f, 0x78, 0x4a, 0x79, 0x4d, 0x39, 0x37, 0x65, 0x44, + 0x69, 0x76, 0x43, 0x6d, 0x4e, 0x36, 0x6c, 0x33, 0x42, 0x7a, 0x7a, 0x49, + 0x34, 0x51, 0x4f, 0x75, 0x72, 0x37, 0x0a, 0x49, 0x2b, 0x49, 0x42, 0x41, + 0x32, 0x63, 0x46, 0x59, 0x4f, 0x4c, 0x7a, 0x6c, 0x4a, 0x46, 0x74, 0x48, + 0x69, 0x62, 0x51, 0x2f, 0x78, 0x49, 0x68, 0x67, 0x64, 0x62, 0x51, 0x68, + 0x44, 0x77, 0x6f, 0x6d, 0x72, 0x37, 0x63, 0x7a, 0x73, 0x52, 0x63, 0x34, + 0x63, 0x32, 0x65, 0x72, 0x38, 0x34, 0x61, 0x59, 0x47, 0x66, 0x34, 0x76, + 0x37, 0x56, 0x67, 0x62, 0x57, 0x51, 0x71, 0x41, 0x71, 0x48, 0x68, 0x51, + 0x31, 0x49, 0x49, 0x76, 0x39, 0x4d, 0x75, 0x2f, 0x4f, 0x75, 0x61, 0x0a, + 0x44, 0x62, 0x49, 0x78, 0x36, 0x76, 0x54, 0x78, 0x68, 0x6c, 0x78, 0x4b, + 0x44, 0x78, 0x41, 0x70, 0x6e, 0x7a, 0x6b, 0x6c, 0x65, 0x76, 0x6c, 0x48, + 0x70, 0x59, 0x67, 0x37, 0x52, 0x75, 0x6e, 0x6e, 0x66, 0x2f, 0x2b, 0x35, + 0x43, 0x55, 0x31, 0x56, 0x62, 0x34, 0x47, 0x62, 0x36, 0x69, 0x73, 0x51, + 0x79, 0x6d, 0x30, 0x4c, 0x44, 0x74, 0x70, 0x70, 0x61, 0x59, 0x64, 0x52, + 0x41, 0x42, 0x72, 0x53, 0x4e, 0x4b, 0x67, 0x74, 0x6e, 0x38, 0x4d, 0x55, + 0x55, 0x5a, 0x65, 0x5a, 0x0a, 0x6f, 0x31, 0x55, 0x78, 0x41, 0x6f, 0x6c, + 0x76, 0x63, 0x72, 0x55, 0x36, 0x7a, 0x43, 0x33, 0x54, 0x4a, 0x62, 0x4c, + 0x36, 0x38, 0x67, 0x50, 0x4a, 0x54, 0x58, 0x69, 0x4c, 0x37, 0x51, 0x49, + 0x46, 0x58, 0x79, 0x45, 0x58, 0x42, 0x30, 0x48, 0x74, 0x55, 0x32, 0x47, + 0x6b, 0x35, 0x58, 0x79, 0x45, 0x65, 0x50, 0x76, 0x65, 0x33, 0x75, 0x41, + 0x4a, 0x4c, 0x38, 0x76, 0x43, 0x52, 0x39, 0x31, 0x6b, 0x51, 0x57, 0x7a, + 0x6c, 0x4e, 0x62, 0x43, 0x78, 0x46, 0x49, 0x47, 0x46, 0x0a, 0x74, 0x65, + 0x53, 0x68, 0x72, 0x7a, 0x2f, 0x6c, 0x57, 0x6f, 0x56, 0x4f, 0x4f, 0x49, + 0x4d, 0x44, 0x6d, 0x42, 0x75, 0x7a, 0x66, 0x4c, 0x66, 0x34, 0x50, 0x58, + 0x30, 0x6a, 0x39, 0x36, 0x41, 0x69, 0x35, 0x47, 0x6b, 0x33, 0x36, 0x66, + 0x41, 0x5a, 0x37, 0x64, 0x76, 0x44, 0x66, 0x57, 0x57, 0x59, 0x48, 0x65, + 0x67, 0x36, 0x4d, 0x2f, 0x70, 0x50, 0x6c, 0x61, 0x6d, 0x52, 0x41, 0x2f, + 0x31, 0x63, 0x51, 0x58, 0x77, 0x6e, 0x69, 0x2b, 0x50, 0x34, 0x53, 0x43, + 0x75, 0x67, 0x0a, 0x45, 0x32, 0x69, 0x58, 0x58, 0x7a, 0x4f, 0x51, 0x67, + 0x4b, 0x77, 0x5a, 0x61, 0x45, 0x74, 0x46, 0x69, 0x43, 0x4a, 0x56, 0x71, + 0x33, 0x64, 0x73, 0x48, 0x57, 0x45, 0x6a, 0x4d, 0x64, 0x33, 0x58, 0x59, + 0x4e, 0x71, 0x65, 0x55, 0x73, 0x45, 0x70, 0x35, 0x37, 0x33, 0x4c, 0x4e, + 0x75, 0x32, 0x67, 0x67, 0x32, 0x36, 0x38, 0x4b, 0x42, 0x45, 0x3d, 0x0a +}; +unsigned int test_data_enc_len = 6756; + +unsigned cpl = 76; +int main(int argc, char **argv) { + // Test encoding... + printf("Test encoding...\n"); + unsigned len = Base64EncodeSize(test_data_len, cpl); + printf("Predicted size: %u\n", len); + char *data = (char*)malloc(len); + len = Base64Encode(data, (const char*)&test_data[0], test_data_len, cpl); + if (len != test_data_enc_len || memcmp(data, (const char*)&test_data_enc[0], len) != 0) { + printf("input size: %u\n", test_data_len); + printf("output size: %u\n", len); + printf("expected output size: %u\n", test_data_enc_len); + printf("Encoding differs...\n"); + return 1; + } + free(data); + printf("Pass\n"); + + printf("Test decoding...\n"); + len = Base64DecodeSize(test_data_enc_len); + printf("Predicted size: %u\n", len); + data = (char*)malloc(len); + len = Base64Decode(data, (const char*)&test_data_enc[0], test_data_enc_len); + if (len != test_data_len || memcmp(data, (const char*)&test_data[0], len) != 0) { + printf("input size: %u\n", test_data_enc_len); + printf("output size: %u\n", len); + printf("expected size: %u\n", test_data_len); + printf("Decoding differs...\n"); + return 1; + } + free(data); + printf("Pass\n"); + return 0; +} diff --git a/src/hos_libvariant/src/test/test_bundleemitter.cc b/src/hos_libvariant/src/test/test_bundleemitter.cc new file mode 100644 index 00000000..7305e0f2 --- /dev/null +++ b/src/hos_libvariant/src/test/test_bundleemitter.cc @@ -0,0 +1,95 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include "TestAssert.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace libvariant; +using namespace std; + +void TestOne() { + cout << "Testing basic functionality" << endl; + Variant v = Variant::MapType; + v["foo"] = 12.33456; + v["bar"] = 873453; + v["boo"] = false; + v["null"] = Variant::NullType; + v["true"] = true; + v["moo"] = "test one two three blah blah blah"; + v["loo"].Append(1).Append(2).Append(3); + const char payload[] = "fp9q8ywtrvapwn98nc4yargcfuiahwer8ytqv9p4tcp98y3crhlei4t8hpse985ytvlseuhrotceyiruth"; + v["payload.data"] = Blob::CreateReferenced((char*)payload, sizeof(payload)); + std::vector buff; + buff.resize(8192); + unsigned len = SerializeBundle(&buff[0], buff.size(), v); + buff.resize(len); + ASSERT((buff.size() - strlen(&buff[0]) - 1) == sizeof(payload)); + ASSERT(memcmp(payload, &buff[strlen(&buff[0]) + 1], sizeof(payload)) == 0); + fwrite(&buff[0], 1, buff.size(), stdout); + printf("\n"); + Variant val = DeserializeBundle(&buff[0], buff.size()); + ASSERT(val["bar"] == v["bar"]); + ASSERT(val["moo"] == v["moo"]); + ASSERT(val["loo"] == v["loo"]); + ASSERT(val["boo"].AsInt() == 0); // bundles don't preserve boolean type information +} + +void TestErrorPaths() { + cout << "Testing error paths" << endl; + std::ostringstream oss; + Emitter e = BundleHdrEmitter(CreateEmitterOutput(oss.rdbuf())); + + // Test error paths + e.BeginDocument(); + try { + e.BeginDocument(); + abort(); + } catch (const std::runtime_error &) {} + e.BeginMap(); + try { + e.BeginMap(); + abort(); + } catch (const std::runtime_error &) {} + try { + e.BeginList(); + abort(); + } catch (const std::runtime_error &) {} + try { + e.EndList(); + abort(); + } catch (const std::runtime_error &) {} + try { + e.Emit("key").Emit((ConstBlobPtr)Blob::CreateCopy((void*)0,0)); + abort(); + } catch (const std::runtime_error &) {} + e.Emit(true); + e.EndMap(); + try { + e.EndMap(); + abort(); + } catch (const std::runtime_error &) {} + try { + e.Emit("abc"); + abort(); + } catch (const std::runtime_error &) {} + e.EndDocument(); + try { + e.EndDocument(); + abort(); + } catch (const std::runtime_error &) {} +} + +int main(int argc, char **argv) { + TestOne(); + TestErrorPaths(); + return 0; +} diff --git a/src/hos_libvariant/src/test/test_bundlehdr.cc b/src/hos_libvariant/src/test/test_bundlehdr.cc new file mode 100644 index 00000000..35f31363 --- /dev/null +++ b/src/hos_libvariant/src/test/test_bundlehdr.cc @@ -0,0 +1,49 @@ +/** \file + * \author John Bridgman + * \brief + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace libvariant; + +const char example_bundle[] = +"bundle.version: 0.0\n" +"keyone: value\n" +"listkey: value1|value2|value3\n" +"doodle: 1234 # comments!\n" +"foo: 0.234245\n" +"singlelist: blah|\n" +"emptylist: |\n" +"\n\n\n\n\0"; + +const char expected[] = "{ \"keyone\": \"value\"," +"\"listkey\": [ \"value1\", \"value2\", \"value3\" ], \"doodle\": 1234, \"foo\": 0.234245," +"\"singlelist\": [ \"blah\" ], \"emptylist\": [] }"; + +int main(int argc, char **argv) { + std::istringstream iss(std::string(&example_bundle[0], strlen(&example_bundle[0])+1)); + Parser parser = BundleHdrParser(CreateParserInputFile(iss.rdbuf())); + + Variant v = ParseVariant(parser); + Variant ex = DeserializeJSON(expected); + if (v != ex) { + puts(""); + SerializeJSON(stdout, v); + puts(""); + SerializeJSON(stdout, ex); + puts(""); + return 1; + } + Emitter emitter = BundleHdrEmitter(CreateEmitterOutput(stdout)); + emitter << v; + return 0; +} diff --git a/src/hos_libvariant/src/test/test_bundleparser.cc b/src/hos_libvariant/src/test/test_bundleparser.cc new file mode 100644 index 00000000..25ec8e47 --- /dev/null +++ b/src/hos_libvariant/src/test/test_bundleparser.cc @@ -0,0 +1,93 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "TestAssert.h" +#include +#include +#include +#include +#include + +using namespace libvariant; +using namespace std; + +const char bundle_str[] = +"bundle.version: 0.0\n" +"id: 1\n" +"payload.length: 40\n" +"\0" +"1234567890" +"1234567890" +"1234567890" +"1234567890" +"bundle.version: 0.0\n" +"id: 2 # comments\n" +"payload.length: 40\n" +"#comments\n" +"\0" +"\000\00\00\00" +"\001\00\00\00" +"\002\00\00\00" +"\003\00\00\00" +"\004\00\00\00" +"\005\00\00\00" +"\006\00\00\00" +"\007\00\00\00" +"\010\00\00\00" +"\011\00\00\00" +"bundle.version: 0.0\n" +"id: 3\n" +"payload.length: 70\n" +"erroniouskey\n" +"\n\n\n\n\n" +"\0" +"1234567890" +"blakdsflks" +"sdkjhasdfs" +"347iuhafgj" +"347aguhfdh" +"iouq5478q7" +"8oq34guily" +; + +std::ostream &operator<<(std::ostream &os, Variant v) { +#ifdef ENABLE_YAML + SerializeYAML(os.rdbuf(), v); +#endif + return os; +} + +int main(int argc, char **argv) { + // Need the -1 there because of the \0 at the end of the string (it looks like an empty bundle at the end...) + shared_ptr input = CreateParserInput(&bundle_str[0], sizeof(bundle_str) - 1); + + Variant v = DeserializeWithPayload(input, SERIALIZE_BUNDLEHDR); + cout << v; + cout << endl << "Payload size: " << v["payload.data"].Size() << endl; + ASSERT(v["id"].AsUnsigned() == 1); + ASSERT(v["payload.data"].Size() == 40); + ASSERT(memcmp("1234567890123456789012345678901234567890", v["payload.data"].AsBlob()->GetPtr(0), 40) == 0); + + v = DeserializeWithPayload(input, SERIALIZE_BUNDLEHDR); + cout << v << endl; + ASSERT(v["id"].AsUnsigned() == 2); + ASSERT(v["payload.data"].Size() == 40); + std::vector buf; + for (int i = 0; i < 10; ++i) { buf.push_back(i); } + ASSERT(memcmp(&buf[0], v["payload.data"].AsBlob()->GetPtr(0), 40) == 0); + + v = DeserializeWithPayload(input, SERIALIZE_BUNDLEHDR); + cout << v << endl; + ASSERT(v["payload.data"].Size() == 70); + string orig = "1234567890" "blakdsflks" "sdkjhasdfs" "347iuhafgj" "347aguhfdh" "iouq5478q7" "8oq34guily"; + std::string p((char *)v["payload.data"].AsBlob()->GetPtr(0), 70); + ASSERT(orig == p); + + // Test that the unsafe zero copy does what it is supposed to do + v = DeserializeBundle(&bundle_str[0], sizeof(bundle_str) - 1); + ASSERT(v["payload.data"].AsBlob()->GetPtr(0) != &bundle_str[strlen(&bundle_str[0])+1]); + v = DeserializeBundle(&bundle_str[0], sizeof(bundle_str) - 1, false); + ASSERT(v["payload.data"].AsBlob()->GetPtr(0) == &bundle_str[strlen(&bundle_str[0])+1]); + return 0; +} diff --git a/src/hos_libvariant/src/test/test_empty.cc b/src/hos_libvariant/src/test/test_empty.cc new file mode 100644 index 00000000..ab8a01e4 --- /dev/null +++ b/src/hos_libvariant/src/test/test_empty.cc @@ -0,0 +1,56 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include +#include +#include +using namespace libvariant; +using namespace std; + +int main(int argc, char **argv) { +#ifdef ENABLE_YAML + Emitter emitter = YAMLEmitter(CreateEmitterOutput(std::cout.rdbuf())); +#else + Emitter emitter = JSONEmitter(CreateEmitterOutput(std::cout.rdbuf()), Variant().Set("pretty", true)); +#endif + emitter.BeginList(); + try { + Variant v = DeserializeJSON(""); + emitter << v; + return 1; + } catch (const std::exception &e) { + emitter << "JSON passed"; + } + + try { + Variant v = DeserializeJSON(" "); + emitter << v; + return 1; + } catch (const std::exception &e) { + emitter << "JSON passed"; + } + emitter.Flush(); + +#ifdef ENABLE_YAML + { + Variant v = DeserializeYAML(""); + emitter << v; + emitter.Flush(); + emitter << "YAML passed"; + } +#endif + +#ifdef ENABLE_XML + try { + Variant v = DeserializeXMLPLIST(""); + emitter << v; + return 1; + } catch (const std::exception &e) { + emitter << "XML passed"; + } +#endif + emitter.EndList(); + return 0; +} diff --git a/src/hos_libvariant/src/test/test_extensions.cc b/src/hos_libvariant/src/test/test_extensions.cc new file mode 100644 index 00000000..6752318b --- /dev/null +++ b/src/hos_libvariant/src/test/test_extensions.cc @@ -0,0 +1,678 @@ +//============================================================================= +//! @file VariantExtensions.cc +//! @author Josh Staley staley@arlut.utexas.edu +//! @brief +//============================================================================= + +//=== Includes ================================================================ + +#include +#include +#include + +using namespace std; +using namespace libvariant; + +//=== Function Declarations =================================================== + +bool TestFlattenPath ( bool verbose = false ); +bool TestExpandPath ( bool verbose = false ); +bool TestRDiff ( bool verbose = false ); +bool TestRUpdate ( bool verbose = false ); +bool TestJSONPointer ( bool verbose = false ); +bool TestJSONDiff ( bool verbose = false ); + +//=== Main ==================================================================== + +//----------------------------------------------------------------------------- +int main ( int argc, char * argv [] ) +//----------------------------------------------------------------------------- +{ + //--- Any are will turn verbosity on --- + bool verbose = false; + if ( argc > 1 ) + verbose = true; + + bool testFlattenPath, testExpandPath, testDiff, testRUpdate, testJSONPointer, testJSONDiff; + + try + { + // FlattenPath() + testFlattenPath = TestFlattenPath( verbose ); + if ( testFlattenPath ) + cout << "FlattenPath - PASSED" << endl; + else + cout << "FlattenPath - FAILED" << endl; + + // ExpandPath() + testExpandPath = TestExpandPath( verbose ); + if ( testExpandPath ) + cout << "ExpandPath - PASSED" << endl; + else + cout << "ExpandPath - FAILED" << endl; + + // RDiff() + testDiff = TestRDiff( verbose ); + if ( testDiff ) + cout << "RDiff - PASSED" << endl; + else + cout << "RDiff - FAILED" << endl; + + // RUpdate() + testRUpdate = TestRUpdate( verbose ); + if ( testRUpdate ) + cout << "RUpdate - PASSED" << endl; + else + cout << "RUpdate - FAILED" << endl; + + testJSONPointer = TestJSONPointer( verbose ); + if ( testJSONPointer ) + cout << "JSONPointer - PASSED" << endl; + else + cout << "JSONPointer - FAILED" << endl; + + testJSONDiff = TestJSONDiff( verbose ); + if ( testJSONDiff ) + cout << "JSONDiff - PASSED" << endl; + else + cout << "JSONDiff - FAILED" << endl; + } + catch ( exception & e ) + { + cerr << "# " << e.what() << endl; + return -1; + } + + cout << "Done" << endl; + + bool passed = testFlattenPath && testExpandPath && testDiff && testRUpdate && testJSONPointer && testJSONDiff; + return passed ? 0 : 1; +} + +//=== Functions =============================================================== + +//----------------------------------------------------------------------------- +bool TestFlattenPath ( bool verbose_ ) +//----------------------------------------------------------------------------- +{ + Variant orig, flat, ideal; + + orig = 10; + ideal = 10; + flat = FlattenPath(orig); + if (flat != ideal) { return false; } + + orig = Variant::MapType; + ideal = Variant::MapType; + + orig["1"]["A"] = Variant::NullType; + orig["1"]["B"] = true; + orig["1"]["C"] = 2; + orig["1"]["D"] = -3; + orig["1"]["E"] = 4.0; + orig["1"]["F"] = "five"; + orig["1"]["G"][0] = Variant::NullType; + orig["1"]["G"][1] = true; + orig["1"]["G"][2] = 2; + orig["1"]["G"][3] = -3; + orig["1"]["G"][4] = 4.0; + orig["1"]["G"][5] = "five"; + orig["2"][0] = Variant::NullType; + orig["2"][1] = true; + orig["2"][2] = 2; + orig["2"][3] = -3; + orig["2"][4] = 4.0; + orig["2"][5] = "five"; + orig["2"][6]["a"] = true; + orig["2"][6]["b"] = "test"; + + ideal["1/A"] = Variant::NullType; + ideal["1/B"] = true; + ideal["1/C"] = 2; + ideal["1/D"] = -3; + ideal["1/E"] = 4.0; + ideal["1/F"] = "five"; + ideal["1/G[0]"] = Variant::NullType; + ideal["1/G[1]"] = true; + ideal["1/G[2]"] = 2; + ideal["1/G[3]"] = -3; + ideal["1/G[4]"] = 4.0; + ideal["1/G[5]"] = "five"; + ideal["2[0]"] = Variant::NullType; + ideal["2[1]"] = true; + ideal["2[2]"] = 2; + ideal["2[3]"] = -3; + ideal["2[4]"] = 4.0; + ideal["2[5]"] = "five"; + ideal["2[6]/a"] = true; + ideal["2[6]/b"] = "test"; + + + try { + flat = FlattenPath( orig, 123); + return false; + } catch (const std::exception &) {} + + try + { + flat = FlattenPath( orig ); + } + catch ( exception & e) + { + cout << "# " << e.what() << endl; + return false; + } + + if ( verbose_ ) + { + cout << "--- flat ---" << endl; + SerializeJSON(cout.rdbuf(), flat, true); + cout << endl; + + cout << "--- ideal ---" << endl; + SerializeJSON(cout.rdbuf(), ideal, true); + cout << endl; + } + + return flat == ideal; +} + +//----------------------------------------------------------------------------- +bool TestExpandPath ( bool verbose_ ) +//----------------------------------------------------------------------------- +{ + // TODO - implement tests + return true; +} + +//----------------------------------------------------------------------------- +bool TestRDiff ( bool verbose_ ) +//----------------------------------------------------------------------------- +{ + Variant base, compare, ideal, diff; + + base["1"]["A"] = Variant::NullType; + base["1"]["B"] = true; + base["1"]["C"] = 2; + base["1"]["D"] = -3; + base["1"]["E"] = 4.0; + base["1"]["F"] = "five"; + base["1"]["G"][0] = Variant::NullType; + base["1"]["G"][1] = true; + base["1"]["G"][2] = 2; + base["1"]["G"][3] = -3; + base["1"]["G"][4] = 4.0; + base["1"]["G"][5] = "five"; + base["2"][0] = Variant::NullType; + base["2"][1] = true; + base["2"][2] = 2; + base["2"][3] = -3; + base["2"][4] = 4.0; + base["2"][5] = "five"; + base["2"][6]["a"] = true; + base["2"][6]["b"] = "test"; + base["3"] = 5; + base["5"] = Variant().Set("a", 1).Set("b", 2); + + compare["1"]["B"] = false; + compare["1"]["C"] = -2; + compare["1"]["D"] = 3.0; + compare["1"]["E"] = "four"; + compare["1"]["F"] = 5.0; + compare["1"]["G"][0] = Variant::NullType; + compare["1"]["G"][1] = true; + compare["1"]["G"][2] = 2; + compare["1"]["G"][3] = -3; + compare["1"]["G"][4] = 4.0; + compare["1"]["G"][5] = "five"; + compare["2"][0] = Variant::NullType; + compare["2"][1] = true; + compare["2"][2] = 2; + compare["2"][3] = -3; + compare["2"][4] = 4.0; + compare["2"][5] = "five"; + compare["2"][6]["a"] = false; + compare["2"][6]["b"] = "test"; + compare["3"] = Variant().Set("a", 1); + compare["4"] = Variant().Set("emptymap", Variant::MapType); + compare["5"] = Variant::MapType; + + ideal["1"]["B"] = false; + ideal["1"]["C"] = -2; + ideal["1"]["D"] = 3.0; + ideal["1"]["E"] = "four"; + ideal["1"]["F"] = 5.0; + ideal["2"][0] = Variant::NullType; + ideal["2"][1] = true; + ideal["2"][2] = 2; + ideal["2"][3] = -3; + ideal["2"][4] = 4.0; + ideal["2"][5] = "five"; + ideal["2"][6]["a"] = false; + ideal["2"][6]["b"] = "test"; + ideal["3"] = Variant().Set("a", 1); + ideal["4"] = Variant().Set("emptymap", Variant::MapType); + // ideal["5"] is removed because it's empty + + try + { + diff = RDiff( base, compare ); + } + catch (exception & e) + { + cout << "# " << e.what() << endl; + return false; + } + + if ( verbose_ ) + { + cout << "--- diff ---" << endl; + SerializeJSON(cout.rdbuf(), diff, true); + cout << endl; + + cout << "--- ideal ---" << endl; + SerializeJSON(cout.rdbuf(), ideal, true); + cout << endl; + } + + return diff == ideal; +} + +//----------------------------------------------------------------------------- +bool TestFlattenPathVariantToStringMap ( bool verbose_ ) +//----------------------------------------------------------------------------- +// TODO - Fix this and add to list of tests in main +//----------------------------------------------------------------------------- +{ + Variant orig; + map flatMap, ideal; + + orig["ONE"]["A"] = true; + orig["ONE"]["B"] = 1; + orig["ONE"]["C"] = -2; + orig["ONE"]["D"] = 3; + orig["ONE"]["E"] = "4"; + orig["ONE"]["F"][0] = false; + orig["ONE"]["F"][1] = 1; + orig["ONE"]["F"][2] = -2; + orig["ONE"]["F"][3] = 3; + orig["ONE"]["F"][4] = "4"; + orig["TWO"][0] = true; + orig["TWO"][1] = 1; + orig["TWO"][2] = -2; + orig["TWO"][3] = 3; + orig["TWO"][4] = "4"; + orig["TWO"][5]["a"] = true; + orig["TWO"][5]["b"] = "test"; + + ideal["ONE.A"] = "true"; + ideal["ONE.B"] = "1"; + ideal["ONE.C"] = "-2"; + ideal["ONE.D"] = "3"; + ideal["ONE.E"] = "4"; + ideal["ONE.F"] = "false,1,-2,3,4"; + ideal["TWO.0"] = "true"; + ideal["TWO.1"] = "1"; + ideal["TWO.2"] = "-2"; + ideal["TWO.3"] = "3"; + ideal["TWO.4"] = "4"; + ideal["TWO.5.a"] = "true"; + ideal["TWO.5.b"] = "test"; + + try + { + flatMap = FlattenPathToStrStrMap( orig ); + } + catch (exception& e) + { + cout << "# " << e.what() << endl; + } + + if( verbose_ ) + { + for( map::iterator i(ideal.begin()), e(ideal.end()); i != e; ++i) + { + cout << flatMap[i->first] << " = " << ideal[i->first] << endl; + } + } + + return ideal == flatMap; +} + +//----------------------------------------------------------------------------- +bool TestRUpdate ( bool verbose ) +//----------------------------------------------------------------------------- +{ + Variant base, update, ideal; + + base["1"]["A"] = Variant::NullType; + base["1"]["B"] = true; + base["1"]["C"] = 2; + base["1"]["D"] = -3; + base["1"]["E"] = 4.0; + base["1"]["F"] = "five"; + base["1"]["G"][0] = Variant::NullType; + base["1"]["G"][1] = true; + base["1"]["G"][2] = 2; + base["1"]["G"][3] = -3; + base["1"]["G"][4] = 4.0; + base["1"]["G"][5] = "five"; + base["2"][0] = Variant::NullType; + base["2"][1] = true; + base["2"][2] = 2; + base["2"][3] = -3; + base["2"][4] = 4.0; + base["2"][5] = "five"; + base["2"][6]["a"] = true; + base["2"][6]["b"] = "test"; + base["3"] = 5; + base["5"] = Variant().Set("a", 1).Set("b", 2); + + update["1"]["B"] = false; + update["1"]["C"] = -2; + update["1"]["D"] = 3.0; + update["1"]["E"] = "four"; + update["1"]["F"] = 5.0; + update["2"][0] = Variant::NullType; + update["2"][1] = true; + update["2"][2] = 2; + update["2"][3] = -3; + update["2"][4] = 4.0; + update["2"][5] = "five"; + update["2"][6]["a"] = false; + update["2"][6]["b"] = "test"; + update["3"] = Variant().Set("a", 1); + update["4"] = Variant().Set("emptymap", Variant::MapType); + + ideal["1"]["A"] = Variant::NullType; + ideal["1"]["B"] = false; + ideal["1"]["C"] = -2; + ideal["1"]["D"] = 3.0; + ideal["1"]["E"] = "four"; + ideal["1"]["F"] = 5.0; + ideal["1"]["G"][0] = Variant::NullType; + ideal["1"]["G"][1] = true; + ideal["1"]["G"][2] = 2; + ideal["1"]["G"][3] = -3; + ideal["1"]["G"][4] = 4.0; + ideal["1"]["G"][5] = "five"; + ideal["2"][0] = Variant::NullType; + ideal["2"][1] = true; + ideal["2"][2] = 2; + ideal["2"][3] = -3; + ideal["2"][4] = 4.0; + ideal["2"][5] = "five"; + ideal["2"][6]["a"] = false; + ideal["2"][6]["b"] = "test"; + ideal["3"] = Variant().Set("a", 1); + ideal["4"] = Variant().Set("emptymap", Variant::MapType); + ideal["5"] = Variant().Set("a", 1).Set("b", 2); + + try { + RUpdate(base, update); + } catch (const exception &e) { + cerr << "# " << e.what() << endl; + return false; + } + if ( verbose ) + { + cout << "--- result ---" << endl; + SerializeJSON(cout.rdbuf(), base, true); + cout << endl; + + cout << "--- ideal ---" << endl; + SerializeJSON(cout.rdbuf(), ideal, true); + cout << endl; + } + return base == ideal; +} + + +bool TestJSONPointer(bool verbose) +{ + Variant test_one = DeserializeJSON("{" + "\"foo\": [\"bar\", \"baz\"]," + "\"\": 0," + "\"a/b\": 1," + "\"c%d\": 2," + "\"e^f\": 3," + "\"g|h\": 4," + "\"i\\\\j\": 5," + "\"k\\\"l\": 6," + "\" \": 7," + "\"m~n\": 8" + "}"); + + std::map pointer_path_map; + pointer_path_map[""] = ""; + pointer_path_map["/foo"] = "foo"; + pointer_path_map["/foo/0"] = "/foo[0]"; + pointer_path_map["/"] = "//"; + pointer_path_map["/a~1b"] = "/a\\/b"; + pointer_path_map["/c%d"] = "c%d"; + pointer_path_map["/e^f"] = "e^f"; + pointer_path_map["/g|h"] = "g|h"; + pointer_path_map["/i\\j"] = "i\\\\j"; + pointer_path_map["/k\"l"] = "k\"l"; + pointer_path_map["/ "] = " "; + pointer_path_map["/m~0n"] = "m~n"; + + bool passed = true; + std::map::iterator i, e; + for (i = pointer_path_map.begin(), e = pointer_path_map.end(); i != e; ++i) { + if (verbose) { + cout << "Testing: \"" << i->first << "\" == \"" << i->second << "\""; + } + if (JSONPointerLookup(i->first, test_one) != test_one.GetPath(i->second)) { + passed = false; + if (verbose) { cout << " FAIL!"; } + } + if (verbose) { cout << endl; } + } + return passed; +} + +bool TestJSONDiff(bool verbose) { + +#define PRINT(x) if (verbose) { std::cout << x << std::endl; } else (void)0 + + Variant base = Variant() + .Set("a", Variant().Set("foo", 1)); + Variant expected = base.Copy(); + expected.SetPath("/a/b", 3); + + Variant diff = Variant() + .Set("op", "add") + .Set("path", "/a/b") + .Set("value", 3); + Variant comp = base.Copy(); + PRINT("Testing add /a/b"); + std::pair result = JSONPatch(comp, diff); + if (!result.first) { PRINT("Patch failed: " << result.second); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + base = Variant() + .Set("q", Variant().Set("bar", 2)); + comp = base.Copy(); + PRINT("Testing add /q/bar invalid"); + if (JSONPatch(comp, diff).first) { PRINT("Patch suceeded"); return false; } + if (comp != base) { PRINT("Expected: " << SerializeJSON(base) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + base = Variant() + .Set("list", Variant().Append(1).Append(2)) + .Set("a", Variant().Set("foo", 1)); + expected = base.Copy() + .Set("list", Variant().Append(1).Append(3).Append(2)); + diff = Variant() + .Set("op", "add") + .Set("path", "/list/1") + .Set("value", 3); + comp = base.Copy(); + PRINT("Testing add list"); + result = JSONPatch(comp, diff); + if (!result.first) { PRINT("Patch failed: " << result.second); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + expected = base.Copy(); + expected.At("list").Append(3); + + diff = Variant() + .Set("op", "add") + .Set("path", "/list/-") + .Set("value", 3); + comp = base.Copy(); + PRINT("Testing append list"); + result = JSONPatch(comp, diff); + if (!result.first) { PRINT("Patch failed: " << result.second); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + expected = base.Copy(); + base.SetPath("a/bar", 4); + diff = Variant() + .Set("op", "remove") + .Set("path", "/a/bar"); + comp = base.Copy(); + PRINT("Testing remove map"); + result = JSONPatch(comp, diff); + if (!result.first) { PRINT("Patch failed: " << result.second); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + diff = Variant() + .Set("op", "remove") + .Set("path", "/a/mar"); + expected = base.Copy(); + comp = base.Copy(); + PRINT("Testing remove not present"); + if (JSONPatch(comp, diff).first) { PRINT("Patch succeeded"); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + diff = Variant() + .Set("op", "remove") + .Set("path", "/c/mar"); + comp = base.Copy(); + PRINT("Testing invalid remove"); + if (JSONPatch(comp, diff).first) { PRINT("Patch succeeded"); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + diff = Variant() + .Set("op", "replace") + .Set("path", "/list/0") + .Set("value", 42); + comp = base.Copy(); + expected = comp.Copy(); + expected.SetPath("/list[0]", 42); + PRINT("Testing replace list element"); + result = JSONPatch(comp, diff); + if (!result.first) { PRINT("Patch failed: " << result.second); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + diff = Variant() + .Set("op", "replace") + .Set("path", "/a/foo") + .Set("value", 42); + comp = base.Copy(); + expected = comp.Copy(); + expected.SetPath("/a/foo", 42); + PRINT("Testing replace map element"); + result = JSONPatch(comp, diff); + if (!result.first) { PRINT("Patch failed: " << result.second); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + diff = Variant() + .Set("op", "replace") + .Set("path", "/a/moo") + .Set("value", 42); + comp = base.Copy(); + expected = comp.Copy(); + PRINT("Testing replace not present"); + if (JSONPatch(comp, diff).first) { PRINT("Patch succeeded"); } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + diff = Variant() + .Set("op", "replace") + .Set("path", "/a/foo") + .Set("value", 42); + comp = base.Copy(); + expected = comp.Copy(); + expected.SetPath("/a/foo", 42); + PRINT("Testing replace map element"); + result = JSONPatch(comp, diff); + if (!result.first) { PRINT("Patch failed: " << result.second); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + diff = Variant() + .Set("op", "move") + .Set("path", "/a/moo") + .Set("from", "/a/foo"); + comp = base.Copy(); + expected = comp.Copy(); + expected.SetPath("/a/moo", expected.GetPath("/a/foo")); + expected.ErasePath("/a/foo"); + PRINT("Testing move map element"); + result = JSONPatch(comp, diff); + if (!result.first) { PRINT("Patch failed: " << result.second); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + diff = Variant() + .Set("op", "copy") + .Set("path", "/a/moo") + .Set("from", "/a/foo"); + comp = base.Copy(); + expected = comp.Copy(); + expected.SetPath("/a/moo", expected.GetPath("/a/foo")); + PRINT("Testing copy map element"); + result = JSONPatch(comp, diff); + if (!result.first) { PRINT("Patch failed: " << result.second); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + PRINT("Diff: " << SerializeJSON(JSONDiff(base, comp))); + + diff = Variant() + .Set("op", "test") + .Set("path", "/a/foo") + .Set("value", 1); + comp = base.Copy(); + expected = comp.Copy(); + PRINT("Testing test map element"); + result = JSONPatch(comp, diff); + if (!result.first) { PRINT("Patch failed: " << result.second); return false; } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + diff = Variant() + .Append( Variant().Set("op", "add").Set("path", "/a/foo").Set("value", 2) ) + .Append( Variant().Set("op", "test").Set("path", "/a/foo").Set("value", 1) ) + ; + comp = base.Copy(); + expected = base.Copy(); + PRINT("Testing test map element, failing patch"); + if (JSONPatch(comp, diff).first) { PRINT("Patch succeeded"); } + if (comp != expected) { PRINT("Expected: " << SerializeJSON(expected) << "\nGot: " << SerializeJSON(comp)); return false; } + + return true; +} + +//============================================================================= diff --git a/src/hos_libvariant/src/test/test_guess.cc b/src/hos_libvariant/src/test/test_guess.cc new file mode 100644 index 00000000..2732569e --- /dev/null +++ b/src/hos_libvariant/src/test/test_guess.cc @@ -0,0 +1,48 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include "TestAssert.h" +#include +#include +#include + +using namespace libvariant; +using namespace std; + +int main(int argc, char **argv) { + Variant v = Variant::MapType; + v["key1"] = 1; + v["blah"] = "murmur"; + v["foo"] = 1.2356; + v["bar"] = 49834; + const char *l[] = { "lisp", "erlang", "haskel", "python", "lua", "c", "c++", "java", "c#", "tcl", 0}; + for (const char **c = &l[0]; *c; c += 1) { v["l"].Append(*c); } + Variant v2; +#ifdef ENABLE_YAML + printf("As yaml\n"); + string yaml = SerializeYAML(v); + printf("%s\n", yaml.c_str()); + v2 = DeserializeGuess(yaml); + ASSERT(v2 == v); + + string empty = " #blah\nnull "; + v2 = DeserializeGuess(empty); + ASSERT(v2 == Variant::NullType); +#endif +#ifdef ENABLE_XML + printf("As xml plist\n"); + string xmlplist = SerializeXMLPLIST(v); + printf("%s\n", xmlplist.c_str()); + v2 = DeserializeGuess(xmlplist); + ASSERT(v2 == v); +#endif + printf("As JSON\n"); + string json = SerializeJSON(v); + printf("%s\n", json.c_str()); + v2 = DeserializeGuess(json); + ASSERT(v2 == v); + + return 0; +} diff --git a/src/hos_libvariant/src/test/test_json_parser.cc b/src/hos_libvariant/src/test/test_json_parser.cc new file mode 100644 index 00000000..fbc300e2 --- /dev/null +++ b/src/hos_libvariant/src/test/test_json_parser.cc @@ -0,0 +1,55 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include +#include +#include "TestCommon.h" + +using namespace libvariant; + +static const char *input_document = "\n\n\n\n{\n" +"\"string\": \"value\",\n" +"\"int10\": 1234,\n" +"\"truth\": true,\n" +"\"float\": [ 0.1, 0.12, 1.0e-2 ],\n" +"\"strnum\": \"12345\"\n," +"\"maxuint64\": 18446744073709551615\n" +"}\n"; + +void ExpectedEvents(Emitter e) { + e.BeginDocument(); + e.BeginMap(); + e.Emit("string"), + e.Emit("value"), + e.Emit("int10"), + e.Emit(intmax_t(1234ll)), + e.Emit("truth"), + e.Emit(true), + e.Emit("float"), + e.BeginList(); + e.Emit(0.1), + e.Emit(.12), + e.Emit(1.0e-2), + e.EndList(); + e.Emit("strnum"), + e.Emit("12345"), + e.Emit("maxuint64"), + e.Emit((uintmax_t)std::numeric_limits::max()), + e.EndMap(); + e.EndDocument(); +} + +int main(int argc, char **argv) { + Parser parser = JSONParser(CreateParserInput(input_document)); + shared_ptr expected(new EventBuffer); + ExpectedEvents(Emitter(expected)); + shared_ptr result(new EventBuffer); + + result->Fill(parser); + + if (!ErrorCheckEventBuffer(expected, result)) { + return 1; + } + return 0; +} diff --git a/src/hos_libvariant/src/test/test_loadall.cc b/src/hos_libvariant/src/test/test_loadall.cc new file mode 100644 index 00000000..dece4aef --- /dev/null +++ b/src/hos_libvariant/src/test/test_loadall.cc @@ -0,0 +1,33 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include +#include + +using namespace libvariant; + +const char test_string[] = "---\n" +"key1: value1\n" +"sublist: [ 1,2 ,3, 4]\n" +"...\n" +"---\n" +"second document\n" +"...\n" +"---\n" +"- a\n- b\n- c\n" +"...\n" +"--- last document\n"; + +int main(int argc, char **argv) { + + LoadAllIterator iter = DeserializeYAMLAll(test_string); + LoadAllIterator end; + while (iter != end) { + Variant v = *iter; + SerializeYAML(stdout, v); + ++iter; + } + return 0; +} diff --git a/src/hos_libvariant/src/test/test_memoryoutput.cc b/src/hos_libvariant/src/test/test_memoryoutput.cc new file mode 100644 index 00000000..a418dda8 --- /dev/null +++ b/src/hos_libvariant/src/test/test_memoryoutput.cc @@ -0,0 +1,29 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include +#include +using namespace libvariant; + +int main(int argc, char **argv) { + Variant v; + v["a key"] = "some value"; + v["another key"] = 1234u; + std::vector buffer(8192); + printf("JSON\n"); + unsigned len = SerializeJSON(&buffer[0], buffer.size(), v); + fwrite(&buffer[0], len, 1, stdout); +#ifdef ENABLE_YAML + printf("\nYAML\n"); + len = SerializeYAML(&buffer[0], buffer.size(), v); + fwrite(&buffer[0], len, 1, stdout); +#endif +#ifdef ENABLE_XML + printf("\nPLIST\n"); + len = SerializeXMLPLIST(&buffer[0], buffer.size(), v); + fwrite(&buffer[0], len, 1, stdout); +#endif + return 0; +} diff --git a/src/hos_libvariant/src/test/test_numerics.cc b/src/hos_libvariant/src/test/test_numerics.cc new file mode 100644 index 00000000..b8735059 --- /dev/null +++ b/src/hos_libvariant/src/test/test_numerics.cc @@ -0,0 +1,327 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "TestAssert.h" +#include +#include +#include +#include +#include +#include +#include +using namespace libvariant; +using namespace std; + +ostream &operator<<(ostream &os, const type_info &t) { + const char *name = t.name(); + int status = -1; + char *dem = 0; + dem = abi::__cxa_demangle(name, 0, 0, &status); + if (status == 0) { + os << dem; + free(dem); + } else { + os << name; + } + return os; +} + +ostream &operator<<(ostream &os, const Variant &v) { + Serialize(os.rdbuf(), v, SERIALIZE_JSON); + return os; +} + +template +void assignCheck(T check) +{ + T a = check; + Variant b = a; + a = variant_cast(b); + if (a != check) { + ostringstream oss; + oss << "Assignment of " << check << " with type " << typeid(T) << " returned " << a; + throw runtime_error(oss.str()); + } + cout << "."; +} + +template +T my_modulus(T r, T l) { return r % l; } +template<> float my_modulus(float r, float l) { return fmod(r, l); } +template<> double my_modulus(double r, double l) { return fmod(r, l); } +template<> long double my_modulus(long double r, long double l) { return fmod(r, l); } + +template +void TestOperations(Variant::Type_t type) { + Variant val = Variant(); + ASSERT(val.IsNull()); + for (T i = 0; i < 1000; i += 10) { + val = Variant(i); + ASSERT(val.As() == i); + ASSERT(val.GetType() == type); + } + + Variant zero = T(0); + Variant one = T(1); + Variant two = T(2); + ASSERT(one + one == two); + ASSERT(one == T(1)); + ASSERT(two == T(2)); + ASSERT(two - one == one); + ASSERT(one == T(1)); + ASSERT(two == T(2)); + ASSERT(one - one == zero); + ASSERT(zero == T(0)); + ASSERT(one == T(1)); + ASSERT(two == T(2)); + ASSERT(zero == zero); + ASSERT(one / two == T(1)/T(2)); + ASSERT(one == T(1)); + ASSERT(two == T(2)); + ASSERT(two * two == T(2) * T(2)); + ASSERT(one == T(1)); + ASSERT(two == T(2)); + ASSERT((two + one) % two == my_modulus((T(2) + T(1)), T(2))); + ASSERT(one == T(1)); + ASSERT(two == T(2)); + // Test doesn't make sense if unsigned + if (!two.IsUnsigned()) { + ASSERT(-two == -T(2)); + } + ASSERT(two == T(2)); + val = two; + ASSERT(one == --val); + ASSERT(one == val); + val = two; + ASSERT(two == val--); + ASSERT(one == val); + val = one; + ASSERT(two == ++val); + ASSERT(two == val); + val = one; + ASSERT(one == val++); + ASSERT(two == val); +} + + +int main(int argc, char **argv) { + assignCheck(true); + assignCheck(false); + // max integer shall be preserved + assignCheck(numeric_limits::max()); + // min integer shall be preserved + assignCheck(numeric_limits::min()); + // max unsigned integer shall be preserved + assignCheck(numeric_limits::max()); + + + // float precision shall be preserved + float ff[] = { __FLT_EPSILON__, __FLT_MIN__, __FLT_MAX__ }; + float f; + for (uint32_t i=0; i(); + if (f!=ff[i]) { + ostringstream oss; + oss << "Float precision test" << v.As() << " != " << ff[i]; + throw runtime_error(oss.str()); + } + } + + // double precision shall be preserved + double dd[] = { __DBL_EPSILON__, __DBL_MIN__, __DBL_MAX__ }; + double d; + for (uint32_t i=0; i() << " != " << dd[i]; + throw runtime_error(oss.str()); + } + } + + // long double precision shall be preserved + long double ldd[] = { __LDBL_EPSILON__, __LDBL_MIN__, __LDBL_MAX__ }; + long double ld; + for (uint32_t i=0; i() << " != " << dd[i]; + throw runtime_error(oss.str()); + } + } + + cout << endl; + cout << "Math tests." << endl; + Variant v = 5; + Variant o = v + 5; + cout << o << endl; + ASSERT(o.AsInt() == 10); + o = v - 2; + cout << o << endl; + ASSERT(o.AsInt() == 3); + o = 7; + o /= 3; + cout << o << endl; + ASSERT(o.AsInt() == 2); + ASSERT(o.IsInt()); + v = 0.1; + cout << o << "/" << v << " = "; + o = o / v; + cout << o << endl; + ASSERT(o.IsFloat()); + o %= 9; + cout << o << endl; + o = 2; + v = o++; + cout << o << " " << v << endl; + ASSERT(v.AsInt() == 2); + ASSERT(o.AsInt() == 3); + --o; + v = o--; + ASSERT(v.AsInt() == 2); + ASSERT(o.AsInt() == 1); + Variant::Type_t extlist[] = { Variant::NullType, Variant::MapType, Variant::ListType, + Variant::StringType, Variant::BlobType, Variant::BoolType }; + + cout << "Verify that numerics throw on non-numeric types." << endl; + for (uint32_t i=0; i(Variant::IntegerType); + TestOperations(Variant::UnsignedType); + TestOperations(Variant::IntegerType); + TestOperations(Variant::UnsignedType); + TestOperations(Variant::IntegerType); + TestOperations(Variant::UnsignedType); + TestOperations(Variant::FloatType); + TestOperations(Variant::FloatType); + TestOperations(Variant::FloatType); + + cout << "Verifying numeric up convert." << endl; + + // T + T == T + { + Variant one(int(1)); + Variant two = one + one; + cout << one.GetType() << " + " << one.GetType() << " = " << two.GetType() << endl; + ASSERT(two == 2); + ASSERT(two.IsInt()); + } + { + Variant one(unsigned(1)); + Variant two = one + one; + cout << one.GetType() << " + " << one.GetType() << " = " << two.GetType() << endl; + ASSERT(two == 2u); + ASSERT(two.IsUnsigned()); + } + { + Variant one(double(1)); + Variant two = one + one; + cout << one.GetType() << " + " << one.GetType() << " = " << two.GetType() << endl; + ASSERT(two == 2.0); + ASSERT(two.IsFloat()); + } + // anything + float == float + { + Variant i_one(int(1)); + Variant f_one(float(1)); + Variant two = i_one + f_one; + cout << i_one.GetType() << " + " << f_one.GetType() << " = " << two.GetType() << endl; + ASSERT(two == 2.0); + ASSERT(two.IsFloat()); + } + { + Variant u_one(unsigned(1)); + Variant f_one(float(1)); + Variant two = u_one + f_one; + cout << u_one.GetType() << " + " << f_one.GetType() << " = " << two.GetType() << endl; + ASSERT(two == 2.0); + ASSERT(two.IsFloat()); + } + + // int + unsigned == unsigned + { + Variant u_one(unsigned(1)); + Variant i_one(int(1)); + Variant two = u_one + i_one; + cout << u_one.GetType() << " + " << i_one.GetType() << " = " << two.GetType() << endl; + ASSERT(two == 2u); + ASSERT(two.IsUnsigned()); + two = i_one + u_one; + cout << i_one.GetType() << " + " << u_one.GetType() << " = " << two.GetType() << endl; + ASSERT(two == 2u); + ASSERT(two.IsUnsigned()); + } + + cout << "PASS" << endl; + return 0; +} diff --git a/src/hos_libvariant/src/test/test_path.cc b/src/hos_libvariant/src/test/test_path.cc new file mode 100644 index 00000000..7893157d --- /dev/null +++ b/src/hos_libvariant/src/test/test_path.cc @@ -0,0 +1,230 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include "TestAssert.h" +#include +#include +#include +#include + +using namespace libvariant; +using namespace std; + +// { +// "key1": [ 1, 2, 3, { "blork": true } ], +// "key2": { +// "subkey": [ "a", { "furple": 1 }, 2 ], +// "sub/key2": true +// } +// } +// +// Then all paths enumerated are: +// Path Value +// "/" Identity +// "/key1" [ 1, 2, 3, { "blork": true } ], +// "/key1[0]" 1 +// "/key1[1]" 2 +// "/key1[2]" 3 +// "/key1[3]" { "blork": true } +// "/key1[3]/blork" true +// "/key2" { "subkey": [ "a", { "furple": 1 }, 2 ], "sub/key2": true } +// "/key2/subkey" [ "a", { "furple": 1 }, 2 ] +// "/key2/subkey[0]" "a" +// "/key2/subkey[1]" { "furple": 1 } +// "/key2/subkey[1]/furple" 1 +// "/key2/subkey[2]" 2 +// "/key2/sub\/key2" true +void TestOne() { + + Variant v = Variant::MapType; + Variant l = Variant::ListType; + l[0] = 1; l[1] = 2; l[2] = 3; + l[3] = Variant::MapType; + l[3]["blork"] = true; + v["key1"] = l; + Variant sub = Variant::MapType; + l = Variant::ListType; + l[0] = "a"; + l[1] = Variant::MapType; + l[1]["furple"] = 1; + l[2] = 2; + sub["subkey"] = l; + sub["sub/key"] = true; + v["key2"] = sub; + + ASSERT(v.GetPath("/") == v); + ASSERT(v.GetPath("") == v); + ASSERT(v.GetPath("/key1") == v["key1"]); + ASSERT(v.GetPath("/key1[0]") == v["key1"][0]); + ASSERT(v.GetPath("/key1[1]") == v["key1"][1]); + ASSERT(v.GetPath("/key1[2]") == v["key1"][2]); + ASSERT(v.GetPath("/key1[3]") == v["key1"][3]); + ASSERT(v.GetPath("/key1[3]/blork") == v["key1"][3]["blork"]); + ASSERT(v.GetPath("/key2") == v["key2"]); + ASSERT(v.GetPath("/key2/subkey") == v["key2"]["subkey"]); + ASSERT(v.GetPath("/key2/subkey[0]") == v["key2"]["subkey"][0]); + ASSERT(v.GetPath("/key2/subkey[1]") == v["key2"]["subkey"][1]); + ASSERT(v.GetPath("/key2/subkey[1]/furple") == v["key2"]["subkey"][1]["furple"]); + ASSERT(v.GetPath("/key2/subkey[2]") == v["key2"]["subkey"][2]); + ASSERT(v.GetPath("/key2/sub\\/key") == v["key2"]["sub/key"]); + + ASSERT(v.GetPath("/key1/") == v["key1"]); + ASSERT(v.GetPath("/key1[0]/") == v["key1"][0]); + ASSERT(v.GetPath("/key1[1]/") == v["key1"][1]); + ASSERT(v.GetPath("/key1[2]/") == v["key1"][2]); + ASSERT(v.GetPath("/key1[3]/") == v["key1"][3]); + ASSERT(v.GetPath("/key1[3]/blork/") == v["key1"][3]["blork"]); + ASSERT(v.GetPath("/key2/") == v["key2"]); + ASSERT(v.GetPath("/key2/subkey/") == v["key2"]["subkey"]); + ASSERT(v.GetPath("/key2/subkey[0]/") == v["key2"]["subkey"][0]); + ASSERT(v.GetPath("/key2/subkey[1]/") == v["key2"]["subkey"][1]); + ASSERT(v.GetPath("/key2/subkey[1]/furple/") == v["key2"]["subkey"][1]["furple"]); + ASSERT(v.GetPath("/key2/subkey[2]/") == v["key2"]["subkey"][2]); + ASSERT(v.GetPath("/key2/sub\\/key/") == v["key2"]["sub/key"]); + + ASSERT(!v.HasPath("/nothing")); + + ASSERT(v.GetPath("key1/") == v["key1"]); + ASSERT(v.GetPath("key1[0]/") == v["key1"][0]); + ASSERT(v.GetPath("key1[1]/") == v["key1"][1]); + ASSERT(v.GetPath("key1[2]/") == v["key1"][2]); + ASSERT(v.GetPath("key1[3]/") == v["key1"][3]); + ASSERT(v.GetPath("key1[3]/blork/") == v["key1"][3]["blork"]); + ASSERT(v.GetPath("key2/") == v["key2"]); + ASSERT(v.GetPath("key2/subkey/") == v["key2"]["subkey"]); + ASSERT(v.GetPath("key2/subkey[0]/") == v["key2"]["subkey"][0]); + ASSERT(v.GetPath("key2/subkey[1]/") == v["key2"]["subkey"][1]); + ASSERT(v.GetPath("key2/subkey[1]/furple/") == v["key2"]["subkey"][1]["furple"]); + ASSERT(v.GetPath("key2/subkey[2]/") == v["key2"]["subkey"][2]); + ASSERT(v.GetPath("key2/sub\\/key/") == v["key2"]["sub/key"]); + + + ASSERT(v.AtPath("key1/") == v["key1"]); + ASSERT(v.AtPath("key1[0]/") == v["key1"][0]); + ASSERT(v.AtPath("key1[1]/") == v["key1"][1]); + ASSERT(v.AtPath("key1[2]/") == v["key1"][2]); + ASSERT(v.AtPath("key1[3]/") == v["key1"][3]); + ASSERT(v.AtPath("key1[3]/blork/") == v["key1"][3]["blork"]); + ASSERT(v.AtPath("key2/") == v["key2"]); + ASSERT(v.AtPath("key2/subkey/") == v["key2"]["subkey"]); + ASSERT(v.AtPath("key2/subkey[0]/") == v["key2"]["subkey"][0]); + ASSERT(v.AtPath("key2/subkey[1]/") == v["key2"]["subkey"][1]); + ASSERT(v.AtPath("key2/subkey[1]/furple/") == v["key2"]["subkey"][1]["furple"]); + ASSERT(v.AtPath("key2/subkey[2]/") == v["key2"]["subkey"][2]); + ASSERT(v.AtPath("key2/sub\\/key/") == v["key2"]["sub/key"]); + + Variant o; + o["foo"] = v; + VariantRef p = o["foo"]; + ASSERT(p.AtPath("key1/") == v["key1"]); + ASSERT(p.GetPath("key1/") == v["key1"]); + ASSERT(!p.HasPath("/nothing")); + + try { + Variant v2; + v2 = v.AtPath("/nothing"); + VariantPrint(v2); + VariantPrint(v); + abort(); + } catch (const std::runtime_error &) {} + + try { + Variant v2 = v.AtPath("/nothing"); + VariantPrint(v2); + VariantPrint(v); + abort(); + } catch (const std::runtime_error &) {} + + try { + Variant v2 = v.AtPath("/key1/nothing"); + VariantPrint(v2); + abort(); + } catch (const std::runtime_error &) {} + + Variant v2; + v2.AtPath("abc/rxy") = 123; + VariantPrint(v2); + + Variant s; + s.SetPath("/key1[0]", 1) + .SetPath("/key1[1]", 2) + .SetPath("/key1[2]", 3) + .SetPath("/key1[3]/blork", true) + .SetPath("/key2/subkey[0]", "a") + .SetPath("/key2/subkey[1]/furple", 1) + .SetPath("/key2/subkey[2]", 2) + .SetPath("/key2/sub\\/key", true); + ASSERT(v == s); + + s.SetPath("/a/b/c", true); + ASSERT(s["a"]["b"]["c"].IsTrue()); + s.SetPath("/a/b/c", false); + ASSERT(s["a"]["b"]["c"].IsFalse()); + s.SetPath("/a/c[0]", 1); + ASSERT(s["a"]["c"][0].AsInt() == 1); + try { + s.SetPath("/a/c/c", 123); + abort(); + } catch (const std::runtime_error &) {} + try { + s.SetPath("/a/b/d[abc]", 1); + abort(); + } catch (const std::runtime_error &) {} +} + +void TestTwo() { + Variant l = Variant::ListType; + l.Append("a"); + l.Append("b"); + l.Append(Variant::MapType); + l[2]["a"] = 1; + l[2]["b"] = Variant::MapType; + l[2]["b"]["c"] = 3u; + ASSERT(l.GetPath("[0]") == "a"); + ASSERT(l.GetPath("[1]") == "b"); + ASSERT(l.GetPath("[2]/a") == 1); + ASSERT(l.GetPath("[2]/b/c") == 3u); + ASSERT(l.GetPath("[2]/b/c").IsUnsigned()); + ASSERT(l.GetPath("[3]/a", 4) == 4); + ASSERT(l.Contains(3) == false); + + Variant s; + s.SetPath("[0]", "a") + .SetPath("[1]", "b") + .SetPath("[2]/a", 1) + .SetPath("[2]/b/c", 3u); + ASSERT(l == s); + s.SetPath("[3]/a/b/c", 123); + ASSERT(s[3]["a"]["b"]["c"].AsInt() == 123); + try { + s.SetPath("/a/b/c", 123); + ASSERT(false); + } catch (const std::runtime_error &) {} + try { + s.GetPath("[a]"); + ASSERT(false); + } catch (const std::runtime_error &) {} +} + +int main(int argc, char **argv) { + TestOne(); + TestTwo(); + + Variant v; + Variant b = v.AtPath("abc/123", Variant::MapType); + ASSERT(b.IsMap()); + b["def"] = 123; + ASSERT(v["abc"].AtPath("123/def") == 123); + ASSERT(v["abc"].At("456", "foo") == "foo"); + ASSERT(v["abc"]["456"] == "foo"); + ASSERT(v["abc"].AtPath("123/rst", "abc") == "abc"); + ASSERT(b["rst"] == "abc"); + b = v.At("list", Variant::ListType); + ASSERT(b.IsList()); + ASSERT(v.AtPath("list[1]", "123") == "123"); + ASSERT(v.AtPath("list[0]/abc", "abc") == "abc"); + VariantPrint(v); + return 0; +} diff --git a/src/hos_libvariant/src/test/test_payload.cc b/src/hos_libvariant/src/test/test_payload.cc new file mode 100644 index 00000000..2a6ca825 --- /dev/null +++ b/src/hos_libvariant/src/test/test_payload.cc @@ -0,0 +1,121 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include "TestAssert.h" +#include +#include +#include +#include +#include + +using namespace libvariant; +using namespace std; + +#define TESTPAYLOAD \ +"1234567890"\ +"1234567890"\ +"1234567890"\ +"1234567890"\ +"1234567890"\ +"1234567890"\ +"1234567890"\ +"1234567890"\ +"1234567890"\ +"1234567890" + +#define TESTPAYLOAD_LEN 100 +#define TESTPAYLOAD_LEN_STR "100" + +const char test_input[] = +"{\"payload\": { \"length\": " TESTPAYLOAD_LEN_STR " }, \"abc\": 123 }" +"\n\n\n\n\n" +"\0" +TESTPAYLOAD + +"{\"payload\": { \"length\": " TESTPAYLOAD_LEN_STR ", \"data\": null }, \"abc\": 123 }" +"\n\n\n\n\n" +"\n\n\n\n\n" +"\0" +TESTPAYLOAD +"{ \"abc\": 123 }" +"\0" +"{ \"payload\": { \"length\": " TESTPAYLOAD_LEN_STR "} }" +"\n\n\n\n\n" +"\n\n\n\n\n" +"\n\n\n\n\n" +"\0" +TESTPAYLOAD +"{ \"payload\": { \"length\": 0 } }" +; + +void TestParse() { + shared_ptr input(CreateParserInput(&test_input[0], sizeof(test_input) - 1)); + const char *datapath = "/payload/data"; + const char *lenpath = "/payload/length"; + Variant params = Variant().Set("length_path", lenpath).Set("data_path", datapath); + + Variant v = DeserializeWithPayload(input, SERIALIZE_JSON, params); + ASSERT(v.GetPath(lenpath) == 100); + ASSERT(v.GetPath("abc") == 123); + BlobPtr b = v.GetPath(datapath).AsBlob(); + ASSERT(b->GetNumBuffers() == 1); + ASSERT(memcmp(b->GetPtr(0), TESTPAYLOAD, TESTPAYLOAD_LEN) == 0); + + v = DeserializeWithPayload(input, SERIALIZE_JSON, params); + ASSERT(v.GetPath(lenpath) == 100); + ASSERT(v.GetPath("abc") == 123); + b = v.GetPath(datapath).AsBlob(); + ASSERT(b->GetNumBuffers() == 1); + ASSERT(memcmp(b->GetPtr(0), TESTPAYLOAD, TESTPAYLOAD_LEN) == 0); + + v = DeserializeWithPayload(input, SERIALIZE_JSON, params); + ASSERT(v.HasPath(datapath) == false); + ASSERT(v.GetPath("abc") == 123); + ASSERT(v.HasPath(lenpath) == false); + + v = DeserializeWithPayload(input, SERIALIZE_JSON, Variant(params.Copy()).Set("data_path", "other/data")); + ASSERT(v.GetPath(lenpath) == 100); + b = v.GetPath("other/data").AsBlob(); + ASSERT(b->GetNumBuffers() == 1); + ASSERT(memcmp(b->GetPtr(0), TESTPAYLOAD, TESTPAYLOAD_LEN) == 0); + + v = DeserializeWithPayload(input, SERIALIZE_JSON, params); + ASSERT(v.GetPath(lenpath) == 0); + ASSERT(v.HasPath(datapath) == false); +} + +void TestEmit() { + + Variant params; + params.Set("length_path", "payload/length").Set("data_path", "other/data"); + Variant v; + BlobPtr b = Blob::CreateCopy(TESTPAYLOAD, TESTPAYLOAD_LEN); + v.SetPath("other/data", b); + SerializeWithPayload(cout.rdbuf(), v, SERIALIZE_JSON, params); + cout << "\n--------------------------------------------------------------------------------\n"; + params.Set("ignore_payload", true); + SerializeWithPayload(cout.rdbuf(), v, SERIALIZE_JSON, params); + cout << "\n--------------------------------------------------------------------------------\n"; + params.Set("ignore_payload", false); + params.Set("payload_length", 5); + SerializeWithPayload(cout.rdbuf(), v, SERIALIZE_JSON, params); + cout << "\n--------------------------------------------------------------------------------\n"; + params.Set("ignore_payload", true); + params.Set("payload_length", 5); + SerializeWithPayload(cout.rdbuf(), v, SERIALIZE_JSON, params); + cout << "\n\n"; +} + +int main(int argc, char **argv) { +try{ + TestParse(); + TestEmit(); + cout << endl; +} catch (const std::exception &e) { + cerr << e.what() << endl; + exit(1); +} + return 0; +} diff --git a/src/hos_libvariant/src/test/test_roundtrip.cc b/src/hos_libvariant/src/test/test_roundtrip.cc new file mode 100644 index 00000000..cc6667d2 --- /dev/null +++ b/src/hos_libvariant/src/test/test_roundtrip.cc @@ -0,0 +1,90 @@ +#include +#include +#include +using namespace libvariant; +using namespace std; + +#include + +int DoTest(SerializeType stype) { + Variant v1; + v1["bool_true"] = true; + v1["bool_false"] = false; + v1["long_double_max"] = numeric_limits::max(); + v1["long_double_min"] = numeric_limits::min(); + v1["double_max"] = numeric_limits::max(); + v1["double_min"] = numeric_limits::min(); + v1["int_max"] = numeric_limits::max(); + v1["int_min"] = numeric_limits::min(); + v1["uint_max"] = numeric_limits::max(); + v1["uint_min"] = numeric_limits::min(); + + string s = Serialize(v1, stype); + Variant v2 = Deserialize(s, stype); + + int result = 0; + + if (variant_cast(v2["bool_true"]) != true) { + cerr << "bool true failed" << endl; + result++; + } + if (variant_cast(v2["bool_false"]) != false) { + cerr << "bool false failed" << endl; + result++; + } + +#if 0 + // long double doesn't roundtrip! + + if (variant_cast(v2["long_double_max"]) != numeric_limits::max()) { + cerr << "long double max failed" << endl; + result++; + } + if (variant_cast(v2["long_double_min"]) != numeric_limits::min()) { + cerr << "long double min failed" << endl; + result++; + } +#endif + + if (variant_cast(v2["double_max"]) != numeric_limits::max()) { + cerr << "double max failed" << endl; + result++; + } + if (variant_cast(v2["double_min"]) != numeric_limits::min()) { + cerr << "double min failed" << endl; + result++; + } + + if (variant_cast(v2["int_max"]) != numeric_limits::max()) { + cerr << "intmax_t max failed" << endl; + result++; + } + if (variant_cast(v2["int_min"]) != numeric_limits::min()) { + cerr << "intmax_t min failed" << endl; + result++; + } + + if (variant_cast(v2["uint_max"]) != numeric_limits::max()) { + cerr << "uintmax_t max failed" << endl; + result++; + } + if (variant_cast(v2["uint_min"]) != numeric_limits::min()) { + cerr << "uintmax_t min failed" << endl; + result++; + } + + return result; +} + +int main(int argv, char** argc) { + int result = 0; + result += DoTest(SERIALIZE_JSON); +#if ENABLE_YAML + result += DoTest(SERIALIZE_YAML); +#endif +#if ENABLE_XML + result += DoTest(SERIALIZE_XMLPLIST); +#endif + result += DoTest(SERIALIZE_BUNDLEHDR); + return result; +} diff --git a/src/hos_libvariant/src/test/test_schema.cc b/src/hos_libvariant/src/test/test_schema.cc new file mode 100644 index 00000000..8285e452 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema.cc @@ -0,0 +1,410 @@ +/** \file + * \author John Bridgman + * \brief + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace libvariant; +using namespace std; + +int TestNormalise() { + int ret = 0; + cout << "Test Normalise\n"; + + cout << "normalise - untouched immediate $ref "; + Variant schema; + schema["items"]["$ref"] = "#"; + SchemaLoader::NormSchema(schema, ""); + if (schema["items"]["$ref"] == "#") { + cout << "PASS" << endl; + } else { + cout << "!!! FAIL !!!" << endl; + ++ret; + abort(); + } + + cout << "normalise - id as base "; + schema = Variant::NullType; + schema["id"] = "baseUrl"; + schema["items"]["$ref"] = "#"; + SchemaLoader::NormSchema(schema, ""); + if (schema["items"]["$ref"] == "baseUrl#") { + cout << "PASS" << endl; + } else { + cout << "!!! FAIL !!!" << endl; + ++ret; + abort(); + } + + cout << "normalise - id relative to parent "; + schema = Variant::NullType; + schema["id"] = "http://example.com/schema"; + schema["items"]["id"] = "otherSchema"; + schema["items"]["items"]["$ref"] = "#"; + SchemaLoader::NormSchema(schema, ""); + if (schema["items"]["id"] == "http://example.com/otherSchema" + && schema["items"]["items"]["$ref"] == "http://example.com/otherSchema#" + ) { + cout << "PASS" << endl; + } else { + cout << "!!! FAIL !!!" << endl; + ++ret; + abort(); + } + + cout << "normalise - do not touch contents of \"enum\" "; + + schema = Variant::NullType; + schema["id"] = "http://example.com/schema"; + schema["items"]["id"] = "otherSchema"; + schema["items"]["enum"][0]["$ref"] = "#"; + SchemaLoader::NormSchema(schema, ""); + + if (schema["items"]["enum"][0]["$ref"] == "#") { + cout << "PASS" << endl; + } else { + cout << "!!! FAIL !!!" << endl; + ++ret; + abort(); + } + + cout << "Only normalise id and $ref if they are strings "; + schema = Variant::NullType; + schema["properties"]["id"]["type"] = "integer"; + schema["properties"]["$ref"]["type"] = "integer"; + Variant data; + data["id"] = "test"; + data["$ref"] = "test"; + SchemaLoader::NormSchema(schema, ""); + if (!SchemaValidate(schema, data).Error()) { + cout << " !!! FAIL !!! " << endl; + ++ret; + abort(); + } else { + cout << " PASS " << endl; + } + + return ret; +} + +bool TestMissingHandler(SchemaLoader *sb, const std::string &uri, SchemaLoader::LoaderError &error, void *m) { + vector &missing = *(vector*)(m); + cout << endl; + cout << "Validator missing schema: \"" << uri << "\"" << endl; + missing.push_back(uri); + return true; +} + +int TestFile(const std::string &testfile) { + int ret = 0; + cout << "Processing file " << testfile << endl; + cout << "-------------------------------------\n"; + cout.flush(); + Variant tests = DeserializeJSONFile(testfile.c_str()); + for (Variant::ListIterator i(tests.ListBegin()), e(tests.ListEnd()); i != e; ++i) { + std::string name = i->At("name").AsString(); + Variant data = i->At("data"); + Variant schema = i->At("schema"); + bool fail = i->Get("fail", false).AsBool(); + bool exception = i->Get("exception", false).AsBool(); + cout << "Running " << (fail ? "negative " : "") << "test \"" << name << "\" "; + cout.flush(); + SchemaLoader loader; + std::vector missing; + loader.SetMissingHandler(&TestMissingHandler, &missing); + SchemaResult result; + try { + result = SchemaValidate(schema, data, &loader); + } catch (const std::exception &e) { + if (exception) { + cout << " PASS with exception\n"; + cout << e.what() << endl; + continue; + } + cout << "\n!!!!FAIL!!!!\n"; + cout << e.what() << endl; + ++ret; + abort(); + } + if (exception) { + cout << "\n!!!!FAIL!!!!\n"; + cout << "Excepted SchemaValidate to throw!\n"; + ++ret; + abort(); + } + + for (unsigned k = 0; k < missing.size(); ++k) { + bool found = false; + Variant m = i->Get("missing", Variant::ListType); + for (Variant::ListIterator j(m.ListBegin()), e(m.ListEnd()); j != e && !found; ++j) { + if (*j == missing[k]) { + found = true; + } + } + if (!found) { + cout << "\n!!!!FAIL!!!!\n"; + cout << "Unexpected missing schema: \"" << missing[k] << "\"\n"; + ++ret; + abort(); + } + } + + if (fail && !result.Error()) { + cout << "\n!!!!!FAIL!!!!!\n"; + cout << result; + ++ret; + abort(); + } else if (!fail && result.Error()) { + cout << "\n!!!!!FAIL!!!!!\n"; + cout << result; + ++ret; + abort(); + } else { + cout << " PASS"; + if (result.Error()) { + cout << endl << result; + } + } + cout << endl; + } + cout << endl; + return ret; +} + +int TestDirectory(const std::string &dirname) { + int ret = 0; + DIR *dir = opendir(dirname.c_str()); + if (!dir) { return 1; } + cout << "\nProcessing " << dirname << " for tests." << endl; + cout << "=========================================\n"; + dirent *ep; + while ((ep = readdir(dir))) { + string fname = ep->d_name; + if (fname == ".") continue; + if (fname == "..") continue; + if (ep->d_type == DT_REG) { + if (fname.find(".") < fname.size() && fname.substr(fname.rfind(".")) == ".test") { + ret += TestFile(dirname + "/" + fname); + } + } + if (ep->d_type == DT_DIR) { + ret += TestDirectory(dirname + "/" + fname); + } + } + cout << endl; + closedir(dir); + return ret; +} + +int TestSchemaLoader() { + cout << "Test advanced schema loader\n"; + int ret = 0; + Variant data = DeserializeGuessFile(TEST_SCHEMA_DATA "/simple-test.json"); + Variant faildata = DeserializeGuessFile(TEST_SCHEMA_DATA "/simple-test-fail.json"); + try { + AdvSchemaLoader loader; + SchemaResult result = SchemaValidate("simple-test-schema.json", data, &loader); + cout << "Look up of schema without path succeeded."; + abort(); + ++ret; + } catch (const std::exception &e) {} + cout << endl; + + { + AdvSchemaLoader loader; + cout << "Testing absolute path.\n"; + SchemaResult result = SchemaValidate(TEST_SCHEMA_DATA "/simple-test-schema.json", data, &loader); + SchemaResult failresult = SchemaValidate(TEST_SCHEMA_DATA "/simple-test-schema.json", faildata, &loader); + if (result.Error()) { + cout << result << endl; + ++ret; + } + if (!failresult.Error()) { + cout << "!!! Negative test failed\n"; + ++ret; + } else { + //cout << failresult << endl; + } + } + cout << endl; + + { + AdvSchemaLoader loader; + cout << "Testing advanced schema loader, loading a file through the path.\n"; + loader.AddPath(TEST_SCHEMA_DATA); + SchemaResult result = SchemaValidate("simple-test-schema.json", data, &loader); + SchemaResult failresult = SchemaValidate("simple-test-schema.json", faildata, &loader); + if (result.Error()) { + cout << result << endl; + ++ret; + } + if (!failresult.Error()) { + cout << "!!! Negative test failed\n"; + ++ret; + } else { + //cout << failresult << endl; + } + } + cout << endl; + + { + AdvSchemaLoader loader; + cout << "Testing file:// absolute path\n"; + SchemaResult result = SchemaValidate("file://" TEST_SCHEMA_DATA "/simple-test-schema.json", data, &loader); + SchemaResult failresult = SchemaValidate("file://" TEST_SCHEMA_DATA "/simple-test-schema.json", faildata, &loader); + if (result.Error()) { + cout << result << endl; + ++ret; + } + if (!failresult.Error()) { + cout << "!!! Negative test failed\n"; + ++ret; + abort(); + } else { + //cout << failresult << endl; + } + } + cout << endl; + + { + AdvSchemaLoader loader; + cout << "Testing file:// relative path\n"; + loader.AddPath(TEST_SCHEMA_DATA); + SchemaResult result = SchemaValidate("file://" "simple-test-schema.json", data, &loader); + SchemaResult failresult = SchemaValidate("file://" "simple-test-schema.json", faildata, &loader); + if (result.Error()) { + cout << result << endl; + ++ret; + } + if (!failresult.Error()) { + cout << "!!! Negative test failed\n"; + ++ret; + abort(); + } else { + //cout << failresult << endl; + } + } + cout << endl; + + try { + AdvSchemaLoader loader; + loader.AddPath(TEST_SCHEMA_DATA); + cout << "Test that missing schema works right...\n"; + SchemaResult result = SchemaValidate("abc-no-such-schema", data, &loader); + cout << "Failed!\n"; + ++ret; + } catch (const std::exception &e) { + cout << "Error:\n" << e.what() << endl; + } + + return ret; +} + +int TestSchemaDefaults() { + cerr << "Testing schema defaults\n"; + int ret = 0; + Variant schema; + schema.SetPath("properties/foo/default", 123) + .SetPath("properties/bar/default", "abc") + .SetPath("default/foo", 456) + .SetPath("default/bar", "def") + .SetPath("properties/list/items/default", false) + .SetPath("definitions/zero/default", 0) + .SetPath("properties/zero/$ref", "#/definitions/zero"); + + + Variant data; + AddSchemaDefaults(schema, data); + if ((data["foo"] != 456 || data["bar"] != "def") && !data.Contains("list")) { + cerr << "Defaults test failed:\n" + "Got: \n"; + Serialize(cerr.rdbuf(), data, SERIALIZE_JSON); + ++ret; + } + data.Erase("foo"); + AddSchemaDefaults(schema, data); + if (data["foo"] != 123 || !data["list"][0].IsFalse() || data["zero"] != 0) { + cerr << "Defaults test failed:\n" + "Got: \n"; + Serialize(cerr.rdbuf(), data, SERIALIZE_JSON); + ++ret; + } + schema.SetPath("properties/alltest/allOf[0]/default", "test"); + AddSchemaDefaults(schema, data); + if (data["alltest"] != "test") { + cerr << "Defaults test failed:\n" + "Got: \n"; + Serialize(cerr.rdbuf(), data, SERIALIZE_JSON); + ++ret; + } + return ret; +} + +int main(int argc, char **argv) { + while (true) { + int c = getopt(argc, argv, "f:"); + if (c == -1) { break; } + switch (c) { + case 'f': + return TestFile(optarg); + default: + break; + } + + } + int i = 0; + int ret = 0; + cout << "Testing SchemaLoader::ResolveURI "; + std::string ruri_file = TEST_SCHEMA_DATA; + ruri_file += "/test_resolveuri.json"; + Variant v = DeserializeJSONFile(ruri_file.c_str()); + while (true) { + std::string ref, base, expected; + ref = v[3*i].AsString(); + base = v[3*i+1].AsString(); + expected = v[3*i+2].AsString(); + if (ref == "" && base == "" && expected == "") { break; } + string res = SchemaLoader::ResolveURI(base, ref); + if (res != expected) { + cout << "\nResolveURI test " << i << " failed\n" + << "ref: \"" << ref << "\"\n" + << "base: \"" << base << "\"\n" + << "result: \"" << res << "\"\n" + << "expected: \"" << expected << "\"" + << endl; + ++ret; + abort(); + } else if (i%5 == 0) { + cout << "."; + cout.flush(); + } + ++i; + } + cout << endl; + + ret += TestNormalise(); + + cout << "Performing schema validation tests" << endl; + ret += TestDirectory(TEST_SCHEMA_DATA); + + ret += TestSchemaLoader(); + + ret += TestSchemaDefaults(); + + cerr << "================================================================================\n"; + if (ret > 0) { + cerr << "FAIL!\n"; + } else { + cerr << "All tests PASS\n"; + } + return ret == 0 ? 0 : 1; +} diff --git a/src/hos_libvariant/src/test/test_schema_data/invalid-schema.test b/src/hos_libvariant/src/test/test_schema_data/invalid-schema.test new file mode 100644 index 00000000..ad8b3443 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/invalid-schema.test @@ -0,0 +1,168 @@ +[ + { + "name": "Invalid anyOf", + "schema": { + "anyOf": { "type": "integer" } + }, + "data": 1234, + "fail": true + }, + { + "name": "Invalid allOf", + "schema": { + "allOf": { "type": "integer" } + }, + "data": 1234, + "fail": true + }, + { + "name": "Invalid oneOf", + "schema": { + "oneOf": { "type": "integer" } + }, + "data": 1234, + "fail": true + }, + { + "name": "Invalid dependencies 1", + "schema": { + "dependencies": 123 + }, + "data": { "a": 1, "b": 2 }, + "fail": true + }, + { + "name": "Invalid dependencies 1", + "schema": { + "dependencies": { "a": 123 } + }, + "data": { "a": 1, "b": 2 }, + "fail": true + }, + { + "name": "Invalid pattern property regex", + "schema": { + "patternProperties": { + "[": {} + } + }, + "data": { + "abc": 123 + }, + "fail": true + }, + { + "name": "Invalid pattern property not an object", + "schema": { + "patternProperties": 123 + }, + "data": { + "abc": 123 + }, + "fail": true + }, + { + "name": "Inavlid properties, not an object", + "schema": { + "properties": 123 + }, + "data": { "abc": 123 }, + "fail": true + }, + { + "name": "uniqueItems not a bool", + "schema": { + "uniqueItems": 123 + }, + "data": [ 1,2,3 ], + "fail": true + }, + { + "name": "minItems not a number", + "schema": { + "minItems": "abc" + }, + "data": [ 1,2,3 ], + "fail": true + }, + { + "name": "maxItems not a number", + "schema": { + "maxItems": "abc" + }, + "data": [ 1,2,3 ], + "fail": true + }, + { + "name": "string pattern not a string", + "schema": { + "pattern": 123 + }, + "data": "abc", + "fail": true + }, + { + "name": "string pattern invalid regex", + "schema": { + "pattern": "[" + }, + "data": "abc", + "fail": true + }, + { + "name": "required keys not a list", + "schema": { + "required": "abc" + }, + "data": { "a": 1, "b": 2 }, + "fail": true + }, + { + "name": "minProperties not a number", + "schema": { + "minProperties": "abc" + }, + "data": { "a": 1, "b": 2 }, + "fail": true + }, + { + "name": "maxProperties not a number", + "schema": { + "maxProperties": "abc" + }, + "data": { "a": 1, "b": 2 }, + "fail": true + }, + { + "name": "minLength not a number", + "schema": { + "minLength": "abc" + }, + "data": "abc", + "fail": true + }, + { + "name": "maxLength not a number", + "schema": { + "maxLength": "abc" + }, + "data": "abc", + "fail": true + }, + { + "name": "minimum not a number", + "schema": { + "minimum": "abc" + }, + "data": 123, + "fail": true + }, + { + "name": "maximum not a number", + "schema": { + "maximum": "abc" + }, + "data": 123, + "fail": true + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/invalid_path.test b/src/hos_libvariant/src/test/test_schema_data/invalid_path.test new file mode 100644 index 00000000..72464395 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/invalid_path.test @@ -0,0 +1,34 @@ +[ + { + "name": "Invalid ref paths - malformed", + "schema": { + "definitions": { + "foo": { + "type": "string" + } + }, + "type": "object", + "properties": { + "foo": { "$ref": "#definitions/foo" } + } + }, + "data": { "foo": "abc" }, + "exception": true + }, + { + "name": "Invalid ref paths - path does not match", + "schema": { + "definitions": { + "foo": { + "type": "string" + } + }, + "type": "object", + "properties": { + "foo": { "$ref": "#/definitions/bar/mar" } + } + }, + "data": { "foo": 123 }, + "exception": true + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/Makefile b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/Makefile new file mode 100644 index 00000000..01e90387 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/Makefile @@ -0,0 +1,7 @@ + +TARGETS := $(patsubst %.json,%.test,$(wildcard *.json)) + +all: $(TARGETS) + +%.test: %.json + python convert.py < $< > $@ diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/README b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/README new file mode 100644 index 00000000..a14cc8fe --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/README @@ -0,0 +1,26 @@ + +The tests in this folder where copied directly from jsonschema by Julian +https://github.com/Julian/jsonschema +https://python-jsonschema.readthedocs.org/ + +Copyright (c) 2013 Julian Berman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalItems.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalItems.json new file mode 100644 index 00000000..521745c8 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalItems.json @@ -0,0 +1,82 @@ +[ + { + "description": "additionalItems as schema", + "schema": { + "items": [{}], + "additionalItems": {"type": "integer"} + }, + "tests": [ + { + "description": "additional items match schema", + "data": [ null, 2, 3, 4 ], + "valid": true + }, + { + "description": "additional items do not match schema", + "data": [ null, 2, 3, "foo" ], + "valid": false + } + ] + }, + { + "description": "items is schema, no additionalItems", + "schema": { + "items": {}, + "additionalItems": false + }, + "tests": [ + { + "description": "all items match schema", + "data": [ 1, 2, 3, 4, 5 ], + "valid": true + } + ] + }, + { + "description": "array of items with no additionalItems", + "schema": { + "items": [{}, {}, {}], + "additionalItems": false + }, + "tests": [ + { + "description": "no additional items present", + "data": [ 1, 2, 3 ], + "valid": true + }, + { + "description": "additional items are not permitted", + "data": [ 1, 2, 3, 4 ], + "valid": false + } + ] + }, + { + "description": "additionalItems as false without items", + "schema": {"additionalItems": false}, + "tests": [ + { + "description": + "items defaults to empty schema so everything is valid", + "data": [ 1, 2, 3, 4, 5 ], + "valid": true + }, + { + "description": "ignores non-arrays", + "data": {"foo" : "bar"}, + "valid": true + } + ] + }, + { + "description": "additionalItems are allowed by default", + "schema": {"items": [{"type": "integer"}]}, + "tests": [ + { + "description": "only the first item is validated", + "data": [1, "foo", false], + "valid": true + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalItems.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalItems.test new file mode 100644 index 00000000..abe443c8 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalItems.test @@ -0,0 +1 @@ +[{"fail": false, "data": [null, 2, 3, 4], "name": "additionalItems as schema -- additional items match schema", "schema": {"items": [{}], "additionalItems": {"type": "integer"}}}, {"fail": true, "data": [null, 2, 3, "foo"], "name": "additionalItems as schema -- additional items do not match schema", "schema": {"items": [{}], "additionalItems": {"type": "integer"}}}, {"fail": false, "data": [1, 2, 3, 4, 5], "name": "items is schema, no additionalItems -- all items match schema", "schema": {"items": {}, "additionalItems": false}}, {"fail": false, "data": [1, 2, 3], "name": "array of items with no additionalItems -- no additional items present", "schema": {"items": [{}, {}, {}], "additionalItems": false}}, {"fail": true, "data": [1, 2, 3, 4], "name": "array of items with no additionalItems -- additional items are not permitted", "schema": {"items": [{}, {}, {}], "additionalItems": false}}, {"fail": false, "data": [1, 2, 3, 4, 5], "name": "additionalItems as false without items -- items defaults to empty schema so everything is valid", "schema": {"additionalItems": false}}, {"fail": false, "data": {"foo": "bar"}, "name": "additionalItems as false without items -- ignores non-arrays", "schema": {"additionalItems": false}}, {"fail": false, "data": [1, "foo", false], "name": "additionalItems are allowed by default -- only the first item is validated", "schema": {"items": [{"type": "integer"}]}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalProperties.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalProperties.json new file mode 100644 index 00000000..c997f75d --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalProperties.json @@ -0,0 +1,63 @@ +[ + { + "description": + "additionalProperties being false does not allow other properties", + "schema": { + "properties": {"foo": {}, "bar": {}}, + "additionalProperties": false + }, + "tests": [ + { + "description": "no additional properties is valid", + "data": {"foo": 1}, + "valid": true + }, + { + "description": "an additional property is invalid", + "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, + "valid": false + }, + { + "description": "ignores non-objects", + "data": [1, 2, 3], + "valid": true + } + ] + }, + { + "description": + "additionalProperties allows a schema which should validate", + "schema": { + "properties": {"foo": {}, "bar": {}}, + "additionalProperties": {"type": "boolean"} + }, + "tests": [ + { + "description": "no additional properties is valid", + "data": {"foo": 1}, + "valid": true + }, + { + "description": "an additional valid property is valid", + "data": {"foo" : 1, "bar" : 2, "quux" : true}, + "valid": true + }, + { + "description": "an additional invalid property is invalid", + "data": {"foo" : 1, "bar" : 2, "quux" : 12}, + "valid": false + } + ] + }, + { + "description": "additionalProperties are allowed by default", + "schema": {"properties": {"foo": {}, "bar": {}}}, + "tests": [ + { + "description": "additional properties are allowed", + "data": {"foo": 1, "bar": 2, "quux": true}, + "valid": true + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalProperties.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalProperties.test new file mode 100644 index 00000000..016cc774 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/additionalProperties.test @@ -0,0 +1 @@ +[{"fail": false, "data": {"foo": 1}, "name": "additionalProperties being false does not allow other properties -- no additional properties is valid", "schema": {"additionalProperties": false, "properties": {"foo": {}, "bar": {}}}}, {"fail": true, "data": {"quux": "boom", "foo": 1, "bar": 2}, "name": "additionalProperties being false does not allow other properties -- an additional property is invalid", "schema": {"additionalProperties": false, "properties": {"foo": {}, "bar": {}}}}, {"fail": false, "data": [1, 2, 3], "name": "additionalProperties being false does not allow other properties -- ignores non-objects", "schema": {"additionalProperties": false, "properties": {"foo": {}, "bar": {}}}}, {"fail": false, "data": {"foo": 1}, "name": "additionalProperties allows a schema which should validate -- no additional properties is valid", "schema": {"additionalProperties": {"type": "boolean"}, "properties": {"foo": {}, "bar": {}}}}, {"fail": false, "data": {"quux": true, "foo": 1, "bar": 2}, "name": "additionalProperties allows a schema which should validate -- an additional valid property is valid", "schema": {"additionalProperties": {"type": "boolean"}, "properties": {"foo": {}, "bar": {}}}}, {"fail": true, "data": {"quux": 12, "foo": 1, "bar": 2}, "name": "additionalProperties allows a schema which should validate -- an additional invalid property is invalid", "schema": {"additionalProperties": {"type": "boolean"}, "properties": {"foo": {}, "bar": {}}}}, {"fail": false, "data": {"quux": true, "foo": 1, "bar": 2}, "name": "additionalProperties are allowed by default -- additional properties are allowed", "schema": {"properties": {"foo": {}, "bar": {}}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/allOf.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/allOf.json new file mode 100644 index 00000000..bbb5f89e --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/allOf.json @@ -0,0 +1,112 @@ +[ + { + "description": "allOf", + "schema": { + "allOf": [ + { + "properties": { + "bar": {"type": "integer"} + }, + "required": ["bar"] + }, + { + "properties": { + "foo": {"type": "string"} + }, + "required": ["foo"] + } + ] + }, + "tests": [ + { + "description": "allOf", + "data": {"foo": "baz", "bar": 2}, + "valid": true + }, + { + "description": "mismatch second", + "data": {"foo": "baz"}, + "valid": false + }, + { + "description": "mismatch first", + "data": {"bar": 2}, + "valid": false + }, + { + "description": "wrong type", + "data": {"foo": "baz", "bar": "quux"}, + "valid": false + } + ] + }, + { + "description": "allOf with base schema", + "schema": { + "properties": {"bar": {"type": "integer"}}, + "required": ["bar"], + "allOf" : [ + { + "properties": { + "foo": {"type": "string"} + }, + "required": ["foo"] + }, + { + "properties": { + "baz": {"type": "null"} + }, + "required": ["baz"] + } + ] + }, + "tests": [ + { + "description": "valid", + "data": {"foo": "quux", "bar": 2, "baz": null}, + "valid": true + }, + { + "description": "mismatch base schema", + "data": {"foo": "quux", "baz": null}, + "valid": false + }, + { + "description": "mismatch first allOf", + "data": {"bar": 2, "baz": null}, + "valid": false + }, + { + "description": "mismatch second allOf", + "data": {"foo": "quux", "bar": 2}, + "valid": false + }, + { + "description": "mismatch both", + "data": {"bar": 2}, + "valid": false + } + ] + }, + { + "description": "allOf simple types", + "schema": { + "allOf": [ + {"maximum": 30}, + {"minimum": 20} + ] + }, + "tests": [ + { + "description": "valid", + "data": 25, + "valid": true + }, + { + "description": "mismatch one", + "data": 35, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/allOf.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/allOf.test new file mode 100644 index 00000000..c03b0ddb --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/allOf.test @@ -0,0 +1 @@ +[{"fail": false, "data": {"foo": "baz", "bar": 2}, "name": "allOf -- allOf", "schema": {"allOf": [{"required": ["bar"], "properties": {"bar": {"type": "integer"}}}, {"required": ["foo"], "properties": {"foo": {"type": "string"}}}]}}, {"fail": true, "data": {"foo": "baz"}, "name": "allOf -- mismatch second", "schema": {"allOf": [{"required": ["bar"], "properties": {"bar": {"type": "integer"}}}, {"required": ["foo"], "properties": {"foo": {"type": "string"}}}]}}, {"fail": true, "data": {"bar": 2}, "name": "allOf -- mismatch first", "schema": {"allOf": [{"required": ["bar"], "properties": {"bar": {"type": "integer"}}}, {"required": ["foo"], "properties": {"foo": {"type": "string"}}}]}}, {"fail": true, "data": {"foo": "baz", "bar": "quux"}, "name": "allOf -- wrong type", "schema": {"allOf": [{"required": ["bar"], "properties": {"bar": {"type": "integer"}}}, {"required": ["foo"], "properties": {"foo": {"type": "string"}}}]}}, {"fail": false, "data": {"baz": null, "foo": "quux", "bar": 2}, "name": "allOf with base schema -- valid", "schema": {"required": ["bar"], "properties": {"bar": {"type": "integer"}}, "allOf": [{"required": ["foo"], "properties": {"foo": {"type": "string"}}}, {"required": ["baz"], "properties": {"baz": {"type": "null"}}}]}}, {"fail": true, "data": {"foo": "quux", "baz": null}, "name": "allOf with base schema -- mismatch base schema", "schema": {"required": ["bar"], "properties": {"bar": {"type": "integer"}}, "allOf": [{"required": ["foo"], "properties": {"foo": {"type": "string"}}}, {"required": ["baz"], "properties": {"baz": {"type": "null"}}}]}}, {"fail": true, "data": {"baz": null, "bar": 2}, "name": "allOf with base schema -- mismatch first allOf", "schema": {"required": ["bar"], "properties": {"bar": {"type": "integer"}}, "allOf": [{"required": ["foo"], "properties": {"foo": {"type": "string"}}}, {"required": ["baz"], "properties": {"baz": {"type": "null"}}}]}}, {"fail": true, "data": {"foo": "quux", "bar": 2}, "name": "allOf with base schema -- mismatch second allOf", "schema": {"required": ["bar"], "properties": {"bar": {"type": "integer"}}, "allOf": [{"required": ["foo"], "properties": {"foo": {"type": "string"}}}, {"required": ["baz"], "properties": {"baz": {"type": "null"}}}]}}, {"fail": true, "data": {"bar": 2}, "name": "allOf with base schema -- mismatch both", "schema": {"required": ["bar"], "properties": {"bar": {"type": "integer"}}, "allOf": [{"required": ["foo"], "properties": {"foo": {"type": "string"}}}, {"required": ["baz"], "properties": {"baz": {"type": "null"}}}]}}, {"fail": false, "data": 25, "name": "allOf simple types -- valid", "schema": {"allOf": [{"maximum": 30}, {"minimum": 20}]}}, {"fail": true, "data": 35, "name": "allOf simple types -- mismatch one", "schema": {"allOf": [{"maximum": 30}, {"minimum": 20}]}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/anyOf.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/anyOf.json new file mode 100644 index 00000000..a58714af --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/anyOf.json @@ -0,0 +1,68 @@ +[ + { + "description": "anyOf", + "schema": { + "anyOf": [ + { + "type": "integer" + }, + { + "minimum": 2 + } + ] + }, + "tests": [ + { + "description": "first anyOf valid", + "data": 1, + "valid": true + }, + { + "description": "second anyOf valid", + "data": 2.5, + "valid": true + }, + { + "description": "both anyOf valid", + "data": 3, + "valid": true + }, + { + "description": "neither anyOf valid", + "data": 1.5, + "valid": false + } + ] + }, + { + "description": "anyOf with base schema", + "schema": { + "type": "string", + "anyOf" : [ + { + "maxLength": 2 + }, + { + "minLength": 4 + } + ] + }, + "tests": [ + { + "description": "mismatch base schema", + "data": 3, + "valid": false + }, + { + "description": "one anyOf valid", + "data": "foobar", + "valid": true + }, + { + "description": "both anyOf invalid", + "data": "foo", + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/anyOf.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/anyOf.test new file mode 100644 index 00000000..5d24c4e8 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/anyOf.test @@ -0,0 +1 @@ +[{"fail": false, "data": 1, "name": "anyOf -- first anyOf valid", "schema": {"anyOf": [{"type": "integer"}, {"minimum": 2}]}}, {"fail": false, "data": 2.5, "name": "anyOf -- second anyOf valid", "schema": {"anyOf": [{"type": "integer"}, {"minimum": 2}]}}, {"fail": false, "data": 3, "name": "anyOf -- both anyOf valid", "schema": {"anyOf": [{"type": "integer"}, {"minimum": 2}]}}, {"fail": true, "data": 1.5, "name": "anyOf -- neither anyOf valid", "schema": {"anyOf": [{"type": "integer"}, {"minimum": 2}]}}, {"fail": true, "data": 3, "name": "anyOf with base schema -- mismatch base schema", "schema": {"anyOf": [{"maxLength": 2}, {"minLength": 4}], "type": "string"}}, {"fail": false, "data": "foobar", "name": "anyOf with base schema -- one anyOf valid", "schema": {"anyOf": [{"maxLength": 2}, {"minLength": 4}], "type": "string"}}, {"fail": true, "data": "foo", "name": "anyOf with base schema -- both anyOf invalid", "schema": {"anyOf": [{"maxLength": 2}, {"minLength": 4}], "type": "string"}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/convert.py b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/convert.py new file mode 100644 index 00000000..99bcec58 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/convert.py @@ -0,0 +1,16 @@ + +import json +import sys + +tests = json.load(sys.stdin) + +out = [] +for t in tests: + for case in t['tests']: + out.append({ + 'name': t['description'] + ' -- ' + case['description'], + 'schema': t['schema'], + 'data': case['data'], + 'fail': not case['valid'] + }) +json.dump(out, sys.stdout) diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/definitions.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/definitions.json new file mode 100644 index 00000000..cf935a32 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/definitions.json @@ -0,0 +1,32 @@ +[ + { + "description": "valid definition", + "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}, + "tests": [ + { + "description": "valid definition schema", + "data": { + "definitions": { + "foo": {"type": "integer"} + } + }, + "valid": true + } + ] + }, + { + "description": "invalid definition", + "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}, + "tests": [ + { + "description": "invalid definition schema", + "data": { + "definitions": { + "foo": {"type": 1} + } + }, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/definitions.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/definitions.test new file mode 100644 index 00000000..4bd8350a --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/definitions.test @@ -0,0 +1 @@ +[{"fail": false, "data": {"definitions": {"foo": {"type": "integer"}}}, "name": "valid definition -- valid definition schema", "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}}, {"fail": true, "data": {"definitions": {"foo": {"type": 1}}}, "name": "invalid definition -- invalid definition schema", "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/dependencies.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/dependencies.json new file mode 100644 index 00000000..7b9b16a7 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/dependencies.json @@ -0,0 +1,113 @@ +[ + { + "description": "dependencies", + "schema": { + "dependencies": {"bar": ["foo"]} + }, + "tests": [ + { + "description": "neither", + "data": {}, + "valid": true + }, + { + "description": "nondependant", + "data": {"foo": 1}, + "valid": true + }, + { + "description": "with dependency", + "data": {"foo": 1, "bar": 2}, + "valid": true + }, + { + "description": "missing dependency", + "data": {"bar": 2}, + "valid": false + }, + { + "description": "ignores non-objects", + "data": "foo", + "valid": true + } + ] + }, + { + "description": "multiple dependencies", + "schema": { + "dependencies": {"quux": ["foo", "bar"]} + }, + "tests": [ + { + "description": "neither", + "data": {}, + "valid": true + }, + { + "description": "nondependants", + "data": {"foo": 1, "bar": 2}, + "valid": true + }, + { + "description": "with dependencies", + "data": {"foo": 1, "bar": 2, "quux": 3}, + "valid": true + }, + { + "description": "missing dependency", + "data": {"foo": 1, "quux": 2}, + "valid": false + }, + { + "description": "missing other dependency", + "data": {"bar": 1, "quux": 2}, + "valid": false + }, + { + "description": "missing both dependencies", + "data": {"quux": 1}, + "valid": false + } + ] + }, + { + "description": "multiple dependencies subschema", + "schema": { + "dependencies": { + "bar": { + "properties": { + "foo": {"type": "integer"}, + "bar": {"type": "integer"} + } + } + } + }, + "tests": [ + { + "description": "valid", + "data": {"foo": 1, "bar": 2}, + "valid": true + }, + { + "description": "no dependency", + "data": {"foo": "quux"}, + "valid": true + }, + { + "description": "wrong type", + "data": {"foo": "quux", "bar": 2}, + "valid": false + }, + { + "description": "wrong type other", + "data": {"foo": 2, "bar": "quux"}, + "valid": false + }, + { + "description": "wrong type both", + "data": {"foo": "quux", "bar": "quux"}, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/dependencies.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/dependencies.test new file mode 100644 index 00000000..f54a1118 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/dependencies.test @@ -0,0 +1 @@ +[{"fail": false, "data": {}, "name": "dependencies -- neither", "schema": {"dependencies": {"bar": ["foo"]}}}, {"fail": false, "data": {"foo": 1}, "name": "dependencies -- nondependant", "schema": {"dependencies": {"bar": ["foo"]}}}, {"fail": false, "data": {"foo": 1, "bar": 2}, "name": "dependencies -- with dependency", "schema": {"dependencies": {"bar": ["foo"]}}}, {"fail": true, "data": {"bar": 2}, "name": "dependencies -- missing dependency", "schema": {"dependencies": {"bar": ["foo"]}}}, {"fail": false, "data": "foo", "name": "dependencies -- ignores non-objects", "schema": {"dependencies": {"bar": ["foo"]}}}, {"fail": false, "data": {}, "name": "multiple dependencies -- neither", "schema": {"dependencies": {"quux": ["foo", "bar"]}}}, {"fail": false, "data": {"foo": 1, "bar": 2}, "name": "multiple dependencies -- nondependants", "schema": {"dependencies": {"quux": ["foo", "bar"]}}}, {"fail": false, "data": {"quux": 3, "foo": 1, "bar": 2}, "name": "multiple dependencies -- with dependencies", "schema": {"dependencies": {"quux": ["foo", "bar"]}}}, {"fail": true, "data": {"quux": 2, "foo": 1}, "name": "multiple dependencies -- missing dependency", "schema": {"dependencies": {"quux": ["foo", "bar"]}}}, {"fail": true, "data": {"quux": 2, "bar": 1}, "name": "multiple dependencies -- missing other dependency", "schema": {"dependencies": {"quux": ["foo", "bar"]}}}, {"fail": true, "data": {"quux": 1}, "name": "multiple dependencies -- missing both dependencies", "schema": {"dependencies": {"quux": ["foo", "bar"]}}}, {"fail": false, "data": {"foo": 1, "bar": 2}, "name": "multiple dependencies subschema -- valid", "schema": {"dependencies": {"bar": {"properties": {"foo": {"type": "integer"}, "bar": {"type": "integer"}}}}}}, {"fail": false, "data": {"foo": "quux"}, "name": "multiple dependencies subschema -- no dependency", "schema": {"dependencies": {"bar": {"properties": {"foo": {"type": "integer"}, "bar": {"type": "integer"}}}}}}, {"fail": true, "data": {"foo": "quux", "bar": 2}, "name": "multiple dependencies subschema -- wrong type", "schema": {"dependencies": {"bar": {"properties": {"foo": {"type": "integer"}, "bar": {"type": "integer"}}}}}}, {"fail": true, "data": {"foo": 2, "bar": "quux"}, "name": "multiple dependencies subschema -- wrong type other", "schema": {"dependencies": {"bar": {"properties": {"foo": {"type": "integer"}, "bar": {"type": "integer"}}}}}}, {"fail": true, "data": {"foo": "quux", "bar": "quux"}, "name": "multiple dependencies subschema -- wrong type both", "schema": {"dependencies": {"bar": {"properties": {"foo": {"type": "integer"}, "bar": {"type": "integer"}}}}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/enum.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/enum.json new file mode 100644 index 00000000..a539edb7 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/enum.json @@ -0,0 +1,39 @@ +[ + { + "description": "simple enum validation", + "schema": {"enum": [1, 2, 3]}, + "tests": [ + { + "description": "one of the enum is valid", + "data": 1, + "valid": true + }, + { + "description": "something else is invalid", + "data": 4, + "valid": false + } + ] + }, + { + "description": "heterogeneous enum validation", + "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}, + "tests": [ + { + "description": "one of the enum is valid", + "data": [], + "valid": true + }, + { + "description": "something else is invalid", + "data": null, + "valid": false + }, + { + "description": "objects are deep compared", + "data": {"foo": false}, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/enum.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/enum.test new file mode 100644 index 00000000..916e4375 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/enum.test @@ -0,0 +1 @@ +[{"fail": false, "data": 1, "name": "simple enum validation -- one of the enum is valid", "schema": {"enum": [1, 2, 3]}}, {"fail": true, "data": 4, "name": "simple enum validation -- something else is invalid", "schema": {"enum": [1, 2, 3]}}, {"fail": false, "data": [], "name": "heterogeneous enum validation -- one of the enum is valid", "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}}, {"fail": true, "data": null, "name": "heterogeneous enum validation -- something else is invalid", "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}}, {"fail": true, "data": {"foo": false}, "name": "heterogeneous enum validation -- objects are deep compared", "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/items.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/items.json new file mode 100644 index 00000000..f5e18a13 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/items.json @@ -0,0 +1,46 @@ +[ + { + "description": "a schema given for items", + "schema": { + "items": {"type": "integer"} + }, + "tests": [ + { + "description": "valid items", + "data": [ 1, 2, 3 ], + "valid": true + }, + { + "description": "wrong type of items", + "data": [1, "x"], + "valid": false + }, + { + "description": "ignores non-arrays", + "data": {"foo" : "bar"}, + "valid": true + } + ] + }, + { + "description": "an array of schemas for items", + "schema": { + "items": [ + {"type": "integer"}, + {"type": "string"} + ] + }, + "tests": [ + { + "description": "correct types", + "data": [ 1, "foo" ], + "valid": true + }, + { + "description": "wrong types", + "data": [ "foo", 1 ], + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/items.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/items.test new file mode 100644 index 00000000..6975dbd9 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/items.test @@ -0,0 +1 @@ +[{"fail": false, "data": [1, 2, 3], "name": "a schema given for items -- valid items", "schema": {"items": {"type": "integer"}}}, {"fail": true, "data": [1, "x"], "name": "a schema given for items -- wrong type of items", "schema": {"items": {"type": "integer"}}}, {"fail": false, "data": {"foo": "bar"}, "name": "a schema given for items -- ignores non-arrays", "schema": {"items": {"type": "integer"}}}, {"fail": false, "data": [1, "foo"], "name": "an array of schemas for items -- correct types", "schema": {"items": [{"type": "integer"}, {"type": "string"}]}}, {"fail": true, "data": ["foo", 1], "name": "an array of schemas for items -- wrong types", "schema": {"items": [{"type": "integer"}, {"type": "string"}]}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxItems.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxItems.json new file mode 100644 index 00000000..3b53a6b3 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxItems.json @@ -0,0 +1,28 @@ +[ + { + "description": "maxItems validation", + "schema": {"maxItems": 2}, + "tests": [ + { + "description": "shorter is valid", + "data": [1], + "valid": true + }, + { + "description": "exact length is valid", + "data": [1, 2], + "valid": true + }, + { + "description": "too long is invalid", + "data": [1, 2, 3], + "valid": false + }, + { + "description": "ignores non-arrays", + "data": "foobar", + "valid": true + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxItems.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxItems.test new file mode 100644 index 00000000..a573f4c0 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxItems.test @@ -0,0 +1 @@ +[{"fail": false, "data": [1], "name": "maxItems validation -- shorter is valid", "schema": {"maxItems": 2}}, {"fail": false, "data": [1, 2], "name": "maxItems validation -- exact length is valid", "schema": {"maxItems": 2}}, {"fail": true, "data": [1, 2, 3], "name": "maxItems validation -- too long is invalid", "schema": {"maxItems": 2}}, {"fail": false, "data": "foobar", "name": "maxItems validation -- ignores non-arrays", "schema": {"maxItems": 2}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxLength.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxLength.json new file mode 100644 index 00000000..561767b9 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxLength.json @@ -0,0 +1,28 @@ +[ + { + "description": "maxLength validation", + "schema": {"maxLength": 2}, + "tests": [ + { + "description": "shorter is valid", + "data": "f", + "valid": true + }, + { + "description": "exact length is valid", + "data": "fo", + "valid": true + }, + { + "description": "too long is invalid", + "data": "foo", + "valid": false + }, + { + "description": "ignores non-strings", + "data": 10, + "valid": true + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxLength.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxLength.test new file mode 100644 index 00000000..4933e821 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxLength.test @@ -0,0 +1 @@ +[{"fail": false, "data": "f", "name": "maxLength validation -- shorter is valid", "schema": {"maxLength": 2}}, {"fail": false, "data": "fo", "name": "maxLength validation -- exact length is valid", "schema": {"maxLength": 2}}, {"fail": true, "data": "foo", "name": "maxLength validation -- too long is invalid", "schema": {"maxLength": 2}}, {"fail": false, "data": 10, "name": "maxLength validation -- ignores non-strings", "schema": {"maxLength": 2}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxProperties.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxProperties.json new file mode 100644 index 00000000..d282446a --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxProperties.json @@ -0,0 +1,28 @@ +[ + { + "description": "maxProperties validation", + "schema": {"maxProperties": 2}, + "tests": [ + { + "description": "shorter is valid", + "data": {"foo": 1}, + "valid": true + }, + { + "description": "exact length is valid", + "data": {"foo": 1, "bar": 2}, + "valid": true + }, + { + "description": "too long is invalid", + "data": {"foo": 1, "bar": 2, "baz": 3}, + "valid": false + }, + { + "description": "ignores non-objects", + "data": "foobar", + "valid": true + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxProperties.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxProperties.test new file mode 100644 index 00000000..dc132fa5 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maxProperties.test @@ -0,0 +1 @@ +[{"fail": false, "data": {"foo": 1}, "name": "maxProperties validation -- shorter is valid", "schema": {"maxProperties": 2}}, {"fail": false, "data": {"foo": 1, "bar": 2}, "name": "maxProperties validation -- exact length is valid", "schema": {"maxProperties": 2}}, {"fail": true, "data": {"baz": 3, "foo": 1, "bar": 2}, "name": "maxProperties validation -- too long is invalid", "schema": {"maxProperties": 2}}, {"fail": false, "data": "foobar", "name": "maxProperties validation -- ignores non-objects", "schema": {"maxProperties": 2}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maximum.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maximum.json new file mode 100644 index 00000000..86c7b89c --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maximum.json @@ -0,0 +1,42 @@ +[ + { + "description": "maximum validation", + "schema": {"maximum": 3.0}, + "tests": [ + { + "description": "below the maximum is valid", + "data": 2.6, + "valid": true + }, + { + "description": "above the maximum is invalid", + "data": 3.5, + "valid": false + }, + { + "description": "ignores non-numbers", + "data": "x", + "valid": true + } + ] + }, + { + "description": "exclusiveMaximum validation", + "schema": { + "maximum": 3.0, + "exclusiveMaximum": true + }, + "tests": [ + { + "description": "below the maximum is still valid", + "data": 2.2, + "valid": true + }, + { + "description": "boundary point is invalid", + "data": 3.0, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maximum.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maximum.test new file mode 100644 index 00000000..70b916e2 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/maximum.test @@ -0,0 +1 @@ +[{"fail": false, "data": 2.6000000000000001, "name": "maximum validation -- below the maximum is valid", "schema": {"maximum": 3.0}}, {"fail": true, "data": 3.5, "name": "maximum validation -- above the maximum is invalid", "schema": {"maximum": 3.0}}, {"fail": false, "data": "x", "name": "maximum validation -- ignores non-numbers", "schema": {"maximum": 3.0}}, {"fail": false, "data": 2.2000000000000002, "name": "exclusiveMaximum validation -- below the maximum is still valid", "schema": {"exclusiveMaximum": true, "maximum": 3.0}}, {"fail": true, "data": 3.0, "name": "exclusiveMaximum validation -- boundary point is invalid", "schema": {"exclusiveMaximum": true, "maximum": 3.0}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minItems.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minItems.json new file mode 100644 index 00000000..ed511881 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minItems.json @@ -0,0 +1,28 @@ +[ + { + "description": "minItems validation", + "schema": {"minItems": 1}, + "tests": [ + { + "description": "longer is valid", + "data": [1, 2], + "valid": true + }, + { + "description": "exact length is valid", + "data": [1], + "valid": true + }, + { + "description": "too short is invalid", + "data": [], + "valid": false + }, + { + "description": "ignores non-arrays", + "data": "", + "valid": true + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minItems.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minItems.test new file mode 100644 index 00000000..4e482def --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minItems.test @@ -0,0 +1 @@ +[{"fail": false, "data": [1, 2], "name": "minItems validation -- longer is valid", "schema": {"minItems": 1}}, {"fail": false, "data": [1], "name": "minItems validation -- exact length is valid", "schema": {"minItems": 1}}, {"fail": true, "data": [], "name": "minItems validation -- too short is invalid", "schema": {"minItems": 1}}, {"fail": false, "data": "", "name": "minItems validation -- ignores non-arrays", "schema": {"minItems": 1}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minLength.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minLength.json new file mode 100644 index 00000000..e9c14b17 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minLength.json @@ -0,0 +1,28 @@ +[ + { + "description": "minLength validation", + "schema": {"minLength": 2}, + "tests": [ + { + "description": "longer is valid", + "data": "foo", + "valid": true + }, + { + "description": "exact length is valid", + "data": "fo", + "valid": true + }, + { + "description": "too short is invalid", + "data": "f", + "valid": false + }, + { + "description": "ignores non-strings", + "data": 1, + "valid": true + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minLength.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minLength.test new file mode 100644 index 00000000..f4fb32ab --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minLength.test @@ -0,0 +1 @@ +[{"fail": false, "data": "foo", "name": "minLength validation -- longer is valid", "schema": {"minLength": 2}}, {"fail": false, "data": "fo", "name": "minLength validation -- exact length is valid", "schema": {"minLength": 2}}, {"fail": true, "data": "f", "name": "minLength validation -- too short is invalid", "schema": {"minLength": 2}}, {"fail": false, "data": 1, "name": "minLength validation -- ignores non-strings", "schema": {"minLength": 2}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minProperties.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minProperties.json new file mode 100644 index 00000000..a72c7d29 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minProperties.json @@ -0,0 +1,28 @@ +[ + { + "description": "minProperties validation", + "schema": {"minProperties": 1}, + "tests": [ + { + "description": "longer is valid", + "data": {"foo": 1, "bar": 2}, + "valid": true + }, + { + "description": "exact length is valid", + "data": {"foo": 1}, + "valid": true + }, + { + "description": "too short is invalid", + "data": {}, + "valid": false + }, + { + "description": "ignores non-objects", + "data": "", + "valid": true + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minProperties.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minProperties.test new file mode 100644 index 00000000..e9fdab6b --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minProperties.test @@ -0,0 +1 @@ +[{"fail": false, "data": {"foo": 1, "bar": 2}, "name": "minProperties validation -- longer is valid", "schema": {"minProperties": 1}}, {"fail": false, "data": {"foo": 1}, "name": "minProperties validation -- exact length is valid", "schema": {"minProperties": 1}}, {"fail": true, "data": {}, "name": "minProperties validation -- too short is invalid", "schema": {"minProperties": 1}}, {"fail": false, "data": "", "name": "minProperties validation -- ignores non-objects", "schema": {"minProperties": 1}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minimum.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minimum.json new file mode 100644 index 00000000..d5bf000b --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minimum.json @@ -0,0 +1,42 @@ +[ + { + "description": "minimum validation", + "schema": {"minimum": 1.1}, + "tests": [ + { + "description": "above the minimum is valid", + "data": 2.6, + "valid": true + }, + { + "description": "below the minimum is invalid", + "data": 0.6, + "valid": false + }, + { + "description": "ignores non-numbers", + "data": "x", + "valid": true + } + ] + }, + { + "description": "exclusiveMinimum validation", + "schema": { + "minimum": 1.1, + "exclusiveMinimum": true + }, + "tests": [ + { + "description": "above the minimum is still valid", + "data": 1.2, + "valid": true + }, + { + "description": "boundary point is invalid", + "data": 1.1, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minimum.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minimum.test new file mode 100644 index 00000000..ae413de4 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/minimum.test @@ -0,0 +1 @@ +[{"fail": false, "data": 2.6000000000000001, "name": "minimum validation -- above the minimum is valid", "schema": {"minimum": 1.1000000000000001}}, {"fail": true, "data": 0.59999999999999998, "name": "minimum validation -- below the minimum is invalid", "schema": {"minimum": 1.1000000000000001}}, {"fail": false, "data": "x", "name": "minimum validation -- ignores non-numbers", "schema": {"minimum": 1.1000000000000001}}, {"fail": false, "data": 1.2, "name": "exclusiveMinimum validation -- above the minimum is still valid", "schema": {"minimum": 1.1000000000000001, "exclusiveMinimum": true}}, {"fail": true, "data": 1.1000000000000001, "name": "exclusiveMinimum validation -- boundary point is invalid", "schema": {"minimum": 1.1000000000000001, "exclusiveMinimum": true}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/multipleOf.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/multipleOf.json new file mode 100644 index 00000000..ca3b7618 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/multipleOf.json @@ -0,0 +1,60 @@ +[ + { + "description": "by int", + "schema": {"multipleOf": 2}, + "tests": [ + { + "description": "int by int", + "data": 10, + "valid": true + }, + { + "description": "int by int fail", + "data": 7, + "valid": false + }, + { + "description": "ignores non-numbers", + "data": "foo", + "valid": true + } + ] + }, + { + "description": "by number", + "schema": {"multipleOf": 1.5}, + "tests": [ + { + "description": "zero is multiple of anything", + "data": 0, + "valid": true + }, + { + "description": "4.5 is multiple of 1.5", + "data": 4.5, + "valid": true + }, + { + "description": "35 is not multiple of 1.5", + "data": 35, + "valid": false + } + ] + }, + { + "description": "by small number", + "schema": {"multipleOf": 0.0001}, + "tests": [ + { + "description": "0.0075 is multiple of 0.0001", + "data": 0.0075, + "valid": true + }, + { + "description": "0.00751 is not multiple of 0.0001", + "data": 0.00751, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/multipleOf.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/multipleOf.test new file mode 100644 index 00000000..0debf687 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/multipleOf.test @@ -0,0 +1 @@ +[{"fail": false, "data": 10, "name": "by int -- int by int", "schema": {"multipleOf": 2}}, {"fail": true, "data": 7, "name": "by int -- int by int fail", "schema": {"multipleOf": 2}}, {"fail": false, "data": "foo", "name": "by int -- ignores non-numbers", "schema": {"multipleOf": 2}}, {"fail": false, "data": 0, "name": "by number -- zero is multiple of anything", "schema": {"multipleOf": 1.5}}, {"fail": false, "data": 4.5, "name": "by number -- 4.5 is multiple of 1.5", "schema": {"multipleOf": 1.5}}, {"fail": true, "data": 35, "name": "by number -- 35 is not multiple of 1.5", "schema": {"multipleOf": 1.5}}, {"fail": false, "data": 0.0074999999999999997, "name": "by small number -- 0.0075 is multiple of 0.0001", "schema": {"multipleOf": 0.0001}}, {"fail": true, "data": 0.0075100000000000002, "name": "by small number -- 0.00751 is not multiple of 0.0001", "schema": {"multipleOf": 0.0001}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/not.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/not.json new file mode 100644 index 00000000..2cdc9790 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/not.json @@ -0,0 +1,73 @@ +[ + { + "description": "not", + "schema": { + "not": {"type": "integer"} + }, + "tests": [ + { + "description": "allowed", + "data": "foo", + "valid": true + }, + { + "description": "disallowed", + "data": 1, + "valid": false + } + ] + }, + { + "description": "not multiple types", + "schema": { + "not": {"type": ["integer", "boolean"]} + }, + "tests": [ + { + "description": "valid", + "data": "foo", + "valid": true + }, + { + "description": "mismatch", + "data": 1, + "valid": false + }, + { + "description": "other mismatch", + "data": true, + "valid": false + } + ] + }, + { + "description": "not more complex schema", + "schema": { + "not": { + "type": "object", + "properties": { + "foo": { + "type": "string" + } + } + } + }, + "tests": [ + { + "description": "match", + "data": 1, + "valid": true + }, + { + "description": "other match", + "data": {"foo": 1}, + "valid": true + }, + { + "description": "mismatch", + "data": {"foo": "bar"}, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/not.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/not.test new file mode 100644 index 00000000..1761ab0f --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/not.test @@ -0,0 +1 @@ +[{"fail": false, "data": "foo", "name": "not -- allowed", "schema": {"not": {"type": "integer"}}}, {"fail": true, "data": 1, "name": "not -- disallowed", "schema": {"not": {"type": "integer"}}}, {"fail": false, "data": "foo", "name": "not multiple types -- valid", "schema": {"not": {"type": ["integer", "boolean"]}}}, {"fail": true, "data": 1, "name": "not multiple types -- mismatch", "schema": {"not": {"type": ["integer", "boolean"]}}}, {"fail": true, "data": true, "name": "not multiple types -- other mismatch", "schema": {"not": {"type": ["integer", "boolean"]}}}, {"fail": false, "data": 1, "name": "not more complex schema -- match", "schema": {"not": {"type": "object", "properties": {"foo": {"type": "string"}}}}}, {"fail": false, "data": {"foo": 1}, "name": "not more complex schema -- other match", "schema": {"not": {"type": "object", "properties": {"foo": {"type": "string"}}}}}, {"fail": true, "data": {"foo": "bar"}, "name": "not more complex schema -- mismatch", "schema": {"not": {"type": "object", "properties": {"foo": {"type": "string"}}}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/oneOf.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/oneOf.json new file mode 100644 index 00000000..1eaa4e47 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/oneOf.json @@ -0,0 +1,68 @@ +[ + { + "description": "oneOf", + "schema": { + "oneOf": [ + { + "type": "integer" + }, + { + "minimum": 2 + } + ] + }, + "tests": [ + { + "description": "first oneOf valid", + "data": 1, + "valid": true + }, + { + "description": "second oneOf valid", + "data": 2.5, + "valid": true + }, + { + "description": "both oneOf valid", + "data": 3, + "valid": false + }, + { + "description": "neither oneOf valid", + "data": 1.5, + "valid": false + } + ] + }, + { + "description": "oneOf with base schema", + "schema": { + "type": "string", + "oneOf" : [ + { + "minLength": 2 + }, + { + "maxLength": 4 + } + ] + }, + "tests": [ + { + "description": "mismatch base schema", + "data": 3, + "valid": false + }, + { + "description": "one oneOf valid", + "data": "foobar", + "valid": true + }, + { + "description": "both oneOf valid", + "data": "foo", + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/oneOf.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/oneOf.test new file mode 100644 index 00000000..f56d6071 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/oneOf.test @@ -0,0 +1 @@ +[{"fail": false, "data": 1, "name": "oneOf -- first oneOf valid", "schema": {"oneOf": [{"type": "integer"}, {"minimum": 2}]}}, {"fail": false, "data": 2.5, "name": "oneOf -- second oneOf valid", "schema": {"oneOf": [{"type": "integer"}, {"minimum": 2}]}}, {"fail": true, "data": 3, "name": "oneOf -- both oneOf valid", "schema": {"oneOf": [{"type": "integer"}, {"minimum": 2}]}}, {"fail": true, "data": 1.5, "name": "oneOf -- neither oneOf valid", "schema": {"oneOf": [{"type": "integer"}, {"minimum": 2}]}}, {"fail": true, "data": 3, "name": "oneOf with base schema -- mismatch base schema", "schema": {"oneOf": [{"minLength": 2}, {"maxLength": 4}], "type": "string"}}, {"fail": false, "data": "foobar", "name": "oneOf with base schema -- one oneOf valid", "schema": {"oneOf": [{"minLength": 2}, {"maxLength": 4}], "type": "string"}}, {"fail": true, "data": "foo", "name": "oneOf with base schema -- both oneOf valid", "schema": {"oneOf": [{"minLength": 2}, {"maxLength": 4}], "type": "string"}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/pattern.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/pattern.json new file mode 100644 index 00000000..befc4b56 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/pattern.json @@ -0,0 +1,23 @@ +[ + { + "description": "pattern validation", + "schema": {"pattern": "^a*$"}, + "tests": [ + { + "description": "a matching pattern is valid", + "data": "aaa", + "valid": true + }, + { + "description": "a non-matching pattern is invalid", + "data": "abc", + "valid": false + }, + { + "description": "ignores non-strings", + "data": true, + "valid": true + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/pattern.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/pattern.test new file mode 100644 index 00000000..0485d619 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/pattern.test @@ -0,0 +1 @@ +[{"fail": false, "data": "aaa", "name": "pattern validation -- a matching pattern is valid", "schema": {"pattern": "^a*$"}}, {"fail": true, "data": "abc", "name": "pattern validation -- a non-matching pattern is invalid", "schema": {"pattern": "^a*$"}}, {"fail": false, "data": true, "name": "pattern validation -- ignores non-strings", "schema": {"pattern": "^a*$"}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/patternProperties.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/patternProperties.json new file mode 100644 index 00000000..18586e5d --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/patternProperties.json @@ -0,0 +1,110 @@ +[ + { + "description": + "patternProperties validates properties matching a regex", + "schema": { + "patternProperties": { + "f.*o": {"type": "integer"} + } + }, + "tests": [ + { + "description": "a single valid match is valid", + "data": {"foo": 1}, + "valid": true + }, + { + "description": "multiple valid matches is valid", + "data": {"foo": 1, "foooooo" : 2}, + "valid": true + }, + { + "description": "a single invalid match is invalid", + "data": {"foo": "bar", "fooooo": 2}, + "valid": false + }, + { + "description": "multiple invalid matches is invalid", + "data": {"foo": "bar", "foooooo" : "baz"}, + "valid": false + }, + { + "description": "ignores non-objects", + "data": 12, + "valid": true + } + ] + }, + { + "description": "multiple simultaneous patternProperties are validated", + "schema": { + "patternProperties": { + "a*": {"type": "integer"}, + "aaa*": {"maximum": 20} + } + }, + "tests": [ + { + "description": "a single valid match is valid", + "data": {"a": 21}, + "valid": true + }, + { + "description": "a simultaneous match is valid", + "data": {"aaaa": 18}, + "valid": true + }, + { + "description": "multiple matches is valid", + "data": {"a": 21, "aaaa": 18}, + "valid": true + }, + { + "description": "an invalid due to one is invalid", + "data": {"a": "bar"}, + "valid": false + }, + { + "description": "an invalid due to the other is invalid", + "data": {"aaaa": 31}, + "valid": false + }, + { + "description": "an invalid due to both is invalid", + "data": {"aaa": "foo", "aaaa": 31}, + "valid": false + } + ] + }, + { + "description": "regexes are not anchored by default and are case sensitive", + "schema": { + "patternProperties": { + "[0-9]{2,}": { "type": "boolean" }, + "X_": { "type": "string" } + } + }, + "tests": [ + { + "description": "non recognized members are ignored", + "data": { "answer 1": "42" }, + "valid": true + }, + { + "description": "recognized members are accounted for", + "data": { "a31b": null }, + "valid": false + }, + { + "description": "regexes are case sensitive", + "data": { "a_x_3": 3 }, + "valid": true + }, + { + "description": "regexes are case sensitive, 2", + "data": { "a_X_3": 3 }, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/patternProperties.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/patternProperties.test new file mode 100644 index 00000000..a5ff2de2 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/patternProperties.test @@ -0,0 +1 @@ +[{"fail": false, "data": {"foo": 1}, "name": "patternProperties validates properties matching a regex -- a single valid match is valid", "schema": {"patternProperties": {"f.*o": {"type": "integer"}}}}, {"fail": false, "data": {"foooooo": 2, "foo": 1}, "name": "patternProperties validates properties matching a regex -- multiple valid matches is valid", "schema": {"patternProperties": {"f.*o": {"type": "integer"}}}}, {"fail": true, "data": {"foo": "bar", "fooooo": 2}, "name": "patternProperties validates properties matching a regex -- a single invalid match is invalid", "schema": {"patternProperties": {"f.*o": {"type": "integer"}}}}, {"fail": true, "data": {"foooooo": "baz", "foo": "bar"}, "name": "patternProperties validates properties matching a regex -- multiple invalid matches is invalid", "schema": {"patternProperties": {"f.*o": {"type": "integer"}}}}, {"fail": false, "data": 12, "name": "patternProperties validates properties matching a regex -- ignores non-objects", "schema": {"patternProperties": {"f.*o": {"type": "integer"}}}}, {"fail": false, "data": {"a": 21}, "name": "multiple simultaneous patternProperties are validated -- a single valid match is valid", "schema": {"patternProperties": {"a*": {"type": "integer"}, "aaa*": {"maximum": 20}}}}, {"fail": false, "data": {"aaaa": 18}, "name": "multiple simultaneous patternProperties are validated -- a simultaneous match is valid", "schema": {"patternProperties": {"a*": {"type": "integer"}, "aaa*": {"maximum": 20}}}}, {"fail": false, "data": {"a": 21, "aaaa": 18}, "name": "multiple simultaneous patternProperties are validated -- multiple matches is valid", "schema": {"patternProperties": {"a*": {"type": "integer"}, "aaa*": {"maximum": 20}}}}, {"fail": true, "data": {"a": "bar"}, "name": "multiple simultaneous patternProperties are validated -- an invalid due to one is invalid", "schema": {"patternProperties": {"a*": {"type": "integer"}, "aaa*": {"maximum": 20}}}}, {"fail": true, "data": {"aaaa": 31}, "name": "multiple simultaneous patternProperties are validated -- an invalid due to the other is invalid", "schema": {"patternProperties": {"a*": {"type": "integer"}, "aaa*": {"maximum": 20}}}}, {"fail": true, "data": {"aaaa": 31, "aaa": "foo"}, "name": "multiple simultaneous patternProperties are validated -- an invalid due to both is invalid", "schema": {"patternProperties": {"a*": {"type": "integer"}, "aaa*": {"maximum": 20}}}}, {"fail": false, "data": {"answer 1": "42"}, "name": "regexes are not anchored by default and are case sensitive -- non recognized members are ignored", "schema": {"patternProperties": {"X_": {"type": "string"}, "[0-9]{2,}": {"type": "boolean"}}}}, {"fail": true, "data": {"a31b": null}, "name": "regexes are not anchored by default and are case sensitive -- recognized members are accounted for", "schema": {"patternProperties": {"X_": {"type": "string"}, "[0-9]{2,}": {"type": "boolean"}}}}, {"fail": false, "data": {"a_x_3": 3}, "name": "regexes are not anchored by default and are case sensitive -- regexes are case sensitive", "schema": {"patternProperties": {"X_": {"type": "string"}, "[0-9]{2,}": {"type": "boolean"}}}}, {"fail": true, "data": {"a_X_3": 3}, "name": "regexes are not anchored by default and are case sensitive -- regexes are case sensitive, 2", "schema": {"patternProperties": {"X_": {"type": "string"}, "[0-9]{2,}": {"type": "boolean"}}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/properties.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/properties.json new file mode 100644 index 00000000..cd1644dc --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/properties.json @@ -0,0 +1,92 @@ +[ + { + "description": "object properties validation", + "schema": { + "properties": { + "foo": {"type": "integer"}, + "bar": {"type": "string"} + } + }, + "tests": [ + { + "description": "both properties present and valid is valid", + "data": {"foo": 1, "bar": "baz"}, + "valid": true + }, + { + "description": "one property invalid is invalid", + "data": {"foo": 1, "bar": {}}, + "valid": false + }, + { + "description": "both properties invalid is invalid", + "data": {"foo": [], "bar": {}}, + "valid": false + }, + { + "description": "doesn't invalidate other properties", + "data": {"quux": []}, + "valid": true + }, + { + "description": "ignores non-objects", + "data": [], + "valid": true + } + ] + }, + { + "description": + "properties, patternProperties, additionalProperties interaction", + "schema": { + "properties": { + "foo": {"type": "array", "maxItems": 3}, + "bar": {"type": "array"} + }, + "patternProperties": {"f.o": {"minItems": 2}}, + "additionalProperties": {"type": "integer"} + }, + "tests": [ + { + "description": "property validates property", + "data": {"foo": [1, 2]}, + "valid": true + }, + { + "description": "property invalidates property", + "data": {"foo": [1, 2, 3, 4]}, + "valid": false + }, + { + "description": "patternProperty invalidates property", + "data": {"foo": []}, + "valid": false + }, + { + "description": "patternProperty validates nonproperty", + "data": {"fxo": [1, 2]}, + "valid": true + }, + { + "description": "patternProperty invalidates nonproperty", + "data": {"fxo": []}, + "valid": false + }, + { + "description": "additionalProperty ignores property", + "data": {"bar": []}, + "valid": true + }, + { + "description": "additionalProperty validates others", + "data": {"quux": 3}, + "valid": true + }, + { + "description": "additionalProperty invalidates others", + "data": {"quux": "foo"}, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/properties.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/properties.test new file mode 100644 index 00000000..61186f68 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/properties.test @@ -0,0 +1 @@ +[{"fail": false, "data": {"foo": 1, "bar": "baz"}, "name": "object properties validation -- both properties present and valid is valid", "schema": {"properties": {"foo": {"type": "integer"}, "bar": {"type": "string"}}}}, {"fail": true, "data": {"foo": 1, "bar": {}}, "name": "object properties validation -- one property invalid is invalid", "schema": {"properties": {"foo": {"type": "integer"}, "bar": {"type": "string"}}}}, {"fail": true, "data": {"foo": [], "bar": {}}, "name": "object properties validation -- both properties invalid is invalid", "schema": {"properties": {"foo": {"type": "integer"}, "bar": {"type": "string"}}}}, {"fail": false, "data": {"quux": []}, "name": "object properties validation -- doesn't invalidate other properties", "schema": {"properties": {"foo": {"type": "integer"}, "bar": {"type": "string"}}}}, {"fail": false, "data": [], "name": "object properties validation -- ignores non-objects", "schema": {"properties": {"foo": {"type": "integer"}, "bar": {"type": "string"}}}}, {"fail": false, "data": {"foo": [1, 2]}, "name": "properties, patternProperties, additionalProperties interaction -- property validates property", "schema": {"additionalProperties": {"type": "integer"}, "patternProperties": {"f.o": {"minItems": 2}}, "properties": {"foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"}}}}, {"fail": true, "data": {"foo": [1, 2, 3, 4]}, "name": "properties, patternProperties, additionalProperties interaction -- property invalidates property", "schema": {"additionalProperties": {"type": "integer"}, "patternProperties": {"f.o": {"minItems": 2}}, "properties": {"foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"}}}}, {"fail": true, "data": {"foo": []}, "name": "properties, patternProperties, additionalProperties interaction -- patternProperty invalidates property", "schema": {"additionalProperties": {"type": "integer"}, "patternProperties": {"f.o": {"minItems": 2}}, "properties": {"foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"}}}}, {"fail": false, "data": {"fxo": [1, 2]}, "name": "properties, patternProperties, additionalProperties interaction -- patternProperty validates nonproperty", "schema": {"additionalProperties": {"type": "integer"}, "patternProperties": {"f.o": {"minItems": 2}}, "properties": {"foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"}}}}, {"fail": true, "data": {"fxo": []}, "name": "properties, patternProperties, additionalProperties interaction -- patternProperty invalidates nonproperty", "schema": {"additionalProperties": {"type": "integer"}, "patternProperties": {"f.o": {"minItems": 2}}, "properties": {"foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"}}}}, {"fail": false, "data": {"bar": []}, "name": "properties, patternProperties, additionalProperties interaction -- additionalProperty ignores property", "schema": {"additionalProperties": {"type": "integer"}, "patternProperties": {"f.o": {"minItems": 2}}, "properties": {"foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"}}}}, {"fail": false, "data": {"quux": 3}, "name": "properties, patternProperties, additionalProperties interaction -- additionalProperty validates others", "schema": {"additionalProperties": {"type": "integer"}, "patternProperties": {"f.o": {"minItems": 2}}, "properties": {"foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"}}}}, {"fail": true, "data": {"quux": "foo"}, "name": "properties, patternProperties, additionalProperties interaction -- additionalProperty invalidates others", "schema": {"additionalProperties": {"type": "integer"}, "patternProperties": {"f.o": {"minItems": 2}}, "properties": {"foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"}}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/ref.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/ref.json new file mode 100644 index 00000000..168f207d --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/ref.json @@ -0,0 +1,123 @@ +[ + { + "description": "root pointer ref", + "schema": { + "properties": { + "foo": {"$ref": "#"} + }, + "additionalProperties": false + }, + "tests": [ + { + "description": "match", + "data": {"foo": false}, + "valid": true + }, + { + "description": "recursive match", + "data": {"foo": {"foo": false}}, + "valid": true + }, + { + "description": "mismatch", + "data": {"bar": false}, + "valid": false + }, + { + "description": "recursive mismatch", + "data": {"foo": {"bar": false}}, + "valid": false + } + ] + }, + { + "description": "relative pointer ref", + "schema": { + "properties": { + "foo": {"type": "integer"}, + "bar": {"$ref": "#/properties/foo"} + } + }, + "tests": [ + { + "description": "match", + "data": {"bar": 3}, + "valid": true + }, + { + "description": "mismatch", + "data": {"bar": true}, + "valid": false + } + ] + }, + { + "description": "escaped pointer ref", + "schema": { + "tilda~field": {"type": "integer"}, + "slash/field": {"type": "integer"}, + "percent%field": {"type": "integer"}, + "properties": { + "tilda": {"$ref": "#/tilda~0field"}, + "slash": {"$ref": "#/slash~1field"}, + "percent": {"$ref": "#/percent%25field"} + } + }, + "tests": [ + { + "description": "slash", + "data": {"slash": "aoeu"}, + "valid": false + }, + { + "description": "tilda", + "data": {"tilda": "aoeu"}, + "valid": false + }, + { + "description": "percent", + "data": {"percent": "aoeu"}, + "valid": false + } + ] + }, + { + "description": "nested refs", + "schema": { + "definitions": { + "a": {"type": "integer"}, + "b": {"$ref": "#/definitions/a"}, + "c": {"$ref": "#/definitions/b"} + }, + "$ref": "#/definitions/c" + }, + "tests": [ + { + "description": "nested ref valid", + "data": 5, + "valid": true + }, + { + "description": "nested ref invalid", + "data": "a", + "valid": false + } + ] + }, + { + "description": "remote ref, containing refs itself", + "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}, + "tests": [ + { + "description": "remote ref valid", + "data": {"minLength": 1}, + "valid": true + }, + { + "description": "remote ref invalid", + "data": {"minLength": -1}, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/ref.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/ref.test new file mode 100644 index 00000000..ab6631c3 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/ref.test @@ -0,0 +1 @@ +[{"fail": false, "data": {"foo": false}, "name": "root pointer ref -- match", "schema": {"additionalProperties": false, "properties": {"foo": {"$ref": "#"}}}}, {"fail": false, "data": {"foo": {"foo": false}}, "name": "root pointer ref -- recursive match", "schema": {"additionalProperties": false, "properties": {"foo": {"$ref": "#"}}}}, {"fail": true, "data": {"bar": false}, "name": "root pointer ref -- mismatch", "schema": {"additionalProperties": false, "properties": {"foo": {"$ref": "#"}}}}, {"fail": true, "data": {"foo": {"bar": false}}, "name": "root pointer ref -- recursive mismatch", "schema": {"additionalProperties": false, "properties": {"foo": {"$ref": "#"}}}}, {"fail": false, "data": {"bar": 3}, "name": "relative pointer ref -- match", "schema": {"properties": {"foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"}}}}, {"fail": true, "data": {"bar": true}, "name": "relative pointer ref -- mismatch", "schema": {"properties": {"foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"}}}}, {"fail": true, "data": {"slash": "aoeu"}, "name": "escaped pointer ref -- slash", "schema": {"slash/field": {"type": "integer"}, "tilda~field": {"type": "integer"}, "percent%field": {"type": "integer"}, "properties": {"tilda": {"$ref": "#/tilda~0field"}, "percent": {"$ref": "#/percent%25field"}, "slash": {"$ref": "#/slash~1field"}}}}, {"fail": true, "data": {"tilda": "aoeu"}, "name": "escaped pointer ref -- tilda", "schema": {"slash/field": {"type": "integer"}, "tilda~field": {"type": "integer"}, "percent%field": {"type": "integer"}, "properties": {"tilda": {"$ref": "#/tilda~0field"}, "percent": {"$ref": "#/percent%25field"}, "slash": {"$ref": "#/slash~1field"}}}}, {"fail": true, "data": {"percent": "aoeu"}, "name": "escaped pointer ref -- percent", "schema": {"slash/field": {"type": "integer"}, "tilda~field": {"type": "integer"}, "percent%field": {"type": "integer"}, "properties": {"tilda": {"$ref": "#/tilda~0field"}, "percent": {"$ref": "#/percent%25field"}, "slash": {"$ref": "#/slash~1field"}}}}, {"fail": false, "data": 5, "name": "nested refs -- nested ref valid", "schema": {"definitions": {"a": {"type": "integer"}, "c": {"$ref": "#/definitions/b"}, "b": {"$ref": "#/definitions/a"}}, "$ref": "#/definitions/c"}}, {"fail": true, "data": "a", "name": "nested refs -- nested ref invalid", "schema": {"definitions": {"a": {"type": "integer"}, "c": {"$ref": "#/definitions/b"}, "b": {"$ref": "#/definitions/a"}}, "$ref": "#/definitions/c"}}, {"fail": false, "data": {"minLength": 1}, "name": "remote ref, containing refs itself -- remote ref valid", "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}}, {"fail": true, "data": {"minLength": -1}, "name": "remote ref, containing refs itself -- remote ref invalid", "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/required.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/required.json new file mode 100644 index 00000000..612f73f3 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/required.json @@ -0,0 +1,39 @@ +[ + { + "description": "required validation", + "schema": { + "properties": { + "foo": {}, + "bar": {} + }, + "required": ["foo"] + }, + "tests": [ + { + "description": "present required property is valid", + "data": {"foo": 1}, + "valid": true + }, + { + "description": "non-present required property is invalid", + "data": {"bar": 1}, + "valid": false + } + ] + }, + { + "description": "required default validation", + "schema": { + "properties": { + "foo": {} + } + }, + "tests": [ + { + "description": "not required by default", + "data": {}, + "valid": true + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/required.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/required.test new file mode 100644 index 00000000..c9762a4d --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/required.test @@ -0,0 +1 @@ +[{"fail": false, "data": {"foo": 1}, "name": "required validation -- present required property is valid", "schema": {"required": ["foo"], "properties": {"foo": {}, "bar": {}}}}, {"fail": true, "data": {"bar": 1}, "name": "required validation -- non-present required property is invalid", "schema": {"required": ["foo"], "properties": {"foo": {}, "bar": {}}}}, {"fail": false, "data": {}, "name": "required default validation -- not required by default", "schema": {"properties": {"foo": {}}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/type.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/type.json new file mode 100644 index 00000000..257f0512 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/type.json @@ -0,0 +1,330 @@ +[ + { + "description": "integer type matches integers", + "schema": {"type": "integer"}, + "tests": [ + { + "description": "an integer is an integer", + "data": 1, + "valid": true + }, + { + "description": "a float is not an integer", + "data": 1.1, + "valid": false + }, + { + "description": "a string is not an integer", + "data": "foo", + "valid": false + }, + { + "description": "an object is not an integer", + "data": {}, + "valid": false + }, + { + "description": "an array is not an integer", + "data": [], + "valid": false + }, + { + "description": "a boolean is not an integer", + "data": true, + "valid": false + }, + { + "description": "null is not an integer", + "data": null, + "valid": false + } + ] + }, + { + "description": "number type matches numbers", + "schema": {"type": "number"}, + "tests": [ + { + "description": "an integer is a number", + "data": 1, + "valid": true + }, + { + "description": "a float is a number", + "data": 1.1, + "valid": true + }, + { + "description": "a string is not a number", + "data": "foo", + "valid": false + }, + { + "description": "an object is not a number", + "data": {}, + "valid": false + }, + { + "description": "an array is not a number", + "data": [], + "valid": false + }, + { + "description": "a boolean is not a number", + "data": true, + "valid": false + }, + { + "description": "null is not a number", + "data": null, + "valid": false + } + ] + }, + { + "description": "string type matches strings", + "schema": {"type": "string"}, + "tests": [ + { + "description": "1 is not a string", + "data": 1, + "valid": false + }, + { + "description": "a float is not a string", + "data": 1.1, + "valid": false + }, + { + "description": "a string is a string", + "data": "foo", + "valid": true + }, + { + "description": "an object is not a string", + "data": {}, + "valid": false + }, + { + "description": "an array is not a string", + "data": [], + "valid": false + }, + { + "description": "a boolean is not a string", + "data": true, + "valid": false + }, + { + "description": "null is not a string", + "data": null, + "valid": false + } + ] + }, + { + "description": "object type matches objects", + "schema": {"type": "object"}, + "tests": [ + { + "description": "an integer is not an object", + "data": 1, + "valid": false + }, + { + "description": "a float is not an object", + "data": 1.1, + "valid": false + }, + { + "description": "a string is not an object", + "data": "foo", + "valid": false + }, + { + "description": "an object is an object", + "data": {}, + "valid": true + }, + { + "description": "an array is not an object", + "data": [], + "valid": false + }, + { + "description": "a boolean is not an object", + "data": true, + "valid": false + }, + { + "description": "null is not an object", + "data": null, + "valid": false + } + ] + }, + { + "description": "array type matches arrays", + "schema": {"type": "array"}, + "tests": [ + { + "description": "an integer is not an array", + "data": 1, + "valid": false + }, + { + "description": "a float is not an array", + "data": 1.1, + "valid": false + }, + { + "description": "a string is not an array", + "data": "foo", + "valid": false + }, + { + "description": "an object is not an array", + "data": {}, + "valid": false + }, + { + "description": "an array is not an array", + "data": [], + "valid": true + }, + { + "description": "a boolean is not an array", + "data": true, + "valid": false + }, + { + "description": "null is not an array", + "data": null, + "valid": false + } + ] + }, + { + "description": "boolean type matches booleans", + "schema": {"type": "boolean"}, + "tests": [ + { + "description": "an integer is not a boolean", + "data": 1, + "valid": false + }, + { + "description": "a float is not a boolean", + "data": 1.1, + "valid": false + }, + { + "description": "a string is not a boolean", + "data": "foo", + "valid": false + }, + { + "description": "an object is not a boolean", + "data": {}, + "valid": false + }, + { + "description": "an array is not a boolean", + "data": [], + "valid": false + }, + { + "description": "a boolean is not a boolean", + "data": true, + "valid": true + }, + { + "description": "null is not a boolean", + "data": null, + "valid": false + } + ] + }, + { + "description": "null type matches only the null object", + "schema": {"type": "null"}, + "tests": [ + { + "description": "an integer is not null", + "data": 1, + "valid": false + }, + { + "description": "a float is not null", + "data": 1.1, + "valid": false + }, + { + "description": "a string is not null", + "data": "foo", + "valid": false + }, + { + "description": "an object is not null", + "data": {}, + "valid": false + }, + { + "description": "an array is not null", + "data": [], + "valid": false + }, + { + "description": "a boolean is not null", + "data": true, + "valid": false + }, + { + "description": "null is null", + "data": null, + "valid": true + } + ] + }, + { + "description": "multiple types can be specified in an array", + "schema": {"type": ["integer", "string"]}, + "tests": [ + { + "description": "an integer is valid", + "data": 1, + "valid": true + }, + { + "description": "a string is valid", + "data": "foo", + "valid": true + }, + { + "description": "a float is invalid", + "data": 1.1, + "valid": false + }, + { + "description": "an object is invalid", + "data": {}, + "valid": false + }, + { + "description": "an array is invalid", + "data": [], + "valid": false + }, + { + "description": "a boolean is invalid", + "data": true, + "valid": false + }, + { + "description": "null is invalid", + "data": null, + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/type.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/type.test new file mode 100644 index 00000000..d93bceae --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/type.test @@ -0,0 +1 @@ +[{"fail": false, "data": 1, "name": "integer type matches integers -- an integer is an integer", "schema": {"type": "integer"}}, {"fail": true, "data": 1.1000000000000001, "name": "integer type matches integers -- a float is not an integer", "schema": {"type": "integer"}}, {"fail": true, "data": "foo", "name": "integer type matches integers -- a string is not an integer", "schema": {"type": "integer"}}, {"fail": true, "data": {}, "name": "integer type matches integers -- an object is not an integer", "schema": {"type": "integer"}}, {"fail": true, "data": [], "name": "integer type matches integers -- an array is not an integer", "schema": {"type": "integer"}}, {"fail": true, "data": true, "name": "integer type matches integers -- a boolean is not an integer", "schema": {"type": "integer"}}, {"fail": true, "data": null, "name": "integer type matches integers -- null is not an integer", "schema": {"type": "integer"}}, {"fail": false, "data": 1, "name": "number type matches numbers -- an integer is a number", "schema": {"type": "number"}}, {"fail": false, "data": 1.1000000000000001, "name": "number type matches numbers -- a float is a number", "schema": {"type": "number"}}, {"fail": true, "data": "foo", "name": "number type matches numbers -- a string is not a number", "schema": {"type": "number"}}, {"fail": true, "data": {}, "name": "number type matches numbers -- an object is not a number", "schema": {"type": "number"}}, {"fail": true, "data": [], "name": "number type matches numbers -- an array is not a number", "schema": {"type": "number"}}, {"fail": true, "data": true, "name": "number type matches numbers -- a boolean is not a number", "schema": {"type": "number"}}, {"fail": true, "data": null, "name": "number type matches numbers -- null is not a number", "schema": {"type": "number"}}, {"fail": true, "data": 1, "name": "string type matches strings -- 1 is not a string", "schema": {"type": "string"}}, {"fail": true, "data": 1.1000000000000001, "name": "string type matches strings -- a float is not a string", "schema": {"type": "string"}}, {"fail": false, "data": "foo", "name": "string type matches strings -- a string is a string", "schema": {"type": "string"}}, {"fail": true, "data": {}, "name": "string type matches strings -- an object is not a string", "schema": {"type": "string"}}, {"fail": true, "data": [], "name": "string type matches strings -- an array is not a string", "schema": {"type": "string"}}, {"fail": true, "data": true, "name": "string type matches strings -- a boolean is not a string", "schema": {"type": "string"}}, {"fail": true, "data": null, "name": "string type matches strings -- null is not a string", "schema": {"type": "string"}}, {"fail": true, "data": 1, "name": "object type matches objects -- an integer is not an object", "schema": {"type": "object"}}, {"fail": true, "data": 1.1000000000000001, "name": "object type matches objects -- a float is not an object", "schema": {"type": "object"}}, {"fail": true, "data": "foo", "name": "object type matches objects -- a string is not an object", "schema": {"type": "object"}}, {"fail": false, "data": {}, "name": "object type matches objects -- an object is an object", "schema": {"type": "object"}}, {"fail": true, "data": [], "name": "object type matches objects -- an array is not an object", "schema": {"type": "object"}}, {"fail": true, "data": true, "name": "object type matches objects -- a boolean is not an object", "schema": {"type": "object"}}, {"fail": true, "data": null, "name": "object type matches objects -- null is not an object", "schema": {"type": "object"}}, {"fail": true, "data": 1, "name": "array type matches arrays -- an integer is not an array", "schema": {"type": "array"}}, {"fail": true, "data": 1.1000000000000001, "name": "array type matches arrays -- a float is not an array", "schema": {"type": "array"}}, {"fail": true, "data": "foo", "name": "array type matches arrays -- a string is not an array", "schema": {"type": "array"}}, {"fail": true, "data": {}, "name": "array type matches arrays -- an object is not an array", "schema": {"type": "array"}}, {"fail": false, "data": [], "name": "array type matches arrays -- an array is not an array", "schema": {"type": "array"}}, {"fail": true, "data": true, "name": "array type matches arrays -- a boolean is not an array", "schema": {"type": "array"}}, {"fail": true, "data": null, "name": "array type matches arrays -- null is not an array", "schema": {"type": "array"}}, {"fail": true, "data": 1, "name": "boolean type matches booleans -- an integer is not a boolean", "schema": {"type": "boolean"}}, {"fail": true, "data": 1.1000000000000001, "name": "boolean type matches booleans -- a float is not a boolean", "schema": {"type": "boolean"}}, {"fail": true, "data": "foo", "name": "boolean type matches booleans -- a string is not a boolean", "schema": {"type": "boolean"}}, {"fail": true, "data": {}, "name": "boolean type matches booleans -- an object is not a boolean", "schema": {"type": "boolean"}}, {"fail": true, "data": [], "name": "boolean type matches booleans -- an array is not a boolean", "schema": {"type": "boolean"}}, {"fail": false, "data": true, "name": "boolean type matches booleans -- a boolean is not a boolean", "schema": {"type": "boolean"}}, {"fail": true, "data": null, "name": "boolean type matches booleans -- null is not a boolean", "schema": {"type": "boolean"}}, {"fail": true, "data": 1, "name": "null type matches only the null object -- an integer is not null", "schema": {"type": "null"}}, {"fail": true, "data": 1.1000000000000001, "name": "null type matches only the null object -- a float is not null", "schema": {"type": "null"}}, {"fail": true, "data": "foo", "name": "null type matches only the null object -- a string is not null", "schema": {"type": "null"}}, {"fail": true, "data": {}, "name": "null type matches only the null object -- an object is not null", "schema": {"type": "null"}}, {"fail": true, "data": [], "name": "null type matches only the null object -- an array is not null", "schema": {"type": "null"}}, {"fail": true, "data": true, "name": "null type matches only the null object -- a boolean is not null", "schema": {"type": "null"}}, {"fail": false, "data": null, "name": "null type matches only the null object -- null is null", "schema": {"type": "null"}}, {"fail": false, "data": 1, "name": "multiple types can be specified in an array -- an integer is valid", "schema": {"type": ["integer", "string"]}}, {"fail": false, "data": "foo", "name": "multiple types can be specified in an array -- a string is valid", "schema": {"type": ["integer", "string"]}}, {"fail": true, "data": 1.1000000000000001, "name": "multiple types can be specified in an array -- a float is invalid", "schema": {"type": ["integer", "string"]}}, {"fail": true, "data": {}, "name": "multiple types can be specified in an array -- an object is invalid", "schema": {"type": ["integer", "string"]}}, {"fail": true, "data": [], "name": "multiple types can be specified in an array -- an array is invalid", "schema": {"type": ["integer", "string"]}}, {"fail": true, "data": true, "name": "multiple types can be specified in an array -- a boolean is invalid", "schema": {"type": ["integer", "string"]}}, {"fail": true, "data": null, "name": "multiple types can be specified in an array -- null is invalid", "schema": {"type": ["integer", "string"]}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/uniqueItems.json b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/uniqueItems.json new file mode 100644 index 00000000..c1f4ab99 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/uniqueItems.json @@ -0,0 +1,79 @@ +[ + { + "description": "uniqueItems validation", + "schema": {"uniqueItems": true}, + "tests": [ + { + "description": "unique array of integers is valid", + "data": [1, 2], + "valid": true + }, + { + "description": "non-unique array of integers is invalid", + "data": [1, 1], + "valid": false + }, + { + "description": "numbers are unique if mathematically unequal", + "data": [1.0, 1.00, 1], + "valid": false + }, + { + "description": "unique array of objects is valid", + "data": [{"foo": "bar"}, {"foo": "baz"}], + "valid": true + }, + { + "description": "non-unique array of objects is invalid", + "data": [{"foo": "bar"}, {"foo": "bar"}], + "valid": false + }, + { + "description": "unique array of nested objects is valid", + "data": [ + {"foo": {"bar" : {"baz" : true}}}, + {"foo": {"bar" : {"baz" : false}}} + ], + "valid": true + }, + { + "description": "non-unique array of nested objects is invalid", + "data": [ + {"foo": {"bar" : {"baz" : true}}}, + {"foo": {"bar" : {"baz" : true}}} + ], + "valid": false + }, + { + "description": "unique array of arrays is valid", + "data": [["foo"], ["bar"]], + "valid": true + }, + { + "description": "non-unique array of arrays is invalid", + "data": [["foo"], ["foo"]], + "valid": false + }, + { + "description": "1 and true are unique", + "data": [1, true], + "valid": true + }, + { + "description": "0 and false are unique", + "data": [0, false], + "valid": true + }, + { + "description": "unique heterogeneous types are valid", + "data": [{}, [1], true, null, 1], + "valid": true + }, + { + "description": "non-unique heterogeneous types are invalid", + "data": [{}, [1], true, null, {}, 1], + "valid": false + } + ] + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/uniqueItems.test b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/uniqueItems.test new file mode 100644 index 00000000..5ebe141c --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/jsonschema-tests/uniqueItems.test @@ -0,0 +1 @@ +[{"fail": false, "data": [1, 2], "name": "uniqueItems validation -- unique array of integers is valid", "schema": {"uniqueItems": true}}, {"fail": true, "data": [1, 1], "name": "uniqueItems validation -- non-unique array of integers is invalid", "schema": {"uniqueItems": true}}, {"fail": true, "data": [1.0, 1.0, 1], "name": "uniqueItems validation -- numbers are unique if mathematically unequal", "schema": {"uniqueItems": true}}, {"fail": false, "data": [{"foo": "bar"}, {"foo": "baz"}], "name": "uniqueItems validation -- unique array of objects is valid", "schema": {"uniqueItems": true}}, {"fail": true, "data": [{"foo": "bar"}, {"foo": "bar"}], "name": "uniqueItems validation -- non-unique array of objects is invalid", "schema": {"uniqueItems": true}}, {"fail": false, "data": [{"foo": {"bar": {"baz": true}}}, {"foo": {"bar": {"baz": false}}}], "name": "uniqueItems validation -- unique array of nested objects is valid", "schema": {"uniqueItems": true}}, {"fail": true, "data": [{"foo": {"bar": {"baz": true}}}, {"foo": {"bar": {"baz": true}}}], "name": "uniqueItems validation -- non-unique array of nested objects is invalid", "schema": {"uniqueItems": true}}, {"fail": false, "data": [["foo"], ["bar"]], "name": "uniqueItems validation -- unique array of arrays is valid", "schema": {"uniqueItems": true}}, {"fail": true, "data": [["foo"], ["foo"]], "name": "uniqueItems validation -- non-unique array of arrays is invalid", "schema": {"uniqueItems": true}}, {"fail": false, "data": [1, true], "name": "uniqueItems validation -- 1 and true are unique", "schema": {"uniqueItems": true}}, {"fail": false, "data": [0, false], "name": "uniqueItems validation -- 0 and false are unique", "schema": {"uniqueItems": true}}, {"fail": false, "data": [{}, [1], true, null, 1], "name": "uniqueItems validation -- unique heterogeneous types are valid", "schema": {"uniqueItems": true}}, {"fail": true, "data": [{}, [1], true, null, {}, 1], "name": "uniqueItems validation -- non-unique heterogeneous types are invalid", "schema": {"uniqueItems": true}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/negative-unique-items.test b/src/hos_libvariant/src/test/test_schema_data/negative-unique-items.test new file mode 100644 index 00000000..a1d53187 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/negative-unique-items.test @@ -0,0 +1,19 @@ +[ + { + "name": "Negative unique items", + "schema": { + "type": "array", + "uniqueItems": false + }, + "data": [ "a", "b", "a", "c" ] + }, + { + "name": "Negative unique items", + "schema": { + "type": "array", + "uniqueItems": true + }, + "data": [ "a", "b", "a", "c" ], + "fail": true + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/recursion.test b/src/hos_libvariant/src/test/test_schema_data/recursion.test new file mode 100644 index 00000000..30d2e8b4 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/recursion.test @@ -0,0 +1,16 @@ +[ + { + "name": "infinite recursion test", + "schema": { + "definitions": { + "a": { "$ref": "#/definitions/b" }, + "b": { "$ref": "#/definitions/a" } + }, + "properties": { + "a": { "$ref": "#/definitions/a" } + } + }, + "data": { "a": { "a": {} } }, + "fail": true + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/sample-test.test b/src/hos_libvariant/src/test/test_schema_data/sample-test.test new file mode 100644 index 00000000..0ebeb3f4 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/sample-test.test @@ -0,0 +1,78 @@ +[ + { + "name": "sample test", + "schema": { + "$schema": "http://json-schema.org/draft-04/schema", + "type":"object", + "additionalProperties":false, + "properties":{ + "fw": { + "type":"number" + }, + "sw": { + "type":"number" + }, + "repos": { + "type":"object", + "additionalProperties": { + "type":"string" + } + } + }, + "required": ["fw", "sw"] + }, + "data": { + "fw": 21, + "repos": { + "abc1": "f4562e9b588a 109 default tip", + "blah2": "b8a9198883cf 22 default tip", + "arg4": "686bb1a70728 1043 default tip lwlcca-development", + "mmmooo": "heads/lwlcca-0-ge679eade196c", + "aaaaaa": "ac7006fded4e 519 default tip", + "....s;iodufhaj": "1e63ee2e1813 568 default tip", + "ufksdid": "b563665d4a02 17 default tip", + "naaa": "5a7cd1abfd8e 59 default tip" + }, + "sw": 21 + } + }, + { + "name": "sample test - failure", + "schema": { + "$schema": "http://json-schema.org/draft-04/schema", + "type":"object", + "additionalProperties":false, + "properties":{ + "fw": { + "type":"number" + }, + "sw": { + "type":"number" + }, + "repos": { + "type":"object", + "additionalProperties": { + "type":"string" + } + } + }, + "required": ["fw", "sw"] + }, + "data": { + "fw": 21, + "repos": { + "abc1": "f4562e9b588a 109 default tip", + "blah2": "b8a9198883cf 22 default tip", + "arg4": "686bb1a70728 1043 default tip lwlcca-development", + "mmmooo": "heads/lwlcca-0-ge679eade196c", + "aaaaaa": "ac7006fded4e 519 default tip", + "....s;iodufhaj": "1e63ee2e1813 568 default tip", + "ufksdid": "b563665d4a02 17 default tip", + "naaa": "5a7cd1abfd8e 59 default tip", + "foo": 21 + }, + "sw": 21 + }, + "fail": true + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/simple-test-fail.json b/src/hos_libvariant/src/test/test_schema_data/simple-test-fail.json new file mode 100644 index 00000000..5267a612 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/simple-test-fail.json @@ -0,0 +1,13 @@ +{ + "fw": 21, + "repos": { + "abc1": "f4562e9b588a 109 default tip", + "blah2": "b8a9198883cf 22 default tip", + "arg4": "686bb1a70728 1043 default tip lwlcca-development", + "mmmooo": "heads/lwlcca-0-ge679eade196c", + "aaaaaa": "ac7006fded4e 519 default tip", + "....s;iodufhaj": "1e63ee2e1813 568 default tip", + "ufksdid": "b563665d4a02 17 default tip", + "naaa": "5a7cd1abfd8e 59 default tip" + } +} diff --git a/src/hos_libvariant/src/test/test_schema_data/simple-test-schema.json b/src/hos_libvariant/src/test/test_schema_data/simple-test-schema.json new file mode 100644 index 00000000..c3d98d9c --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/simple-test-schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema", + "type":"object", + "additionalProperties":false, + "properties":{ + "fw": { + "type":"number" + }, + "sw": { + "type":"number" + }, + "repos": { + "type":"object", + "additionalProperties": { + "type":"string" + } + } + }, + "required": ["fw", "sw"] +} diff --git a/src/hos_libvariant/src/test/test_schema_data/simple-test.json b/src/hos_libvariant/src/test/test_schema_data/simple-test.json new file mode 100644 index 00000000..38f8eeb9 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/simple-test.json @@ -0,0 +1,14 @@ +{ + "fw": 21, + "repos": { + "abc1": "f4562e9b588a 109 default tip", + "blah2": "b8a9198883cf 22 default tip", + "arg4": "686bb1a70728 1043 default tip lwlcca-development", + "mmmooo": "heads/lwlcca-0-ge679eade196c", + "aaaaaa": "ac7006fded4e 519 default tip", + "....s;iodufhaj": "1e63ee2e1813 568 default tip", + "ufksdid": "b563665d4a02 17 default tip", + "naaa": "5a7cd1abfd8e 59 default tip" + }, + "sw": 21 +} diff --git a/src/hos_libvariant/src/test/test_schema_data/test_resolveuri.json b/src/hos_libvariant/src/test/test_schema_data/test_resolveuri.json new file mode 100644 index 00000000..3e59369b --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/test_resolveuri.json @@ -0,0 +1,203 @@ +[ +/* These tests where taken verbatim from: +// http://skew.org/uri/uri_tests.html#absoluteizeURI +// They are in the format of reference, base, expected result +// ends in a empty string +These where then modified for the slightly different behavior we want +regarding .. segments. +*/ +"","http://example.com/path?query#frag","http://example.com/path?query", +"../c","foo:a/b","foo:c", +"foo:.","foo:a","foo:", +"/foo/../../../bar","zz:abc","zz:/bar", +"/foo/../bar","zz:abc","zz:/bar", +"foo/../../../bar","zz:abc","zz:bar", +"foo/../bar","zz:abc","zz:bar", +"zz:.","zz:abc","zz:", +"/.","http://a/b/c/d;p?q","http://a/", +"/.foo","http://a/b/c/d;p?q","http://a/.foo", +".foo","http://a/b/c/d;p?q","http://a/b/c/.foo", +"g:h","http://a/b/c/d;p?q","g:h", +"g","http://a/b/c/d;p?q","http://a/b/c/g", +"./g","http://a/b/c/d;p?q","http://a/b/c/g", +"g/","http://a/b/c/d;p?q","http://a/b/c/g/", +"/g","http://a/b/c/d;p?q","http://a/g", +"//g","http://a/b/c/d;p?q","http://g", +"?y","http://a/b/c/d;p?q","http://a/b/c/d;p?y", +"g?y","http://a/b/c/d;p?q","http://a/b/c/g?y", +"#s","http://a/b/c/d;p?q","http://a/b/c/d;p?q#s", +"g#s","http://a/b/c/d;p?q","http://a/b/c/g#s", +"g?y#s","http://a/b/c/d;p?q","http://a/b/c/g?y#s", +";x","http://a/b/c/d;p?q","http://a/b/c/;x", +"g;x","http://a/b/c/d;p?q","http://a/b/c/g;x", +"g;x?y#s","http://a/b/c/d;p?q","http://a/b/c/g;x?y#s", +"","http://a/b/c/d;p?q","http://a/b/c/d;p?q", +".","http://a/b/c/d;p?q","http://a/b/c/", +"./","http://a/b/c/d;p?q","http://a/b/c/", +"..","http://a/b/c/d;p?q","http://a/b/", +"../","http://a/b/c/d;p?q","http://a/b/", +"../g","http://a/b/c/d;p?q","http://a/b/g", +"../..","http://a/b/c/d;p?q","http://a/", +"../../","http://a/b/c/d;p?q","http://a/", +"../../g","http://a/b/c/d;p?q","http://a/g", +"../../../g","http://a/b/c/d;p?q","http://a/../g", +"../../../../g","http://a/b/c/d;p?q","http://a/g", +"/./g","http://a/b/c/d;p?q","http://a/g", +"/../g","http://a/b/c/d;p?q","http://a/../g", +"g.","http://a/b/c/d;p?q","http://a/b/c/g.", +".g","http://a/b/c/d;p?q","http://a/b/c/.g", +"g..","http://a/b/c/d;p?q","http://a/b/c/g..", +"..g","http://a/b/c/d;p?q","http://a/b/c/..g", +"./../g","http://a/b/c/d;p?q","http://a/b/g", +"./g/.","http://a/b/c/d;p?q","http://a/b/c/g/", +"g/./h","http://a/b/c/d;p?q","http://a/b/c/g/h", +"g/../h","http://a/b/c/d;p?q","http://a/b/c/h", +"g;x=1/./y","http://a/b/c/d;p?q","http://a/b/c/g;x=1/y", +"g;x=1/../y","http://a/b/c/d;p?q","http://a/b/c/y", +"g?y/./x","http://a/b/c/d;p?q","http://a/b/c/g?y/./x", +"g?y/../x","http://a/b/c/d;p?q","http://a/b/c/g?y/../x", +"g#s/./x","http://a/b/c/d;p?q","http://a/b/c/g#s/./x", +"g#s/../x","http://a/b/c/d;p?q","http://a/b/c/g#s/../x", +"http:g","http://a/b/c/d;p?q","http:g", +"http:","http://a/b/c/d;p?q","http:", +"/a/b/c/./../../g","http://a/b/c/d;p?q","http://a/a/g", +"g","http://a/b/c/d;p?q=1/2","http://a/b/c/g", +"./g","http://a/b/c/d;p?q=1/2","http://a/b/c/g", +"g/","http://a/b/c/d;p?q=1/2","http://a/b/c/g/", +"/g","http://a/b/c/d;p?q=1/2","http://a/g", +"//g","http://a/b/c/d;p?q=1/2","http://g", +"?y","http://a/b/c/d;p?q=1/2","http://a/b/c/d;p?y", +"g?y","http://a/b/c/d;p?q=1/2","http://a/b/c/g?y", +"g?y/./x","http://a/b/c/d;p?q=1/2","http://a/b/c/g?y/./x", +"g?y/../x","http://a/b/c/d;p?q=1/2","http://a/b/c/g?y/../x", +"g#s","http://a/b/c/d;p?q=1/2","http://a/b/c/g#s", +"g#s/./x","http://a/b/c/d;p?q=1/2","http://a/b/c/g#s/./x", +"g#s/../x","http://a/b/c/d;p?q=1/2","http://a/b/c/g#s/../x", +"./","http://a/b/c/d;p?q=1/2","http://a/b/c/", +"../","http://a/b/c/d;p?q=1/2","http://a/b/", +"../g","http://a/b/c/d;p?q=1/2","http://a/b/g", +"../../","http://a/b/c/d;p?q=1/2","http://a/", +"../../g","http://a/b/c/d;p?q=1/2","http://a/g", +"g","http://a/b/c/d;p=1/2?q","http://a/b/c/d;p=1/g", +"./g","http://a/b/c/d;p=1/2?q","http://a/b/c/d;p=1/g", +"g/","http://a/b/c/d;p=1/2?q","http://a/b/c/d;p=1/g/", +"g?y","http://a/b/c/d;p=1/2?q","http://a/b/c/d;p=1/g?y", +";x","http://a/b/c/d;p=1/2?q","http://a/b/c/d;p=1/;x", +"g;x","http://a/b/c/d;p=1/2?q","http://a/b/c/d;p=1/g;x", +"g;x=1/./y","http://a/b/c/d;p=1/2?q","http://a/b/c/d;p=1/g;x=1/y", +"g;x=1/../y","http://a/b/c/d;p=1/2?q","http://a/b/c/d;p=1/y", +"./","http://a/b/c/d;p=1/2?q","http://a/b/c/d;p=1/", +"../","http://a/b/c/d;p=1/2?q","http://a/b/c/", +"../g","http://a/b/c/d;p=1/2?q","http://a/b/c/g", +"../../","http://a/b/c/d;p=1/2?q","http://a/b/", +"../../g","http://a/b/c/d;p=1/2?q","http://a/b/g", +"g:h","fred:///s//a/b/c","g:h", +"g","fred:///s//a/b/c","fred:///s//a/b/g", +"./g","fred:///s//a/b/c","fred:///s//a/b/g", +"g/","fred:///s//a/b/c","fred:///s//a/b/g/", +"/g","fred:///s//a/b/c","fred:///g", +"//g","fred:///s//a/b/c","fred://g", +"//g/x","fred:///s//a/b/c","fred://g/x", +"///g","fred:///s//a/b/c","fred:///g", +"./","fred:///s//a/b/c","fred:///s//a/b/", +"../","fred:///s//a/b/c","fred:///s//a/", +"../g","fred:///s//a/b/c","fred:///s//a/g", +"../../","fred:///s//a/b/c","fred:///s//", +"../../g","fred:///s//a/b/c","fred:///s//g", +"../../../g","fred:///s//a/b/c","fred:///s/g", +"../../../../g","fred:///s//a/b/c","fred:///g", +"g:h","http:///s//a/b/c","g:h", +"g","http:///s//a/b/c","http:///s//a/b/g", +"./g","http:///s//a/b/c","http:///s//a/b/g", +"g/","http:///s//a/b/c","http:///s//a/b/g/", +"/g","http:///s//a/b/c","http:///g", +"//g","http:///s//a/b/c","http://g", +"//g/x","http:///s//a/b/c","http://g/x", +"///g","http:///s//a/b/c","http:///g", +"./","http:///s//a/b/c","http:///s//a/b/", +"../","http:///s//a/b/c","http:///s//a/", +"../g","http:///s//a/b/c","http:///s//a/g", +"../../","http:///s//a/b/c","http:///s//", +"../../g","http:///s//a/b/c","http:///s//g", +"../../../g","http:///s//a/b/c","http:///s/g", +"../../../../g","http:///s//a/b/c","http:///g", +"bar:abc","foo:xyz","bar:abc", +"../abc","http://example/x/y/z","http://example/x/abc", +"http://example/x/abc","http://example2/x/y/z","http://example/x/abc", +"../r","http://ex/x/y/z","http://ex/x/r", +"q/r","http://ex/x/y","http://ex/x/q/r", +"q/r#s","http://ex/x/y","http://ex/x/q/r#s", +"q/r#s/t","http://ex/x/y","http://ex/x/q/r#s/t", +"ftp://ex/x/q/r","http://ex/x/y","ftp://ex/x/q/r", +"","http://ex/x/y","http://ex/x/y", +"","http://ex/x/y/","http://ex/x/y/", +"","http://ex/x/y/pdq","http://ex/x/y/pdq", +"z/","http://ex/x/y/","http://ex/x/y/z/", +"#Animal","file:/swap/test/animal.rdf","file:/swap/test/animal.rdf#Animal", +"../abc","file:/e/x/y/z","file:/e/x/abc", +"/example/x/abc","file:/example2/x/y/z","file:/example/x/abc", +"../r","file:/ex/x/y/z","file:/ex/x/r", +"/r","file:/ex/x/y/z","file:/r", +"q/r","file:/ex/x/y","file:/ex/x/q/r", +"q/r#s","file:/ex/x/y","file:/ex/x/q/r#s", +"q/r#","file:/ex/x/y","file:/ex/x/q/r#", +"q/r#s/t","file:/ex/x/y","file:/ex/x/q/r#s/t", +"ftp://ex/x/q/r","file:/ex/x/y","ftp://ex/x/q/r", +"","file:/ex/x/y","file:/ex/x/y", +"","file:/ex/x/y/","file:/ex/x/y/", +"","file:/ex/x/y/pdq","file:/ex/x/y/pdq", +"z/","file:/ex/x/y/","file:/ex/x/y/z/", +"file://meetings.example.com/cal#m1","file:/devel/WWW/2000/10/swap/test/reluri-1.n3","file://meetings.example.com/cal#m1", +"file://meetings.example.com/cal#m1","file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3","file://meetings.example.com/cal#m1", +"./#blort","file:/some/dir/foo","file:/some/dir/#blort", +"./#","file:/some/dir/foo","file:/some/dir/#", +"./","http://example/x/abc.efg","http://example/x/", +"//example/x/abc","http://example2/x/y/z","http://example/x/abc", +"/r","http://ex/x/y/z","http://ex/r", +"./q:r","http://ex/x/y","http://ex/x/q:r", +"./p=q:r","http://ex/x/y","http://ex/x/p=q:r", +"?pp/rr","http://ex/x/y?pp/qq","http://ex/x/y?pp/rr", +"y/z","http://ex/x/y?pp/qq","http://ex/x/y/z", +"local/qual@domain.org#frag","mailto:local","mailto:local/qual@domain.org#frag", +"more/qual2@domain2.org#frag","mailto:local/qual1@domain1.org","mailto:local/more/qual2@domain2.org#frag", +"y?q","http://ex/x/y?q","http://ex/x/y?q", +"/x/y?q","http://ex?p","http://ex/x/y?q", +"c/d","foo:a/b","foo:a/c/d", +"/c/d","foo:a/b","foo:/c/d", +"","foo:a/b?c#d","foo:a/b?c", +"b/c","foo:a","foo:b/c", +"../b/c","foo:/a/y/z","foo:/a/b/c", +"./b/c","foo:a","foo:b/c", +"/./b/c","foo:a","foo:/b/c", +"../../d","foo://a//b/c","foo://a/d", +".","foo:a","foo:", +"..","foo:a","foo:..", +"abc","http://example/x/y%2Fz","http://example/x/abc", +"../../x%2Fabc","http://example/a/x/y/z","http://example/a/x%2Fabc", +"../x%2Fabc","http://example/a/x/y%2Fz","http://example/a/x%2Fabc", +"abc","http://example/x%2Fy/z","http://example/x%2Fy/abc", +"q%3Ar","http://ex/x/y","http://ex/x/q%3Ar", +"/x%2Fabc","http://example/x/y%2Fz","http://example/x%2Fabc", +"/x%2Fabc","http://example/x/y/z","http://example/x%2Fabc", +"local2@domain2","mailto:local1@domain1?query1","mailto:local2@domain2", +"local2@domain2?query2","mailto:local1@domain1","mailto:local2@domain2?query2", +"local2@domain2?query2","mailto:local1@domain1?query1","mailto:local2@domain2?query2", +"?query2","mailto:local@domain?query1","mailto:local@domain?query2", +"local@domain?query2","mailto:?query1","mailto:local@domain?query2", +"?query2","mailto:local@domain?query1","mailto:local@domain?query2", +"http://example/a/b?c/../d","foo:bar","http://example/a/b?c/../d", +"http://example/a/b#c/../d","foo:bar","http://example/a/b#c/../d", +"http:this","http://example.org/base/uri","http:this", +"http:this","http:base","http:this", +".//g","f:/a","f://g", +"b/c//d/e","f://example.org/base/a","f://example.org/base/b/c//d/e", +"m2@example.ord/c2@example.org","mid:m@example.ord/c@example.org","mid:m@example.ord/m2@example.ord/c2@example.org", +"mini1.xml","file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/","file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/mini1.xml", +"../b/c","foo:a/y/z","foo:a/b/c", +"b","foo:","foo:b", +"b","foo://a","foo://a/b", +"b","foo://a?q","foo://a/b", +"b?q","foo://a","foo://a/b?q", +"b?q","foo://a?r","foo://a/b?q", +"", "", "" +] diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/01-type.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/01-type.test new file mode 100644 index 00000000..78c4d842 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/01-type.test @@ -0,0 +1,46 @@ +[ + { + "name": "no type specified", + "data": {}, + "schema": {} + }, + { + "name": "must be object, is object", + "data": {}, + "schema": { "type": "object" } + }, + { + "name": "must be object or string, is object", + "data": {}, + "schema": { "type": ["object", "string"] } + }, + { + "name": "must be object or string, is array", + "data": [], + "schema": { "type": ["object", "string"] }, + "fail": true + }, + { + "name": "must be array, is object", + "data": {}, + "schema": { "type": ["array"] }, + "fail": true + }, + { + "name": "must be string, is integer", + "data": 5, + "schema": {"type": ["string"] }, + "fail": true + }, + { + "name": "must be object, is null", + "data": null, + "schema": { "type": ["object"] }, + "fail": true + }, + { + "name": "must be null, is null", + "data": null, + "schema": { "type": "null" } + } +] diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/02-enum.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/02-enum.test new file mode 100644 index 00000000..c8c533b1 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/02-enum.test @@ -0,0 +1 @@ +[{"data": 1, "name": "enum [1], was 1", "schema": {"enum": [1]}}, {"fail": true, "data": "1", "name": "enum[1], was \"1\"", "schema": {"enum": [1]}}, {"data": {}, "name": "enum [{}], was {}", "schema": {"enum": [{}]}}, {"fail": true, "data": {}, "name": "enum [{\"key\":\"value\"}], was {}", "schema": {"enum": [{"key": "value"}]}}, {"fail": false, "data": {"key": "value"}, "name": "enum [{\"key\":\"value\", was {\"key\": \"value\"}", "schema": {"enum": [{"key": "value"}]}}, {"fail": false, "data": [1, true, 0], "name": "Enum with array value - success", "schema": {"enum": [[1, true, 0], 5, {}]}}, {"fail": true, "data": [1, true, 0, 5], "name": "Enum with array value - failure 1", "schema": {"enum": [[1, true, 0], 5, {}]}}, {"fail": true, "data": [1, true, 5], "name": "Enum with array value - failure 2", "schema": {"enum": [[1, true, 0], 5, {}]}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/02-enum.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/02-enum.yaml new file mode 100644 index 00000000..f8f3d20b --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/02-enum.yaml @@ -0,0 +1,30 @@ +- name: enum [1], was 1 + data: 1 + schema: { enum: [1] } +- name: enum[1], was "1" + data: "1" + schema: { enum: [1] } + fail: true +- name: enum [{}], was {} + data: {} + schema: { enum: [{}] } +- name: enum [{"key":"value"}], was {} + data: {} + schema: { enum: [{ key: value}] } + fail: true +- name: 'enum [{"key":"value", was {"key": "value"}' + data: { key: value } + schema: { enum: [{ key: value }] } + fail: false +- name: Enum with array value - success + data: [ 1, true, 0] + schema: { enum: [[1, true, 0], 5, {}] } + fail: false +- name: Enum with array value - failure 1 + data: [1, true, 0, 5] + schema: { enum: [[1, true, 0], 5, {}] } + fail: true +- name: Enum with array value - failure 2 + data: [1, true, 5] + schema: { enum: [[1, true, 0], 5, {}] } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/Makefile b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/Makefile new file mode 100644 index 00000000..91c369e5 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/01-any-type/Makefile @@ -0,0 +1,5 @@ + +tests: 02-enum.test + +02-enum.test: 02-enum.yaml + python -c "import json; import yaml; import sys; json.dump(yaml.load(sys.stdin), sys.stdout);" < $< > $@ diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/01-min-max.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/01-min-max.test new file mode 100644 index 00000000..45f121dd --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/01-min-max.test @@ -0,0 +1 @@ +[{"data": 5, "name": "minimum success", "schema": {"minimum": 2.5}}, {"fail": true, "data": 5, "name": "minimum failure", "schema": {"minimum": 7}}, {"data": 5, "name": "minimum equality success", "schema": {"minimum": 5}}, {"fail": true, "data": 5, "name": "minimum equality failure", "schema": {"minimum": 5, "exclusiveMinimum": true}}, {"data": 5, "name": "maximum success", "schema": {"maximum": 7}}, {"fail": true, "data": -5, "name": "maximum failure", "schema": {"maximum": -7}}, {"data": 5, "name": "exclusive maximum success", "schema": {"maximum": 5}}, {"fail": true, "data": 5, "name": "exclusive maximum failure", "schema": {"exclusiveMaximum": true, "maximum": 5}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/01-min-max.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/01-min-max.yaml new file mode 100644 index 00000000..89390321 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/01-min-max.yaml @@ -0,0 +1,28 @@ +- name: minimum success + data: 5 + schema: { minimum: 2.5 } +- name: minimum failure + data: 5 + schema: { minimum: 7 } + fail: true +- name: minimum equality success + data: 5 + schema: { minimum: 5 } +- name: minimum equality failure + data: 5 + schema: { minimum: 5, exclusiveMinimum: true } + fail: true +- name: maximum success + data: 5 + schema: { maximum: 7 } +- name: maximum failure + data: -5 + schema: { maximum: -7 } + fail: true +- name: exclusive maximum success + data: 5 + schema: { maximum: 5 } +- name: exclusive maximum failure + data: 5 + schema: { maximum: 5, exclusiveMaximum: true } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/02-multipleOf.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/02-multipleOf.test new file mode 100644 index 00000000..f7b0e24a --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/02-multipleOf.test @@ -0,0 +1 @@ +[{"data": 5, "name": "multipleOf", "schema": {"multipleOf": 2.5}}, {"fail": true, "data": 5, "name": "multipleOf failure", "schema": {"multipleOf": 0.75}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/02-multipleOf.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/02-multipleOf.yaml new file mode 100644 index 00000000..ba0fc6aa --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/02-multipleOf.yaml @@ -0,0 +1,7 @@ +- name: multipleOf + data: 5 + schema: { multipleOf: 2.5 } +- name: multipleOf failure + data: 5 + schema: { multipleOf: 0.75 } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/Makefile b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/Makefile new file mode 100644 index 00000000..a4899796 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/02-numeric/Makefile @@ -0,0 +1,9 @@ + +TARGETS := $(patsubst %.yaml,%.test,$(wildcard *.yaml)) + +tests: $(TARGETS) + + +%.test: %.yaml + python -c "import json; import yaml; import sys; json.dump(yaml.load(sys.stdin), sys.stdout);" < $< > $@ + diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/01-min-max-length.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/01-min-max-length.test new file mode 100644 index 00000000..ba630590 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/01-min-max-length.test @@ -0,0 +1 @@ +[{"data": "test", "name": "no length constraints", "schema": {}}, {"data": "test", "name": "minimum length success", "schema": {"minLength": 3}}, {"fail": true, "data": "test", "name": "min length failure", "schema": {"minLength": 5}}, {"data": "test1234", "name": "maximum length success", "schema": {"maxLength": 10}}, {"fail": true, "data": "test1234", "name": "maximum length failure", "schema": {"maxLength": 5}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/01-min-max-length.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/01-min-max-length.yaml new file mode 100644 index 00000000..c32d4c70 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/01-min-max-length.yaml @@ -0,0 +1,17 @@ +- name: no length constraints + data: test + schema: {} +- name: minimum length success + data: test + schema: { minLength: 3 } +- name: min length failure + data: test + schema: { minLength: 5 } + fail: true +- name: maximum length success + data: test1234 + schema: { maxLength: 10 } +- name: maximum length failure + data: test1234 + schema: { maxLength: 5 } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/02-pattern.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/02-pattern.test new file mode 100644 index 00000000..5ac7fa12 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/02-pattern.test @@ -0,0 +1 @@ +[{"data": "9test", "name": "pattern success", "schema": {"pattern": "^[0-9][a-zA-Z]*$"}}, {"fail": true, "data": "9test9", "name": "pattern failure", "schema": {"pattern": "^[0-9][a-zA-Z]*$"}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/02-pattern.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/02-pattern.yaml new file mode 100644 index 00000000..bfe04876 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/02-pattern.yaml @@ -0,0 +1,7 @@ +- name: pattern success + data: 9test + schema: { pattern: "^[0-9][a-zA-Z]*$" } +- name: pattern failure + data: 9test9 + schema: { pattern: "^[0-9][a-zA-Z]*$" } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/Makefile b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/Makefile new file mode 100644 index 00000000..a4899796 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/03-strings/Makefile @@ -0,0 +1,9 @@ + +TARGETS := $(patsubst %.yaml,%.test,$(wildcard *.yaml)) + +tests: $(TARGETS) + + +%.test: %.yaml + python -c "import json; import yaml; import sys; json.dump(yaml.load(sys.stdin), sys.stdout);" < $< > $@ + diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/01-min-max-length.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/01-min-max-length.test new file mode 100644 index 00000000..c7369388 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/01-min-max-length.test @@ -0,0 +1 @@ +[{"data": [1, 2, 3], "name": "no length contraints", "schema": {}}, {"data": [1, 2, 3], "name": "minimum length success", "schema": {"minItems": 3}}, {"fail": true, "data": [1, 2, 3], "name": "minimum length failure", "schema": {"minItems": 5}}, {"data": [1, 2, 3, 4, 5], "name": "maximum length success", "schema": {"maxItems": 10}}, {"fail": true, "data": [1, 2, 3, 4, 5], "name": "maximum length failure", "schema": {"maxItems": 3}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/01-min-max-length.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/01-min-max-length.yaml new file mode 100644 index 00000000..a399502c --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/01-min-max-length.yaml @@ -0,0 +1,17 @@ +- name: no length contraints + data: [1,2,3] + schema: {} +- name: minimum length success + data: [1,2,3] + schema: { minItems: 3 } +- name: minimum length failure + data: [1,2,3] + schema: { minItems: 5 } + fail: true +- name: maximum length success + data: [1,2,3,4,5] + schema: { maxItems: 10 } +- name: maximum length failure + data: [1,2,3,4,5] + schema: { maxItems: 3 } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/02-uniqueitems.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/02-uniqueitems.test new file mode 100644 index 00000000..30ee13a0 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/02-uniqueitems.test @@ -0,0 +1 @@ +[{"data": [1, true, "1"], "name": "uniqueItems success", "schema": {"uniqueItems": true}}, {"fail": true, "data": [1, true, "1", 1], "name": "uniqueItems failure", "schema": {"uniqueItems": true}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/02-uniqueitems.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/02-uniqueitems.yaml new file mode 100644 index 00000000..8cf319c4 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/02-uniqueitems.yaml @@ -0,0 +1,7 @@ +- name: uniqueItems success + data: [1, true, "1"] + schema: { uniqueItems: true } +- name: uniqueItems failure + data: [1, true, "1", 1] + schema: { uniqueItems: true } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/03-items-plain.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/03-items-plain.test new file mode 100644 index 00000000..bf60b9b9 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/03-items-plain.test @@ -0,0 +1 @@ +[{"data": [1, 2, 3, 4], "name": "plain item success", "schema": {"items": {"type": "integer"}}}, {"fail": true, "data": [1, 2, true, 4], "name": "plain item failure", "schema": {"items": {"type": "integer"}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/03-items-plain.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/03-items-plain.yaml new file mode 100644 index 00000000..16930d55 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/03-items-plain.yaml @@ -0,0 +1,7 @@ +- name: plain item success + data: [1,2,3,4] + schema: { items: { type: integer } } +- name: plain item failure + data: [1,2,true,4] + schema: { items: { type: integer } } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/04-items-tuple-typing.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/04-items-tuple-typing.test new file mode 100644 index 00000000..77084821 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/04-items-tuple-typing.test @@ -0,0 +1 @@ +[{"data": [1, true, "one"], "name": "items success", "schema": {"items": [{"type": "integer"}, {"type": "boolean"}]}}, {"fail": true, "data": [1, null, "one"], "name": "items failure", "schema": {"items": [{"type": "integer"}, {"type": "boolean"}]}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/04-items-tuple-typing.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/04-items-tuple-typing.yaml new file mode 100644 index 00000000..89850307 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/04-items-tuple-typing.yaml @@ -0,0 +1,7 @@ +- name: items success + data: [1, true, "one"] + schema: { items: [ { type: integer} , { type: boolean } ] } +- name: items failure + data: [1, null, "one"] + schema: { items: [ { type: integer} , { type: boolean } ] } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/05-additionalitems.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/05-additionalitems.test new file mode 100644 index 00000000..f7c59a57 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/05-additionalitems.test @@ -0,0 +1 @@ +[{"data": [1, true, "one", "uno"], "name": "additional items schema success", "schema": {"items": [{"type": "integer"}, {"type": "boolean"}], "additionalItems": {"type": "string"}}}, {"fail": true, "data": [1, true, "one", 1], "name": "additional items schema failure", "schema": {"items": [{"type": "integer"}, {"type": "boolean"}], "additionalItems": {"type": "string"}}}, {"data": [1, true, "one", "uno"], "name": "additional items boolean success", "schema": {"items": [{"type": "integer"}, {"type": "boolean"}], "additionalItems": true}}, {"fail": true, "data": [1, true, "one", "uno"], "name": "additional items boolean failure", "schema": {"items": [{"type": "integer"}, {"type": "boolean"}], "additionalItems": false}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/05-additionalitems.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/05-additionalitems.yaml new file mode 100644 index 00000000..ee6ad935 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/05-additionalitems.yaml @@ -0,0 +1,31 @@ +- name: additional items schema success + data: [1, true, "one", "uno"] + schema: + items: + - type: integer + - type: boolean + additionalItems: { type: string } +- name: additional items schema failure + data: [1, true, "one", 1] + schema: + items: + - type: integer + - type: boolean + additionalItems: { type: string } + fail: true +- name: additional items boolean success + data: [1, true, "one", "uno"] + schema: + items: + - type: integer + - type: boolean + additionalItems: true +- name: additional items boolean failure + data: [1, true, "one", "uno"] + schema: + items: + - type: integer + - type: boolean + additionalItems: false + fail: true + diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/Makefile b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/Makefile new file mode 100644 index 00000000..a4899796 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/04-arrays/Makefile @@ -0,0 +1,9 @@ + +TARGETS := $(patsubst %.yaml,%.test,$(wildcard *.yaml)) + +tests: $(TARGETS) + + +%.test: %.yaml + python -c "import json; import yaml; import sys; json.dump(yaml.load(sys.stdin), sys.stdout);" < $< > $@ + diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/01-min-max-properties.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/01-min-max-properties.test new file mode 100644 index 00000000..9eecafed --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/01-min-max-properties.test @@ -0,0 +1 @@ +[{"data": {"key3": 3, "key2": 2, "key": 1}, "name": "minimum length success", "schema": {"minProperties": 3}}, {"fail": true, "data": {"key3": 3, "key2": 2, "key": 1}, "name": "minimum length failure", "schema": {"minProperties": 5}}, {"data": {"key3": 3, "key2": 2, "key": 1}, "name": "maximum length success", "schema": {"maxProperties": 5}}, {"fail": true, "data": {"key3": 3, "key2": 2, "key": 1}, "name": "maximum length failure", "schema": {"maxProperties": 2}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/01-min-max-properties.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/01-min-max-properties.yaml new file mode 100644 index 00000000..01151718 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/01-min-max-properties.yaml @@ -0,0 +1,14 @@ +- name: minimum length success + data: { key: 1, key2: 2, key3: 3 } + schema: { minProperties: 3 } +- name: minimum length failure + data: { key: 1, key2: 2, key3: 3 } + schema: { minProperties: 5 } + fail: true +- name: maximum length success + data: { key: 1, key2: 2, key3: 3 } + schema: { maxProperties: 5 } +- name: maximum length failure + data: { key: 1, key2: 2, key3: 3 } + schema: { maxProperties: 2 } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/02-required.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/02-required.test new file mode 100644 index 00000000..c33d9b7d --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/02-required.test @@ -0,0 +1 @@ +[{"data": {"key3": 3, "key2": 2, "key1": 1}, "name": "required success", "schema": {"required": ["key1", "key2"]}}, {"fail": true, "data": {"key3": 3, "key2": 2, "key1": 1}, "name": "required failure", "schema": {"required": ["key1", "notDefined"]}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/02-required.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/02-required.yaml new file mode 100644 index 00000000..0acc7e51 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/02-required.yaml @@ -0,0 +1,7 @@ +- name: required success + data: { key1: 1, key2: 2, key3: 3 } + schema: { required: [ key1, key2 ] } +- name: required failure + data: { key1: 1, key2: 2, key3: 3 } + schema: { required: [ key1, notDefined ] } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/03-properties.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/03-properties.test new file mode 100644 index 00000000..84cd7400 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/03-properties.test @@ -0,0 +1 @@ +[{"data": {"stringKey": "one", "intKey": 1}, "name": "properties success", "schema": {"properties": {"stringKey": {"type": "string"}, "intKey": {"type": "integer"}}}}, {"fail": true, "data": {"stringKey": false, "intKey": 1}, "name": "properties failure", "schema": {"properties": {"stringKey": {"type": "string"}, "intKey": {"type": "integer"}}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/03-properties.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/03-properties.yaml new file mode 100644 index 00000000..024d09eb --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/03-properties.yaml @@ -0,0 +1,13 @@ +- name: properties success + data: { intKey: 1, stringKey: "one" } + schema: + properties: + intKey: { type: integer } + stringKey: { type: string } +- name: properties failure + data: { intKey: 1, stringKey: false } + schema: + properties: + intKey: { type: integer } + stringKey: { type: string } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/04-patternproperties.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/04-patternproperties.test new file mode 100644 index 00000000..2b911b39 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/04-patternproperties.test @@ -0,0 +1 @@ +[{"data": {"intKey2": 5, "intKey": 1}, "name": "patternProperties success", "schema": {"patternProperties": {"^int": {"minimum": 0}}, "properties": {"intKey": {"type": "integer"}}}}, {"fail": true, "data": {"intKey2": 5, "intKey": 1}, "name": "patternProperties failure 1", "schema": {"patternProperties": {"^int": {"type": "integer"}}, "properties": {"intKey": {"minimum": 5}}}}, {"fail": true, "data": {"intKey2": "string value", "intkey": 10}, "name": "patternProperties failure 2", "schema": {"patternProperties": {"^int": {"type": "integer"}}, "properties": {"intKey": {"minimum": 5}}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/04-patternproperties.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/04-patternproperties.yaml new file mode 100644 index 00000000..d4beb524 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/04-patternproperties.yaml @@ -0,0 +1,23 @@ +- name: patternProperties success + data: { intKey: 1, intKey2: 5 } + schema: + properties: + intKey: { type: integer } + patternProperties: + "^int": { minimum: 0 } +- name: patternProperties failure 1 + data: { intKey: 1, intKey2: 5 } + schema: + properties: + intKey: { minimum: 5 } + patternProperties: + "^int": { type: integer } + fail: true +- name: patternProperties failure 2 + data: { intkey: 10, intKey2: "string value" } + schema: + properties: + intKey: { minimum: 5 } + patternProperties: + "^int": { type: integer } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/05-additionalproperties.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/05-additionalproperties.test new file mode 100644 index 00000000..2d5f0bc4 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/05-additionalproperties.test @@ -0,0 +1 @@ +[{"data": {"stringKey": "string", "intKey2": 5, "intKey": 1}, "name": "additionalProperties schema success", "schema": {"additionalProperties": {"type": "string"}, "patternProperties": {"^int": {"minimum": 0}}, "properties": {"intKey": {"type": "integer"}}}}, {"fail": true, "data": {"stringKey": null, "intKey2": 5, "intKey": 10}, "name": "additionalProperties schema failure", "schema": {"additionalProperties": {"type": "string"}, "patternProperties": {"^int": {"type": "integer"}}, "properties": {"intKey": {"minimum": 5}}}}, {"data": {"stringKey": null, "intKey2": 5, "intKey": 10}, "name": "additionalProperties boolean success", "schema": {"additionalProperties": true, "patternProperties": {"^int": {"type": "integer"}}, "properties": {"intKey": {"minimum": 5}}}}, {"fail": true, "data": {"stringKey": null, "intKey2": 5, "intKey": 10}, "name": "additionalProperties boolean failure", "schema": {"additionalProperties": false, "patternProperties": {"^int": {"type": "integer"}}, "properties": {"intKey": {"minimum": 5}}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/05-additionalproperties.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/05-additionalproperties.yaml new file mode 100644 index 00000000..f3fb4fbd --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/05-additionalproperties.yaml @@ -0,0 +1,34 @@ +- name: additionalProperties schema success + data: { intKey: 1, intKey2: 5, stringKey: string } + schema: + properties: + intKey: { type: integer } + patternProperties: + "^int": { minimum: 0 } + additionalProperties: { type: string } +- name: additionalProperties schema failure + data: { intKey: 10, intKey2: 5, stringKey: null } + schema: + properties: + intKey: { minimum: 5 } + patternProperties: + "^int": { type: integer } + additionalProperties: { type: string } + fail: true +- name: additionalProperties boolean success + data: { intKey: 10, intKey2: 5, stringKey: null } + schema: + properties: + intKey: { minimum: 5 } + patternProperties: + "^int": { type: integer } + additionalProperties: true +- name: additionalProperties boolean failure + data: { intKey: 10, intKey2: 5, stringKey: null } + schema: + properties: + intKey: { minimum: 5 } + patternProperties: + "^int": { type: integer } + additionalProperties: false + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/06-dependencies.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/06-dependencies.test new file mode 100644 index 00000000..2a4c7600 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/06-dependencies.test @@ -0,0 +1 @@ +[{"data": {"key2": "string", "key1": 5}, "name": "string dependency success", "schema": {"dependencies": {"key1": "key2"}}}, {"fail": true, "data": {"key1": 5}, "name": "string dependency failure", "schema": {"dependencies": {"key1": "key2"}}}, {"data": {"key2": "string", "key1": 5}, "name": "array dependency success", "schema": {"dependencies": {"key1": ["key2"]}}}, {"fail": true, "data": {"key1": 5}, "name": "array dependency failure", "schema": {"dependencies": {"key1": ["key2"]}}}, {"data": {"key2": "string", "key1": 5}, "name": "schema dependency success", "schema": {"dependencies": {"key1": {"properties": {"key2": {"type": "string"}}}}}}, {"fail": true, "data": {"key2": 5, "key1": 5}, "name": "schema dependency failure", "schema": {"dependencies": {"key1": {"properties": {"key2": {"type": "string"}}}}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/06-dependencies.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/06-dependencies.yaml new file mode 100644 index 00000000..e33a7d81 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/06-dependencies.yaml @@ -0,0 +1,21 @@ +- name: string dependency success + data: { key1: 5, key2: string } + schema: { dependencies: { key1: key2 } } +- name: string dependency failure + data: { key1: 5 } + schema: { dependencies: { key1: key2 } } + fail: true +- name: array dependency success + data: { key1: 5, key2: string } + schema: { dependencies: { key1: [ key2 ] } } +- name: array dependency failure + data: { key1: 5 } + schema: { dependencies: { key1: [ key2 ] } } + fail: true +- name: schema dependency success + data: { key1: 5, key2: string } + schema: { dependencies: { key1: { properties: { key2: { type: string } } } } } +- name: schema dependency failure + data: { key1: 5, key2: 5 } + schema: { dependencies: { key1: { properties: { key2: { type: string } } } } } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/Makefile b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/Makefile new file mode 100644 index 00000000..a4899796 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/05-objects/Makefile @@ -0,0 +1,9 @@ + +TARGETS := $(patsubst %.yaml,%.test,$(wildcard *.yaml)) + +tests: $(TARGETS) + + +%.test: %.yaml + python -c "import json; import yaml; import sys; json.dump(yaml.load(sys.stdin), sys.stdout);" < $< > $@ + diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/01-allOf.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/01-allOf.test new file mode 100644 index 00000000..c2da9972 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/01-allOf.test @@ -0,0 +1 @@ +[{"data": 10, "name": "allOf success", "schema": {"allOf": [{"type": "integer"}, {"minimum": 5}]}}, {"fail": true, "data": 1, "name": "allOf failure", "schema": {"allOf": [{"type": "integer"}, {"minimum": 5}]}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/01-allOf.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/01-allOf.yaml new file mode 100644 index 00000000..47673f6b --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/01-allOf.yaml @@ -0,0 +1,13 @@ +- name: allOf success + data: 10 + schema: + allOf: + - type: integer + - minimum: 5 +- name: allOf failure + data: 1 + schema: + allOf: + - type: integer + - minimum: 5 + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/02-anyOf.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/02-anyOf.test new file mode 100644 index 00000000..8215a2ba --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/02-anyOf.test @@ -0,0 +1 @@ +[{"data": "hello", "name": "anyOf success", "schema": {"anyOf": [{"type": "integer"}, {"type": "string"}, {"minlength": 1}]}}, {"fail": true, "data": true, "name": "anyOf failure", "schema": {"anyOf": [{"type": "integer"}, {"type": "string"}]}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/02-anyOf.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/02-anyOf.yaml new file mode 100644 index 00000000..708f3ed7 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/02-anyOf.yaml @@ -0,0 +1,14 @@ +- name: anyOf success + data: hello + schema: + anyOf: + - type: integer + - type: string + - minlength: 1 +- name: anyOf failure + data: true + schema: + anyOf: + - type: integer + - type: string + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/03-oneOf.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/03-oneOf.test new file mode 100644 index 00000000..6142b60b --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/03-oneOf.test @@ -0,0 +1 @@ +[{"data": 5, "name": "oneOf success", "schema": {"oneOf": [{"type": "integer"}, {"type": "string"}, {"minLength": 1, "type": "string"}]}}, {"fail": true, "data": "string", "name": "oneOf failure (too many)", "schema": {"oneOf": [{"type": "integer"}, {"type": "string"}, {"minLength": 1, "type": "string"}]}}, {"fail": true, "data": false, "name": "oneOf failure (no matches)", "schema": {"oneOf": [{"type": "integer"}, {"type": "string"}, {"minLength": 1, "type": "string"}]}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/03-oneOf.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/03-oneOf.yaml new file mode 100644 index 00000000..259e2597 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/03-oneOf.yaml @@ -0,0 +1,23 @@ +- name: oneOf success + data: 5 + schema: + oneOf: + - type: integer + - type: string + - { type: string, minLength: 1 } +- name: oneOf failure (too many) + data: string + schema: + oneOf: + - type: integer + - type: string + - { type: string, minLength: 1 } + fail: true +- name: oneOf failure (no matches) + data: false + schema: + oneOf: + - type: integer + - type: string + - { type: string, minLength: 1 } + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/04-not.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/04-not.test new file mode 100644 index 00000000..0589f2fd --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/04-not.test @@ -0,0 +1 @@ +[{"data": 5, "name": "not success", "schema": {"not": {"type": "string"}}}, {"fail": true, "data": "test", "name": "not failure", "schema": {"not": {"type": "string"}}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/04-not.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/04-not.yaml new file mode 100644 index 00000000..89774327 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/04-not.yaml @@ -0,0 +1,11 @@ +- name: not success + data: 5 + schema: + not: + type: string +- name: not failure + data: test + schema: + not: + type: string + fail: true diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/Makefile b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/Makefile new file mode 100644 index 00000000..a4899796 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/06-combinations/Makefile @@ -0,0 +1,9 @@ + +TARGETS := $(patsubst %.yaml,%.test,$(wildcard *.yaml)) + +tests: $(TARGETS) + + +%.test: %.yaml + python -c "import json; import yaml; import sys; json.dump(yaml.load(sys.stdin), sys.stdout);" < $< > $@ + diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/04-ref.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/04-ref.test new file mode 100644 index 00000000..4df30aeb --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/04-ref.test @@ -0,0 +1 @@ +[{"data": [[], [[]]], "name": "internal $ref 1", "schema": {"items": {"$ref": "#"}, "type": "array"}}, {"fail": true, "data": [1, 2, 3, 4], "name": "internal $ref 2", "schema": {"items": {"$ref": "#"}, "type": "array"}}, {"fail": true, "data": [[false], [[]]], "name": "internal $ref 2", "schema": {"items": {"$ref": "#"}, "type": "array"}}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/04-ref.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/04-ref.yaml new file mode 100644 index 00000000..819de210 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/04-ref.yaml @@ -0,0 +1,12 @@ +- name: internal $ref 1 + schema: { type: array, items: { "$ref": "#" } } + data: [[],[[]]] +- name: internal $ref 2 + schema: { type: array, items: { "$ref": "#" } } + data: [1,2,3,4] + fail: true +- name: internal $ref 2 + schema: { type: array, items: { "$ref": "#" } } + data: [[false],[[]]] + fail: true + diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/05-inline-addressing.test b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/05-inline-addressing.test new file mode 100644 index 00000000..e096a487 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/05-inline-addressing.test @@ -0,0 +1 @@ +[{"fail": true, "data": [0, false], "name": "inline addressing for fragments", "schema": {"items": {"$ref": "#test"}, "type": "array", "testSchema": {"type": "boolean", "id": "#test"}}}, {"schema": {"items": {"$ref": "other-schema"}, "type": "array", "id": "http://example.com/123/schema", "testSchema": {"type": "boolean", "id": "/other-schema"}}, "data": [0, false], "name": "don't trust non sub-paths", "missing": ["http://example.com/123/other-schema"]}] \ No newline at end of file diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/05-inline-addressing.yaml b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/05-inline-addressing.yaml new file mode 100644 index 00000000..06fdbfdb --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/05-inline-addressing.yaml @@ -0,0 +1,20 @@ +- name: inline addressing for fragments + data: [0, false] + schema: + type: array + items: { "$ref": "#test" } + testSchema: + id: "#test" + type: boolean + fail: true +- name: "don't trust non sub-paths" + data: [0, false] + schema: + id: 'http://example.com/123/schema' + type: array + items: { "$ref": "other-schema" } + testSchema: + id: "/other-schema" + type: boolean + missing: + - 'http://example.com/123/other-schema' diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/Makefile b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/Makefile new file mode 100644 index 00000000..a4899796 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/07-ref/Makefile @@ -0,0 +1,9 @@ + +TARGETS := $(patsubst %.yaml,%.test,$(wildcard *.yaml)) + +tests: $(TARGETS) + + +%.test: %.yaml + python -c "import json; import yaml; import sys; json.dump(yaml.load(sys.stdin), sys.stdout);" < $< > $@ + diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/Makefile b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/Makefile new file mode 100644 index 00000000..de57236d --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/Makefile @@ -0,0 +1,11 @@ + +all: + $(MAKE) -C 01-any-type + $(MAKE) -C 02-numeric + $(MAKE) -C 03-strings + $(MAKE) -C 04-arrays + $(MAKE) -C 05-objects + $(MAKE) -C 06-combinations + $(MAKE) -C 07-ref + + diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/README b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/README new file mode 100644 index 00000000..f7613fc4 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/README @@ -0,0 +1,4 @@ + +All the tests in this folder came from the tv4 javascript implementation. + +http://geraintluff.github.com/tv4/ diff --git a/src/hos_libvariant/src/test/test_schema_data/tv4-tests/submakefile b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/submakefile new file mode 100644 index 00000000..a4899796 --- /dev/null +++ b/src/hos_libvariant/src/test/test_schema_data/tv4-tests/submakefile @@ -0,0 +1,9 @@ + +TARGETS := $(patsubst %.yaml,%.test,$(wildcard *.yaml)) + +tests: $(TARGETS) + + +%.test: %.yaml + python -c "import json; import yaml; import sys; json.dump(yaml.load(sys.stdin), sys.stdout);" < $< > $@ + diff --git a/src/hos_libvariant/src/test/test_variant.cc b/src/hos_libvariant/src/test/test_variant.cc new file mode 100644 index 00000000..6a8c0bce --- /dev/null +++ b/src/hos_libvariant/src/test/test_variant.cc @@ -0,0 +1,744 @@ +//============================================================================= +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published +// by the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// The GNU Public License is available in the file LICENSE, or you +// can write to the Free Software Foundation, Inc., 59 Temple Place - +// Suite 330, Boston, MA 02111-1307, USA, or you can find it on the +// World Wide Web at http://www.fsf.org. +//============================================================================= +/** \file + * \author John Bridgman + * \brief A simple test for the Variant and JSONToVariant parser. + */ +#include +#include +#include +#include "TestCommon.h" +#include "TestAssert.h" +#include +#include +#include +#include +#include + +using namespace libvariant; +using namespace std; + + +void VariantTest() { + std::cout << "Testing some of Variant's functionality\n"; + + Variant null; + ASSERT(null.IsNull()); + Variant v; + v = 5; + ASSERT(!v.IsNull()); + ASSERT(v.AsInt() == 5); + ASSERT(v.AsUnsigned() == 5u); + ASSERT(v.AsDouble() == 5.0); + ASSERT(v == Variant(5)); + ASSERT(v != "5"); + Variant b = true; + ASSERT(b.IsBool()); + ASSERT(b.IsTrue()); + ASSERT(!b.IsFalse()); + b = false; + ASSERT(b.IsBool()); + ASSERT(b.IsFalse()); + ASSERT(!b.IsTrue()); + Variant map; + ASSERT(map.Empty()); + map["one"] = v; + map["two"] = "two"; + ASSERT(map["one"] == v); + ASSERT(v == map["one"]); + ASSERT(map.Empty() == false); + ASSERT(map["one"].Exists()); + ASSERT(!map["nothing"].Exists()); + ASSERT(map.Exists()); + Variant list; + ASSERT(list.GetType() == Variant::NullType); + list[0] = 1; + list[2] = "two"; + list[5] = map; + list[4] = 123u; + list[6] = 0.3535566; + ASSERT(list.GetType() == Variant::ListType); + ASSERT(!list.Empty()); + ASSERT(list.Size() == 7); + ASSERT(list[0].GetType() == Variant::IntegerType); + ASSERT(list[2].GetType() == Variant::StringType); + ASSERT(list[4].GetType() == Variant::UnsignedType); + ASSERT(list[5].GetType() == Variant::MapType); + ASSERT(list[6].GetType() == Variant::FloatType); + + ASSERT(list.Index("two") == 2); + ASSERT(list.Index("not here") == list.Size()); + + VariantRef listref = list; + ASSERT(listref.Index("two") == 2); + ASSERT(listref.Index("not here") == listref.Size()); + + try { + map.Index("abc"); + abort(); + } catch (const std::runtime_error &) {} + + try { + map.AsBool(); + abort(); + } catch (const std::runtime_error &) {} + try { + map.AsInt(); + abort(); + } catch (const std::runtime_error &) {} + try { + map.AsUnsigned(); + abort(); + } catch (const std::runtime_error &) {} + try { + map.AsLongDouble(); + abort(); + } catch (const std::runtime_error &) {} + try { + map.AsString(); + abort(); + } catch (const std::runtime_error &) {} + try { + map.AsBlob(); + abort(); + } catch (const std::runtime_error &) {} + try { + map.AsList(); + abort(); + } catch (const std::runtime_error &) {} + try { + map[1]; + abort(); + } catch (const std::runtime_error &) {} + try { + list.AsMap(); + abort(); + } catch (const std::runtime_error &) {} + try { + list["test"]; + abort(); + } catch (const std::runtime_error &) {} + try { + b.Size(); + abort(); + } catch (const std::runtime_error &) {} + ASSERT(b.IsBool()); + try { + b.Empty(); + abort(); + } catch (const std::runtime_error &) {} + try { + b.Erase("abc"); + abort(); + } catch (const std::runtime_error &) {} + try { + b.At("abc"); + abort(); + } catch (const std::runtime_error &) {} + try { + b.At(1); + abort(); + } catch (const std::runtime_error &) {} + try { + b.Get("abc"); + abort(); + } catch (const std::runtime_error &) {} + try { + b.Get(1); + abort(); + } catch (const std::runtime_error &) {} + try { + list.AtPath("[0][1]").As(); + abort(); + } catch (const std::runtime_error &) {} + try { + b.Set("abc", 1); + abort(); + } catch (const std::runtime_error &) {} + try { + b.Set(1, 1); + abort(); + } catch (const std::runtime_error &) {} + + b.Clear(); + ASSERT(b.IsNull()); + ASSERT(!b.Contains(123)); + ASSERT(!b.Contains("abc")); + ASSERT(b.AsBool() == false); + ASSERT(b.AsInt() == 0); + ASSERT(b.AsUnsigned() == 0); + ASSERT(b.AsLongDouble() == 0.0); + ASSERT(b.AsString() == ""); + ASSERT(b.Empty()); + ASSERT(b.Size() == 0); + b.Clear(); + b.Erase("abc"); + b.AsMap(); + ASSERT(b.IsMap()); + b.Clear(); + ASSERT(Variant(true).AsString() == "true"); + ASSERT(Variant(false).AsString() == "false"); + ASSERT(Variant(true).AsInt() == 1); + ASSERT(Variant(false).AsInt() == 0); + ASSERT(Variant(true).AsUnsigned() == 1); + ASSERT(Variant(false).AsUnsigned() == 0); + ASSERT(Variant(true).AsLongDouble() == 1.); + ASSERT(Variant(false).AsLongDouble() == 0.); + ASSERT(Variant(false) != Variant()); + ASSERT(Variant(123u).AsBool()); + ASSERT(Variant(123.456).AsUnsigned() == 123u); + ASSERT(Variant(123.456).AsInt() == 123); + ASSERT(Variant(123.456).AsBool() == true); + ASSERT(Variant(0.0).AsBool() == false); + ASSERT(Variant("true").AsBool() == true); + ASSERT(Variant("anything").AsBool() == true); + ASSERT(Variant("false").AsBool() == false); + ASSERT(Variant("555.5").AsLongDouble() == 555.5); + ASSERT(Variant("123").AsUnsigned() == 123u); + ASSERT(Variant("123").AsInt() == 123); + ASSERT(Variant("").Empty()); + ASSERT(!Variant("abc").Empty()); + b = "abc"; + b.Clear(); + ASSERT(b.Empty()); + + cout << "Some simple path testing\n"; + + ASSERT(map.GetPath("/") == map); + ASSERT(map.GetPath("/one") == v); + ASSERT(list.GetPath("[5]/two") == "two"); + + cout << "Testing that the proxy works as expected.\n"; + list[1] = map["one"]; + VariantRef ref = map["three"]; + ref = 3; + ASSERT(map["three"].AsInt() == 3); + + VariantRef ref2 = map["nothing"]; + ref2 = 4; + map.Erase("nothing"); + try { + ref2.AsUnsigned(); + abort(); + } catch (const std::runtime_error &) {} + + try { + map["four"].IsNull(); + ASSERT(false); + } catch (const KeyError &e) {} + ASSERT(!map.Contains("four")); + ASSERT(map.AsMap().find("four") == map.MapEnd()); + + try { + Variant tmp; + tmp = map["four"]; + SerializeJSON(stdout, map); + ASSERT(false); + } catch (const KeyError &e) {} + ASSERT(!map.Contains("four")); + ASSERT(map.AsMap().find("four") == map.MapEnd()); + + try { + Variant tmp = map["four"]; + SerializeJSON(stdout, map); + ASSERT(false); + } catch (const KeyError &e) {} + ASSERT(!map.Contains("four")); + ASSERT(map.AsMap().find("four") == map.MapEnd()); + + cout << "Testing vector constructor\n"; + std::vector intvec; + intvec.push_back(1); + intvec.push_back(2); + intvec.push_back(3); + intvec.push_back(4); + Variant v2 = intvec; + ASSERT(intvec == variant_cast< std::vector >(v2)); + + std::vector< std::complex< float > > complexvec; + complexvec.push_back(std::complex(1, 3)); + complexvec.push_back(std::complex(0, 2)); + complexvec.push_back(std::complex(10, 0)); + complexvec.push_back(std::complex(4, 0)); + Variant complexvec1 = Variant() + .Append(Variant().Set("real", 1).Set("imag", 3)) + .Append(Variant().Set("imag", 2)) + .Append(Variant().Set("real", 10)) + .Append(4); + ASSERT(complexvec == variant_cast< std::vector< std::complex > >(complexvec1)); + Variant complexvec2 = Variant() + .Append(Variant().Append(1).Append(3)) + .Append(Variant().Append(0).Append(2)) + .Append(10) + .Append(Variant().Append(4)); + std::vector< std::complex< float > > complexvec4 = variant_cast< std::vector< std::complex > >(complexvec2); + ASSERT(complexvec == complexvec4); + + cout << "Testing map constructor\n"; + std::map intmap; + intmap["key1"] = 1; + intmap["key2"] = 2; + v2.Append(intmap); + ASSERT( (intmap == variant_cast< std::map >(v2[4])) ); + ASSERT(variant_cast(v2[1]) == 2); + std::vector intvec2(4); + transform(v2.ListBegin(), v2.ListEnd() - 1, intvec2.begin(), variant_cast); + ASSERT(intvec2 == intvec); + ASSERT(v2 == variant_cast(v2)); + + VariantPrint(v2); + // Test a case where proxy had a dangling reference on resize. + for (unsigned i = v2.Size(), end = v2.AsList().capacity()*2; i < end; ++i) { + v2[i] = v2[i-1]; + } + + cout << "Test Get and GetInto\n"; + int ival; + map.GetInto(ival, "one", 0); + ASSERT(ival == v.AsInt()); + ASSERT(map.Get("three").AsUnsigned() == 3); + map["intmap"] = intmap; + ival = 0; + map["intmap"].GetInto(ival, "key1", 0); + ASSERT(ival == 1); + try { + map["none"].GetInto(ival, "blah", 0); + ASSERT(false); + } catch (const KeyError &e) {} + + // list == [ 1, 5, "two", null, 123, { "intmap": { "key1": 1, "key2": 2 }, "one": 5, "two": "two", "three": 3 }, 0.3535566 ] + ASSERT(list == Variant().Append(1).Append(5).Append("two").Append(Variant::NullType) + .Append(123u).Append( + Variant().Set("intmap", Variant().Set("key1", 1).Set("key2", 2)) + .Set("one", 5).Set("two", "two").Set("three", 3) + ).Append(0.3535566) + ); + + list.Clear(); + ASSERT(list.Empty()); + ASSERT(list.Size() == 0); + ASSERT(list.Get(2, 123) == 123); + ASSERT(list.At(2, 123) == 123); + ASSERT(list.Get(2) == 123); + list.Set(2, 345); + ASSERT(list.Get(2) == 345); +} + +void TestCopy() { + cout << "Testing Copy\n"; + Variant v1; + v1.SetPath("foo/bar", 3); + v1.SetPath("list[0]", "abc"); + Variant v2 = v1; + ASSERT(v1 == v2); + v2 = v1.Copy(); + v2.SetPath("foo/goo", 4); + ASSERT(v1 != v2); + v2 = v1.Copy(); + v2.SetPath("list[1]", 123); + ASSERT(v1 != v2); +} + +void TestRefReassign() { + cout << "Testing VariantRef reassign\n"; + + Variant v1; + v1.SetPath("a/b/c", 1) + .SetPath("a/b/d", 2) + .SetPath("a/d", 4); + VariantRef ref = v1["a"]["b"]["c"]; + ASSERT(ref == 1); + ref.ReassignRef(v1.AtPath("a/b/d")); + ASSERT(ref == 2); + ref = 5; + ASSERT(v1.GetPath("a/b/c") == 1); + ASSERT(v1.GetPath("a/b/d") == 5); + + VariantRef ref1 = v1.AtPath("foo/bar"); + VariantRef ref2 = v1.AtPath("foo").AtPath("bar"); + VariantPrint(v1); + ASSERT(!v1.HasPath("foo")); + ASSERT(!v1.HasPath("foo/bar")); + +} + +void TestProxy() { + Variant v = Variant().Set("abc", 123).Set("def", 0.456); + // Error cases + try { + v["none"].GetType(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].AsBool(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].AsLongDouble(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].AsUnsigned(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].AsInt(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].AsString(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].AsBlob(); + abort(); + } catch (const std::runtime_error &) {} + try { + ((const Variant &)v["none"]).AsList(); + abort(); + } catch (const std::runtime_error &) {} + try { + ((const Variant &)v["none"]).AsMap(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Size(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Empty(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Clear(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Contains(1); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Contains("1"); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Erase("1"); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Add(1); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Sub(1); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Mul(1); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Div(1); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Rem(1); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Incr(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Decr(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Neg(); + abort(); + } catch (const std::runtime_error &) {} + try { + v["none"].Compare("abc"); + abort(); + } catch (const std::runtime_error &) {} + + std::map map; + map["abc"] = 123; + std::vector list; + list.push_back(123); + v["map"] = map; + v["list"] = list; + + v["abc"].GetType(); + v["abc"].AsBool(); + v["abc"].AsLongDouble(); + v["abc"].AsInt(); + v["abc"].AsUnsigned(); + v["map"].AsMap(); + v["list"].AsList(); + v["map"].Size(); + v["map"].Empty(); + v["map"].Clear(); + v["map"].Contains("abc"); + v["list"].Contains(1); + v["map"].Erase("foo"); + v["n"] = 0; + v["n"]++; + v["n"]--; + v["n"] + 1; + v["n"] - 1; + v["n"] * 1; + v["n"] / 1; + v["n"] % 1; + -v["n"]; + + VariantRef ref = v["n"].Ref(); + ASSERT(ref == v["n"]); + ASSERT(v["map"].Copy() == v["map"]); + ASSERT(ref.Resolve() == v["n"]); + + ASSERT(ref.As() == v["n"].As()); + + Variant v_copy = v.Copy(); + try { + v.AtPath("/some/path/string").As(); + abort(); + } catch (const KeyError &) {} + try { + v_copy["some"]["path"]["string"].As(); + abort(); + } catch (const KeyError &) {} + try { + const VariantRef const_ref = v_copy["does not exist"]; + const_ref.Resolve(); + abort(); + } catch (const KeyError &) {} + ASSERT(v_copy == v); + + VariantRef p = v["p"].Ref(); + v["p"] = 123; + ASSERT(p == 123); + + try { + v.GetPath("/some/path/string"); + abort(); + } catch (const KeyError &) {} + ASSERT(v.AtPath("/some/path/string", "value") == "value"); + v.AtPath("/some/other/path") = 123; + ASSERT(v.GetPath("/some/other/path") == 123); + VariantRef ref_copy = v_copy.AtPath("/some/path/string"); + ref_copy.Resolve() = "value"; + ASSERT(v_copy.AtPath("/some/path/string") == "value"); + + v.AtPath("/one/two/three").Resolve(123); + v.AtPath("/some/path/string").Resolve(123); + ASSERT(v.GetPath("/one/two/three") == 123); + ASSERT(v.GetPath("/some/path/string") == "value"); + v.ErasePath("/one/two/three", true); + v.ErasePath("p"); + v.ErasePath("some/other/path", true); + v.ErasePath("/some/path/string"); + v_copy.ErasePath("/some/path/string"); + ASSERT(v == v_copy); + ASSERT(v.HasPath("some/path")); + v.SetPath("list[1]/a", 123); + v.ErasePath("list[1]/a", true); + ASSERT(v == v_copy); + +} + +void VariantTestJSONParsing() { + std::cout << "Testing JSON -> Variant parsing\n"; + Variant v; + Variant param; + param["pretty"] = true; + Emitter emitter = JSONEmitter(CreateEmitterOutput(std::cout.rdbuf()), param); + std::string text = "[1,2,3,4,{\"A\":2}, \"text\"]"; + text += "[\"doodle\", \"foo\", \"bar\", \"\\b\\f\\r\\u0001\\u1111\", true, false]"; + std::istringstream iss(text); + Parser jv = JSONParser(CreateParserInputFile(iss.rdbuf())); + v = ParseVariant(jv); + emitter << v; + v = v; + ASSERT(v.IsList()); + ASSERT(v[4].IsMap()); + ASSERT(v[5].IsString()); + ASSERT(v[4]["A"].IsNumber()); + v[4]["b"]; + ASSERT(!v[4].Contains("b")); + v[10]; + ASSERT(!v.Contains(10)); + const Variant cv = v; + ASSERT(cv.IsList()); + ASSERT(cv[4].IsMap()); + ASSERT(cv[5].IsString()); + ASSERT(cv[4]["A"].IsNumber()); + ASSERT(!cv[4].Contains("b")); + try { + cv[10]; + ASSERT(false); + } catch (const std::out_of_range&) { + + } + v = v[4]; + v = "\n"; + + jv.Reset(); + v = ParseVariant(jv); + ASSERT(jv.Done()); + ASSERT(v[1].AsString() == "foo"); + + emitter.Flush(); + std::cout << std::endl; + // Test that really big indents work... + Serialize(std::cout.rdbuf(), v, SERIALIZE_JSON, Variant().Set("pretty", true).Set("indent", 200)); + std::cout << std::endl; + +} + +void VariantTestYAMLParsing() { + std::cout << "Testing YAML -> Variant parsing\n"; + std::string text = "some: yaml\na key: and a value\n" + "some more: [a, list, 123, values, 1.23, null, true, false]\n" + "max uintmax: 18446744073709551616\n" + "---\n" + "Lets try multiple documents!\n"; + Parser parser = YAMLParser(CreateParserInput(text.c_str(), text.length())); + Variant v1 = ParseVariant(parser); + Variant v2 = ParseVariant(parser); + ASSERT(v1["some"].IsString()); + ASSERT(v1["some more"].IsList()); + ASSERT(v1["some more"].Size() == 8); + ASSERT(v1["some more"][6].IsTrue()); + ASSERT(v1["max uintmax"].AsUnsigned() == std::numeric_limits::max()); + ASSERT(v2.IsString()); +} + +void PrintError(std::vector &stack, const std::string &msg, Variant orig, Variant cur) { + cerr << "Error comparing variants at: "; + for (std::vector::iterator i(stack.begin()), e(stack.end()); i!=e; ++i) { + cerr << i->AsString() << ": "; + } + cerr << "\n\n" << msg; + Emitter emitter = JSONEmitter(CreateEmitterOutput(cerr.rdbuf())); + emitter.BeginMap(); + emitter << "orig" << orig << "cur" << cur; + emitter.EndMap(); + emitter.Close(); + cerr << "\n"; + abort(); +} + +void DoDiff(Variant orig, Variant cur, std::vector &stack) { + if (orig != cur) { + if (orig.GetType() != cur.GetType()) { + PrintError(stack, "differing types", orig, cur); + } + // find the difference and print it out + switch (orig.GetType()) { + case Variant::NullType: + abort(); + case Variant::BoolType: + PrintError(stack, "differing boolean", orig, cur); + abort(); + break; + case Variant::IntegerType: + case Variant::UnsignedType: + case Variant::FloatType: + abort(); + break; + case Variant::StringType: + abort(); + break; + case Variant::ListType: + for (unsigned i = 0; i < orig.Size(); ++i) { + stack.push_back(i); + DoDiff(orig[i], cur[i], stack); + stack.pop_back(); + } + break; + case Variant::MapType: + for (Variant::MapIterator i(orig.MapBegin()), e(orig.MapEnd()); i!=e; i++) { + stack.push_back(i->first); + DoDiff(i->second, cur[i->first], stack); + stack.pop_back(); + } + break; + case Variant::BlobType: + abort(); + break; + } + PrintError(stack, "Comparison showed different but cannot find difference", orig, cur); + } +} + +void Diff(Variant orig, Variant cur) { + std::vector stack; + DoDiff(orig, cur, stack); +} + +void TestVariantEmitParseRandom(int verbose, int numtests, Parser (*Parser_t)(shared_ptr), Emitter (*Emitter_t)(shared_ptr, Variant), bool allow_nan) { + for (int i = 0; i < numtests; ++i) { + if (verbose > 0) { + std::cout << "Random test number " << i << std::endl; + } + Variant v = GenerateRandomVariant(allow_nan); + ASSERT(!v.IsNull()); + std::stringstream ss; + Emitter emitter = Emitter_t(CreateEmitterOutput(ss.rdbuf()), Variant()); + emitter << v; + emitter.Close(); + if (verbose > 1) { + std::cout << ss.str() << std::endl; + } + Parser parser = Parser_t(CreateParserInputFile(ss.rdbuf())); + Variant v2 = ParseVariant(parser); + Diff(v, v2); + if (verbose > 0) { + std::cout << "End random test number " << i << std::endl; + } + } +} + +int main(int argv, char** argc) { + VariantTest(); + TestCopy(); + TestRefReassign(); + TestProxy(); + VariantTestJSONParsing(); +#ifdef ENABLE_YAML + VariantTestYAMLParsing(); +#endif + int verbose = 1; + int num_tests = 100; + + cout << "Random test of JSON\n"; + TestVariantEmitParseRandom(verbose, num_tests, JSONParser, JSONEmitter, false); +#ifdef ENABLE_YAML + cout << "Random test of YAML\n"; + TestVariantEmitParseRandom(verbose, num_tests, YAMLParser, YAMLEmitter, true); +#endif +#ifdef ENABLE_XML + cout << "Random test of XML\n"; + TestVariantEmitParseRandom(verbose, num_tests, XMLPLISTParser, XMLPLISTEmitter, true); +#endif +#ifdef ENABLE_MSGPACK + cout << "Random test of MsgPack\n"; + TestVariantEmitParseRandom(verbose, num_tests, MsgPackParser, MsgPackEmitter, true); +#endif + return 0; +} diff --git a/src/hos_libvariant/src/test/test_xml_parser.cc b/src/hos_libvariant/src/test/test_xml_parser.cc new file mode 100644 index 00000000..57df8e81 --- /dev/null +++ b/src/hos_libvariant/src/test/test_xml_parser.cc @@ -0,0 +1,32 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include "TestAssert.h" +#include +#include + +using namespace libvariant; +using namespace std; + +const char *test_xml = +"\n" +" \n" +"\n\n" +" some value with spaces \n" +"\n\n\n" +"\n" +"\tSome formated\n" +"\tstring with strange stuff in it...\n" +"\n" +"\n" +"\n"; + +int main(int argc, char **argv) { + Variant v = DeserializeXMLPLIST(test_xml); + SerializeJSON(cout.rdbuf(), v, true); + cout << endl; + Variant v2 = DeserializeXMLPLIST(SerializeXMLPLIST(v, true)); + ASSERT(v2 == v); + return 0; +} diff --git a/src/hos_libvariant/src/test/test_yaml_parser.cc b/src/hos_libvariant/src/test/test_yaml_parser.cc new file mode 100644 index 00000000..7baf82d3 --- /dev/null +++ b/src/hos_libvariant/src/test/test_yaml_parser.cc @@ -0,0 +1,64 @@ +/** \file + * \author John Bridgman + * \brief + */ +#include +#include +#include "EventBuffer.h" +#include "TestCommon.h" +#include + +using namespace libvariant; + +static const char *input_document = "---\n" +"string: value\n" +"int10: 1234\n" +"int8: 0o234\n" +"int16: 0x2F\n" +"float: [ 0.1, .12, 1.0e-2 ]\n" +"nan: .nan\n" +"inf: .inf\n" +"strnum: '12345'\n" +"...\n"; + +void ExpectedEvents(Emitter e) { + e.BeginDocument(); + e.BeginMap(); + e.Emit("string"); + e.Emit("value"); + e.Emit("int10"); + e.Emit(intmax_t(1234ll)); + e.Emit("int8"); + e.Emit(uintmax_t(0234ll)); + e.Emit("int16"); + e.Emit(uintmax_t(0x2Fll)); + e.Emit("float"); + e.BeginList(); + e.Emit(0.1); + e.Emit(.12); + e.Emit(1.0e-2); + e.EndList(); + e.Emit("nan"), + e.Emit(std::numeric_limits::quiet_NaN()), + e.Emit("inf"), + e.Emit(std::numeric_limits::infinity()), + e.Emit("strnum"), + e.Emit("12345"), + e.EndMap(); + e.EndDocument(); +} + + +int main(int argc, char **argv) { + Parser parser = YAMLParser(CreateParserInput(input_document)); + shared_ptr expected(new EventBuffer); + ExpectedEvents(Emitter(expected)); + shared_ptr result(new EventBuffer); + + result->Fill(parser); + + if (!ErrorCheckEventBuffer(expected, result)) { + return 1; + } + return 0; +} diff --git a/src/hos_philips_hue/python/hos_huecontroller/huecontroller.py b/src/hos_philips_hue/python/hos_huecontroller/huecontroller.py index 66df1b10..0cdcc645 100644 --- a/src/hos_philips_hue/python/hos_huecontroller/huecontroller.py +++ b/src/hos_philips_hue/python/hos_huecontroller/huecontroller.py @@ -87,7 +87,7 @@ class HueController(object): msg = DeviceStatusUpdate() msg.seq = seq msg.device_id = device_id - msg.device_type = "hos/huelight" + msg.device_type = "hue/huelight" msg.stamp = stamp msg_body = dict()