diff --git a/README.md b/README.md
index c54b985..4231cc9 100644
--- a/README.md
+++ b/README.md
@@ -2,60 +2,101 @@
livox_ros_driver is a new ros package, which is designed to gradually become the standard driver package for livox devices in the ros environment.
-### Compile & Install Livox SDK
+## Compile & Install Livox SDK
livox_ros_driver depends on Livox-SDK lib. If you have never installed Livox-SDK lib or it is out of date, you must first install Livox-SDK lib. If you have installed the latest version of Livox-SDK, skip this step and go to the next step.
1. Download or clone the [Livox-SDK/Livox-SDK](https://github.com/Livox-SDK/Livox-SDK/) repository on GitHub.
2. Compile and install the Livox-SDK under the ***build*** directory following `README.md` of Livox-SDK/Livox-SDK.
-### Clone livox_ros_driver
+## Clone livox_ros_driver
-1. Clone livox_ros_driver package for github:
+1. Clone livox_ros_driver package for github :
`git clone https://github.com/Livox-SDK/livox_ros_driver.git ws_livox/src`
-2. Build livox_ros_driver package:
+2. Build livox_ros_driver package :
```
cd ws_livox
catkin_make
```
-3. Package environment setup:
+3. Package environment setup :
- `source ./devel/setup.sh`
+ `source ./devel/setup.sh`
-### Run livox ros driver
+## Run livox_ros_driver
-The driver offers users a wealth of options when using different launch file. There is *bd_list* arg in each launch file. All Livox LiDAR units in your LAN will be connected automatically in default.
+##### Run livox_ros_driver using launch file
-e.g.
+The command format is :
-```
-roslaunch livox_ros_driver livox_lidar_rviz.launch
-```
+ `roslaunch livox_ros_driver [launch file] [param]`
-If you want to connect to the specific LiDAR uint(s) only, please add the broadcast code into command line.
+1. Connect LiDAR uint(s) automatically.
-e.g.
+ `roslaunch livox_ros_driver livox_lidar_rviz.launch`
-```
-roslaunch livox_ros_driver livox_lidar_rviz.launch bd_list:="broadcast_code1&broadcast_code2&broadcast_code3"
-```
+2. Connect to the specific LiDAR uint(s), suppose there are LiDAR(0TFDG3B006H2Z11) and LiDAR(1HDDG8M00100191) .
-Features of *.launch* files are listed as below:
+ Specify the LiDAR via command line arguments :
+
+ ```
+ roslaunch livox_ros_driver livox_lidar_rviz.launch bd_list:="0TFDG3B006H2Z11&1HDDG8M00100191"
+ ```
+
+ *Specifying the LiDAR via json file is supported, detailed usage will be explained later.*
+
+***NOTE:***
+
+Each Livox LiDAR unit owns a unique Broadcast Code . The broadcast code consists of its serial number and an additional number (1,2, or 3). The serial number can be found on the body of the LiDAR unit (below the QR code).The Broadcast Code may be used when you want to connect to the specific LiDAR unit(s). The detailed format is shown as below :
+
+
+
+##### Launch file introduction
+
+The driver offers users a wealth of options when using different launch file. The launch file directory
+
+is "ws_livox/src/livox_ros_driver/launch". All launch files are listed as below :
| launch file | features |
| ------------------------- | ------------------------------------------------------------ |
-| *livox_lidar_rviz.launch* | Connect to Livox LiDAR units
Publish pointcloud2 format point cloud
Automatically load rviz |
+| livox_lidar_rviz.launch | Connect to Livox LiDAR units
Publish pointcloud2 format point cloud
Automatically load rviz |
| livox_hub_rviz.launch | Connect to Livox Hub units
Publish pointcloud2 format point cloud
Automatically load rviz |
| livox_lidar.launch | Connect to Livox LiDAR units
Publish pointcloud2 format point cloud |
| livox_hub.launch | Connect to Livox Hub units
Publish pointcloud2 format point cloud |
| livox_lidar_msg.launch | Connect to Livox LiDAR units
Publish livox custom format point cloud |
| livox_hub_msg.launch | Connect to Livox Hub units
Publish livox custom format point cloud |
+| lvx_to_rosbag.launch | Covert lvx file to rosbag file
Covert lvx file directly to rosbag file |
+| lvx_to_rosbag_rviz.launch | Covert lvx file to rosbag file
Read data from lvx file and convert it to pointcloud2, then publish using ros topic |
-Livox custom msg format:
+## Configure livox_ros_driver internal parameter
+
+The livox_ros_driver internal parameters are in the launch file, they are listed as below :
+
+| Parameter name | detail |
+| -------------- | ------------------------------------------------------------ |
+| publish_freq | Set the frequency of publishing pointcloud data
The data type is float, it can be set to 10.0,20.0,50.0,100.0,200, etc. |
+| multi_topic | All lidars share the same topic, or each lidar uses a topic independently
0 -- all lidars share the same topic
1 -- each lidar uses a topic independently |
+| xfer_format | Set publish data format
0 -- livox pointcloud2(PointXYZRTL)
1 -- livox custom msg format
2 -- pcl pointcloud2(pcl::PointXYZI) |
+
+***Notes :***
+
+Detailed xfer data format
+
+1.1 The livox point format in pointcloud2 message :
+
+```
+float32 x # X axis, unit:m
+float32 y # Y axis, unit:m
+float32 z # Z axis, unit:m
+float intensity # the value is reflectivity, 0~255
+uint8 tag # livox tag
+uint8 line # laser number in lidar
+```
+
+1.2 Livox custom message format :
```
Header header # ROS standard message header
@@ -65,12 +106,139 @@ uint8 lidar_id # Lidar device id number
uint8[3] rsvd # Reserved use
CustomPoint[] points # Pointcloud data
```
-pointcloud format:
+
+The Custom Point format in custom message :
+
```
uint32 offset_time # offset time relative to the base time
float32 x # X axis, unit:m
float32 y # Y axis, unit:m
float32 z # Z axis, unit:m
uint8 reflectivity # reflectivity, 0~255
+uint8 tag # livox tag
uint8 line # laser number in lidar
```
+
+1.3 PCL pointcloud2(pcl::PointXYZI) format :
+
+ Please refer the pcl::PointXYZI structure in Point Cloud Library (point_types.hpp) .
+
+## Configure LiDAR parameter
+
+There are two json files in the directory "ws_livox/src/livox_ros_driver/launch", they are livox_hub_config.json and livox_lidar_config.json.
+
+1. When connect with LiDAR only, we can modify LiDAR parameter in livox_lidar_config.json.
+
+ The content of the file livox_lidar_config.json is as follows :
+
+ ```
+ {
+ "lidar_config": [
+ {
+ "broadcast_code": "0TFDG3B006H2Z11",
+ "enable_connect": true,
+ "enable_fan": true,
+ "return_mode": 0,
+ "coordinate": 0,
+ "imu_rate": 1,
+ "extrinsic_parameter_source": 0
+ }
+ ]
+ }
+ ```
+
+ If you want to config a new LiDAR by livox_lidar_config.json file. For example , if you want to config a LiDAR (broadcast code : "1HDDG8M00100191") : (1) enable connection;(2) enable fan; (3) select First single return mode; (4) use Cartesian coordinate; (5) use Cartesian coordinate; (6) set imu rate to 200; (7)enable extrinsic parameter. the content of livox_lidar_config.json file should be :
+
+ ```
+ {
+ "lidar_config": [
+ {
+ "broadcast_code": "0TFDG3B006H2Z11",
+ "enable_connect": true,
+ "enable_fan": true,
+ "return_mode": 0,
+ "coordinate": 0,
+ "imu_rate": 1,
+ "extrinsic_parameter_source": 1
+ },
+ {
+ "broadcast_code": "1HDDG8M00100191",
+ "enable_connect": true,
+ "enable_fan": true,
+ "return_mode": 0,
+ "coordinate": 0,
+ "imu_rate": 1,
+ "extrinsic_parameter_source": 1
+ }
+ ]
+ }
+ ```
+
+
+
+2. When connect with Hub, we must modify Hub or LiDAR parameter in livox_hub_config.json.
+
+ The content of the livox_hub_config.json is as follows :
+
+ ```
+ {
+ "hub_config": {
+ "broadcast_code": "13UUG1R00400170",
+ "enable_connect": true,
+ "coordinate": 0
+ },
+ "lidar_config": [
+ {
+ "broadcast_code": "0TFDG3B006H2Z11",
+ "enable_fan": true,
+ "return_mode": 0,
+ "imu_rate": 1
+ }
+ ]
+ }
+ ```
+
+If you want to config a new LiDAR by the livox_hub_config.json file, For example , if you want to config a LiDAR (broadcast code : "1HDDG8M00100191") : (1) enable connection;(2) enable fan; (3) select First single return mode; (4) use Cartesian coordinate; (5) use Cartesian coordinate; (6) set imu rate to 200. the content of the livox_hub_config.json file should be :
+
+```
+{
+ "hub_config": {
+ "broadcast_code": "13UUG1R00400170",
+ "enable_connect": true,
+ "coordinate": 0
+ },
+ "lidar_config": [
+ {
+ "broadcast_code": "0TFDG3B006H2Z11",
+ "enable_fan": true,
+ "return_mode": 0,
+ "imu_rate": 1
+ },
+ {
+ "broadcast_code": "1HDDG8M00100191",
+ "enable_fan": true,
+ "return_mode": 0,
+ "imu_rate": 1
+ }
+ ]
+}
+```
+
+***Notes :***
+
+When connect with Hub, the lidar's parameter "enable_connect" and "coordinate" could only be set via hub.
+
+## Convert the lvx data file(v1.0/v1.1) to rosbag file
+
+Livox ros driver support lvx file to rosbag file function, using lvx_to_rosbag.launch file.
+
+Excute the follow command :
+
+ `roslaunch livox_ros_driver lvx_to_rosbag.launch lvx_file_path:="/home/livox/test.lvx"`
+
+Replace the path "/home/livox/test.lvx" to your local path when convert the lvx data file.
+
+
+
+
+
diff --git a/images/broadcast_code.png b/images/broadcast_code.png
new file mode 100644
index 0000000..78deb5a
Binary files /dev/null and b/images/broadcast_code.png differ
diff --git a/livox_ros_driver/CMakeLists.txt b/livox_ros_driver/CMakeLists.txt
old mode 100755
new mode 100644
index 61e7d2c..0b95e1b
--- a/livox_ros_driver/CMakeLists.txt
+++ b/livox_ros_driver/CMakeLists.txt
@@ -1,162 +1,50 @@
-cmake_minimum_required(VERSION 2.8.3)
+# Copyright(c) 2019 livoxtech limited.
-project(livox_ros_driver)
+cmake_minimum_required(VERSION 3.0)
-set(PROJECT_LIDAR livox_lidar)
-set(PROJECT_HUB livox_hub)
-set(PROJECT_LIDAR_SRC ./livox_lidar.cpp)
-set(PROJECT_HUB_SRC ./livox_hub.cpp)
-## Compile as C++11, supported in ROS Kinetic and newer
-# add_compile_options(-std=c++11)
-add_definitions(-std=c++11)
+#---------------------------------------------------------------------------------------
+# Start livox_ros_driver project
+#---------------------------------------------------------------------------------------
+include(cmake/version.cmake)
+project(livox_ros_driver VERSION ${LIVOX_ROS_DRIVER_VERSION} LANGUAGES CXX)
+message(STATUS "livox_ros_driver version: ${LIVOX_ROS_DRIVER_VERSION}")
+
+#---------------------------------------------------------------------------------------
+# find package and the dependecy
+#---------------------------------------------------------------------------------------
+find_package(Boost 1.54 REQUIRED COMPONENTS
+ system
+ thread
+ chrono
+ )
## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
- roscpp
- rospy
- std_msgs
- message_generation
-)
+ roscpp
+ rospy
+ sensor_msgs
+ std_msgs
+ message_generation
+ rosbag
+ )
-find_package(Boost REQUIRED)
-
-find_package(Boost REQUIRED COMPONENTS thread)
-
-## get pointcloud package
+## Find pcl lib
find_package(PCL REQUIRED)
-## System dependencies are found with CMake's conventions
-# find_package(Boost REQUIRED COMPONENTS system)
-
-
-## Uncomment this if the package has a setup.py. This macro ensures
-## modules and global scripts declared therein get installed
-## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
-# catkin_python_setup()
-
-
-
-################################################
-## Declare ROS messages, services and actions ##
-################################################
-
-## To declare and build messages, services or actions from within this
-## package, follow these steps:
-## * Let MSG_DEP_SET be the set of packages whose message types you use in
-## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
-## * In the file package.xml:
-## * add a build_depend tag for "message_generation"
-## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET
-## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
-## but can be declared for certainty nonetheless:
-## * add a run_depend tag for "message_runtime"
-## * In this file (CMakeLists.txt):
-## * add "message_generation" and every package in MSG_DEP_SET to
-## find_package(catkin REQUIRED COMPONENTS ...)
-## * add "message_runtime" and every package in MSG_DEP_SET to
-## catkin_package(CATKIN_DEPENDS ...)
-## * uncomment the add_*_files sections below as needed
-## and list every .msg/.srv/.action file to be processed
-## * uncomment the generate_messages entry below
-## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
-
## Generate messages in the 'msg' folder
add_message_files(FILES
CustomPoint.msg
CustomMsg.msg
# Message2.msg
-)
-
-## Generate services in the 'srv' folder
-# add_service_files(
-# FILES
-# Service1.srv
-# Service2.srv
-# )
-
-## Generate actions in the 'action' folder
-# add_action_files(
-# FILES
-# Action1.action
-# Action2.action
-# )
+ )
## Generate added messages and services with any dependencies listed here
generate_messages(DEPENDENCIES
- std_msgs
- )
-
-################################################
-## Declare ROS dynamic reconfigure parameters ##
-################################################
-
-## To declare and build dynamic reconfigure parameters within this
-## package, follow these steps:
-## * In the file package.xml:
-## * add a build_depend and a run_depend tag for "dynamic_reconfigure"
-## * In this file (CMakeLists.txt):
-## * add "dynamic_reconfigure" to
-## find_package(catkin REQUIRED COMPONENTS ...)
-## * uncomment the "generate_dynamic_reconfigure_options" section below
-## and list every .cfg file to be processed
-
-## Generate dynamic reconfigure parameters in the 'cfg' folder
-# generate_dynamic_reconfigure_options(
-# cfg/DynReconf1.cfg
-# cfg/DynReconf2.cfg
-# )
-
-###################################
-## catkin specific configuration ##
-###################################
-## The catkin_package macro generates cmake config files for your package
-## Declare things to be passed to dependent projects
-## INCLUDE_DIRS: uncomment this if your package contains header files
-## LIBRARIES: libraries you create in this project that dependent projects also need
-## CATKIN_DEPENDS: catkin_packages dependent projects also need
-## DEPENDS: system dependencies of this project that dependent projects also need
-catkin_package(CATKIN_DEPENDS
- roscpp rospy std_msgs message_runtime
-)
-
-###########
-## Build ##
-###########
-
-## Specify additional locations of header files
-## Your package locations should be listed before other locations
-include_directories(
- ${catkin_INCLUDE_DIRS}
- ${PCL_INCLUDE_DIRS}
-)
-
-## Declare a C++ library
-# add_library(${PROJECT_NAME}
-# src/${PROJECT_NAME}/lidar_sdk.cpp
-# )
-
-## Add cmake target dependencies of the library
-## as an example, code may need to be generated before libraries
-## either from message generation or dynamic reconfigure
-# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
-
-## Declare a C++ executable
-## With catkin_make all packages are built within a single CMake context
-## The recommended prefix ensures that target names across packages don't collide
-##SET(SRC_DIR
-## ./
-##)
-
-# traverse all source directories and add include dir
-##FOREACH(dir ${SRC_DIR})
-## MESSAGE(STATUS"src_dir: "${dir})
-## include_directories(./include/${dir})
-## include_directories(./${dir})
-## AUX_SOURCE_DIRECTORY(${dir} source_list)
-##ENDFOREACH()
+ std_msgs
+ )
find_package(PkgConfig)
pkg_check_modules(APR apr-1)
@@ -165,14 +53,32 @@ if (APR_FOUND)
message(${APR_LIBRARIES})
endif (APR_FOUND)
-include_directories(
- ./
- ${APR_INCLUDE_DIRS}
-)
+###################################
+## catkin specific configuration ##
+###################################
+## The catkin_package macro generates cmake config files for your package
+## Declare things to be passed to dependent projects
+## INCLUDE_DIRS: uncomment this if your package contains header files
+## LIBRARIES: libraries you create in this project that dependent projects als o need
+## CATKIN_DEPENDS: catkin_packages dependent projects also need
+## DEPENDS: system dependencies of this project that dependent projects also n eed
+catkin_package(CATKIN_DEPENDS
+ roscpp rospy std_msgs message_runtime
+ )
-## PCL library
-link_directories(${PCL_LIBRARY_DIRS})
-add_definitions(${PCL_DEFINITIONS})
+#---------------------------------------------------------------------------------------
+# Set default build to release
+#---------------------------------------------------------------------------------------
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE)
+endif()
+
+#---------------------------------------------------------------------------------------
+# Compiler config
+#---------------------------------------------------------------------------------------
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
## make sure the livox_sdk_static library is installed
find_library(LIVOX_SDK_LIBRARY liblivox_sdk_static.a /usr/local/lib)
@@ -218,113 +124,83 @@ if((NOT LIVOX_SDK_LIBRARY) OR (NOT EXISTS ${LIVOX_SDK_LIBRARY}))
${CMAKE_CURRENT_SOURCE_DIR}/Livox-SDK/build/sdk_core
)
- ## add lidar project here
- add_executable(${PROJECT_LIDAR}_node
- ${PROJECT_LIDAR_SRC}
- )
-
- add_dependencies(${PROJECT_LIDAR}_node ${PROJECT_NAME}_generate_messages_cpp)
-
- target_link_libraries(${PROJECT_LIDAR}_node
- livox_sdk_static.a
- ${APR_LIBRARIES}
- ${catkin_LIBRARIES}
- ${Boost_LIBRARIES}
- -lrt
- )
-
- ## add hub project here
- add_executable(${PROJECT_HUB}_node
- ${PROJECT_HUB_SRC}
- )
-
- add_dependencies(${PROJECT_LIDAR}_node ${PROJECT_NAME}_generate_messages_cpp)
-
- target_link_libraries(${PROJECT_HUB}_node
- livox_sdk_static.a
- ${APR_LIBRARIES}
- ${catkin_LIBRARIES}
- ${Boost_LIBRARIES}
- -lrt
- )
-
else()
message("find livox sdk library success")
-
- ## add lidar project here
- add_executable(${PROJECT_LIDAR}_node
- ${PROJECT_LIDAR_SRC}
- )
-
- add_dependencies(${PROJECT_LIDAR}_node ${PROJECT_NAME}_generate_messages_cpp)
-
- target_link_libraries(${PROJECT_LIDAR}_node
- livox_sdk_static.a
- ${APR_LIBRARIES}
- ${catkin_LIBRARIES}
- ${Boost_LIBRARIES}
- -lrt
- )
-
- ## add hub project here
- add_executable(${PROJECT_HUB}_node
- ${PROJECT_HUB_SRC}
- )
-
- add_dependencies(${PROJECT_HUB}_node ${PROJECT_NAME}_generate_messages_cpp)
-
- target_link_libraries(${PROJECT_HUB}_node
- livox_sdk_static.a
- ${APR_LIBRARIES}
- ${catkin_LIBRARIES}
- ${Boost_LIBRARIES}
- -lrt
- )
-
endif()
-#############
-## Install ##
-#############
+## PCL library
+link_directories(${PCL_LIBRARY_DIRS})
+add_definitions(${PCL_DEFINITIONS})
-# all install targets should use catkin DESTINATION variables
-# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
+#---------------------------------------------------------------------------------------
+# generate excutable and add libraries
+#---------------------------------------------------------------------------------------
+add_executable(${PROJECT_NAME}_node
+ ""
+ )
-## Mark executable scripts (Python etc.) for installation
-## in contrast to setup.py, you can choose the destination
-# install(PROGRAMS
-# scripts/my_python_script
-# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
-# )
+#---------------------------------------------------------------------------------------
+# precompile macro and compile option
+#---------------------------------------------------------------------------------------
+target_compile_options(${PROJECT_NAME}_node
+ PRIVATE $<$:-Wall -Werror>
+ )
-## Mark executables and/or libraries for installation
-# install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node
-# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
-# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
-# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
-# )
+#---------------------------------------------------------------------------------------
+# add projects that depend on
+#---------------------------------------------------------------------------------------
+add_dependencies(${PROJECT_NAME}_node ${PROJECT_NAME}_generate_messages_cpp)
-## Mark cpp header files for installation
-# install(DIRECTORY include/${PROJECT_NAME}/
-# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
-# FILES_MATCHING PATTERN "*.h"
-# PATTERN ".svn" EXCLUDE
-# )
+#---------------------------------------------------------------------------------------
+# source file
+#---------------------------------------------------------------------------------------
+target_sources(${PROJECT_NAME}_node
+ PRIVATE
+ livox_ros_driver/lvx_file.cpp
+ livox_ros_driver/ldq.cpp
+ livox_ros_driver/lds.cpp
+ livox_ros_driver/lds_lvx.cpp
+ livox_ros_driver/lds_lidar.cpp
+ livox_ros_driver/lds_hub.cpp
+ livox_ros_driver/lddc.cpp
+ livox_ros_driver/livox_ros_driver.cpp
+ timesync/timesync.cpp
+ timesync/user_uart/user_uart.cpp
+ common/comm/comm_protocol.cpp
+ common/comm/sdk_protocol.cpp
+ common/comm/gps_protocol.cpp
+ )
-## Mark other files for installation (e.g. launch and bag files, etc.)
-# install(FILES
-# # myfile1
-# # myfile2
-# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
-# )
+#---------------------------------------------------------------------------------------
+# include file
+#---------------------------------------------------------------------------------------
+target_include_directories(${PROJECT_NAME}_node
+ PUBLIC
+ ${catkin_INCLUDE_DIRS}
+ ${PCL_INCLUDE_DIRS}
+ ${APR_INCLUDE_DIRS}
+ common
+ common/rapidjson
+ comon/rapdidxml
+ common/comm
+ timesync
+ timesync/user_uart
+ livox_ros_driver
+ )
-#############
-## Testing ##
-#############
+#---------------------------------------------------------------------------------------
+# link libraries
+#---------------------------------------------------------------------------------------
+target_link_libraries(${PROJECT_NAME}_node
+ livox_sdk_static.a
+ ${Boost_LIBRARY}
+ ${catkin_LIBRARIES}
+ ${PCL_LIBRARIES}
+ ${APR_LIBRARIES}
+ )
+
+#---------------------------------------------------------------------------------------
+# end of CMakeList.txt
+#---------------------------------------------------------------------------------------
-## Add gtest based cpp test target and link libraries
-# catkin_add_gtest(${PROJECT_NAME}-test test/test_lidar_sdk.cpp)
-# if(TARGET ${PROJECT_NAME}-test)
-# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
-# endif()
diff --git a/livox_ros_driver/cmake/version.cmake b/livox_ros_driver/cmake/version.cmake
new file mode 100644
index 0000000..74bb86b
--- /dev/null
+++ b/livox_ros_driver/cmake/version.cmake
@@ -0,0 +1,16 @@
+#---------------------------------------------------------------------------------------
+# Get livox_ros_driver version from include/livox_ros_driver.h
+#---------------------------------------------------------------------------------------
+file(READ "${CMAKE_CURRENT_LIST_DIR}/../livox_ros_driver/include/livox_ros_driver.h" LIVOX_ROS_DRIVER_VERSION_FILE)
+string(REGEX MATCH "LIVOX_ROS_DRIVER_VER_MAJOR ([0-9]+)" _ "${LIVOX_ROS_DRIVER_VERSION_FILE}")
+set(ver_major ${CMAKE_MATCH_1})
+
+string(REGEX MATCH "LIVOX_ROS_DRIVER_VER_MINOR ([0-9]+)" _ "${LIVOX_ROS_DRIVER_VERSION_FILE}")
+set(ver_minor ${CMAKE_MATCH_1})
+string(REGEX MATCH "LIVOX_ROS_DRIVER_VER_PATCH ([0-9]+)" _ "${LIVOX_ROS_DRIVER_VERSION_FILE}")
+set(ver_patch ${CMAKE_MATCH_1})
+
+if (NOT DEFINED ver_major OR NOT DEFINED ver_minor OR NOT DEFINED ver_patch)
+ message(FATAL_ERROR "Could not extract valid version from include/livox_ros_driver.h")
+endif()
+set (LIVOX_ROS_DRIVER_VERSION "${ver_major}.${ver_minor}.${ver_patch}")
diff --git a/livox_ros_driver/common/FastCRC/FastCRC.h b/livox_ros_driver/common/FastCRC/FastCRC.h
new file mode 100644
index 0000000..d796171
--- /dev/null
+++ b/livox_ros_driver/common/FastCRC/FastCRC.h
@@ -0,0 +1,79 @@
+/* FastCRC library code is placed under the MIT license
+ * Copyright (c) 2014,2015 Frank Bosing
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+// Teensy 3.0, Teensy 3.1:
+// See K20P64M72SF1RM.pdf (Kinetis), Pages 638 - 641 for documentation of CRC Device
+// See KINETIS_4N30D.pdf for Errata (Errata ID 2776)
+//
+// So, ALL HW-calculations are done as 32 bit.
+//
+//
+//
+// Thanks to:
+// - Catalogue of parametrised CRC algorithms, CRC RevEng
+// http://reveng.sourceforge.net/crc-catalogue/
+//
+// - Danjel McGougan (CRC-Table-Generator)
+//
+
+//
+// modify from FastCRC library @ 2018/11/20
+//
+
+#ifndef FASTCRC_FASTCRC_H_
+#define FASTCRC_FASTCRC_H_
+
+#include
+
+
+// ================= 16-BIT CRC ===================
+
+class FastCRC16 {
+public:
+ FastCRC16(uint16_t seed);
+
+ // change function name from mcrf4xx_upd to mcrf4xx
+ uint16_t mcrf4xx_calc(const uint8_t *data,const uint16_t datalen); // Equivalent to _crc_ccitt_update() in crc16.h from avr_libc
+
+private:
+ uint16_t seed_;
+
+};
+
+// ================= 32-BIT CRC ===================
+
+class FastCRC32 {
+public:
+ FastCRC32(uint32_t seed);
+
+ // change function name from crc32_upd to crc32
+ uint32_t crc32_calc(const uint8_t *data, uint16_t len); // Call for subsequent calculations with previous seed
+
+private:
+ uint32_t seed_;
+};
+
+#endif // FASTCRC_FASTCRC_H_
+
diff --git a/livox_ros_driver/common/FastCRC/FastCRC_tables.hpp b/livox_ros_driver/common/FastCRC/FastCRC_tables.hpp
new file mode 100644
index 0000000..4726e26
--- /dev/null
+++ b/livox_ros_driver/common/FastCRC/FastCRC_tables.hpp
@@ -0,0 +1,241 @@
+/* FastCRC library code is placed under the MIT license
+ * Copyright (c) 2014,2015 Frank Bosing
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+ /*
+ Tables generated with universal_crc by Danjel McGougan
+ */
+
+//
+// modify from FastCRC library @ 2018/11/20
+//
+
+
+#ifndef FASTCRC_FASTCRC_TABLES_H_
+#define FASTCRC_FASTCRC_TABLES_H_
+
+#include
+
+// crc16 table
+const uint16_t crc_table_mcrf4xx[1024] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78,
+ 0x0000, 0x19d8, 0x33b0, 0x2a68, 0x6760, 0x7eb8, 0x54d0, 0x4d08,
+ 0xcec0, 0xd718, 0xfd70, 0xe4a8, 0xa9a0, 0xb078, 0x9a10, 0x83c8,
+ 0x9591, 0x8c49, 0xa621, 0xbff9, 0xf2f1, 0xeb29, 0xc141, 0xd899,
+ 0x5b51, 0x4289, 0x68e1, 0x7139, 0x3c31, 0x25e9, 0x0f81, 0x1659,
+ 0x2333, 0x3aeb, 0x1083, 0x095b, 0x4453, 0x5d8b, 0x77e3, 0x6e3b,
+ 0xedf3, 0xf42b, 0xde43, 0xc79b, 0x8a93, 0x934b, 0xb923, 0xa0fb,
+ 0xb6a2, 0xaf7a, 0x8512, 0x9cca, 0xd1c2, 0xc81a, 0xe272, 0xfbaa,
+ 0x7862, 0x61ba, 0x4bd2, 0x520a, 0x1f02, 0x06da, 0x2cb2, 0x356a,
+ 0x4666, 0x5fbe, 0x75d6, 0x6c0e, 0x2106, 0x38de, 0x12b6, 0x0b6e,
+ 0x88a6, 0x917e, 0xbb16, 0xa2ce, 0xefc6, 0xf61e, 0xdc76, 0xc5ae,
+ 0xd3f7, 0xca2f, 0xe047, 0xf99f, 0xb497, 0xad4f, 0x8727, 0x9eff,
+ 0x1d37, 0x04ef, 0x2e87, 0x375f, 0x7a57, 0x638f, 0x49e7, 0x503f,
+ 0x6555, 0x7c8d, 0x56e5, 0x4f3d, 0x0235, 0x1bed, 0x3185, 0x285d,
+ 0xab95, 0xb24d, 0x9825, 0x81fd, 0xccf5, 0xd52d, 0xff45, 0xe69d,
+ 0xf0c4, 0xe91c, 0xc374, 0xdaac, 0x97a4, 0x8e7c, 0xa414, 0xbdcc,
+ 0x3e04, 0x27dc, 0x0db4, 0x146c, 0x5964, 0x40bc, 0x6ad4, 0x730c,
+ 0x8ccc, 0x9514, 0xbf7c, 0xa6a4, 0xebac, 0xf274, 0xd81c, 0xc1c4,
+ 0x420c, 0x5bd4, 0x71bc, 0x6864, 0x256c, 0x3cb4, 0x16dc, 0x0f04,
+ 0x195d, 0x0085, 0x2aed, 0x3335, 0x7e3d, 0x67e5, 0x4d8d, 0x5455,
+ 0xd79d, 0xce45, 0xe42d, 0xfdf5, 0xb0fd, 0xa925, 0x834d, 0x9a95,
+ 0xafff, 0xb627, 0x9c4f, 0x8597, 0xc89f, 0xd147, 0xfb2f, 0xe2f7,
+ 0x613f, 0x78e7, 0x528f, 0x4b57, 0x065f, 0x1f87, 0x35ef, 0x2c37,
+ 0x3a6e, 0x23b6, 0x09de, 0x1006, 0x5d0e, 0x44d6, 0x6ebe, 0x7766,
+ 0xf4ae, 0xed76, 0xc71e, 0xdec6, 0x93ce, 0x8a16, 0xa07e, 0xb9a6,
+ 0xcaaa, 0xd372, 0xf91a, 0xe0c2, 0xadca, 0xb412, 0x9e7a, 0x87a2,
+ 0x046a, 0x1db2, 0x37da, 0x2e02, 0x630a, 0x7ad2, 0x50ba, 0x4962,
+ 0x5f3b, 0x46e3, 0x6c8b, 0x7553, 0x385b, 0x2183, 0x0beb, 0x1233,
+ 0x91fb, 0x8823, 0xa24b, 0xbb93, 0xf69b, 0xef43, 0xc52b, 0xdcf3,
+ 0xe999, 0xf041, 0xda29, 0xc3f1, 0x8ef9, 0x9721, 0xbd49, 0xa491,
+ 0x2759, 0x3e81, 0x14e9, 0x0d31, 0x4039, 0x59e1, 0x7389, 0x6a51,
+ 0x7c08, 0x65d0, 0x4fb8, 0x5660, 0x1b68, 0x02b0, 0x28d8, 0x3100,
+ 0xb2c8, 0xab10, 0x8178, 0x98a0, 0xd5a8, 0xcc70, 0xe618, 0xffc0,
+ 0x0000, 0x5adc, 0xb5b8, 0xef64, 0x6361, 0x39bd, 0xd6d9, 0x8c05,
+ 0xc6c2, 0x9c1e, 0x737a, 0x29a6, 0xa5a3, 0xff7f, 0x101b, 0x4ac7,
+ 0x8595, 0xdf49, 0x302d, 0x6af1, 0xe6f4, 0xbc28, 0x534c, 0x0990,
+ 0x4357, 0x198b, 0xf6ef, 0xac33, 0x2036, 0x7aea, 0x958e, 0xcf52,
+ 0x033b, 0x59e7, 0xb683, 0xec5f, 0x605a, 0x3a86, 0xd5e2, 0x8f3e,
+ 0xc5f9, 0x9f25, 0x7041, 0x2a9d, 0xa698, 0xfc44, 0x1320, 0x49fc,
+ 0x86ae, 0xdc72, 0x3316, 0x69ca, 0xe5cf, 0xbf13, 0x5077, 0x0aab,
+ 0x406c, 0x1ab0, 0xf5d4, 0xaf08, 0x230d, 0x79d1, 0x96b5, 0xcc69,
+ 0x0676, 0x5caa, 0xb3ce, 0xe912, 0x6517, 0x3fcb, 0xd0af, 0x8a73,
+ 0xc0b4, 0x9a68, 0x750c, 0x2fd0, 0xa3d5, 0xf909, 0x166d, 0x4cb1,
+ 0x83e3, 0xd93f, 0x365b, 0x6c87, 0xe082, 0xba5e, 0x553a, 0x0fe6,
+ 0x4521, 0x1ffd, 0xf099, 0xaa45, 0x2640, 0x7c9c, 0x93f8, 0xc924,
+ 0x054d, 0x5f91, 0xb0f5, 0xea29, 0x662c, 0x3cf0, 0xd394, 0x8948,
+ 0xc38f, 0x9953, 0x7637, 0x2ceb, 0xa0ee, 0xfa32, 0x1556, 0x4f8a,
+ 0x80d8, 0xda04, 0x3560, 0x6fbc, 0xe3b9, 0xb965, 0x5601, 0x0cdd,
+ 0x461a, 0x1cc6, 0xf3a2, 0xa97e, 0x257b, 0x7fa7, 0x90c3, 0xca1f,
+ 0x0cec, 0x5630, 0xb954, 0xe388, 0x6f8d, 0x3551, 0xda35, 0x80e9,
+ 0xca2e, 0x90f2, 0x7f96, 0x254a, 0xa94f, 0xf393, 0x1cf7, 0x462b,
+ 0x8979, 0xd3a5, 0x3cc1, 0x661d, 0xea18, 0xb0c4, 0x5fa0, 0x057c,
+ 0x4fbb, 0x1567, 0xfa03, 0xa0df, 0x2cda, 0x7606, 0x9962, 0xc3be,
+ 0x0fd7, 0x550b, 0xba6f, 0xe0b3, 0x6cb6, 0x366a, 0xd90e, 0x83d2,
+ 0xc915, 0x93c9, 0x7cad, 0x2671, 0xaa74, 0xf0a8, 0x1fcc, 0x4510,
+ 0x8a42, 0xd09e, 0x3ffa, 0x6526, 0xe923, 0xb3ff, 0x5c9b, 0x0647,
+ 0x4c80, 0x165c, 0xf938, 0xa3e4, 0x2fe1, 0x753d, 0x9a59, 0xc085,
+ 0x0a9a, 0x5046, 0xbf22, 0xe5fe, 0x69fb, 0x3327, 0xdc43, 0x869f,
+ 0xcc58, 0x9684, 0x79e0, 0x233c, 0xaf39, 0xf5e5, 0x1a81, 0x405d,
+ 0x8f0f, 0xd5d3, 0x3ab7, 0x606b, 0xec6e, 0xb6b2, 0x59d6, 0x030a,
+ 0x49cd, 0x1311, 0xfc75, 0xa6a9, 0x2aac, 0x7070, 0x9f14, 0xc5c8,
+ 0x09a1, 0x537d, 0xbc19, 0xe6c5, 0x6ac0, 0x301c, 0xdf78, 0x85a4,
+ 0xcf63, 0x95bf, 0x7adb, 0x2007, 0xac02, 0xf6de, 0x19ba, 0x4366,
+ 0x8c34, 0xd6e8, 0x398c, 0x6350, 0xef55, 0xb589, 0x5aed, 0x0031,
+ 0x4af6, 0x102a, 0xff4e, 0xa592, 0x2997, 0x734b, 0x9c2f, 0xc6f3,
+ 0x0000, 0x1cbb, 0x3976, 0x25cd, 0x72ec, 0x6e57, 0x4b9a, 0x5721,
+ 0xe5d8, 0xf963, 0xdcae, 0xc015, 0x9734, 0x8b8f, 0xae42, 0xb2f9,
+ 0xc3a1, 0xdf1a, 0xfad7, 0xe66c, 0xb14d, 0xadf6, 0x883b, 0x9480,
+ 0x2679, 0x3ac2, 0x1f0f, 0x03b4, 0x5495, 0x482e, 0x6de3, 0x7158,
+ 0x8f53, 0x93e8, 0xb625, 0xaa9e, 0xfdbf, 0xe104, 0xc4c9, 0xd872,
+ 0x6a8b, 0x7630, 0x53fd, 0x4f46, 0x1867, 0x04dc, 0x2111, 0x3daa,
+ 0x4cf2, 0x5049, 0x7584, 0x693f, 0x3e1e, 0x22a5, 0x0768, 0x1bd3,
+ 0xa92a, 0xb591, 0x905c, 0x8ce7, 0xdbc6, 0xc77d, 0xe2b0, 0xfe0b,
+ 0x16b7, 0x0a0c, 0x2fc1, 0x337a, 0x645b, 0x78e0, 0x5d2d, 0x4196,
+ 0xf36f, 0xefd4, 0xca19, 0xd6a2, 0x8183, 0x9d38, 0xb8f5, 0xa44e,
+ 0xd516, 0xc9ad, 0xec60, 0xf0db, 0xa7fa, 0xbb41, 0x9e8c, 0x8237,
+ 0x30ce, 0x2c75, 0x09b8, 0x1503, 0x4222, 0x5e99, 0x7b54, 0x67ef,
+ 0x99e4, 0x855f, 0xa092, 0xbc29, 0xeb08, 0xf7b3, 0xd27e, 0xcec5,
+ 0x7c3c, 0x6087, 0x454a, 0x59f1, 0x0ed0, 0x126b, 0x37a6, 0x2b1d,
+ 0x5a45, 0x46fe, 0x6333, 0x7f88, 0x28a9, 0x3412, 0x11df, 0x0d64,
+ 0xbf9d, 0xa326, 0x86eb, 0x9a50, 0xcd71, 0xd1ca, 0xf407, 0xe8bc,
+ 0x2d6e, 0x31d5, 0x1418, 0x08a3, 0x5f82, 0x4339, 0x66f4, 0x7a4f,
+ 0xc8b6, 0xd40d, 0xf1c0, 0xed7b, 0xba5a, 0xa6e1, 0x832c, 0x9f97,
+ 0xeecf, 0xf274, 0xd7b9, 0xcb02, 0x9c23, 0x8098, 0xa555, 0xb9ee,
+ 0x0b17, 0x17ac, 0x3261, 0x2eda, 0x79fb, 0x6540, 0x408d, 0x5c36,
+ 0xa23d, 0xbe86, 0x9b4b, 0x87f0, 0xd0d1, 0xcc6a, 0xe9a7, 0xf51c,
+ 0x47e5, 0x5b5e, 0x7e93, 0x6228, 0x3509, 0x29b2, 0x0c7f, 0x10c4,
+ 0x619c, 0x7d27, 0x58ea, 0x4451, 0x1370, 0x0fcb, 0x2a06, 0x36bd,
+ 0x8444, 0x98ff, 0xbd32, 0xa189, 0xf6a8, 0xea13, 0xcfde, 0xd365,
+ 0x3bd9, 0x2762, 0x02af, 0x1e14, 0x4935, 0x558e, 0x7043, 0x6cf8,
+ 0xde01, 0xc2ba, 0xe777, 0xfbcc, 0xaced, 0xb056, 0x959b, 0x8920,
+ 0xf878, 0xe4c3, 0xc10e, 0xddb5, 0x8a94, 0x962f, 0xb3e2, 0xaf59,
+ 0x1da0, 0x011b, 0x24d6, 0x386d, 0x6f4c, 0x73f7, 0x563a, 0x4a81,
+ 0xb48a, 0xa831, 0x8dfc, 0x9147, 0xc666, 0xdadd, 0xff10, 0xe3ab,
+ 0x5152, 0x4de9, 0x6824, 0x749f, 0x23be, 0x3f05, 0x1ac8, 0x0673,
+ 0x772b, 0x6b90, 0x4e5d, 0x52e6, 0x05c7, 0x197c, 0x3cb1, 0x200a,
+ 0x92f3, 0x8e48, 0xab85, 0xb73e, 0xe01f, 0xfca4, 0xd969, 0xc5d2
+};
+
+// crc32 table
+const uint32_t crc_table_crc32[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+
+#endif
+
diff --git a/livox_ros_driver/common/FastCRC/FastCRCsw.cpp b/livox_ros_driver/common/FastCRC/FastCRCsw.cpp
new file mode 100644
index 0000000..e3b659d
--- /dev/null
+++ b/livox_ros_driver/common/FastCRC/FastCRCsw.cpp
@@ -0,0 +1,154 @@
+/* FastCRC library code is placed under the MIT license
+ * Copyright (c) 2014,2015,2016 Frank Bosing
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+//
+// Thanks to:
+// - Catalogue of parametrised CRC algorithms, CRC RevEng
+// http://reveng.sourceforge.net/crc-catalogue/
+//
+// - Danjel McGougan (CRC-Table-Generator)
+//
+
+//
+// modify from FastCRC library @ 2018/11/20
+//
+
+#include "FastCRC.h"
+#include "FastCRC_tables.hpp"
+
+
+// ================= 16-BIT CRC ===================
+/** Constructor
+ */
+FastCRC16::FastCRC16(uint16_t seed) {
+ seed_ = seed;
+}
+
+#define crc_n4(crc, data, table) crc ^= data; \
+ crc = (table[(crc & 0xff) + 0x300]) ^ \
+ (table[((crc >> 8) & 0xff) + 0x200]) ^ \
+ (table[((data >> 16) & 0xff) + 0x100]) ^ \
+ (table[data >> 24]);
+
+/** MCRF4XX
+ * equivalent to _crc_ccitt_update() in crc16.h from avr_libc
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+
+uint16_t FastCRC16::mcrf4xx_calc(const uint8_t *data, uint16_t len) {
+
+ uint16_t crc = seed_;
+
+ while (((uintptr_t)data & 3) && len) {
+ crc = (crc >> 8) ^ crc_table_mcrf4xx[(crc & 0xff) ^ *data++];
+ len--;
+ }
+
+ while (len >= 16) {
+ len -= 16;
+ crc_n4(crc, ((uint32_t *)data)[0], crc_table_mcrf4xx);
+ crc_n4(crc, ((uint32_t *)data)[1], crc_table_mcrf4xx);
+ crc_n4(crc, ((uint32_t *)data)[2], crc_table_mcrf4xx);
+ crc_n4(crc, ((uint32_t *)data)[3], crc_table_mcrf4xx);
+ data += 16;
+ }
+
+ while (len--) {
+ crc = (crc >> 8) ^ crc_table_mcrf4xx[(crc & 0xff) ^ *data++];
+ }
+
+ //seed = crc;
+ return crc;
+}
+
+
+// ================= 32-BIT CRC ===================
+/** Constructor
+ */
+FastCRC32::FastCRC32(uint32_t seed) {
+ seed_ = seed;
+}
+
+#define crc_n4d(crc, data, table) crc ^= data; \
+ crc = (table[(crc & 0xff) + 0x300]) ^ \
+ (table[((crc >> 8) & 0xff) + 0x200]) ^ \
+ (table[((crc >> 16) & 0xff) + 0x100]) ^ \
+ (table[(crc >> 24) & 0xff]);
+
+#define crcsm_n4d(crc, data, table) crc ^= data; \
+ crc = (crc >> 8) ^ (table[crc & 0xff]); \
+ crc = (crc >> 8) ^ (table[crc & 0xff]); \
+ crc = (crc >> 8) ^ (table[crc & 0xff]); \
+ crc = (crc >> 8) ^ (table[crc & 0xff]);
+
+/** CRC32
+ * Alias CRC-32/ADCCP, PKZIP, Ethernet, 802.3
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+#if CRC_BIGTABLES
+#define CRC_TABLE_CRC32 crc_table_crc32_big
+#else
+#define CRC_TABLE_CRC32 crc_table_crc32
+#endif
+
+uint32_t FastCRC32::crc32_calc(const uint8_t *data, uint16_t len) {
+
+ uint32_t crc = seed_^0xffffffff;
+
+ while (((uintptr_t)data & 3) && len) {
+ crc = (crc >> 8) ^ CRC_TABLE_CRC32[(crc & 0xff) ^ *data++];
+ len--;
+ }
+
+ while (len >= 16) {
+ len -= 16;
+ #if CRC_BIGTABLES
+ crc_n4d(crc, ((uint32_t *)data)[0], CRC_TABLE_CRC32);
+ crc_n4d(crc, ((uint32_t *)data)[1], CRC_TABLE_CRC32);
+ crc_n4d(crc, ((uint32_t *)data)[2], CRC_TABLE_CRC32);
+ crc_n4d(crc, ((uint32_t *)data)[3], CRC_TABLE_CRC32);
+ #else
+ crcsm_n4d(crc, ((uint32_t *)data)[0], CRC_TABLE_CRC32);
+ crcsm_n4d(crc, ((uint32_t *)data)[1], CRC_TABLE_CRC32);
+ crcsm_n4d(crc, ((uint32_t *)data)[2], CRC_TABLE_CRC32);
+ crcsm_n4d(crc, ((uint32_t *)data)[3], CRC_TABLE_CRC32);
+ #endif
+ data += 16;
+ }
+
+ while (len--) {
+ crc = (crc >> 8) ^ CRC_TABLE_CRC32[(crc & 0xff) ^ *data++];
+ }
+
+ //seed = crc;
+ crc ^= 0xffffffff;
+
+ return crc;
+}
+
+
diff --git a/livox_ros_driver/common/FastCRC/LICENSE.md b/livox_ros_driver/common/FastCRC/LICENSE.md
new file mode 100644
index 0000000..b7c7a98
--- /dev/null
+++ b/livox_ros_driver/common/FastCRC/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Frank
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/livox_ros_driver/common/FastCRC/README.md b/livox_ros_driver/common/FastCRC/README.md
new file mode 100644
index 0000000..97ae86c
--- /dev/null
+++ b/livox_ros_driver/common/FastCRC/README.md
@@ -0,0 +1,56 @@
+FastCRC
+=======
+
+Fast CRC Arduino library
+Up to 30 times faster than crc16.h (_avr_libc)
+
+ - uses the on-chip hardware for Teensy 3.0 / 3.1 / 3.2 / 3.5 / 3.6
+ - uses fast table-algorithms for other chips
+
+List of supported CRC calculations:
+-
+7 BIT:
+
+CRC7
+ (poly=0x09 init=0x00 refin=false refout=false xorout=0x00 check=0x75)
+ MultiMediaCard interface
+
+
+8 BIT:
+
+SMBUS
+ (poly=0x07 init=0x00 refin=false refout=false xorout=0x00 check=0xf4)
+
+MAXIM
+ (poly=0x31 init=0x00 refin=true refout=true xorout=0x00 check=0xa1)
+
+
+16 BIT:
+
+KERMIT (Alias CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-CCITT)
+ (poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189
+ Attention: sometimes you'll find byteswapped presentation of result in other implementations)
+
+CCITT-FALSE
+ (poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1)
+
+MCRF4XX
+ (poly=0x1021 init=0xffff refin=true refout=true xorout=0x0000 check=0x6f91)
+
+MODBUS
+ (poly=0x8005 init=0xffff refin=true refout=true xorout=0x0000 check=0x4b37)
+
+XMODEM (Alias ZMODEM, CRC-16/ACORN)
+ (poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x31c3)
+
+X25 (Alias CRC-16/IBM-SDLC, CRC-16/ISO-HDLC, CRC-B)
+ (poly=0x1021 init=0xffff refin=true refout=true xorout=0xffff check=0x906e)
+
+
+32 BIT:
+
+CRC32, CRC-32/ADCCP, PKZIP, ETHERNET, 802.3
+ (poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0xcbf43926)
+
+CKSUM, CRC-32/POSIX
+ (poly=0x04c11db7 init=0x00000000 refin=false refout=false xorout=0xffffffff check=0x765e7680)
diff --git a/livox_ros_driver/common/comm/comm_device.h b/livox_ros_driver/common/comm/comm_device.h
new file mode 100644
index 0000000..f64508d
--- /dev/null
+++ b/livox_ros_driver/common/comm/comm_device.h
@@ -0,0 +1,71 @@
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2019 Livox. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+
+#ifndef COMM_COMM_DEVICE_H_
+#define COMM_COMM_DEVICE_H_
+
+#include
+
+namespace livox_ros {
+
+const uint32_t kDevNameLengthMax = 256;
+
+/** Communication device type define */
+enum CommDeviceType {
+ kCommDevUart,
+ kCommDevUsb,
+ kCommDevCan,
+ kCommDevEthernet,
+ kCommDevUndef
+};
+
+/** Communication device uart config */
+struct CommDevUartConfig {
+ uint8_t baudrate;
+ uint8_t parity;
+};
+
+/** Communication device usb config */
+struct CommDevUsbConfig {
+ void* data;
+};
+
+/** Communication device can config */
+struct CommDevCanConfig {
+ void* data;
+};
+
+/** Communication device config */
+typedef struct {
+ uint8_t type;
+ char name[kDevNameLengthMax];
+ union {
+ CommDevUartConfig uart;
+ CommDevUsbConfig usb;
+ CommDevCanConfig can;
+ } config;
+} CommDevConfig;
+
+} // namespace livox
+#endif // COMM_COMM_DEVICE_H_
diff --git a/livox_ros_driver/common/comm/comm_protocol.cpp b/livox_ros_driver/common/comm/comm_protocol.cpp
new file mode 100644
index 0000000..6a82387
--- /dev/null
+++ b/livox_ros_driver/common/comm/comm_protocol.cpp
@@ -0,0 +1,224 @@
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2019 Livox. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+
+#include "comm_protocol.h"
+#include
+#include
+#include
+
+namespace livox_ros {
+
+CommProtocol::CommProtocol(ProtocolConfig& config) : config_(config) {
+ ResetParser();
+ ResetCache();
+
+ offset_to_read_index_= 0;
+ packet_length_ = 0;
+
+ if (kGps == config.type) {
+ is_length_known = false;
+ protocol_ = new GpsProtocol();
+ } else {
+ is_length_known = true;
+ protocol_ = nullptr;
+ }
+}
+
+CommProtocol::~CommProtocol() {
+ if (protocol_) {
+ delete protocol_;
+ }
+}
+
+uint8_t *CommProtocol::FetchCacheFreeSpace(uint32_t *o_len) {
+ UpdateCache();
+
+ if (cache_.wr_idx < cache_.size) {
+ *o_len = cache_.size - cache_.wr_idx;
+ return &cache_.buf[cache_.wr_idx];
+ } else {
+ *o_len = 0;
+ return nullptr;
+ }
+}
+
+int32_t CommProtocol::UpdateCacheWrIdx(uint32_t used_size) {
+ if ((cache_.wr_idx + used_size) < cache_.size) {
+ cache_.wr_idx += used_size;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+uint32_t CommProtocol::GetCacheTailSize() {
+ if (cache_.wr_idx < cache_.size) {
+ return cache_.size - cache_.wr_idx;
+ } else {
+ return 0;
+ }
+}
+
+uint32_t CommProtocol::GetValidDataSize() {
+ if (cache_.wr_idx > cache_.rd_idx) {
+ return cache_.wr_idx - cache_.rd_idx;
+ } else {
+ return 0;
+ }
+}
+
+void CommProtocol::UpdateCache(void) {
+ if (GetCacheTailSize() < kMoveCacheLimit) { /* move unused data to cache head */
+ uint32_t valid_data_size = GetValidDataSize();
+
+ if (valid_data_size) {
+ memmove(cache_.buf, &cache_.buf[cache_.rd_idx], valid_data_size);
+ cache_.rd_idx = 0;
+ cache_.wr_idx = valid_data_size;
+ } else if (cache_.rd_idx) {
+ cache_.rd_idx = 0;
+ cache_.wr_idx = 0;
+ }
+ }
+}
+
+int32_t CommProtocol::Pack(uint8_t *o_buf, uint32_t o_buf_size, uint32_t *o_len, \
+ const CommPacket &i_packet) {
+ return protocol_->Pack(o_buf, o_buf_size, o_len, i_packet);
+}
+
+void CommProtocol::ResetParser() {
+ fsm_parse_step_ = kSearchPacketPreamble;
+}
+
+int32_t CommProtocol::ParseCommStream(CommPacket *o_pack) {
+ int32_t ret = kParseFail;
+ while ((GetValidDataSize() > protocol_->GetPreambleLen()) && \
+ (GetValidDataSize() > offset_to_read_index_)) {
+ switch (fsm_parse_step_) {
+ case kSearchPacketPreamble: {
+ FsmSearchPacketPreamble();
+ break;
+ }
+ case kFindPacketLength: {
+ FsmFindPacketLength();
+ break;
+ }
+ case kGetPacketData: {
+ ret = FsmGetPacketData(o_pack);
+ break;
+ }
+ default: {
+ FsmParserStateTransfer(kSearchPacketPreamble);
+ }
+ }
+
+ if (ret == kParseNeedMoreData) break; /* */
+ }
+
+ return ret;
+}
+
+uint16_t CommProtocol::GetAndUpdateSeqNum() {
+ /* add lock here for thread safe */
+ uint16_t seq = seq_num_;
+ seq_num_++;
+
+ return seq;
+}
+
+int32_t CommProtocol::FsmSearchPacketPreamble() {
+ do {
+ if (!protocol_->CheckPreamble(GetCacheReadPos())) {
+ if (!is_length_known) {
+ offset_to_read_index_ = 0;
+ packet_length_ = 0;
+ FsmParserStateTransfer(kFindPacketLength);
+ break;
+ } else {
+ packet_length_ = protocol_->GetPacketLen(GetCacheReadPos());
+ if ((packet_length_ < cache_.size) && \
+ (packet_length_ > protocol_->GetPacketWrapperLen())) { /* check the legality of length */
+ FsmParserStateTransfer(kGetPacketData);
+ break;
+ }
+ }
+ }
+ //printf("|%2x", cache_.buf[cache_.rd_idx]);
+ ++cache_.rd_idx; /* skip one byte */
+ } while(0);
+
+ return 0;
+}
+
+int32_t CommProtocol::FsmFindPacketLength() {
+ uint32_t valid_data_size = GetValidDataSize();
+ uint32_t ret = protocol_->FindPacketLen(GetCacheReadPos(), valid_data_size);
+ if (ret == kFindLengthSuccess) {
+ packet_length_ = protocol_->GetPacketLen(GetCacheReadPos());
+ FsmParserStateTransfer(kGetPacketData);
+ offset_to_read_index_ = 0;
+ } else if (ret == kFindLengthContinue) { /* continue to find next time */
+ offset_to_read_index_ = valid_data_size;
+ } else { /* find length error */
+ offset_to_read_index_ = 0;
+ cache_.rd_idx += valid_data_size;
+ FsmParserStateTransfer(kSearchPacketPreamble);
+ printf("Continue to find length error\n");
+ }
+
+ return 0;
+}
+
+int32_t CommProtocol::FsmGetPacketData(CommPacket *o_pack) {
+ int32_t ret = kParseFail;
+ do {
+ if (GetValidDataSize() < packet_length_) {
+ ret = kParseNeedMoreData;
+ break;
+ }
+
+ if (protocol_->CheckPacket(GetCacheReadPos())) {
+ cache_.rd_idx += protocol_->GetPreambleLen();
+ FsmParserStateTransfer(kSearchPacketPreamble);
+ printf("Check packet error\n");
+ break;
+ }
+
+ if (protocol_->ParsePacket(GetCacheReadPos(), packet_length_, o_pack)) {
+ cache_.rd_idx += protocol_->GetPacketLen(GetCacheReadPos());
+ FsmParserStateTransfer(kSearchPacketPreamble);
+ printf("Parse packet error\n");
+ break;
+ }
+
+ cache_.rd_idx += protocol_->GetPacketLen(GetCacheReadPos());
+ FsmParserStateTransfer(kSearchPacketPreamble);
+ return kParseSuccess;
+ } while(0);
+
+ return ret;
+}
+
+} // namespace livox
diff --git a/livox_ros_driver/common/comm/comm_protocol.h b/livox_ros_driver/common/comm/comm_protocol.h
new file mode 100644
index 0000000..c4396c7
--- /dev/null
+++ b/livox_ros_driver/common/comm/comm_protocol.h
@@ -0,0 +1,104 @@
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2019 Livox. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+
+#ifndef COMM_COMM_PROTOCOL_H_
+#define COMM_COMM_PROTOCOL_H_
+
+#include
+#include "protocol.h"
+#include "sdk_protocol.h"
+#include "gps_protocol.h"
+
+namespace livox_ros {
+const uint32_t kCacheSize = 8192;
+const uint32_t kMoveCacheLimit = 1536;
+
+enum FsmParseState {
+ kSearchPacketPreamble = 0,
+ kFindPacketLength = 1,
+ kGetPacketData = 2,
+ kParseStepUndef
+};
+
+/** Communication data cache define */
+typedef struct {
+ uint8_t buf[kCacheSize];
+ uint32_t rd_idx;
+ uint32_t wr_idx;
+ uint32_t size;
+} CommCache;
+
+class CommProtocol {
+ public:
+ CommProtocol(ProtocolConfig& config);
+ ~CommProtocol();
+
+ int32_t Pack(uint8_t *o_buf, uint32_t o_buf_size, uint32_t *o_len, const CommPacket &i_packet);
+
+ int32_t ParseCommStream(CommPacket *o_pack);
+
+ uint8_t *FetchCacheFreeSpace(uint32_t *o_len);
+
+ int32_t UpdateCacheWrIdx(uint32_t used_size);
+
+ uint16_t GetAndUpdateSeqNum();
+
+ void ResetParser();
+
+ private:
+ uint32_t GetCacheTailSize();
+ uint32_t GetValidDataSize();
+ void UpdateCache(void);
+ uint8_t* GetCacheReadPos() { return &cache_.buf[cache_.rd_idx]; }
+ void ResetCache() {
+ cache_.wr_idx = 0;
+ cache_.rd_idx = 0;
+ cache_.size = kCacheSize;
+ }
+
+ ProtocolConfig config_;
+ Protocol* protocol_;
+ CommCache cache_;
+ uint16_t seq_num_;
+
+ bool is_length_known;
+ bool IsLengthKnown() { return is_length_known; }
+
+ volatile uint32_t offset_to_read_index_;
+ uint32_t packet_length_;
+ volatile uint32_t fsm_parse_step_;
+ int32_t FsmSearchPacketPreamble();
+ int32_t FsmFindPacketLength();
+ int32_t FsmGetPacketData(CommPacket *o_pack);
+ void FsmParserStateTransfer(uint32_t new_state) {
+ if(new_state < kParseStepUndef) {
+ fsm_parse_step_ = new_state;
+ } else {
+ fsm_parse_step_ = kSearchPacketPreamble;
+ }
+ }
+};
+
+} // namespace livox
+#endif // COMM_COMM_PROTOCOL_H_
diff --git a/livox_ros_driver/common/comm/gps_protocol.cpp b/livox_ros_driver/common/comm/gps_protocol.cpp
new file mode 100644
index 0000000..fa57c66
--- /dev/null
+++ b/livox_ros_driver/common/comm/gps_protocol.cpp
@@ -0,0 +1,130 @@
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2019 Livox. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+
+#include "gps_protocol.h"
+
+#include
+#include
+#include
+
+namespace livox_ros {
+
+const uint8_t kGpsProtocolSof = '$';
+const uint8_t kGpsProtocolEof = '*';
+const uint32_t kPacketLengthLmit = 200;
+const uint32_t kPreambleLen = 1;
+const uint32_t kWrapperLen = 4; /** '$' + '*' + '2 checksum byte' */
+
+
+GpsProtocol::GpsProtocol() {
+ found_length_ = 0;
+}
+
+int32_t GpsProtocol::Pack(uint8_t *o_buf, uint32_t o_buf_size, uint32_t *o_len, \
+ const CommPacket &i_packet) {
+ //GpsPacket* gps_packet = (GpsPacket*)o_buf;
+ return 0;
+}
+
+int32_t GpsProtocol::ParsePacket(const uint8_t *i_buf, uint32_t i_len, CommPacket *o_packet) {
+ //GpsPacket *gps_packet = (GpsPacket *)i_buf;
+
+ if (i_len < GetPacketWrapperLen()) {
+ return -1; // packet length error
+ }
+ memset((void *)o_packet, 0, sizeof(CommPacket));
+ o_packet->protocol = kGps;
+ o_packet->data = (uint8_t *)i_buf;
+ o_packet->data_len = i_len;
+
+ return 0;
+}
+
+uint32_t GpsProtocol::GetPreambleLen() {
+ return kPreambleLen; /** '$' */
+}
+
+uint32_t GpsProtocol::GetPacketWrapperLen() {
+ return kWrapperLen; /** '$' + '*' + '2 checksum bytes' */
+}
+
+uint32_t GpsProtocol::FindPacketLen(const uint8_t *buf, uint32_t buf_length) {
+ uint32_t i=0;
+ for (; (isof == kGpsProtocolSof) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int32_t GpsProtocol::CheckPacket(const uint8_t *buf) {
+ uint8_t checksum = CalcGpsPacketChecksum(&buf[1], found_length_ - kWrapperLen);
+ uint8_t raw_checksum = AscciiToHex(&buf[found_length_ - 2]);
+ if (checksum == raw_checksum) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+uint8_t GpsProtocol::CalcGpsPacketChecksum(const uint8_t *buf, uint32_t length) {
+ uint8_t result = buf[0];
+ for (uint32_t i = 1; i < length; i++) {
+ result ^= buf[i];
+ }
+ return result;
+}
+
+
+uint8_t AscciiToHex(const uint8_t *TwoChar) {
+ uint8_t h = toupper(TwoChar[0]) - 0x30;
+ if (h > 9) h -= 7;
+
+ uint8_t l = toupper(TwoChar[1]) - 0x30;
+ if (l > 9) l -= 7;
+
+ return h*16 + l;
+}
+
+}// namespace livox
diff --git a/livox_ros_driver/common/comm/gps_protocol.h b/livox_ros_driver/common/comm/gps_protocol.h
new file mode 100644
index 0000000..0506d79
--- /dev/null
+++ b/livox_ros_driver/common/comm/gps_protocol.h
@@ -0,0 +1,79 @@
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2019 Livox. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+
+#ifndef LIVOX_GPS_PROTOCOL_H_
+#define LIVOX_GPS_PROTOCOL_H_
+
+#include
+#include "protocol.h"
+
+namespace livox_ros {
+
+#pragma pack(1)
+
+typedef struct {
+ uint8_t sof;
+ uint8_t cmd_str[1];
+} GpsPreamble;
+
+typedef struct {
+ uint8_t sof;
+ uint8_t data[1];
+} GpsPacket;
+
+#pragma pack()
+
+uint8_t AscciiToHex(const uint8_t *TwoChar);
+
+class GpsProtocol : public Protocol {
+ public:
+ GpsProtocol();
+ ~GpsProtocol() = default;
+
+ int32_t ParsePacket(const uint8_t *i_buf, uint32_t i_len, CommPacket *o_packet) override;
+
+ int32_t Pack(uint8_t *o_buf, uint32_t o_buf_size, uint32_t *o_len, \
+ const CommPacket &i_packet) override;
+
+ uint32_t GetPreambleLen() override;
+
+ uint32_t GetPacketWrapperLen() override;
+
+ uint32_t FindPacketLen(const uint8_t *buf, uint32_t buf_length) override;
+
+ uint32_t GetPacketLen(const uint8_t *buf) override;
+
+ int32_t CheckPreamble(const uint8_t *buf) override;
+
+ int32_t CheckPacket(const uint8_t *buf) override;
+
+ private:
+ uint32_t found_length_;
+
+ uint8_t CalcGpsPacketChecksum(const uint8_t *buf, uint32_t length);
+
+};
+
+} // namespace livox
+#endif // LIVOX_GPS_PROTOCOL_H_
diff --git a/livox_ros_driver/common/comm/protocol.h b/livox_ros_driver/common/comm/protocol.h
new file mode 100644
index 0000000..0c914b5
--- /dev/null
+++ b/livox_ros_driver/common/comm/protocol.h
@@ -0,0 +1,106 @@
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2019 Livox. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+
+#ifndef COMM_PROTOCOL_H_
+#define COMM_PROTOCOL_H_
+
+#include
+
+namespace livox_ros {
+typedef struct CommPacket CommPacket;
+
+typedef int (*RequestPackCb)(CommPacket *packet);
+
+typedef enum { kRequestPack, kAckPack, kMsgPack } PacketType;
+
+typedef enum { kLidarSdk, kRsvd1, kGps, kProtocolUndef } ProtocolType;
+
+typedef enum { kNoNeed, kNeedAck, kDelayAck } NeedAckType;
+
+typedef enum { kParseSuccess, kParseFail, kParseNeedMoreData } ParseResult;
+
+typedef enum { kFindLengthSuccess, kFindLengthContinue, kFindLengthError } FindLengthResult;
+
+typedef struct CommPacket {
+ uint8_t packet_type;
+ uint8_t protocol;
+ uint8_t protocol_version;
+ uint8_t cmd_set;
+ uint32_t cmd_code;
+ uint32_t sender;
+ uint32_t sub_sender;
+ uint32_t receiver;
+ uint32_t sub_receiver;
+ uint32_t seq_num;
+ uint8_t *data;
+ uint16_t data_len;
+ uint32_t padding;
+ // RequestPackCb *ack_request_cb;
+ // uint32_t retry_times;
+ // uint32_t timeout;
+} CommPacket;
+
+/** SDK Protocol info config */
+typedef struct {
+ uint16_t seed16;
+ uint16_t seed32;
+} SdkProtocolConfig;
+
+/** NAME-0183 Protocol info config for gps */
+typedef struct {
+ void* data;
+} GpsProtocolConfig;
+
+typedef struct {
+ uint8_t type;
+ union {
+ SdkProtocolConfig sdk;
+ GpsProtocolConfig gps;
+ } config;
+} ProtocolConfig;
+
+class Protocol {
+ public:
+ virtual ~Protocol() = default;
+
+ virtual int32_t ParsePacket(const uint8_t *i_buf, uint32_t i_len, CommPacket *o_packet) = 0;
+
+ virtual int32_t Pack(uint8_t *o_buf, uint32_t o_buf_size, uint32_t *o_len, \
+ const CommPacket &i_packet) = 0;
+
+ virtual uint32_t GetPreambleLen() = 0;
+
+ virtual uint32_t GetPacketWrapperLen() = 0;
+
+ virtual uint32_t FindPacketLen(const uint8_t *buf, uint32_t buf_length) = 0;
+
+ virtual uint32_t GetPacketLen(const uint8_t *buf) = 0;
+
+ virtual int32_t CheckPreamble(const uint8_t *buf) = 0;
+
+ virtual int32_t CheckPacket(const uint8_t *buf) = 0;
+};
+
+} // namespace livox
+#endif // COMM_PROTOCOL_H_
diff --git a/livox_ros_driver/common/comm/sdk_protocol.cpp b/livox_ros_driver/common/comm/sdk_protocol.cpp
new file mode 100644
index 0000000..ec8242a
--- /dev/null
+++ b/livox_ros_driver/common/comm/sdk_protocol.cpp
@@ -0,0 +1,132 @@
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2019 Livox. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+
+#include "sdk_protocol.h"
+
+#include
+#include
+
+namespace livox_ros {
+const uint8_t kSdkProtocolSof = 0xAA;
+const uint32_t kSdkPacketCrcSize = 4; // crc32
+const uint32_t kSdkPacketPreambleCrcSize = 2; // crc16
+
+SdkProtocol::SdkProtocol(uint16_t seed16, uint32_t seed32) : crc16_(seed16), crc32_(seed32) {}
+
+int32_t SdkProtocol::Pack(uint8_t *o_buf, uint32_t o_buf_size, uint32_t *o_len,\
+ const CommPacket &i_packet) {
+ SdkPacket *sdk_packet = (SdkPacket *)o_buf;
+
+ if (kLidarSdk != i_packet.protocol) {
+ return -1;
+ }
+
+ sdk_packet->sof = kSdkProtocolSof;
+ sdk_packet->length = i_packet.data_len + GetPacketWrapperLen();
+
+ if (sdk_packet->length > o_buf_size) {
+ return -1;
+ }
+
+ sdk_packet->version = kSdkVer0;
+ sdk_packet->packet_type = i_packet.packet_type;
+ sdk_packet->seq_num = i_packet.seq_num & 0xFFFF;
+ sdk_packet->preamble_crc = crc16_.mcrf4xx_calc(o_buf, GetPreambleLen() - \
+ kSdkPacketPreambleCrcSize);
+ sdk_packet->cmd_set = i_packet.cmd_set;
+ sdk_packet->cmd_id = i_packet.cmd_code;
+
+ memcpy(sdk_packet->data, i_packet.data, i_packet.data_len);
+
+ uint32_t crc = crc32_.crc32_calc(o_buf, sdk_packet->length - kSdkPacketCrcSize);
+ o_buf[sdk_packet->length - 4] = crc & 0xFF;
+ o_buf[sdk_packet->length - 3] = (crc >> 8) & 0xFF;
+ o_buf[sdk_packet->length - 2] = (crc >> 16) & 0xFF;
+ o_buf[sdk_packet->length - 1] = (crc >> 24) & 0xFF;
+
+ *o_len = sdk_packet->length;
+
+ return 0;
+}
+
+int32_t SdkProtocol::ParsePacket(const uint8_t *i_buf, uint32_t i_len, CommPacket *o_packet) {
+ SdkPacket *sdk_packet = (SdkPacket *)i_buf;
+
+ if (i_len < GetPacketWrapperLen()) {
+ return -1; // packet lenth error
+ }
+
+ memset((void *)o_packet, 0, sizeof(CommPacket));
+
+ o_packet->packet_type = sdk_packet->packet_type;
+ o_packet->protocol = kLidarSdk;
+ o_packet->protocol_version = sdk_packet->version;
+
+ o_packet->seq_num = sdk_packet->seq_num;
+ o_packet->cmd_set = sdk_packet->cmd_set;
+ o_packet->cmd_code = sdk_packet->cmd_id;
+ o_packet->data_len = sdk_packet->length - GetPacketWrapperLen();
+ o_packet->data = sdk_packet->data;
+
+ return 0;
+}
+
+uint32_t SdkProtocol::GetPreambleLen() {
+ return sizeof(SdkPreamble);
+}
+
+uint32_t SdkProtocol::GetPacketWrapperLen() {
+ return sizeof(SdkPacket) - 1 + kSdkPacketCrcSize;
+}
+
+uint32_t SdkProtocol::GetPacketLen(const uint8_t *buf) {
+ SdkPreamble *preamble = (SdkPreamble *)buf;
+ return preamble->length;
+}
+
+int32_t SdkProtocol::CheckPreamble(const uint8_t *buf) {
+ SdkPreamble *preamble = (SdkPreamble *)buf;
+
+ if ((preamble->sof == kSdkProtocolSof) && (crc16_.mcrf4xx_calc(buf, GetPreambleLen()) == 0)) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int32_t SdkProtocol::CheckPacket(const uint8_t *buf) {
+ SdkPacket *sdk_packet = (SdkPacket *)buf;
+
+ uint32_t crc = ((uint32_t)(buf[sdk_packet->length - 4])) | \
+ (((uint32_t)(buf[sdk_packet->length - 3])) << 8) | \
+ (((uint32_t)(buf[sdk_packet->length - 2])) << 16) | \
+ (((uint32_t)(buf[sdk_packet->length - 1])) << 24);
+
+ if (crc32_.crc32_calc(buf, sdk_packet->length - kSdkPacketCrcSize) == crc) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+}// namespace livox
diff --git a/livox_ros_driver/common/comm/sdk_protocol.h b/livox_ros_driver/common/comm/sdk_protocol.h
new file mode 100644
index 0000000..e6f5b06
--- /dev/null
+++ b/livox_ros_driver/common/comm/sdk_protocol.h
@@ -0,0 +1,85 @@
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2019 Livox. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+
+#ifndef LIVOX_SDK_PROTOCOL_H_
+#define LIVOX_SDK_PROTOCOL_H_
+
+#include
+#include "protocol.h"
+#include "FastCRC/FastCRC.h"
+
+namespace livox_ros {
+typedef enum { kSdkVerNone, kSdkVer0, kSdkVer1 } SdkVersion;
+
+#pragma pack(1)
+
+typedef struct {
+ uint8_t sof;
+ uint8_t version;
+ uint16_t length;
+ uint8_t packet_type;
+ uint16_t seq_num;
+ uint16_t preamble_crc;
+} SdkPreamble;
+
+typedef struct {
+ uint8_t sof;
+ uint8_t version;
+ uint16_t length;
+ uint8_t packet_type;
+ uint16_t seq_num;
+ uint16_t preamble_crc;
+ uint8_t cmd_set;
+ uint8_t cmd_id;
+ uint8_t data[1];
+} SdkPacket;
+
+#pragma pack()
+
+class SdkProtocol : public Protocol {
+ public:
+ SdkProtocol(uint16_t seed16, uint32_t seed32);
+ ~SdkProtocol() = default;
+
+ int32_t ParsePacket(const uint8_t *i_buf, uint32_t i_len, CommPacket *o_packet) override;
+
+ int32_t Pack(uint8_t *o_buf, uint32_t o_buf_size, uint32_t *o_len, \
+ const CommPacket &i_packet) override;
+
+ uint32_t GetPreambleLen() override;
+
+ uint32_t GetPacketWrapperLen() override;
+
+ uint32_t GetPacketLen(const uint8_t *buf) override;
+
+ int32_t CheckPreamble(const uint8_t *buf) override;
+
+ int32_t CheckPacket(const uint8_t *buf) override;
+
+ private:
+ FastCRC16 crc16_;
+ FastCRC32 crc32_;
+};
+} // namespace livox
+#endif // LIVOX_SDK_PROTOCOL_H_
diff --git a/livox_ros_driver/common/rapidjson/allocators.h b/livox_ros_driver/common/rapidjson/allocators.h
new file mode 100644
index 0000000..cc67c89
--- /dev/null
+++ b/livox_ros_driver/common/rapidjson/allocators.h
@@ -0,0 +1,284 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ALLOCATORS_H_
+#define RAPIDJSON_ALLOCATORS_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Allocator
+
+/*! \class rapidjson::Allocator
+ \brief Concept for allocating, resizing and freeing memory block.
+
+ Note that Malloc() and Realloc() are non-static but Free() is static.
+
+ So if an allocator need to support Free(), it needs to put its pointer in
+ the header of memory block.
+
+\code
+concept Allocator {
+ static const bool kNeedFree; //!< Whether this allocator needs to call Free().
+
+ // Allocate a memory block.
+ // \param size of the memory block in bytes.
+ // \returns pointer to the memory block.
+ void* Malloc(size_t size);
+
+ // Resize a memory block.
+ // \param originalPtr The pointer to current memory block. Null pointer is permitted.
+ // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
+ // \param newSize the new size in bytes.
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+ // Free a memory block.
+ // \param pointer to the memory block. Null pointer is permitted.
+ static void Free(void *ptr);
+};
+\endcode
+*/
+
+
+/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-defined kDefaultChunkCapacity definition.
+
+ User can define this as any \c size that is a power of 2.
+*/
+
+#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
+#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CrtAllocator
+
+//! C-runtime library allocator.
+/*! This class is just wrapper for standard C library memory routines.
+ \note implements Allocator concept
+*/
+class CrtAllocator {
+public:
+ static const bool kNeedFree = true;
+ void* Malloc(size_t size) {
+ if (size) // behavior of malloc(0) is implementation defined.
+ return std::malloc(size);
+ else
+ return NULL; // standardize to returning NULL.
+ }
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+ (void)originalSize;
+ if (newSize == 0) {
+ std::free(originalPtr);
+ return NULL;
+ }
+ return std::realloc(originalPtr, newSize);
+ }
+ static void Free(void *ptr) { std::free(ptr); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryPoolAllocator
+
+//! Default memory allocator used by the parser and DOM.
+/*! This allocator allocate memory blocks from pre-allocated memory chunks.
+
+ It does not free memory blocks. And Realloc() only allocate new memory.
+
+ The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
+
+ User may also supply a buffer as the first chunk.
+
+ If the user-buffer is full then additional chunks are allocated by BaseAllocator.
+
+ The user-buffer is not deallocated by this allocator.
+
+ \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
+ \note implements Allocator concept
+*/
+template
+class MemoryPoolAllocator {
+public:
+ static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+
+ //! Constructor with chunkSize.
+ /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ }
+
+ //! Constructor with user-supplied buffer.
+ /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
+
+ The user buffer will not be deallocated when this allocator is destructed.
+
+ \param buffer User supplied buffer.
+ \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
+ \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ RAPIDJSON_ASSERT(buffer != 0);
+ RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
+ chunkHead_ = reinterpret_cast(buffer);
+ chunkHead_->capacity = size - sizeof(ChunkHeader);
+ chunkHead_->size = 0;
+ chunkHead_->next = 0;
+ }
+
+ //! Destructor.
+ /*! This deallocates all memory chunks, excluding the user-supplied buffer.
+ */
+ ~MemoryPoolAllocator() {
+ Clear();
+ RAPIDJSON_DELETE(ownBaseAllocator_);
+ }
+
+ //! Deallocates all memory chunks, excluding the user-supplied buffer.
+ void Clear() {
+ while (chunkHead_ && chunkHead_ != userBuffer_) {
+ ChunkHeader* next = chunkHead_->next;
+ baseAllocator_->Free(chunkHead_);
+ chunkHead_ = next;
+ }
+ if (chunkHead_ && chunkHead_ == userBuffer_)
+ chunkHead_->size = 0; // Clear user buffer
+ }
+
+ //! Computes the total capacity of allocated memory chunks.
+ /*! \return total capacity in bytes.
+ */
+ size_t Capacity() const {
+ size_t capacity = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ capacity += c->capacity;
+ return capacity;
+ }
+
+ //! Computes the memory blocks allocated.
+ /*! \return total used bytes.
+ */
+ size_t Size() const {
+ size_t size = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ size += c->size;
+ return size;
+ }
+
+ //! Allocates a memory block. (concept Allocator)
+ void* Malloc(size_t size) {
+ if (!size)
+ return NULL;
+
+ size = RAPIDJSON_ALIGN(size);
+ if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
+ if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
+ return NULL;
+
+ void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
+ chunkHead_->size += size;
+ return buffer;
+ }
+
+ //! Resizes a memory block (concept Allocator)
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+ if (originalPtr == 0)
+ return Malloc(newSize);
+
+ if (newSize == 0)
+ return NULL;
+
+ originalSize = RAPIDJSON_ALIGN(originalSize);
+ newSize = RAPIDJSON_ALIGN(newSize);
+
+ // Do not shrink if new size is smaller than original
+ if (originalSize >= newSize)
+ return originalPtr;
+
+ // Simply expand it if it is the last allocation and there is sufficient space
+ if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
+ size_t increment = static_cast(newSize - originalSize);
+ if (chunkHead_->size + increment <= chunkHead_->capacity) {
+ chunkHead_->size += increment;
+ return originalPtr;
+ }
+ }
+
+ // Realloc process: allocate and copy memory, do not free original buffer.
+ if (void* newBuffer = Malloc(newSize)) {
+ if (originalSize)
+ std::memcpy(newBuffer, originalPtr, originalSize);
+ return newBuffer;
+ }
+ else
+ return NULL;
+ }
+
+ //! Frees a memory block (concept Allocator)
+ static void Free(void *ptr) { (void)ptr; } // Do nothing
+
+private:
+ //! Copy constructor is not permitted.
+ MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
+ //! Copy assignment operator is not permitted.
+ MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
+
+ //! Creates a new chunk.
+ /*! \param capacity Capacity of the chunk in bytes.
+ \return true if success.
+ */
+ bool AddChunk(size_t capacity) {
+ if (!baseAllocator_)
+ ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
+ if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
+ chunk->capacity = capacity;
+ chunk->size = 0;
+ chunk->next = chunkHead_;
+ chunkHead_ = chunk;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
+
+ //! Chunk header for perpending to each chunk.
+ /*! Chunks are stored as a singly linked list.
+ */
+ struct ChunkHeader {
+ size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
+ size_t size; //!< Current size of allocated memory in bytes.
+ ChunkHeader *next; //!< Next chunk in the linked list.
+ };
+
+ ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+ size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
+ void *userBuffer_; //!< User supplied buffer.
+ BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
+ BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ENCODINGS_H_
diff --git a/livox_ros_driver/common/rapidjson/cursorstreamwrapper.h b/livox_ros_driver/common/rapidjson/cursorstreamwrapper.h
new file mode 100644
index 0000000..52c11a7
--- /dev/null
+++ b/livox_ros_driver/common/rapidjson/cursorstreamwrapper.h
@@ -0,0 +1,78 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_
+#define RAPIDJSON_CURSORSTREAMWRAPPER_H_
+
+#include "stream.h"
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+
+//! Cursor stream wrapper for counting line and column number if error exists.
+/*!
+ \tparam InputStream Any stream that implements Stream Concept
+*/
+template >
+class CursorStreamWrapper : public GenericStreamWrapper {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ CursorStreamWrapper(InputStream& is):
+ GenericStreamWrapper(is), line_(1), col_(0) {}
+
+ // counting line and column number
+ Ch Take() {
+ Ch ch = this->is_.Take();
+ if(ch == '\n') {
+ line_ ++;
+ col_ = 0;
+ } else {
+ col_ ++;
+ }
+ return ch;
+ }
+
+ //! Get the error line number, if error exists.
+ size_t GetLine() const { return line_; }
+ //! Get the error column number, if error exists.
+ size_t GetColumn() const { return col_; }
+
+private:
+ size_t line_; //!< Current Line
+ size_t col_; //!< Current Column
+};
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_POP
+#endif
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_
diff --git a/livox_ros_driver/common/rapidjson/document.h b/livox_ros_driver/common/rapidjson/document.h
new file mode 100644
index 0000000..f070234
--- /dev/null
+++ b/livox_ros_driver/common/rapidjson/document.h
@@ -0,0 +1,2682 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_DOCUMENT_H_
+#define RAPIDJSON_DOCUMENT_H_
+
+/*! \file document.h */
+
+#include "reader.h"
+#include "internal/meta.h"
+#include "internal/strfunc.h"
+#include "memorystream.h"
+#include "encodedstream.h"
+#include // placement new
+#include
+
+RAPIDJSON_DIAG_PUSH
+#ifdef __clang__
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_OFF(effc++)
+#endif // __GNUC__
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+#include // std::random_access_iterator_tag
+#endif
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include // std::move
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+// Forward declaration.
+template
+class GenericValue;
+
+template
+class GenericDocument;
+
+//! Name-value pair in a JSON object value.
+/*!
+ This class was internal to GenericValue. It used to be a inner struct.
+ But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
+ https://code.google.com/p/rapidjson/issues/detail?id=64
+*/
+template
+class GenericMember {
+public:
+ GenericValue name; //!< name of member (must be a string)
+ GenericValue value; //!< value of member.
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericMember(GenericMember&& rhs) RAPIDJSON_NOEXCEPT
+ : name(std::move(rhs.name)),
+ value(std::move(rhs.value))
+ {
+ }
+
+ //! Move assignment in C++11
+ GenericMember& operator=(GenericMember&& rhs) RAPIDJSON_NOEXCEPT {
+ return *this = static_cast(rhs);
+ }
+#endif
+
+ //! Assignment with move semantics.
+ /*! \param rhs Source of the assignment. Its name and value will become a null value after assignment.
+ */
+ GenericMember& operator=(GenericMember& rhs) RAPIDJSON_NOEXCEPT {
+ if (RAPIDJSON_LIKELY(this != &rhs)) {
+ name = rhs.name;
+ value = rhs.value;
+ }
+ return *this;
+ }
+
+ // swap() for std::sort() and other potential use in STL.
+ friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT {
+ a.name.Swap(b.name);
+ a.value.Swap(b.value);
+ }
+
+private:
+ //! Copy constructor is not permitted.
+ GenericMember(const GenericMember& rhs);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericMemberIterator
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+
+//! (Constant) member iterator for a JSON object value
+/*!
+ \tparam Const Is this a constant iterator?
+ \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
+ \tparam Allocator Allocator type for allocating memory of object, array and string.
+
+ This class implements a Random Access Iterator for GenericMember elements
+ of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].
+
+ \note This iterator implementation is mainly intended to avoid implicit
+ conversions from iterator values to \c NULL,
+ e.g. from GenericValue::FindMember.
+
+ \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
+ pointer-based implementation, if your platform doesn't provide
+ the C++ header.
+
+ \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
+ */
+template
+class GenericMemberIterator {
+
+ friend class GenericValue;
+ template friend class GenericMemberIterator;
+
+ typedef GenericMember PlainType;
+ typedef typename internal::MaybeAddConst::Type ValueType;
+
+public:
+ //! Iterator type itself
+ typedef GenericMemberIterator Iterator;
+ //! Constant iterator type
+ typedef GenericMemberIterator ConstIterator;
+ //! Non-constant iterator type
+ typedef GenericMemberIterator NonConstIterator;
+
+ /** \name std::iterator_traits support */
+ //@{
+ typedef ValueType value_type;
+ typedef ValueType * pointer;
+ typedef ValueType & reference;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ //@}
+
+ //! Pointer to (const) GenericMember
+ typedef pointer Pointer;
+ //! Reference to (const) GenericMember
+ typedef reference Reference;
+ //! Signed integer type (e.g. \c ptrdiff_t)
+ typedef difference_type DifferenceType;
+
+ //! Default constructor (singular value)
+ /*! Creates an iterator pointing to no element.
+ \note All operations, except for comparisons, are undefined on such values.
+ */
+ GenericMemberIterator() : ptr_() {}
+
+ //! Iterator conversions to more const
+ /*!
+ \param it (Non-const) iterator to copy from
+
+ Allows the creation of an iterator from another GenericMemberIterator
+ that is "less const". Especially, creating a non-constant iterator
+ from a constant iterator are disabled:
+ \li const -> non-const (not ok)
+ \li const -> const (ok)
+ \li non-const -> const (ok)
+ \li non-const -> non-const (ok)
+
+ \note If the \c Const template parameter is already \c false, this
+ constructor effectively defines a regular copy-constructor.
+ Otherwise, the copy constructor is implicitly defined.
+ */
+ GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
+ Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; }
+
+ //! @name stepping
+ //@{
+ Iterator& operator++(){ ++ptr_; return *this; }
+ Iterator& operator--(){ --ptr_; return *this; }
+ Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; }
+ Iterator operator--(int){ Iterator old(*this); --ptr_; return old; }
+ //@}
+
+ //! @name increment/decrement
+ //@{
+ Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }
+ Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }
+
+ Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }
+ Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }
+ //@}
+
+ //! @name relations
+ //@{
+ bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
+ bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
+ bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
+ bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
+ bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }
+ bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }
+ //@}
+
+ //! @name dereference
+ //@{
+ Reference operator*() const { return *ptr_; }
+ Pointer operator->() const { return ptr_; }
+ Reference operator[](DifferenceType n) const { return ptr_[n]; }
+ //@}
+
+ //! Distance
+ DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }
+
+private:
+ //! Internal constructor from plain pointer
+ explicit GenericMemberIterator(Pointer p) : ptr_(p) {}
+
+ Pointer ptr_; //!< raw pointer
+};
+
+#else // RAPIDJSON_NOMEMBERITERATORCLASS
+
+// class-based member iterator implementation disabled, use plain pointers
+
+template
+class GenericMemberIterator;
+
+//! non-const GenericMemberIterator
+template
+class GenericMemberIterator {
+ //! use plain pointer as iterator type
+ typedef GenericMember* Iterator;
+};
+//! const GenericMemberIterator
+template
+class GenericMemberIterator {
+ //! use plain const pointer as iterator type
+ typedef const GenericMember* Iterator;
+};
+
+#endif // RAPIDJSON_NOMEMBERITERATORCLASS
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericStringRef
+
+//! Reference to a constant string (not taking a copy)
+/*!
+ \tparam CharType character type of the string
+
+ This helper class is used to automatically infer constant string
+ references for string literals, especially from \c const \b (!)
+ character arrays.
+
+ The main use is for creating JSON string values without copying the
+ source string via an \ref Allocator. This requires that the referenced
+ string pointers have a sufficient lifetime, which exceeds the lifetime
+ of the associated GenericValue.
+
+ \b Example
+ \code
+ Value v("foo"); // ok, no need to copy & calculate length
+ const char foo[] = "foo";
+ v.SetString(foo); // ok
+
+ const char* bar = foo;
+ // Value x(bar); // not ok, can't rely on bar's lifetime
+ Value x(StringRef(bar)); // lifetime explicitly guaranteed by user
+ Value y(StringRef(bar, 3)); // ok, explicitly pass length
+ \endcode
+
+ \see StringRef, GenericValue::SetString
+*/
+template
+struct GenericStringRef {
+ typedef CharType Ch; //!< character type of the string
+
+ //! Create string reference from \c const character array
+#ifndef __clang__ // -Wdocumentation
+ /*!
+ This constructor implicitly creates a constant string reference from
+ a \c const character array. It has better performance than
+ \ref StringRef(const CharType*) by inferring the string \ref length
+ from the array length, and also supports strings containing null
+ characters.
+
+ \tparam N length of the string, automatically inferred
+
+ \param str Constant character array, lifetime assumed to be longer
+ than the use of the string in e.g. a GenericValue
+
+ \post \ref s == str
+
+ \note Constant complexity.
+ \note There is a hidden, private overload to disallow references to
+ non-const character arrays to be created via this constructor.
+ By this, e.g. function-scope arrays used to be filled via
+ \c snprintf are excluded from consideration.
+ In such cases, the referenced string should be \b copied to the
+ GenericValue instead.
+ */
+#endif
+ template
+ GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
+ : s(str), length(N-1) {}
+
+ //! Explicitly create string reference from \c const character pointer
+#ifndef __clang__ // -Wdocumentation
+ /*!
+ This constructor can be used to \b explicitly create a reference to
+ a constant string pointer.
+
+ \see StringRef(const CharType*)
+
+ \param str Constant character pointer, lifetime assumed to be longer
+ than the use of the string in e.g. a GenericValue
+
+ \post \ref s == str
+
+ \note There is a hidden, private overload to disallow references to
+ non-const character arrays to be created via this constructor.
+ By this, e.g. function-scope arrays used to be filled via
+ \c snprintf are excluded from consideration.
+ In such cases, the referenced string should be \b copied to the
+ GenericValue instead.
+ */
+#endif
+ explicit GenericStringRef(const CharType* str)
+ : s(str), length(NotNullStrLen(str)) {}
+
+ //! Create constant string reference from pointer and length
+#ifndef __clang__ // -Wdocumentation
+ /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \param len length of the string, excluding the trailing NULL terminator
+
+ \post \ref s == str && \ref length == len
+ \note Constant complexity.
+ */
+#endif
+ GenericStringRef(const CharType* str, SizeType len)
+ : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); }
+
+ GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
+
+ //! implicit conversion to plain CharType pointer
+ operator const Ch *() const { return s; }
+
+ const Ch* const s; //!< plain CharType pointer
+ const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
+
+private:
+ SizeType NotNullStrLen(const CharType* str) {
+ RAPIDJSON_ASSERT(str != 0);
+ return internal::StrLen(str);
+ }
+
+ /// Empty string - used when passing in a NULL pointer
+ static const Ch emptyString[];
+
+ //! Disallow construction from non-const array
+ template
+ GenericStringRef(CharType (&str)[N]) /* = delete */;
+ //! Copy assignment operator not permitted - immutable type
+ GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */;
+};
+
+template
+const CharType GenericStringRef::emptyString[] = { CharType() };
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal". This function
+ can be used to avoid copying a character string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+ \tparam CharType Character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+
+ \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember
+*/
+template
+inline GenericStringRef StringRef(const CharType* str) {
+ return GenericStringRef(str);
+}
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal". This function
+ can be used to avoid copying a character string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+
+ This version has better performance with supplied length, and also
+ supports string containing null characters.
+
+ \tparam CharType character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \param length The length of source string.
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+*/
+template
+inline GenericStringRef StringRef(const CharType* str, size_t length) {
+ return GenericStringRef(str, SizeType(length));
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+//! Mark a string object as constant string
+/*! Mark a string object (e.g. \c std::string) as a "string literal".
+ This function can be used to avoid copying a string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+
+ \tparam CharType character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+ \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+*/
+template
+inline GenericStringRef StringRef(const std::basic_string& str) {
+ return GenericStringRef(str.data(), SizeType(str.size()));
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue type traits
+namespace internal {
+
+template
+struct IsGenericValueImpl : FalseType {};
+
+// select candidates according to nested encoding and allocator types
+template struct IsGenericValueImpl::Type, typename Void::Type>
+ : IsBaseOf, T>::Type {};
+
+// helper to match arbitrary GenericValue instantiations, including derived classes
+template struct IsGenericValue : IsGenericValueImpl::Type {};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// TypeHelper
+
+namespace internal {
+
+template
+struct TypeHelper {};
+
+template
+struct TypeHelper {
+ static bool Is(const ValueType& v) { return v.IsBool(); }
+ static bool Get(const ValueType& v) { return v.GetBool(); }
+ static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); }
+ static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); }
+};
+
+template
+struct TypeHelper {
+ static bool Is(const ValueType& v) { return v.IsInt(); }
+ static int Get(const ValueType& v) { return v.GetInt(); }
+ static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); }
+ static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
+};
+
+template
+struct TypeHelper {
+ static bool Is(const ValueType& v) { return v.IsUint(); }
+ static unsigned Get(const ValueType& v) { return v.GetUint(); }
+ static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); }
+ static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
+};
+
+#ifdef _MSC_VER
+RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int));
+template
+struct TypeHelper {
+ static bool Is(const ValueType& v) { return v.IsInt(); }
+ static long Get(const ValueType& v) { return v.GetInt(); }
+ static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); }
+ static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
+};
+
+RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned));
+template
+struct TypeHelper {
+ static bool Is(const ValueType& v) { return v.IsUint(); }
+ static unsigned long Get(const ValueType& v) { return v.GetUint(); }
+ static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); }
+ static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
+};
+#endif
+
+template
+struct TypeHelper {
+ static bool Is(const ValueType& v) { return v.IsInt64(); }
+ static int64_t Get(const ValueType& v) { return v.GetInt64(); }
+ static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); }
+ static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); }
+};
+
+template
+struct TypeHelper {
+ static bool Is(const ValueType& v) { return v.IsUint64(); }
+ static uint64_t Get(const ValueType& v) { return v.GetUint64(); }
+ static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); }
+ static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); }
+};
+
+template
+struct TypeHelper {
+ static bool Is(const ValueType& v) { return v.IsDouble(); }
+ static double Get(const ValueType& v) { return v.GetDouble(); }
+ static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); }
+ static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); }
+};
+
+template
+struct TypeHelper {
+ static bool Is(const ValueType& v) { return v.IsFloat(); }
+ static float Get(const ValueType& v) { return v.GetFloat(); }
+ static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); }
+ static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); }
+};
+
+template
+struct TypeHelper {
+ typedef const typename ValueType::Ch* StringType;
+ static bool Is(const ValueType& v) { return v.IsString(); }
+ static StringType Get(const ValueType& v) { return v.GetString(); }
+ static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); }
+ static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
+};
+
+#if RAPIDJSON_HAS_STDSTRING
+template
+struct TypeHelper > {
+ typedef std::basic_string StringType;
+ static bool Is(const ValueType& v) { return v.IsString(); }
+ static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); }
+ static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
+};
+#endif
+
+template
+struct TypeHelper {
+ typedef typename ValueType::Array ArrayType;
+ static bool Is(const ValueType& v) { return v.IsArray(); }
+ static ArrayType Get(ValueType& v) { return v.GetArray(); }
+ static ValueType& Set(ValueType& v, ArrayType data) { return v = data; }
+ static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; }
+};
+
+template
+struct TypeHelper {
+ typedef typename ValueType::ConstArray ArrayType;
+ static bool Is(const ValueType& v) { return v.IsArray(); }
+ static ArrayType Get(const ValueType& v) { return v.GetArray(); }
+};
+
+template
+struct TypeHelper {
+ typedef typename ValueType::Object ObjectType;
+ static bool Is(const ValueType& v) { return v.IsObject(); }
+ static ObjectType Get(ValueType& v) { return v.GetObject(); }
+ static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }
+ static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; }
+};
+
+template
+struct TypeHelper {
+ typedef typename ValueType::ConstObject ObjectType;
+ static bool Is(const ValueType& v) { return v.IsObject(); }
+ static ObjectType Get(const ValueType& v) { return v.GetObject(); }
+};
+
+} // namespace internal
+
+// Forward declarations
+template class GenericArray;
+template class GenericObject;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue
+
+//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
+/*!
+ A JSON value can be one of 7 types. This class is a variant type supporting
+ these types.
+
+ Use the Value if UTF8 and default allocator
+
+ \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
+ \tparam Allocator Allocator type for allocating memory of object, array and string.
+*/
+template >
+class GenericValue {
+public:
+ //! Name-value pair in an object.
+ typedef GenericMember Member;
+ typedef Encoding EncodingType; //!< Encoding type from template parameter.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericStringRef StringRefType; //!< Reference to a constant string
+ typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object.
+ typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object.
+ typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
+ typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
+ typedef GenericValue ValueType; //!< Value type of itself.
+ typedef GenericArray Array;
+ typedef GenericArray ConstArray;
+ typedef GenericObject Object;
+ typedef GenericObject ConstObject;
+
+ //!@name Constructors and destructor.
+ //@{
+
+ //! Default constructor creates a null value.
+ GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) {
+ rhs.data_.f.flags = kNullFlag; // give up contents
+ }
+#endif
+
+private:
+ //! Copy constructor is not permitted.
+ GenericValue(const GenericValue& rhs);
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Moving from a GenericDocument is not permitted.
+ template
+ GenericValue(GenericDocument&& rhs);
+
+ //! Move assignment from a GenericDocument is not permitted.
+ template
+ GenericValue& operator=(GenericDocument&& rhs);
+#endif
+
+public:
+
+ //! Constructor with JSON value type.
+ /*! This creates a Value of specified type with default content.
+ \param type Type of the value.
+ \note Default content for number is zero.
+ */
+ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
+ static const uint16_t defaultFlags[] = {
+ kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
+ kNumberAnyFlag
+ };
+ RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType);
+ data_.f.flags = defaultFlags[type];
+
+ // Use ShortString to store empty string.
+ if (type == kStringType)
+ data_.ss.SetLength(0);
+ }
+
+ //! Explicit copy constructor (with allocator)
+ /*! Creates a copy of a Value by using the given Allocator
+ \tparam SourceAllocator allocator of \c rhs
+ \param rhs Value to copy from (read-only)
+ \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
+ \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)
+ \see CopyFrom()
+ */
+ template
+ GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) {
+ switch (rhs.GetType()) {
+ case kObjectType: {
+ SizeType count = rhs.data_.o.size;
+ Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member)));
+ const typename GenericValue::Member* rm = rhs.GetMembersPointer();
+ for (SizeType i = 0; i < count; i++) {
+ new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
+ new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
+ }
+ data_.f.flags = kObjectFlag;
+ data_.o.size = data_.o.capacity = count;
+ SetMembersPointer(lm);
+ }
+ break;
+ case kArrayType: {
+ SizeType count = rhs.data_.a.size;
+ GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue)));
+ const GenericValue* re = rhs.GetElementsPointer();
+ for (SizeType i = 0; i < count; i++)
+ new (&le[i]) GenericValue(re[i], allocator, copyConstStrings);
+ data_.f.flags = kArrayFlag;
+ data_.a.size = data_.a.capacity = count;
+ SetElementsPointer(le);
+ }
+ break;
+ case kStringType:
+ if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) {
+ data_.f.flags = rhs.data_.f.flags;
+ data_ = *reinterpret_cast(&rhs.data_);
+ }
+ else
+ SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
+ break;
+ default:
+ data_.f.flags = rhs.data_.f.flags;
+ data_ = *reinterpret_cast(&rhs.data_);
+ break;
+ }
+ }
+
+ //! Constructor for boolean value.
+ /*! \param b Boolean value
+ \note This constructor is limited to \em real boolean values and rejects
+ implicitly converted types like arbitrary pointers. Use an explicit cast
+ to \c bool, if you want to construct a boolean JSON value in such cases.
+ */
+#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
+ template
+ explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT // See #472
+#else
+ explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
+#endif
+ : data_() {
+ // safe-guard against failing SFINAE
+ RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value));
+ data_.f.flags = b ? kTrueFlag : kFalseFlag;
+ }
+
+ //! Constructor for int value.
+ explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.i64 = i;
+ data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag;
+ }
+
+ //! Constructor for unsigned value.
+ explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.u64 = u;
+ data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag);
+ }
+
+ //! Constructor for int64_t value.
+ explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.i64 = i64;
+ data_.f.flags = kNumberInt64Flag;
+ if (i64 >= 0) {
+ data_.f.flags |= kNumberUint64Flag;
+ if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+ data_.f.flags |= kUintFlag;
+ if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ data_.f.flags |= kIntFlag;
+ }
+ else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ data_.f.flags |= kIntFlag;
+ }
+
+ //! Constructor for uint64_t value.
+ explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.u64 = u64;
+ data_.f.flags = kNumberUint64Flag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
+ data_.f.flags |= kInt64Flag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+ data_.f.flags |= kUintFlag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ data_.f.flags |= kIntFlag;
+ }
+
+ //! Constructor for double value.
+ explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }
+
+ //! Constructor for float value.
+ explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast(f); data_.f.flags = kNumberDoubleFlag; }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Constructor for copy-string from a string object (i.e. do make a copy of string)
+ /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
+#endif
+
+ //! Constructor for Array.
+ /*!
+ \param a An array obtained by \c GetArray().
+ \note \c Array is always pass-by-value.
+ \note the source array is moved into this value and the sourec array becomes empty.
+ */
+ GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) {
+ a.value_.data_ = Data();
+ a.value_.data_.f.flags = kArrayFlag;
+ }
+
+ //! Constructor for Object.
+ /*!
+ \param o An object obtained by \c GetObject().
+ \note \c Object is always pass-by-value.
+ \note the source object is moved into this value and the sourec object becomes empty.
+ */
+ GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) {
+ o.value_.data_ = Data();
+ o.value_.data_.f.flags = kObjectFlag;
+ }
+
+ //! Destructor.
+ /*! Need to destruct elements of array, members of object, or copy-string.
+ */
+ ~GenericValue() {
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ switch(data_.f.flags) {
+ case kArrayFlag:
+ {
+ GenericValue* e = GetElementsPointer();
+ for (GenericValue* v = e; v != e + data_.a.size; ++v)
+ v->~GenericValue();
+ Allocator::Free(e);
+ }
+ break;
+
+ case kObjectFlag:
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ Allocator::Free(GetMembersPointer());
+ break;
+
+ case kCopyStringFlag:
+ Allocator::Free(const_cast(GetStringPointer()));
+ break;
+
+ default:
+ break; // Do nothing for other types.
+ }
+ }
+ }
+
+ //@}
+
+ //!@name Assignment operators
+ //@{
+
+ //! Assignment with move semantics.
+ /*! \param rhs Source of the assignment. It will become a null value after assignment.
+ */
+ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+ if (RAPIDJSON_LIKELY(this != &rhs)) {
+ this->~GenericValue();
+ RawAssign(rhs);
+ }
+ return *this;
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move assignment in C++11
+ GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {
+ return *this = rhs.Move();
+ }
+#endif
+
+ //! Assignment of constant string reference (no copy)
+ /*! \param str Constant string reference to be assigned
+ \note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
+ \see GenericStringRef, operator=(T)
+ */
+ GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {
+ GenericValue s(str);
+ return *this = s;
+ }
+
+ //! Assignment with primitive types.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param value The value to be assigned.
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref SetString(const Ch*, Allocator&) (for copying) or
+ \ref StringRef() (to explicitly mark the pointer as constant) instead.
+ All other pointer types would implicitly convert to \c bool,
+ use \ref SetBool() instead.
+ */
+ template
+ RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&))
+ operator=(T value) {
+ GenericValue v(value);
+ return *this = v;
+ }
+
+ //! Deep-copy assignment from Value
+ /*! Assigns a \b copy of the Value to the current Value object
+ \tparam SourceAllocator Allocator type of \c rhs
+ \param rhs Value to copy from (read-only)
+ \param allocator Allocator to use for copying
+ \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)
+ */
+ template
+ GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) {
+ RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs));
+ this->~GenericValue();
+ new (this) GenericValue(rhs, allocator, copyConstStrings);
+ return *this;
+ }
+
+ //! Exchange the contents of this value with those of other.
+ /*!
+ \param other Another value.
+ \note Constant complexity.
+ */
+ GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
+ GenericValue temp;
+ temp.RawAssign(*this);
+ RawAssign(other);
+ other.RawAssign(temp);
+ return *this;
+ }
+
+ //! free-standing swap function helper
+ /*!
+ Helper function to enable support for common swap implementation pattern based on \c std::swap:
+ \code
+ void swap(MyClass& a, MyClass& b) {
+ using std::swap;
+ swap(a.value, b.value);
+ // ...
+ }
+ \endcode
+ \see Swap()
+ */
+ friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
+
+ //! Prepare Value for move semantics
+ /*! \return *this */
+ GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
+ //@}
+
+ //!@name Equal-to and not-equal-to operators
+ //@{
+ //! Equal-to operator
+ /*!
+ \note If an object contains duplicated named member, comparing equality with any object is always \c false.
+ \note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings).
+ */
+ template
+ bool operator==(const GenericValue& rhs) const {
+ typedef GenericValue RhsType;
+ if (GetType() != rhs.GetType())
+ return false;
+
+ switch (GetType()) {
+ case kObjectType: // Warning: O(n^2) inner-loop
+ if (data_.o.size != rhs.data_.o.size)
+ return false;
+ for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
+ typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
+ if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
+ return false;
+ }
+ return true;
+
+ case kArrayType:
+ if (data_.a.size != rhs.data_.a.size)
+ return false;
+ for (SizeType i = 0; i < data_.a.size; i++)
+ if ((*this)[i] != rhs[i])
+ return false;
+ return true;
+
+ case kStringType:
+ return StringEqual(rhs);
+
+ case kNumberType:
+ if (IsDouble() || rhs.IsDouble()) {
+ double a = GetDouble(); // May convert from integer to double.
+ double b = rhs.GetDouble(); // Ditto
+ return a >= b && a <= b; // Prevent -Wfloat-equal
+ }
+ else
+ return data_.n.u64 == rhs.data_.n.u64;
+
+ default:
+ return true;
+ }
+ }
+
+ //! Equal-to operator with const C-string pointer
+ bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Equal-to operator with string object
+ /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); }
+#endif
+
+ //! Equal-to operator with primitive types
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
+ */
+ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
+
+ //! Not-equal-to operator
+ /*! \return !(*this == rhs)
+ */
+ template
+ bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); }
+
+ //! Not-equal-to operator with const C-string pointer
+ bool operator!=(const Ch* rhs) const { return !(*this == rhs); }
+
+ //! Not-equal-to operator with arbitrary types
+ /*! \return !(*this == rhs)
+ */
+ template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
+
+ //! Equal-to operator with arbitrary types (symmetric version)
+ /*! \return (rhs == lhs)
+ */
+ template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
+
+ //! Not-Equal-to operator with arbitrary types (symmetric version)
+ /*! \return !(rhs == lhs)
+ */
+ template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
+ //@}
+
+ //!@name Type
+ //@{
+
+ Type GetType() const { return static_cast(data_.f.flags & kTypeMask); }
+ bool IsNull() const { return data_.f.flags == kNullFlag; }
+ bool IsFalse() const { return data_.f.flags == kFalseFlag; }
+ bool IsTrue() const { return data_.f.flags == kTrueFlag; }
+ bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; }
+ bool IsObject() const { return data_.f.flags == kObjectFlag; }
+ bool IsArray() const { return data_.f.flags == kArrayFlag; }
+ bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }
+ bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; }
+ bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; }
+ bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; }
+ bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }
+ bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; }
+ bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }
+
+ // Checks whether a number can be losslessly converted to a double.
+ bool IsLosslessDouble() const {
+ if (!IsNumber()) return false;
+ if (IsUint64()) {
+ uint64_t u = GetUint64();
+ volatile double d = static_cast(u);
+ return (d >= 0.0)
+ && (d < static_cast((std::numeric_limits::max)()))
+ && (u == static_cast(d));
+ }
+ if (IsInt64()) {
+ int64_t i = GetInt64();
+ volatile double d = static_cast(i);
+ return (d >= static_cast((std::numeric_limits::min)()))
+ && (d < static_cast((std::numeric_limits::max)()))
+ && (i == static_cast(d));
+ }
+ return true; // double, int, uint are always lossless
+ }
+
+ // Checks whether a number is a float (possible lossy).
+ bool IsFloat() const {
+ if ((data_.f.flags & kDoubleFlag) == 0)
+ return false;
+ double d = GetDouble();
+ return d >= -3.4028234e38 && d <= 3.4028234e38;
+ }
+ // Checks whether a number can be losslessly converted to a float.
+ bool IsLosslessFloat() const {
+ if (!IsNumber()) return false;
+ double a = GetDouble();
+ if (a < static_cast(-(std::numeric_limits::max)())
+ || a > static_cast((std::numeric_limits::max)()))
+ return false;
+ double b = static_cast(static_cast(a));
+ return a >= b && a <= b; // Prevent -Wfloat-equal
+ }
+
+ //@}
+
+ //!@name Null
+ //@{
+
+ GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
+
+ //@}
+
+ //!@name Bool
+ //@{
+
+ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; }
+ //!< Set boolean value
+ /*! \post IsBool() == true */
+ GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
+
+ //@}
+
+ //!@name Object
+ //@{
+
+ //! Set this value as an empty object.
+ /*! \post IsObject() == true */
+ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
+
+ //! Get the number of members in the object.
+ SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
+
+ //! Get the capacity of object.
+ SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; }
+
+ //! Check whether the object is empty.
+ bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
+
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType))
+ \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.
+ Since 0.2, if the name is not correct, it will assert.
+ If user is unsure whether a member exists, user should use HasMember() first.
+ A better approach is to use FindMember().
+ \note Linear time complexity.
+ */
+ template
+ RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) {
+ GenericValue n(StringRef(name));
+ return (*this)[n];
+ }
+ template
+ RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; }
+
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam SourceAllocator Allocator of the \c name value
+
+ \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen().
+ And it can also handle strings with embedded null characters.
+
+ \note Linear time complexity.
+ */
+ template
+ GenericValue& operator[](const GenericValue& name) {
+ MemberIterator member = FindMember(name);
+ if (member != MemberEnd())
+ return member->value;
+ else {
+ RAPIDJSON_ASSERT(false); // see above note
+
+ // This will generate -Wexit-time-destructors in clang
+ // static GenericValue NullValue;
+ // return NullValue;
+
+ // Use static buffer and placement-new to prevent destruction
+ static char buffer[sizeof(GenericValue)];
+ return *new (buffer) GenericValue();
+ }
+ }
+ template
+ const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Get a value from an object associated with name (string object).
+ GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; }
+ const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; }
+#endif
+
+ //! Const member iterator
+ /*! \pre IsObject() == true */
+ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); }
+ //! Const \em past-the-end member iterator
+ /*! \pre IsObject() == true */
+ ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); }
+ //! Member iterator
+ /*! \pre IsObject() == true */
+ MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); }
+ //! \em Past-the-end member iterator
+ /*! \pre IsObject() == true */
+ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
+
+ //! Request the object to have enough capacity to store members.
+ /*! \param newCapacity The capacity that the object at least need to have.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note Linear time complexity.
+ */
+ GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) {
+ RAPIDJSON_ASSERT(IsObject());
+ if (newCapacity > data_.o.capacity) {
+ SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member))));
+ data_.o.capacity = newCapacity;
+ }
+ return *this;
+ }
+
+ //! Check whether a member exists in the object.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Check whether a member exists in the object with string object.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); }
+#endif
+
+ //! Check whether a member exists in the object with GenericValue name.
+ /*!
+ This version is faster because it does not need a StrLen(). It can also handle string with null character.
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ template
+ bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); }
+
+ //! Find member by name.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+
+ \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+ the requested member doesn't exist. For consistency with e.g.
+ \c std::map, this has been changed to MemberEnd() now.
+ \note Linear time complexity.
+ */
+ MemberIterator FindMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return FindMember(n);
+ }
+
+ ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); }
+
+ //! Find member by name.
+ /*!
+ This version is faster because it does not need a StrLen(). It can also handle string with null character.
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+
+ \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+ the requested member doesn't exist. For consistency with e.g.
+ \c std::map, this has been changed to MemberEnd() now.
+ \note Linear time complexity.
+ */
+ template
+ MemberIterator FindMember(const GenericValue& name) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+ MemberIterator member = MemberBegin();
+ for ( ; member != MemberEnd(); ++member)
+ if (name.StringEqual(member->name))
+ break;
+ return member;
+ }
+ template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Find member by string object name.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+ */
+ MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); }
+ ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); }
+#endif
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note The ownership of \c name and \c value will be transferred to this object on success.
+ \pre IsObject() && name.IsString()
+ \post name.IsNull() && value.IsNull()
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+
+ ObjectData& o = data_.o;
+ if (o.size >= o.capacity)
+ MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator);
+ Member* members = GetMembersPointer();
+ members[o.size].name.RawAssign(name);
+ members[o.size].value.RawAssign(value);
+ o.size++;
+ return *this;
+ }
+
+ //! Add a constant string value as member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Add a string object as member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) {
+ GenericValue v(value, allocator);
+ return AddMember(name, v, allocator);
+ }
+#endif
+
+ //! Add any primitive value as member (name-value pair) to the object.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param name A string value as name of member.
+ \param value Value of primitive type \c T as value of member
+ \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+ AddMember(StringRefType, StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized Constant time complexity.
+ */
+ template
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&))
+ AddMember(GenericValue& name, T value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A constant string reference as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note The ownership of \c value will be transferred to this object on success.
+ \pre IsObject()
+ \post value.IsNull()
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+
+ //! Add a constant string value as member (name-value pair) to the object.
+ /*! \param name A constant string reference as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+ //! Add any primitive value as member (name-value pair) to the object.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param name A constant string reference as name of member.
+ \param value Value of primitive type \c T as value of member
+ \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+ AddMember(StringRefType, StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized Constant time complexity.
+ */
+ template
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&))
+ AddMember(StringRefType name, T value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+
+ //! Remove all members in the object.
+ /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged.
+ \note Linear time complexity.
+ */
+ void RemoveAllMembers() {
+ RAPIDJSON_ASSERT(IsObject());
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ data_.o.size = 0;
+ }
+
+ //! Remove a member in object by its name.
+ /*! \param name Name of member to be removed.
+ \return Whether the member existed.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
+ \note Linear time complexity.
+ */
+ bool RemoveMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return RemoveMember(n);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); }
+#endif
+
+ template
+ bool RemoveMember(const GenericValue& name) {
+ MemberIterator m = FindMember(name);
+ if (m != MemberEnd()) {
+ RemoveMember(m);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ //! Remove a member in object by iterator.
+ /*! \param m member iterator (obtained by FindMember() or MemberBegin()).
+ \return the new iterator after removal.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
+ \note Constant time complexity.
+ */
+ MemberIterator RemoveMember(MemberIterator m) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(GetMembersPointer() != 0);
+ RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
+
+ MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
+ if (data_.o.size > 1 && m != last)
+ *m = *last; // Move the last one to this place
+ else
+ m->~Member(); // Only one left, just destroy
+ --data_.o.size;
+ return m;
+ }
+
+ //! Remove a member from an object by iterator.
+ /*! \param pos iterator to the member to remove
+ \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd()
+ \return Iterator following the removed element.
+ If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned.
+ \note This function preserves the relative order of the remaining object
+ members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator).
+ \note Linear time complexity.
+ */
+ MemberIterator EraseMember(ConstMemberIterator pos) {
+ return EraseMember(pos, pos +1);
+ }
+
+ //! Remove members in the range [first, last) from an object.
+ /*! \param first iterator to the first member to remove
+ \param last iterator following the last member to remove
+ \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd()
+ \return Iterator following the last removed element.
+ \note This function preserves the relative order of the remaining object
+ members.
+ \note Linear time complexity.
+ */
+ MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(GetMembersPointer() != 0);
+ RAPIDJSON_ASSERT(first >= MemberBegin());
+ RAPIDJSON_ASSERT(first <= last);
+ RAPIDJSON_ASSERT(last <= MemberEnd());
+
+ MemberIterator pos = MemberBegin() + (first - MemberBegin());
+ for (MemberIterator itr = pos; itr != last; ++itr)
+ itr->~Member();
+ std::memmove(static_cast(&*pos), &*last, static_cast(MemberEnd() - last) * sizeof(Member));
+ data_.o.size -= static_cast(last - first);
+ return pos;
+ }
+
+ //! Erase a member in object by its name.
+ /*! \param name Name of member to be removed.
+ \return Whether the member existed.
+ \note Linear time complexity.
+ */
+ bool EraseMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return EraseMember(n);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); }
+#endif
+
+ template
+ bool EraseMember(const GenericValue& name) {
+ MemberIterator m = FindMember(name);
+ if (m != MemberEnd()) {
+ EraseMember(m);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
+ ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
+
+ //@}
+
+ //!@name Array
+ //@{
+
+ //! Set this value as an empty array.
+ /*! \post IsArray == true */
+ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
+
+ //! Get the number of elements in array.
+ SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
+
+ //! Get the capacity of array.
+ SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
+
+ //! Check whether the array is empty.
+ bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
+
+ //! Remove all elements in the array.
+ /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
+ \note Linear time complexity.
+ */
+ void Clear() {
+ RAPIDJSON_ASSERT(IsArray());
+ GenericValue* e = GetElementsPointer();
+ for (GenericValue* v = e; v != e + data_.a.size; ++v)
+ v->~GenericValue();
+ data_.a.size = 0;
+ }
+
+ //! Get an element from array by index.
+ /*! \pre IsArray() == true
+ \param index Zero-based index of element.
+ \see operator[](T*)
+ */
+ GenericValue& operator[](SizeType index) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(index < data_.a.size);
+ return GetElementsPointer()[index];
+ }
+ const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; }
+
+ //! Element iterator
+ /*! \pre IsArray() == true */
+ ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); }
+ //! \em Past-the-end element iterator
+ /*! \pre IsArray() == true */
+ ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; }
+ //! Constant element iterator
+ /*! \pre IsArray() == true */
+ ConstValueIterator Begin() const { return const_cast(*this).Begin(); }
+ //! Constant \em past-the-end element iterator
+ /*! \pre IsArray() == true */
+ ConstValueIterator End() const { return const_cast(*this).End(); }
+
+ //! Request the array to have enough capacity to store elements.
+ /*! \param newCapacity The capacity that the array at least need to have.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note Linear time complexity.
+ */
+ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (newCapacity > data_.a.capacity) {
+ SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue))));
+ data_.a.capacity = newCapacity;
+ }
+ return *this;
+ }
+
+ //! Append a GenericValue at the end of the array.
+ /*! \param value Value to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \post value.IsNull() == true
+ \return The value itself for fluent API.
+ \note The ownership of \c value will be transferred to this array on success.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+ \note Amortized constant time complexity.
+ */
+ GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (data_.a.size >= data_.a.capacity)
+ Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
+ GetElementsPointer()[data_.a.size++].RawAssign(value);
+ return *this;
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {
+ return PushBack(value, allocator);
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+ //! Append a constant string reference at the end of the array.
+ /*! \param value Constant string reference to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \return The value itself for fluent API.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+ \note Amortized constant time complexity.
+ \see GenericStringRef
+ */
+ GenericValue& PushBack(StringRefType value, Allocator& allocator) {
+ return (*this).template PushBack(value, allocator);
+ }
+
+ //! Append a primitive value at the end of the array.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param value Value of primitive type T to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \return The value itself for fluent API.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref PushBack(GenericValue&, Allocator&) or \ref
+ PushBack(StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized constant time complexity.
+ */
+ template
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&))
+ PushBack(T value, Allocator& allocator) {
+ GenericValue v(value);
+ return PushBack(v, allocator);
+ }
+
+ //! Remove the last element in the array.
+ /*!
+ \note Constant time complexity.
+ */
+ GenericValue& PopBack() {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(!Empty());
+ GetElementsPointer()[--data_.a.size].~GenericValue();
+ return *this;
+ }
+
+ //! Remove an element of array by iterator.
+ /*!
+ \param pos iterator to the element to remove
+ \pre IsArray() == true && \ref Begin() <= \c pos < \ref End()
+ \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.
+ \note Linear time complexity.
+ */
+ ValueIterator Erase(ConstValueIterator pos) {
+ return Erase(pos, pos + 1);
+ }
+
+ //! Remove elements in the range [first, last) of the array.
+ /*!
+ \param first iterator to the first element to remove
+ \param last iterator following the last element to remove
+ \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End()
+ \return Iterator following the last removed element.
+ \note Linear time complexity.
+ */
+ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(data_.a.size > 0);
+ RAPIDJSON_ASSERT(GetElementsPointer() != 0);
+ RAPIDJSON_ASSERT(first >= Begin());
+ RAPIDJSON_ASSERT(first <= last);
+ RAPIDJSON_ASSERT(last <= End());
+ ValueIterator pos = Begin() + (first - Begin());
+ for (ValueIterator itr = pos; itr != last; ++itr)
+ itr->~GenericValue();
+ std::memmove(static_cast(pos), last, static_cast(End() - last) * sizeof(GenericValue));
+ data_.a.size -= static_cast(last - first);
+ return pos;
+ }
+
+ Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); }
+ ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); }
+
+ //@}
+
+ //!@name Number
+ //@{
+
+ int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; }
+ unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; }
+ int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; }
+ uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; }
+
+ //! Get the value as double type.
+ /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless.
+ */
+ double GetDouble() const {
+ RAPIDJSON_ASSERT(IsNumber());
+ if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
+ if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double
+ if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
+ if ((data_.f.flags & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision)
+ RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision)
+ }
+
+ //! Get the value as float type.
+ /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless.
+ */
+ float GetFloat() const {
+ return static_cast(GetDouble());
+ }
+
+ GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
+ GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; }
+ GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
+ GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
+ GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
+ GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast(f)); return *this; }
+
+ //@}
+
+ //!@name String
+ //@{
+
+ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }
+
+ //! Get the length of string.
+ /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
+ */
+ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
+
+ //! Set this value as a string without copying source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string pointer.
+ \param length The length of source string, excluding the trailing null terminator.
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() == s && GetStringLength() == length
+ \see SetString(StringRefType)
+ */
+ GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }
+
+ //! Set this value as a string without copying source string.
+ /*! \param s source string reference
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() == s && GetStringLength() == s.length
+ */
+ GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }
+
+ //! Set this value as a string by copying from source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string.
+ \param length The length of source string, excluding the trailing null terminator.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+ */
+ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); }
+
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+ */
+ GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
+
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string reference
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+ */
+ GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
+ \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
+#endif
+
+ //@}
+
+ //!@name Array
+ //@{
+
+ //! Templated version for checking whether this value is type T.
+ /*!
+ \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string
+ */
+ template
+ bool Is() const { return internal::TypeHelper::Is(*this); }
+
+ template
+ T Get() const { return internal::TypeHelper::Get(*this); }
+
+ template
+ T Get() { return internal::TypeHelper::Get(*this); }
+
+ template
+ ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); }
+
+ template
+ ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); }
+
+ //@}
+
+ //! Generate events of this value to a Handler.
+ /*! This function adopts the GoF visitor pattern.
+ Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
+ It can also be used to deep clone this value via GenericDocument, which is also a Handler.
+ \tparam Handler type of handler.
+ \param handler An object implementing concept Handler.
+ */
+ template
+ bool Accept(Handler& handler) const {
+ switch(GetType()) {
+ case kNullType: return handler.Null();
+ case kFalseType: return handler.Bool(false);
+ case kTrueType: return handler.Bool(true);
+
+ case kObjectType:
+ if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
+ return false;
+ for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
+ RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
+ if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0)))
+ return false;
+ if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))
+ return false;
+ }
+ return handler.EndObject(data_.o.size);
+
+ case kArrayType:
+ if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
+ return false;
+ for (const GenericValue* v = Begin(); v != End(); ++v)
+ if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
+ return false;
+ return handler.EndArray(data_.a.size);
+
+ case kStringType:
+ return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0);
+
+ default:
+ RAPIDJSON_ASSERT(GetType() == kNumberType);
+ if (IsDouble()) return handler.Double(data_.n.d);
+ else if (IsInt()) return handler.Int(data_.n.i.i);
+ else if (IsUint()) return handler.Uint(data_.n.u.u);
+ else if (IsInt64()) return handler.Int64(data_.n.i64);
+ else return handler.Uint64(data_.n.u64);
+ }
+ }
+
+private:
+ template friend class GenericValue;
+ template friend class GenericDocument;
+
+ enum {
+ kBoolFlag = 0x0008,
+ kNumberFlag = 0x0010,
+ kIntFlag = 0x0020,
+ kUintFlag = 0x0040,
+ kInt64Flag = 0x0080,
+ kUint64Flag = 0x0100,
+ kDoubleFlag = 0x0200,
+ kStringFlag = 0x0400,
+ kCopyFlag = 0x0800,
+ kInlineStrFlag = 0x1000,
+
+ // Initial flags of different types.
+ kNullFlag = kNullType,
+ kTrueFlag = kTrueType | kBoolFlag,
+ kFalseFlag = kFalseType | kBoolFlag,
+ kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
+ kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
+ kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
+ kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
+ kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
+ kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
+ kConstStringFlag = kStringType | kStringFlag,
+ kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
+ kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
+ kObjectFlag = kObjectType,
+ kArrayFlag = kArrayType,
+
+ kTypeMask = 0x07
+ };
+
+ static const SizeType kDefaultArrayCapacity = 16;
+ static const SizeType kDefaultObjectCapacity = 16;
+
+ struct Flag {
+#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
+ char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer
+#elif RAPIDJSON_64BIT
+ char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes
+#else
+ char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes
+#endif
+ uint16_t flags;
+ };
+
+ struct String {
+ SizeType length;
+ SizeType hashcode; //!< reserved
+ const Ch* str;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
+ // (excluding the terminating zero) and store a value to determine the length of the contained
+ // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string
+ // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
+ // the string terminator as well. For getting the string length back from that value just use
+ // "MaxSize - str[LenPos]".
+ // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode,
+ // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings).
+ struct ShortString {
+ enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
+ Ch str[MaxChars];
+
+ inline static bool Usable(SizeType len) { return (MaxSize >= len); }
+ inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); }
+ inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); }
+ }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // By using proper binary layout, retrieval of different integer types do not need conversions.
+ union Number {
+#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
+ struct I {
+ int i;
+ char padding[4];
+ }i;
+ struct U {
+ unsigned u;
+ char padding2[4];
+ }u;
+#else
+ struct I {
+ char padding[4];
+ int i;
+ }i;
+ struct U {
+ char padding2[4];
+ unsigned u;
+ }u;
+#endif
+ int64_t i64;
+ uint64_t u64;
+ double d;
+ }; // 8 bytes
+
+ struct ObjectData {
+ SizeType size;
+ SizeType capacity;
+ Member* members;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ struct ArrayData {
+ SizeType size;
+ SizeType capacity;
+ GenericValue* elements;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ union Data {
+ String s;
+ ShortString ss;
+ Number n;
+ ObjectData o;
+ ArrayData a;
+ Flag f;
+ }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
+
+ RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
+ RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
+ RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
+ RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); }
+ RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
+ RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
+
+ // Initialize this value as array with initial data, without calling destructor.
+ void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
+ data_.f.flags = kArrayFlag;
+ if (count) {
+ GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue)));
+ SetElementsPointer(e);
+ std::memcpy(static_cast(e), values, count * sizeof(GenericValue));
+ }
+ else
+ SetElementsPointer(0);
+ data_.a.size = data_.a.capacity = count;
+ }
+
+ //! Initialize this value as object with initial data, without calling destructor.
+ void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
+ data_.f.flags = kObjectFlag;
+ if (count) {
+ Member* m = static_cast(allocator.Malloc(count * sizeof(Member)));
+ SetMembersPointer(m);
+ std::memcpy(static_cast(m), members, count * sizeof(Member));
+ }
+ else
+ SetMembersPointer(0);
+ data_.o.size = data_.o.capacity = count;
+ }
+
+ //! Initialize this value as constant string, without calling destructor.
+ void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
+ data_.f.flags = kConstStringFlag;
+ SetStringPointer(s);
+ data_.s.length = s.length;
+ }
+
+ //! Initialize this value as copy string with initial data, without calling destructor.
+ void SetStringRaw(StringRefType s, Allocator& allocator) {
+ Ch* str = 0;
+ if (ShortString::Usable(s.length)) {
+ data_.f.flags = kShortStringFlag;
+ data_.ss.SetLength(s.length);
+ str = data_.ss.str;
+ } else {
+ data_.f.flags = kCopyStringFlag;
+ data_.s.length = s.length;
+ str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch)));
+ SetStringPointer(str);
+ }
+ std::memcpy(str, s, s.length * sizeof(Ch));
+ str[s.length] = '\0';
+ }
+
+ //! Assignment without calling destructor
+ void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+ data_ = rhs.data_;
+ // data_.f.flags = rhs.data_.f.flags;
+ rhs.data_.f.flags = kNullFlag;
+ }
+
+ template