├── .gitignore ├── CMakeLists.txt ├── json ├── CMakeLists.txt ├── autolink.h ├── config.h ├── features.h ├── forwards.h ├── json.h ├── json_batchallocator.h ├── json_internalarray.inl ├── json_internalmap.inl ├── json_reader.cpp ├── json_value.cpp ├── json_valueiterator.inl ├── json_writer.cpp ├── reader.h ├── value.h └── writer.h ├── package.xml └── src ├── CHTTP_post.cpp ├── CHTTP_post.h ├── CWebSocket.cpp ├── CWebSocket.h └── RemoteControl_node.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(RemoteControl) 3 | 4 | ## Compile as C++11, supported in ROS Kinetic and newer 5 | add_compile_options(-std=c++11) 6 | 7 | ## Find catkin macros and libraries 8 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) 9 | ## is used, also find other catkin packages 10 | find_package(catkin REQUIRED COMPONENTS 11 | roscpp 12 | rospy 13 | std_msgs 14 | ) 15 | 16 | find_package(CURL) 17 | #find_package(boost) 18 | #find_package(websocketpp) 19 | ## System dependencies are found with CMake's conventions 20 | # find_package(Boost REQUIRED COMPONENTS system) 21 | 22 | 23 | ## Uncomment this if the package has a setup.py. This macro ensures 24 | ## modules and global scripts declared therein get installed 25 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html 26 | # catkin_python_setup() 27 | 28 | ################################################ 29 | ## Declare ROS messages, services and actions ## 30 | ################################################ 31 | 32 | ## To declare and build messages, services or actions from within this 33 | ## package, follow these steps: 34 | ## * Let MSG_DEP_SET be the set of packages whose message types you use in 35 | ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). 36 | ## * In the file package.xml: 37 | ## * add a build_depend tag for "message_generation" 38 | ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET 39 | ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in 40 | ## but can be declared for certainty nonetheless: 41 | ## * add a exec_depend tag for "message_runtime" 42 | ## * In this file (CMakeLists.txt): 43 | ## * add "message_generation" and every package in MSG_DEP_SET to 44 | ## find_package(catkin REQUIRED COMPONENTS ...) 45 | ## * add "message_runtime" and every package in MSG_DEP_SET to 46 | ## catkin_package(CATKIN_DEPENDS ...) 47 | ## * uncomment the add_*_files sections below as needed 48 | ## and list every .msg/.srv/.action file to be processed 49 | ## * uncomment the generate_messages entry below 50 | ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) 51 | 52 | ## Generate messages in the 'msg' folder 53 | # add_message_files( 54 | # FILES 55 | # Message1.msg 56 | # Message2.msg 57 | # ) 58 | 59 | ## Generate services in the 'srv' folder 60 | # add_service_files( 61 | # FILES 62 | # Service1.srv 63 | # Service2.srv 64 | # ) 65 | 66 | ## Generate actions in the 'action' folder 67 | # add_action_files( 68 | # FILES 69 | # Action1.action 70 | # Action2.action 71 | # ) 72 | 73 | ## Generate added messages and services with any dependencies listed here 74 | # generate_messages( 75 | # DEPENDENCIES 76 | # std_msgs 77 | # ) 78 | 79 | ################################################ 80 | ## Declare ROS dynamic reconfigure parameters ## 81 | ################################################ 82 | 83 | ## To declare and build dynamic reconfigure parameters within this 84 | ## package, follow these steps: 85 | ## * In the file package.xml: 86 | ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" 87 | ## * In this file (CMakeLists.txt): 88 | ## * add "dynamic_reconfigure" to 89 | ## find_package(catkin REQUIRED COMPONENTS ...) 90 | ## * uncomment the "generate_dynamic_reconfigure_options" section below 91 | ## and list every .cfg file to be processed 92 | 93 | ## Generate dynamic reconfigure parameters in the 'cfg' folder 94 | # generate_dynamic_reconfigure_options( 95 | # cfg/DynReconf1.cfg 96 | # cfg/DynReconf2.cfg 97 | # ) 98 | 99 | ################################### 100 | ## catkin specific configuration ## 101 | ################################### 102 | ## The catkin_package macro generates cmake config files for your package 103 | ## Declare things to be passed to dependent projects 104 | ## INCLUDE_DIRS: uncomment this if your package contains header files 105 | ## LIBRARIES: libraries you create in this project that dependent projects also need 106 | ## CATKIN_DEPENDS: catkin_packages dependent projects also need 107 | ## DEPENDS: system dependencies of this project that dependent projects also need 108 | catkin_package( 109 | # INCLUDE_DIRS include 110 | LIBRARIES RemoteControl 111 | CATKIN_DEPENDS roscpp rospy std_msgs 112 | # DEPENDS system_lib 113 | ) 114 | 115 | ########### 116 | ## Build ## 117 | ########### 118 | 119 | ## Specify additional locations of header files 120 | ## Your package locations should be listed before other locations 121 | include_directories( 122 | # include 123 | ${catkin_INCLUDE_DIRS} 124 | ${CURL_INCLUDE_DIR} 125 | #${jsoncpp_INCLUDE_DIR} 126 | /home/books/Downloads/websocketpp-master 127 | #json 128 | ) 129 | 130 | ## Declare a C++ library 131 | # add_library(${PROJECT_NAME} 132 | # src/${PROJECT_NAME}/RemoteControl.cpp 133 | # ) 134 | # 编译 json 135 | add_subdirectory(json) 136 | ## Add cmake target dependencies of the library 137 | ## as an example, code may need to be generated before libraries 138 | ## either from message generation or dynamic reconfigure 139 | # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 140 | 141 | ## Declare a C++ executable 142 | ## With catkin_make all packages are built within a single CMake context 143 | ## The recommended prefix ensures that target names across packages don't collide 144 | add_executable(${PROJECT_NAME}_node src/RemoteControl_node.cpp 145 | src/CHTTP_post.cpp src/CHTTP_post.h src/CWebSocket.cpp src/CWebSocket.h) 146 | 147 | ## Rename C++ executable without prefix 148 | ## The above recommended prefix causes long target names, the following renames the 149 | ## target back to the shorter version for ease of user use 150 | ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" 151 | # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") 152 | 153 | ## Add cmake target dependencies of the executable 154 | ## same as for the library above 155 | add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 156 | 157 | ## Specify libraries to link a library or executable target against 158 | target_link_libraries(${PROJECT_NAME}_node 159 | ${catkin_LIBRARIES} 160 | ${CURL_LIBRARY} 161 | #${jsoncpp_LIBRARY} 162 | json 163 | ${websocketpp_LIBRARY} 164 | ) 165 | 166 | ############# 167 | ## Install ## 168 | ############# 169 | 170 | # all install targets should use catkin DESTINATION variables 171 | # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html 172 | 173 | ## Mark executable scripts (Python etc.) for installation 174 | ## in contrast to setup.py, you can choose the destination 175 | # install(PROGRAMS 176 | # scripts/my_python_script 177 | # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 178 | # ) 179 | 180 | ## Mark executables and/or libraries for installation 181 | # install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node 182 | # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 183 | # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 184 | # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 185 | # ) 186 | 187 | ## Mark cpp header files for installation 188 | # install(DIRECTORY include/${PROJECT_NAME}/ 189 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} 190 | # FILES_MATCHING PATTERN "*.h" 191 | # PATTERN ".svn" EXCLUDE 192 | # ) 193 | 194 | ## Mark other files for installation (e.g. launch and bag files, etc.) 195 | # install(FILES 196 | # # myfile1 197 | # # myfile2 198 | # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} 199 | # ) 200 | 201 | ############# 202 | ## Testing ## 203 | ############# 204 | 205 | ## Add gtest based cpp test target and link libraries 206 | # catkin_add_gtest(${PROJECT_NAME}-test test/test_RemoteControl.cpp) 207 | # if(TARGET ${PROJECT_NAME}-test) 208 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) 209 | # endif() 210 | 211 | ## Add folders to be run by python nosetests 212 | # catkin_add_nosetests(test) 213 | -------------------------------------------------------------------------------- /json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 编译选项 2 | aux_source_directory("." JSON_SRC) 3 | add_library(json STATIC ${JSON_SRC}) 4 | 5 | -------------------------------------------------------------------------------- /json/autolink.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_AUTOLINK_H_INCLUDED 2 | # define JSON_AUTOLINK_H_INCLUDED 3 | 4 | # include "config.h" 5 | 6 | # ifdef JSON_IN_CPPTL 7 | # include 8 | # endif 9 | 10 | # if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) 11 | # define CPPTL_AUTOLINK_NAME "json" 12 | # undef CPPTL_AUTOLINK_DLL 13 | # ifdef JSON_DLL 14 | # define CPPTL_AUTOLINK_DLL 15 | # endif 16 | # include "autolink.h" 17 | # endif 18 | 19 | #endif // JSON_AUTOLINK_H_INCLUDED 20 | -------------------------------------------------------------------------------- /json/config.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_CONFIG_H_INCLUDED 2 | # define JSON_CONFIG_H_INCLUDED 3 | 4 | /// If defined, indicates that json library is embedded in CppTL library. 5 | //# define JSON_IN_CPPTL 1 6 | 7 | /// If defined, indicates that json may leverage CppTL library 8 | //# define JSON_USE_CPPTL 1 9 | /// If defined, indicates that cpptl vector based map should be used instead of std::map 10 | /// as Value container. 11 | //# define JSON_USE_CPPTL_SMALLMAP 1 12 | /// If defined, indicates that Json specific container should be used 13 | /// (hash table & simple deque container with customizable allocator). 14 | /// THIS FEATURE IS STILL EXPERIMENTAL! 15 | //# define JSON_VALUE_USE_INTERNAL_MAP 1 16 | /// Force usage of standard new/malloc based allocator instead of memory pool based allocator. 17 | /// The memory pools allocator used optimization (initializing Value and ValueInternalLink 18 | /// as if it was a POD) that may cause some validation tool to report errors. 19 | /// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. 20 | //# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 21 | 22 | /// If defined, indicates that Json use exception to report invalid type manipulation 23 | /// instead of C assert macro. 24 | # define JSON_USE_EXCEPTION 1 25 | 26 | # ifdef JSON_IN_CPPTL 27 | # include 28 | # ifndef JSON_USE_CPPTL 29 | # define JSON_USE_CPPTL 1 30 | # endif 31 | # endif 32 | 33 | # ifdef JSON_IN_CPPTL 34 | # define JSON_API CPPTL_API 35 | # elif defined(JSON_DLL_BUILD) 36 | # define JSON_API __declspec(dllexport) 37 | # elif defined(JSON_DLL) 38 | # define JSON_API __declspec(dllimport) 39 | # else 40 | # define JSON_API 41 | # endif 42 | 43 | #endif // JSON_CONFIG_H_INCLUDED 44 | -------------------------------------------------------------------------------- /json/features.h: -------------------------------------------------------------------------------- 1 | #ifndef CPPTL_JSON_FEATURES_H_INCLUDED 2 | # define CPPTL_JSON_FEATURES_H_INCLUDED 3 | 4 | # include "forwards.h" 5 | 6 | namespace Json { 7 | 8 | /** \brief Configuration passed to reader and writer. 9 | * This configuration object can be used to force the Reader or Writer 10 | * to behave in a standard conforming way. 11 | */ 12 | class JSON_API Features 13 | { 14 | public: 15 | /** \brief A configuration that allows all features and assumes all strings are UTF-8. 16 | * - C & C++ comments are allowed 17 | * - Root object can be any JSON value 18 | * - Assumes Value strings are encoded in UTF-8 19 | */ 20 | static Features all(); 21 | 22 | /** \brief A configuration that is strictly compatible with the JSON specification. 23 | * - Comments are forbidden. 24 | * - Root object must be either an array or an object value. 25 | * - Assumes Value strings are encoded in UTF-8 26 | */ 27 | static Features strictMode(); 28 | 29 | /** \brief Initialize the configuration like JsonConfig::allFeatures; 30 | */ 31 | Features(); 32 | 33 | /// \c true if comments are allowed. Default: \c true. 34 | bool allowComments_; 35 | 36 | /// \c true if root must be either an array or an object value. Default: \c false. 37 | bool strictRoot_; 38 | }; 39 | 40 | } // namespace Json 41 | 42 | #endif // CPPTL_JSON_FEATURES_H_INCLUDED 43 | -------------------------------------------------------------------------------- /json/forwards.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_FORWARDS_H_INCLUDED 2 | # define JSON_FORWARDS_H_INCLUDED 3 | 4 | # include "config.h" 5 | 6 | namespace Json { 7 | 8 | // writer.h 9 | class FastWriter; 10 | class StyledWriter; 11 | 12 | // reader.h 13 | class Reader; 14 | 15 | // features.h 16 | class Features; 17 | 18 | // value.h 19 | typedef int Int; 20 | typedef unsigned int UInt; 21 | class StaticString; 22 | class Path; 23 | class PathArgument; 24 | class Value; 25 | class ValueIteratorBase; 26 | class ValueIterator; 27 | class ValueConstIterator; 28 | #ifdef JSON_VALUE_USE_INTERNAL_MAP 29 | class ValueAllocator; 30 | class ValueMapAllocator; 31 | class ValueInternalLink; 32 | class ValueInternalArray; 33 | class ValueInternalMap; 34 | #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP 35 | 36 | } // namespace Json 37 | 38 | 39 | #endif // JSON_FORWARDS_H_INCLUDED 40 | -------------------------------------------------------------------------------- /json/json.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_JSON_H_INCLUDED 2 | # define JSON_JSON_H_INCLUDED 3 | 4 | # include "autolink.h" 5 | # include "value.h" 6 | # include "reader.h" 7 | # include "writer.h" 8 | # include "features.h" 9 | 10 | #endif // JSON_JSON_H_INCLUDED 11 | -------------------------------------------------------------------------------- /json/json_batchallocator.h: -------------------------------------------------------------------------------- 1 | #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED 2 | # define JSONCPP_BATCHALLOCATOR_H_INCLUDED 3 | 4 | # include 5 | # include 6 | 7 | # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 8 | 9 | namespace Json { 10 | 11 | /* Fast memory allocator. 12 | * 13 | * This memory allocator allocates memory for a batch of object (specified by 14 | * the page size, the number of object in each page). 15 | * 16 | * It does not allow the destruction of a single object. All the allocated objects 17 | * can be destroyed at once. The memory can be either released or reused for future 18 | * allocation. 19 | * 20 | * The in-place new operator must be used to construct the object using the pointer 21 | * returned by allocate. 22 | */ 23 | template 25 | class BatchAllocator 26 | { 27 | public: 28 | typedef AllocatedType Type; 29 | 30 | BatchAllocator( unsigned int objectsPerPage = 255 ) 31 | : freeHead_( 0 ) 32 | , objectsPerPage_( objectsPerPage ) 33 | { 34 | // printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); 35 | assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. 36 | assert( objectsPerPage >= 16 ); 37 | batches_ = allocateBatch( 0 ); // allocated a dummy page 38 | currentBatch_ = batches_; 39 | } 40 | 41 | ~BatchAllocator() 42 | { 43 | for ( BatchInfo *batch = batches_; batch; ) 44 | { 45 | BatchInfo *nextBatch = batch->next_; 46 | free( batch ); 47 | batch = nextBatch; 48 | } 49 | } 50 | 51 | /// allocate space for an array of objectPerAllocation object. 52 | /// @warning it is the responsability of the caller to call objects constructors. 53 | AllocatedType *allocate() 54 | { 55 | if ( freeHead_ ) // returns node from free list. 56 | { 57 | AllocatedType *object = freeHead_; 58 | freeHead_ = *(AllocatedType **)object; 59 | return object; 60 | } 61 | if ( currentBatch_->used_ == currentBatch_->end_ ) 62 | { 63 | currentBatch_ = currentBatch_->next_; 64 | while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) 65 | currentBatch_ = currentBatch_->next_; 66 | 67 | if ( !currentBatch_ ) // no free batch found, allocate a new one 68 | { 69 | currentBatch_ = allocateBatch( objectsPerPage_ ); 70 | currentBatch_->next_ = batches_; // insert at the head of the list 71 | batches_ = currentBatch_; 72 | } 73 | } 74 | AllocatedType *allocated = currentBatch_->used_; 75 | currentBatch_->used_ += objectPerAllocation; 76 | return allocated; 77 | } 78 | 79 | /// Release the object. 80 | /// @warning it is the responsability of the caller to actually destruct the object. 81 | void release( AllocatedType *object ) 82 | { 83 | assert( object != 0 ); 84 | *(AllocatedType **)object = freeHead_; 85 | freeHead_ = object; 86 | } 87 | 88 | private: 89 | struct BatchInfo 90 | { 91 | BatchInfo *next_; 92 | AllocatedType *used_; 93 | AllocatedType *end_; 94 | AllocatedType buffer_[objectPerAllocation]; 95 | }; 96 | 97 | // disabled copy constructor and assignement operator. 98 | BatchAllocator( const BatchAllocator & ); 99 | void operator =( const BatchAllocator &); 100 | 101 | static BatchInfo *allocateBatch( unsigned int objectsPerPage ) 102 | { 103 | const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation 104 | + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; 105 | BatchInfo *batch = static_cast( malloc( mallocSize ) ); 106 | batch->next_ = 0; 107 | batch->used_ = batch->buffer_; 108 | batch->end_ = batch->buffer_ + objectsPerPage; 109 | return batch; 110 | } 111 | 112 | BatchInfo *batches_; 113 | BatchInfo *currentBatch_; 114 | /// Head of a single linked list within the allocated space of freeed object 115 | AllocatedType *freeHead_; 116 | unsigned int objectsPerPage_; 117 | }; 118 | 119 | 120 | } // namespace Json 121 | 122 | # endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION 123 | 124 | #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED 125 | 126 | -------------------------------------------------------------------------------- /json/json_internalarray.inl: -------------------------------------------------------------------------------- 1 | // included by json_value.cpp 2 | // everything is within Json namespace 3 | 4 | // ////////////////////////////////////////////////////////////////// 5 | // ////////////////////////////////////////////////////////////////// 6 | // ////////////////////////////////////////////////////////////////// 7 | // class ValueInternalArray 8 | // ////////////////////////////////////////////////////////////////// 9 | // ////////////////////////////////////////////////////////////////// 10 | // ////////////////////////////////////////////////////////////////// 11 | 12 | ValueArrayAllocator::~ValueArrayAllocator() 13 | { 14 | } 15 | 16 | // ////////////////////////////////////////////////////////////////// 17 | // class DefaultValueArrayAllocator 18 | // ////////////////////////////////////////////////////////////////// 19 | #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 20 | class DefaultValueArrayAllocator : public ValueArrayAllocator 21 | { 22 | public: // overridden from ValueArrayAllocator 23 | virtual ~DefaultValueArrayAllocator() 24 | { 25 | } 26 | 27 | virtual ValueInternalArray *newArray() 28 | { 29 | return new ValueInternalArray(); 30 | } 31 | 32 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) 33 | { 34 | return new ValueInternalArray( other ); 35 | } 36 | 37 | virtual void destructArray( ValueInternalArray *array ) 38 | { 39 | delete array; 40 | } 41 | 42 | virtual void reallocateArrayPageIndex( Value **&indexes, 43 | ValueInternalArray::PageIndex &indexCount, 44 | ValueInternalArray::PageIndex minNewIndexCount ) 45 | { 46 | ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; 47 | if ( minNewIndexCount > newIndexCount ) 48 | newIndexCount = minNewIndexCount; 49 | void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); 50 | if ( !newIndexes ) 51 | throw std::bad_alloc(); 52 | indexCount = newIndexCount; 53 | indexes = static_cast( newIndexes ); 54 | } 55 | virtual void releaseArrayPageIndex( Value **indexes, 56 | ValueInternalArray::PageIndex indexCount ) 57 | { 58 | if ( indexes ) 59 | free( indexes ); 60 | } 61 | 62 | virtual Value *allocateArrayPage() 63 | { 64 | return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); 65 | } 66 | 67 | virtual void releaseArrayPage( Value *value ) 68 | { 69 | if ( value ) 70 | free( value ); 71 | } 72 | }; 73 | 74 | #else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 75 | /// @todo make this thread-safe (lock when accessign batch allocator) 76 | class DefaultValueArrayAllocator : public ValueArrayAllocator 77 | { 78 | public: // overridden from ValueArrayAllocator 79 | virtual ~DefaultValueArrayAllocator() 80 | { 81 | } 82 | 83 | virtual ValueInternalArray *newArray() 84 | { 85 | ValueInternalArray *array = arraysAllocator_.allocate(); 86 | new (array) ValueInternalArray(); // placement new 87 | return array; 88 | } 89 | 90 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) 91 | { 92 | ValueInternalArray *array = arraysAllocator_.allocate(); 93 | new (array) ValueInternalArray( other ); // placement new 94 | return array; 95 | } 96 | 97 | virtual void destructArray( ValueInternalArray *array ) 98 | { 99 | if ( array ) 100 | { 101 | array->~ValueInternalArray(); 102 | arraysAllocator_.release( array ); 103 | } 104 | } 105 | 106 | virtual void reallocateArrayPageIndex( Value **&indexes, 107 | ValueInternalArray::PageIndex &indexCount, 108 | ValueInternalArray::PageIndex minNewIndexCount ) 109 | { 110 | ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; 111 | if ( minNewIndexCount > newIndexCount ) 112 | newIndexCount = minNewIndexCount; 113 | void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); 114 | if ( !newIndexes ) 115 | throw std::bad_alloc(); 116 | indexCount = newIndexCount; 117 | indexes = static_cast( newIndexes ); 118 | } 119 | virtual void releaseArrayPageIndex( Value **indexes, 120 | ValueInternalArray::PageIndex indexCount ) 121 | { 122 | if ( indexes ) 123 | free( indexes ); 124 | } 125 | 126 | virtual Value *allocateArrayPage() 127 | { 128 | return static_cast( pagesAllocator_.allocate() ); 129 | } 130 | 131 | virtual void releaseArrayPage( Value *value ) 132 | { 133 | if ( value ) 134 | pagesAllocator_.release( value ); 135 | } 136 | private: 137 | BatchAllocator arraysAllocator_; 138 | BatchAllocator pagesAllocator_; 139 | }; 140 | #endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 141 | 142 | static ValueArrayAllocator *&arrayAllocator() 143 | { 144 | static DefaultValueArrayAllocator defaultAllocator; 145 | static ValueArrayAllocator *arrayAllocator = &defaultAllocator; 146 | return arrayAllocator; 147 | } 148 | 149 | static struct DummyArrayAllocatorInitializer { 150 | DummyArrayAllocatorInitializer() 151 | { 152 | arrayAllocator(); // ensure arrayAllocator() statics are initialized before main(). 153 | } 154 | } dummyArrayAllocatorInitializer; 155 | 156 | // ////////////////////////////////////////////////////////////////// 157 | // class ValueInternalArray 158 | // ////////////////////////////////////////////////////////////////// 159 | bool 160 | ValueInternalArray::equals( const IteratorState &x, 161 | const IteratorState &other ) 162 | { 163 | return x.array_ == other.array_ 164 | && x.currentItemIndex_ == other.currentItemIndex_ 165 | && x.currentPageIndex_ == other.currentPageIndex_; 166 | } 167 | 168 | 169 | void 170 | ValueInternalArray::increment( IteratorState &it ) 171 | { 172 | JSON_ASSERT_MESSAGE( it.array_ && 173 | (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ 174 | != it.array_->size_, 175 | "ValueInternalArray::increment(): moving iterator beyond end" ); 176 | ++(it.currentItemIndex_); 177 | if ( it.currentItemIndex_ == itemsPerPage ) 178 | { 179 | it.currentItemIndex_ = 0; 180 | ++(it.currentPageIndex_); 181 | } 182 | } 183 | 184 | 185 | void 186 | ValueInternalArray::decrement( IteratorState &it ) 187 | { 188 | JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_ 189 | && it.currentItemIndex_ == 0, 190 | "ValueInternalArray::decrement(): moving iterator beyond end" ); 191 | if ( it.currentItemIndex_ == 0 ) 192 | { 193 | it.currentItemIndex_ = itemsPerPage-1; 194 | --(it.currentPageIndex_); 195 | } 196 | else 197 | { 198 | --(it.currentItemIndex_); 199 | } 200 | } 201 | 202 | 203 | Value & 204 | ValueInternalArray::unsafeDereference( const IteratorState &it ) 205 | { 206 | return (*(it.currentPageIndex_))[it.currentItemIndex_]; 207 | } 208 | 209 | 210 | Value & 211 | ValueInternalArray::dereference( const IteratorState &it ) 212 | { 213 | JSON_ASSERT_MESSAGE( it.array_ && 214 | (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ 215 | < it.array_->size_, 216 | "ValueInternalArray::dereference(): dereferencing invalid iterator" ); 217 | return unsafeDereference( it ); 218 | } 219 | 220 | void 221 | ValueInternalArray::makeBeginIterator( IteratorState &it ) const 222 | { 223 | it.array_ = const_cast( this ); 224 | it.currentItemIndex_ = 0; 225 | it.currentPageIndex_ = pages_; 226 | } 227 | 228 | 229 | void 230 | ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const 231 | { 232 | it.array_ = const_cast( this ); 233 | it.currentItemIndex_ = index % itemsPerPage; 234 | it.currentPageIndex_ = pages_ + index / itemsPerPage; 235 | } 236 | 237 | 238 | void 239 | ValueInternalArray::makeEndIterator( IteratorState &it ) const 240 | { 241 | makeIterator( it, size_ ); 242 | } 243 | 244 | 245 | ValueInternalArray::ValueInternalArray() 246 | : pages_( 0 ) 247 | , size_( 0 ) 248 | , pageCount_( 0 ) 249 | { 250 | } 251 | 252 | 253 | ValueInternalArray::ValueInternalArray( const ValueInternalArray &other ) 254 | : pages_( 0 ) 255 | , pageCount_( 0 ) 256 | , size_( other.size_ ) 257 | { 258 | PageIndex minNewPages = other.size_ / itemsPerPage; 259 | arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); 260 | JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, 261 | "ValueInternalArray::reserve(): bad reallocation" ); 262 | IteratorState itOther; 263 | other.makeBeginIterator( itOther ); 264 | Value *value; 265 | for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) ) 266 | { 267 | if ( index % itemsPerPage == 0 ) 268 | { 269 | PageIndex pageIndex = index / itemsPerPage; 270 | value = arrayAllocator()->allocateArrayPage(); 271 | pages_[pageIndex] = value; 272 | } 273 | new (value) Value( dereference( itOther ) ); 274 | } 275 | } 276 | 277 | 278 | ValueInternalArray & 279 | ValueInternalArray::operator =( const ValueInternalArray &other ) 280 | { 281 | ValueInternalArray temp( other ); 282 | swap( temp ); 283 | return *this; 284 | } 285 | 286 | 287 | ValueInternalArray::~ValueInternalArray() 288 | { 289 | // destroy all constructed items 290 | IteratorState it; 291 | IteratorState itEnd; 292 | makeBeginIterator( it); 293 | makeEndIterator( itEnd ); 294 | for ( ; !equals(it,itEnd); increment(it) ) 295 | { 296 | Value *value = &dereference(it); 297 | value->~Value(); 298 | } 299 | // release all pages 300 | PageIndex lastPageIndex = size_ / itemsPerPage; 301 | for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex ) 302 | arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); 303 | // release pages index 304 | arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ ); 305 | } 306 | 307 | 308 | void 309 | ValueInternalArray::swap( ValueInternalArray &other ) 310 | { 311 | Value **tempPages = pages_; 312 | pages_ = other.pages_; 313 | other.pages_ = tempPages; 314 | ArrayIndex tempSize = size_; 315 | size_ = other.size_; 316 | other.size_ = tempSize; 317 | PageIndex tempPageCount = pageCount_; 318 | pageCount_ = other.pageCount_; 319 | other.pageCount_ = tempPageCount; 320 | } 321 | 322 | void 323 | ValueInternalArray::clear() 324 | { 325 | ValueInternalArray dummy; 326 | swap( dummy ); 327 | } 328 | 329 | 330 | void 331 | ValueInternalArray::resize( ArrayIndex newSize ) 332 | { 333 | if ( newSize == 0 ) 334 | clear(); 335 | else if ( newSize < size_ ) 336 | { 337 | IteratorState it; 338 | IteratorState itEnd; 339 | makeIterator( it, newSize ); 340 | makeIterator( itEnd, size_ ); 341 | for ( ; !equals(it,itEnd); increment(it) ) 342 | { 343 | Value *value = &dereference(it); 344 | value->~Value(); 345 | } 346 | PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage; 347 | PageIndex lastPageIndex = size_ / itemsPerPage; 348 | for ( ; pageIndex < lastPageIndex; ++pageIndex ) 349 | arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); 350 | size_ = newSize; 351 | } 352 | else if ( newSize > size_ ) 353 | resolveReference( newSize ); 354 | } 355 | 356 | 357 | void 358 | ValueInternalArray::makeIndexValid( ArrayIndex index ) 359 | { 360 | // Need to enlarge page index ? 361 | if ( index >= pageCount_ * itemsPerPage ) 362 | { 363 | PageIndex minNewPages = (index + 1) / itemsPerPage; 364 | arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); 365 | JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" ); 366 | } 367 | 368 | // Need to allocate new pages ? 369 | ArrayIndex nextPageIndex = 370 | (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage 371 | : size_; 372 | if ( nextPageIndex <= index ) 373 | { 374 | PageIndex pageIndex = nextPageIndex / itemsPerPage; 375 | PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1; 376 | for ( ; pageToAllocate-- > 0; ++pageIndex ) 377 | pages_[pageIndex] = arrayAllocator()->allocateArrayPage(); 378 | } 379 | 380 | // Initialize all new entries 381 | IteratorState it; 382 | IteratorState itEnd; 383 | makeIterator( it, size_ ); 384 | size_ = index + 1; 385 | makeIterator( itEnd, size_ ); 386 | for ( ; !equals(it,itEnd); increment(it) ) 387 | { 388 | Value *value = &dereference(it); 389 | new (value) Value(); // Construct a default value using placement new 390 | } 391 | } 392 | 393 | Value & 394 | ValueInternalArray::resolveReference( ArrayIndex index ) 395 | { 396 | if ( index >= size_ ) 397 | makeIndexValid( index ); 398 | return pages_[index/itemsPerPage][index%itemsPerPage]; 399 | } 400 | 401 | Value * 402 | ValueInternalArray::find( ArrayIndex index ) const 403 | { 404 | if ( index >= size_ ) 405 | return 0; 406 | return &(pages_[index/itemsPerPage][index%itemsPerPage]); 407 | } 408 | 409 | ValueInternalArray::ArrayIndex 410 | ValueInternalArray::size() const 411 | { 412 | return size_; 413 | } 414 | 415 | int 416 | ValueInternalArray::distance( const IteratorState &x, const IteratorState &y ) 417 | { 418 | return indexOf(y) - indexOf(x); 419 | } 420 | 421 | 422 | ValueInternalArray::ArrayIndex 423 | ValueInternalArray::indexOf( const IteratorState &iterator ) 424 | { 425 | if ( !iterator.array_ ) 426 | return ArrayIndex(-1); 427 | return ArrayIndex( 428 | (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage 429 | + iterator.currentItemIndex_ ); 430 | } 431 | 432 | 433 | int 434 | ValueInternalArray::compare( const ValueInternalArray &other ) const 435 | { 436 | int sizeDiff( size_ - other.size_ ); 437 | if ( sizeDiff != 0 ) 438 | return sizeDiff; 439 | 440 | for ( ArrayIndex index =0; index < size_; ++index ) 441 | { 442 | int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( 443 | other.pages_[index/itemsPerPage][index%itemsPerPage] ); 444 | if ( diff != 0 ) 445 | return diff; 446 | } 447 | return 0; 448 | } 449 | -------------------------------------------------------------------------------- /json/json_internalmap.inl: -------------------------------------------------------------------------------- 1 | // included by json_value.cpp 2 | // everything is within Json namespace 3 | 4 | // ////////////////////////////////////////////////////////////////// 5 | // ////////////////////////////////////////////////////////////////// 6 | // ////////////////////////////////////////////////////////////////// 7 | // class ValueInternalMap 8 | // ////////////////////////////////////////////////////////////////// 9 | // ////////////////////////////////////////////////////////////////// 10 | // ////////////////////////////////////////////////////////////////// 11 | 12 | /** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) ); 13 | * This optimization is used by the fast allocator. 14 | */ 15 | ValueInternalLink::ValueInternalLink() 16 | : previous_( 0 ) 17 | , next_( 0 ) 18 | { 19 | } 20 | 21 | ValueInternalLink::~ValueInternalLink() 22 | { 23 | for ( int index =0; index < itemPerLink; ++index ) 24 | { 25 | if ( !items_[index].isItemAvailable() ) 26 | { 27 | if ( !items_[index].isMemberNameStatic() ) 28 | free( keys_[index] ); 29 | } 30 | else 31 | break; 32 | } 33 | } 34 | 35 | 36 | 37 | ValueMapAllocator::~ValueMapAllocator() 38 | { 39 | } 40 | 41 | #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 42 | class DefaultValueMapAllocator : public ValueMapAllocator 43 | { 44 | public: // overridden from ValueMapAllocator 45 | virtual ValueInternalMap *newMap() 46 | { 47 | return new ValueInternalMap(); 48 | } 49 | 50 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) 51 | { 52 | return new ValueInternalMap( other ); 53 | } 54 | 55 | virtual void destructMap( ValueInternalMap *map ) 56 | { 57 | delete map; 58 | } 59 | 60 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) 61 | { 62 | return new ValueInternalLink[size]; 63 | } 64 | 65 | virtual void releaseMapBuckets( ValueInternalLink *links ) 66 | { 67 | delete [] links; 68 | } 69 | 70 | virtual ValueInternalLink *allocateMapLink() 71 | { 72 | return new ValueInternalLink(); 73 | } 74 | 75 | virtual void releaseMapLink( ValueInternalLink *link ) 76 | { 77 | delete link; 78 | } 79 | }; 80 | #else 81 | /// @todo make this thread-safe (lock when accessign batch allocator) 82 | class DefaultValueMapAllocator : public ValueMapAllocator 83 | { 84 | public: // overridden from ValueMapAllocator 85 | virtual ValueInternalMap *newMap() 86 | { 87 | ValueInternalMap *map = mapsAllocator_.allocate(); 88 | new (map) ValueInternalMap(); // placement new 89 | return map; 90 | } 91 | 92 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) 93 | { 94 | ValueInternalMap *map = mapsAllocator_.allocate(); 95 | new (map) ValueInternalMap( other ); // placement new 96 | return map; 97 | } 98 | 99 | virtual void destructMap( ValueInternalMap *map ) 100 | { 101 | if ( map ) 102 | { 103 | map->~ValueInternalMap(); 104 | mapsAllocator_.release( map ); 105 | } 106 | } 107 | 108 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) 109 | { 110 | return new ValueInternalLink[size]; 111 | } 112 | 113 | virtual void releaseMapBuckets( ValueInternalLink *links ) 114 | { 115 | delete [] links; 116 | } 117 | 118 | virtual ValueInternalLink *allocateMapLink() 119 | { 120 | ValueInternalLink *link = linksAllocator_.allocate(); 121 | memset( link, 0, sizeof(ValueInternalLink) ); 122 | return link; 123 | } 124 | 125 | virtual void releaseMapLink( ValueInternalLink *link ) 126 | { 127 | link->~ValueInternalLink(); 128 | linksAllocator_.release( link ); 129 | } 130 | private: 131 | BatchAllocator mapsAllocator_; 132 | BatchAllocator linksAllocator_; 133 | }; 134 | #endif 135 | 136 | static ValueMapAllocator *&mapAllocator() 137 | { 138 | static DefaultValueMapAllocator defaultAllocator; 139 | static ValueMapAllocator *mapAllocator = &defaultAllocator; 140 | return mapAllocator; 141 | } 142 | 143 | static struct DummyMapAllocatorInitializer { 144 | DummyMapAllocatorInitializer() 145 | { 146 | mapAllocator(); // ensure mapAllocator() statics are initialized before main(). 147 | } 148 | } dummyMapAllocatorInitializer; 149 | 150 | 151 | 152 | // h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32. 153 | 154 | /* 155 | use linked list hash map. 156 | buckets array is a container. 157 | linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124) 158 | value have extra state: valid, available, deleted 159 | */ 160 | 161 | 162 | ValueInternalMap::ValueInternalMap() 163 | : buckets_( 0 ) 164 | , tailLink_( 0 ) 165 | , bucketsSize_( 0 ) 166 | , itemCount_( 0 ) 167 | { 168 | } 169 | 170 | 171 | ValueInternalMap::ValueInternalMap( const ValueInternalMap &other ) 172 | : buckets_( 0 ) 173 | , tailLink_( 0 ) 174 | , bucketsSize_( 0 ) 175 | , itemCount_( 0 ) 176 | { 177 | reserve( other.itemCount_ ); 178 | IteratorState it; 179 | IteratorState itEnd; 180 | other.makeBeginIterator( it ); 181 | other.makeEndIterator( itEnd ); 182 | for ( ; !equals(it,itEnd); increment(it) ) 183 | { 184 | bool isStatic; 185 | const char *memberName = key( it, isStatic ); 186 | const Value &aValue = value( it ); 187 | resolveReference(memberName, isStatic) = aValue; 188 | } 189 | } 190 | 191 | 192 | ValueInternalMap & 193 | ValueInternalMap::operator =( const ValueInternalMap &other ) 194 | { 195 | ValueInternalMap dummy( other ); 196 | swap( dummy ); 197 | return *this; 198 | } 199 | 200 | 201 | ValueInternalMap::~ValueInternalMap() 202 | { 203 | if ( buckets_ ) 204 | { 205 | for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex ) 206 | { 207 | ValueInternalLink *link = buckets_[bucketIndex].next_; 208 | while ( link ) 209 | { 210 | ValueInternalLink *linkToRelease = link; 211 | link = link->next_; 212 | mapAllocator()->releaseMapLink( linkToRelease ); 213 | } 214 | } 215 | mapAllocator()->releaseMapBuckets( buckets_ ); 216 | } 217 | } 218 | 219 | 220 | void 221 | ValueInternalMap::swap( ValueInternalMap &other ) 222 | { 223 | ValueInternalLink *tempBuckets = buckets_; 224 | buckets_ = other.buckets_; 225 | other.buckets_ = tempBuckets; 226 | ValueInternalLink *tempTailLink = tailLink_; 227 | tailLink_ = other.tailLink_; 228 | other.tailLink_ = tempTailLink; 229 | BucketIndex tempBucketsSize = bucketsSize_; 230 | bucketsSize_ = other.bucketsSize_; 231 | other.bucketsSize_ = tempBucketsSize; 232 | BucketIndex tempItemCount = itemCount_; 233 | itemCount_ = other.itemCount_; 234 | other.itemCount_ = tempItemCount; 235 | } 236 | 237 | 238 | void 239 | ValueInternalMap::clear() 240 | { 241 | ValueInternalMap dummy; 242 | swap( dummy ); 243 | } 244 | 245 | 246 | ValueInternalMap::BucketIndex 247 | ValueInternalMap::size() const 248 | { 249 | return itemCount_; 250 | } 251 | 252 | bool 253 | ValueInternalMap::reserveDelta( BucketIndex growth ) 254 | { 255 | return reserve( itemCount_ + growth ); 256 | } 257 | 258 | bool 259 | ValueInternalMap::reserve( BucketIndex newItemCount ) 260 | { 261 | if ( !buckets_ && newItemCount > 0 ) 262 | { 263 | buckets_ = mapAllocator()->allocateMapBuckets( 1 ); 264 | bucketsSize_ = 1; 265 | tailLink_ = &buckets_[0]; 266 | } 267 | // BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink; 268 | return true; 269 | } 270 | 271 | 272 | const Value * 273 | ValueInternalMap::find( const char *key ) const 274 | { 275 | if ( !bucketsSize_ ) 276 | return 0; 277 | HashKey hashedKey = hash( key ); 278 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 279 | for ( const ValueInternalLink *current = &buckets_[bucketIndex]; 280 | current != 0; 281 | current = current->next_ ) 282 | { 283 | for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index ) 284 | { 285 | if ( current->items_[index].isItemAvailable() ) 286 | return 0; 287 | if ( strcmp( key, current->keys_[index] ) == 0 ) 288 | return ¤t->items_[index]; 289 | } 290 | } 291 | return 0; 292 | } 293 | 294 | 295 | Value * 296 | ValueInternalMap::find( const char *key ) 297 | { 298 | const ValueInternalMap *constThis = this; 299 | return const_cast( constThis->find( key ) ); 300 | } 301 | 302 | 303 | Value & 304 | ValueInternalMap::resolveReference( const char *key, 305 | bool isStatic ) 306 | { 307 | HashKey hashedKey = hash( key ); 308 | if ( bucketsSize_ ) 309 | { 310 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 311 | ValueInternalLink **previous = 0; 312 | BucketIndex index; 313 | for ( ValueInternalLink *current = &buckets_[bucketIndex]; 314 | current != 0; 315 | previous = ¤t->next_, current = current->next_ ) 316 | { 317 | for ( index=0; index < ValueInternalLink::itemPerLink; ++index ) 318 | { 319 | if ( current->items_[index].isItemAvailable() ) 320 | return setNewItem( key, isStatic, current, index ); 321 | if ( strcmp( key, current->keys_[index] ) == 0 ) 322 | return current->items_[index]; 323 | } 324 | } 325 | } 326 | 327 | reserveDelta( 1 ); 328 | return unsafeAdd( key, isStatic, hashedKey ); 329 | } 330 | 331 | 332 | void 333 | ValueInternalMap::remove( const char *key ) 334 | { 335 | HashKey hashedKey = hash( key ); 336 | if ( !bucketsSize_ ) 337 | return; 338 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 339 | for ( ValueInternalLink *link = &buckets_[bucketIndex]; 340 | link != 0; 341 | link = link->next_ ) 342 | { 343 | BucketIndex index; 344 | for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) 345 | { 346 | if ( link->items_[index].isItemAvailable() ) 347 | return; 348 | if ( strcmp( key, link->keys_[index] ) == 0 ) 349 | { 350 | doActualRemove( link, index, bucketIndex ); 351 | return; 352 | } 353 | } 354 | } 355 | } 356 | 357 | void 358 | ValueInternalMap::doActualRemove( ValueInternalLink *link, 359 | BucketIndex index, 360 | BucketIndex bucketIndex ) 361 | { 362 | // find last item of the bucket and swap it with the 'removed' one. 363 | // set removed items flags to 'available'. 364 | // if last page only contains 'available' items, then desallocate it (it's empty) 365 | ValueInternalLink *&lastLink = getLastLinkInBucket( index ); 366 | BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1 367 | for ( ; 368 | lastItemIndex < ValueInternalLink::itemPerLink; 369 | ++lastItemIndex ) // may be optimized with dicotomic search 370 | { 371 | if ( lastLink->items_[lastItemIndex].isItemAvailable() ) 372 | break; 373 | } 374 | 375 | BucketIndex lastUsedIndex = lastItemIndex - 1; 376 | Value *valueToDelete = &link->items_[index]; 377 | Value *valueToPreserve = &lastLink->items_[lastUsedIndex]; 378 | if ( valueToDelete != valueToPreserve ) 379 | valueToDelete->swap( *valueToPreserve ); 380 | if ( lastUsedIndex == 0 ) // page is now empty 381 | { // remove it from bucket linked list and delete it. 382 | ValueInternalLink *linkPreviousToLast = lastLink->previous_; 383 | if ( linkPreviousToLast != 0 ) // can not deleted bucket link. 384 | { 385 | mapAllocator()->releaseMapLink( lastLink ); 386 | linkPreviousToLast->next_ = 0; 387 | lastLink = linkPreviousToLast; 388 | } 389 | } 390 | else 391 | { 392 | Value dummy; 393 | valueToPreserve->swap( dummy ); // restore deleted to default Value. 394 | valueToPreserve->setItemUsed( false ); 395 | } 396 | --itemCount_; 397 | } 398 | 399 | 400 | ValueInternalLink *& 401 | ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex ) 402 | { 403 | if ( bucketIndex == bucketsSize_ - 1 ) 404 | return tailLink_; 405 | ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_; 406 | if ( !previous ) 407 | previous = &buckets_[bucketIndex]; 408 | return previous; 409 | } 410 | 411 | 412 | Value & 413 | ValueInternalMap::setNewItem( const char *key, 414 | bool isStatic, 415 | ValueInternalLink *link, 416 | BucketIndex index ) 417 | { 418 | char *duplicatedKey = valueAllocator()->makeMemberName( key ); 419 | ++itemCount_; 420 | link->keys_[index] = duplicatedKey; 421 | link->items_[index].setItemUsed(); 422 | link->items_[index].setMemberNameIsStatic( isStatic ); 423 | return link->items_[index]; // items already default constructed. 424 | } 425 | 426 | 427 | Value & 428 | ValueInternalMap::unsafeAdd( const char *key, 429 | bool isStatic, 430 | HashKey hashedKey ) 431 | { 432 | JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." ); 433 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 434 | ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex ); 435 | ValueInternalLink *link = previousLink; 436 | BucketIndex index; 437 | for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) 438 | { 439 | if ( link->items_[index].isItemAvailable() ) 440 | break; 441 | } 442 | if ( index == ValueInternalLink::itemPerLink ) // need to add a new page 443 | { 444 | ValueInternalLink *newLink = mapAllocator()->allocateMapLink(); 445 | index = 0; 446 | link->next_ = newLink; 447 | previousLink = newLink; 448 | link = newLink; 449 | } 450 | return setNewItem( key, isStatic, link, index ); 451 | } 452 | 453 | 454 | ValueInternalMap::HashKey 455 | ValueInternalMap::hash( const char *key ) const 456 | { 457 | HashKey hash = 0; 458 | while ( *key ) 459 | hash += *key++ * 37; 460 | return hash; 461 | } 462 | 463 | 464 | int 465 | ValueInternalMap::compare( const ValueInternalMap &other ) const 466 | { 467 | int sizeDiff( itemCount_ - other.itemCount_ ); 468 | if ( sizeDiff != 0 ) 469 | return sizeDiff; 470 | // Strict order guaranty is required. Compare all keys FIRST, then compare values. 471 | IteratorState it; 472 | IteratorState itEnd; 473 | makeBeginIterator( it ); 474 | makeEndIterator( itEnd ); 475 | for ( ; !equals(it,itEnd); increment(it) ) 476 | { 477 | if ( !other.find( key( it ) ) ) 478 | return 1; 479 | } 480 | 481 | // All keys are equals, let's compare values 482 | makeBeginIterator( it ); 483 | for ( ; !equals(it,itEnd); increment(it) ) 484 | { 485 | const Value *otherValue = other.find( key( it ) ); 486 | int valueDiff = value(it).compare( *otherValue ); 487 | if ( valueDiff != 0 ) 488 | return valueDiff; 489 | } 490 | return 0; 491 | } 492 | 493 | 494 | void 495 | ValueInternalMap::makeBeginIterator( IteratorState &it ) const 496 | { 497 | it.map_ = const_cast( this ); 498 | it.bucketIndex_ = 0; 499 | it.itemIndex_ = 0; 500 | it.link_ = buckets_; 501 | } 502 | 503 | 504 | void 505 | ValueInternalMap::makeEndIterator( IteratorState &it ) const 506 | { 507 | it.map_ = const_cast( this ); 508 | it.bucketIndex_ = bucketsSize_; 509 | it.itemIndex_ = 0; 510 | it.link_ = 0; 511 | } 512 | 513 | 514 | bool 515 | ValueInternalMap::equals( const IteratorState &x, const IteratorState &other ) 516 | { 517 | return x.map_ == other.map_ 518 | && x.bucketIndex_ == other.bucketIndex_ 519 | && x.link_ == other.link_ 520 | && x.itemIndex_ == other.itemIndex_; 521 | } 522 | 523 | 524 | void 525 | ValueInternalMap::incrementBucket( IteratorState &iterator ) 526 | { 527 | ++iterator.bucketIndex_; 528 | JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_, 529 | "ValueInternalMap::increment(): attempting to iterate beyond end." ); 530 | if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ ) 531 | iterator.link_ = 0; 532 | else 533 | iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]); 534 | iterator.itemIndex_ = 0; 535 | } 536 | 537 | 538 | void 539 | ValueInternalMap::increment( IteratorState &iterator ) 540 | { 541 | JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." ); 542 | ++iterator.itemIndex_; 543 | if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink ) 544 | { 545 | JSON_ASSERT_MESSAGE( iterator.link_ != 0, 546 | "ValueInternalMap::increment(): attempting to iterate beyond end." ); 547 | iterator.link_ = iterator.link_->next_; 548 | if ( iterator.link_ == 0 ) 549 | incrementBucket( iterator ); 550 | } 551 | else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() ) 552 | { 553 | incrementBucket( iterator ); 554 | } 555 | } 556 | 557 | 558 | void 559 | ValueInternalMap::decrement( IteratorState &iterator ) 560 | { 561 | if ( iterator.itemIndex_ == 0 ) 562 | { 563 | JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." ); 564 | if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] ) 565 | { 566 | JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." ); 567 | --(iterator.bucketIndex_); 568 | } 569 | iterator.link_ = iterator.link_->previous_; 570 | iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1; 571 | } 572 | } 573 | 574 | 575 | const char * 576 | ValueInternalMap::key( const IteratorState &iterator ) 577 | { 578 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); 579 | return iterator.link_->keys_[iterator.itemIndex_]; 580 | } 581 | 582 | const char * 583 | ValueInternalMap::key( const IteratorState &iterator, bool &isStatic ) 584 | { 585 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); 586 | isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic(); 587 | return iterator.link_->keys_[iterator.itemIndex_]; 588 | } 589 | 590 | 591 | Value & 592 | ValueInternalMap::value( const IteratorState &iterator ) 593 | { 594 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); 595 | return iterator.link_->items_[iterator.itemIndex_]; 596 | } 597 | 598 | 599 | int 600 | ValueInternalMap::distance( const IteratorState &x, const IteratorState &y ) 601 | { 602 | int offset = 0; 603 | IteratorState it = x; 604 | while ( !equals( it, y ) ) 605 | increment( it ); 606 | return offset; 607 | } 608 | -------------------------------------------------------------------------------- /json/json_reader.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "reader.h" 3 | #include "value.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if _MSC_VER >= 1400 // VC++ 8.0 12 | #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. 13 | #endif 14 | 15 | namespace Json { 16 | 17 | // Implementation of class Features 18 | // //////////////////////////////// 19 | 20 | Features::Features() 21 | : allowComments_( true ) 22 | , strictRoot_( false ) 23 | { 24 | } 25 | 26 | 27 | Features 28 | Features::all() 29 | { 30 | return Features(); 31 | } 32 | 33 | 34 | Features 35 | Features::strictMode() 36 | { 37 | Features features; 38 | features.allowComments_ = false; 39 | features.strictRoot_ = true; 40 | return features; 41 | } 42 | 43 | // Implementation of class Reader 44 | // //////////////////////////////// 45 | 46 | 47 | static inline bool 48 | in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) 49 | { 50 | return c == c1 || c == c2 || c == c3 || c == c4; 51 | } 52 | 53 | static inline bool 54 | in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) 55 | { 56 | return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; 57 | } 58 | 59 | 60 | static bool 61 | containsNewLine( Reader::Location begin, 62 | Reader::Location end ) 63 | { 64 | for ( ;begin < end; ++begin ) 65 | if ( *begin == '\n' || *begin == '\r' ) 66 | return true; 67 | return false; 68 | } 69 | 70 | static std::string codePointToUTF8(unsigned int cp) 71 | { 72 | std::string result; 73 | 74 | // based on description from http://en.wikipedia.org/wiki/UTF-8 75 | 76 | if (cp <= 0x7f) 77 | { 78 | result.resize(1); 79 | result[0] = static_cast(cp); 80 | } 81 | else if (cp <= 0x7FF) 82 | { 83 | result.resize(2); 84 | result[1] = static_cast(0x80 | (0x3f & cp)); 85 | result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); 86 | } 87 | else if (cp <= 0xFFFF) 88 | { 89 | result.resize(3); 90 | result[2] = static_cast(0x80 | (0x3f & cp)); 91 | result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); 92 | result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); 93 | } 94 | else if (cp <= 0x10FFFF) 95 | { 96 | result.resize(4); 97 | result[3] = static_cast(0x80 | (0x3f & cp)); 98 | result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); 99 | result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); 100 | result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); 101 | } 102 | 103 | return result; 104 | } 105 | 106 | 107 | // Class Reader 108 | // ////////////////////////////////////////////////////////////////// 109 | 110 | Reader::Reader() 111 | : features_( Features::all() ) 112 | { 113 | } 114 | 115 | 116 | Reader::Reader( const Features &features ) 117 | : features_( features ) 118 | { 119 | } 120 | 121 | 122 | bool 123 | Reader::parse( const std::string &document, 124 | Value &root, 125 | bool collectComments ) 126 | { 127 | document_ = document; 128 | const char *begin = document_.c_str(); 129 | const char *end = begin + document_.length(); 130 | return parse( begin, end, root, collectComments ); 131 | } 132 | 133 | 134 | bool 135 | Reader::parse( std::istream& sin, 136 | Value &root, 137 | bool collectComments ) 138 | { 139 | //std::istream_iterator begin(sin); 140 | //std::istream_iterator end; 141 | // Those would allow streamed input from a file, if parse() were a 142 | // template function. 143 | 144 | // Since std::string is reference-counted, this at least does not 145 | // create an extra copy. 146 | std::string doc; 147 | std::getline(sin, doc, (char)EOF); 148 | return parse( doc, root, collectComments ); 149 | } 150 | 151 | bool 152 | Reader::parse( const char *beginDoc, const char *endDoc, 153 | Value &root, 154 | bool collectComments ) 155 | { 156 | if ( !features_.allowComments_ ) 157 | { 158 | collectComments = false; 159 | } 160 | 161 | begin_ = beginDoc; 162 | end_ = endDoc; 163 | collectComments_ = collectComments; 164 | current_ = begin_; 165 | lastValueEnd_ = 0; 166 | lastValue_ = 0; 167 | commentsBefore_ = ""; 168 | errors_.clear(); 169 | while ( !nodes_.empty() ) 170 | nodes_.pop(); 171 | nodes_.push( &root ); 172 | 173 | bool successful = readValue(); 174 | Token token; 175 | skipCommentTokens( token ); 176 | if ( collectComments_ && !commentsBefore_.empty() ) 177 | root.setComment( commentsBefore_, commentAfter ); 178 | if ( features_.strictRoot_ ) 179 | { 180 | if ( !root.isArray() && !root.isObject() ) 181 | { 182 | // Set error location to start of doc, ideally should be first token found in doc 183 | token.type_ = tokenError; 184 | token.start_ = beginDoc; 185 | token.end_ = endDoc; 186 | addError( "A valid JSON document must be either an array or an object value.", 187 | token ); 188 | return false; 189 | } 190 | } 191 | return successful; 192 | } 193 | 194 | 195 | bool 196 | Reader::readValue() 197 | { 198 | Token token; 199 | skipCommentTokens( token ); 200 | bool successful = true; 201 | 202 | if ( collectComments_ && !commentsBefore_.empty() ) 203 | { 204 | currentValue().setComment( commentsBefore_, commentBefore ); 205 | commentsBefore_ = ""; 206 | } 207 | 208 | 209 | switch ( token.type_ ) 210 | { 211 | case tokenObjectBegin: 212 | successful = readObject( token ); 213 | break; 214 | case tokenArrayBegin: 215 | successful = readArray( token ); 216 | break; 217 | case tokenNumber: 218 | successful = decodeNumber( token ); 219 | break; 220 | case tokenString: 221 | successful = decodeString( token ); 222 | break; 223 | case tokenTrue: 224 | currentValue() = true; 225 | break; 226 | case tokenFalse: 227 | currentValue() = false; 228 | break; 229 | case tokenNull: 230 | currentValue() = Value(); 231 | break; 232 | default: 233 | return addError( "Syntax error: value, object or array expected.", token ); 234 | } 235 | 236 | if ( collectComments_ ) 237 | { 238 | lastValueEnd_ = current_; 239 | lastValue_ = ¤tValue(); 240 | } 241 | 242 | return successful; 243 | } 244 | 245 | 246 | void 247 | Reader::skipCommentTokens( Token &token ) 248 | { 249 | if ( features_.allowComments_ ) 250 | { 251 | do 252 | { 253 | readToken( token ); 254 | } 255 | while ( token.type_ == tokenComment ); 256 | } 257 | else 258 | { 259 | readToken( token ); 260 | } 261 | } 262 | 263 | 264 | bool 265 | Reader::expectToken( TokenType type, Token &token, const char *message ) 266 | { 267 | readToken( token ); 268 | if ( token.type_ != type ) 269 | return addError( message, token ); 270 | return true; 271 | } 272 | 273 | 274 | bool 275 | Reader::readToken( Token &token ) 276 | { 277 | skipSpaces(); 278 | token.start_ = current_; 279 | Char c = getNextChar(); 280 | bool ok = true; 281 | switch ( c ) 282 | { 283 | case '{': 284 | token.type_ = tokenObjectBegin; 285 | break; 286 | case '}': 287 | token.type_ = tokenObjectEnd; 288 | break; 289 | case '[': 290 | token.type_ = tokenArrayBegin; 291 | break; 292 | case ']': 293 | token.type_ = tokenArrayEnd; 294 | break; 295 | case '"': 296 | token.type_ = tokenString; 297 | ok = readString(); 298 | break; 299 | case '/': 300 | token.type_ = tokenComment; 301 | ok = readComment(); 302 | break; 303 | case '0': 304 | case '1': 305 | case '2': 306 | case '3': 307 | case '4': 308 | case '5': 309 | case '6': 310 | case '7': 311 | case '8': 312 | case '9': 313 | case '-': 314 | token.type_ = tokenNumber; 315 | readNumber(); 316 | break; 317 | case 't': 318 | token.type_ = tokenTrue; 319 | ok = match( "rue", 3 ); 320 | break; 321 | case 'f': 322 | token.type_ = tokenFalse; 323 | ok = match( "alse", 4 ); 324 | break; 325 | case 'n': 326 | token.type_ = tokenNull; 327 | ok = match( "ull", 3 ); 328 | break; 329 | case ',': 330 | token.type_ = tokenArraySeparator; 331 | break; 332 | case ':': 333 | token.type_ = tokenMemberSeparator; 334 | break; 335 | case 0: 336 | token.type_ = tokenEndOfStream; 337 | break; 338 | default: 339 | ok = false; 340 | break; 341 | } 342 | if ( !ok ) 343 | token.type_ = tokenError; 344 | token.end_ = current_; 345 | return true; 346 | } 347 | 348 | 349 | void 350 | Reader::skipSpaces() 351 | { 352 | while ( current_ != end_ ) 353 | { 354 | Char c = *current_; 355 | if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) 356 | ++current_; 357 | else 358 | break; 359 | } 360 | } 361 | 362 | 363 | bool 364 | Reader::match( Location pattern, 365 | int patternLength ) 366 | { 367 | if ( end_ - current_ < patternLength ) 368 | return false; 369 | int index = patternLength; 370 | while ( index-- ) 371 | if ( current_[index] != pattern[index] ) 372 | return false; 373 | current_ += patternLength; 374 | return true; 375 | } 376 | 377 | 378 | bool 379 | Reader::readComment() 380 | { 381 | Location commentBegin = current_ - 1; 382 | Char c = getNextChar(); 383 | bool successful = false; 384 | if ( c == '*' ) 385 | successful = readCStyleComment(); 386 | else if ( c == '/' ) 387 | successful = readCppStyleComment(); 388 | if ( !successful ) 389 | return false; 390 | 391 | if ( collectComments_ ) 392 | { 393 | CommentPlacement placement = commentBefore; 394 | if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) 395 | { 396 | if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) 397 | placement = commentAfterOnSameLine; 398 | } 399 | 400 | addComment( commentBegin, current_, placement ); 401 | } 402 | return true; 403 | } 404 | 405 | 406 | void 407 | Reader::addComment( Location begin, 408 | Location end, 409 | CommentPlacement placement ) 410 | { 411 | assert( collectComments_ ); 412 | if ( placement == commentAfterOnSameLine ) 413 | { 414 | assert( lastValue_ != 0 ); 415 | lastValue_->setComment( std::string( begin, end ), placement ); 416 | } 417 | else 418 | { 419 | if ( !commentsBefore_.empty() ) 420 | commentsBefore_ += "\n"; 421 | commentsBefore_ += std::string( begin, end ); 422 | } 423 | } 424 | 425 | 426 | bool 427 | Reader::readCStyleComment() 428 | { 429 | while ( current_ != end_ ) 430 | { 431 | Char c = getNextChar(); 432 | if ( c == '*' && *current_ == '/' ) 433 | break; 434 | } 435 | return getNextChar() == '/'; 436 | } 437 | 438 | 439 | bool 440 | Reader::readCppStyleComment() 441 | { 442 | while ( current_ != end_ ) 443 | { 444 | Char c = getNextChar(); 445 | if ( c == '\r' || c == '\n' ) 446 | break; 447 | } 448 | return true; 449 | } 450 | 451 | 452 | void 453 | Reader::readNumber() 454 | { 455 | while ( current_ != end_ ) 456 | { 457 | if ( !(*current_ >= '0' && *current_ <= '9') && 458 | !in( *current_, '.', 'e', 'E', '+', '-' ) ) 459 | break; 460 | ++current_; 461 | } 462 | } 463 | 464 | bool 465 | Reader::readString() 466 | { 467 | Char c = 0; 468 | while ( current_ != end_ ) 469 | { 470 | c = getNextChar(); 471 | if ( c == '\\' ) 472 | getNextChar(); 473 | else if ( c == '"' ) 474 | break; 475 | } 476 | return c == '"'; 477 | } 478 | 479 | 480 | bool 481 | Reader::readObject( Token &tokenStart ) 482 | { 483 | Token tokenName; 484 | std::string name; 485 | currentValue() = Value( objectValue ); 486 | while ( readToken( tokenName ) ) 487 | { 488 | bool initialTokenOk = true; 489 | while ( tokenName.type_ == tokenComment && initialTokenOk ) 490 | initialTokenOk = readToken( tokenName ); 491 | if ( !initialTokenOk ) 492 | break; 493 | if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object 494 | return true; 495 | if ( tokenName.type_ != tokenString ) 496 | break; 497 | 498 | name = ""; 499 | if ( !decodeString( tokenName, name ) ) 500 | return recoverFromError( tokenObjectEnd ); 501 | 502 | Token colon; 503 | if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) 504 | { 505 | return addErrorAndRecover( "Missing ':' after object member name", 506 | colon, 507 | tokenObjectEnd ); 508 | } 509 | Value &value = currentValue()[ name ]; 510 | nodes_.push( &value ); 511 | bool ok = readValue(); 512 | nodes_.pop(); 513 | if ( !ok ) // error already set 514 | return recoverFromError( tokenObjectEnd ); 515 | 516 | Token comma; 517 | if ( !readToken( comma ) 518 | || ( comma.type_ != tokenObjectEnd && 519 | comma.type_ != tokenArraySeparator && 520 | comma.type_ != tokenComment ) ) 521 | { 522 | return addErrorAndRecover( "Missing ',' or '}' in object declaration", 523 | comma, 524 | tokenObjectEnd ); 525 | } 526 | bool finalizeTokenOk = true; 527 | while ( comma.type_ == tokenComment && 528 | finalizeTokenOk ) 529 | finalizeTokenOk = readToken( comma ); 530 | if ( comma.type_ == tokenObjectEnd ) 531 | return true; 532 | } 533 | return addErrorAndRecover( "Missing '}' or object member name", 534 | tokenName, 535 | tokenObjectEnd ); 536 | } 537 | 538 | 539 | bool 540 | Reader::readArray( Token &tokenStart ) 541 | { 542 | currentValue() = Value( arrayValue ); 543 | skipSpaces(); 544 | if ( *current_ == ']' ) // empty array 545 | { 546 | Token endArray; 547 | readToken( endArray ); 548 | return true; 549 | } 550 | int index = 0; 551 | while ( true ) 552 | { 553 | Value &value = currentValue()[ index++ ]; 554 | nodes_.push( &value ); 555 | bool ok = readValue(); 556 | nodes_.pop(); 557 | if ( !ok ) // error already set 558 | return recoverFromError( tokenArrayEnd ); 559 | 560 | Token token; 561 | // Accept Comment after last item in the array. 562 | ok = readToken( token ); 563 | while ( token.type_ == tokenComment && ok ) 564 | { 565 | ok = readToken( token ); 566 | } 567 | bool badTokenType = ( token.type_ == tokenArraySeparator && 568 | token.type_ == tokenArrayEnd ); 569 | if ( !ok || badTokenType ) 570 | { 571 | return addErrorAndRecover( "Missing ',' or ']' in array declaration", 572 | token, 573 | tokenArrayEnd ); 574 | } 575 | if ( token.type_ == tokenArrayEnd ) 576 | break; 577 | } 578 | return true; 579 | } 580 | 581 | 582 | bool 583 | Reader::decodeNumber( Token &token ) 584 | { 585 | bool isDouble = false; 586 | for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) 587 | { 588 | isDouble = isDouble 589 | || in( *inspect, '.', 'e', 'E', '+' ) 590 | || ( *inspect == '-' && inspect != token.start_ ); 591 | } 592 | if ( isDouble ) 593 | return decodeDouble( token ); 594 | Location current = token.start_; 595 | bool isNegative = *current == '-'; 596 | if ( isNegative ) 597 | ++current; 598 | Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) 599 | : Value::maxUInt) / 10; 600 | Value::UInt value = 0; 601 | while ( current < token.end_ ) 602 | { 603 | Char c = *current++; 604 | if ( c < '0' || c > '9' ) 605 | return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); 606 | if ( value >= threshold ) 607 | return decodeDouble( token ); 608 | value = value * 10 + Value::UInt(c - '0'); 609 | } 610 | if ( isNegative ) 611 | currentValue() = -Value::Int( value ); 612 | else if ( value <= Value::UInt(Value::maxInt) ) 613 | currentValue() = Value::Int( value ); 614 | else 615 | currentValue() = value; 616 | return true; 617 | } 618 | 619 | 620 | bool 621 | Reader::decodeDouble( Token &token ) 622 | { 623 | double value = 0; 624 | const int bufferSize = 32; 625 | int count; 626 | int length = int(token.end_ - token.start_); 627 | if ( length <= bufferSize ) 628 | { 629 | Char buffer[bufferSize]; 630 | memcpy( buffer, token.start_, length ); 631 | buffer[length] = 0; 632 | count = sscanf( buffer, "%lf", &value ); 633 | } 634 | else 635 | { 636 | std::string buffer( token.start_, token.end_ ); 637 | count = sscanf( buffer.c_str(), "%lf", &value ); 638 | } 639 | 640 | if ( count != 1 ) 641 | return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); 642 | currentValue() = value; 643 | return true; 644 | } 645 | 646 | 647 | bool 648 | Reader::decodeString( Token &token ) 649 | { 650 | std::string decoded; 651 | if ( !decodeString( token, decoded ) ) 652 | return false; 653 | currentValue() = decoded; 654 | return true; 655 | } 656 | 657 | 658 | bool 659 | Reader::decodeString( Token &token, std::string &decoded ) 660 | { 661 | decoded.reserve( token.end_ - token.start_ - 2 ); 662 | Location current = token.start_ + 1; // skip '"' 663 | Location end = token.end_ - 1; // do not include '"' 664 | while ( current != end ) 665 | { 666 | Char c = *current++; 667 | if ( c == '"' ) 668 | break; 669 | else if ( c == '\\' ) 670 | { 671 | if ( current == end ) 672 | return addError( "Empty escape sequence in string", token, current ); 673 | Char escape = *current++; 674 | switch ( escape ) 675 | { 676 | case '"': decoded += '"'; break; 677 | case '/': decoded += '/'; break; 678 | case '\\': decoded += '\\'; break; 679 | case 'b': decoded += '\b'; break; 680 | case 'f': decoded += '\f'; break; 681 | case 'n': decoded += '\n'; break; 682 | case 'r': decoded += '\r'; break; 683 | case 't': decoded += '\t'; break; 684 | case 'u': 685 | { 686 | unsigned int unicode; 687 | if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) 688 | return false; 689 | decoded += codePointToUTF8(unicode); 690 | } 691 | break; 692 | default: 693 | return addError( "Bad escape sequence in string", token, current ); 694 | } 695 | } 696 | else 697 | { 698 | decoded += c; 699 | } 700 | } 701 | return true; 702 | } 703 | 704 | bool 705 | Reader::decodeUnicodeCodePoint( Token &token, 706 | Location ¤t, 707 | Location end, 708 | unsigned int &unicode ) 709 | { 710 | 711 | if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) 712 | return false; 713 | if (unicode >= 0xD800 && unicode <= 0xDBFF) 714 | { 715 | // surrogate pairs 716 | if (end - current < 6) 717 | return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); 718 | unsigned int surrogatePair; 719 | if (*(current++) == '\\' && *(current++)== 'u') 720 | { 721 | if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) 722 | { 723 | unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); 724 | } 725 | else 726 | return false; 727 | } 728 | else 729 | return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); 730 | } 731 | return true; 732 | } 733 | 734 | bool 735 | Reader::decodeUnicodeEscapeSequence( Token &token, 736 | Location ¤t, 737 | Location end, 738 | unsigned int &unicode ) 739 | { 740 | if ( end - current < 4 ) 741 | return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); 742 | unicode = 0; 743 | for ( int index =0; index < 4; ++index ) 744 | { 745 | Char c = *current++; 746 | unicode *= 16; 747 | if ( c >= '0' && c <= '9' ) 748 | unicode += c - '0'; 749 | else if ( c >= 'a' && c <= 'f' ) 750 | unicode += c - 'a' + 10; 751 | else if ( c >= 'A' && c <= 'F' ) 752 | unicode += c - 'A' + 10; 753 | else 754 | return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); 755 | } 756 | return true; 757 | } 758 | 759 | 760 | bool 761 | Reader::addError( const std::string &message, 762 | Token &token, 763 | Location extra ) 764 | { 765 | ErrorInfo info; 766 | info.token_ = token; 767 | info.message_ = message; 768 | info.extra_ = extra; 769 | errors_.push_back( info ); 770 | return false; 771 | } 772 | 773 | 774 | bool 775 | Reader::recoverFromError( TokenType skipUntilToken ) 776 | { 777 | int errorCount = int(errors_.size()); 778 | Token skip; 779 | while ( true ) 780 | { 781 | if ( !readToken(skip) ) 782 | errors_.resize( errorCount ); // discard errors caused by recovery 783 | if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) 784 | break; 785 | } 786 | errors_.resize( errorCount ); 787 | return false; 788 | } 789 | 790 | 791 | bool 792 | Reader::addErrorAndRecover( const std::string &message, 793 | Token &token, 794 | TokenType skipUntilToken ) 795 | { 796 | addError( message, token ); 797 | return recoverFromError( skipUntilToken ); 798 | } 799 | 800 | 801 | Value & 802 | Reader::currentValue() 803 | { 804 | return *(nodes_.top()); 805 | } 806 | 807 | 808 | Reader::Char 809 | Reader::getNextChar() 810 | { 811 | if ( current_ == end_ ) 812 | return 0; 813 | return *current_++; 814 | } 815 | 816 | 817 | void 818 | Reader::getLocationLineAndColumn( Location location, 819 | int &line, 820 | int &column ) const 821 | { 822 | Location current = begin_; 823 | Location lastLineStart = current; 824 | line = 0; 825 | while ( current < location && current != end_ ) 826 | { 827 | Char c = *current++; 828 | if ( c == '\r' ) 829 | { 830 | if ( *current == '\n' ) 831 | ++current; 832 | lastLineStart = current; 833 | ++line; 834 | } 835 | else if ( c == '\n' ) 836 | { 837 | lastLineStart = current; 838 | ++line; 839 | } 840 | } 841 | // column & line start at 1 842 | column = int(location - lastLineStart) + 1; 843 | ++line; 844 | } 845 | 846 | 847 | std::string 848 | Reader::getLocationLineAndColumn( Location location ) const 849 | { 850 | int line, column; 851 | getLocationLineAndColumn( location, line, column ); 852 | char buffer[18+16+16+1]; 853 | sprintf( buffer, "Line %d, Column %d", line, column ); 854 | return buffer; 855 | } 856 | 857 | 858 | std::string 859 | Reader::getFormatedErrorMessages() const 860 | { 861 | std::string formattedMessage; 862 | for ( Errors::const_iterator itError = errors_.begin(); 863 | itError != errors_.end(); 864 | ++itError ) 865 | { 866 | const ErrorInfo &error = *itError; 867 | formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; 868 | formattedMessage += " " + error.message_ + "\n"; 869 | if ( error.extra_ ) 870 | formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; 871 | } 872 | return formattedMessage; 873 | } 874 | 875 | 876 | std::istream& operator>>( std::istream &sin, Value &root ) 877 | { 878 | Json::Reader reader; 879 | bool ok = reader.parse(sin, root, true); 880 | //JSON_ASSERT( ok ); 881 | if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); 882 | return sin; 883 | } 884 | 885 | 886 | } // namespace Json 887 | -------------------------------------------------------------------------------- /json/json_valueiterator.inl: -------------------------------------------------------------------------------- 1 | // included by json_value.cpp 2 | // everything is within Json namespace 3 | 4 | 5 | // ////////////////////////////////////////////////////////////////// 6 | // ////////////////////////////////////////////////////////////////// 7 | // ////////////////////////////////////////////////////////////////// 8 | // class ValueIteratorBase 9 | // ////////////////////////////////////////////////////////////////// 10 | // ////////////////////////////////////////////////////////////////// 11 | // ////////////////////////////////////////////////////////////////// 12 | 13 | ValueIteratorBase::ValueIteratorBase() 14 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 15 | : current_() 16 | , isNull_( true ) 17 | { 18 | } 19 | #else 20 | : isArray_( true ) 21 | , isNull_( true ) 22 | { 23 | iterator_.array_ = ValueInternalArray::IteratorState(); 24 | } 25 | #endif 26 | 27 | 28 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 29 | ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) 30 | : current_( current ) 31 | , isNull_( false ) 32 | { 33 | } 34 | #else 35 | ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) 36 | : isArray_( true ) 37 | { 38 | iterator_.array_ = state; 39 | } 40 | 41 | 42 | ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) 43 | : isArray_( false ) 44 | { 45 | iterator_.map_ = state; 46 | } 47 | #endif 48 | 49 | Value & 50 | ValueIteratorBase::deref() const 51 | { 52 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 53 | return current_->second; 54 | #else 55 | if ( isArray_ ) 56 | return ValueInternalArray::dereference( iterator_.array_ ); 57 | return ValueInternalMap::value( iterator_.map_ ); 58 | #endif 59 | } 60 | 61 | 62 | void 63 | ValueIteratorBase::increment() 64 | { 65 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 66 | ++current_; 67 | #else 68 | if ( isArray_ ) 69 | ValueInternalArray::increment( iterator_.array_ ); 70 | ValueInternalMap::increment( iterator_.map_ ); 71 | #endif 72 | } 73 | 74 | 75 | void 76 | ValueIteratorBase::decrement() 77 | { 78 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 79 | --current_; 80 | #else 81 | if ( isArray_ ) 82 | ValueInternalArray::decrement( iterator_.array_ ); 83 | ValueInternalMap::decrement( iterator_.map_ ); 84 | #endif 85 | } 86 | 87 | 88 | ValueIteratorBase::difference_type 89 | ValueIteratorBase::computeDistance( const SelfType &other ) const 90 | { 91 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 92 | # ifdef JSON_USE_CPPTL_SMALLMAP 93 | return current_ - other.current_; 94 | # else 95 | // Iterator for null value are initialized using the default 96 | // constructor, which initialize current_ to the default 97 | // std::map::iterator. As begin() and end() are two instance 98 | // of the default std::map::iterator, they can not be compared. 99 | // To allow this, we handle this comparison specifically. 100 | if ( isNull_ && other.isNull_ ) 101 | { 102 | return 0; 103 | } 104 | 105 | 106 | // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, 107 | // which is the one used by default). 108 | // Using a portable hand-made version for non random iterator instead: 109 | // return difference_type( std::distance( current_, other.current_ ) ); 110 | difference_type myDistance = 0; 111 | for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) 112 | { 113 | ++myDistance; 114 | } 115 | return myDistance; 116 | # endif 117 | #else 118 | if ( isArray_ ) 119 | return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); 120 | return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); 121 | #endif 122 | } 123 | 124 | 125 | bool 126 | ValueIteratorBase::isEqual( const SelfType &other ) const 127 | { 128 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 129 | if ( isNull_ ) 130 | { 131 | return other.isNull_; 132 | } 133 | return current_ == other.current_; 134 | #else 135 | if ( isArray_ ) 136 | return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); 137 | return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); 138 | #endif 139 | } 140 | 141 | 142 | void 143 | ValueIteratorBase::copy( const SelfType &other ) 144 | { 145 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 146 | current_ = other.current_; 147 | #else 148 | if ( isArray_ ) 149 | iterator_.array_ = other.iterator_.array_; 150 | iterator_.map_ = other.iterator_.map_; 151 | #endif 152 | } 153 | 154 | 155 | Value 156 | ValueIteratorBase::key() const 157 | { 158 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 159 | const Value::CZString czstring = (*current_).first; 160 | if ( czstring.c_str() ) 161 | { 162 | if ( czstring.isStaticString() ) 163 | return Value( StaticString( czstring.c_str() ) ); 164 | return Value( czstring.c_str() ); 165 | } 166 | return Value( czstring.index() ); 167 | #else 168 | if ( isArray_ ) 169 | return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); 170 | bool isStatic; 171 | const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); 172 | if ( isStatic ) 173 | return Value( StaticString( memberName ) ); 174 | return Value( memberName ); 175 | #endif 176 | } 177 | 178 | 179 | UInt 180 | ValueIteratorBase::index() const 181 | { 182 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 183 | const Value::CZString czstring = (*current_).first; 184 | if ( !czstring.c_str() ) 185 | return czstring.index(); 186 | return Value::UInt( -1 ); 187 | #else 188 | if ( isArray_ ) 189 | return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); 190 | return Value::UInt( -1 ); 191 | #endif 192 | } 193 | 194 | 195 | const char * 196 | ValueIteratorBase::memberName() const 197 | { 198 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 199 | const char *name = (*current_).first.c_str(); 200 | return name ? name : ""; 201 | #else 202 | if ( !isArray_ ) 203 | return ValueInternalMap::key( iterator_.map_ ); 204 | return ""; 205 | #endif 206 | } 207 | 208 | 209 | // ////////////////////////////////////////////////////////////////// 210 | // ////////////////////////////////////////////////////////////////// 211 | // ////////////////////////////////////////////////////////////////// 212 | // class ValueConstIterator 213 | // ////////////////////////////////////////////////////////////////// 214 | // ////////////////////////////////////////////////////////////////// 215 | // ////////////////////////////////////////////////////////////////// 216 | 217 | ValueConstIterator::ValueConstIterator() 218 | { 219 | } 220 | 221 | 222 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 223 | ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) 224 | : ValueIteratorBase( current ) 225 | { 226 | } 227 | #else 228 | ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) 229 | : ValueIteratorBase( state ) 230 | { 231 | } 232 | 233 | ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) 234 | : ValueIteratorBase( state ) 235 | { 236 | } 237 | #endif 238 | 239 | ValueConstIterator & 240 | ValueConstIterator::operator =( const ValueIteratorBase &other ) 241 | { 242 | copy( other ); 243 | return *this; 244 | } 245 | 246 | 247 | // ////////////////////////////////////////////////////////////////// 248 | // ////////////////////////////////////////////////////////////////// 249 | // ////////////////////////////////////////////////////////////////// 250 | // class ValueIterator 251 | // ////////////////////////////////////////////////////////////////// 252 | // ////////////////////////////////////////////////////////////////// 253 | // ////////////////////////////////////////////////////////////////// 254 | 255 | ValueIterator::ValueIterator() 256 | { 257 | } 258 | 259 | 260 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 261 | ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) 262 | : ValueIteratorBase( current ) 263 | { 264 | } 265 | #else 266 | ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) 267 | : ValueIteratorBase( state ) 268 | { 269 | } 270 | 271 | ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) 272 | : ValueIteratorBase( state ) 273 | { 274 | } 275 | #endif 276 | 277 | ValueIterator::ValueIterator( const ValueConstIterator &other ) 278 | : ValueIteratorBase( other ) 279 | { 280 | } 281 | 282 | ValueIterator::ValueIterator( const ValueIterator &other ) 283 | : ValueIteratorBase( other ) 284 | { 285 | } 286 | 287 | ValueIterator & 288 | ValueIterator::operator =( const SelfType &other ) 289 | { 290 | copy( other ); 291 | return *this; 292 | } 293 | -------------------------------------------------------------------------------- /json/json_writer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "writer.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if _MSC_VER >= 1400 // VC++ 8.0 12 | #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. 13 | #endif 14 | 15 | namespace Json { 16 | 17 | static bool isControlCharacter(char ch) 18 | { 19 | return ch > 0 && ch <= 0x1F; 20 | } 21 | 22 | static bool containsControlCharacter( const char* str ) 23 | { 24 | while ( *str ) 25 | { 26 | if ( isControlCharacter( *(str++) ) ) 27 | return true; 28 | } 29 | return false; 30 | } 31 | static void uintToString( unsigned int value, 32 | char *¤t ) 33 | { 34 | *--current = 0; 35 | do 36 | { 37 | *--current = (value % 10) + '0'; 38 | value /= 10; 39 | } 40 | while ( value != 0 ); 41 | } 42 | 43 | std::string valueToString( Int value ) 44 | { 45 | char buffer[32]; 46 | char *current = buffer + sizeof(buffer); 47 | bool isNegative = value < 0; 48 | if ( isNegative ) 49 | value = -value; 50 | uintToString( UInt(value), current ); 51 | if ( isNegative ) 52 | *--current = '-'; 53 | assert( current >= buffer ); 54 | return current; 55 | } 56 | 57 | 58 | std::string valueToString( UInt value ) 59 | { 60 | char buffer[32]; 61 | char *current = buffer + sizeof(buffer); 62 | uintToString( value, current ); 63 | assert( current >= buffer ); 64 | return current; 65 | } 66 | 67 | std::string valueToString( double value ) 68 | { 69 | char buffer[32]; 70 | #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. 71 | sprintf_s(buffer, sizeof(buffer), "%#.16g", value); 72 | #else 73 | sprintf(buffer, "%#.16g", value); 74 | #endif 75 | char* ch = buffer + strlen(buffer) - 1; 76 | if (*ch != '0') return buffer; // nothing to truncate, so save time 77 | while(ch > buffer && *ch == '0'){ 78 | --ch; 79 | } 80 | char* last_nonzero = ch; 81 | while(ch >= buffer){ 82 | switch(*ch){ 83 | case '0': 84 | case '1': 85 | case '2': 86 | case '3': 87 | case '4': 88 | case '5': 89 | case '6': 90 | case '7': 91 | case '8': 92 | case '9': 93 | --ch; 94 | continue; 95 | case '.': 96 | // Truncate zeroes to save bytes in output, but keep one. 97 | *(last_nonzero+2) = '\0'; 98 | return buffer; 99 | default: 100 | return buffer; 101 | } 102 | } 103 | return buffer; 104 | } 105 | 106 | 107 | std::string valueToString( bool value ) 108 | { 109 | return value ? "true" : "false"; 110 | } 111 | 112 | std::string valueToQuotedString( const char *value ) 113 | { 114 | // Not sure how to handle unicode... 115 | if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) 116 | return std::string("\"") + value + "\""; 117 | // We have to walk value and escape any special characters. 118 | // Appending to std::string is not efficient, but this should be rare. 119 | // (Note: forward slashes are *not* rare, but I am not escaping them.) 120 | unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL 121 | std::string result; 122 | result.reserve(maxsize); // to avoid lots of mallocs 123 | result += "\""; 124 | for (const char* c=value; *c != 0; ++c) 125 | { 126 | switch(*c) 127 | { 128 | case '\"': 129 | result += "\\\""; 130 | break; 131 | case '\\': 132 | result += "\\\\"; 133 | break; 134 | case '\b': 135 | result += "\\b"; 136 | break; 137 | case '\f': 138 | result += "\\f"; 139 | break; 140 | case '\n': 141 | result += "\\n"; 142 | break; 143 | case '\r': 144 | result += "\\r"; 145 | break; 146 | case '\t': 147 | result += "\\t"; 148 | break; 149 | //case '/': 150 | // Even though \/ is considered a legal escape in JSON, a bare 151 | // slash is also legal, so I see no reason to escape it. 152 | // (I hope I am not misunderstanding something. 153 | // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); 162 | result += oss.str(); 163 | } 164 | else 165 | { 166 | result += *c; 167 | } 168 | break; 169 | } 170 | } 171 | result += "\""; 172 | return result; 173 | } 174 | 175 | // Class Writer 176 | // ////////////////////////////////////////////////////////////////// 177 | Writer::~Writer() 178 | { 179 | } 180 | 181 | 182 | // Class FastWriter 183 | // ////////////////////////////////////////////////////////////////// 184 | 185 | FastWriter::FastWriter() 186 | : yamlCompatiblityEnabled_( false ) 187 | { 188 | } 189 | 190 | 191 | void 192 | FastWriter::enableYAMLCompatibility() 193 | { 194 | yamlCompatiblityEnabled_ = true; 195 | } 196 | 197 | 198 | std::string 199 | FastWriter::write( const Value &root ) 200 | { 201 | document_ = ""; 202 | writeValue( root ); 203 | document_ += "\n"; 204 | return document_; 205 | } 206 | 207 | 208 | void 209 | FastWriter::writeValue( const Value &value ) 210 | { 211 | switch ( value.type() ) 212 | { 213 | case nullValue: 214 | document_ += "null"; 215 | break; 216 | case intValue: 217 | document_ += valueToString( value.asInt() ); 218 | break; 219 | case uintValue: 220 | document_ += valueToString( value.asUInt() ); 221 | break; 222 | case realValue: 223 | document_ += valueToString( value.asDouble() ); 224 | break; 225 | case stringValue: 226 | document_ += valueToQuotedString( value.asCString() ); 227 | break; 228 | case booleanValue: 229 | document_ += valueToString( value.asBool() ); 230 | break; 231 | case arrayValue: 232 | { 233 | document_ += "["; 234 | int size = value.size(); 235 | for ( int index =0; index < size; ++index ) 236 | { 237 | if ( index > 0 ) 238 | document_ += ","; 239 | writeValue( value[index] ); 240 | } 241 | document_ += "]"; 242 | } 243 | break; 244 | case objectValue: 245 | { 246 | Value::Members members( value.getMemberNames() ); 247 | document_ += "{"; 248 | for ( Value::Members::iterator it = members.begin(); 249 | it != members.end(); 250 | ++it ) 251 | { 252 | const std::string &name = *it; 253 | if ( it != members.begin() ) 254 | document_ += ","; 255 | document_ += valueToQuotedString( name.c_str() ); 256 | document_ += yamlCompatiblityEnabled_ ? ": " 257 | : ":"; 258 | writeValue( value[name] ); 259 | } 260 | document_ += "}"; 261 | } 262 | break; 263 | } 264 | } 265 | 266 | 267 | // Class StyledWriter 268 | // ////////////////////////////////////////////////////////////////// 269 | 270 | StyledWriter::StyledWriter() 271 | : rightMargin_( 74 ) 272 | , indentSize_( 3 ) 273 | { 274 | } 275 | 276 | 277 | std::string 278 | StyledWriter::write( const Value &root ) 279 | { 280 | document_ = ""; 281 | addChildValues_ = false; 282 | indentString_ = ""; 283 | writeCommentBeforeValue( root ); 284 | writeValue( root ); 285 | writeCommentAfterValueOnSameLine( root ); 286 | document_ += "\n"; 287 | return document_; 288 | } 289 | 290 | 291 | void 292 | StyledWriter::writeValue( const Value &value ) 293 | { 294 | switch ( value.type() ) 295 | { 296 | case nullValue: 297 | pushValue( "null" ); 298 | break; 299 | case intValue: 300 | pushValue( valueToString( value.asInt() ) ); 301 | break; 302 | case uintValue: 303 | pushValue( valueToString( value.asUInt() ) ); 304 | break; 305 | case realValue: 306 | pushValue( valueToString( value.asDouble() ) ); 307 | break; 308 | case stringValue: 309 | pushValue( valueToQuotedString( value.asCString() ) ); 310 | break; 311 | case booleanValue: 312 | pushValue( valueToString( value.asBool() ) ); 313 | break; 314 | case arrayValue: 315 | writeArrayValue( value); 316 | break; 317 | case objectValue: 318 | { 319 | Value::Members members( value.getMemberNames() ); 320 | if ( members.empty() ) 321 | pushValue( "{}" ); 322 | else 323 | { 324 | writeWithIndent( "{" ); 325 | indent(); 326 | Value::Members::iterator it = members.begin(); 327 | while ( true ) 328 | { 329 | const std::string &name = *it; 330 | const Value &childValue = value[name]; 331 | writeCommentBeforeValue( childValue ); 332 | writeWithIndent( valueToQuotedString( name.c_str() ) ); 333 | document_ += " : "; 334 | writeValue( childValue ); 335 | if ( ++it == members.end() ) 336 | { 337 | writeCommentAfterValueOnSameLine( childValue ); 338 | break; 339 | } 340 | document_ += ","; 341 | writeCommentAfterValueOnSameLine( childValue ); 342 | } 343 | unindent(); 344 | writeWithIndent( "}" ); 345 | } 346 | } 347 | break; 348 | } 349 | } 350 | 351 | 352 | void 353 | StyledWriter::writeArrayValue( const Value &value ) 354 | { 355 | unsigned size = value.size(); 356 | if ( size == 0 ) 357 | pushValue( "[]" ); 358 | else 359 | { 360 | bool isArrayMultiLine = isMultineArray( value ); 361 | if ( isArrayMultiLine ) 362 | { 363 | writeWithIndent( "[" ); 364 | indent(); 365 | bool hasChildValue = !childValues_.empty(); 366 | unsigned index =0; 367 | while ( true ) 368 | { 369 | const Value &childValue = value[index]; 370 | writeCommentBeforeValue( childValue ); 371 | if ( hasChildValue ) 372 | writeWithIndent( childValues_[index] ); 373 | else 374 | { 375 | writeIndent(); 376 | writeValue( childValue ); 377 | } 378 | if ( ++index == size ) 379 | { 380 | writeCommentAfterValueOnSameLine( childValue ); 381 | break; 382 | } 383 | document_ += ","; 384 | writeCommentAfterValueOnSameLine( childValue ); 385 | } 386 | unindent(); 387 | writeWithIndent( "]" ); 388 | } 389 | else // output on a single line 390 | { 391 | assert( childValues_.size() == size ); 392 | document_ += "[ "; 393 | for ( unsigned index =0; index < size; ++index ) 394 | { 395 | if ( index > 0 ) 396 | document_ += ", "; 397 | document_ += childValues_[index]; 398 | } 399 | document_ += " ]"; 400 | } 401 | } 402 | } 403 | 404 | 405 | bool 406 | StyledWriter::isMultineArray( const Value &value ) 407 | { 408 | int size = value.size(); 409 | bool isMultiLine = size*3 >= rightMargin_ ; 410 | childValues_.clear(); 411 | for ( int index =0; index < size && !isMultiLine; ++index ) 412 | { 413 | const Value &childValue = value[index]; 414 | isMultiLine = isMultiLine || 415 | ( (childValue.isArray() || childValue.isObject()) && 416 | childValue.size() > 0 ); 417 | } 418 | if ( !isMultiLine ) // check if line length > max line length 419 | { 420 | childValues_.reserve( size ); 421 | addChildValues_ = true; 422 | int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' 423 | for ( int index =0; index < size && !isMultiLine; ++index ) 424 | { 425 | writeValue( value[index] ); 426 | lineLength += int( childValues_[index].length() ); 427 | isMultiLine = isMultiLine && hasCommentForValue( value[index] ); 428 | } 429 | addChildValues_ = false; 430 | isMultiLine = isMultiLine || lineLength >= rightMargin_; 431 | } 432 | return isMultiLine; 433 | } 434 | 435 | 436 | void 437 | StyledWriter::pushValue( const std::string &value ) 438 | { 439 | if ( addChildValues_ ) 440 | childValues_.push_back( value ); 441 | else 442 | document_ += value; 443 | } 444 | 445 | 446 | void 447 | StyledWriter::writeIndent() 448 | { 449 | if ( !document_.empty() ) 450 | { 451 | char last = document_[document_.length()-1]; 452 | if ( last == ' ' ) // already indented 453 | return; 454 | if ( last != '\n' ) // Comments may add new-line 455 | document_ += '\n'; 456 | } 457 | document_ += indentString_; 458 | } 459 | 460 | 461 | void 462 | StyledWriter::writeWithIndent( const std::string &value ) 463 | { 464 | writeIndent(); 465 | document_ += value; 466 | } 467 | 468 | 469 | void 470 | StyledWriter::indent() 471 | { 472 | indentString_ += std::string( indentSize_, ' ' ); 473 | } 474 | 475 | 476 | void 477 | StyledWriter::unindent() 478 | { 479 | assert( int(indentString_.size()) >= indentSize_ ); 480 | indentString_.resize( indentString_.size() - indentSize_ ); 481 | } 482 | 483 | 484 | void 485 | StyledWriter::writeCommentBeforeValue( const Value &root ) 486 | { 487 | if ( !root.hasComment( commentBefore ) ) 488 | return; 489 | document_ += normalizeEOL( root.getComment( commentBefore ) ); 490 | document_ += "\n"; 491 | } 492 | 493 | 494 | void 495 | StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) 496 | { 497 | if ( root.hasComment( commentAfterOnSameLine ) ) 498 | document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); 499 | 500 | if ( root.hasComment( commentAfter ) ) 501 | { 502 | document_ += "\n"; 503 | document_ += normalizeEOL( root.getComment( commentAfter ) ); 504 | document_ += "\n"; 505 | } 506 | } 507 | 508 | 509 | bool 510 | StyledWriter::hasCommentForValue( const Value &value ) 511 | { 512 | return value.hasComment( commentBefore ) 513 | || value.hasComment( commentAfterOnSameLine ) 514 | || value.hasComment( commentAfter ); 515 | } 516 | 517 | 518 | std::string 519 | StyledWriter::normalizeEOL( const std::string &text ) 520 | { 521 | std::string normalized; 522 | normalized.reserve( text.length() ); 523 | const char *begin = text.c_str(); 524 | const char *end = begin + text.length(); 525 | const char *current = begin; 526 | while ( current != end ) 527 | { 528 | char c = *current++; 529 | if ( c == '\r' ) // mac or dos EOL 530 | { 531 | if ( *current == '\n' ) // convert dos EOL 532 | ++current; 533 | normalized += '\n'; 534 | } 535 | else // handle unix EOL & other char 536 | normalized += c; 537 | } 538 | return normalized; 539 | } 540 | 541 | 542 | // Class StyledStreamWriter 543 | // ////////////////////////////////////////////////////////////////// 544 | 545 | StyledStreamWriter::StyledStreamWriter( std::string indentation ) 546 | : document_(NULL) 547 | , rightMargin_( 74 ) 548 | , indentation_( indentation ) 549 | { 550 | } 551 | 552 | 553 | void 554 | StyledStreamWriter::write( std::ostream &out, const Value &root ) 555 | { 556 | document_ = &out; 557 | addChildValues_ = false; 558 | indentString_ = ""; 559 | writeCommentBeforeValue( root ); 560 | writeValue( root ); 561 | writeCommentAfterValueOnSameLine( root ); 562 | *document_ << "\n"; 563 | document_ = NULL; // Forget the stream, for safety. 564 | } 565 | 566 | 567 | void 568 | StyledStreamWriter::writeValue( const Value &value ) 569 | { 570 | switch ( value.type() ) 571 | { 572 | case nullValue: 573 | pushValue( "null" ); 574 | break; 575 | case intValue: 576 | pushValue( valueToString( value.asInt() ) ); 577 | break; 578 | case uintValue: 579 | pushValue( valueToString( value.asUInt() ) ); 580 | break; 581 | case realValue: 582 | pushValue( valueToString( value.asDouble() ) ); 583 | break; 584 | case stringValue: 585 | pushValue( valueToQuotedString( value.asCString() ) ); 586 | break; 587 | case booleanValue: 588 | pushValue( valueToString( value.asBool() ) ); 589 | break; 590 | case arrayValue: 591 | writeArrayValue( value); 592 | break; 593 | case objectValue: 594 | { 595 | Value::Members members( value.getMemberNames() ); 596 | if ( members.empty() ) 597 | pushValue( "{}" ); 598 | else 599 | { 600 | writeWithIndent( "{" ); 601 | indent(); 602 | Value::Members::iterator it = members.begin(); 603 | while ( true ) 604 | { 605 | const std::string &name = *it; 606 | const Value &childValue = value[name]; 607 | writeCommentBeforeValue( childValue ); 608 | writeWithIndent( valueToQuotedString( name.c_str() ) ); 609 | *document_ << " : "; 610 | writeValue( childValue ); 611 | if ( ++it == members.end() ) 612 | { 613 | writeCommentAfterValueOnSameLine( childValue ); 614 | break; 615 | } 616 | *document_ << ","; 617 | writeCommentAfterValueOnSameLine( childValue ); 618 | } 619 | unindent(); 620 | writeWithIndent( "}" ); 621 | } 622 | } 623 | break; 624 | } 625 | } 626 | 627 | 628 | void 629 | StyledStreamWriter::writeArrayValue( const Value &value ) 630 | { 631 | unsigned size = value.size(); 632 | if ( size == 0 ) 633 | pushValue( "[]" ); 634 | else 635 | { 636 | bool isArrayMultiLine = isMultineArray( value ); 637 | if ( isArrayMultiLine ) 638 | { 639 | writeWithIndent( "[" ); 640 | indent(); 641 | bool hasChildValue = !childValues_.empty(); 642 | unsigned index =0; 643 | while ( true ) 644 | { 645 | const Value &childValue = value[index]; 646 | writeCommentBeforeValue( childValue ); 647 | if ( hasChildValue ) 648 | writeWithIndent( childValues_[index] ); 649 | else 650 | { 651 | writeIndent(); 652 | writeValue( childValue ); 653 | } 654 | if ( ++index == size ) 655 | { 656 | writeCommentAfterValueOnSameLine( childValue ); 657 | break; 658 | } 659 | *document_ << ","; 660 | writeCommentAfterValueOnSameLine( childValue ); 661 | } 662 | unindent(); 663 | writeWithIndent( "]" ); 664 | } 665 | else // output on a single line 666 | { 667 | assert( childValues_.size() == size ); 668 | *document_ << "[ "; 669 | for ( unsigned index =0; index < size; ++index ) 670 | { 671 | if ( index > 0 ) 672 | *document_ << ", "; 673 | *document_ << childValues_[index]; 674 | } 675 | *document_ << " ]"; 676 | } 677 | } 678 | } 679 | 680 | 681 | bool 682 | StyledStreamWriter::isMultineArray( const Value &value ) 683 | { 684 | int size = value.size(); 685 | bool isMultiLine = size*3 >= rightMargin_ ; 686 | childValues_.clear(); 687 | for ( int index =0; index < size && !isMultiLine; ++index ) 688 | { 689 | const Value &childValue = value[index]; 690 | isMultiLine = isMultiLine || 691 | ( (childValue.isArray() || childValue.isObject()) && 692 | childValue.size() > 0 ); 693 | } 694 | if ( !isMultiLine ) // check if line length > max line length 695 | { 696 | childValues_.reserve( size ); 697 | addChildValues_ = true; 698 | int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' 699 | for ( int index =0; index < size && !isMultiLine; ++index ) 700 | { 701 | writeValue( value[index] ); 702 | lineLength += int( childValues_[index].length() ); 703 | isMultiLine = isMultiLine && hasCommentForValue( value[index] ); 704 | } 705 | addChildValues_ = false; 706 | isMultiLine = isMultiLine || lineLength >= rightMargin_; 707 | } 708 | return isMultiLine; 709 | } 710 | 711 | 712 | void 713 | StyledStreamWriter::pushValue( const std::string &value ) 714 | { 715 | if ( addChildValues_ ) 716 | childValues_.push_back( value ); 717 | else 718 | *document_ << value; 719 | } 720 | 721 | 722 | void 723 | StyledStreamWriter::writeIndent() 724 | { 725 | /* 726 | Some comments in this method would have been nice. ;-) 727 | 728 | if ( !document_.empty() ) 729 | { 730 | char last = document_[document_.length()-1]; 731 | if ( last == ' ' ) // already indented 732 | return; 733 | if ( last != '\n' ) // Comments may add new-line 734 | *document_ << '\n'; 735 | } 736 | */ 737 | *document_ << '\n' << indentString_; 738 | } 739 | 740 | 741 | void 742 | StyledStreamWriter::writeWithIndent( const std::string &value ) 743 | { 744 | writeIndent(); 745 | *document_ << value; 746 | } 747 | 748 | 749 | void 750 | StyledStreamWriter::indent() 751 | { 752 | indentString_ += indentation_; 753 | } 754 | 755 | 756 | void 757 | StyledStreamWriter::unindent() 758 | { 759 | assert( indentString_.size() >= indentation_.size() ); 760 | indentString_.resize( indentString_.size() - indentation_.size() ); 761 | } 762 | 763 | 764 | void 765 | StyledStreamWriter::writeCommentBeforeValue( const Value &root ) 766 | { 767 | if ( !root.hasComment( commentBefore ) ) 768 | return; 769 | *document_ << normalizeEOL( root.getComment( commentBefore ) ); 770 | *document_ << "\n"; 771 | } 772 | 773 | 774 | void 775 | StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) 776 | { 777 | if ( root.hasComment( commentAfterOnSameLine ) ) 778 | *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); 779 | 780 | if ( root.hasComment( commentAfter ) ) 781 | { 782 | *document_ << "\n"; 783 | *document_ << normalizeEOL( root.getComment( commentAfter ) ); 784 | *document_ << "\n"; 785 | } 786 | } 787 | 788 | 789 | bool 790 | StyledStreamWriter::hasCommentForValue( const Value &value ) 791 | { 792 | return value.hasComment( commentBefore ) 793 | || value.hasComment( commentAfterOnSameLine ) 794 | || value.hasComment( commentAfter ); 795 | } 796 | 797 | 798 | std::string 799 | StyledStreamWriter::normalizeEOL( const std::string &text ) 800 | { 801 | std::string normalized; 802 | normalized.reserve( text.length() ); 803 | const char *begin = text.c_str(); 804 | const char *end = begin + text.length(); 805 | const char *current = begin; 806 | while ( current != end ) 807 | { 808 | char c = *current++; 809 | if ( c == '\r' ) // mac or dos EOL 810 | { 811 | if ( *current == '\n' ) // convert dos EOL 812 | ++current; 813 | normalized += '\n'; 814 | } 815 | else // handle unix EOL & other char 816 | normalized += c; 817 | } 818 | return normalized; 819 | } 820 | 821 | 822 | std::ostream& operator<<( std::ostream &sout, const Value &root ) 823 | { 824 | Json::StyledStreamWriter writer; 825 | writer.write(sout, root); 826 | return sout; 827 | } 828 | 829 | 830 | } // namespace Json 831 | -------------------------------------------------------------------------------- /json/reader.h: -------------------------------------------------------------------------------- 1 | #ifndef CPPTL_JSON_READER_H_INCLUDED 2 | # define CPPTL_JSON_READER_H_INCLUDED 3 | 4 | # include "features.h" 5 | # include "value.h" 6 | # include 7 | # include 8 | # include 9 | # include 10 | 11 | namespace Json { 12 | 13 | /** \brief Unserialize a JSON document into a Value. 14 | * 15 | */ 16 | class JSON_API Reader 17 | { 18 | public: 19 | typedef char Char; 20 | typedef const Char *Location; 21 | 22 | /** \brief Constructs a Reader allowing all features 23 | * for parsing. 24 | */ 25 | Reader(); 26 | 27 | /** \brief Constructs a Reader allowing the specified feature set 28 | * for parsing. 29 | */ 30 | Reader( const Features &features ); 31 | 32 | /** \brief Read a Value from a JSON document. 33 | * \param document UTF-8 encoded string containing the document to read. 34 | * \param root [out] Contains the root value of the document if it was 35 | * successfully parsed. 36 | * \param collectComments \c true to collect comment and allow writing them back during 37 | * serialization, \c false to discard comments. 38 | * This parameter is ignored if Features::allowComments_ 39 | * is \c false. 40 | * \return \c true if the document was successfully parsed, \c false if an error occurred. 41 | */ 42 | bool parse( const std::string &document, 43 | Value &root, 44 | bool collectComments = true ); 45 | 46 | /** \brief Read a Value from a JSON document. 47 | * \param document UTF-8 encoded string containing the document to read. 48 | * \param root [out] Contains the root value of the document if it was 49 | * successfully parsed. 50 | * \param collectComments \c true to collect comment and allow writing them back during 51 | * serialization, \c false to discard comments. 52 | * This parameter is ignored if Features::allowComments_ 53 | * is \c false. 54 | * \return \c true if the document was successfully parsed, \c false if an error occurred. 55 | */ 56 | bool parse( const char *beginDoc, const char *endDoc, 57 | Value &root, 58 | bool collectComments = true ); 59 | 60 | /// \brief Parse from input stream. 61 | /// \see Json::operator>>(std::istream&, Json::Value&). 62 | bool parse( std::istream &is, 63 | Value &root, 64 | bool collectComments = true ); 65 | 66 | /** \brief Returns a user friendly string that list errors in the parsed document. 67 | * \return Formatted error message with the list of errors with their location in 68 | * the parsed document. An empty string is returned if no error occurred 69 | * during parsing. 70 | */ 71 | std::string getFormatedErrorMessages() const; 72 | 73 | private: 74 | enum TokenType 75 | { 76 | tokenEndOfStream = 0, 77 | tokenObjectBegin, 78 | tokenObjectEnd, 79 | tokenArrayBegin, 80 | tokenArrayEnd, 81 | tokenString, 82 | tokenNumber, 83 | tokenTrue, 84 | tokenFalse, 85 | tokenNull, 86 | tokenArraySeparator, 87 | tokenMemberSeparator, 88 | tokenComment, 89 | tokenError 90 | }; 91 | 92 | class Token 93 | { 94 | public: 95 | TokenType type_; 96 | Location start_; 97 | Location end_; 98 | }; 99 | 100 | class ErrorInfo 101 | { 102 | public: 103 | Token token_; 104 | std::string message_; 105 | Location extra_; 106 | }; 107 | 108 | typedef std::deque Errors; 109 | 110 | bool expectToken( TokenType type, Token &token, const char *message ); 111 | bool readToken( Token &token ); 112 | void skipSpaces(); 113 | bool match( Location pattern, 114 | int patternLength ); 115 | bool readComment(); 116 | bool readCStyleComment(); 117 | bool readCppStyleComment(); 118 | bool readString(); 119 | void readNumber(); 120 | bool readValue(); 121 | bool readObject( Token &token ); 122 | bool readArray( Token &token ); 123 | bool decodeNumber( Token &token ); 124 | bool decodeString( Token &token ); 125 | bool decodeString( Token &token, std::string &decoded ); 126 | bool decodeDouble( Token &token ); 127 | bool decodeUnicodeCodePoint( Token &token, 128 | Location ¤t, 129 | Location end, 130 | unsigned int &unicode ); 131 | bool decodeUnicodeEscapeSequence( Token &token, 132 | Location ¤t, 133 | Location end, 134 | unsigned int &unicode ); 135 | bool addError( const std::string &message, 136 | Token &token, 137 | Location extra = 0 ); 138 | bool recoverFromError( TokenType skipUntilToken ); 139 | bool addErrorAndRecover( const std::string &message, 140 | Token &token, 141 | TokenType skipUntilToken ); 142 | void skipUntilSpace(); 143 | Value ¤tValue(); 144 | Char getNextChar(); 145 | void getLocationLineAndColumn( Location location, 146 | int &line, 147 | int &column ) const; 148 | std::string getLocationLineAndColumn( Location location ) const; 149 | void addComment( Location begin, 150 | Location end, 151 | CommentPlacement placement ); 152 | void skipCommentTokens( Token &token ); 153 | 154 | typedef std::stack Nodes; 155 | Nodes nodes_; 156 | Errors errors_; 157 | std::string document_; 158 | Location begin_; 159 | Location end_; 160 | Location current_; 161 | Location lastValueEnd_; 162 | Value *lastValue_; 163 | std::string commentsBefore_; 164 | Features features_; 165 | bool collectComments_; 166 | }; 167 | 168 | /** \brief Read from 'sin' into 'root'. 169 | 170 | Always keep comments from the input JSON. 171 | 172 | This can be used to read a file into a particular sub-object. 173 | For example: 174 | \code 175 | Json::Value root; 176 | cin >> root["dir"]["file"]; 177 | cout << root; 178 | \endcode 179 | Result: 180 | \verbatim 181 | { 182 | "dir": { 183 | "file": { 184 | // The input stream JSON would be nested here. 185 | } 186 | } 187 | } 188 | \endverbatim 189 | \throw std::exception on parse error. 190 | \see Json::operator<<() 191 | */ 192 | std::istream& operator>>( std::istream&, Value& ); 193 | 194 | } // namespace Json 195 | 196 | #endif // CPPTL_JSON_READER_H_INCLUDED 197 | -------------------------------------------------------------------------------- /json/value.h: -------------------------------------------------------------------------------- 1 | #ifndef CPPTL_JSON_H_INCLUDED 2 | # define CPPTL_JSON_H_INCLUDED 3 | 4 | # include "forwards.h" 5 | # include 6 | # include 7 | 8 | # ifndef JSON_USE_CPPTL_SMALLMAP 9 | # include 10 | # else 11 | # include 12 | # endif 13 | # ifdef JSON_USE_CPPTL 14 | # include 15 | # endif 16 | 17 | /** \brief JSON (JavaScript Object Notation). 18 | */ 19 | namespace Json { 20 | 21 | /** \brief Type of the value held by a Value object. 22 | */ 23 | enum ValueType 24 | { 25 | nullValue = 0, ///< 'null' value 26 | intValue, ///< signed integer value 27 | uintValue, ///< unsigned integer value 28 | realValue, ///< double value 29 | stringValue, ///< UTF-8 string value 30 | booleanValue, ///< bool value 31 | arrayValue, ///< array value (ordered list) 32 | objectValue ///< object value (collection of name/value pairs). 33 | }; 34 | 35 | enum CommentPlacement 36 | { 37 | commentBefore = 0, ///< a comment placed on the line before a value 38 | commentAfterOnSameLine, ///< a comment just after a value on the same line 39 | commentAfter, ///< a comment on the line after a value (only make sense for root value) 40 | numberOfCommentPlacement 41 | }; 42 | 43 | //# ifdef JSON_USE_CPPTL 44 | // typedef CppTL::AnyEnumerator EnumMemberNames; 45 | // typedef CppTL::AnyEnumerator EnumValues; 46 | //# endif 47 | 48 | /** \brief Lightweight wrapper to tag static string. 49 | * 50 | * Value constructor and objectValue member assignement takes advantage of the 51 | * StaticString and avoid the cost of string duplication when storing the 52 | * string or the member name. 53 | * 54 | * Example of usage: 55 | * \code 56 | * Json::Value aValue( StaticString("some text") ); 57 | * Json::Value object; 58 | * static const StaticString code("code"); 59 | * object[code] = 1234; 60 | * \endcode 61 | */ 62 | class JSON_API StaticString 63 | { 64 | public: 65 | explicit StaticString( const char *czstring ) 66 | : str_( czstring ) 67 | { 68 | } 69 | 70 | operator const char *() const 71 | { 72 | return str_; 73 | } 74 | 75 | const char *c_str() const 76 | { 77 | return str_; 78 | } 79 | 80 | private: 81 | const char *str_; 82 | }; 83 | 84 | /** \brief Represents a JSON value. 85 | * 86 | * This class is a discriminated union wrapper that can represents a: 87 | * - signed integer [range: Value::minInt - Value::maxInt] 88 | * - unsigned integer (range: 0 - Value::maxUInt) 89 | * - double 90 | * - UTF-8 string 91 | * - boolean 92 | * - 'null' 93 | * - an ordered list of Value 94 | * - collection of name/value pairs (javascript object) 95 | * 96 | * The type of the held value is represented by a #ValueType and 97 | * can be obtained using type(). 98 | * 99 | * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. 100 | * Non const methods will automatically create the a #nullValue element 101 | * if it does not exist. 102 | * The sequence of an #arrayValue will be automatically resize and initialized 103 | * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. 104 | * 105 | * The get() methods can be used to obtanis default value in the case the required element 106 | * does not exist. 107 | * 108 | * It is possible to iterate over the list of a #objectValue values using 109 | * the getMemberNames() method. 110 | */ 111 | class JSON_API Value 112 | { 113 | friend class ValueIteratorBase; 114 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 115 | friend class ValueInternalLink; 116 | friend class ValueInternalMap; 117 | # endif 118 | public: 119 | typedef std::vector Members; 120 | typedef ValueIterator iterator; 121 | typedef ValueConstIterator const_iterator; 122 | typedef Json::UInt UInt; 123 | typedef Json::Int Int; 124 | typedef UInt ArrayIndex; 125 | 126 | static const Value null; 127 | static const Int minInt; 128 | static const Int maxInt; 129 | static const UInt maxUInt; 130 | 131 | private: 132 | #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 133 | # ifndef JSON_VALUE_USE_INTERNAL_MAP 134 | class CZString 135 | { 136 | public: 137 | enum DuplicationPolicy 138 | { 139 | noDuplication = 0, 140 | duplicate, 141 | duplicateOnCopy 142 | }; 143 | CZString( int index ); 144 | CZString( const char *cstr, DuplicationPolicy allocate ); 145 | CZString( const CZString &other ); 146 | ~CZString(); 147 | CZString &operator =( const CZString &other ); 148 | bool operator<( const CZString &other ) const; 149 | bool operator==( const CZString &other ) const; 150 | int index() const; 151 | const char *c_str() const; 152 | bool isStaticString() const; 153 | private: 154 | void swap( CZString &other ); 155 | const char *cstr_; 156 | int index_; 157 | }; 158 | 159 | public: 160 | # ifndef JSON_USE_CPPTL_SMALLMAP 161 | typedef std::map ObjectValues; 162 | # else 163 | typedef CppTL::SmallMap ObjectValues; 164 | # endif // ifndef JSON_USE_CPPTL_SMALLMAP 165 | # endif // ifndef JSON_VALUE_USE_INTERNAL_MAP 166 | #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 167 | 168 | public: 169 | /** \brief Create a default Value of the given type. 170 | 171 | This is a very useful constructor. 172 | To create an empty array, pass arrayValue. 173 | To create an empty object, pass objectValue. 174 | Another Value can then be set to this one by assignment. 175 | This is useful since clear() and resize() will not alter types. 176 | 177 | Examples: 178 | \code 179 | Json::Value null_value; // null 180 | Json::Value arr_value(Json::arrayValue); // [] 181 | Json::Value obj_value(Json::objectValue); // {} 182 | \endcode 183 | */ 184 | Value( ValueType type = nullValue ); 185 | Value( Int value ); 186 | Value( UInt value ); 187 | Value( double value ); 188 | Value( const char *value ); 189 | Value( const char *beginValue, const char *endValue ); 190 | /** \brief Constructs a value from a static string. 191 | 192 | * Like other value string constructor but do not duplicate the string for 193 | * internal storage. The given string must remain alive after the call to this 194 | * constructor. 195 | * Example of usage: 196 | * \code 197 | * Json::Value aValue( StaticString("some text") ); 198 | * \endcode 199 | */ 200 | Value( const StaticString &value ); 201 | Value( const std::string &value ); 202 | # ifdef JSON_USE_CPPTL 203 | Value( const CppTL::ConstString &value ); 204 | # endif 205 | Value( bool value ); 206 | Value( const Value &other ); 207 | ~Value(); 208 | 209 | Value &operator=( const Value &other ); 210 | /// Swap values. 211 | /// \note Currently, comments are intentionally not swapped, for 212 | /// both logic and efficiency. 213 | void swap( Value &other ); 214 | 215 | ValueType type() const; 216 | 217 | bool operator <( const Value &other ) const; 218 | bool operator <=( const Value &other ) const; 219 | bool operator >=( const Value &other ) const; 220 | bool operator >( const Value &other ) const; 221 | 222 | bool operator ==( const Value &other ) const; 223 | bool operator !=( const Value &other ) const; 224 | 225 | int compare( const Value &other ); 226 | 227 | const char *asCString() const; 228 | std::string asString() const; 229 | # ifdef JSON_USE_CPPTL 230 | CppTL::ConstString asConstString() const; 231 | # endif 232 | Int asInt() const; 233 | UInt asUInt() const; 234 | double asDouble() const; 235 | bool asBool() const; 236 | 237 | bool isNull() const; 238 | bool isBool() const; 239 | bool isInt() const; 240 | bool isUInt() const; 241 | bool isIntegral() const; 242 | bool isDouble() const; 243 | bool isNumeric() const; 244 | bool isString() const; 245 | bool isArray() const; 246 | bool isObject() const; 247 | 248 | bool isConvertibleTo( ValueType other ) const; 249 | 250 | /// Number of values in array or object 251 | UInt size() const; 252 | 253 | /// \brief Return true if empty array, empty object, or null; 254 | /// otherwise, false. 255 | bool empty() const; 256 | 257 | /// Return isNull() 258 | bool operator!() const; 259 | 260 | /// Remove all object members and array elements. 261 | /// \pre type() is arrayValue, objectValue, or nullValue 262 | /// \post type() is unchanged 263 | void clear(); 264 | 265 | /// Resize the array to size elements. 266 | /// New elements are initialized to null. 267 | /// May only be called on nullValue or arrayValue. 268 | /// \pre type() is arrayValue or nullValue 269 | /// \post type() is arrayValue 270 | void resize( UInt size ); 271 | 272 | /// Access an array element (zero based index ). 273 | /// If the array contains less than index element, then null value are inserted 274 | /// in the array so that its size is index+1. 275 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 276 | /// this from the operator[] which takes a string.) 277 | Value &operator[]( UInt index ); 278 | /// Access an array element (zero based index ) 279 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 280 | /// this from the operator[] which takes a string.) 281 | const Value &operator[]( UInt index ) const; 282 | /// If the array contains at least index+1 elements, returns the element value, 283 | /// otherwise returns defaultValue. 284 | Value get( UInt index, 285 | const Value &defaultValue ) const; 286 | /// Return true if index < size(). 287 | bool isValidIndex( UInt index ) const; 288 | /// \brief Append value to array at the end. 289 | /// 290 | /// Equivalent to jsonvalue[jsonvalue.size()] = value; 291 | Value &append( const Value &value ); 292 | 293 | /// Access an object value by name, create a null member if it does not exist. 294 | Value &operator[]( const char *key ); 295 | /// Access an object value by name, returns null if there is no member with that name. 296 | const Value &operator[]( const char *key ) const; 297 | /// Access an object value by name, create a null member if it does not exist. 298 | Value &operator[]( const std::string &key ); 299 | /// Access an object value by name, returns null if there is no member with that name. 300 | const Value &operator[]( const std::string &key ) const; 301 | /** \brief Access an object value by name, create a null member if it does not exist. 302 | 303 | * If the object as no entry for that name, then the member name used to store 304 | * the new entry is not duplicated. 305 | * Example of use: 306 | * \code 307 | * Json::Value object; 308 | * static const StaticString code("code"); 309 | * object[code] = 1234; 310 | * \endcode 311 | */ 312 | Value &operator[]( const StaticString &key ); 313 | # ifdef JSON_USE_CPPTL 314 | /// Access an object value by name, create a null member if it does not exist. 315 | Value &operator[]( const CppTL::ConstString &key ); 316 | /// Access an object value by name, returns null if there is no member with that name. 317 | const Value &operator[]( const CppTL::ConstString &key ) const; 318 | # endif 319 | /// Return the member named key if it exist, defaultValue otherwise. 320 | Value get( const char *key, 321 | const Value &defaultValue ) const; 322 | /// Return the member named key if it exist, defaultValue otherwise. 323 | Value get( const std::string &key, 324 | const Value &defaultValue ) const; 325 | # ifdef JSON_USE_CPPTL 326 | /// Return the member named key if it exist, defaultValue otherwise. 327 | Value get( const CppTL::ConstString &key, 328 | const Value &defaultValue ) const; 329 | # endif 330 | /// \brief Remove and return the named member. 331 | /// 332 | /// Do nothing if it did not exist. 333 | /// \return the removed Value, or null. 334 | /// \pre type() is objectValue or nullValue 335 | /// \post type() is unchanged 336 | Value removeMember( const char* key ); 337 | /// Same as removeMember(const char*) 338 | Value removeMember( const std::string &key ); 339 | 340 | /// Return true if the object has a member named key. 341 | bool isMember( const char *key ) const; 342 | /// Return true if the object has a member named key. 343 | bool isMember( const std::string &key ) const; 344 | # ifdef JSON_USE_CPPTL 345 | /// Return true if the object has a member named key. 346 | bool isMember( const CppTL::ConstString &key ) const; 347 | # endif 348 | 349 | /// \brief Return a list of the member names. 350 | /// 351 | /// If null, return an empty list. 352 | /// \pre type() is objectValue or nullValue 353 | /// \post if type() was nullValue, it remains nullValue 354 | Members getMemberNames() const; 355 | 356 | //# ifdef JSON_USE_CPPTL 357 | // EnumMemberNames enumMemberNames() const; 358 | // EnumValues enumValues() const; 359 | //# endif 360 | 361 | /// Comments must be //... or /* ... */ 362 | void setComment( const char *comment, 363 | CommentPlacement placement ); 364 | /// Comments must be //... or /* ... */ 365 | void setComment( const std::string &comment, 366 | CommentPlacement placement ); 367 | bool hasComment( CommentPlacement placement ) const; 368 | /// Include delimiters and embedded newlines. 369 | std::string getComment( CommentPlacement placement ) const; 370 | 371 | std::string toStyledString() const; 372 | 373 | const_iterator begin() const; 374 | const_iterator end() const; 375 | 376 | iterator begin(); 377 | iterator end(); 378 | 379 | private: 380 | Value &resolveReference( const char *key, 381 | bool isStatic ); 382 | 383 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 384 | inline bool isItemAvailable() const 385 | { 386 | return itemIsUsed_ == 0; 387 | } 388 | 389 | inline void setItemUsed( bool isUsed = true ) 390 | { 391 | itemIsUsed_ = isUsed ? 1 : 0; 392 | } 393 | 394 | inline bool isMemberNameStatic() const 395 | { 396 | return memberNameIsStatic_ == 0; 397 | } 398 | 399 | inline void setMemberNameIsStatic( bool isStatic ) 400 | { 401 | memberNameIsStatic_ = isStatic ? 1 : 0; 402 | } 403 | # endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP 404 | 405 | private: 406 | struct CommentInfo 407 | { 408 | CommentInfo(); 409 | ~CommentInfo(); 410 | 411 | void setComment( const char *text ); 412 | 413 | char *comment_; 414 | }; 415 | 416 | //struct MemberNamesTransform 417 | //{ 418 | // typedef const char *result_type; 419 | // const char *operator()( const CZString &name ) const 420 | // { 421 | // return name.c_str(); 422 | // } 423 | //}; 424 | 425 | union ValueHolder 426 | { 427 | Int int_; 428 | UInt uint_; 429 | double real_; 430 | bool bool_; 431 | char *string_; 432 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 433 | ValueInternalArray *array_; 434 | ValueInternalMap *map_; 435 | #else 436 | ObjectValues *map_; 437 | # endif 438 | } value_; 439 | ValueType type_ : 8; 440 | int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. 441 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 442 | unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. 443 | int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. 444 | # endif 445 | CommentInfo *comments_; 446 | }; 447 | 448 | 449 | /** \brief Experimental and untested: represents an element of the "path" to access a node. 450 | */ 451 | class PathArgument 452 | { 453 | public: 454 | friend class Path; 455 | 456 | PathArgument(); 457 | PathArgument( UInt index ); 458 | PathArgument( const char *key ); 459 | PathArgument( const std::string &key ); 460 | 461 | private: 462 | enum Kind 463 | { 464 | kindNone = 0, 465 | kindIndex, 466 | kindKey 467 | }; 468 | std::string key_; 469 | UInt index_; 470 | Kind kind_; 471 | }; 472 | 473 | /** \brief Experimental and untested: represents a "path" to access a node. 474 | * 475 | * Syntax: 476 | * - "." => root node 477 | * - ".[n]" => elements at index 'n' of root node (an array value) 478 | * - ".name" => member named 'name' of root node (an object value) 479 | * - ".name1.name2.name3" 480 | * - ".[0][1][2].name1[3]" 481 | * - ".%" => member name is provided as parameter 482 | * - ".[%]" => index is provied as parameter 483 | */ 484 | class Path 485 | { 486 | public: 487 | Path( const std::string &path, 488 | const PathArgument &a1 = PathArgument(), 489 | const PathArgument &a2 = PathArgument(), 490 | const PathArgument &a3 = PathArgument(), 491 | const PathArgument &a4 = PathArgument(), 492 | const PathArgument &a5 = PathArgument() ); 493 | 494 | const Value &resolve( const Value &root ) const; 495 | Value resolve( const Value &root, 496 | const Value &defaultValue ) const; 497 | /// Creates the "path" to access the specified node and returns a reference on the node. 498 | Value &make( Value &root ) const; 499 | 500 | private: 501 | typedef std::vector InArgs; 502 | typedef std::vector Args; 503 | 504 | void makePath( const std::string &path, 505 | const InArgs &in ); 506 | void addPathInArg( const std::string &path, 507 | const InArgs &in, 508 | InArgs::const_iterator &itInArg, 509 | PathArgument::Kind kind ); 510 | void invalidPath( const std::string &path, 511 | int location ); 512 | 513 | Args args_; 514 | }; 515 | 516 | /** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value. 517 | * 518 | * - makeMemberName() and releaseMemberName() are called to respectively duplicate and 519 | * free an Json::objectValue member name. 520 | * - duplicateStringValue() and releaseStringValue() are called similarly to 521 | * duplicate and free a Json::stringValue value. 522 | */ 523 | class ValueAllocator 524 | { 525 | public: 526 | enum { unknown = (unsigned)-1 }; 527 | 528 | virtual ~ValueAllocator(); 529 | 530 | virtual char *makeMemberName( const char *memberName ) = 0; 531 | virtual void releaseMemberName( char *memberName ) = 0; 532 | virtual char *duplicateStringValue( const char *value, 533 | unsigned int length = unknown ) = 0; 534 | virtual void releaseStringValue( char *value ) = 0; 535 | }; 536 | 537 | #ifdef JSON_VALUE_USE_INTERNAL_MAP 538 | /** \brief Allocator to customize Value internal map. 539 | * Below is an example of a simple implementation (default implementation actually 540 | * use memory pool for speed). 541 | * \code 542 | class DefaultValueMapAllocator : public ValueMapAllocator 543 | { 544 | public: // overridden from ValueMapAllocator 545 | virtual ValueInternalMap *newMap() 546 | { 547 | return new ValueInternalMap(); 548 | } 549 | 550 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) 551 | { 552 | return new ValueInternalMap( other ); 553 | } 554 | 555 | virtual void destructMap( ValueInternalMap *map ) 556 | { 557 | delete map; 558 | } 559 | 560 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) 561 | { 562 | return new ValueInternalLink[size]; 563 | } 564 | 565 | virtual void releaseMapBuckets( ValueInternalLink *links ) 566 | { 567 | delete [] links; 568 | } 569 | 570 | virtual ValueInternalLink *allocateMapLink() 571 | { 572 | return new ValueInternalLink(); 573 | } 574 | 575 | virtual void releaseMapLink( ValueInternalLink *link ) 576 | { 577 | delete link; 578 | } 579 | }; 580 | * \endcode 581 | */ 582 | class JSON_API ValueMapAllocator 583 | { 584 | public: 585 | virtual ~ValueMapAllocator(); 586 | virtual ValueInternalMap *newMap() = 0; 587 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; 588 | virtual void destructMap( ValueInternalMap *map ) = 0; 589 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; 590 | virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; 591 | virtual ValueInternalLink *allocateMapLink() = 0; 592 | virtual void releaseMapLink( ValueInternalLink *link ) = 0; 593 | }; 594 | 595 | /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). 596 | * \internal previous_ & next_ allows for bidirectional traversal. 597 | */ 598 | class JSON_API ValueInternalLink 599 | { 600 | public: 601 | enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. 602 | enum InternalFlags { 603 | flagAvailable = 0, 604 | flagUsed = 1 605 | }; 606 | 607 | ValueInternalLink(); 608 | 609 | ~ValueInternalLink(); 610 | 611 | Value items_[itemPerLink]; 612 | char *keys_[itemPerLink]; 613 | ValueInternalLink *previous_; 614 | ValueInternalLink *next_; 615 | }; 616 | 617 | 618 | /** \brief A linked page based hash-table implementation used internally by Value. 619 | * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked 620 | * list in each bucket to handle collision. There is an addional twist in that 621 | * each node of the collision linked list is a page containing a fixed amount of 622 | * value. This provides a better compromise between memory usage and speed. 623 | * 624 | * Each bucket is made up of a chained list of ValueInternalLink. The last 625 | * link of a given bucket can be found in the 'previous_' field of the following bucket. 626 | * The last link of the last bucket is stored in tailLink_ as it has no following bucket. 627 | * Only the last link of a bucket may contains 'available' item. The last link always 628 | * contains at least one element unless is it the bucket one very first link. 629 | */ 630 | class JSON_API ValueInternalMap 631 | { 632 | friend class ValueIteratorBase; 633 | friend class Value; 634 | public: 635 | typedef unsigned int HashKey; 636 | typedef unsigned int BucketIndex; 637 | 638 | # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 639 | struct IteratorState 640 | { 641 | IteratorState() 642 | : map_(0) 643 | , link_(0) 644 | , itemIndex_(0) 645 | , bucketIndex_(0) 646 | { 647 | } 648 | ValueInternalMap *map_; 649 | ValueInternalLink *link_; 650 | BucketIndex itemIndex_; 651 | BucketIndex bucketIndex_; 652 | }; 653 | # endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 654 | 655 | ValueInternalMap(); 656 | ValueInternalMap( const ValueInternalMap &other ); 657 | ValueInternalMap &operator =( const ValueInternalMap &other ); 658 | ~ValueInternalMap(); 659 | 660 | void swap( ValueInternalMap &other ); 661 | 662 | BucketIndex size() const; 663 | 664 | void clear(); 665 | 666 | bool reserveDelta( BucketIndex growth ); 667 | 668 | bool reserve( BucketIndex newItemCount ); 669 | 670 | const Value *find( const char *key ) const; 671 | 672 | Value *find( const char *key ); 673 | 674 | Value &resolveReference( const char *key, 675 | bool isStatic ); 676 | 677 | void remove( const char *key ); 678 | 679 | void doActualRemove( ValueInternalLink *link, 680 | BucketIndex index, 681 | BucketIndex bucketIndex ); 682 | 683 | ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); 684 | 685 | Value &setNewItem( const char *key, 686 | bool isStatic, 687 | ValueInternalLink *link, 688 | BucketIndex index ); 689 | 690 | Value &unsafeAdd( const char *key, 691 | bool isStatic, 692 | HashKey hashedKey ); 693 | 694 | HashKey hash( const char *key ) const; 695 | 696 | int compare( const ValueInternalMap &other ) const; 697 | 698 | private: 699 | void makeBeginIterator( IteratorState &it ) const; 700 | void makeEndIterator( IteratorState &it ) const; 701 | static bool equals( const IteratorState &x, const IteratorState &other ); 702 | static void increment( IteratorState &iterator ); 703 | static void incrementBucket( IteratorState &iterator ); 704 | static void decrement( IteratorState &iterator ); 705 | static const char *key( const IteratorState &iterator ); 706 | static const char *key( const IteratorState &iterator, bool &isStatic ); 707 | static Value &value( const IteratorState &iterator ); 708 | static int distance( const IteratorState &x, const IteratorState &y ); 709 | 710 | private: 711 | ValueInternalLink *buckets_; 712 | ValueInternalLink *tailLink_; 713 | BucketIndex bucketsSize_; 714 | BucketIndex itemCount_; 715 | }; 716 | 717 | /** \brief A simplified deque implementation used internally by Value. 718 | * \internal 719 | * It is based on a list of fixed "page", each page contains a fixed number of items. 720 | * Instead of using a linked-list, a array of pointer is used for fast item look-up. 721 | * Look-up for an element is as follow: 722 | * - compute page index: pageIndex = itemIndex / itemsPerPage 723 | * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] 724 | * 725 | * Insertion is amortized constant time (only the array containing the index of pointers 726 | * need to be reallocated when items are appended). 727 | */ 728 | class JSON_API ValueInternalArray 729 | { 730 | friend class Value; 731 | friend class ValueIteratorBase; 732 | public: 733 | enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. 734 | typedef Value::ArrayIndex ArrayIndex; 735 | typedef unsigned int PageIndex; 736 | 737 | # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 738 | struct IteratorState // Must be a POD 739 | { 740 | IteratorState() 741 | : array_(0) 742 | , currentPageIndex_(0) 743 | , currentItemIndex_(0) 744 | { 745 | } 746 | ValueInternalArray *array_; 747 | Value **currentPageIndex_; 748 | unsigned int currentItemIndex_; 749 | }; 750 | # endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 751 | 752 | ValueInternalArray(); 753 | ValueInternalArray( const ValueInternalArray &other ); 754 | ValueInternalArray &operator =( const ValueInternalArray &other ); 755 | ~ValueInternalArray(); 756 | void swap( ValueInternalArray &other ); 757 | 758 | void clear(); 759 | void resize( ArrayIndex newSize ); 760 | 761 | Value &resolveReference( ArrayIndex index ); 762 | 763 | Value *find( ArrayIndex index ) const; 764 | 765 | ArrayIndex size() const; 766 | 767 | int compare( const ValueInternalArray &other ) const; 768 | 769 | private: 770 | static bool equals( const IteratorState &x, const IteratorState &other ); 771 | static void increment( IteratorState &iterator ); 772 | static void decrement( IteratorState &iterator ); 773 | static Value &dereference( const IteratorState &iterator ); 774 | static Value &unsafeDereference( const IteratorState &iterator ); 775 | static int distance( const IteratorState &x, const IteratorState &y ); 776 | static ArrayIndex indexOf( const IteratorState &iterator ); 777 | void makeBeginIterator( IteratorState &it ) const; 778 | void makeEndIterator( IteratorState &it ) const; 779 | void makeIterator( IteratorState &it, ArrayIndex index ) const; 780 | 781 | void makeIndexValid( ArrayIndex index ); 782 | 783 | Value **pages_; 784 | ArrayIndex size_; 785 | PageIndex pageCount_; 786 | }; 787 | 788 | /** \brief Experimental: do not use. Allocator to customize Value internal array. 789 | * Below is an example of a simple implementation (actual implementation use 790 | * memory pool). 791 | \code 792 | class DefaultValueArrayAllocator : public ValueArrayAllocator 793 | { 794 | public: // overridden from ValueArrayAllocator 795 | virtual ~DefaultValueArrayAllocator() 796 | { 797 | } 798 | 799 | virtual ValueInternalArray *newArray() 800 | { 801 | return new ValueInternalArray(); 802 | } 803 | 804 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) 805 | { 806 | return new ValueInternalArray( other ); 807 | } 808 | 809 | virtual void destruct( ValueInternalArray *array ) 810 | { 811 | delete array; 812 | } 813 | 814 | virtual void reallocateArrayPageIndex( Value **&indexes, 815 | ValueInternalArray::PageIndex &indexCount, 816 | ValueInternalArray::PageIndex minNewIndexCount ) 817 | { 818 | ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; 819 | if ( minNewIndexCount > newIndexCount ) 820 | newIndexCount = minNewIndexCount; 821 | void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); 822 | if ( !newIndexes ) 823 | throw std::bad_alloc(); 824 | indexCount = newIndexCount; 825 | indexes = static_cast( newIndexes ); 826 | } 827 | virtual void releaseArrayPageIndex( Value **indexes, 828 | ValueInternalArray::PageIndex indexCount ) 829 | { 830 | if ( indexes ) 831 | free( indexes ); 832 | } 833 | 834 | virtual Value *allocateArrayPage() 835 | { 836 | return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); 837 | } 838 | 839 | virtual void releaseArrayPage( Value *value ) 840 | { 841 | if ( value ) 842 | free( value ); 843 | } 844 | }; 845 | \endcode 846 | */ 847 | class JSON_API ValueArrayAllocator 848 | { 849 | public: 850 | virtual ~ValueArrayAllocator(); 851 | virtual ValueInternalArray *newArray() = 0; 852 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; 853 | virtual void destructArray( ValueInternalArray *array ) = 0; 854 | /** \brief Reallocate array page index. 855 | * Reallocates an array of pointer on each page. 856 | * \param indexes [input] pointer on the current index. May be \c NULL. 857 | * [output] pointer on the new index of at least 858 | * \a minNewIndexCount pages. 859 | * \param indexCount [input] current number of pages in the index. 860 | * [output] number of page the reallocated index can handle. 861 | * \b MUST be >= \a minNewIndexCount. 862 | * \param minNewIndexCount Minimum number of page the new index must be able to 863 | * handle. 864 | */ 865 | virtual void reallocateArrayPageIndex( Value **&indexes, 866 | ValueInternalArray::PageIndex &indexCount, 867 | ValueInternalArray::PageIndex minNewIndexCount ) = 0; 868 | virtual void releaseArrayPageIndex( Value **indexes, 869 | ValueInternalArray::PageIndex indexCount ) = 0; 870 | virtual Value *allocateArrayPage() = 0; 871 | virtual void releaseArrayPage( Value *value ) = 0; 872 | }; 873 | #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP 874 | 875 | 876 | /** \brief base class for Value iterators. 877 | * 878 | */ 879 | class ValueIteratorBase 880 | { 881 | public: 882 | typedef unsigned int size_t; 883 | typedef int difference_type; 884 | typedef ValueIteratorBase SelfType; 885 | 886 | ValueIteratorBase(); 887 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 888 | explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); 889 | #else 890 | ValueIteratorBase( const ValueInternalArray::IteratorState &state ); 891 | ValueIteratorBase( const ValueInternalMap::IteratorState &state ); 892 | #endif 893 | 894 | bool operator ==( const SelfType &other ) const 895 | { 896 | return isEqual( other ); 897 | } 898 | 899 | bool operator !=( const SelfType &other ) const 900 | { 901 | return !isEqual( other ); 902 | } 903 | 904 | difference_type operator -( const SelfType &other ) const 905 | { 906 | return computeDistance( other ); 907 | } 908 | 909 | /// Return either the index or the member name of the referenced value as a Value. 910 | Value key() const; 911 | 912 | /// Return the index of the referenced Value. -1 if it is not an arrayValue. 913 | UInt index() const; 914 | 915 | /// Return the member name of the referenced Value. "" if it is not an objectValue. 916 | const char *memberName() const; 917 | 918 | protected: 919 | Value &deref() const; 920 | 921 | void increment(); 922 | 923 | void decrement(); 924 | 925 | difference_type computeDistance( const SelfType &other ) const; 926 | 927 | bool isEqual( const SelfType &other ) const; 928 | 929 | void copy( const SelfType &other ); 930 | 931 | private: 932 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 933 | Value::ObjectValues::iterator current_; 934 | // Indicates that iterator is for a null value. 935 | bool isNull_; 936 | #else 937 | union 938 | { 939 | ValueInternalArray::IteratorState array_; 940 | ValueInternalMap::IteratorState map_; 941 | } iterator_; 942 | bool isArray_; 943 | #endif 944 | }; 945 | 946 | /** \brief const iterator for object and array value. 947 | * 948 | */ 949 | class ValueConstIterator : public ValueIteratorBase 950 | { 951 | friend class Value; 952 | public: 953 | typedef unsigned int size_t; 954 | typedef int difference_type; 955 | typedef const Value &reference; 956 | typedef const Value *pointer; 957 | typedef ValueConstIterator SelfType; 958 | 959 | ValueConstIterator(); 960 | private: 961 | /*! \internal Use by Value to create an iterator. 962 | */ 963 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 964 | explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); 965 | #else 966 | ValueConstIterator( const ValueInternalArray::IteratorState &state ); 967 | ValueConstIterator( const ValueInternalMap::IteratorState &state ); 968 | #endif 969 | public: 970 | SelfType &operator =( const ValueIteratorBase &other ); 971 | 972 | SelfType operator++( int ) 973 | { 974 | SelfType temp( *this ); 975 | ++*this; 976 | return temp; 977 | } 978 | 979 | SelfType operator--( int ) 980 | { 981 | SelfType temp( *this ); 982 | --*this; 983 | return temp; 984 | } 985 | 986 | SelfType &operator--() 987 | { 988 | decrement(); 989 | return *this; 990 | } 991 | 992 | SelfType &operator++() 993 | { 994 | increment(); 995 | return *this; 996 | } 997 | 998 | reference operator *() const 999 | { 1000 | return deref(); 1001 | } 1002 | }; 1003 | 1004 | 1005 | /** \brief Iterator for object and array value. 1006 | */ 1007 | class ValueIterator : public ValueIteratorBase 1008 | { 1009 | friend class Value; 1010 | public: 1011 | typedef unsigned int size_t; 1012 | typedef int difference_type; 1013 | typedef Value &reference; 1014 | typedef Value *pointer; 1015 | typedef ValueIterator SelfType; 1016 | 1017 | ValueIterator(); 1018 | ValueIterator( const ValueConstIterator &other ); 1019 | ValueIterator( const ValueIterator &other ); 1020 | private: 1021 | /*! \internal Use by Value to create an iterator. 1022 | */ 1023 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 1024 | explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); 1025 | #else 1026 | ValueIterator( const ValueInternalArray::IteratorState &state ); 1027 | ValueIterator( const ValueInternalMap::IteratorState &state ); 1028 | #endif 1029 | public: 1030 | 1031 | SelfType &operator =( const SelfType &other ); 1032 | 1033 | SelfType operator++( int ) 1034 | { 1035 | SelfType temp( *this ); 1036 | ++*this; 1037 | return temp; 1038 | } 1039 | 1040 | SelfType operator--( int ) 1041 | { 1042 | SelfType temp( *this ); 1043 | --*this; 1044 | return temp; 1045 | } 1046 | 1047 | SelfType &operator--() 1048 | { 1049 | decrement(); 1050 | return *this; 1051 | } 1052 | 1053 | SelfType &operator++() 1054 | { 1055 | increment(); 1056 | return *this; 1057 | } 1058 | 1059 | reference operator *() const 1060 | { 1061 | return deref(); 1062 | } 1063 | }; 1064 | 1065 | 1066 | } // namespace Json 1067 | 1068 | 1069 | #endif // CPPTL_JSON_H_INCLUDED 1070 | -------------------------------------------------------------------------------- /json/writer.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_WRITER_H_INCLUDED 2 | # define JSON_WRITER_H_INCLUDED 3 | 4 | # include "value.h" 5 | # include 6 | # include 7 | # include 8 | 9 | namespace Json { 10 | 11 | class Value; 12 | 13 | /** \brief Abstract class for writers. 14 | */ 15 | class JSON_API Writer 16 | { 17 | public: 18 | virtual ~Writer(); 19 | 20 | virtual std::string write( const Value &root ) = 0; 21 | }; 22 | 23 | /** \brief Outputs a Value in JSON format without formatting (not human friendly). 24 | * 25 | * The JSON document is written in a single line. It is not intended for 'human' consumption, 26 | * but may be usefull to support feature such as RPC where bandwith is limited. 27 | * \sa Reader, Value 28 | */ 29 | class JSON_API FastWriter : public Writer 30 | { 31 | public: 32 | FastWriter(); 33 | virtual ~FastWriter(){} 34 | 35 | void enableYAMLCompatibility(); 36 | 37 | public: // overridden from Writer 38 | virtual std::string write( const Value &root ); 39 | 40 | private: 41 | void writeValue( const Value &value ); 42 | 43 | std::string document_; 44 | bool yamlCompatiblityEnabled_; 45 | }; 46 | 47 | /** \brief Writes a Value in JSON format in a human friendly way. 48 | * 49 | * The rules for line break and indent are as follow: 50 | * - Object value: 51 | * - if empty then print {} without indent and line break 52 | * - if not empty the print '{', line break & indent, print one value per line 53 | * and then unindent and line break and print '}'. 54 | * - Array value: 55 | * - if empty then print [] without indent and line break 56 | * - if the array contains no object value, empty array or some other value types, 57 | * and all the values fit on one lines, then print the array on a single line. 58 | * - otherwise, it the values do not fit on one line, or the array contains 59 | * object or non empty array, then print one value per line. 60 | * 61 | * If the Value have comments then they are outputed according to their #CommentPlacement. 62 | * 63 | * \sa Reader, Value, Value::setComment() 64 | */ 65 | class JSON_API StyledWriter: public Writer 66 | { 67 | public: 68 | StyledWriter(); 69 | virtual ~StyledWriter(){} 70 | 71 | public: // overridden from Writer 72 | /** \brief Serialize a Value in JSON format. 73 | * \param root Value to serialize. 74 | * \return String containing the JSON document that represents the root value. 75 | */ 76 | virtual std::string write( const Value &root ); 77 | 78 | private: 79 | void writeValue( const Value &value ); 80 | void writeArrayValue( const Value &value ); 81 | bool isMultineArray( const Value &value ); 82 | void pushValue( const std::string &value ); 83 | void writeIndent(); 84 | void writeWithIndent( const std::string &value ); 85 | void indent(); 86 | void unindent(); 87 | void writeCommentBeforeValue( const Value &root ); 88 | void writeCommentAfterValueOnSameLine( const Value &root ); 89 | bool hasCommentForValue( const Value &value ); 90 | static std::string normalizeEOL( const std::string &text ); 91 | 92 | typedef std::vector ChildValues; 93 | 94 | ChildValues childValues_; 95 | std::string document_; 96 | std::string indentString_; 97 | int rightMargin_; 98 | int indentSize_; 99 | bool addChildValues_; 100 | }; 101 | 102 | /** \brief Writes a Value in JSON format in a human friendly way, 103 | to a stream rather than to a string. 104 | * 105 | * The rules for line break and indent are as follow: 106 | * - Object value: 107 | * - if empty then print {} without indent and line break 108 | * - if not empty the print '{', line break & indent, print one value per line 109 | * and then unindent and line break and print '}'. 110 | * - Array value: 111 | * - if empty then print [] without indent and line break 112 | * - if the array contains no object value, empty array or some other value types, 113 | * and all the values fit on one lines, then print the array on a single line. 114 | * - otherwise, it the values do not fit on one line, or the array contains 115 | * object or non empty array, then print one value per line. 116 | * 117 | * If the Value have comments then they are outputed according to their #CommentPlacement. 118 | * 119 | * \param indentation Each level will be indented by this amount extra. 120 | * \sa Reader, Value, Value::setComment() 121 | */ 122 | class JSON_API StyledStreamWriter 123 | { 124 | public: 125 | StyledStreamWriter( std::string indentation="\t" ); 126 | ~StyledStreamWriter(){} 127 | 128 | public: 129 | /** \brief Serialize a Value in JSON format. 130 | * \param out Stream to write to. (Can be ostringstream, e.g.) 131 | * \param root Value to serialize. 132 | * \note There is no point in deriving from Writer, since write() should not return a value. 133 | */ 134 | void write( std::ostream &out, const Value &root ); 135 | 136 | private: 137 | void writeValue( const Value &value ); 138 | void writeArrayValue( const Value &value ); 139 | bool isMultineArray( const Value &value ); 140 | void pushValue( const std::string &value ); 141 | void writeIndent(); 142 | void writeWithIndent( const std::string &value ); 143 | void indent(); 144 | void unindent(); 145 | void writeCommentBeforeValue( const Value &root ); 146 | void writeCommentAfterValueOnSameLine( const Value &root ); 147 | bool hasCommentForValue( const Value &value ); 148 | static std::string normalizeEOL( const std::string &text ); 149 | 150 | typedef std::vector ChildValues; 151 | 152 | ChildValues childValues_; 153 | std::ostream* document_; 154 | std::string indentString_; 155 | int rightMargin_; 156 | std::string indentation_; 157 | bool addChildValues_; 158 | }; 159 | 160 | std::string JSON_API valueToString( Int value ); 161 | std::string JSON_API valueToString( UInt value ); 162 | std::string JSON_API valueToString( double value ); 163 | std::string JSON_API valueToString( bool value ); 164 | std::string JSON_API valueToQuotedString( const char *value ); 165 | 166 | /// \brief Output using the StyledStreamWriter. 167 | /// \see Json::operator>>() 168 | std::ostream& operator<<( std::ostream&, const Value &root ); 169 | 170 | } // namespace Json 171 | 172 | 173 | 174 | #endif // JSON_WRITER_H_INCLUDED 175 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | RemoteControl 4 | 0.0.0 5 | The RemoteControl package 6 | 7 | 8 | 9 | 10 | books 11 | 12 | 13 | 14 | 15 | 16 | TODO 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 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 | catkin 52 | roscpp 53 | rospy 54 | std_msgs 55 | roscpp 56 | rospy 57 | std_msgs 58 | roscpp 59 | rospy 60 | std_msgs 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/CHTTP_post.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "CHTTP_post.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | using namespace std; 13 | #define BASE64_ENCODE_MAX_FILESIZE (1024 * 1024) 14 | 15 | static string m_callback_result; 16 | // 共用的 callback 17 | //std::string UtfToGbk(const char* utf8) 18 | //{ 19 | // int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); 20 | // wchar_t* wstr = new wchar_t[len + 1]; 21 | // memset(wstr, 0, len + 1); 22 | // MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len); 23 | // len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL); 24 | // char* str = new char[len + 1]; 25 | // memset(str, 0, len + 1); 26 | // WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL); 27 | // if (wstr) delete[] wstr; 28 | // return str; 29 | //} 30 | static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *stream) { 31 | // 获取到的body存放在ptr中,先将其转换为string格式 32 | //auto a = UtfToGbk((char*)ptr); 33 | m_callback_result = std::string((char *)ptr, size * nmemb); 34 | return size * nmemb; 35 | } 36 | 37 | 38 | bool CHTTP_post::xfuture_http_post_json(string url, string post, string &result, string &errmsg) 39 | { 40 | m_callback_result = ""; 41 | 42 | CURL *curl = NULL; 43 | CURLcode result_code; 44 | 45 | curl = curl_easy_init(); 46 | if (curl) { 47 | curl_easy_setopt(curl, CURLOPT_URL, url.data()); 48 | curl_easy_setopt(curl, CURLOPT_POST, 1); 49 | 50 | curl_slist *headers = NULL; 51 | headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");// 52 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 53 | 54 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1); 55 | 56 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); 57 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post.c_str()); 58 | struct timeval t1,t2; 59 | gettimeofday(&t1,NULL); 60 | result_code = curl_easy_perform(curl); 61 | gettimeofday(&t2,NULL); 62 | int64_t ts = (int64_t)(t2.tv_sec-t1.tv_sec)*1000 + (t2.tv_usec-t1.tv_usec)/1000; 63 | //cout< 0) { 172 | //char* p = g_base64_encode(buf, rd); 173 | //out = string(p); 174 | //res = out.length(); 175 | //g_free(p); 176 | } else { 177 | res = 0; 178 | out = ""; 179 | } 180 | fclose(fp); 181 | return res; 182 | } 183 | 184 | -------------------------------------------------------------------------------- /src/CHTTP_post.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | 5 | 6 | using std::string; 7 | 8 | class CHTTP_post { 9 | public: 10 | CHTTP_post() = default; 11 | ~CHTTP_post() = default; 12 | 13 | /** 14 | * @brief 发送普通 post json 请求 15 | * @param url POST URL 16 | * @param post POST 内容字符串 17 | * @param result POST 返回结果字符串 18 | * @param errmsg 如果出错,写入错误信息 19 | * @return 成功返回 true, 失败返回 false 20 | */ 21 | bool xfuture_http_post_json(string url, string post, string &result, string &errmsg); 22 | 23 | 24 | /** 25 | * @brief 发送 pgm post 请求 26 | * @param url POST URL 27 | * @param pgm POST PGM 内容 28 | * @param result POST 返回结果字符串 29 | * @param errmsg 如果出错,写入错误信息 30 | * @return 成功返回 true, 失败返回 false 31 | */ 32 | bool xfuture_http_post_pgm(string url, string pgm, string &result, string &errmsg); 33 | 34 | /** 35 | * @brief 发送 post 请求 36 | * @param url POST URL 37 | * @param raw POST 内容 38 | * @param result POST 返回结果字符串 39 | * @param errmsg 如果出错,写入错误信息 40 | * @return 成功返回 true, 失败返回 false 41 | */ 42 | bool xfuture_http_post_raw(string url, string raw, string &result, string &errmsg); 43 | 44 | /** 45 | * @brief 对文件进行 base64 编码 46 | * @param file 文件路径,不支持超过 1MB 大小的文件 47 | * @param out 编码后的文件内容 48 | * @return 返回编码后的文件内容字节数,返回 -1 表示出错 49 | */ 50 | int xfuture_http_base64_encode_file(string file, string &out); 51 | 52 | }; 53 | -------------------------------------------------------------------------------- /src/CWebSocket.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "CWebSocket.h" 15 | 16 | typedef websocketpp::client ws_client; 17 | 18 | namespace kagula 19 | { 20 | 21 | class connection_metadata { 22 | public: 23 | typedef websocketpp::lib::shared_ptr ptr; 24 | 25 | connection_metadata(websocketpp::connection_hdl hdl, std::string uri) 26 | : m_hdl(hdl) 27 | , m_status("Connecting") 28 | , m_uri(uri) 29 | , m_server("N/A") 30 | {} 31 | 32 | void on_open(ws_client *client, websocketpp::connection_hdl hdl) { 33 | m_status = "Open"; 34 | 35 | ws_client::connection_ptr con = client->get_con_from_hdl(hdl); 36 | m_server = con->get_response_header("Server"); 37 | } 38 | 39 | // if connection failed, the function will be invoke. 40 | void on_fail(ws_client *client, websocketpp::connection_hdl hdl) { 41 | m_status = "Failed"; 42 | 43 | ws_client::connection_ptr con = client->get_con_from_hdl(hdl); 44 | m_server = con->get_response_header("Server"); 45 | m_error_reason = con->get_ec().message(); 46 | } 47 | 48 | void on_close(ws_client *client, websocketpp::connection_hdl hdl) { 49 | m_status = "Closed"; 50 | ws_client::connection_ptr con = client->get_con_from_hdl(hdl); 51 | std::stringstream s; 52 | s << "close code: " << con->get_remote_close_code() << " (" 53 | << websocketpp::close::status::get_string(con->get_remote_close_code()) 54 | << "), close reason: " << con->get_remote_close_reason(); 55 | m_error_reason = s.str(); 56 | } 57 | 58 | void on_message(websocketpp::connection_hdl, ws_client::message_ptr msg) { 59 | std::vector temp; 60 | if (msg->get_opcode() == websocketpp::frame::opcode::text) { 61 | temp.push_back(/*"<< " +*/ msg->get_payload()); 62 | } 63 | else { 64 | temp.push_back(/*"<< " +*/ websocketpp::utility::to_hex(msg->get_payload())); 65 | } 66 | m_messages = temp; 67 | } 68 | 69 | websocketpp::connection_hdl get_hdl() const { 70 | return m_hdl; 71 | } 72 | 73 | std::string get_status() const { 74 | return m_status; 75 | } 76 | 77 | std::string get_uri() const { 78 | return m_uri; 79 | } 80 | 81 | std::vector get_message() const { 82 | return m_messages; 83 | } 84 | 85 | void record_sent_message(std::string message) { 86 | m_messages.push_back(">> " + message); 87 | } 88 | 89 | friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data); 90 | private: 91 | websocketpp::connection_hdl m_hdl; 92 | std::string m_status; 93 | std::string m_uri; 94 | std::string m_server; 95 | std::string m_error_reason; 96 | std::vector m_messages; 97 | }; 98 | 99 | std::ostream & operator<< (std::ostream & out, connection_metadata const & data) { 100 | out << "> URI: " << data.m_uri << "\n" 101 | << "> Status: " << data.m_status << "\n" 102 | << "> Remote Server: " << (data.m_server.empty() ? "None Specified" : data.m_server) << "\n" 103 | << "> Error/close reason: " << (data.m_error_reason.empty() ? "N/A" : data.m_error_reason) << "\n"; 104 | out << "> Messages Processed: (" << data.m_messages.size() << ") \n"; 105 | 106 | //std::vector::const_iterator it; 107 | //for (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) { 108 | // out << *it << "\n"; 109 | //} 110 | 111 | return out; 112 | } 113 | 114 | ws_client g_wsEndPoint; 115 | connection_metadata::ptr g_wsClientConnection; 116 | 117 | websocketpp::lib::shared_ptr g_threadWS; 118 | 119 | websocket_endpoint::websocket_endpoint() { 120 | g_wsEndPoint.clear_access_channels(websocketpp::log::alevel::all); 121 | g_wsEndPoint.clear_error_channels(websocketpp::log::elevel::all); 122 | 123 | g_wsEndPoint.init_asio(); 124 | g_wsEndPoint.start_perpetual(); 125 | 126 | g_threadWS = websocketpp::lib::make_shared(&ws_client::run, &g_wsEndPoint); 127 | } 128 | 129 | websocket_endpoint::~websocket_endpoint() { 130 | g_wsEndPoint.stop_perpetual(); 131 | 132 | if (g_wsClientConnection->get_status() == "Open") { 133 | // Only close open connections 134 | websocketpp::lib::error_code ec; 135 | g_wsEndPoint.close(g_wsClientConnection->get_hdl(), websocketpp::close::status::going_away, "", ec); 136 | if (ec) { 137 | std::cout << "> Error closing ws connection " << g_wsClientConnection->get_uri() << " :" << ec.message() << std::endl; 138 | } 139 | } 140 | 141 | g_threadWS->join(); 142 | } 143 | 144 | int websocket_endpoint::connect(std::string const & uri) { 145 | websocketpp::lib::error_code ec; 146 | 147 | ws_client::connection_ptr pConnection = g_wsEndPoint.get_connection(uri, ec); 148 | 149 | if (ec) { 150 | std::cout << "> Connect initialization error: " << ec.message() << std::endl; 151 | return -1; 152 | } 153 | 154 | g_wsClientConnection = websocketpp::lib::make_shared(pConnection->get_handle(), uri); 155 | 156 | pConnection->set_open_handler(websocketpp::lib::bind( 157 | &connection_metadata::on_open, 158 | g_wsClientConnection, 159 | &g_wsEndPoint, 160 | websocketpp::lib::placeholders::_1 161 | )); 162 | pConnection->set_fail_handler(websocketpp::lib::bind( 163 | &connection_metadata::on_fail, 164 | g_wsClientConnection, 165 | &g_wsEndPoint, 166 | websocketpp::lib::placeholders::_1 167 | )); 168 | pConnection->set_close_handler(websocketpp::lib::bind( 169 | &connection_metadata::on_close, 170 | g_wsClientConnection, 171 | &g_wsEndPoint, 172 | websocketpp::lib::placeholders::_1 173 | )); 174 | pConnection->set_message_handler(websocketpp::lib::bind( 175 | &connection_metadata::on_message, 176 | g_wsClientConnection, 177 | websocketpp::lib::placeholders::_1, 178 | websocketpp::lib::placeholders::_2 179 | )); 180 | 181 | g_wsEndPoint.connect(pConnection); 182 | 183 | return 0; 184 | } 185 | 186 | void close(websocketpp::close::status::value code, std::string reason) { 187 | websocketpp::lib::error_code ec; 188 | 189 | g_wsEndPoint.close(g_wsClientConnection->get_hdl(), code, reason, ec); 190 | if (ec) { 191 | std::cout << "> Error initiating close: " << ec.message() << std::endl; 192 | } 193 | } 194 | 195 | void websocket_endpoint::close() 196 | { 197 | if (g_wsClientConnection->get_status() == "Open") 198 | { 199 | int close_code = websocketpp::close::status::normal; 200 | kagula::close(close_code, ""); 201 | } 202 | } 203 | 204 | void websocket_endpoint::send(std::string message) { 205 | websocketpp::lib::error_code ec; 206 | 207 | g_wsEndPoint.send(g_wsClientConnection->get_hdl(), message, websocketpp::frame::opcode::text, ec); 208 | if (ec) { 209 | std::cout << "> Error sending message: " << ec.message() << std::endl; 210 | return; 211 | } 212 | 213 | g_wsClientConnection->record_sent_message(message); 214 | } 215 | 216 | void websocket_endpoint::show(std::vector &msg) 217 | { 218 | //std::cout << *g_wsClientConnection << std::endl; 219 | msg = g_wsClientConnection->get_message(); 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/CWebSocket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | namespace kagula 4 | { 5 | class websocket_endpoint { 6 | public: 7 | websocket_endpoint(); 8 | ~websocket_endpoint(); 9 | 10 | int connect(std::string const & uri); 11 | void close(); 12 | 13 | void send(std::string message); 14 | void show(std::vector &msg); 15 | }; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/RemoteControl_node.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ros/ros.h" 3 | #include "sensor_msgs/Joy.h" 4 | #include "CHTTP_post.h" 5 | #include "CWebSocket.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #define steerMax -1.0 12 | using namespace std; 13 | 14 | //control 15 | double m_carSpeed = 0; 16 | double m_carWheel = 0; 17 | double m_sendwheel; 18 | double m_speed; 19 | 20 | bool flag_sendThread_stop =true; 21 | bool flag_SendThread = false; 22 | bool flag_ReceiveThread =false; 23 | bool flag_Apprequest =false; 24 | bool appfirst=true; 25 | struct JsonStruct 26 | { 27 | int wheel; 28 | double speed; 29 | std::string Id; 30 | std::string reserve; 31 | }; 32 | struct CarStatus 33 | { 34 | double wheelAngle; 35 | double vehicleSpeed; 36 | int gear; 37 | int controlStatus; 38 | enum GEAR { 39 | UNKNOWN=0, 40 | N = 1, 41 | D = 2, 42 | R=3, 43 | P=4, 44 | L=5, 45 | M=6, 46 | }; 47 | enum controlStatus { 48 | IDLE = 0, 49 | START=1, 50 | STOP=2, 51 | E_STOP=3, 52 | }; 53 | }; 54 | enum CALIBRATE_CONTROL { 55 | SKIP = -1, 56 | SAVE = -2, 57 | CANCEL = -3, 58 | 59 | WHEEL = 0, 60 | ACCELERATOR = 1, 61 | BRAKE = 2, 62 | CLUTCH = 3, 63 | 64 | X_AXIS = 1, 65 | Y_AXIS = 2, 66 | Z_AXIS = 3, 67 | SLIDER_0 = 4, 68 | SLIDER_1 = 5, 69 | X_ROT = 6, 70 | Y_ROT = 7, 71 | Z_ROT = 8, 72 | }; 73 | void callback_control(const sensor_msgs::Joy::ConstPtr& msg){ 74 | //wheel 75 | double m_wheel = msg->axes[0]; 76 | //cout<axes[2]; 79 | //brake 80 | double m_brake =msg->axes[3]; 81 | 82 | auto flagg = msg->buttons[0];//stop send 83 | if(flagg==1) 84 | flag_SendThread = false; 85 | auto flagg_stop = msg->buttons[2];//stop send 86 | if(flagg_stop==1) 87 | { 88 | flag_SendThread = true; 89 | flag_Apprequest = false; 90 | appfirst=true; 91 | } 92 | 93 | double a=0; 94 | int t = 1;//时间差 95 | //define max deceleration 7.5m/ss; 96 | if (m_brake > steerMax)//16bit 刹车被踩下 97 | { 98 | double delta =fabs( m_brake-steerMax); 99 | a = delta / (2.0 * steerMax) *10.0; 100 | } 101 | //define max accelerated speed 7.5m/ss; 102 | else if (m_youmen > steerMax)//油门被踩下 103 | { 104 | double delta = fabs(steerMax - m_youmen); 105 | a = -delta / (2.0 * steerMax) *15.0; 106 | } 107 | m_speed = m_carSpeed + a * t; 108 | if (m_speed < 0)m_speed = 0; 109 | m_sendwheel = double(m_wheel) / double(steerMax) * 520.0; 110 | //cout<<"111111111111speed:"< msg; 123 | 124 | endpoint.show(msg); 125 | //cout<=1) 141 | { 142 | m_carSpeed = carStatus.vehicleSpeed; 143 | m_carWheel = carStatus.wheelAngle; 144 | } 145 | auto map_s = root["MapStatus"]["map_status"].asInt(); 146 | if(map_s==5) 147 | flag_Apprequest=true; 148 | } 149 | 150 | } 151 | } 152 | 153 | 154 | //cout<<"car speed:"<-530&&s>=0&&s<30) 196 | ht.xfuture_http_post_json(url, post, result, errormsg); 197 | else 198 | ROS_WARN("input invalid..."); 199 | auto t2 = ros::Time::now().toSec(); 200 | auto de = t2-t1; 201 | //cout<<"send time:"<100000) 206 | count =0; 207 | } 208 | flag_sendThread_stop = true; 209 | } 210 | void StartSendThread() 211 | { 212 | if (!flag_SendThread && flag_sendThread_stop) 213 | { 214 | //boost::function0< void> f = boost::bind(&SendThread, NULL); 215 | boost::thread thread1(&SendThread); 216 | thread1.detach(); 217 | } 218 | else 219 | { 220 | ROS_WARN("Sending thread is already running!"); 221 | return; 222 | } 223 | } 224 | void StartReceiveThread() 225 | { 226 | if (!flag_ReceiveThread) 227 | { 228 | //boost::function0< void> f = boost::bind(&CLojiWheelRsvDlg::receiveThread, this); 229 | boost::thread thread1(&ReceiveThread); 230 | thread1.detach(); 231 | } 232 | else 233 | { 234 | ROS_WARN("Receive thread is already running!"); 235 | return; 236 | } 237 | } 238 | int main(int argc,char *argv[]){ 239 | ros::init(argc,argv,"remoteControl"); 240 | ros::NodeHandle n; 241 | ros::Subscriber joy_sub = n.subscribe("joy",1000,&callback_control); 242 | StartSendThread(); 243 | StartReceiveThread(); 244 | while (ros::ok()) 245 | { 246 | ros::spinOnce(); 247 | //cout<<"spinOnce"<