From 19182ffe53ec308decfd6541e96f4e0e54d474d8 Mon Sep 17 00:00:00 2001 From: lyq Date: Thu, 15 Jan 2026 09:38:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6gps=E4=B8=8A=E6=8A=A5?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=8E=BB=E9=99=A4=E5=8E=9F=E6=9C=89?= =?UTF-8?q?=E7=9A=84pub=5Fgps=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.json | 1 - .../include/mqtt_report/get_config.h | 7 +- .../include/mqtt_report/mqtt_client.hpp | 152 +- src/communication/pub_gps/CMakeLists.txt | 68 - .../pub_gps/include/paho_mqtt_3c/Base64.h | 83 - .../pub_gps/include/paho_mqtt_3c/Clients.h | 153 - .../pub_gps/include/paho_mqtt_3c/Heap.h | 82 - .../pub_gps/include/paho_mqtt_3c/LinkedList.h | 105 - .../pub_gps/include/paho_mqtt_3c/Log.h | 85 - .../pub_gps/include/paho_mqtt_3c/MQTTAsync.h | 2068 ------- .../pub_gps/include/paho_mqtt_3c/MQTTClient.h | 1670 ------ .../paho_mqtt_3c/MQTTClientPersistence.h | 254 - .../include/paho_mqtt_3c/MQTTConnect.h | 148 - .../pub_gps/include/paho_mqtt_3c/MQTTFormat.h | 37 - .../pub_gps/include/paho_mqtt_3c/MQTTPacket.h | 270 - .../include/paho_mqtt_3c/MQTTPacketOut.h | 39 - .../include/paho_mqtt_3c/MQTTPersistence.h | 94 - .../paho_mqtt_3c/MQTTPersistenceDefault.h | 38 - .../include/paho_mqtt_3c/MQTTProperties.h | 225 - .../include/paho_mqtt_3c/MQTTProtocol.h | 46 - .../include/paho_mqtt_3c/MQTTProtocolClient.h | 60 - .../include/paho_mqtt_3c/MQTTProtocolOut.h | 50 - .../include/paho_mqtt_3c/MQTTPublish.h | 38 - .../include/paho_mqtt_3c/MQTTReasonCodes.h | 85 - .../include/paho_mqtt_3c/MQTTSubscribe.h | 39 - .../include/paho_mqtt_3c/MQTTSubscribeOpts.h | 46 - .../include/paho_mqtt_3c/MQTTUnsubscribe.h | 38 - .../pub_gps/include/paho_mqtt_3c/Messages.h | 24 - .../pub_gps/include/paho_mqtt_3c/OsWrapper.h | 42 - .../pub_gps/include/paho_mqtt_3c/SHA1.h | 91 - .../pub_gps/include/paho_mqtt_3c/SSLSocket.h | 52 - .../pub_gps/include/paho_mqtt_3c/Socket.h | 145 - .../include/paho_mqtt_3c/SocketBuffer.h | 84 - .../pub_gps/include/paho_mqtt_3c/StackTrace.h | 71 - .../pub_gps/include/paho_mqtt_3c/Thread.h | 75 - .../pub_gps/include/paho_mqtt_3c/Tree.h | 115 - .../include/paho_mqtt_3c/VersionInfo.h.in | 7 - .../pub_gps/include/paho_mqtt_3c/WebSocket.h | 77 - .../pub_gps/include/paho_mqtt_3c/mutex_type.h | 25 - .../include/paho_mqtt_3c/pubsub_opts.h | 86 - .../pub_gps/include/paho_mqtt_3c/utf-8.h | 23 - .../pub_gps/include/pub_gps/json.h | 2351 -------- .../pub_gps/include/pub_gps/pub_gps_node.hpp | 14 - .../pub_gps/lib/libpaho-mqtt3c-static.a | Bin 331658 -> 0 bytes .../pub_gps/lib/libpaho-mqtt3c.a | Bin 362166 -> 0 bytes src/communication/pub_gps/package.xml | 22 - src/communication/pub_gps/src/jsoncpp.cpp | 5342 ----------------- .../pub_gps/src/pub_gps_node.cpp | 305 - 48 files changed, 107 insertions(+), 14825 deletions(-) delete mode 100644 src/communication/pub_gps/CMakeLists.txt delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/Base64.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/Clients.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/Heap.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/LinkedList.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/Log.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTAsync.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTClient.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTClientPersistence.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTConnect.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTFormat.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTPacket.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTPacketOut.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTPersistence.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTPersistenceDefault.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTProperties.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocol.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocolClient.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocolOut.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTPublish.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTReasonCodes.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTSubscribe.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTSubscribeOpts.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/MQTTUnsubscribe.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/Messages.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/OsWrapper.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/SHA1.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/SSLSocket.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/Socket.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/SocketBuffer.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/StackTrace.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/Thread.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/Tree.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/VersionInfo.h.in delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/WebSocket.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/mutex_type.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/pubsub_opts.h delete mode 100644 src/communication/pub_gps/include/paho_mqtt_3c/utf-8.h delete mode 100644 src/communication/pub_gps/include/pub_gps/json.h delete mode 100644 src/communication/pub_gps/include/pub_gps/pub_gps_node.hpp delete mode 100644 src/communication/pub_gps/lib/libpaho-mqtt3c-static.a delete mode 100644 src/communication/pub_gps/lib/libpaho-mqtt3c.a delete mode 100644 src/communication/pub_gps/package.xml delete mode 100644 src/communication/pub_gps/src/jsoncpp.cpp delete mode 100644 src/communication/pub_gps/src/pub_gps_node.cpp diff --git a/config.json b/config.json index 28b174f..d201630 100644 --- a/config.json +++ b/config.json @@ -7,7 +7,6 @@ "info_topic": "/zxwl/sweeper/{vid}/info", "fault_topic": "/zxwl/sweeper/{vid}/fault", "gps_topic": "/zxwl/sweeper/{vid}/gps", - "pub_gps_topic": "/zxwl/sweeper/V060003/gps", "remote_topic": "/zxwl/sweeper/V060003/ctrl", "upload_url": "https://qsc.ntiov.com:8443/api/sys/route/upload", "download_url_pre": "http://36.153.162.171:9510/api/ccp-web/file/", diff --git a/src/communication/mqtt_report/include/mqtt_report/get_config.h b/src/communication/mqtt_report/include/mqtt_report/get_config.h index b0d4ee5..9ac98f7 100644 --- a/src/communication/mqtt_report/include/mqtt_report/get_config.h +++ b/src/communication/mqtt_report/include/mqtt_report/get_config.h @@ -24,9 +24,10 @@ struct Config std::string mqtt_username; std::string mqtt_password; - std::string info_topic_template; // e.g. /zxwl/vehicle/{vid}/info - std::string gps_topic_template; - std::string fault_topic_template; // e.g. /zxwl/vehicle/{vid}/fault + // ===== 上行 topic ===== + std::string info_topic_template; // /zxwl/sweeper/{vid}/info + std::string gps_topic_template; // /zxwl/sweeper/{vid}/gps + std::string fault_topic_template; // /zxwl/sweeper/{vid}/fault }; bool load_config(const std::string& path, Config& config); diff --git a/src/communication/mqtt_report/include/mqtt_report/mqtt_client.hpp b/src/communication/mqtt_report/include/mqtt_report/mqtt_client.hpp index c897a8a..06cf8fd 100644 --- a/src/communication/mqtt_report/include/mqtt_report/mqtt_client.hpp +++ b/src/communication/mqtt_report/include/mqtt_report/mqtt_client.hpp @@ -1,21 +1,23 @@ #pragma once -#include "paho_mqtt_3c/MQTTClient.h" -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include + +#include "paho_mqtt_3c/MQTTClient.h" class MQTTClientWrapper { -public: - MQTTClientWrapper(const std::string &server_uri, - const std::string &client_id, - const std::string &username = "", - const std::string &password = "", - int reconnect_interval_ms = 3000) + public: + using MessageHandler = std::function; + + MQTTClientWrapper(const std::string& server_uri, const std::string& client_id, const std::string& username = "", + const std::string& password = "", int reconnect_interval_ms = 3000) : server_uri_(server_uri), client_id_(client_id), username_(username), @@ -24,20 +26,17 @@ public: connected_(false), stop_flag_(false) { - int rc = MQTTClient_create(&client_, - server_uri_.c_str(), - client_id_.c_str(), - MQTTCLIENT_PERSISTENCE_NONE, - nullptr); + int rc = + MQTTClient_create(&client_, server_uri_.c_str(), client_id_.c_str(), MQTTCLIENT_PERSISTENCE_NONE, nullptr); if (rc != MQTTCLIENT_SUCCESS) { - std::cerr << "MQTTClient_create failed! rc=" << rc << std::endl; + std::cerr << "[MQTT] create failed rc=" << rc << std::endl; client_ = nullptr; return; } - MQTTClient_setCallbacks(client_, this, conn_lost_cb, nullptr, nullptr); + MQTTClient_setCallbacks(client_, this, conn_lost_cb, msg_arrived_cb, nullptr); reconnect_thread_ = std::thread([this]() { reconnectLoop(); }); } @@ -46,41 +45,36 @@ public: { stop_flag_ = true; - if (reconnect_thread_.joinable()) - reconnect_thread_.join(); + if (reconnect_thread_.joinable()) reconnect_thread_.join(); std::lock_guard lock(mtx_); if (client_) { - if (connected_) - MQTTClient_disconnect(client_, 2000); + if (connected_) MQTTClient_disconnect(client_, 2000); MQTTClient_destroy(&client_); } } - // 手动连接(可选) + // ===================== Connection ===================== + bool connect() { std::lock_guard lock(mtx_); return doConnect(); } - // 发布(非阻塞,无 waitForCompletion) - bool publish(const std::string &topic, - const std::string &payload, - int qos = 0, - bool retained = false) + bool isConnected() const { return connected_; } + + // ===================== Publish ===================== + + bool publish(const std::string& topic, const std::string& payload, int qos = 0, bool retained = false) { std::lock_guard lock(mtx_); - if (!client_) - return false; - - if (!connected_) - return false; + if (!client_ || !connected_) return false; MQTTClient_message msg = MQTTClient_message_initializer; - msg.payload = (void *)payload.c_str(); + msg.payload = (void*)payload.c_str(); msg.payloadlen = payload.size(); msg.qos = qos; msg.retained = retained ? 1 : 0; @@ -93,18 +87,54 @@ public: connected_ = false; return false; } - - // 非阻塞,不等待 completion return true; } - bool isConnected() const { return connected_; } + // ===================== Subscribe ===================== + + bool subscribe(const std::string& topic, int qos = 0) + { + std::lock_guard lock(mtx_); + if (!client_) return false; + + subscribed_topics_[topic] = qos; + + if (!connected_) return true; // 等重连后自动订阅 + + int rc = MQTTClient_subscribe(client_, topic.c_str(), qos); + if (rc != MQTTCLIENT_SUCCESS) + { + std::cerr << "[MQTT] subscribe failed rc=" << rc << std::endl; + return false; + } + return true; + } + + bool unsubscribe(const std::string& topic) + { + std::lock_guard lock(mtx_); + subscribed_topics_.erase(topic); + + if (!connected_ || !client_) return true; + + MQTTClient_unsubscribe(client_, topic.c_str()); + return true; + } + + // ===================== Message Handler ===================== + + void setMessageHandler(MessageHandler handler) + { + std::lock_guard lock(mtx_); + message_handler_ = std::move(handler); + } + + private: + // ===================== Internal ===================== -private: bool doConnect() { - if (!client_) - return false; + if (!client_) return false; MQTTClient_connectOptions opts = MQTTClient_connectOptions_initializer; opts.keepAliveInterval = 20; @@ -120,24 +150,45 @@ private: int rc = MQTTClient_connect(client_, &opts); if (rc == MQTTCLIENT_SUCCESS) { - std::cout << "[MQTT] Connected." << std::endl; connected_ = true; + std::cout << "[MQTT] Connected." << std::endl; + + // 重连后恢复订阅 + for (const auto& [topic, qos] : subscribed_topics_) + { + MQTTClient_subscribe(client_, topic.c_str(), qos); + } return true; } - std::cerr << "[MQTT] Connect failed rc=" << rc << std::endl; connected_ = false; return false; } - static void conn_lost_cb(void *context, char *cause) + static void conn_lost_cb(void* context, char* cause) { - auto *self = static_cast(context); + auto* self = static_cast(context); std::cerr << "[MQTT] Connection lost: " << (cause ? cause : "unknown") << std::endl; self->connected_ = false; } - // 自动重连线程 + static int msg_arrived_cb(void* context, char* topicName, int /*topicLen*/, MQTTClient_message* message) + { + auto* self = static_cast(context); + + std::string topic(topicName); + std::string payload(static_cast(message->payload), message->payloadlen); + + { + std::lock_guard lock(self->mtx_); + if (self->message_handler_) self->message_handler_(topic, payload); + } + + MQTTClient_freeMessage(&message); + MQTTClient_free(topicName); + return 1; + } + void reconnectLoop() { while (!stop_flag_) @@ -148,13 +199,13 @@ private: doConnect(); } - std::this_thread::sleep_for( - std::chrono::milliseconds(reconnect_interval_ms_)); + std::this_thread::sleep_for(std::chrono::milliseconds(reconnect_interval_ms_)); } } -private: - MQTTClient client_; + private: + MQTTClient client_{}; + std::string server_uri_; std::string client_id_; std::string username_; @@ -165,6 +216,9 @@ private: std::atomic connected_; std::atomic stop_flag_; + std::unordered_map subscribed_topics_; + MessageHandler message_handler_; + std::mutex mtx_; std::thread reconnect_thread_; }; diff --git a/src/communication/pub_gps/CMakeLists.txt b/src/communication/pub_gps/CMakeLists.txt deleted file mode 100644 index 7751d44..0000000 --- a/src/communication/pub_gps/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -cmake_minimum_required(VERSION 3.5) -project(pub_gps) - -# Default to C99 -if(NOT CMAKE_C_STANDARD) - set(CMAKE_C_STANDARD 99) -endif() - -# Default to C++14 -if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 14) -endif() - -if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") - add_compile_options(-Wall -Wextra -Wpedantic) -endif() - -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - add_compile_options(-w) # 禁用所有警告 -endif() - -# find dependencies -find_package(ament_cmake REQUIRED) -find_package(rclcpp REQUIRED) -find_package(std_msgs REQUIRED) -find_package(sweeper_interfaces REQUIRED) - -include_directories( - include/pub_gps - include/paho_mqtt_3c -) - -add_executable(pub_gps_node - src/pub_gps_node.cpp - src/jsoncpp.cpp -) - -ament_target_dependencies(pub_gps_node rclcpp std_msgs sweeper_interfaces) - -if(CMAKE_SYSTEM_PROCESSOR MATCHES aarch64) - target_link_libraries( - pub_gps_node - ${PROJECT_SOURCE_DIR}/lib/libpaho-mqtt3c-static.a - ) -else() - target_link_libraries( - pub_gps_node - ${PROJECT_SOURCE_DIR}/lib/libpaho-mqtt3c.a - ) -endif() - -install(TARGETS - pub_gps_node - DESTINATION lib/${PROJECT_NAME} -) - -if(BUILD_TESTING) - find_package(ament_lint_auto REQUIRED) - # the following line skips the linter which checks for copyrights - # uncomment the line when a copyright and license is not present in all source files - #set(ament_cmake_copyright_FOUND TRUE) - # the following line skips cpplint (only works in a git repo) - # uncomment the line when this package is not in a git repo - #set(ament_cmake_cpplint_FOUND TRUE) - ament_lint_auto_find_test_dependencies() -endif() - -ament_package() diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/Base64.h b/src/communication/pub_gps/include/paho_mqtt_3c/Base64.h deleted file mode 100644 index df9dd75..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/Base64.h +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 Wind River Systems, Inc. All Rights Reserved. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Keith Holman - initial implementation and documentation - *******************************************************************************/ - -#if !defined(BASE64_H) -#define BASE64_H - -/** type for size of a buffer, it saves passing around @p size_t (unsigned long long or unsigned long int) */ -typedef unsigned int b64_size_t; -/** type for raw base64 data */ -typedef unsigned char b64_data_t; - -/** - * Decodes base64 data - * - * @param[out] out decoded data - * @param[in] out_len length of output buffer - * @param[in] in base64 string to decode - * @param[in] in_len length of input buffer - * - * @return the amount of data decoded - * - * @see Base64_decodeLength - * @see Base64_encode - */ -b64_size_t Base64_decode( b64_data_t *out, b64_size_t out_len, - const char *in, b64_size_t in_len ); - -/** - * Size of buffer required to decode base64 data - * - * @param[in] in base64 string to decode - * @param[in] in_len length of input buffer - * - * @return the size of buffer the decoded string would require - * - * @see Base64_decode - * @see Base64_encodeLength - */ -b64_size_t Base64_decodeLength( const char *in, b64_size_t in_len ); - -/** - * Encodes base64 data - * - * @param[out] out encode base64 string - * @param[in] out_len length of output buffer - * @param[in] in raw data to encode - * @param[in] in_len length of input buffer - * - * @return the amount of data encoded - * - * @see Base64_decode - * @see Base64_encodeLength - */ -b64_size_t Base64_encode( char *out, b64_size_t out_len, - const b64_data_t *in, b64_size_t in_len ); - -/** - * Size of buffer required to encode base64 data - * - * @param[in] in raw data to encode - * @param[in] in_len length of input buffer - * - * @return the size of buffer the encoded string would require - * - * @see Base64_decodeLength - * @see Base64_encode - */ -b64_size_t Base64_encodeLength( const b64_data_t *in, b64_size_t in_len ); - -#endif /* BASE64_H */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/Clients.h b/src/communication/pub_gps/include/paho_mqtt_3c/Clients.h deleted file mode 100644 index fd32e3b..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/Clients.h +++ /dev/null @@ -1,153 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs - add SSL support - * Ian Craggs - fix for bug 413429 - connectionLost not called - * Ian Craggs - change will payload to binary - * Ian Craggs - password to binary - * Ian Craggs - MQTT 5 support - *******************************************************************************/ - -#if !defined(CLIENTS_H) -#define CLIENTS_H - -#include -#if defined(OPENSSL) -#if defined(WIN32) || defined(WIN64) -#include -#endif -#include -#endif -#include "MQTTClient.h" -#include "LinkedList.h" -#include "MQTTClientPersistence.h" - - -/** - * Stored publication data to minimize copying - */ -typedef struct -{ - char *topic; - int topiclen; - char* payload; - int payloadlen; - int refcount; -} Publications; - -/** - * Client publication message data - */ -typedef struct -{ - int qos; - int retain; - int msgid; - int MQTTVersion; - MQTTProperties properties; - Publications *publish; - time_t lastTouch; /**> used for retry and expiry */ - char nextMessageType; /**> PUBREC, PUBREL, PUBCOMP */ - int len; /**> length of the whole structure+data */ -} Messages; - -/** - * Client will message data - */ -typedef struct -{ - char *topic; - int payloadlen; - void *payload; - int retained; - int qos; -} willMessages; - -typedef struct -{ - int socket; - time_t lastSent; - time_t lastReceived; -#if defined(OPENSSL) - SSL* ssl; - SSL_CTX* ctx; -#endif - int websocket; /**< socket has been upgraded to use web sockets */ - char *websocket_key; -} networkHandles; - - -/* connection states */ -/** no connection in progress, see connected value */ -#define NOT_IN_PROGRESS 0x0 -/** TCP connection in progress */ -#define TCP_IN_PROGRESS 0x1 -/** SSL connection in progress */ -#define SSL_IN_PROGRESS 0x2 -/** Websocket connection in progress */ -#define WEBSOCKET_IN_PROGRESS 0x3 -/** TCP completed, waiting for MQTT ACK */ -#define WAIT_FOR_CONNACK 0x4 -/** Disconnecting */ -#define DISCONNECTING -2 - -/** - * Data related to one client - */ -typedef struct -{ - char* clientID; /**< the string id of the client */ - const char* username; /**< MQTT v3.1 user name */ - int passwordlen; /**< MQTT password length */ - const void* password; /**< MQTT v3.1 binary password */ - unsigned int cleansession : 1; /**< MQTT V3 clean session flag */ - unsigned int cleanstart : 1; /**< MQTT V5 clean start flag */ - unsigned int connected : 1; /**< whether it is currently connected */ - unsigned int good : 1; /**< if we have an error on the socket we turn this off */ - unsigned int ping_outstanding : 1; - signed int connect_state : 4; - networkHandles net; - int msgID; - int keepAliveInterval; - int retryInterval; - int maxInflightMessages; - willMessages* will; - List* inboundMsgs; - List* outboundMsgs; /**< in flight */ - List* messageQueue; - unsigned int qentry_seqno; - void* phandle; /* the persistence handle */ - MQTTClient_persistence* persistence; /* a persistence implementation */ - void* context; /* calling context - used when calling disconnect_internal */ - int MQTTVersion; - int sessionExpiry; /**< MQTT 5 session expiry */ -#if defined(OPENSSL) - MQTTClient_SSLOptions *sslopts; - SSL_SESSION* session; /***< SSL session pointer for fast handhake */ -#endif -} Clients; - -int clientIDCompare(void* a, void* b); -int clientSocketCompare(void* a, void* b); - -/** - * Configuration data related to all clients - */ -typedef struct -{ - const char* version; - List* clients; -} ClientStates; - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/Heap.h b/src/communication/pub_gps/include/paho_mqtt_3c/Heap.h deleted file mode 100644 index 6d24c04..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/Heap.h +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2013 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs - use tree data structure instead of list - *******************************************************************************/ - - -#if !defined(HEAP_H) -#define HEAP_H - -#if defined(HIGH_PERFORMANCE) -#define NO_HEAP_TRACKING 1 -#endif - -#include -#include - -#if !defined(NO_HEAP_TRACKING) -/** - * redefines malloc to use "mymalloc" so that heap allocation can be tracked - * @param x the size of the item to be allocated - * @return the pointer to the item allocated, or NULL - */ -#define malloc(x) mymalloc(__FILE__, __LINE__, x) - -/** - * redefines realloc to use "myrealloc" so that heap allocation can be tracked - * @param a the heap item to be reallocated - * @param b the new size of the item - * @return the new pointer to the heap item - */ -#define realloc(a, b) myrealloc(__FILE__, __LINE__, a, b) - -/** - * redefines free to use "myfree" so that heap allocation can be tracked - * @param x the size of the item to be freed - */ -#define free(x) myfree(__FILE__, __LINE__, x) - -#endif - -/** - * Information about the state of the heap. - */ -typedef struct -{ - size_t current_size; /**< current size of the heap in bytes */ - size_t max_size; /**< max size the heap has reached in bytes */ -} heap_info; - -#if defined(__cplusplus) - extern "C" { -#endif - -void* mymalloc(char*, int, size_t size); -void* myrealloc(char*, int, void* p, size_t size); -void myfree(char*, int, void* p); - -void Heap_scan(FILE* file); -int Heap_initialize(void); -void Heap_terminate(void); -heap_info* Heap_get_info(void); -int HeapDump(FILE* file); -int HeapDumpString(FILE* file, char* str); -void* Heap_findItem(void* p); -void Heap_unlink(char* file, int line, void* p); -#ifdef __cplusplus - } -#endif - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/LinkedList.h b/src/communication/pub_gps/include/paho_mqtt_3c/LinkedList.h deleted file mode 100644 index 102a4fd..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/LinkedList.h +++ /dev/null @@ -1,105 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2013 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs - updates for the async client - * Ian Craggs - change size types from int to size_t - *******************************************************************************/ - -#if !defined(LINKEDLIST_H) -#define LINKEDLIST_H - -#include /* for size_t definition */ - -/*BE -defm defList(T) - -def T concat Item -{ - at 4 - n32 ptr T concat Item suppress "next" - at 0 - n32 ptr T concat Item suppress "prev" - at 8 - n32 ptr T id2str(T) -} - -def T concat List -{ - n32 ptr T concat Item suppress "first" - n32 ptr T concat Item suppress "last" - n32 ptr T concat Item suppress "current" - n32 dec "count" - n32 suppress "size" -} -endm - -defList(INT) -defList(STRING) -defList(TMP) - -BE*/ - -/** - * Structure to hold all data for one list element - */ -typedef struct ListElementStruct -{ - struct ListElementStruct *prev, /**< pointer to previous list element */ - *next; /**< pointer to next list element */ - void* content; /**< pointer to element content */ -} ListElement; - - -/** - * Structure to hold all data for one list - */ -typedef struct -{ - ListElement *first, /**< first element in the list */ - *last, /**< last element in the list */ - *current; /**< current element in the list, for iteration */ - int count; /**< no of items */ - size_t size; /**< heap storage used */ -} List; - -void ListZero(List*); -List* ListInitialize(void); - -void ListAppend(List* aList, void* content, size_t size); -void ListAppendNoMalloc(List* aList, void* content, ListElement* newel, size_t size); -void ListInsert(List* aList, void* content, size_t size, ListElement* index); - -int ListRemove(List* aList, void* content); -int ListRemoveItem(List* aList, void* content, int(*callback)(void*, void*)); -void* ListDetachHead(List* aList); -int ListRemoveHead(List* aList); -void* ListPopTail(List* aList); - -int ListDetach(List* aList, void* content); -int ListDetachItem(List* aList, void* content, int(*callback)(void*, void*)); - -void ListFree(List* aList); -void ListEmpty(List* aList); -void ListFreeNoContent(List* aList); - -ListElement* ListNextElement(List* aList, ListElement** pos); -ListElement* ListPrevElement(List* aList, ListElement** pos); - -ListElement* ListFind(List* aList, void* content); -ListElement* ListFindItem(List* aList, void* content, int(*callback)(void*, void*)); - -int intcompare(void* a, void* b); -int stringcompare(void* a, void* b); - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/Log.h b/src/communication/pub_gps/include/paho_mqtt_3c/Log.h deleted file mode 100644 index 455beb6..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/Log.h +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2013 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs - updates for the async client - *******************************************************************************/ - -#if !defined(LOG_H) -#define LOG_H - -/*BE -map LOG_LEVELS -{ - "TRACE_MAXIMUM" 1 - "TRACE_MEDIUM" 2 - "TRACE_MINIMUM" 3 - "TRACE_PROTOCOL" 4 - - "ERROR" 5 - "SEVERE" 6 - "FATAL" 7 -} -BE*/ - -enum LOG_LEVELS { - INVALID_LEVEL = -1, - TRACE_MAXIMUM = 1, - TRACE_MEDIUM, - TRACE_MINIMUM, - TRACE_PROTOCOL, - LOG_ERROR, - LOG_SEVERE, - LOG_FATAL, -}; - - -/*BE -def trace_settings_type -{ - n32 map LOG_LEVELS "trace_level" - n32 dec "max_trace_entries" - n32 dec "trace_output_level" -} -BE*/ -typedef struct -{ - enum LOG_LEVELS trace_level; /**< trace level */ - int max_trace_entries; /**< max no of entries in the trace buffer */ - enum LOG_LEVELS trace_output_level; /**< trace level to output to destination */ -} trace_settings_type; - -extern trace_settings_type trace_settings; - -#define LOG_PROTOCOL TRACE_PROTOCOL -#define TRACE_MAX TRACE_MAXIMUM -#define TRACE_MIN TRACE_MINIMUM -#define TRACE_MED TRACE_MEDIUM - -typedef struct -{ - const char* name; - const char* value; -} Log_nameValue; - -int Log_initialize(Log_nameValue*); -void Log_terminate(void); - -void Log(enum LOG_LEVELS, int, const char *, ...); -void Log_stackTrace(enum LOG_LEVELS, int, int, int, const char*, int, int*); - -typedef void Log_traceCallback(enum LOG_LEVELS level, const char *message); -void Log_setTraceCallback(Log_traceCallback* callback); -void Log_setTraceLevel(enum LOG_LEVELS level); - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTAsync.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTAsync.h deleted file mode 100644 index 7b2067a..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTAsync.h +++ /dev/null @@ -1,2068 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation - * Ian Craggs, Allan Stockdill-Mander - SSL connections - * Ian Craggs - multiple server connection support - * Ian Craggs - MQTT 3.1.1 support - * Ian Craggs - fix for bug 444103 - success/failure callbacks not invoked - * Ian Craggs - automatic reconnect and offline buffering (send while disconnected) - * Ian Craggs - binary will message - * Ian Craggs - binary password - * Ian Craggs - remove const on eyecatchers #168 - * Ian Craggs - MQTT 5.0 - *******************************************************************************/ - -/********************************************************************/ - -/** - * @cond MQTTAsync_main - * @mainpage Asynchronous MQTT client library for C - * - * © Copyright IBM Corp. 2009, 2018 - * - * @brief An Asynchronous MQTT client library for C. - * - * An MQTT client application connects to MQTT-capable servers. - * A typical client is responsible for collecting information from a telemetry - * device and publishing the information to the server. It can also subscribe - * to topics, receive messages, and use this information to control the - * telemetry device. - * - * MQTT clients implement the published MQTT v3 protocol. You can write your own - * API to the MQTT protocol using the programming language and platform of your - * choice. This can be time-consuming and error-prone. - * - * To simplify writing MQTT client applications, this library encapsulates - * the MQTT v3 protocol for you. Using this library enables a fully functional - * MQTT client application to be written in a few lines of code. - * The information presented here documents the API provided - * by the Asynchronous MQTT Client library for C. - * - * Using the client
- * Applications that use the client library typically use a similar structure: - *
    - *
  • Create a client object
  • - *
  • Set the options to connect to an MQTT server
  • - *
  • Set up callback functions
  • - *
  • Connect the client to an MQTT server
  • - *
  • Subscribe to any topics the client needs to receive
  • - *
  • Repeat until finished:
  • - *
      - *
    • Publish any messages the client needs to
    • - *
    • Handle any incoming messages
    • - *
    - *
  • Disconnect the client
  • - *
  • Free any memory being used by the client
  • - *
- * Some simple examples are shown here: - *
    - *
  • @ref publish
  • - *
  • @ref subscribe
  • - *
- * Additional information about important concepts is provided here: - *
    - *
  • @ref async
  • - *
  • @ref wildcard
  • - *
  • @ref qos
  • - *
  • @ref tracing
  • - *
  • @ref auto_reconnect
  • - *
  • @ref offline_publish
  • - *
- * @endcond - */ - -/* -/// @cond EXCLUDE -*/ -#if !defined(MQTTASYNC_H) -#define MQTTASYNC_H - -#if defined(__cplusplus) - extern "C" { -#endif - -#if defined(WIN32) || defined(WIN64) - #define DLLImport __declspec(dllimport) - #define DLLExport __declspec(dllexport) -#else - #define DLLImport extern - #define DLLExport __attribute__ ((visibility ("default"))) -#endif - -#include -/* -/// @endcond -*/ - -#include "MQTTProperties.h" -#include "MQTTReasonCodes.h" -#include "MQTTSubscribeOpts.h" -#if !defined(NO_PERSISTENCE) -#include "MQTTClientPersistence.h" -#endif - -/** - * Return code: No error. Indicates successful completion of an MQTT client - * operation. - */ -#define MQTTASYNC_SUCCESS 0 -/** - * Return code: A generic error code indicating the failure of an MQTT client - * operation. - */ -#define MQTTASYNC_FAILURE -1 - -/* error code -2 is MQTTAsync_PERSISTENCE_ERROR */ - -#define MQTTASYNC_PERSISTENCE_ERROR -2 - -/** - * Return code: The client is disconnected. - */ -#define MQTTASYNC_DISCONNECTED -3 -/** - * Return code: The maximum number of messages allowed to be simultaneously - * in-flight has been reached. - */ -#define MQTTASYNC_MAX_MESSAGES_INFLIGHT -4 -/** - * Return code: An invalid UTF-8 string has been detected. - */ -#define MQTTASYNC_BAD_UTF8_STRING -5 -/** - * Return code: A NULL parameter has been supplied when this is invalid. - */ -#define MQTTASYNC_NULL_PARAMETER -6 -/** - * Return code: The topic has been truncated (the topic string includes - * embedded NULL characters). String functions will not access the full topic. - * Use the topic length value to access the full topic. - */ -#define MQTTASYNC_TOPICNAME_TRUNCATED -7 -/** - * Return code: A structure parameter does not have the correct eyecatcher - * and version number. - */ -#define MQTTASYNC_BAD_STRUCTURE -8 -/** - * Return code: A qos parameter is not 0, 1 or 2 - */ -#define MQTTASYNC_BAD_QOS -9 -/** - * Return code: All 65535 MQTT msgids are being used - */ -#define MQTTASYNC_NO_MORE_MSGIDS -10 -/** - * Return code: the request is being discarded when not complete - */ -#define MQTTASYNC_OPERATION_INCOMPLETE -11 -/** - * Return code: no more messages can be buffered - */ -#define MQTTASYNC_MAX_BUFFERED_MESSAGES -12 -/** - * Return code: Attempting SSL connection using non-SSL version of library - */ -#define MQTTASYNC_SSL_NOT_SUPPORTED -13 -/** - * Return code: protocol prefix in serverURI should be tcp:// or ssl:// - */ -#define MQTTASYNC_BAD_PROTOCOL -14 - /** - * Return code: don't use options for another version of MQTT - */ - #define MQTTASYNC_BAD_MQTT_OPTION -15 - /** - * Return code: call not applicable to the client's version of MQTT - */ - #define MQTTASYNC_WRONG_MQTT_VERSION -16 - - -/** - * Default MQTT version to connect with. Use 3.1.1 then fall back to 3.1 - */ -#define MQTTVERSION_DEFAULT 0 -/** - * MQTT version to connect with: 3.1 - */ -#define MQTTVERSION_3_1 3 -/** - * MQTT version to connect with: 3.1.1 - */ -#define MQTTVERSION_3_1_1 4 -/** - * MQTT version to connect with: 5 - */ -#define MQTTVERSION_5 5 -/** - * Bad return code from subscribe, as defined in the 3.1.1 specification - */ -#define MQTT_BAD_SUBSCRIBE 0x80 - - -/** - * Initialization options - */ -typedef struct -{ - /** The eyecatcher for this structure. Must be MQTG. */ - char struct_id[4]; - /** The version number of this structure. Must be 0 */ - int struct_version; - /** 1 = we do openssl init, 0 = leave it to the application */ - int do_openssl_init; -} MQTTAsync_init_options; - -#define MQTTAsync_init_options_initializer { {'M', 'Q', 'T', 'G'}, 0, 0 } - -/** - * Global init of mqtt library. Call once on program start to set global behaviour. - * handle_openssl_init - if mqtt library should handle openssl init (1) or rely on the caller to init it before using mqtt (0) - */ -DLLExport void MQTTAsync_global_init(MQTTAsync_init_options* inits); - -/** - * A handle representing an MQTT client. A valid client handle is available - * following a successful call to MQTTAsync_create(). - */ -typedef void* MQTTAsync; -/** - * A value representing an MQTT message. A token is returned to the - * client application when a message is published. The token can then be used to - * check that the message was successfully delivered to its destination (see - * MQTTAsync_publish(), - * MQTTAsync_publishMessage(), - * MQTTAsync_deliveryComplete(), and - * MQTTAsync_getPendingTokens()). - */ -typedef int MQTTAsync_token; - -/** - * A structure representing the payload and attributes of an MQTT message. The - * message topic is not part of this structure (see MQTTAsync_publishMessage(), - * MQTTAsync_publish(), MQTTAsync_receive(), MQTTAsync_freeMessage() - * and MQTTAsync_messageArrived()). - */ -typedef struct -{ - /** The eyecatcher for this structure. must be MQTM. */ - char struct_id[4]; - /** The version number of this structure. Must be 0 or 1. - * 0 indicates no message properties */ - int struct_version; - /** The length of the MQTT message payload in bytes. */ - int payloadlen; - /** A pointer to the payload of the MQTT message. */ - void* payload; - /** - * The quality of service (QoS) assigned to the message. - * There are three levels of QoS: - *
- *
QoS0
- *
Fire and forget - the message may not be delivered
- *
QoS1
- *
At least once - the message will be delivered, but may be - * delivered more than once in some circumstances.
- *
QoS2
- *
Once and one only - the message will be delivered exactly once.
- *
- */ - int qos; - /** - * The retained flag serves two purposes depending on whether the message - * it is associated with is being published or received. - * - * retained = true
- * For messages being published, a true setting indicates that the MQTT - * server should retain a copy of the message. The message will then be - * transmitted to new subscribers to a topic that matches the message topic. - * For subscribers registering a new subscription, the flag being true - * indicates that the received message is not a new one, but one that has - * been retained by the MQTT server. - * - * retained = false
- * For publishers, this indicates that this message should not be retained - * by the MQTT server. For subscribers, a false setting indicates this is - * a normal message, received as a result of it being published to the - * server. - */ - int retained; - /** - * The dup flag indicates whether or not this message is a duplicate. - * It is only meaningful when receiving QoS1 messages. When true, the - * client application should take appropriate action to deal with the - * duplicate message. - */ - int dup; - /** The message identifier is normally reserved for internal use by the - * MQTT client and server. - */ - int msgid; - /** - * The MQTT V5 properties associated with the message. - */ - MQTTProperties properties; -} MQTTAsync_message; - -#define MQTTAsync_message_initializer { {'M', 'Q', 'T', 'M'}, 1, 0, NULL, 0, 0, 0, 0, MQTTProperties_initializer } - -/** - * This is a callback function. The client application - * must provide an implementation of this function to enable asynchronous - * receipt of messages. The function is registered with the client library by - * passing it as an argument to MQTTAsync_setCallbacks(). It is - * called by the client library when a new message that matches a client - * subscription has been received from the server. This function is executed on - * a separate thread to the one on which the client application is running. - * @param context A pointer to the context value originally passed to - * MQTTAsync_setCallbacks(), which contains any application-specific context. - * @param topicName The topic associated with the received message. - * @param topicLen The length of the topic if there are one - * more NULL characters embedded in topicName, otherwise topicLen - * is 0. If topicLen is 0, the value returned by strlen(topicName) - * can be trusted. If topicLen is greater than 0, the full topic name - * can be retrieved by accessing topicName as a byte array of length - * topicLen. - * @param message The MQTTAsync_message structure for the received message. - * This structure contains the message payload and attributes. - * @return This function must return a boolean value indicating whether or not - * the message has been safely received by the client application. Returning - * true indicates that the message has been successfully handled. - * Returning false indicates that there was a problem. In this - * case, the client library will reinvoke MQTTAsync_messageArrived() to - * attempt to deliver the message to the application again. - */ -typedef int MQTTAsync_messageArrived(void* context, char* topicName, int topicLen, MQTTAsync_message* message); - -/** - * This is a callback function. The client application - * must provide an implementation of this function to enable asynchronous - * notification of delivery of messages to the server. The function is - * registered with the client library by passing it as an argument to MQTTAsync_setCallbacks(). - * It is called by the client library after the client application has - * published a message to the server. It indicates that the necessary - * handshaking and acknowledgements for the requested quality of service (see - * MQTTAsync_message.qos) have been completed. This function is executed on a - * separate thread to the one on which the client application is running. - * @param context A pointer to the context value originally passed to - * MQTTAsync_setCallbacks(), which contains any application-specific context. - * @param token The ::MQTTAsync_token associated with - * the published message. Applications can check that all messages have been - * correctly published by matching the tokens returned from calls to - * MQTTAsync_send() and MQTTAsync_sendMessage() with the tokens passed - * to this callback. - */ -typedef void MQTTAsync_deliveryComplete(void* context, MQTTAsync_token token); - -/** - * This is a callback function. The client application - * must provide an implementation of this function to enable asynchronous - * notification of the loss of connection to the server. The function is - * registered with the client library by passing it as an argument to - * MQTTAsync_setCallbacks(). It is called by the client library if the client - * loses its connection to the server. The client application must take - * appropriate action, such as trying to reconnect or reporting the problem. - * This function is executed on a separate thread to the one on which the - * client application is running. - * @param context A pointer to the context value originally passed to - * MQTTAsync_setCallbacks(), which contains any application-specific context. - * @param cause The reason for the disconnection. - * Currently, cause is always set to NULL. - */ -typedef void MQTTAsync_connectionLost(void* context, char* cause); - - -/** - * This is a callback function, which will be called when the client - * library successfully connects. This is superfluous when the connection - * is made in response to a MQTTAsync_connect call, because the onSuccess - * callback can be used. It is intended for use when automatic reconnect - * is enabled, so that when a reconnection attempt succeeds in the background, - * the application is notified and can take any required actions. - * @param context A pointer to the context value originally passed to - * MQTTAsync_setCallbacks(), which contains any application-specific context. - * @param cause The reason for the disconnection. - * Currently, cause is always set to NULL. - */ -typedef void MQTTAsync_connected(void* context, char* cause); - -/** - * This is a callback function, which will be called when the client - * library receives a disconnect packet. - * @param context A pointer to the context value originally passed to - * MQTTAsync_setCallbacks(), which contains any application-specific context. - * @param properties the properties in the disconnect packet. - * @param properties the reason code from the disconnect packet - * Currently, cause is always set to NULL. - */ -typedef void MQTTAsync_disconnected(void* context, MQTTProperties* properties, - enum MQTTReasonCodes reasonCode); - -/** - * Sets the MQTTAsync_disconnected() callback function for a client. - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param context A pointer to any application-specific context. The - * the context pointer is passed to each of the callback functions to - * provide access to the context information in the callback. - * @param co A pointer to an MQTTAsync_connected() callback - * function. NULL removes the callback setting. - * @return ::MQTTASYNC_SUCCESS if the callbacks were correctly set, - * ::MQTTASYNC_FAILURE if an error occurred. - */ -DLLExport int MQTTAsync_setDisconnected(MQTTAsync handle, void* context, MQTTAsync_disconnected* co); - - -/** The data returned on completion of an unsuccessful API call in the response callback onFailure. */ -typedef struct -{ - /** A token identifying the failed request. */ - MQTTAsync_token token; - /** A numeric code identifying the error. */ - int code; - /** Optional text explaining the error. Can be NULL. */ - const char *message; -} MQTTAsync_failureData; - - -/** The data returned on completion of an unsuccessful API call in the response callback onFailure. */ -typedef struct -{ - /** The eyecatcher for this structure. Will be MQFD. */ - char struct_id[4]; - /** The version number of this structure. Will be 0 */ - int struct_version; - /** A token identifying the failed request. */ - MQTTAsync_token token; - /** The MQTT reason code returned. */ - enum MQTTReasonCodes reasonCode; - /** The MQTT properties on the ack, if any. */ - MQTTProperties properties; - /** A numeric code identifying the MQTT client library error. */ - int code; - /** Optional further text explaining the error. Can be NULL. */ - const char *message; - /** Packet type on which the failure occurred - used for publish QoS 1/2 exchanges*/ - int packet_type; -} MQTTAsync_failureData5; - -#define MQTTAsync_failureData5_initializer {{'M', 'Q', 'F', 'D'}, 0, 0, MQTTREASONCODE_SUCCESS, MQTTProperties_initializer, 0, NULL} - -/** The data returned on completion of a successful API call in the response callback onSuccess. */ -typedef struct -{ - /** A token identifying the successful request. Can be used to refer to the request later. */ - MQTTAsync_token token; - /** A union of the different values that can be returned for subscribe, unsubscribe and publish. */ - union - { - /** For subscribe, the granted QoS of the subscription returned by the server. */ - int qos; - /** For subscribeMany, the list of granted QoSs of the subscriptions returned by the server. */ - int* qosList; - /** For publish, the message being sent to the server. */ - struct - { - MQTTAsync_message message; - char* destinationName; - } pub; - /* For connect, the server connected to, MQTT version used, and sessionPresent flag */ - struct - { - char* serverURI; - int MQTTVersion; - int sessionPresent; - } connect; - } alt; -} MQTTAsync_successData; - - -/** The data returned on completion of a successful API call in the response callback onSuccess. */ -typedef struct -{ - char struct_id[4]; /**< The eyecatcher for this structure. Will be MQSD. */ - int struct_version; /**< The version number of this structure. Will be 0 */ - /** A token identifying the successful request. Can be used to refer to the request later. */ - MQTTAsync_token token; - enum MQTTReasonCodes reasonCode; /**< MQTT V5 reason code returned */ - MQTTProperties properties; /**< MQTT V5 properties returned, if any */ - /** A union of the different values that can be returned for subscribe, unsubscribe and publish. */ - union - { - /** For subscribeMany, the list of reasonCodes returned by the server. */ - struct - { - int reasonCodeCount; /**< the number of reason codes in the reasonCodes array */ - enum MQTTReasonCodes* reasonCodes; /**< an array of reasonCodes */ - } sub; - /** For publish, the message being sent to the server. */ - struct - { - MQTTAsync_message message; /**< the message being sent to the server */ - char* destinationName; /**< the topic destination for the message */ - } pub; - /* For connect, the server connected to, MQTT version used, and sessionPresent flag */ - struct - { - char* serverURI; /**< the connection string of the server */ - int MQTTVersion; /**< the version of MQTT being used */ - int sessionPresent; /**< the session present flag returned from the server */ - } connect; - /** For unsubscribeMany, the list of reasonCodes returned by the server. */ - struct - { - int reasonCodeCount; /**< the number of reason codes in the reasonCodes array */ - enum MQTTReasonCodes* reasonCodes; /**< an array of reasonCodes */ - } unsub; - } alt; -} MQTTAsync_successData5; - -#define MQTTAsync_successData5_initializer {{'M', 'Q', 'S', 'D'}, 0, 0, MQTTREASONCODE_SUCCESS, MQTTProperties_initializer} - -/** - * This is a callback function. The client application - * must provide an implementation of this function to enable asynchronous - * notification of the successful completion of an API call. The function is - * registered with the client library by passing it as an argument in - * ::MQTTAsync_responseOptions. - * @param context A pointer to the context value originally passed to - * ::MQTTAsync_responseOptions, which contains any application-specific context. - * @param response Any success data associated with the API completion. - */ -typedef void MQTTAsync_onSuccess(void* context, MQTTAsync_successData* response); - -/** - * This is a callback function, the MQTT V5 version of ::MQTTAsync_onSuccess. - * The client application - * must provide an implementation of this function to enable asynchronous - * notification of the successful completion of an API call. The function is - * registered with the client library by passing it as an argument in - * ::MQTTAsync_responseOptions. - * @param context A pointer to the context value originally passed to - * ::MQTTAsync_responseOptions, which contains any application-specific context. - * @param response Any success data associated with the API completion. - */ -typedef void MQTTAsync_onSuccess5(void* context, MQTTAsync_successData5* response); - -/** - * This is a callback function. The client application - * must provide an implementation of this function to enable asynchronous - * notification of the unsuccessful completion of an API call. The function is - * registered with the client library by passing it as an argument in - * ::MQTTAsync_responseOptions. - * @param context A pointer to the context value originally passed to - * ::MQTTAsync_responseOptions, which contains any application-specific context. - * @param response Failure data associated with the API completion. - */ -typedef void MQTTAsync_onFailure(void* context, MQTTAsync_failureData* response); - -/** - * This is a callback function, the MQTT V5 version of ::MQTTAsync_onFailure. - * The application must provide an implementation of this function to enable asynchronous - * notification of the unsuccessful completion of an API call. The function is - * registered with the client library by passing it as an argument in - * ::MQTTAsync_responseOptions. - * @param context A pointer to the context value originally passed to - * ::MQTTAsync_responseOptions, which contains any application-specific context. - * @param response Failure data associated with the API completion. - */ -typedef void MQTTAsync_onFailure5(void* context, MQTTAsync_failureData5* response); - -typedef struct MQTTAsync_responseOptions -{ - /** The eyecatcher for this structure. Must be MQTR */ - char struct_id[4]; - /** The version number of this structure. Must be 0 or 1 - * if 0, no MQTTV5 options */ - int struct_version; - /** - * A pointer to a callback function to be called if the API call successfully - * completes. Can be set to NULL, in which case no indication of successful - * completion will be received. - */ - MQTTAsync_onSuccess* onSuccess; - /** - * A pointer to a callback function to be called if the API call fails. - * Can be set to NULL, in which case no indication of unsuccessful - * completion will be received. - */ - MQTTAsync_onFailure* onFailure; - /** - * A pointer to any application-specific context. The - * the context pointer is passed to success or failure callback functions to - * provide access to the context information in the callback. - */ - void* context; - /** - * A token is returned from the call. It can be used to track - * the state of this request, both in the callbacks and in future calls - * such as ::MQTTAsync_waitForCompletion. - */ - MQTTAsync_token token; - /** - * A pointer to a callback function to be called if the API call successfully - * completes. Can be set to NULL, in which case no indication of successful - * completion will be received. - */ - MQTTAsync_onSuccess5* onSuccess5; - /** - * A pointer to a callback function to be called if the API call successfully - * completes. Can be set to NULL, in which case no indication of successful - * completion will be received. - */ - MQTTAsync_onFailure5* onFailure5; - /** - * MQTT V5 input properties - */ - MQTTProperties properties; - /* - * MQTT V5 subscribe options, when used with subscribe only. - */ - MQTTSubscribe_options subscribeOptions; - /* - * MQTT V5 subscribe option count, when used with subscribeMany only. - * The number of entries in the subscribe_options_list array. - */ - int subscribeOptionsCount; - /* - * MQTT V5 subscribe option array, when used with subscribeMany only. - */ - MQTTSubscribe_options* subscribeOptionsList; -} MQTTAsync_responseOptions; - -#define MQTTAsync_responseOptions_initializer { {'M', 'Q', 'T', 'R'}, 1, NULL, NULL, 0, 0, NULL, NULL, MQTTProperties_initializer, MQTTSubscribe_options_initializer, 0, NULL} - -typedef struct MQTTAsync_responseOptions MQTTAsync_callOptions; -#define MQTTAsync_callOptions_initializer MQTTAsync_responseOptions_initializer - -/** - * This function sets the global callback functions for a specific client. - * If your client application doesn't use a particular callback, set the - * relevant parameter to NULL. Any necessary message acknowledgements and - * status communications are handled in the background without any intervention - * from the client application. If you do not set a messageArrived callback - * function, you will not be notified of the receipt of any messages as a - * result of a subscription. - * - * Note: The MQTT client must be disconnected when this function is - * called. - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param context A pointer to any application-specific context. The - * the context pointer is passed to each of the callback functions to - * provide access to the context information in the callback. - * @param cl A pointer to an MQTTAsync_connectionLost() callback - * function. You can set this to NULL if your application doesn't handle - * disconnections. - * @param ma A pointer to an MQTTAsync_messageArrived() callback - * function. You can set this to NULL if your application doesn't handle - * receipt of messages. - * @param dc A pointer to an MQTTAsync_deliveryComplete() callback - * function. You can set this to NULL if you do not want to check - * for successful delivery. - * @return ::MQTTASYNC_SUCCESS if the callbacks were correctly set, - * ::MQTTASYNC_FAILURE if an error occurred. - */ -DLLExport int MQTTAsync_setCallbacks(MQTTAsync handle, void* context, MQTTAsync_connectionLost* cl, - MQTTAsync_messageArrived* ma, MQTTAsync_deliveryComplete* dc); - -/** - * This function sets the callback function for a connection lost event for - * a specific client. Any necessary message acknowledgements and status - * communications are handled in the background without any intervention - * from the client application. - * - * Note: The MQTT client must be disconnected when this function is - * called. - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param context A pointer to any application-specific context. The - * the context pointer is passed the callback functions to provide - * access to the context information in the callback. - * @param cl A pointer to an MQTTAsync_connectionLost() callback - * function. You can set this to NULL if your application doesn't handle - * disconnections. - * @return ::MQTTASYNC_SUCCESS if the callbacks were correctly set, - * ::MQTTASYNC_FAILURE if an error occurred. - */ - -DLLExport int MQTTAsync_setConnectionLostCallback(MQTTAsync handle, void* context, - MQTTAsync_connectionLost* cl); - -/** - * This function sets the callback function for a message arrived event for - * a specific client. Any necessary message acknowledgements and status - * communications are handled in the background without any intervention - * from the client application. If you do not set a messageArrived callback - * function, you will not be notified of the receipt of any messages as a - * result of a subscription. - * - * Note: The MQTT client must be disconnected when this function is - * called. - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param context A pointer to any application-specific context. The - * the context pointer is passed to the callback functions to provide - * access to the context information in the callback. - * @param ma A pointer to an MQTTAsync_messageArrived() callback - * function. You can set this to NULL if your application doesn't handle - * receipt of messages. - * @return ::MQTTASYNC_SUCCESS if the callbacks were correctly set, - * ::MQTTASYNC_FAILURE if an error occurred. - */ -DLLExport int MQTTAsync_setMessageArrivedCallback(MQTTAsync handle, void* context, - MQTTAsync_messageArrived* ma); - -/** - * This function sets the callback function for a delivery complete event - * for a specific client. Any necessary message acknowledgements and status - * communications are handled in the background without any intervention - * from the client application. - * - * Note: The MQTT client must be disconnected when this function is - * called. - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param context A pointer to any application-specific context. The - * the context pointer is passed to the callback functions to provide - * access to the context information in the callback. - * @param dc A pointer to an MQTTAsync_deliveryComplete() callback - * function. You can set this to NULL if you do not want to check - * for successful delivery. - * @return ::MQTTASYNC_SUCCESS if the callbacks were correctly set, - * ::MQTTASYNC_FAILURE if an error occurred. - */ -DLLExport int MQTTAsync_setDeliveryCompleteCallback(MQTTAsync handle, void* context, - MQTTAsync_deliveryComplete* dc); - -/** - * Sets the MQTTAsync_connected() callback function for a client. - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param context A pointer to any application-specific context. The - * the context pointer is passed to each of the callback functions to - * provide access to the context information in the callback. - * @param co A pointer to an MQTTAsync_connected() callback - * function. NULL removes the callback setting. - * @return ::MQTTASYNC_SUCCESS if the callbacks were correctly set, - * ::MQTTASYNC_FAILURE if an error occurred. - */ -DLLExport int MQTTAsync_setConnected(MQTTAsync handle, void* context, MQTTAsync_connected* co); - - -/** - * Reconnects a client with the previously used connect options. Connect - * must have previously been called for this to work. - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @return ::MQTTASYNC_SUCCESS if the callbacks were correctly set, - * ::MQTTASYNC_FAILURE if an error occurred. - */ -DLLExport int MQTTAsync_reconnect(MQTTAsync handle); - - -/** - * This function creates an MQTT client ready for connection to the - * specified server and using the specified persistent storage (see - * MQTTAsync_persistence). See also MQTTAsync_destroy(). - * @param handle A pointer to an ::MQTTAsync handle. The handle is - * populated with a valid client reference following a successful return from - * this function. - * @param serverURI A null-terminated string specifying the server to - * which the client will connect. It takes the form protocol://host:port. - * protocol must be tcp or ssl. For host, you can - * specify either an IP address or a host name. For instance, to connect to - * a server running on the local machines with the default MQTT port, specify - * tcp://localhost:1883. - * @param clientId The client identifier passed to the server when the - * client connects to it. It is a null-terminated UTF-8 encoded string. - * @param persistence_type The type of persistence to be used by the client: - *
- * ::MQTTCLIENT_PERSISTENCE_NONE: Use in-memory persistence. If the device or - * system on which the client is running fails or is switched off, the current - * state of any in-flight messages is lost and some messages may not be - * delivered even at QoS1 and QoS2. - *
- * ::MQTTCLIENT_PERSISTENCE_DEFAULT: Use the default (file system-based) - * persistence mechanism. Status about in-flight messages is held in persistent - * storage and provides some protection against message loss in the case of - * unexpected failure. - *
- * ::MQTTCLIENT_PERSISTENCE_USER: Use an application-specific persistence - * implementation. Using this type of persistence gives control of the - * persistence mechanism to the application. The application has to implement - * the MQTTClient_persistence interface. - * @param persistence_context If the application uses - * ::MQTTCLIENT_PERSISTENCE_NONE persistence, this argument is unused and should - * be set to NULL. For ::MQTTCLIENT_PERSISTENCE_DEFAULT persistence, it - * should be set to the location of the persistence directory (if set - * to NULL, the persistence directory used is the working directory). - * Applications that use ::MQTTCLIENT_PERSISTENCE_USER persistence set this - * argument to point to a valid MQTTClient_persistence structure. - * @return ::MQTTASYNC_SUCCESS if the client is successfully created, otherwise - * an error code is returned. - */ -DLLExport int MQTTAsync_create(MQTTAsync* handle, const char* serverURI, const char* clientId, - int persistence_type, void* persistence_context); - -typedef struct -{ - /** The eyecatcher for this structure. must be MQCO. */ - char struct_id[4]; - /** The version number of this structure. Must be 0 or 1 - * 0 means no MQTTVersion - */ - int struct_version; - /** Whether to allow messages to be sent when the client library is not connected. */ - int sendWhileDisconnected; - /** the maximum number of messages allowed to be buffered while not connected. */ - int maxBufferedMessages; - /** Whether the MQTT version is 3.1, 3.1.1, or 5. To use V5, this must be set. - * MQTT V5 has to be chosen here, because during the create call the message persistence - * is initialized, and we want to know whether the format of any persisted messages - * is appropriate for the MQTT version we are going to connect with. Selecting 3.1 or - * 3.1.1 and attempting to read 5.0 persisted messages will result in an error on create. */ - int MQTTVersion; -} MQTTAsync_createOptions; - -#define MQTTAsync_createOptions_initializer { {'M', 'Q', 'C', 'O'}, 0, 0, 100, MQTTVERSION_DEFAULT } - - -DLLExport int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverURI, const char* clientId, - int persistence_type, void* persistence_context, MQTTAsync_createOptions* options); - -/** - * MQTTAsync_willOptions defines the MQTT "Last Will and Testament" (LWT) settings for - * the client. In the event that a client unexpectedly loses its connection to - * the server, the server publishes the LWT message to the LWT topic on - * behalf of the client. This allows other clients (subscribed to the LWT topic) - * to be made aware that the client has disconnected. To enable the LWT - * function for a specific client, a valid pointer to an MQTTAsync_willOptions - * structure is passed in the MQTTAsync_connectOptions structure used in the - * MQTTAsync_connect() call that connects the client to the server. The pointer - * to MQTTAsync_willOptions can be set to NULL if the LWT function is not - * required. - */ -typedef struct -{ - /** The eyecatcher for this structure. must be MQTW. */ - char struct_id[4]; - /** The version number of this structure. Must be 0 or 1 - 0 indicates no binary will message support - */ - int struct_version; - /** The LWT topic to which the LWT message will be published. */ - const char* topicName; - /** The LWT payload. */ - const char* message; - /** - * The retained flag for the LWT message (see MQTTAsync_message.retained). - */ - int retained; - /** - * The quality of service setting for the LWT message (see - * MQTTAsync_message.qos and @ref qos). - */ - int qos; - /** The LWT payload in binary form. This is only checked and used if the message option is NULL */ - struct - { - int len; /**< binary payload length */ - const void* data; /**< binary payload data */ - } payload; -} MQTTAsync_willOptions; - -#define MQTTAsync_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 1, NULL, NULL, 0, 0, { 0, NULL } } - -#define MQTT_SSL_VERSION_DEFAULT 0 -#define MQTT_SSL_VERSION_TLS_1_0 1 -#define MQTT_SSL_VERSION_TLS_1_1 2 -#define MQTT_SSL_VERSION_TLS_1_2 3 - -/** -* MQTTAsync_sslProperties defines the settings to establish an SSL/TLS connection using the -* OpenSSL library. It covers the following scenarios: -* - Server authentication: The client needs the digital certificate of the server. It is included -* in a store containting trusted material (also known as "trust store"). -* - Mutual authentication: Both client and server are authenticated during the SSL handshake. In -* addition to the digital certificate of the server in a trust store, the client will need its own -* digital certificate and the private key used to sign its digital certificate stored in a "key store". -* - Anonymous connection: Both client and server do not get authenticated and no credentials are needed -* to establish an SSL connection. Note that this scenario is not fully secure since it is subject to -* man-in-the-middle attacks. -*/ -typedef struct -{ - /** The eyecatcher for this structure. Must be MQTS */ - char struct_id[4]; - /** The version number of this structure. Must be 0, or 1 to enable TLS version selection. */ - int struct_version; - - /** The file in PEM format containing the public digital certificates trusted by the client. */ - const char* trustStore; - - /** The file in PEM format containing the public certificate chain of the client. It may also include - * the client's private key. - */ - const char* keyStore; - - /** If not included in the sslKeyStore, this setting points to the file in PEM format containing - * the client's private key. - */ - const char* privateKey; - /** The password to load the client's privateKey if encrypted. */ - const char* privateKeyPassword; - - /** - * The list of cipher suites that the client will present to the server during the SSL handshake. For a - * full explanation of the cipher list format, please see the OpenSSL on-line documentation: - * http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT - * If this setting is ommitted, its default value will be "ALL", that is, all the cipher suites -excluding - * those offering no encryption- will be considered. - * This setting can be used to set an SSL anonymous connection ("aNULL" string value, for instance). - */ - const char* enabledCipherSuites; - - /** True/False option to enable verification of the server certificate **/ - int enableServerCertAuth; - - /** The SSL/TLS version to use. Specify one of MQTT_SSL_VERSION_DEFAULT (0), - * MQTT_SSL_VERSION_TLS_1_0 (1), MQTT_SSL_VERSION_TLS_1_1 (2) or MQTT_SSL_VERSION_TLS_1_2 (3). - * Only used if struct_version is >= 1. - */ - int sslVersion; - - /** - * Whether to carry out post-connect checks, including that a certificate - * matches the given host name. - * Exists only if struct_version >= 2 - */ - int verify; - - /** - * From the OpenSSL documentation: - * If CApath is not NULL, it points to a directory containing CA certificates in PEM format. - * Exists only if struct_version >= 2 - */ - const char* CApath; - - /** - * Callback function for OpenSSL error handler ERR_print_errors_cb - * Exists only if struct_version >= 3 - */ - int (*ssl_error_cb) (const char *str, size_t len, void *u); - - /** - * Application-specific contex for OpenSSL error handler ERR_print_errors_cb - * Exists only if struct_version >= 3 - */ - void* ssl_error_context; -} MQTTAsync_SSLOptions; - -#define MQTTAsync_SSLOptions_initializer { {'M', 'Q', 'T', 'S'}, 3, NULL, NULL, NULL, NULL, NULL, 1, MQTT_SSL_VERSION_DEFAULT, 0, NULL, NULL, NULL } - -/** - * MQTTAsync_connectOptions defines several settings that control the way the - * client connects to an MQTT server. Default values are set in - * MQTTAsync_connectOptions_initializer. - */ -typedef struct -{ - /** The eyecatcher for this structure. must be MQTC. */ - char struct_id[4]; - /** The version number of this structure. Must be 0, 1, 2, 3 4 5 or 6. - * 0 signifies no SSL options and no serverURIs - * 1 signifies no serverURIs - * 2 signifies no MQTTVersion - * 3 signifies no automatic reconnect options - * 4 signifies no binary password option (just string) - * 5 signifies no MQTTV5 properties - */ - int struct_version; - /** The "keep alive" interval, measured in seconds, defines the maximum time - * that should pass without communication between the client and the server - * The client will ensure that at least one message travels across the - * network within each keep alive period. In the absence of a data-related - * message during the time period, the client sends a very small MQTT - * "ping" message, which the server will acknowledge. The keep alive - * interval enables the client to detect when the server is no longer - * available without having to wait for the long TCP/IP timeout. - * Set to 0 if you do not want any keep alive processing. - */ - int keepAliveInterval; - /** - * This is a boolean value. The cleansession setting controls the behaviour - * of both the client and the server at connection and disconnection time. - * The client and server both maintain session state information. This - * information is used to ensure "at least once" and "exactly once" - * delivery, and "exactly once" receipt of messages. Session state also - * includes subscriptions created by an MQTT client. You can choose to - * maintain or discard state information between sessions. - * - * When cleansession is true, the state information is discarded at - * connect and disconnect. Setting cleansession to false keeps the state - * information. When you connect an MQTT client application with - * MQTTAsync_connect(), the client identifies the connection using the - * client identifier and the address of the server. The server checks - * whether session information for this client - * has been saved from a previous connection to the server. If a previous - * session still exists, and cleansession=true, then the previous session - * information at the client and server is cleared. If cleansession=false, - * the previous session is resumed. If no previous session exists, a new - * session is started. - */ - int cleansession; - /** - * This controls how many messages can be in-flight simultaneously. - */ - int maxInflight; - /** - * This is a pointer to an MQTTAsync_willOptions structure. If your - * application does not make use of the Last Will and Testament feature, - * set this pointer to NULL. - */ - MQTTAsync_willOptions* will; - /** - * MQTT servers that support the MQTT v3.1 protocol provide authentication - * and authorisation by user name and password. This is the user name - * parameter. - */ - const char* username; - /** - * MQTT servers that support the MQTT v3.1 protocol provide authentication - * and authorisation by user name and password. This is the password - * parameter. - */ - const char* password; - /** - * The time interval in seconds to allow a connect to complete. - */ - int connectTimeout; - /** - * The time interval in seconds after which unacknowledged publish requests are - * retried during a TCP session. With MQTT 3.1.1 and later, retries are - * not required except on reconnect. 0 turns off in-session retries, and is the - * recommended setting. Adding retries to an already overloaded network only - * exacerbates the problem. - */ - int retryInterval; - /** - * This is a pointer to an MQTTAsync_SSLOptions structure. If your - * application does not make use of SSL, set this pointer to NULL. - */ - MQTTAsync_SSLOptions* ssl; - /** - * A pointer to a callback function to be called if the connect successfully - * completes. Can be set to NULL, in which case no indication of successful - * completion will be received. - */ - MQTTAsync_onSuccess* onSuccess; - /** - * A pointer to a callback function to be called if the connect fails. - * Can be set to NULL, in which case no indication of unsuccessful - * completion will be received. - */ - MQTTAsync_onFailure* onFailure; - /** - * A pointer to any application-specific context. The - * the context pointer is passed to success or failure callback functions to - * provide access to the context information in the callback. - */ - void* context; - /** - * The number of entries in the serverURIs array. - */ - int serverURIcount; - /** - * An array of null-terminated strings specifying the servers to - * which the client will connect. Each string takes the form protocol://host:port. - * protocol must be tcp or ssl. For host, you can - * specify either an IP address or a domain name. For instance, to connect to - * a server running on the local machines with the default MQTT port, specify - * tcp://localhost:1883. - */ - char* const* serverURIs; - /** - * Sets the version of MQTT to be used on the connect. - * MQTTVERSION_DEFAULT (0) = default: start with 3.1.1, and if that fails, fall back to 3.1 - * MQTTVERSION_3_1 (3) = only try version 3.1 - * MQTTVERSION_3_1_1 (4) = only try version 3.1.1 - */ - int MQTTVersion; - /** - * Reconnect automatically in the case of a connection being lost? - */ - int automaticReconnect; - /** - * Minimum retry interval in seconds. Doubled on each failed retry. - */ - int minRetryInterval; - /** - * Maximum retry interval in seconds. The doubling stops here on failed retries. - */ - int maxRetryInterval; - /** - * Optional binary password. Only checked and used if the password option is NULL - */ - struct { - int len; /**< binary password length */ - const void* data; /**< binary password data */ - } binarypwd; - /* - * MQTT V5 clean start flag. Only clears state at the beginning of the session. - */ - int cleanstart; - /** - * MQTT V5 properties for connect - */ - MQTTProperties *connectProperties; - /** - * MQTT V5 properties for the will message in the connect - */ - MQTTProperties *willProperties; - /** - * A pointer to a callback function to be called if the connect successfully - * completes. Can be set to NULL, in which case no indication of successful - * completion will be received. - */ - MQTTAsync_onSuccess5* onSuccess5; - /** - * A pointer to a callback function to be called if the connect fails. - * Can be set to NULL, in which case no indication of unsuccessful - * completion will be received. - */ - MQTTAsync_onFailure5* onFailure5; -} MQTTAsync_connectOptions; - - -#define MQTTAsync_connectOptions_initializer { {'M', 'Q', 'T', 'C'}, 6, 60, 1, 65535, NULL, NULL, NULL, 30, 0,\ -NULL, NULL, NULL, NULL, 0, NULL, MQTTVERSION_DEFAULT, 0, 1, 60, {0, NULL}, 0, NULL, NULL, NULL, NULL} - -#define MQTTAsync_connectOptions_initializer5 { {'M', 'Q', 'T', 'C'}, 6, 60, 0, 65535, NULL, NULL, NULL, 30, 0,\ -NULL, NULL, NULL, NULL, 0, NULL, MQTTVERSION_5, 0, 1, 60, {0, NULL}, 1, NULL, NULL, NULL, NULL} - - -/** - * This function attempts to connect a previously-created client (see - * MQTTAsync_create()) to an MQTT server using the specified options. If you - * want to enable asynchronous message and status notifications, you must call - * MQTTAsync_setCallbacks() prior to MQTTAsync_connect(). - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param options A pointer to a valid MQTTAsync_connectOptions - * structure. - * @return ::MQTTASYNC_SUCCESS if the client connect request was accepted. - * If the client was unable to connect to the server, an error code is - * returned via the onFailure callback, if set. - * Error codes greater than 0 are returned by the MQTT protocol:

- * 1: Connection refused: Unacceptable protocol version
- * 2: Connection refused: Identifier rejected
- * 3: Connection refused: Server unavailable
- * 4: Connection refused: Bad user name or password
- * 5: Connection refused: Not authorized
- * 6-255: Reserved for future use
- */ -DLLExport int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options); - - -typedef struct -{ - /** The eyecatcher for this structure. Must be MQTD. */ - char struct_id[4]; - /** The version number of this structure. Must be 0 or 1. 0 signifies no V5 properties */ - int struct_version; - /** - * The client delays disconnection for up to this time (in - * milliseconds) in order to allow in-flight message transfers to complete. - */ - int timeout; - /** - * A pointer to a callback function to be called if the disconnect successfully - * completes. Can be set to NULL, in which case no indication of successful - * completion will be received. - */ - MQTTAsync_onSuccess* onSuccess; - /** - * A pointer to a callback function to be called if the disconnect fails. - * Can be set to NULL, in which case no indication of unsuccessful - * completion will be received. - */ - MQTTAsync_onFailure* onFailure; - /** - * A pointer to any application-specific context. The - * the context pointer is passed to success or failure callback functions to - * provide access to the context information in the callback. - */ - void* context; - /** - * MQTT V5 input properties - */ - MQTTProperties properties; - /** - * Reason code for MQTTV5 disconnect - */ - enum MQTTReasonCodes reasonCode; - /** - * A pointer to a callback function to be called if the disconnect successfully - * completes. Can be set to NULL, in which case no indication of successful - * completion will be received. - */ - MQTTAsync_onSuccess5* onSuccess5; - /** - * A pointer to a callback function to be called if the disconnect fails. - * Can be set to NULL, in which case no indication of unsuccessful - * completion will be received. - */ - MQTTAsync_onFailure5* onFailure5; -} MQTTAsync_disconnectOptions; - -#define MQTTAsync_disconnectOptions_initializer { {'M', 'Q', 'T', 'D'}, 1, 0, NULL, NULL, NULL, MQTTProperties_initializer, MQTTREASONCODE_SUCCESS } - - -/** - * This function attempts to disconnect the client from the MQTT - * server. In order to allow the client time to complete handling of messages - * that are in-flight when this function is called, a timeout period is - * specified. When the timeout period has expired, the client disconnects even - * if there are still outstanding message acknowledgements. - * The next time the client connects to the same server, any QoS 1 or 2 - * messages which have not completed will be retried depending on the - * cleansession settings for both the previous and the new connection (see - * MQTTAsync_connectOptions.cleansession and MQTTAsync_connect()). - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param options The client delays disconnection for up to this time (in - * milliseconds) in order to allow in-flight message transfers to complete. - * @return ::MQTTASYNC_SUCCESS if the client successfully disconnects from - * the server. An error code is returned if the client was unable to disconnect - * from the server - */ -DLLExport int MQTTAsync_disconnect(MQTTAsync handle, const MQTTAsync_disconnectOptions* options); - - -/** - * This function allows the client application to test whether or not a - * client is currently connected to the MQTT server. - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @return Boolean true if the client is connected, otherwise false. - */ -DLLExport int MQTTAsync_isConnected(MQTTAsync handle); - - -/** - * This function attempts to subscribe a client to a single topic, which may - * contain wildcards (see @ref wildcard). This call also specifies the - * @ref qos requested for the subscription - * (see also MQTTAsync_subscribeMany()). - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param topic The subscription topic, which may include wildcards. - * @param qos The requested quality of service for the subscription. - * @param response A pointer to a response options structure. Used to set callback functions. - * @return ::MQTTASYNC_SUCCESS if the subscription request is successful. - * An error code is returned if there was a problem registering the - * subscription. - */ -DLLExport int MQTTAsync_subscribe(MQTTAsync handle, const char* topic, int qos, MQTTAsync_responseOptions* response); - - -/** - * This function attempts to subscribe a client to a list of topics, which may - * contain wildcards (see @ref wildcard). This call also specifies the - * @ref qos requested for each topic (see also MQTTAsync_subscribe()). - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param count The number of topics for which the client is requesting - * subscriptions. - * @param topic An array (of length count) of pointers to - * topics, each of which may include wildcards. - * @param qos An array (of length count) of @ref qos - * values. qos[n] is the requested QoS for topic[n]. - * @param response A pointer to a response options structure. Used to set callback functions. - * @return ::MQTTASYNC_SUCCESS if the subscription request is successful. - * An error code is returned if there was a problem registering the - * subscriptions. - */ -DLLExport int MQTTAsync_subscribeMany(MQTTAsync handle, int count, char* const* topic, int* qos, MQTTAsync_responseOptions* response); - -/** - * This function attempts to remove an existing subscription made by the - * specified client. - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param topic The topic for the subscription to be removed, which may - * include wildcards (see @ref wildcard). - * @param response A pointer to a response options structure. Used to set callback functions. - * @return ::MQTTASYNC_SUCCESS if the subscription is removed. - * An error code is returned if there was a problem removing the - * subscription. - */ -DLLExport int MQTTAsync_unsubscribe(MQTTAsync handle, const char* topic, MQTTAsync_responseOptions* response); - -/** - * This function attempts to remove existing subscriptions to a list of topics - * made by the specified client. - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param count The number subscriptions to be removed. - * @param topic An array (of length count) of pointers to the topics of - * the subscriptions to be removed, each of which may include wildcards. - * @param response A pointer to a response options structure. Used to set callback functions. - * @return ::MQTTASYNC_SUCCESS if the subscriptions are removed. - * An error code is returned if there was a problem removing the subscriptions. - */ -DLLExport int MQTTAsync_unsubscribeMany(MQTTAsync handle, int count, char* const* topic, MQTTAsync_responseOptions* response); - - -/** - * This function attempts to publish a message to a given topic (see also - * ::MQTTAsync_sendMessage()). An ::MQTTAsync_token is issued when - * this function returns successfully. If the client application needs to - * test for successful delivery of messages, a callback should be set - * (see ::MQTTAsync_onSuccess() and ::MQTTAsync_deliveryComplete()). - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param destinationName The topic associated with this message. - * @param payloadlen The length of the payload in bytes. - * @param payload A pointer to the byte array payload of the message. - * @param qos The @ref qos of the message. - * @param retained The retained flag for the message. - * @param response A pointer to an ::MQTTAsync_responseOptions structure. Used to set callback functions. - * This is optional and can be set to NULL. - * @return ::MQTTASYNC_SUCCESS if the message is accepted for publication. - * An error code is returned if there was a problem accepting the message. - */ -DLLExport int MQTTAsync_send(MQTTAsync handle, const char* destinationName, int payloadlen, const void* payload, int qos, - int retained, MQTTAsync_responseOptions* response); - - -/** - * This function attempts to publish a message to a given topic (see also - * MQTTAsync_publish()). An ::MQTTAsync_token is issued when - * this function returns successfully. If the client application needs to - * test for successful delivery of messages, a callback should be set - * (see ::MQTTAsync_onSuccess() and ::MQTTAsync_deliveryComplete()). - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param destinationName The topic associated with this message. - * @param msg A pointer to a valid MQTTAsync_message structure containing - * the payload and attributes of the message to be published. - * @param response A pointer to an ::MQTTAsync_responseOptions structure. Used to set callback functions. - * @return ::MQTTASYNC_SUCCESS if the message is accepted for publication. - * An error code is returned if there was a problem accepting the message. - */ -DLLExport int MQTTAsync_sendMessage(MQTTAsync handle, const char* destinationName, const MQTTAsync_message* msg, MQTTAsync_responseOptions* response); - - -/** - * This function sets a pointer to an array of tokens for - * messages that are currently in-flight (pending completion). - * - * Important note: The memory used to hold the array of tokens is - * malloc()'d in this function. The client application is responsible for - * freeing this memory when it is no longer required. - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param tokens The address of a pointer to an ::MQTTAsync_token. - * When the function returns successfully, the pointer is set to point to an - * array of tokens representing messages pending completion. The last member of - * the array is set to -1 to indicate there are no more tokens. If no tokens - * are pending, the pointer is set to NULL. - * @return ::MQTTASYNC_SUCCESS if the function returns successfully. - * An error code is returned if there was a problem obtaining the list of - * pending tokens. - */ -DLLExport int MQTTAsync_getPendingTokens(MQTTAsync handle, MQTTAsync_token **tokens); - -/** - * Tests whether a request corresponding to a token is complete. - * - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param token An ::MQTTAsync_token associated with a request. - * @return 1 if the request has been completed, 0 if not. - */ -#define MQTTASYNC_TRUE 1 -DLLExport int MQTTAsync_isComplete(MQTTAsync handle, MQTTAsync_token token); - - -/** - * Waits for a request corresponding to a token to complete. - * - * @param handle A valid client handle from a successful call to - * MQTTAsync_create(). - * @param token An ::MQTTAsync_token associated with a request. - * @param timeout the maximum time to wait for completion, in milliseconds - * @return ::MQTTASYNC_SUCCESS if the request has been completed in the time allocated, - * ::MQTTASYNC_FAILURE if not. - */ -DLLExport int MQTTAsync_waitForCompletion(MQTTAsync handle, MQTTAsync_token token, unsigned long timeout); - - -/** - * This function frees memory allocated to an MQTT message, including the - * additional memory allocated to the message payload. The client application - * calls this function when the message has been fully processed. Important - * note: This function does not free the memory allocated to a message - * topic string. It is the responsibility of the client application to free - * this memory using the MQTTAsync_free() library function. - * @param msg The address of a pointer to the ::MQTTAsync_message structure - * to be freed. - */ -DLLExport void MQTTAsync_freeMessage(MQTTAsync_message** msg); - -/** - * This function frees memory allocated by the MQTT C client library, especially the - * topic name. This is needed on Windows when the client libary and application - * program have been compiled with different versions of the C compiler. It is - * thus good policy to always use this function when freeing any MQTT C client- - * allocated memory. - * @param ptr The pointer to the client library storage to be freed. - */ -DLLExport void MQTTAsync_free(void* ptr); - -/** - * This function frees the memory allocated to an MQTT client (see - * MQTTAsync_create()). It should be called when the client is no longer - * required. - * @param handle A pointer to the handle referring to the ::MQTTAsync - * structure to be freed. - */ -DLLExport void MQTTAsync_destroy(MQTTAsync* handle); - - - -enum MQTTASYNC_TRACE_LEVELS -{ - MQTTASYNC_TRACE_MAXIMUM = 1, - MQTTASYNC_TRACE_MEDIUM, - MQTTASYNC_TRACE_MINIMUM, - MQTTASYNC_TRACE_PROTOCOL, - MQTTASYNC_TRACE_ERROR, - MQTTASYNC_TRACE_SEVERE, - MQTTASYNC_TRACE_FATAL, -}; - - -/** - * This function sets the level of trace information which will be - * returned in the trace callback. - * @param level the trace level required - */ -DLLExport void MQTTAsync_setTraceLevel(enum MQTTASYNC_TRACE_LEVELS level); - - -/** - * This is a callback function prototype which must be implemented if you want - * to receive trace information. - * @param level the trace level of the message returned - * @param message the trace message. This is a pointer to a static buffer which - * will be overwritten on each call. You must copy the data if you want to keep - * it for later. - */ -typedef void MQTTAsync_traceCallback(enum MQTTASYNC_TRACE_LEVELS level, char* message); - -/** - * This function sets the trace callback if needed. If set to NULL, - * no trace information will be returned. The default trace level is - * MQTTASYNC_TRACE_MINIMUM. - * @param callback a pointer to the function which will handle the trace information - */ -DLLExport void MQTTAsync_setTraceCallback(MQTTAsync_traceCallback* callback); - - -typedef struct -{ - const char* name; - const char* value; -} MQTTAsync_nameValue; - -/** - * This function returns version information about the library. - * no trace information will be returned. The default trace level is - * MQTTASYNC_TRACE_MINIMUM - * @return an array of strings describing the library. The last entry is a NULL pointer. - */ -DLLExport MQTTAsync_nameValue* MQTTAsync_getVersionInfo(void); - -/** - * Returns a pointer to a string representation of the error code, or NULL. - * Do not free after use. Returns NULL if the error code is unknown. - * @param code the MQTTASYNC_ return code. - * @return a static string representation of the error code. - */ -DLLExport const char* MQTTAsync_strerror(int code); - - -/** - * @cond MQTTAsync_main - * @page async Threading - * The client application runs on several threads. - * Processing of handshaking and maintaining - * the network connection is performed in the background. - * This API is thread safe: functions may be called by multiple application - * threads. - * Notifications of status and message reception are provided to the client - * application using callbacks registered with the library by the call to - * MQTTAsync_setCallbacks() (see MQTTAsync_messageArrived(), - * MQTTAsync_connectionLost() and MQTTAsync_deliveryComplete()). - * In addition, some functions allow success and failure callbacks to be set - * for individual requests, in the ::MQTTAsync_responseOptions structure. Applications - * can be written as a chain of callback functions. Note that it is a theoretically - * possible but unlikely event, that a success or failure callback could be called - * before function requesting the callback has returned. In this case the token - * delivered in the callback would not yet be known to the application program (see - * Race condition for MQTTAsync_token in MQTTAsync.c - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=444093) - * - * @page auto_reconnect Automatic Reconnect - * The ability for the client library to reconnect automatically in the event - * of a connection failure was added in 1.1. The connection lost callback - * allows a flexible response to the loss of a connection, so almost any - * behaviour can be implemented in that way. Automatic reconnect does have the - * advantage of being a little simpler to use. - * - * To switch on automatic reconnect, the connect options field - * automaticReconnect should be set to non-zero. The minimum and maximum times - * before the next connection attempt can also be set, the defaults being 1 and - * 60 seconds. At each failure to reconnect, the retry interval is doubled until - * the maximum value is reached, and there it stays until the connection is - * successfully re-established whereupon it is reset. - * - * When a reconnection attempt is successful, the ::MQTTAsync_connected callback - * function is invoked, if set by calling ::MQTTAsync_setConnected. This allows - * the application to take any actions needed, such as amending subscriptions. - * - * @page offline_publish Publish While Disconnected - * This feature was not originally available because with persistence enabled, - * messages could be stored locally without ever knowing if they could be sent. - * The client application could have created the client with an erroneous broker - * address or port for instance. - * - * To enable messages to be published when the application is disconnected - * ::MQTTAsync_createWithOptions must be used instead of ::MQTTAsync_create to - * create the client object. The ::createOptions field sendWhileDisconnected - * must be set to non-zero, and the maxBufferedMessages field set as required - - * the default being 100. - * - * ::MQTTAsync_getPendingTokens can be called to return the ids of the messages - * waiting to be sent, or for which the sending process has not completed. - * - * @page wildcard Subscription wildcards - * Every MQTT message includes a topic that classifies it. MQTT servers use - * topics to determine which subscribers should receive messages published to - * the server. - * - * Consider the server receiving messages from several environmental sensors. - * Each sensor publishes its measurement data as a message with an associated - * topic. Subscribing applications need to know which sensor originally - * published each received message. A unique topic is thus used to identify - * each sensor and measurement type. Topics such as SENSOR1TEMP, - * SENSOR1HUMIDITY, SENSOR2TEMP and so on achieve this but are not very - * flexible. If additional sensors are added to the system at a later date, - * subscribing applications must be modified to receive them. - * - * To provide more flexibility, MQTT supports a hierarchical topic namespace. - * This allows application designers to organize topics to simplify their - * management. Levels in the hierarchy are delimited by the '/' character, - * such as SENSOR/1/HUMIDITY. Publishers and subscribers use these - * hierarchical topics as already described. - * - * For subscriptions, two wildcard characters are supported: - *
    - *
  • A '#' character represents a complete sub-tree of the hierarchy and - * thus must be the last character in a subscription topic string, such as - * SENSOR/#. This will match any topic starting with SENSOR/, such as - * SENSOR/1/TEMP and SENSOR/2/HUMIDITY.
  • - *
  • A '+' character represents a single level of the hierarchy and is - * used between delimiters. For example, SENSOR/+/TEMP will match - * SENSOR/1/TEMP and SENSOR/2/TEMP.
  • - *
- * Publishers are not allowed to use the wildcard characters in their topic - * names. - * - * Deciding on your topic hierarchy is an important step in your system design. - * - * @page qos Quality of service - * The MQTT protocol provides three qualities of service for delivering - * messages between clients and servers: "at most once", "at least once" and - * "exactly once". - * - * Quality of service (QoS) is an attribute of an individual message being - * published. An application sets the QoS for a specific message by setting the - * MQTTAsync_message.qos field to the required value. - * - * A subscribing client can set the maximum quality of service a server uses - * to send messages that match the client subscriptions. The - * MQTTAsync_subscribe() and MQTTAsync_subscribeMany() functions set this - * maximum. The QoS of a message forwarded to a subscriber thus might be - * different to the QoS given to the message by the original publisher. - * The lower of the two values is used to forward a message. - * - * The three levels are: - * - * QoS0, At most once: The message is delivered at most once, or it - * may not be delivered at all. Its delivery across the network is not - * acknowledged. The message is not stored. The message could be lost if the - * client is disconnected, or if the server fails. QoS0 is the fastest mode of - * transfer. It is sometimes called "fire and forget". - * - * The MQTT protocol does not require servers to forward publications at QoS0 - * to a client. If the client is disconnected at the time the server receives - * the publication, the publication might be discarded, depending on the - * server implementation. - * - * QoS1, At least once: The message is always delivered at least once. - * It might be delivered multiple times if there is a failure before an - * acknowledgment is received by the sender. The message must be stored - * locally at the sender, until the sender receives confirmation that the - * message has been published by the receiver. The message is stored in case - * the message must be sent again. - * - * QoS2, Exactly once: The message is always delivered exactly once. - * The message must be stored locally at the sender, until the sender receives - * confirmation that the message has been published by the receiver. The - * message is stored in case the message must be sent again. QoS2 is the - * safest, but slowest mode of transfer. A more sophisticated handshaking - * and acknowledgement sequence is used than for QoS1 to ensure no duplication - * of messages occurs. - - - * @page publish Publication example -@code -#include -#include -#include -#include "MQTTAsync.h" - -#define ADDRESS "tcp://localhost:1883" -#define CLIENTID "ExampleClientPub" -#define TOPIC "MQTT Examples" -#define PAYLOAD "Hello World!" -#define QOS 1 -#define TIMEOUT 10000L - -volatile MQTTAsync_token deliveredtoken; - -int finished = 0; - -void connlost(void *context, char *cause) -{ - MQTTAsync client = (MQTTAsync)context; - MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer; - int rc; - - printf("\nConnection lost\n"); - printf(" cause: %s\n", cause); - - printf("Reconnecting\n"); - conn_opts.keepAliveInterval = 20; - conn_opts.cleansession = 1; - if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS) - { - printf("Failed to start connect, return code %d\n", rc); - finished = 1; - } -} - - -void onDisconnect(void* context, MQTTAsync_successData* response) -{ - printf("Successful disconnection\n"); - finished = 1; -} - - -void onSend(void* context, MQTTAsync_successData* response) -{ - MQTTAsync client = (MQTTAsync)context; - MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer; - int rc; - - printf("Message with token value %d delivery confirmed\n", response->token); - - opts.onSuccess = onDisconnect; - opts.context = client; - - if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS) - { - printf("Failed to start sendMessage, return code %d\n", rc); - exit(EXIT_FAILURE); - } -} - - -void onConnectFailure(void* context, MQTTAsync_failureData* response) -{ - printf("Connect failed, rc %d\n", response ? response->code : 0); - finished = 1; -} - - -void onConnect(void* context, MQTTAsync_successData* response) -{ - MQTTAsync client = (MQTTAsync)context; - MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; - MQTTAsync_message pubmsg = MQTTAsync_message_initializer; - int rc; - - printf("Successful connection\n"); - - opts.onSuccess = onSend; - opts.context = client; - - pubmsg.payload = PAYLOAD; - pubmsg.payloadlen = strlen(PAYLOAD); - pubmsg.qos = QOS; - pubmsg.retained = 0; - deliveredtoken = 0; - - if ((rc = MQTTAsync_sendMessage(client, TOPIC, &pubmsg, &opts)) != MQTTASYNC_SUCCESS) - { - printf("Failed to start sendMessage, return code %d\n", rc); - exit(EXIT_FAILURE); - } -} - - -int main(int argc, char* argv[]) -{ - MQTTAsync client; - MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer; - MQTTAsync_message pubmsg = MQTTAsync_message_initializer; - MQTTAsync_token token; - int rc; - - MQTTAsync_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL); - - MQTTAsync_setCallbacks(client, NULL, connlost, NULL, NULL); - - conn_opts.keepAliveInterval = 20; - conn_opts.cleansession = 1; - conn_opts.onSuccess = onConnect; - conn_opts.onFailure = onConnectFailure; - conn_opts.context = client; - if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS) - { - printf("Failed to start connect, return code %d\n", rc); - exit(EXIT_FAILURE); - } - - printf("Waiting for publication of %s\n" - "on topic %s for client with ClientID: %s\n", - PAYLOAD, TOPIC, CLIENTID); - while (!finished) - #if defined(WIN32) || defined(WIN64) - Sleep(100); - #else - usleep(10000L); - #endif - - MQTTAsync_destroy(&client); - return rc; -} - - * @endcode - * @page subscribe Subscription example -@code -#include -#include -#include -#include "MQTTAsync.h" - -#define ADDRESS "tcp://localhost:1883" -#define CLIENTID "ExampleClientSub" -#define TOPIC "MQTT Examples" -#define PAYLOAD "Hello World!" -#define QOS 1 -#define TIMEOUT 10000L - -volatile MQTTAsync_token deliveredtoken; - -int disc_finished = 0; -int subscribed = 0; -int finished = 0; - -void connlost(void *context, char *cause) -{ - MQTTAsync client = (MQTTAsync)context; - MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer; - int rc; - - printf("\nConnection lost\n"); - printf(" cause: %s\n", cause); - - printf("Reconnecting\n"); - conn_opts.keepAliveInterval = 20; - conn_opts.cleansession = 1; - if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS) - { - printf("Failed to start connect, return code %d\n", rc); - finished = 1; - } -} - - -int msgarrvd(void *context, char *topicName, int topicLen, MQTTAsync_message *message) -{ - int i; - char* payloadptr; - - printf("Message arrived\n"); - printf(" topic: %s\n", topicName); - printf(" message: "); - - payloadptr = message->payload; - for(i=0; ipayloadlen; i++) - { - putchar(*payloadptr++); - } - putchar('\n'); - MQTTAsync_freeMessage(&message); - MQTTAsync_free(topicName); - return 1; -} - - -void onDisconnect(void* context, MQTTAsync_successData* response) -{ - printf("Successful disconnection\n"); - disc_finished = 1; -} - - -void onSubscribe(void* context, MQTTAsync_successData* response) -{ - printf("Subscribe succeeded\n"); - subscribed = 1; -} - -void onSubscribeFailure(void* context, MQTTAsync_failureData* response) -{ - printf("Subscribe failed, rc %d\n", response ? response->code : 0); - finished = 1; -} - - -void onConnectFailure(void* context, MQTTAsync_failureData* response) -{ - printf("Connect failed, rc %d\n", response ? response->code : 0); - finished = 1; -} - - -void onConnect(void* context, MQTTAsync_successData* response) -{ - MQTTAsync client = (MQTTAsync)context; - MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; - MQTTAsync_message pubmsg = MQTTAsync_message_initializer; - int rc; - - printf("Successful connection\n"); - - printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n" - "Press Q to quit\n\n", TOPIC, CLIENTID, QOS); - opts.onSuccess = onSubscribe; - opts.onFailure = onSubscribeFailure; - opts.context = client; - - deliveredtoken = 0; - - if ((rc = MQTTAsync_subscribe(client, TOPIC, QOS, &opts)) != MQTTASYNC_SUCCESS) - { - printf("Failed to start subscribe, return code %d\n", rc); - exit(EXIT_FAILURE); - } -} - - -int main(int argc, char* argv[]) -{ - MQTTAsync client; - MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer; - MQTTAsync_disconnectOptions disc_opts = MQTTAsync_disconnectOptions_initializer; - MQTTAsync_message pubmsg = MQTTAsync_message_initializer; - MQTTAsync_token token; - int rc; - int ch; - - MQTTAsync_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL); - - MQTTAsync_setCallbacks(client, NULL, connlost, msgarrvd, NULL); - - conn_opts.keepAliveInterval = 20; - conn_opts.cleansession = 1; - conn_opts.onSuccess = onConnect; - conn_opts.onFailure = onConnectFailure; - conn_opts.context = client; - if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS) - { - printf("Failed to start connect, return code %d\n", rc); - exit(EXIT_FAILURE); - } - - while (!subscribed) - #if defined(WIN32) || defined(WIN64) - Sleep(100); - #else - usleep(10000L); - #endif - - if (finished) - goto exit; - - do - { - ch = getchar(); - } while (ch!='Q' && ch != 'q'); - - disc_opts.onSuccess = onDisconnect; - if ((rc = MQTTAsync_disconnect(client, &disc_opts)) != MQTTASYNC_SUCCESS) - { - printf("Failed to start disconnect, return code %d\n", rc); - exit(EXIT_FAILURE); - } - while (!disc_finished) - #if defined(WIN32) || defined(WIN64) - Sleep(100); - #else - usleep(10000L); - #endif - -exit: - MQTTAsync_destroy(&client); - return rc; -} - - * @endcode -* @page tracing Tracing - * - * Runtime tracing can be controlled by environment variables or API calls. - * - * #### Environment variables - * - * Tracing is switched on by setting the MQTT_C_CLIENT_TRACE environment variable. - * A value of ON, or stdout, prints to stdout, any other value is interpreted as a file name to use. - * - * The amount of trace detail is controlled with the MQTT_C_CLIENT_TRACE_LEVEL environment - * variable - valid values are ERROR, PROTOCOL, MINIMUM, MEDIUM and MAXIMUM - * (from least to most verbose). - * - * The variable MQTT_C_CLIENT_TRACE_MAX_LINES limits the number of lines of trace that are output - * to a file. Two files are used at most, when they are full, the last one is overwritten with the - * new trace entries. The default size is 1000 lines. - * - * #### Trace API calls - * - * MQTTAsync_traceCallback() is used to set a callback function which is called whenever trace - * information is available. This will be the same information as that printed if the - * environment variables were used to control the trace. - * - * The MQTTAsync_setTraceLevel() calls is used to set the maximum level of trace entries that will be - * passed to the callback function. The levels are: - * 1. ::MQTTASYNC_TRACE_MAXIMUM - * 2. ::MQTTASYNC_TRACE_MEDIUM - * 3. ::MQTTASYNC_TRACE_MINIMUM - * 4. ::MQTTASYNC_TRACE_PROTOCOL - * 5. ::MQTTASYNC_TRACE_ERROR - * 6. ::MQTTASYNC_TRACE_SEVERE - * 7. ::MQTTASYNC_TRACE_FATAL - * - * Selecting ::MQTTASYNC_TRACE_MAXIMUM will cause all trace entries at all levels to be returned. - * Choosing ::MQTTASYNC_TRACE_ERROR will cause ERROR, SEVERE and FATAL trace entries to be returned - * to the callback function. - * - * ### MQTT Packet Tracing - * - * A feature that can be very useful is printing the MQTT packets that are sent and received. To - * achieve this, use the following environment variable settings: - * @code - MQTT_C_CLIENT_TRACE=ON - MQTT_C_CLIENT_TRACE_LEVEL=PROTOCOL - * @endcode - * The output you should see looks like this: - * @code - 20130528 155936.813 3 stdout-subscriber -> CONNECT cleansession: 1 (0) - 20130528 155936.813 3 stdout-subscriber <- CONNACK rc: 0 - 20130528 155936.813 3 stdout-subscriber -> SUBSCRIBE msgid: 1 (0) - 20130528 155936.813 3 stdout-subscriber <- SUBACK msgid: 1 - 20130528 155941.818 3 stdout-subscriber -> DISCONNECT (0) - * @endcode - * where the fields are: - * 1. date - * 2. time - * 3. socket number - * 4. client id - * 5. direction (-> from client to server, <- from server to client) - * 6. packet details - * - * ### Default Level Tracing - * - * This is an extract of a default level trace of a call to connect: - * @code - 19700101 010000.000 (1152206656) (0)> MQTTClient_connect:893 - 19700101 010000.000 (1152206656) (1)> MQTTClient_connectURI:716 - 20130528 160447.479 Connecting to serverURI localhost:1883 - 20130528 160447.479 (1152206656) (2)> MQTTProtocol_connect:98 - 20130528 160447.479 (1152206656) (3)> MQTTProtocol_addressPort:48 - 20130528 160447.479 (1152206656) (3)< MQTTProtocol_addressPort:73 - 20130528 160447.479 (1152206656) (3)> Socket_new:599 - 20130528 160447.479 New socket 4 for localhost, port 1883 - 20130528 160447.479 (1152206656) (4)> Socket_addSocket:163 - 20130528 160447.479 (1152206656) (5)> Socket_setnonblocking:73 - 20130528 160447.479 (1152206656) (5)< Socket_setnonblocking:78 (0) - 20130528 160447.479 (1152206656) (4)< Socket_addSocket:176 (0) - 20130528 160447.479 (1152206656) (4)> Socket_error:95 - 20130528 160447.479 (1152206656) (4)< Socket_error:104 (115) - 20130528 160447.479 Connect pending - 20130528 160447.479 (1152206656) (3)< Socket_new:683 (115) - 20130528 160447.479 (1152206656) (2)< MQTTProtocol_connect:131 (115) - * @endcode - * where the fields are: - * 1. date - * 2. time - * 3. thread id - * 4. function nesting level - * 5. function entry (>) or exit (<) - * 6. function name : line of source code file - * 7. return value (if there is one) - * - * ### Memory Allocation Tracing - * - * Setting the trace level to maximum causes memory allocations and frees to be traced along with - * the default trace entries, with messages like the following: - * @code - 20130528 161819.657 Allocating 16 bytes in heap at file /home/icraggs/workspaces/mqrtc/mqttv3c/src/MQTTPacket.c line 177 ptr 0x179f930 - - 20130528 161819.657 Freeing 16 bytes in heap at file /home/icraggs/workspaces/mqrtc/mqttv3c/src/MQTTPacket.c line 201, heap use now 896 bytes - * @endcode - * When the last MQTT client object is destroyed, if the trace is being recorded - * and all memory allocated by the client library has not been freed, an error message will be - * written to the trace. This can help with fixing memory leaks. The message will look like this: - * @code - 20130528 163909.208 Some memory not freed at shutdown, possible memory leak - 20130528 163909.208 Heap scan start, total 880 bytes - 20130528 163909.208 Heap element size 32, line 354, file /home/icraggs/workspaces/mqrtc/mqttv3c/src/MQTTPacket.c, ptr 0x260cb00 - 20130528 163909.208 Content - 20130528 163909.209 Heap scan end - * @endcode - * @endcond - */ - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTClient.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTClient.h deleted file mode 100644 index 518dbbd..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTClient.h +++ /dev/null @@ -1,1670 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs, Allan Stockdill-Mander - SSL updates - * Ian Craggs - multiple server connection support - * Ian Craggs - MQTT 3.1.1 support - * Ian Craggs - remove const from eyecatchers #168 - *******************************************************************************/ - -/** - * @cond MQTTClient_internal - * @mainpage MQTT Client Library Internals - * In the beginning there was one MQTT C client library, MQTTClient, as implemented in MQTTClient.c - * This library was designed to be easy to use for applications which didn't mind if some of the calls - * blocked for a while. For instance, the MQTTClient_connect call will block until a successful - * connection has completed, or a connection has failed, which could be as long as the "connection - * timeout" interval, whose default is 30 seconds. - * - * However in mobile devices and other windowing environments, blocking on the GUI thread is a bad - * thing as it causes the user interface to freeze. Hence a new API, MQTTAsync, implemented - * in MQTTAsync.c, was devised. There are no blocking calls in this library, so it is well suited - * to GUI and mobile environments, at the expense of some extra complexity. - * - * Both libraries are designed to be sparing in the use of threads. So multiple client objects are - * handled by one or two threads, with a select call in Socket_getReadySocket(), used to determine - * when a socket has incoming data. This API is thread safe: functions may be called by multiple application - * threads, with the exception of ::MQTTClient_yield and ::MQTTClient_receive, which are intended - * for single threaded environments only. - * - * @endcond - * @cond MQTTClient_main - * @mainpage MQTT Client library for C - * © Copyright IBM Corp. 2009, 2018 - * - * @brief An MQTT client library in C. - * - * These pages describe the original more synchronous API which might be - * considered easier to use. Some of the calls will block. For the new - * totally asynchronous API where no calls block, which is especially suitable - * for use in windowed environments, see the - * MQTT C Client Asynchronous API Documentation. - * The MQTTClient API is not thread safe, whereas the MQTTAsync API is. - * - * An MQTT client application connects to MQTT-capable servers. - * A typical client is responsible for collecting information from a telemetry - * device and publishing the information to the server. It can also subscribe - * to topics, receive messages, and use this information to control the - * telemetry device. - * - * MQTT clients implement the published MQTT v3 protocol. You can write your own - * API to the MQTT protocol using the programming language and platform of your - * choice. This can be time-consuming and error-prone. - * - * To simplify writing MQTT client applications, this library encapsulates - * the MQTT v3 protocol for you. Using this library enables a fully functional - * MQTT client application to be written in a few lines of code. - * The information presented here documents the API provided - * by the MQTT Client library for C. - * - * Using the client
- * Applications that use the client library typically use a similar structure: - *
    - *
  • Create a client object
  • - *
  • Set the options to connect to an MQTT server
  • - *
  • Set up callback functions if multi-threaded (asynchronous mode) - * operation is being used (see @ref async).
  • - *
  • Subscribe to any topics the client needs to receive
  • - *
  • Repeat until finished:
  • - *
      - *
    • Publish any messages the client needs to
    • - *
    • Handle any incoming messages
    • - *
    - *
  • Disconnect the client
  • - *
  • Free any memory being used by the client
  • - *
- * Some simple examples are shown here: - *
    - *
  • @ref pubsync
  • - *
  • @ref pubasync
  • - *
  • @ref subasync
  • - *
- * Additional information about important concepts is provided here: - *
    - *
  • @ref async
  • - *
  • @ref wildcard
  • - *
  • @ref qos
  • - *
  • @ref tracing
  • - *
- * @endcond - */ - -/* -/// @cond EXCLUDE -*/ -#if !defined(MQTTCLIENT_H) -#define MQTTCLIENT_H - -#if defined(__cplusplus) - extern "C" { -#endif - -#if defined(WIN32) || defined(WIN64) - #define DLLImport __declspec(dllimport) - #define DLLExport __declspec(dllexport) -#else - #define DLLImport extern - #define DLLExport __attribute__ ((visibility ("default"))) -#endif - -#include -/* -/// @endcond -*/ - -#include "MQTTProperties.h" -#include "MQTTReasonCodes.h" -#include "MQTTSubscribeOpts.h" -#if !defined(NO_PERSISTENCE) -#include "MQTTClientPersistence.h" -#endif - -/** - * Return code: No error. Indicates successful completion of an MQTT client - * operation. - */ -#define MQTTCLIENT_SUCCESS 0 -/** - * Return code: A generic error code indicating the failure of an MQTT client - * operation. - */ -#define MQTTCLIENT_FAILURE -1 - -/* error code -2 is MQTTCLIENT_PERSISTENCE_ERROR */ - -/** - * Return code: The client is disconnected. - */ -#define MQTTCLIENT_DISCONNECTED -3 -/** - * Return code: The maximum number of messages allowed to be simultaneously - * in-flight has been reached. - */ -#define MQTTCLIENT_MAX_MESSAGES_INFLIGHT -4 -/** - * Return code: An invalid UTF-8 string has been detected. - */ -#define MQTTCLIENT_BAD_UTF8_STRING -5 -/** - * Return code: A NULL parameter has been supplied when this is invalid. - */ -#define MQTTCLIENT_NULL_PARAMETER -6 -/** - * Return code: The topic has been truncated (the topic string includes - * embedded NULL characters). String functions will not access the full topic. - * Use the topic length value to access the full topic. - */ -#define MQTTCLIENT_TOPICNAME_TRUNCATED -7 -/** - * Return code: A structure parameter does not have the correct eyecatcher - * and version number. - */ -#define MQTTCLIENT_BAD_STRUCTURE -8 -/** - * Return code: A QoS value that falls outside of the acceptable range (0,1,2) - */ -#define MQTTCLIENT_BAD_QOS -9 -/** - * Return code: Attempting SSL connection using non-SSL version of library - */ -#define MQTTCLIENT_SSL_NOT_SUPPORTED -10 - /** - * Return code: unrecognized MQTT version - */ - #define MQTTCLIENT_BAD_MQTT_VERSION -11 -/** - * Return code: protocol prefix in serverURI should be tcp:// or ssl:// - */ -#define MQTTCLIENT_BAD_PROTOCOL -14 - /** - * Return code: option not applicable to the requested version of MQTT - */ - #define MQTTCLIENT_BAD_MQTT_OPTION -15 - /** - * Return code: call not applicable to the requested version of MQTT - */ - #define MQTTCLIENT_WRONG_MQTT_VERSION -16 - - -/** - * Default MQTT version to connect with. Use 3.1.1 then fall back to 3.1 - */ -#define MQTTVERSION_DEFAULT 0 -/** - * MQTT version to connect with: 3.1 - */ -#define MQTTVERSION_3_1 3 -/** - * MQTT version to connect with: 3.1.1 - */ -#define MQTTVERSION_3_1_1 4 - /** - * MQTT version to connect with: 5 - */ - #define MQTTVERSION_5 5 -/** - * Bad return code from subscribe, as defined in the 3.1.1 specification - */ -#define MQTT_BAD_SUBSCRIBE 0x80 - -/** - * Initialization options - */ -typedef struct -{ - /** The eyecatcher for this structure. Must be MQTG. */ - char struct_id[4]; - /** The version number of this structure. Must be 0 */ - int struct_version; - /** 1 = we do openssl init, 0 = leave it to the application */ - int do_openssl_init; -} MQTTClient_init_options; - -#define MQTTClient_init_options_initializer { {'M', 'Q', 'T', 'G'}, 0, 0 } - -/** - * Global init of mqtt library. Call once on program start to set global behaviour. - * do_openssl_init - if mqtt library should initialize OpenSSL (1) or rely on the caller to do it before using the library (0) - */ -DLLExport void MQTTClient_global_init(MQTTClient_init_options* inits); - -/** - * A handle representing an MQTT client. A valid client handle is available - * following a successful call to MQTTClient_create(). - */ -typedef void* MQTTClient; -/** - * A value representing an MQTT message. A delivery token is returned to the - * client application when a message is published. The token can then be used to - * check that the message was successfully delivered to its destination (see - * MQTTClient_publish(), - * MQTTClient_publishMessage(), - * MQTTClient_deliveryComplete(), - * MQTTClient_waitForCompletion() and - * MQTTClient_getPendingDeliveryTokens()). - */ -typedef int MQTTClient_deliveryToken; -typedef int MQTTClient_token; - -/** - * A structure representing the payload and attributes of an MQTT message. The - * message topic is not part of this structure (see MQTTClient_publishMessage(), - * MQTTClient_publish(), MQTTClient_receive(), MQTTClient_freeMessage() - * and MQTTClient_messageArrived()). - */ -typedef struct -{ - /** The eyecatcher for this structure. must be MQTM. */ - char struct_id[4]; - /** The version number of this structure. Must be 0 or 1 - * 0 indicates no message properties */ - int struct_version; - /** The length of the MQTT message payload in bytes. */ - int payloadlen; - /** A pointer to the payload of the MQTT message. */ - void* payload; - /** - * The quality of service (QoS) assigned to the message. - * There are three levels of QoS: - *
- *
QoS0
- *
Fire and forget - the message may not be delivered
- *
QoS1
- *
At least once - the message will be delivered, but may be - * delivered more than once in some circumstances.
- *
QoS2
- *
Once and one only - the message will be delivered exactly once.
- *
- */ - int qos; - /** - * The retained flag serves two purposes depending on whether the message - * it is associated with is being published or received. - * - * retained = true
- * For messages being published, a true setting indicates that the MQTT - * server should retain a copy of the message. The message will then be - * transmitted to new subscribers to a topic that matches the message topic. - * For subscribers registering a new subscription, the flag being true - * indicates that the received message is not a new one, but one that has - * been retained by the MQTT server. - * - * retained = false
- * For publishers, this indicates that this message should not be retained - * by the MQTT server. For subscribers, a false setting indicates this is - * a normal message, received as a result of it being published to the - * server. - */ - int retained; - /** - * The dup flag indicates whether or not this message is a duplicate. - * It is only meaningful when receiving QoS1 messages. When true, the - * client application should take appropriate action to deal with the - * duplicate message. - */ - int dup; - /** The message identifier is normally reserved for internal use by the - * MQTT client and server. - */ - int msgid; - /** - * The MQTT V5 properties associated with the message. - */ - MQTTProperties properties; -} MQTTClient_message; - -#define MQTTClient_message_initializer { {'M', 'Q', 'T', 'M'}, 1, 0, NULL, 0, 0, 0, 0, MQTTProperties_initializer } - -/** - * This is a callback function. The client application - * must provide an implementation of this function to enable asynchronous - * receipt of messages. The function is registered with the client library by - * passing it as an argument to MQTTClient_setCallbacks(). It is - * called by the client library when a new message that matches a client - * subscription has been received from the server. This function is executed on - * a separate thread to the one on which the client application is running. - * @param context A pointer to the context value originally passed to - * MQTTClient_setCallbacks(), which contains any application-specific context. - * @param topicName The topic associated with the received message. - * @param topicLen The length of the topic if there are one - * more NULL characters embedded in topicName, otherwise topicLen - * is 0. If topicLen is 0, the value returned by strlen(topicName) - * can be trusted. If topicLen is greater than 0, the full topic name - * can be retrieved by accessing topicName as a byte array of length - * topicLen. - * @param message The MQTTClient_message structure for the received message. - * This structure contains the message payload and attributes. - * @return This function must return a boolean value indicating whether or not - * the message has been safely received by the client application. Returning - * true indicates that the message has been successfully handled. - * Returning false indicates that there was a problem. In this - * case, the client library will reinvoke MQTTClient_messageArrived() to - * attempt to deliver the message to the application again. - */ -typedef int MQTTClient_messageArrived(void* context, char* topicName, int topicLen, MQTTClient_message* message); - -/** - * This is a callback function. The client application - * must provide an implementation of this function to enable asynchronous - * notification of delivery of messages. The function is registered with the - * client library by passing it as an argument to MQTTClient_setCallbacks(). - * It is called by the client library after the client application has - * published a message to the server. It indicates that the necessary - * handshaking and acknowledgements for the requested quality of service (see - * MQTTClient_message.qos) have been completed. This function is executed on a - * separate thread to the one on which the client application is running. - * Note:MQTTClient_deliveryComplete() is not called when messages are - * published at QoS0. - * @param context A pointer to the context value originally passed to - * MQTTClient_setCallbacks(), which contains any application-specific context. - * @param dt The ::MQTTClient_deliveryToken associated with - * the published message. Applications can check that all messages have been - * correctly published by matching the delivery tokens returned from calls to - * MQTTClient_publish() and MQTTClient_publishMessage() with the tokens passed - * to this callback. - */ -typedef void MQTTClient_deliveryComplete(void* context, MQTTClient_deliveryToken dt); - -/** - * This is a callback function. The client application - * must provide an implementation of this function to enable asynchronous - * notification of the loss of connection to the server. The function is - * registered with the client library by passing it as an argument to - * MQTTClient_setCallbacks(). It is called by the client library if the client - * loses its connection to the server. The client application must take - * appropriate action, such as trying to reconnect or reporting the problem. - * This function is executed on a separate thread to the one on which the - * client application is running. - * @param context A pointer to the context value originally passed to - * MQTTClient_setCallbacks(), which contains any application-specific context. - * @param cause The reason for the disconnection. - * Currently, cause is always set to NULL. - */ -typedef void MQTTClient_connectionLost(void* context, char* cause); - -/** - * This function sets the callback functions for a specific client. - * If your client application doesn't use a particular callback, set the - * relevant parameter to NULL. Calling MQTTClient_setCallbacks() puts the - * client into multi-threaded mode. Any necessary message acknowledgements and - * status communications are handled in the background without any intervention - * from the client application. See @ref async for more information. - * - * Note: The MQTT client must be disconnected when this function is - * called. - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param context A pointer to any application-specific context. The - * the context pointer is passed to each of the callback functions to - * provide access to the context information in the callback. - * @param cl A pointer to an MQTTClient_connectionLost() callback - * function. You can set this to NULL if your application doesn't handle - * disconnections. - * @param ma A pointer to an MQTTClient_messageArrived() callback - * function. This callback function must be specified when you call - * MQTTClient_setCallbacks(). - * @param dc A pointer to an MQTTClient_deliveryComplete() callback - * function. You can set this to NULL if your application publishes - * synchronously or if you do not want to check for successful delivery. - * @return ::MQTTCLIENT_SUCCESS if the callbacks were correctly set, - * ::MQTTCLIENT_FAILURE if an error occurred. - */ -DLLExport int MQTTClient_setCallbacks(MQTTClient handle, void* context, MQTTClient_connectionLost* cl, - MQTTClient_messageArrived* ma, MQTTClient_deliveryComplete* dc); - - -/** - * This is a callback function, which will be called when the a disconnect - * packet is received from the server. This applies to MQTT V5 and above only. - * @param context A pointer to the context value originally passed to - * ::MQTTAsync_setDisconnected(), which contains any application-specific context. - * @param properties The MQTT V5 properties received with the disconnect, if any. - * @param reasonCode The MQTT V5 reason code received with the disconnect. - * Currently, cause is always set to NULL. - */ -typedef void MQTTClient_disconnected(void* context, MQTTProperties* properties, - enum MQTTReasonCodes reasonCode); - -/** - * Sets the MQTTClient_disconnected() callback function for a client. This will be called - * if a disconnect packet is received from the server. Only valid for MQTT V5 and above. - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param context A pointer to any application-specific context. The - * the context pointer is passed to each of the callback functions to - * provide access to the context information in the callback. - * @param co A pointer to an MQTTClient_disconnected() callback - * function. NULL removes the callback setting. - * @return ::MQTTCLIENT_SUCCESS if the callbacks were correctly set, - * ::MQTTCLIENT_FAILURE if an error occurred. - */ -DLLExport int MQTTClient_setDisconnected(MQTTClient handle, void* context, MQTTClient_disconnected* co); - -/** - * This is a callback function, the MQTT V5 version of MQTTClient_deliveryComplete(). - * The client application - * must provide an implementation of this function to enable asynchronous - * notification of the completed delivery of messages. - * It is called by the client library after the client application has - * published a message to the server. It indicates that the necessary - * handshaking and acknowledgements for the requested quality of service (see - * MQTTClient_message.qos) have been completed. This function is executed on a - * separate thread to the one on which the client application is running. - * Note: It is not called when messages are published at QoS0. - * @param context A pointer to the context value originally passed to - * MQTTClient_setCallbacks(), which contains any application-specific context. - * @param dt The ::MQTTClient_deliveryToken associated with - * the published message. Applications can check that all messages have been - * correctly published by matching the delivery tokens returned from calls to - * MQTTClient_publish() and MQTTClient_publishMessage() with the tokens passed - * to this callback. - * @param packet_type the last received packet type for this completion. For QoS 1 - * always PUBACK. For QoS 2 could be PUBREC or PUBCOMP. - * @param properties the MQTT V5 properties returned with the last packet from the server - * @param reasonCode the reason code returned from the server - */ -typedef void MQTTClient_published(void* context, int dt, int packet_type, MQTTProperties* properties, - enum MQTTReasonCodes reasonCode); - -DLLExport int MQTTClient_setPublished(MQTTClient handle, void* context, MQTTClient_published* co); - -/** - * This function creates an MQTT client ready for connection to the - * specified server and using the specified persistent storage (see - * MQTTClient_persistence). See also MQTTClient_destroy(). - * @param handle A pointer to an ::MQTTClient handle. The handle is - * populated with a valid client reference following a successful return from - * this function. - * @param serverURI A null-terminated string specifying the server to - * which the client will connect. It takes the form protocol://host:port. - * Currently, protocol must be tcp or ssl. - * For host, you can - * specify either an IP address or a host name. For instance, to connect to - * a server running on the local machines with the default MQTT port, specify - * tcp://localhost:1883. - * @param clientId The client identifier passed to the server when the - * client connects to it. It is a null-terminated UTF-8 encoded string. - * @param persistence_type The type of persistence to be used by the client: - *
- * ::MQTTCLIENT_PERSISTENCE_NONE: Use in-memory persistence. If the device or - * system on which the client is running fails or is switched off, the current - * state of any in-flight messages is lost and some messages may not be - * delivered even at QoS1 and QoS2. - *
- * ::MQTTCLIENT_PERSISTENCE_DEFAULT: Use the default (file system-based) - * persistence mechanism. Status about in-flight messages is held in persistent - * storage and provides some protection against message loss in the case of - * unexpected failure. - *
- * ::MQTTCLIENT_PERSISTENCE_USER: Use an application-specific persistence - * implementation. Using this type of persistence gives control of the - * persistence mechanism to the application. The application has to implement - * the MQTTClient_persistence interface. - * @param persistence_context If the application uses - * ::MQTTCLIENT_PERSISTENCE_NONE persistence, this argument is unused and should - * be set to NULL. For ::MQTTCLIENT_PERSISTENCE_DEFAULT persistence, it - * should be set to the location of the persistence directory (if set - * to NULL, the persistence directory used is the working directory). - * Applications that use ::MQTTCLIENT_PERSISTENCE_USER persistence set this - * argument to point to a valid MQTTClient_persistence structure. - * @return ::MQTTCLIENT_SUCCESS if the client is successfully created, otherwise - * an error code is returned. - */ -DLLExport int MQTTClient_create(MQTTClient* handle, const char* serverURI, const char* clientId, - int persistence_type, void* persistence_context); - -typedef struct -{ - /** The eyecatcher for this structure. must be MQCO. */ - char struct_id[4]; - /** The version number of this structure. Must be 0 */ - int struct_version; - /** Whether the MQTT version is 3.1, 3.1.1, or 5. To use V5, this must be set. - * MQTT V5 has to be chosen here, because during the create call the message persistence - * is initialized, and we want to know whether the format of any persisted messages - * is appropriate for the MQTT version we are going to connect with. Selecting 3.1 or - * 3.1.1 and attempting to read 5.0 persisted messages will result in an error on create. */ - int MQTTVersion; -} MQTTClient_createOptions; - -#define MQTTClient_createOptions_initializer { {'M', 'Q', 'C', 'O'}, MQTTVERSION_DEFAULT } - -/** - * A version of :MQTTClient_create() with additional options. - * This function creates an MQTT client ready for connection to the - * specified server and using the specified persistent storage (see - * MQTTClient_persistence). See also MQTTClient_destroy(). - * @param handle A pointer to an ::MQTTClient handle. The handle is - * populated with a valid client reference following a successful return from - * this function. - * @param serverURI A null-terminated string specifying the server to - * which the client will connect. It takes the form protocol://host:port. - * Currently, protocol must be tcp or ssl. - * For host, you can - * specify either an IP address or a host name. For instance, to connect to - * a server running on the local machines with the default MQTT port, specify - * tcp://localhost:1883. - * @param clientId The client identifier passed to the server when the - * client connects to it. It is a null-terminated UTF-8 encoded string. - * @param persistence_type The type of persistence to be used by the client: - *
- * ::MQTTCLIENT_PERSISTENCE_NONE: Use in-memory persistence. If the device or - * system on which the client is running fails or is switched off, the current - * state of any in-flight messages is lost and some messages may not be - * delivered even at QoS1 and QoS2. - *
- * ::MQTTCLIENT_PERSISTENCE_DEFAULT: Use the default (file system-based) - * persistence mechanism. Status about in-flight messages is held in persistent - * storage and provides some protection against message loss in the case of - * unexpected failure. - *
- * ::MQTTCLIENT_PERSISTENCE_USER: Use an application-specific persistence - * implementation. Using this type of persistence gives control of the - * persistence mechanism to the application. The application has to implement - * the MQTTClient_persistence interface. - * @param persistence_context If the application uses - * ::MQTTCLIENT_PERSISTENCE_NONE persistence, this argument is unused and should - * be set to NULL. For ::MQTTCLIENT_PERSISTENCE_DEFAULT persistence, it - * should be set to the location of the persistence directory (if set - * to NULL, the persistence directory used is the working directory). - * Applications that use ::MQTTCLIENT_PERSISTENCE_USER persistence set this - * argument to point to a valid MQTTClient_persistence structure. - * @param options additional options for the create. - * @return ::MQTTCLIENT_SUCCESS if the client is successfully created, otherwise - * an error code is returned. - */ -DLLExport int MQTTClient_createWithOptions(MQTTClient* handle, const char* serverURI, const char* clientId, - int persistence_type, void* persistence_context, MQTTClient_createOptions* options); - -/** - * MQTTClient_willOptions defines the MQTT "Last Will and Testament" (LWT) settings for - * the client. In the event that a client unexpectedly loses its connection to - * the server, the server publishes the LWT message to the LWT topic on - * behalf of the client. This allows other clients (subscribed to the LWT topic) - * to be made aware that the client has disconnected. To enable the LWT - * function for a specific client, a valid pointer to an MQTTClient_willOptions - * structure is passed in the MQTTClient_connectOptions structure used in the - * MQTTClient_connect() call that connects the client to the server. The pointer - * to MQTTClient_willOptions can be set to NULL if the LWT function is not - * required. - */ -typedef struct -{ - /** The eyecatcher for this structure. must be MQTW. */ - char struct_id[4]; - /** The version number of this structure. Must be 0 or 1 - 0 means there is no binary payload option - */ - int struct_version; - /** The LWT topic to which the LWT message will be published. */ - const char* topicName; - /** The LWT payload in string form. */ - const char* message; - /** - * The retained flag for the LWT message (see MQTTClient_message.retained). - */ - int retained; - /** - * The quality of service setting for the LWT message (see - * MQTTClient_message.qos and @ref qos). - */ - int qos; - /** The LWT payload in binary form. This is only checked and used if the message option is NULL */ - struct - { - int len; /**< binary payload length */ - const void* data; /**< binary payload data */ - } payload; -} MQTTClient_willOptions; - -#define MQTTClient_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 1, NULL, NULL, 0, 0, {0, NULL} } - -#define MQTT_SSL_VERSION_DEFAULT 0 -#define MQTT_SSL_VERSION_TLS_1_0 1 -#define MQTT_SSL_VERSION_TLS_1_1 2 -#define MQTT_SSL_VERSION_TLS_1_2 3 - -/** -* MQTTClient_sslProperties defines the settings to establish an SSL/TLS connection using the -* OpenSSL library. It covers the following scenarios: -* - Server authentication: The client needs the digital certificate of the server. It is included -* in a store containting trusted material (also known as "trust store"). -* - Mutual authentication: Both client and server are authenticated during the SSL handshake. In -* addition to the digital certificate of the server in a trust store, the client will need its own -* digital certificate and the private key used to sign its digital certificate stored in a "key store". -* - Anonymous connection: Both client and server do not get authenticated and no credentials are needed -* to establish an SSL connection. Note that this scenario is not fully secure since it is subject to -* man-in-the-middle attacks. -*/ -typedef struct -{ - /** The eyecatcher for this structure. Must be MQTS */ - char struct_id[4]; - /** The version number of this structure. Must be 0, or 1 to enable TLS version selection. */ - int struct_version; - - /** The file in PEM format containing the public digital certificates trusted by the client. */ - const char* trustStore; - - /** The file in PEM format containing the public certificate chain of the client. It may also include - * the client's private key. - */ - const char* keyStore; - - /** If not included in the sslKeyStore, this setting points to the file in PEM format containing - * the client's private key. - */ - const char* privateKey; - /** The password to load the client's privateKey if encrypted. */ - const char* privateKeyPassword; - - /** - * The list of cipher suites that the client will present to the server during the SSL handshake. For a - * full explanation of the cipher list format, please see the OpenSSL on-line documentation: - * http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT - * If this setting is ommitted, its default value will be "ALL", that is, all the cipher suites -excluding - * those offering no encryption- will be considered. - * This setting can be used to set an SSL anonymous connection ("aNULL" string value, for instance). - */ - const char* enabledCipherSuites; - - /** True/False option to enable verification of the server certificate **/ - int enableServerCertAuth; - - /** The SSL/TLS version to use. Specify one of MQTT_SSL_VERSION_DEFAULT (0), - * MQTT_SSL_VERSION_TLS_1_0 (1), MQTT_SSL_VERSION_TLS_1_1 (2) or MQTT_SSL_VERSION_TLS_1_2 (3). - * Only used if struct_version is >= 1. - */ - int sslVersion; - - /** - * Whether to carry out post-connect checks, including that a certificate - * matches the given host name. - * Exists only if struct_version >= 2 - */ - int verify; - - /** - * From the OpenSSL documentation: - * If CApath is not NULL, it points to a directory containing CA certificates in PEM format. - * Exists only if struct_version >= 2 - */ - const char* CApath; - - /** - * Callback function for OpenSSL error handler ERR_print_errors_cb - * Exists only if struct_version >= 3 - */ - int (*ssl_error_cb) (const char *str, size_t len, void *u); - - /** - * Application-specific contex for OpenSSL error handler ERR_print_errors_cb - * Exists only if struct_version >= 3 - */ - void* ssl_error_context; - -} MQTTClient_SSLOptions; - -#define MQTTClient_SSLOptions_initializer { {'M', 'Q', 'T', 'S'}, 3, NULL, NULL, NULL, NULL, NULL, 1, MQTT_SSL_VERSION_DEFAULT, 0, NULL, NULL, NULL } - -/** - * MQTTClient_connectOptions defines several settings that control the way the - * client connects to an MQTT server. - * - * Note: Default values are not defined for members of - * MQTTClient_connectOptions so it is good practice to specify all settings. - * If the MQTTClient_connectOptions structure is defined as an automatic - * variable, all members are set to random values and thus must be set by the - * client application. If the MQTTClient_connectOptions structure is defined - * as a static variable, initialization (in compliant compilers) sets all - * values to 0 (NULL for pointers). A #keepAliveInterval setting of 0 prevents - * correct operation of the client and so you must at least set a value - * for #keepAliveInterval. - */ -typedef struct -{ - /** The eyecatcher for this structure. must be MQTC. */ - char struct_id[4]; - /** The version number of this structure. Must be 0, 1, 2, 3, 4, 5 or 6. - * 0 signifies no SSL options and no serverURIs - * 1 signifies no serverURIs - * 2 signifies no MQTTVersion - * 3 signifies no returned values - * 4 signifies no binary password option - * 5 signifies no maxInflightMessages and cleanstart - */ - int struct_version; - /** The "keep alive" interval, measured in seconds, defines the maximum time - * that should pass without communication between the client and the server - * The client will ensure that at least one message travels across the - * network within each keep alive period. In the absence of a data-related - * message during the time period, the client sends a very small MQTT - * "ping" message, which the server will acknowledge. The keep alive - * interval enables the client to detect when the server is no longer - * available without having to wait for the long TCP/IP timeout. - */ - int keepAliveInterval; - /** - * This is a boolean value. The cleansession setting controls the behaviour - * of both the client and the server at connection and disconnection time. - * The client and server both maintain session state information. This - * information is used to ensure "at least once" and "exactly once" - * delivery, and "exactly once" receipt of messages. Session state also - * includes subscriptions created by an MQTT client. You can choose to - * maintain or discard state information between sessions. - * - * When cleansession is true, the state information is discarded at - * connect and disconnect. Setting cleansession to false keeps the state - * information. When you connect an MQTT client application with - * MQTTClient_connect(), the client identifies the connection using the - * client identifier and the address of the server. The server checks - * whether session information for this client - * has been saved from a previous connection to the server. If a previous - * session still exists, and cleansession=true, then the previous session - * information at the client and server is cleared. If cleansession=false, - * the previous session is resumed. If no previous session exists, a new - * session is started. - */ - int cleansession; - /** - * This is a boolean value that controls how many messages can be in-flight - * simultaneously. Setting reliable to true means that a published - * message must be completed (acknowledgements received) before another - * can be sent. Attempts to publish additional messages receive an - * ::MQTTCLIENT_MAX_MESSAGES_INFLIGHT return code. Setting this flag to - * false allows up to 10 messages to be in-flight. This can increase - * overall throughput in some circumstances. - */ - int reliable; - /** - * This is a pointer to an MQTTClient_willOptions structure. If your - * application does not make use of the Last Will and Testament feature, - * set this pointer to NULL. - */ - MQTTClient_willOptions* will; - /** - * MQTT servers that support the MQTT v3.1.1 protocol provide authentication - * and authorisation by user name and password. This is the user name - * parameter. - */ - const char* username; - /** - * MQTT servers that support the MQTT v3.1.1 protocol provide authentication - * and authorisation by user name and password. This is the password - * parameter. - */ - const char* password; - /** - * The time interval in seconds to allow a connect to complete. - */ - int connectTimeout; - /** - * The time interval in seconds after which unacknowledged publish requests are - * retried during a TCP session. With MQTT 3.1.1 and later, retries are - * not required except on reconnect. 0 turns off in-session retries, and is the - * recommended setting. Adding retries to an already overloaded network only - * exacerbates the problem. - */ - int retryInterval; - /** - * This is a pointer to an MQTTClient_SSLOptions structure. If your - * application does not make use of SSL, set this pointer to NULL. - */ - MQTTClient_SSLOptions* ssl; - /** - * The number of entries in the optional serverURIs array. Defaults to 0. - */ - int serverURIcount; - /** - * An optional array of null-terminated strings specifying the servers to - * which the client will connect. Each string takes the form protocol://host:port. - * protocol must be tcp or ssl. For host, you can - * specify either an IP address or a host name. For instance, to connect to - * a server running on the local machines with the default MQTT port, specify - * tcp://localhost:1883. - * If this list is empty (the default), the server URI specified on MQTTClient_create() - * is used. - */ - char* const* serverURIs; - /** - * Sets the version of MQTT to be used on the connect. - * MQTTVERSION_DEFAULT (0) = default: start with 3.1.1, and if that fails, fall back to 3.1 - * MQTTVERSION_3_1 (3) = only try version 3.1 - * MQTTVERSION_3_1_1 (4) = only try version 3.1.1 - * MQTTVERSION_5 (5) = only try version 5.0 - */ - int MQTTVersion; - /** - * Returned from the connect when the MQTT version used to connect is 3.1.1 - */ - struct - { - const char* serverURI; /**< the serverURI connected to */ - int MQTTVersion; /**< the MQTT version used to connect with */ - int sessionPresent; /**< if the MQTT version is 3.1.1, the value of sessionPresent returned in the connack */ - } returned; - /** - * Optional binary password. Only checked and used if the password option is NULL - */ - struct - { - int len; /**< binary password length */ - const void* data; /**< binary password data */ - } binarypwd; - /** - * The maximum number of messages in flight - */ - int maxInflightMessages; - /* - * MQTT V5 clean start flag. Only clears state at the beginning of the session. - */ - int cleanstart; -} MQTTClient_connectOptions; - -#define MQTTClient_connectOptions_initializer { {'M', 'Q', 'T', 'C'}, 6, 60, 1, 1, NULL, NULL, NULL, 30, 0, NULL, 0, NULL, MQTTVERSION_DEFAULT, {NULL, 0, 0}, {0, NULL}, -1, 0} - -#define MQTTClient_connectOptions_initializer5 { {'M', 'Q', 'T', 'C'}, 6, 60, 0, 1, NULL, NULL, NULL, 30, 0, NULL, 0, NULL, MQTTVERSION_5, {NULL, 0, 0}, {0, NULL}, -1, 1} - -/** - * MQTTClient_libraryInfo is used to store details relating to the currently used - * library such as the version in use, the time it was built and relevant openSSL - * options. - * There is one static instance of this struct in MQTTClient.c - */ - -typedef struct -{ - const char* name; - const char* value; -} MQTTClient_nameValue; - -/** - * This function returns version information about the library. - * no trace information will be returned. - * @return an array of strings describing the library. The last entry is a NULL pointer. - */ -DLLExport MQTTClient_nameValue* MQTTClient_getVersionInfo(void); - -/** - * This function attempts to connect a previously-created client (see - * MQTTClient_create()) to an MQTT server using the specified options. If you - * want to enable asynchronous message and status notifications, you must call - * MQTTClient_setCallbacks() prior to MQTTClient_connect(). - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param options A pointer to a valid MQTTClient_connectOptions - * structure. - * @return ::MQTTCLIENT_SUCCESS if the client successfully connects to the - * server. An error code is returned if the client was unable to connect to - * the server. - * Error codes greater than 0 are returned by the MQTT protocol:

- * 1: Connection refused: Unacceptable protocol version
- * 2: Connection refused: Identifier rejected
- * 3: Connection refused: Server unavailable
- * 4: Connection refused: Bad user name or password
- * 5: Connection refused: Not authorized
- * 6-255: Reserved for future use
- */ -DLLExport int MQTTClient_connect(MQTTClient handle, MQTTClient_connectOptions* options); - - -typedef struct MQTTResponse -{ - int version; - enum MQTTReasonCodes reasonCode; - int reasonCodeCount; /* used for subscribeMany5 and unsubscribeMany5 */ - enum MQTTReasonCodes* reasonCodes; /* used for subscribeMany5 and unsubscribeMany5 */ - MQTTProperties* properties; /* optional */ -} MQTTResponse; - -#define MQTTResponse_initializer {1, MQTTREASONCODE_SUCCESS, 0, NULL, NULL} - -DLLExport void MQTTResponse_free(MQTTResponse response); - -DLLExport MQTTResponse MQTTClient_connect5(MQTTClient handle, MQTTClient_connectOptions* options, - MQTTProperties* connectProperties, MQTTProperties* willProperties); - -/** - * This function attempts to disconnect the client from the MQTT - * server. In order to allow the client time to complete handling of messages - * that are in-flight when this function is called, a timeout period is - * specified. When the timeout period has expired, the client disconnects even - * if there are still outstanding message acknowledgements. - * The next time the client connects to the same server, any QoS 1 or 2 - * messages which have not completed will be retried depending on the - * cleansession settings for both the previous and the new connection (see - * MQTTClient_connectOptions.cleansession and MQTTClient_connect()). - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param timeout The client delays disconnection for up to this time (in - * milliseconds) in order to allow in-flight message transfers to complete. - * @return ::MQTTCLIENT_SUCCESS if the client successfully disconnects from - * the server. An error code is returned if the client was unable to disconnect - * from the server - */ -DLLExport int MQTTClient_disconnect(MQTTClient handle, int timeout); - -DLLExport int MQTTClient_disconnect5(MQTTClient handle, int timeout, enum MQTTReasonCodes reason, MQTTProperties* props); - -/** - * This function allows the client application to test whether or not a - * client is currently connected to the MQTT server. - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @return Boolean true if the client is connected, otherwise false. - */ -DLLExport int MQTTClient_isConnected(MQTTClient handle); - - -/* Subscribe is synchronous. QoS list parameter is changed on return to granted QoSs. - Returns return code, MQTTCLIENT_SUCCESS == success, non-zero some sort of error (TBD) */ - -/** - * This function attempts to subscribe a client to a single topic, which may - * contain wildcards (see @ref wildcard). This call also specifies the - * @ref qos requested for the subscription - * (see also MQTTClient_subscribeMany()). - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param topic The subscription topic, which may include wildcards. - * @param qos The requested quality of service for the subscription. - * @return ::MQTTCLIENT_SUCCESS if the subscription request is successful. - * An error code is returned if there was a problem registering the - * subscription. - */ -DLLExport int MQTTClient_subscribe(MQTTClient handle, const char* topic, int qos); - - -DLLExport MQTTResponse MQTTClient_subscribe5(MQTTClient handle, const char* topic, int qos, - MQTTSubscribe_options* opts, MQTTProperties* props); - -/** - * This function attempts to subscribe a client to a list of topics, which may - * contain wildcards (see @ref wildcard). This call also specifies the - * @ref qos requested for each topic (see also MQTTClient_subscribe()). - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param count The number of topics for which the client is requesting - * subscriptions. - * @param topic An array (of length count) of pointers to - * topics, each of which may include wildcards. - * @param qos An array (of length count) of @ref qos - * values. qos[n] is the requested QoS for topic[n]. - * @return ::MQTTCLIENT_SUCCESS if the subscription request is successful. - * An error code is returned if there was a problem registering the - * subscriptions. - */ -DLLExport int MQTTClient_subscribeMany(MQTTClient handle, int count, char* const* topic, int* qos); - -DLLExport MQTTResponse MQTTClient_subscribeMany5(MQTTClient handle, int count, char* const* topic, - int* qos, MQTTSubscribe_options* opts, MQTTProperties* props); - -/** - * This function attempts to remove an existing subscription made by the - * specified client. - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param topic The topic for the subscription to be removed, which may - * include wildcards (see @ref wildcard). - * @return ::MQTTCLIENT_SUCCESS if the subscription is removed. - * An error code is returned if there was a problem removing the - * subscription. - */ -DLLExport int MQTTClient_unsubscribe(MQTTClient handle, const char* topic); - -DLLExport MQTTResponse MQTTClient_unsubscribe5(MQTTClient handle, const char* topic, MQTTProperties* props); - -/** - * This function attempts to remove existing subscriptions to a list of topics - * made by the specified client. - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param count The number subscriptions to be removed. - * @param topic An array (of length count) of pointers to the topics of - * the subscriptions to be removed, each of which may include wildcards. - * @return ::MQTTCLIENT_SUCCESS if the subscriptions are removed. - * An error code is returned if there was a problem removing the subscriptions. - */ -DLLExport int MQTTClient_unsubscribeMany(MQTTClient handle, int count, char* const* topic); - -DLLExport MQTTResponse MQTTClient_unsubscribeMany5(MQTTClient handle, int count, char* const* topic, MQTTProperties* props); - -/** - * This function attempts to publish a message to a given topic (see also - * MQTTClient_publishMessage()). An ::MQTTClient_deliveryToken is issued when - * this function returns successfully. If the client application needs to - * test for succesful delivery of QoS1 and QoS2 messages, this can be done - * either asynchronously or synchronously (see @ref async, - * ::MQTTClient_waitForCompletion and MQTTClient_deliveryComplete()). - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param topicName The topic associated with this message. - * @param payloadlen The length of the payload in bytes. - * @param payload A pointer to the byte array payload of the message. - * @param qos The @ref qos of the message. - * @param retained The retained flag for the message. - * @param dt A pointer to an ::MQTTClient_deliveryToken. This is populated - * with a token representing the message when the function returns - * successfully. If your application does not use delivery tokens, set this - * argument to NULL. - * @return ::MQTTCLIENT_SUCCESS if the message is accepted for publication. - * An error code is returned if there was a problem accepting the message. - */ -DLLExport int MQTTClient_publish(MQTTClient handle, const char* topicName, int payloadlen, const void* payload, int qos, int retained, - MQTTClient_deliveryToken* dt); - -DLLExport MQTTResponse MQTTClient_publish5(MQTTClient handle, const char* topicName, int payloadlen, const void* payload, - int qos, int retained, MQTTProperties* properties, MQTTClient_deliveryToken* dt); -/** - * This function attempts to publish a message to a given topic (see also - * MQTTClient_publish()). An ::MQTTClient_deliveryToken is issued when - * this function returns successfully. If the client application needs to - * test for succesful delivery of QoS1 and QoS2 messages, this can be done - * either asynchronously or synchronously (see @ref async, - * ::MQTTClient_waitForCompletion and MQTTClient_deliveryComplete()). - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param topicName The topic associated with this message. - * @param msg A pointer to a valid MQTTClient_message structure containing - * the payload and attributes of the message to be published. - * @param dt A pointer to an ::MQTTClient_deliveryToken. This is populated - * with a token representing the message when the function returns - * successfully. If your application does not use delivery tokens, set this - * argument to NULL. - * @return ::MQTTCLIENT_SUCCESS if the message is accepted for publication. - * An error code is returned if there was a problem accepting the message. - */ -DLLExport int MQTTClient_publishMessage(MQTTClient handle, const char* topicName, MQTTClient_message* msg, MQTTClient_deliveryToken* dt); - - -DLLExport MQTTResponse MQTTClient_publishMessage5(MQTTClient handle, const char* topicName, MQTTClient_message* msg, - MQTTClient_deliveryToken* dt); - -/** - * This function is called by the client application to synchronize execution - * of the main thread with completed publication of a message. When called, - * MQTTClient_waitForCompletion() blocks execution until the message has been - * successful delivered or the specified timeout has expired. See @ref async. - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param dt The ::MQTTClient_deliveryToken that represents the message being - * tested for successful delivery. Delivery tokens are issued by the - * publishing functions MQTTClient_publish() and MQTTClient_publishMessage(). - * @param timeout The maximum time to wait in milliseconds. - * @return ::MQTTCLIENT_SUCCESS if the message was successfully delivered. - * An error code is returned if the timeout expires or there was a problem - * checking the token. - */ -DLLExport int MQTTClient_waitForCompletion(MQTTClient handle, MQTTClient_deliveryToken dt, unsigned long timeout); - - -/** - * This function sets a pointer to an array of delivery tokens for - * messages that are currently in-flight (pending completion). - * - * Important note: The memory used to hold the array of tokens is - * malloc()'d in this function. The client application is responsible for - * freeing this memory when it is no longer required. - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param tokens The address of a pointer to an ::MQTTClient_deliveryToken. - * When the function returns successfully, the pointer is set to point to an - * array of tokens representing messages pending completion. The last member of - * the array is set to -1 to indicate there are no more tokens. If no tokens - * are pending, the pointer is set to NULL. - * @return ::MQTTCLIENT_SUCCESS if the function returns successfully. - * An error code is returned if there was a problem obtaining the list of - * pending tokens. - */ -DLLExport int MQTTClient_getPendingDeliveryTokens(MQTTClient handle, MQTTClient_deliveryToken **tokens); - -/** - * When implementing a single-threaded client, call this function periodically - * to allow processing of message retries and to send MQTT keepalive pings. - * If the application is calling MQTTClient_receive() regularly, then it is - * not necessary to call this function. - */ -DLLExport void MQTTClient_yield(void); - -/** - * This function performs a synchronous receive of incoming messages. It should - * be used only when the client application has not set callback methods to - * support asynchronous receipt of messages (see @ref async and - * MQTTClient_setCallbacks()). Using this function allows a single-threaded - * client subscriber application to be written. When called, this function - * blocks until the next message arrives or the specified timeout expires - *(see also MQTTClient_yield()). - * - * Important note: The application must free() the memory allocated - * to the topic and the message when processing is complete (see - * MQTTClient_freeMessage()). - * @param handle A valid client handle from a successful call to - * MQTTClient_create(). - * @param topicName The address of a pointer to a topic. This function - * allocates the memory for the topic and returns it to the application - * by setting topicName to point to the topic. - * @param topicLen The length of the topic. If the return code from this - * function is ::MQTTCLIENT_TOPICNAME_TRUNCATED, the topic contains embedded - * NULL characters and the full topic should be retrieved by using - * topicLen. - * @param message The address of a pointer to the received message. This - * function allocates the memory for the message and returns it to the - * application by setting message to point to the received message. - * The pointer is set to NULL if the timeout expires. - * @param timeout The length of time to wait for a message in milliseconds. - * @return ::MQTTCLIENT_SUCCESS or ::MQTTCLIENT_TOPICNAME_TRUNCATED if a - * message is received. ::MQTTCLIENT_SUCCESS can also indicate that the - * timeout expired, in which case message is NULL. An error code is - * returned if there was a problem trying to receive a message. - */ -DLLExport int MQTTClient_receive(MQTTClient handle, char** topicName, int* topicLen, MQTTClient_message** message, - unsigned long timeout); - -/** - * This function frees memory allocated to an MQTT message, including the - * additional memory allocated to the message payload. The client application - * calls this function when the message has been fully processed. Important - * note: This function does not free the memory allocated to a message - * topic string. It is the responsibility of the client application to free - * this memory using the MQTTClient_free() library function. - * @param msg The address of a pointer to the ::MQTTClient_message structure - * to be freed. - */ -DLLExport void MQTTClient_freeMessage(MQTTClient_message** msg); - -/** - * This function frees memory allocated by the MQTT C client library, especially the - * topic name. This is needed on Windows when the client libary and application - * program have been compiled with different versions of the C compiler. It is - * thus good policy to always use this function when freeing any MQTT C client- - * allocated memory. - * @param ptr The pointer to the client library storage to be freed. - */ -DLLExport void MQTTClient_free(void* ptr); - -/** - * This function frees the memory allocated to an MQTT client (see - * MQTTClient_create()). It should be called when the client is no longer - * required. - * @param handle A pointer to the handle referring to the ::MQTTClient - * structure to be freed. - */ -DLLExport void MQTTClient_destroy(MQTTClient* handle); - - -enum MQTTCLIENT_TRACE_LEVELS -{ - MQTTCLIENT_TRACE_MAXIMUM = 1, - MQTTCLIENT_TRACE_MEDIUM, - MQTTCLIENT_TRACE_MINIMUM, - MQTTCLIENT_TRACE_PROTOCOL, - MQTTCLIENT_TRACE_ERROR, - MQTTCLIENT_TRACE_SEVERE, - MQTTCLIENT_TRACE_FATAL, -}; - - -/** - * This function sets the level of trace information which will be - * returned in the trace callback. - * @param level the trace level required - */ -DLLExport void MQTTClient_setTraceLevel(enum MQTTCLIENT_TRACE_LEVELS level); - - -/** - * This is a callback function prototype which must be implemented if you want - * to receive trace information. - * @param level the trace level of the message returned - * @param message the trace message. This is a pointer to a static buffer which - * will be overwritten on each call. You must copy the data if you want to keep - * it for later. - */ -typedef void MQTTClient_traceCallback(enum MQTTCLIENT_TRACE_LEVELS level, char* message); - -/** - * This function sets the trace callback if needed. If set to NULL, - * no trace information will be returned. The default trace level is - * MQTTASYNC_TRACE_MINIMUM. - * @param callback a pointer to the function which will handle the trace information - */ -DLLExport void MQTTClient_setTraceCallback(MQTTClient_traceCallback* callback); - -/** - * Returns a pointer to the string representation of the error or NULL. - * - * Do not free after use. Returns NULL if the error code is unknown. - */ -DLLExport const char* MQTTClient_strerror(int code); - -#ifdef __cplusplus - } -#endif - -#endif - -/** - * @cond MQTTClient_main - * @page async Asynchronous vs synchronous client applications - * The client library supports two modes of operation. These are referred to - * as synchronous and asynchronous modes. If your application - * calls MQTTClient_setCallbacks(), this puts the client into asynchronous - * mode, otherwise it operates in synchronous mode. - * - * In synchronous mode, the client application runs on a single thread. - * Messages are published using the MQTTClient_publish() and - * MQTTClient_publishMessage() functions. To determine that a QoS1 or QoS2 - * (see @ref qos) message has been successfully delivered, the application - * must call the MQTTClient_waitForCompletion() function. An example showing - * synchronous publication is shown in @ref pubsync. Receiving messages in - * synchronous mode uses the MQTTClient_receive() function. Client applications - * must call either MQTTClient_receive() or MQTTClient_yield() relatively - * frequently in order to allow processing of acknowledgements and the MQTT - * "pings" that keep the network connection to the server alive. - * - * In asynchronous mode, the client application runs on several threads. The - * main program calls functions in the client library to publish and subscribe, - * just as for the synchronous mode. Processing of handshaking and maintaining - * the network connection is performed in the background, however. - * Notifications of status and message reception are provided to the client - * application using callbacks registered with the library by the call to - * MQTTClient_setCallbacks() (see MQTTClient_messageArrived(), - * MQTTClient_connectionLost() and MQTTClient_deliveryComplete()). - * This API is not thread safe however - it is not possible to call it from multiple - * threads without synchronization. You can use the MQTTAsync API for that. - * - * @page wildcard Subscription wildcards - * Every MQTT message includes a topic that classifies it. MQTT servers use - * topics to determine which subscribers should receive messages published to - * the server. - * - * Consider the server receiving messages from several environmental sensors. - * Each sensor publishes its measurement data as a message with an associated - * topic. Subscribing applications need to know which sensor originally - * published each received message. A unique topic is thus used to identify - * each sensor and measurement type. Topics such as SENSOR1TEMP, - * SENSOR1HUMIDITY, SENSOR2TEMP and so on achieve this but are not very - * flexible. If additional sensors are added to the system at a later date, - * subscribing applications must be modified to receive them. - * - * To provide more flexibility, MQTT supports a hierarchical topic namespace. - * This allows application designers to organize topics to simplify their - * management. Levels in the hierarchy are delimited by the '/' character, - * such as SENSOR/1/HUMIDITY. Publishers and subscribers use these - * hierarchical topics as already described. - * - * For subscriptions, two wildcard characters are supported: - *
    - *
  • A '#' character represents a complete sub-tree of the hierarchy and - * thus must be the last character in a subscription topic string, such as - * SENSOR/#. This will match any topic starting with SENSOR/, such as - * SENSOR/1/TEMP and SENSOR/2/HUMIDITY.
  • - *
  • A '+' character represents a single level of the hierarchy and is - * used between delimiters. For example, SENSOR/+/TEMP will match - * SENSOR/1/TEMP and SENSOR/2/TEMP.
  • - *
- * Publishers are not allowed to use the wildcard characters in their topic - * names. - * - * Deciding on your topic hierarchy is an important step in your system design. - * - * @page qos Quality of service - * The MQTT protocol provides three qualities of service for delivering - * messages between clients and servers: "at most once", "at least once" and - * "exactly once". - * - * Quality of service (QoS) is an attribute of an individual message being - * published. An application sets the QoS for a specific message by setting the - * MQTTClient_message.qos field to the required value. - * - * A subscribing client can set the maximum quality of service a server uses - * to send messages that match the client subscriptions. The - * MQTTClient_subscribe() and MQTTClient_subscribeMany() functions set this - * maximum. The QoS of a message forwarded to a subscriber thus might be - * different to the QoS given to the message by the original publisher. - * The lower of the two values is used to forward a message. - * - * The three levels are: - * - * QoS0, At most once: The message is delivered at most once, or it - * may not be delivered at all. Its delivery across the network is not - * acknowledged. The message is not stored. The message could be lost if the - * client is disconnected, or if the server fails. QoS0 is the fastest mode of - * transfer. It is sometimes called "fire and forget". - * - * The MQTT protocol does not require servers to forward publications at QoS0 - * to a client. If the client is disconnected at the time the server receives - * the publication, the publication might be discarded, depending on the - * server implementation. - * - * QoS1, At least once: The message is always delivered at least once. - * It might be delivered multiple times if there is a failure before an - * acknowledgment is received by the sender. The message must be stored - * locally at the sender, until the sender receives confirmation that the - * message has been published by the receiver. The message is stored in case - * the message must be sent again. - * - * QoS2, Exactly once: The message is always delivered exactly once. - * The message must be stored locally at the sender, until the sender receives - * confirmation that the message has been published by the receiver. The - * message is stored in case the message must be sent again. QoS2 is the - * safest, but slowest mode of transfer. A more sophisticated handshaking - * and acknowledgement sequence is used than for QoS1 to ensure no duplication - * of messages occurs. - * @page pubsync Synchronous publication example -@code -#include -#include -#include -#include "MQTTClient.h" - -#define ADDRESS "tcp://localhost:1883" -#define CLIENTID "ExampleClientPub" -#define TOPIC "MQTT Examples" -#define PAYLOAD "Hello World!" -#define QOS 1 -#define TIMEOUT 10000L - -int main(int argc, char* argv[]) -{ - MQTTClient client; - MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; - MQTTClient_message pubmsg = MQTTClient_message_initializer; - MQTTClient_deliveryToken token; - int rc; - - MQTTClient_create(&client, ADDRESS, CLIENTID, - MQTTCLIENT_PERSISTENCE_NONE, NULL); - conn_opts.keepAliveInterval = 20; - conn_opts.cleansession = 1; - - if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) - { - printf("Failed to connect, return code %d\n", rc); - exit(EXIT_FAILURE); - } - pubmsg.payload = PAYLOAD; - pubmsg.payloadlen = strlen(PAYLOAD); - pubmsg.qos = QOS; - pubmsg.retained = 0; - MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token); - printf("Waiting for up to %d seconds for publication of %s\n" - "on topic %s for client with ClientID: %s\n", - (int)(TIMEOUT/1000), PAYLOAD, TOPIC, CLIENTID); - rc = MQTTClient_waitForCompletion(client, token, TIMEOUT); - printf("Message with delivery token %d delivered\n", token); - MQTTClient_disconnect(client, 10000); - MQTTClient_destroy(&client); - return rc; -} - - * @endcode - * - * @page pubasync Asynchronous publication example -@code{.c} -#include -#include -#include -#include "MQTTClient.h" - -#define ADDRESS "tcp://localhost:1883" -#define CLIENTID "ExampleClientPub" -#define TOPIC "MQTT Examples" -#define PAYLOAD "Hello World!" -#define QOS 1 -#define TIMEOUT 10000L - -volatile MQTTClient_deliveryToken deliveredtoken; - -void delivered(void *context, MQTTClient_deliveryToken dt) -{ - printf("Message with token value %d delivery confirmed\n", dt); - deliveredtoken = dt; -} - -int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message) -{ - int i; - char* payloadptr; - - printf("Message arrived\n"); - printf(" topic: %s\n", topicName); - printf(" message: "); - - payloadptr = message->payload; - for(i=0; ipayloadlen; i++) - { - putchar(*payloadptr++); - } - putchar('\n'); - MQTTClient_freeMessage(&message); - MQTTClient_free(topicName); - return 1; -} - -void connlost(void *context, char *cause) -{ - printf("\nConnection lost\n"); - printf(" cause: %s\n", cause); -} - -int main(int argc, char* argv[]) -{ - MQTTClient client; - MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; - MQTTClient_message pubmsg = MQTTClient_message_initializer; - MQTTClient_deliveryToken token; - int rc; - - MQTTClient_create(&client, ADDRESS, CLIENTID, - MQTTCLIENT_PERSISTENCE_NONE, NULL); - conn_opts.keepAliveInterval = 20; - conn_opts.cleansession = 1; - - MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered); - - if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) - { - printf("Failed to connect, return code %d\n", rc); - exit(EXIT_FAILURE); - } - pubmsg.payload = PAYLOAD; - pubmsg.payloadlen = strlen(PAYLOAD); - pubmsg.qos = QOS; - pubmsg.retained = 0; - deliveredtoken = 0; - MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token); - printf("Waiting for publication of %s\n" - "on topic %s for client with ClientID: %s\n", - PAYLOAD, TOPIC, CLIENTID); - while(deliveredtoken != token); - MQTTClient_disconnect(client, 10000); - MQTTClient_destroy(&client); - return rc; -} - - * @endcode - * @page subasync Asynchronous subscription example -@code -#include -#include -#include -#include "MQTTClient.h" - -#define ADDRESS "tcp://localhost:1883" -#define CLIENTID "ExampleClientSub" -#define TOPIC "MQTT Examples" -#define PAYLOAD "Hello World!" -#define QOS 1 -#define TIMEOUT 10000L - -volatile MQTTClient_deliveryToken deliveredtoken; - -void delivered(void *context, MQTTClient_deliveryToken dt) -{ - printf("Message with token value %d delivery confirmed\n", dt); - deliveredtoken = dt; -} - -int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message) -{ - int i; - char* payloadptr; - - printf("Message arrived\n"); - printf(" topic: %s\n", topicName); - printf(" message: "); - - payloadptr = message->payload; - for(i=0; ipayloadlen; i++) - { - putchar(*payloadptr++); - } - putchar('\n'); - MQTTClient_freeMessage(&message); - MQTTClient_free(topicName); - return 1; -} - -void connlost(void *context, char *cause) -{ - printf("\nConnection lost\n"); - printf(" cause: %s\n", cause); -} - -int main(int argc, char* argv[]) -{ - MQTTClient client; - MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; - int rc; - int ch; - - MQTTClient_create(&client, ADDRESS, CLIENTID, - MQTTCLIENT_PERSISTENCE_NONE, NULL); - conn_opts.keepAliveInterval = 20; - conn_opts.cleansession = 1; - - MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered); - - if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) - { - printf("Failed to connect, return code %d\n", rc); - exit(EXIT_FAILURE); - } - printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n" - "Press Q to quit\n\n", TOPIC, CLIENTID, QOS); - MQTTClient_subscribe(client, TOPIC, QOS); - - do - { - ch = getchar(); - } while(ch!='Q' && ch != 'q'); - - MQTTClient_disconnect(client, 10000); - MQTTClient_destroy(&client); - return rc; -} - - * @endcode - * @page tracing Tracing - * - * Runtime tracing is controlled by environment variables. - * - * Tracing is switched on by setting MQTT_C_CLIENT_TRACE. A value of ON, or stdout, prints to - * stdout, any other value is interpreted as a file name to use. - * - * The amount of trace detail is controlled with the MQTT_C_CLIENT_TRACE_LEVEL environment - * variable - valid values are ERROR, PROTOCOL, MINIMUM, MEDIUM and MAXIMUM - * (from least to most verbose). - * - * The variable MQTT_C_CLIENT_TRACE_MAX_LINES limits the number of lines of trace that are output - * to a file. Two files are used at most, when they are full, the last one is overwritten with the - * new trace entries. The default size is 1000 lines. - * - * ### MQTT Packet Tracing - * - * A feature that can be very useful is printing the MQTT packets that are sent and received. To - * achieve this, use the following environment variable settings: - * @code - MQTT_C_CLIENT_TRACE=ON - MQTT_C_CLIENT_TRACE_LEVEL=PROTOCOL - * @endcode - * The output you should see looks like this: - * @code - 20130528 155936.813 3 stdout-subscriber -> CONNECT cleansession: 1 (0) - 20130528 155936.813 3 stdout-subscriber <- CONNACK rc: 0 - 20130528 155936.813 3 stdout-subscriber -> SUBSCRIBE msgid: 1 (0) - 20130528 155936.813 3 stdout-subscriber <- SUBACK msgid: 1 - 20130528 155941.818 3 stdout-subscriber -> DISCONNECT (0) - * @endcode - * where the fields are: - * 1. date - * 2. time - * 3. socket number - * 4. client id - * 5. direction (-> from client to server, <- from server to client) - * 6. packet details - * - * ### Default Level Tracing - * - * This is an extract of a default level trace of a call to connect: - * @code - 19700101 010000.000 (1152206656) (0)> MQTTClient_connect:893 - 19700101 010000.000 (1152206656) (1)> MQTTClient_connectURI:716 - 20130528 160447.479 Connecting to serverURI localhost:1883 - 20130528 160447.479 (1152206656) (2)> MQTTProtocol_connect:98 - 20130528 160447.479 (1152206656) (3)> MQTTProtocol_addressPort:48 - 20130528 160447.479 (1152206656) (3)< MQTTProtocol_addressPort:73 - 20130528 160447.479 (1152206656) (3)> Socket_new:599 - 20130528 160447.479 New socket 4 for localhost, port 1883 - 20130528 160447.479 (1152206656) (4)> Socket_addSocket:163 - 20130528 160447.479 (1152206656) (5)> Socket_setnonblocking:73 - 20130528 160447.479 (1152206656) (5)< Socket_setnonblocking:78 (0) - 20130528 160447.479 (1152206656) (4)< Socket_addSocket:176 (0) - 20130528 160447.479 (1152206656) (4)> Socket_error:95 - 20130528 160447.479 (1152206656) (4)< Socket_error:104 (115) - 20130528 160447.479 Connect pending - 20130528 160447.479 (1152206656) (3)< Socket_new:683 (115) - 20130528 160447.479 (1152206656) (2)< MQTTProtocol_connect:131 (115) - * @endcode - * where the fields are: - * 1. date - * 2. time - * 3. thread id - * 4. function nesting level - * 5. function entry (>) or exit (<) - * 6. function name : line of source code file - * 7. return value (if there is one) - * - * ### Memory Allocation Tracing - * - * Setting the trace level to maximum causes memory allocations and frees to be traced along with - * the default trace entries, with messages like the following: - * @code - 20130528 161819.657 Allocating 16 bytes in heap at file /home/icraggs/workspaces/mqrtc/mqttv3c/src/MQTTPacket.c line 177 ptr 0x179f930 - - 20130528 161819.657 Freeing 16 bytes in heap at file /home/icraggs/workspaces/mqrtc/mqttv3c/src/MQTTPacket.c line 201, heap use now 896 bytes - * @endcode - * When the last MQTT client object is destroyed, if the trace is being recorded - * and all memory allocated by the client library has not been freed, an error message will be - * written to the trace. This can help with fixing memory leaks. The message will look like this: - * @code - 20130528 163909.208 Some memory not freed at shutdown, possible memory leak - 20130528 163909.208 Heap scan start, total 880 bytes - 20130528 163909.208 Heap element size 32, line 354, file /home/icraggs/workspaces/mqrtc/mqttv3c/src/MQTTPacket.c, ptr 0x260cb00 - 20130528 163909.208 Content - 20130528 163909.209 Heap scan end - * @endcode - * @endcond - */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTClientPersistence.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTClientPersistence.h deleted file mode 100644 index 4c9014d..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTClientPersistence.h +++ /dev/null @@ -1,254 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2012 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - *******************************************************************************/ - -/** - * @file - * \brief This structure represents a persistent data store, used to store - * outbound and inbound messages, in order to achieve reliable messaging. - * - * The MQTT Client persists QoS1 and QoS2 messages in order to meet the - * assurances of delivery associated with these @ref qos levels. The messages - * are saved in persistent storage - * The type and context of the persistence implementation are specified when - * the MQTT client is created (see MQTTClient_create()). The default - * persistence type (::MQTTCLIENT_PERSISTENCE_DEFAULT) uses a file system-based - * persistence mechanism. The persistence_context argument passed to - * MQTTClient_create() when using the default peristence is a string - * representing the location of the persistence directory. If the context - * argument is NULL, the working directory will be used. - * - * To use memory-based persistence, an application passes - * ::MQTTCLIENT_PERSISTENCE_NONE as the persistence_type to - * MQTTClient_create(). This can lead to message loss in certain situations, - * but can be appropriate in some cases (see @ref qos). - * - * Client applications can provide their own persistence mechanism by passing - * ::MQTTCLIENT_PERSISTENCE_USER as the persistence_type. To implement a - * custom persistence mechanism, the application must pass an initialized - * ::MQTTClient_persistence structure as the persistence_context - * argument to MQTTClient_create(). - * - * If the functions defined return an ::MQTTCLIENT_PERSISTENCE_ERROR then the - * state of the persisted data should remain as it was prior to the function - * being called. For example, if Persistence_put() returns - * ::MQTTCLIENT_PERSISTENCE_ERROR, then it is assumed tha tthe persistent store - * does not contain the data that was passed to the function. Similarly, if - * Persistence_remove() returns ::MQTTCLIENT_PERSISTENCE_ERROR then it is - * assumed that the data to be removed is still held in the persistent store. - * - * It is up to the persistence implementation to log any error information that - * may be required to diagnose a persistence mechanism failure. - */ - -/* -/// @cond EXCLUDE -*/ -#if !defined(MQTTCLIENTPERSISTENCE_H) -#define MQTTCLIENTPERSISTENCE_H -/* -/// @endcond -*/ - -/** - * This persistence_type value specifies the default file system-based - * persistence mechanism (see MQTTClient_create()). - */ -#define MQTTCLIENT_PERSISTENCE_DEFAULT 0 -/** - * This persistence_type value specifies a memory-based - * persistence mechanism (see MQTTClient_create()). - */ -#define MQTTCLIENT_PERSISTENCE_NONE 1 -/** - * This persistence_type value specifies an application-specific - * persistence mechanism (see MQTTClient_create()). - */ -#define MQTTCLIENT_PERSISTENCE_USER 2 - -/** - * Application-specific persistence functions must return this error code if - * there is a problem executing the function. - */ -#define MQTTCLIENT_PERSISTENCE_ERROR -2 - -/** - * @brief Initialize the persistent store. - * - * Either open the existing persistent store for this client ID or create a new - * one if one doesn't exist. If the persistent store is already open, return - * without taking any action. - * - * An application can use the same client identifier to connect to many - * different servers. The clientid in conjunction with the - * serverURI uniquely identifies the persistence store required. - * - * @param handle The address of a pointer to a handle for this persistence - * implementation. This function must set handle to a valid reference to the - * persistence following a successful return. - * The handle pointer is passed as an argument to all the other - * persistence functions. It may include the context parameter and/or any other - * data for use by the persistence functions. - * @param clientID The client identifier for which the persistent store should - * be opened. - * @param serverURI The connection string specified when the MQTT client was - * created (see MQTTClient_create()). - * @param context A pointer to any data required to initialize the persistent - * store (see ::MQTTClient_persistence). - * @return Return 0 if the function completes successfully, otherwise return - * ::MQTTCLIENT_PERSISTENCE_ERROR. - */ -typedef int (*Persistence_open)(void** handle, const char* clientID, const char* serverURI, void* context); - -/** - * @brief Close the persistent store referred to by the handle. - * - * @param handle The handle pointer from a successful call to - * Persistence_open(). - * @return Return 0 if the function completes successfully, otherwise return - * ::MQTTCLIENT_PERSISTENCE_ERROR. - */ -typedef int (*Persistence_close)(void* handle); - -/** - * @brief Put the specified data into the persistent store. - * - * @param handle The handle pointer from a successful call to - * Persistence_open(). - * @param key A string used as the key for the data to be put in the store. The - * key is later used to retrieve data from the store with Persistence_get(). - * @param bufcount The number of buffers to write to the persistence store. - * @param buffers An array of pointers to the data buffers associated with - * this key. - * @param buflens An array of lengths of the data buffers. buflen[n] - * gives the length of buffer[n]. - * @return Return 0 if the function completes successfully, otherwise return - * ::MQTTCLIENT_PERSISTENCE_ERROR. - */ -typedef int (*Persistence_put)(void* handle, char* key, int bufcount, char* buffers[], int buflens[]); - -/** - * @brief Retrieve the specified data from the persistent store. - * - * @param handle The handle pointer from a successful call to - * Persistence_open(). - * @param key A string that is the key for the data to be retrieved. This is - * the same key used to save the data to the store with Persistence_put(). - * @param buffer The address of a pointer to a buffer. This function sets the - * pointer to point at the retrieved data, if successful. - * @param buflen The address of an int that is set to the length of - * buffer by this function if successful. - * @return Return 0 if the function completes successfully, otherwise return - * ::MQTTCLIENT_PERSISTENCE_ERROR. - */ -typedef int (*Persistence_get)(void* handle, char* key, char** buffer, int* buflen); - -/** - * @brief Remove the data for the specified key from the store. - * - * @param handle The handle pointer from a successful call to - * Persistence_open(). - * @param key A string that is the key for the data to be removed from the - * store. This is the same key used to save the data to the store with - * Persistence_put(). - * @return Return 0 if the function completes successfully, otherwise return - * ::MQTTCLIENT_PERSISTENCE_ERROR. - */ -typedef int (*Persistence_remove)(void* handle, char* key); - -/** - * @brief Returns the keys in this persistent data store. - * - * @param handle The handle pointer from a successful call to - * Persistence_open(). - * @param keys The address of a pointer to pointers to strings. Assuming - * successful execution, this function allocates memory to hold the returned - * keys (strings used to store the data with Persistence_put()). It also - * allocates memory to hold an array of pointers to these strings. keys - * is set to point to the array of pointers to strings. - * @param nkeys A pointer to the number of keys in this persistent data store. - * This function sets the number of keys, if successful. - * @return Return 0 if the function completes successfully, otherwise return - * ::MQTTCLIENT_PERSISTENCE_ERROR. - */ -typedef int (*Persistence_keys)(void* handle, char*** keys, int* nkeys); - -/** - * @brief Clears the persistence store, so that it no longer contains any - * persisted data. - * - * @param handle The handle pointer from a successful call to - * Persistence_open(). - * @return Return 0 if the function completes successfully, otherwise return - * ::MQTTCLIENT_PERSISTENCE_ERROR. - */ -typedef int (*Persistence_clear)(void* handle); - -/** - * @brief Returns whether any data has been persisted using the specified key. - * - * @param handle The handle pointer from a successful call to - * Persistence_open(). - * @param key The string to be tested for existence in the store. - * @return Return 0 if the key was found in the store, otherwise return - * ::MQTTCLIENT_PERSISTENCE_ERROR. - */ -typedef int (*Persistence_containskey)(void* handle, char* key); - -/** - * @brief A structure containing the function pointers to a persistence - * implementation and the context or state that will be shared across all - * the persistence functions. - */ -typedef struct { - /** - * A pointer to any data required to initialize the persistent store. - */ - void* context; - /** - * A function pointer to an implementation of Persistence_open(). - */ - Persistence_open popen; - /** - * A function pointer to an implementation of Persistence_close(). - */ - Persistence_close pclose; - /** - * A function pointer to an implementation of Persistence_put(). - */ - Persistence_put pput; - /** - * A function pointer to an implementation of Persistence_get(). - */ - Persistence_get pget; - /** - * A function pointer to an implementation of Persistence_remove(). - */ - Persistence_remove premove; - /** - * A function pointer to an implementation of Persistence_keys(). - */ - Persistence_keys pkeys; - /** - * A function pointer to an implementation of Persistence_clear(). - */ - Persistence_clear pclear; - /** - * A function pointer to an implementation of Persistence_containskey(). - */ - Persistence_containskey pcontainskey; -} MQTTClient_persistence; - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTConnect.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTConnect.h deleted file mode 100644 index 98c2c16..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTConnect.h +++ /dev/null @@ -1,148 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014, 2017 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs - add connack return code definitions - * Xiang Rong - 442039 Add makefile to Embedded C client - * Ian Craggs - fix for issue #64, bit order in connack response - *******************************************************************************/ - -#ifndef MQTTCONNECT_H_ -#define MQTTCONNECT_H_ - -enum connack_return_codes -{ - MQTT_CONNECTION_ACCEPTED = 0, - MQTT_UNNACCEPTABLE_PROTOCOL = 1, - MQTT_CLIENTID_REJECTED = 2, - MQTT_SERVER_UNAVAILABLE = 3, - MQTT_BAD_USERNAME_OR_PASSWORD = 4, - MQTT_NOT_AUTHORIZED = 5, -}; - -#if !defined(DLLImport) - #define DLLImport -#endif -#if !defined(DLLExport) - #define DLLExport -#endif - - -typedef union -{ - unsigned char all; /**< all connect flags */ -#if defined(REVERSED) - struct - { - unsigned int username : 1; /**< 3.1 user name */ - unsigned int password : 1; /**< 3.1 password */ - unsigned int willRetain : 1; /**< will retain setting */ - unsigned int willQoS : 2; /**< will QoS value */ - unsigned int will : 1; /**< will flag */ - unsigned int cleansession : 1; /**< clean session flag */ - unsigned int : 1; /**< unused */ - } bits; -#else - struct - { - unsigned int : 1; /**< unused */ - unsigned int cleansession : 1; /**< cleansession flag */ - unsigned int will : 1; /**< will flag */ - unsigned int willQoS : 2; /**< will QoS value */ - unsigned int willRetain : 1; /**< will retain setting */ - unsigned int password : 1; /**< 3.1 password */ - unsigned int username : 1; /**< 3.1 user name */ - } bits; -#endif -} MQTTConnectFlags; /**< connect flags byte */ - - - -/** - * Defines the MQTT "Last Will and Testament" (LWT) settings for - * the connect packet. - */ -typedef struct -{ - /** The eyecatcher for this structure. must be MQTW. */ - char struct_id[4]; - /** The version number of this structure. Must be 0 */ - int struct_version; - /** The LWT topic to which the LWT message will be published. */ - MQTTString topicName; - /** The LWT payload. */ - MQTTString message; - /** - * The retained flag for the LWT message (see MQTTAsync_message.retained). - */ - unsigned char retained; - /** - * The quality of service setting for the LWT message (see - * MQTTAsync_message.qos and @ref qos). - */ - char qos; -} MQTTPacket_willOptions; - - -#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 } - - -typedef struct -{ - /** The eyecatcher for this structure. must be MQTC. */ - char struct_id[4]; - /** The version number of this structure. Must be 0 */ - int struct_version; - /** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1 - */ - unsigned char MQTTVersion; - MQTTString clientID; - unsigned short keepAliveInterval; - unsigned char cleansession; - unsigned char willFlag; - MQTTPacket_willOptions will; - MQTTString username; - MQTTString password; -} MQTTPacket_connectData; - -typedef union -{ - unsigned char all; /**< all connack flags */ -#if defined(REVERSED) - struct - { - unsigned int reserved : 7; /**< unused */ - unsigned int sessionpresent : 1; /**< session present flag */ - } bits; -#else - struct - { - unsigned int sessionpresent : 1; /**< session present flag */ - unsigned int reserved: 7; /**< unused */ - } bits; -#endif -} MQTTConnackFlags; /**< connack flags byte */ - -#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \ - MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} } - -DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options); -DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len); - -DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent); -DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen); - -DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen); -DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen); - -#endif /* MQTTCONNECT_H_ */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTFormat.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTFormat.h deleted file mode 100644 index 47b0c41..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTFormat.h +++ /dev/null @@ -1,37 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - *******************************************************************************/ - -#if !defined(MQTTFORMAT_H) -#define MQTTFORMAT_H - -#include "StackTrace.h" -#include "MQTTPacket.h" - -const char* MQTTPacket_getName(unsigned short packetid); -int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data); -int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent); -int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained, - unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen); -int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid); -int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count, - MQTTString topicFilters[], int requestedQoSs[]); -int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs); -int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, - int count, MQTTString topicFilters[]); -char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen); -char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen); - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPacket.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPacket.h deleted file mode 100644 index 350886e..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPacket.h +++ /dev/null @@ -1,270 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs, Allan Stockdill-Mander - SSL updates - * Ian Craggs - MQTT 3.1.1 support - * Ian Craggs - big endian Linux reversed definition - * Ian Craggs - MQTT 5.0 support - *******************************************************************************/ - -#if !defined(MQTTPACKET_H) -#define MQTTPACKET_H - -#include "Socket.h" -#if defined(OPENSSL) -#include "SSLSocket.h" -#endif -#include "LinkedList.h" -#include "Clients.h" - -typedef unsigned int bool; -typedef void* (*pf)(int, unsigned char, char*, size_t); - -#include "MQTTProperties.h" -#include "MQTTReasonCodes.h" - -enum errors -{ - MQTTPACKET_BAD = -4, - MQTTPACKET_BUFFER_TOO_SHORT = -2, - MQTTPACKET_READ_ERROR = -1, - MQTTPACKET_READ_COMPLETE -}; - - -enum msgTypes -{ - CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, - PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, - PINGREQ, PINGRESP, DISCONNECT, AUTH -}; - -#if defined(__linux__) -#include -#if __BYTE_ORDER == __BIG_ENDIAN - #define REVERSED 1 -#endif -#endif - -/** - * Bitfields for the MQTT header byte. - */ -typedef union -{ - /*unsigned*/ char byte; /**< the whole byte */ -#if defined(REVERSED) - struct - { - unsigned int type : 4; /**< message type nibble */ - bool dup : 1; /**< DUP flag bit */ - unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */ - bool retain : 1; /**< retained flag bit */ - } bits; -#else - struct - { - bool retain : 1; /**< retained flag bit */ - unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */ - bool dup : 1; /**< DUP flag bit */ - unsigned int type : 4; /**< message type nibble */ - } bits; -#endif -} Header; - - -/** - * Data for a connect packet. - */ -typedef struct -{ - Header header; /**< MQTT header byte */ - union - { - unsigned char all; /**< all connect flags */ -#if defined(REVERSED) - struct - { - bool username : 1; /**< 3.1 user name */ - bool password : 1; /**< 3.1 password */ - bool willRetain : 1; /**< will retain setting */ - unsigned int willQoS : 2; /**< will QoS value */ - bool will : 1; /**< will flag */ - bool cleanstart : 1; /**< cleansession flag */ - int : 1; /**< unused */ - } bits; -#else - struct - { - int : 1; /**< unused */ - bool cleanstart : 1; /**< cleansession flag */ - bool will : 1; /**< will flag */ - unsigned int willQoS : 2; /**< will QoS value */ - bool willRetain : 1; /**< will retain setting */ - bool password : 1; /**< 3.1 password */ - bool username : 1; /**< 3.1 user name */ - } bits; -#endif - } flags; /**< connect flags byte */ - - char *Protocol, /**< MQTT protocol name */ - *clientID, /**< string client id */ - *willTopic, /**< will topic */ - *willMsg; /**< will payload */ - - int keepAliveTimer; /**< keepalive timeout value in seconds */ - unsigned char version; /**< MQTT version number */ -} Connect; - - -/** - * Data for a connack packet. - */ -typedef struct -{ - Header header; /**< MQTT header byte */ - union - { - unsigned char all; /**< all connack flags */ -#if defined(REVERSED) - struct - { - unsigned int reserved : 7; /**< message type nibble */ - bool sessionPresent : 1; /**< was a session found on the server? */ - } bits; -#else - struct - { - bool sessionPresent : 1; /**< was a session found on the server? */ - unsigned int reserved : 7; /**< message type nibble */ - } bits; -#endif - } flags; /**< connack flags byte */ - unsigned char rc; /**< connack reason code */ - unsigned int MQTTVersion; /**< the version of MQTT */ - MQTTProperties properties; /**< MQTT 5.0 properties. Not used for MQTT < 5.0 */ -} Connack; - - -/** - * Data for a packet with header only. - */ -typedef struct -{ - Header header; /**< MQTT header byte */ -} MQTTPacket; - - -/** - * Data for a suback packet. - */ -typedef struct -{ - Header header; /**< MQTT header byte */ - int msgId; /**< MQTT message id */ - int MQTTVersion; /**< the version of MQTT */ - MQTTProperties properties; /**< MQTT 5.0 properties. Not used for MQTT < 5.0 */ - List* qoss; /**< list of granted QoSs (MQTT 3/4) / reason codes (MQTT 5) */ -} Suback; - - -/** - * Data for an MQTT V5 unsuback packet. - */ -typedef struct -{ - Header header; /**< MQTT header byte */ - int msgId; /**< MQTT message id */ - int MQTTVersion; /**< the version of MQTT */ - MQTTProperties properties; /**< MQTT 5.0 properties. Not used for MQTT < 5.0 */ - List* reasonCodes; /**< list of reason codes */ -} Unsuback; - - -/** - * Data for a publish packet. - */ -typedef struct -{ - Header header; /**< MQTT header byte */ - char* topic; /**< topic string */ - int topiclen; - int msgId; /**< MQTT message id */ - char* payload; /**< binary payload, length delimited */ - int payloadlen; /**< payload length */ - int MQTTVersion; /**< the version of MQTT */ - MQTTProperties properties; /**< MQTT 5.0 properties. Not used for MQTT < 5.0 */ -} Publish; - - -/** - * Data for one of the ack packets. - */ -typedef struct -{ - Header header; /**< MQTT header byte */ - int msgId; /**< MQTT message id */ - unsigned char rc; /**< MQTT 5 reason code */ - int MQTTVersion; /**< the version of MQTT */ - MQTTProperties properties; /**< MQTT 5.0 properties. Not used for MQTT < 5.0 */ -} Ack; - -typedef Ack Puback; -typedef Ack Pubrec; -typedef Ack Pubrel; -typedef Ack Pubcomp; - -int MQTTPacket_encode(char* buf, size_t length); -int MQTTPacket_decode(networkHandles* net, size_t* value); -int readInt(char** pptr); -char* readUTF(char** pptr, char* enddata); -unsigned char readChar(char** pptr); -void writeChar(char** pptr, char c); -void writeInt(char** pptr, int anInt); -void writeUTF(char** pptr, const char* string); -void writeData(char** pptr, const void* data, int datalen); - -const char* MQTTPacket_name(int ptype); - -void* MQTTPacket_Factory(int MQTTVersion, networkHandles* net, int* error); -int MQTTPacket_send(networkHandles* net, Header header, char* buffer, size_t buflen, int free, int MQTTVersion); -int MQTTPacket_sends(networkHandles* net, Header header, int count, char** buffers, size_t* buflens, int* frees, int MQTTVersion); - -void* MQTTPacket_header_only(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen); -int MQTTPacket_send_disconnect(Clients* client, enum MQTTReasonCodes reason, MQTTProperties* props); - -void* MQTTPacket_publish(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen); -void MQTTPacket_freePublish(Publish* pack); -int MQTTPacket_send_publish(Publish* pack, int dup, int qos, int retained, networkHandles* net, const char* clientID); -int MQTTPacket_send_puback(int msgid, networkHandles* net, const char* clientID); -void* MQTTPacket_ack(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen); - -void MQTTPacket_freeAck(Ack* pack); -void MQTTPacket_freeSuback(Suback* pack); -void MQTTPacket_freeUnsuback(Unsuback* pack); -int MQTTPacket_send_pubrec(int msgid, networkHandles* net, const char* clientID); -int MQTTPacket_send_pubrel(int msgid, int dup, networkHandles* net, const char* clientID); -int MQTTPacket_send_pubcomp(int msgid, networkHandles* net, const char* clientID); - -void MQTTPacket_free_packet(MQTTPacket* pack); - -void writeInt4(char** pptr, int anInt); -int readInt4(char** pptr); -void writeMQTTLenString(char** pptr, MQTTLenString lenstring); -int MQTTLenStringRead(MQTTLenString* lenstring, char** pptr, char* enddata); -int MQTTPacket_VBIlen(int rem_len); -int MQTTPacket_decodeBuf(char* buf, int* value); - -#include "MQTTPacketOut.h" - -#endif /* MQTTPACKET_H */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPacketOut.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPacketOut.h deleted file mode 100644 index 4e0ae10..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPacketOut.h +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs, Allan Stockdill-Mander - SSL updates - * Ian Craggs - MQTT 3.1.1 support - * Ian Craggs - MQTT 5.0 support - *******************************************************************************/ - -#if !defined(MQTTPACKETOUT_H) -#define MQTTPACKETOUT_H - -#include "MQTTPacket.h" - -int MQTTPacket_send_connect(Clients* client, int MQTTVersion, - MQTTProperties* connectProperties, MQTTProperties* willProperties); -void* MQTTPacket_connack(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen); -void MQTTPacket_freeConnack(Connack* pack); - -int MQTTPacket_send_pingreq(networkHandles* net, const char* clientID); - -int MQTTPacket_send_subscribe(List* topics, List* qoss, MQTTSubscribe_options* opts, MQTTProperties* props, - int msgid, int dup, Clients* client); -void* MQTTPacket_suback(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen); - -int MQTTPacket_send_unsubscribe(List* topics, MQTTProperties* props, int msgid, int dup, Clients* client); -void* MQTTPacket_unsuback(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen); - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPersistence.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPersistence.h deleted file mode 100644 index 93edb2b..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPersistence.h +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs - async client updates - * Ian Craggs - fix for bug 432903 - queue persistence - * Ian Craggs - MQTT V5 updates - *******************************************************************************/ - -#if !defined(MQTTPERSISTENCE_H) -#define MQTTPERSISTENCE_H - -#if defined(__cplusplus) - extern "C" { -#endif - -#include "Clients.h" -#include "MQTTProperties.h" - -/** Stem of the key for a sent PUBLISH QoS1 or QoS2 */ -#define PERSISTENCE_PUBLISH_SENT "s-" -/** Stem of the key for a sent PUBREL */ -#define PERSISTENCE_PUBREL "sc-" -/** Stem of the key for a received PUBLISH QoS2 */ -#define PERSISTENCE_PUBLISH_RECEIVED "r-" - -/** Stem of the key for a sent MQTT V5 PUBLISH QoS1 or QoS2 */ -#define PERSISTENCE_V5_PUBLISH_SENT "s5-" -/** Stem of the key for a sent MQTT V5 PUBREL */ -#define PERSISTENCE_V5_PUBREL "sc5-" -/** Stem of the key for a received MQTT V5 PUBLISH QoS2 */ -#define PERSISTENCE_V5_PUBLISH_RECEIVED "r5-" - -/** Stem of the key for an async client command */ -#define PERSISTENCE_COMMAND_KEY "c-" -/** Stem of the key for an MQTT V5 async client command */ -#define PERSISTENCE_V5_COMMAND_KEY "c-" -/** Stem of the key for an async client message queue */ -#define PERSISTENCE_QUEUE_KEY "q-" -/** Stem of the key for an MQTT V5 message queue */ -#define PERSISTENCE_V5_QUEUE_KEY "q5-" -#define PERSISTENCE_MAX_KEY_LENGTH 8 - -int MQTTPersistence_create(MQTTClient_persistence** per, int type, void* pcontext); -int MQTTPersistence_initialize(Clients* c, const char* serverURI); -int MQTTPersistence_close(Clients* c); -int MQTTPersistence_clear(Clients* c); -int MQTTPersistence_restore(Clients* c); -void* MQTTPersistence_restorePacket(int MQTTVersion, char* buffer, size_t buflen); -void MQTTPersistence_insertInOrder(List* list, void* content, size_t size); -int MQTTPersistence_put(int socket, char* buf0, size_t buf0len, int count, - char** buffers, size_t* buflens, int htype, int msgId, int scr, int MQTTVersion); -int MQTTPersistence_remove(Clients* c, char* type, int qos, int msgId); -void MQTTPersistence_wrapMsgID(Clients *c); - -typedef struct -{ - char struct_id[4]; - int struct_version; - int payloadlen; - void* payload; - int qos; - int retained; - int dup; - int msgid; - MQTTProperties properties; -} MQTTPersistence_message; - -typedef struct -{ - MQTTPersistence_message* msg; - char* topicName; - int topicLen; - unsigned int seqno; /* only used on restore */ -} MQTTPersistence_qEntry; - -int MQTTPersistence_unpersistQueueEntry(Clients* client, MQTTPersistence_qEntry* qe); -int MQTTPersistence_persistQueueEntry(Clients* aclient, MQTTPersistence_qEntry* qe); -int MQTTPersistence_restoreMessageQueue(Clients* c); -#ifdef __cplusplus - } -#endif - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPersistenceDefault.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPersistenceDefault.h deleted file mode 100644 index 9c1034c..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPersistenceDefault.h +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - *******************************************************************************/ - -#if !defined(MQTTPERSISTENCEDEFAULT_H) -#define MQTTPERSISTENCEDEFAULT_H - -/** 8.3 filesystem */ -#define MESSAGE_FILENAME_LENGTH 8 -/** Extension of the filename */ -#define MESSAGE_FILENAME_EXTENSION ".msg" - -/* prototypes of the functions for the default file system persistence */ -int pstopen(void** handle, const char* clientID, const char* serverURI, void* context); -int pstclose(void* handle); -int pstput(void* handle, char* key, int bufcount, char* buffers[], int buflens[]); -int pstget(void* handle, char* key, char** buffer, int* buflen); -int pstremove(void* handle, char* key); -int pstkeys(void* handle, char*** keys, int* nkeys); -int pstclear(void* handle); -int pstcontainskey(void* handle, char* key); - -int pstmkdir(char *pPathname); - -#endif - diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProperties.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProperties.h deleted file mode 100644 index deec124..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProperties.h +++ /dev/null @@ -1,225 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - *******************************************************************************/ - -#if !defined(MQTTPROPERTIES_H) -#define MQTTPROPERTIES_H - -#define MQTT_INVALID_PROPERTY_ID -2 - -/** The one byte MQTT V5 property indicator */ -enum MQTTPropertyCodes { - MQTTPROPERTY_CODE_PAYLOAD_FORMAT_INDICATOR = 1, /**< The value is 1 */ - MQTTPROPERTY_CODE_MESSAGE_EXPIRY_INTERVAL = 2, /**< The value is 2 */ - MQTTPROPERTY_CODE_CONTENT_TYPE = 3, /**< The value is 3 */ - MQTTPROPERTY_CODE_RESPONSE_TOPIC = 8, /**< The value is 8 */ - MQTTPROPERTY_CODE_CORRELATION_DATA = 9, /**< The value is 9 */ - MQTTPROPERTY_CODE_SUBSCRIPTION_IDENTIFIER = 11, /**< The value is 11 */ - MQTTPROPERTY_CODE_SESSION_EXPIRY_INTERVAL = 17, /**< The value is 17 */ - MQTTPROPERTY_CODE_ASSIGNED_CLIENT_IDENTIFER = 18,/**< The value is 18 */ - MQTTPROPERTY_CODE_SERVER_KEEP_ALIVE = 19, /**< The value is 19 */ - MQTTPROPERTY_CODE_AUTHENTICATION_METHOD = 21, /**< The value is 21 */ - MQTTPROPERTY_CODE_AUTHENTICATION_DATA = 22, /**< The value is 22 */ - MQTTPROPERTY_CODE_REQUEST_PROBLEM_INFORMATION = 23,/**< The value is 23 */ - MQTTPROPERTY_CODE_WILL_DELAY_INTERVAL = 24, /**< The value is 24 */ - MQTTPROPERTY_CODE_REQUEST_RESPONSE_INFORMATION = 25,/**< The value is 25 */ - MQTTPROPERTY_CODE_RESPONSE_INFORMATION = 26, /**< The value is 26 */ - MQTTPROPERTY_CODE_SERVER_REFERENCE = 28, /**< The value is 28 */ - MQTTPROPERTY_CODE_REASON_STRING = 31, /**< The value is 31 */ - MQTTPROPERTY_CODE_RECEIVE_MAXIMUM = 33, /**< The value is 33*/ - MQTTPROPERTY_CODE_TOPIC_ALIAS_MAXIMUM = 34, /**< The value is 34 */ - MQTTPROPERTY_CODE_TOPIC_ALIAS = 35, /**< The value is 35 */ - MQTTPROPERTY_CODE_MAXIMUM_QOS = 36, /**< The value is 36 */ - MQTTPROPERTY_CODE_RETAIN_AVAILABLE = 37, /**< The value is 37 */ - MQTTPROPERTY_CODE_USER_PROPERTY = 38, /**< The value is 38 */ - MQTTPROPERTY_CODE_MAXIMUM_PACKET_SIZE = 39, /**< The value is 39 */ - MQTTPROPERTY_CODE_WILDCARD_SUBSCRIPTION_AVAILABLE = 40,/**< The value is 40 */ - MQTTPROPERTY_CODE_SUBSCRIPTION_IDENTIFIERS_AVAILABLE = 41,/**< The value is 41 */ - MQTTPROPERTY_CODE_SHARED_SUBSCRIPTION_AVAILABLE = 42/**< The value is 241 */ -}; - -#if defined(WIN32) || defined(WIN64) - #define DLLImport __declspec(dllimport) - #define DLLExport __declspec(dllexport) -#else - #define DLLImport extern - #define DLLExport __attribute__ ((visibility ("default"))) -#endif - -/** - * Returns a printable string description of an MQTT V5 property code. - * @param value an MQTT V5 property code. - * @return the printable string description of the input property code. - * NULL if the code was not found. - */ -DLLExport const char* MQTTPropertyName(enum MQTTPropertyCodes value); - -/** The one byte MQTT V5 property type */ -enum MQTTPropertyTypes { - MQTTPROPERTY_TYPE_BYTE, - MQTTPROPERTY_TYPE_TWO_BYTE_INTEGER, - MQTTPROPERTY_TYPE_FOUR_BYTE_INTEGER, - MQTTPROPERTY_TYPE_VARIABLE_BYTE_INTEGER, - MQTTPROPERTY_TYPE_BINARY_DATA, - MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING, - MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR -}; - -/** - * Returns the MQTT V5 type code of an MQTT V5 property. - * @param value an MQTT V5 property code. - * @return the MQTT V5 type code of the input property. -1 if the code was not found. - */ -DLLExport int MQTTProperty_getType(enum MQTTPropertyCodes value); - -/** - * The data for a length delimited string - */ -typedef struct -{ - int len; /**< the length of the string */ - char* data; /**< pointer to the string data */ -} MQTTLenString; - - -/** - * Structure to hold an MQTT version 5 property of any type - */ -typedef struct -{ - enum MQTTPropertyCodes identifier; /**< The MQTT V5 property id. A multi-byte integer. */ - /** The value of the property, as a union of the different possible types. */ - union { - char byte; /**< holds the value of a byte property type */ - short integer2; /**< holds the value of a 2 byte integer property type */ - int integer4; /**< holds the value of a 4 byte integer property type */ - struct { - MQTTLenString data; /**< The value of a string property, or the name of a user property. */ - MQTTLenString value; /**< The value of a user property. */ - }; - } value; -} MQTTProperty; - -/** - * MQTT version 5 property list - */ -typedef struct MQTTProperties -{ - int count; /**< number of property entries in the array */ - int max_count; /**< max number of properties that the currently allocated array can store */ - int length; /**< mbi: byte length of all properties */ - MQTTProperty *array; /**< array of properties */ -} MQTTProperties; - -#define MQTTProperties_initializer {0, 0, 0, NULL} - -/** - * Returns the length of the properties structure when serialized ready for network transmission. - * @param props an MQTT V5 property structure. - * @return the length in bytes of the properties when serialized. - */ -int MQTTProperties_len(MQTTProperties* props); - -/** - * Add a property pointer to the property array. There is no memory allocation. - * @param props The property list to add the property to. - * @param prop The property to add to the list. - * @return 0 on success, -1 on failure. - */ -DLLExport int MQTTProperties_add(MQTTProperties* props, const MQTTProperty* prop); - -/** - * Serialize the given property list to a character buffer, e.g. for writing to the network. - * @param pptr pointer to the buffer - move the pointer as we add data - * @param properties pointer to the property list, can be NULL - * @return whether the write succeeded or not: number of bytes written, or < 0 on failure. - */ -int MQTTProperties_write(char** pptr, const MQTTProperties* properties); - -/** - * Reads a property list from a character buffer into an array. - * @param properties pointer to the property list to be filled. Should be initalized but empty. - * @param pptr pointer to the character buffer. - * @param enddata pointer to the end of the character buffer so we don't read beyond. - * @return 1 if the properties were read successfully. - */ -int MQTTProperties_read(MQTTProperties* properties, char** pptr, char* enddata); - -/** - * Free all memory allocated to the property list, including any to individual properties. - * @param properties pointer to the property list. - */ -DLLExport void MQTTProperties_free(MQTTProperties* properties); - -/** - * Copy the contents of a property list, allocating additional memory if needed. - * @param props pointer to the property list. - * @return the duplicated property list. - */ -DLLExport MQTTProperties MQTTProperties_copy(const MQTTProperties* props); - -/** - * Checks if property list contains a specific property. - * @param props pointer to the property list. - * @param propid the property id to check for. - * @return 1 if found, 0 if not. - */ -DLLExport int MQTTProperties_hasProperty(MQTTProperties *props, enum MQTTPropertyCodes propid); - -/** - * Returns the number of instances of a property id. Most properties can exist only once. - * User properties and subscription ids can exist more than once. - * @param props pointer to the property list. - * @param propid the property id to check for. - * @return the number of times found. Can be 0. - */ -DLLExport int MQTTProperties_propertyCount(MQTTProperties *props, enum MQTTPropertyCodes propid); - -/** - * Returns the integer value of a specific property. The property given must be a numeric type. - * @param props pointer to the property list. - * @param propid the property id to check for. - * @return the integer value of the property. -9999999 on failure. - */ -DLLExport int MQTTProperties_getNumericValue(MQTTProperties *props, enum MQTTPropertyCodes propid); - -/** - * Returns the integer value of a specific property when it's not the only instance. - * The property given must be a numeric type. - * @param props pointer to the property list. - * @param propid the property id to check for. - * @param index the instance number, starting at 0. - * @return the integer value of the property. -9999999 on failure. - */ -DLLExport int MQTTProperties_getNumericValueAt(MQTTProperties *props, enum MQTTPropertyCodes propid, int index); - -/** - * Returns a pointer to the property structure for a specific property. - * @param props pointer to the property list. - * @param propid the property id to check for. - * @return the pointer to the property structure if found. NULL if not found. - */ -DLLExport MQTTProperty* MQTTProperties_getProperty(MQTTProperties *props, enum MQTTPropertyCodes propid); - -/** - * Returns a pointer to the property structure for a specific property when it's not the only instance. - * @param props pointer to the property list. - * @param propid the property id to check for. - * @param index the instance number, starting at 0. - * @return the pointer to the property structure if found. NULL if not found. - */ -DLLExport MQTTProperty* MQTTProperties_getPropertyAt(MQTTProperties *props, enum MQTTPropertyCodes propid, int index); - -#endif /* MQTTPROPERTIES_H */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocol.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocol.h deleted file mode 100644 index 7478103..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocol.h +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2014 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs - MQTT 3.1.1 updates - *******************************************************************************/ - -#if !defined(MQTTPROTOCOL_H) -#define MQTTPROTOCOL_H - -#include "LinkedList.h" -#include "MQTTPacket.h" -#include "Clients.h" - -#define MAX_MSG_ID 65535 -#define MAX_CLIENTID_LEN 65535 - -typedef struct -{ - int socket; - Publications* p; -} pending_write; - - -typedef struct -{ - List publications; - unsigned int msgs_received; - unsigned int msgs_sent; - List pending_writes; /* for qos 0 writes not complete */ -} MQTTProtocol; - - -#include "MQTTProtocolOut.h" - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocolClient.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocolClient.h deleted file mode 100644 index 92b43a8..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocolClient.h +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2017 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs, Allan Stockdill-Mander - SSL updates - * Ian Craggs - MQTT 3.1.1 updates - * Rong Xiang, Ian Craggs - C++ compatibility - * Ian Craggs - add debug definition of MQTTStrdup for when needed - *******************************************************************************/ - -#if !defined(MQTTPROTOCOLCLIENT_H) -#define MQTTPROTOCOLCLIENT_H - -#include "LinkedList.h" -#include "MQTTPacket.h" -#include "Log.h" -#include "MQTTProtocol.h" -#include "Messages.h" -#include "MQTTProperties.h" - -#define MAX_MSG_ID 65535 -#define MAX_CLIENTID_LEN 65535 - -int MQTTProtocol_startPublish(Clients* pubclient, Publish* publish, int qos, int retained, Messages** m); -Messages* MQTTProtocol_createMessage(Publish* publish, Messages** mm, int qos, int retained); -Publications* MQTTProtocol_storePublication(Publish* publish, int* len); -int messageIDCompare(void* a, void* b); -int MQTTProtocol_assignMsgId(Clients* client); -void MQTTProtocol_removePublication(Publications* p); -void Protocol_processPublication(Publish* publish, Clients* client); - -int MQTTProtocol_handlePublishes(void* pack, int sock); -int MQTTProtocol_handlePubacks(void* pack, int sock); -int MQTTProtocol_handlePubrecs(void* pack, int sock); -int MQTTProtocol_handlePubrels(void* pack, int sock); -int MQTTProtocol_handlePubcomps(void* pack, int sock); - -void MQTTProtocol_closeSession(Clients* c, int sendwill); -void MQTTProtocol_keepalive(time_t); -void MQTTProtocol_retry(time_t, int, int); -void MQTTProtocol_freeClient(Clients* client); -void MQTTProtocol_emptyMessageList(List* msgList); -void MQTTProtocol_freeMessageList(List* msgList); - -char* MQTTStrncpy(char *dest, const char* src, size_t num); -char* MQTTStrdup(const char* src); - -//#define MQTTStrdup(src) MQTTStrncpy(malloc(strlen(src)+1), src, strlen(src)+1) - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocolOut.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocolOut.h deleted file mode 100644 index e2c2645..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTProtocolOut.h +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs, Allan Stockdill-Mander - SSL updates - * Ian Craggs - MQTT 3.1.1 support - * Ian Craggs - SNI support - * Ian Craggs - MQTT 5.0 support - *******************************************************************************/ - -#if !defined(MQTTPROTOCOLOUT_H) -#define MQTTPROTOCOLOUT_H - -#include "LinkedList.h" -#include "MQTTPacket.h" -#include "Clients.h" -#include "Log.h" -#include "Messages.h" -#include "MQTTProtocol.h" -#include "MQTTProtocolClient.h" - -#define DEFAULT_PORT 1883 - -size_t MQTTProtocol_addressPort(const char* uri, int* port, const char **topic); -void MQTTProtocol_reconnect(const char* ip_address, Clients* client); -#if defined(OPENSSL) -int MQTTProtocol_connect(const char* ip_address, Clients* acClients, int ssl, int websocket, int MQTTVersion, - MQTTProperties* connectProperties, MQTTProperties* willProperties); -#else -int MQTTProtocol_connect(const char* ip_address, Clients* acClients, int websocket, int MQTTVersion, - MQTTProperties* connectProperties, MQTTProperties* willProperties); -#endif -int MQTTProtocol_handlePingresps(void* pack, int sock); -int MQTTProtocol_subscribe(Clients* client, List* topics, List* qoss, int msgID, - MQTTSubscribe_options* opts, MQTTProperties* props); -int MQTTProtocol_handleSubacks(void* pack, int sock); -int MQTTProtocol_unsubscribe(Clients* client, List* topics, int msgID, MQTTProperties* props); -int MQTTProtocol_handleUnsubacks(void* pack, int sock); - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPublish.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPublish.h deleted file mode 100644 index ebe479d..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTPublish.h +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Xiang Rong - 442039 Add makefile to Embedded C client - *******************************************************************************/ - -#ifndef MQTTPUBLISH_H_ -#define MQTTPUBLISH_H_ - -#if !defined(DLLImport) - #define DLLImport -#endif -#if !defined(DLLExport) - #define DLLExport -#endif - -DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid, - MQTTString topicName, unsigned char* payload, int payloadlen); - -DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName, - unsigned char** payload, int* payloadlen, unsigned char* buf, int len); - -DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid); -DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid); -DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid); - -#endif /* MQTTPUBLISH_H_ */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTReasonCodes.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTReasonCodes.h deleted file mode 100644 index 369543b..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTReasonCodes.h +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - *******************************************************************************/ - -#if !defined(MQTTREASONCODES_H) -#define MQTTREASONCODES_H - -/** The MQTT V5 one byte reason code */ -enum MQTTReasonCodes { - MQTTREASONCODE_SUCCESS = 0, - MQTTREASONCODE_NORMAL_DISCONNECTION = 0, - MQTTREASONCODE_GRANTED_QOS_0 = 0, - MQTTREASONCODE_GRANTED_QOS_1 = 1, - MQTTREASONCODE_GRANTED_QOS_2 = 2, - MQTTREASONCODE_DISCONNECT_WITH_WILL_MESSAGE = 4, - MQTTREASONCODE_NO_MATCHING_SUBSCRIBERS = 16, - MQTTREASONCODE_NO_SUBSCRIPTION_FOUND = 17, - MQTTREASONCODE_CONTINUE_AUTHENTICATION = 24, - MQTTREASONCODE_RE_AUTHENTICATE = 25, - MQTTREASONCODE_UNSPECIFIED_ERROR = 128, - MQTTREASONCODE_MALFORMED_PACKET = 129, - MQTTREASONCODE_PROTOCOL_ERROR = 130, - MQTTREASONCODE_IMPLEMENTATION_SPECIFIC_ERROR = 131, - MQTTREASONCODE_UNSUPPORTED_PROTOCOL_VERSION = 132, - MQTTREASONCODE_CLIENT_IDENTIFIER_NOT_VALID = 133, - MQTTREASONCODE_BAD_USER_NAME_OR_PASSWORD = 134, - MQTTREASONCODE_NOT_AUTHORIZED = 135, - MQTTREASONCODE_SERVER_UNAVAILABLE = 136, - MQTTREASONCODE_SERVER_BUSY = 137, - MQTTREASONCODE_BANNED = 138, - MQTTREASONCODE_SERVER_SHUTTING_DOWN = 139, - MQTTREASONCODE_BAD_AUTHENTICATION_METHOD = 140, - MQTTREASONCODE_KEEP_ALIVE_TIMEOUT = 141, - MQTTREASONCODE_SESSION_TAKEN_OVER = 142, - MQTTREASONCODE_TOPIC_FILTER_INVALID = 143, - MQTTREASONCODE_TOPIC_NAME_INVALID = 144, - MQTTREASONCODE_PACKET_IDENTIFIER_IN_USE = 145, - MQTTREASONCODE_PACKET_IDENTIFIER_NOT_FOUND = 146, - MQTTREASONCODE_RECEIVE_MAXIMUM_EXCEEDED = 147, - MQTTREASONCODE_TOPIC_ALIAS_INVALID = 148, - MQTTREASONCODE_PACKET_TOO_LARGE = 149, - MQTTREASONCODE_MESSAGE_RATE_TOO_HIGH = 150, - MQTTREASONCODE_QUOTA_EXCEEDED = 151, - MQTTREASONCODE_ADMINISTRATIVE_ACTION = 152, - MQTTREASONCODE_PAYLOAD_FORMAT_INVALID = 153, - MQTTREASONCODE_RETAIN_NOT_SUPPORTED = 154, - MQTTREASONCODE_QOS_NOT_SUPPORTED = 155, - MQTTREASONCODE_USE_ANOTHER_SERVER = 156, - MQTTREASONCODE_SERVER_MOVED = 157, - MQTTREASONCODE_SHARED_SUBSCRIPTIONS_NOT_SUPPORTED = 158, - MQTTREASONCODE_CONNECTION_RATE_EXCEEDED = 159, - MQTTREASONCODE_MAXIMUM_CONNECT_TIME = 160, - MQTTREASONCODE_SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED = 161, - MQTTREASONCODE_WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 162 -}; - -#if defined(WIN32) || defined(WIN64) - #define DLLImport __declspec(dllimport) - #define DLLExport __declspec(dllexport) -#else - #define DLLImport extern - #define DLLExport __attribute__ ((visibility ("default"))) -#endif - -/** - * Returns a printable string description of an MQTT V5 reason code. - * @param value an MQTT V5 reason code. - * @return the printable string description of the input reason code. - * NULL if the code was not found. - */ -DLLExport const char* MQTTReasonCode_toString(enum MQTTReasonCodes value); - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTSubscribe.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTSubscribe.h deleted file mode 100644 index aa91826..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTSubscribe.h +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Xiang Rong - 442039 Add makefile to Embedded C client - *******************************************************************************/ - -#ifndef MQTTSUBSCRIBE_H_ -#define MQTTSUBSCRIBE_H_ - -#if !defined(DLLImport) - #define DLLImport -#endif -#if !defined(DLLExport) - #define DLLExport -#endif - -DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, - int count, MQTTString topicFilters[], int requestedQoSs[]); - -DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, - int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len); - -DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs); - -DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len); - - -#endif /* MQTTSUBSCRIBE_H_ */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTSubscribeOpts.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTSubscribeOpts.h deleted file mode 100644 index 1ae4678..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTSubscribeOpts.h +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - *******************************************************************************/ - -#if !defined(SUBOPTS_H) -#define SUBOPTS_H - -/** The MQTT V5 subscribe options, apart from QoS which existed before V5. */ -typedef struct MQTTSubscribe_options -{ - /** The eyecatcher for this structure. Must be MQSO. */ - char struct_id[4]; - /** The version number of this structure. Must be 0. - */ - int struct_version; - /** To not receive our own publications, set to 1. - * 0 is the original MQTT behaviour - all messages matching the subscription are received. - */ - unsigned char noLocal; - /** To keep the retain flag as on the original publish message, set to 1. - * If 0, defaults to the original MQTT behaviour where the retain flag is only set on - * publications sent by a broker if in response to a subscribe request. - */ - unsigned char retainAsPublished; - /** 0 - send retained messages at the time of the subscribe (original MQTT behaviour) - * 1 - send retained messages on subscribe only if the subscription is new - * 2 - do not send retained messages at all - */ - unsigned char retainHandling; -} MQTTSubscribe_options; - -#define MQTTSubscribe_options_initializer { {'M', 'Q', 'S', 'O'}, 0, 0, 0, 0 } - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTUnsubscribe.h b/src/communication/pub_gps/include/paho_mqtt_3c/MQTTUnsubscribe.h deleted file mode 100644 index 355ca9a..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/MQTTUnsubscribe.h +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Xiang Rong - 442039 Add makefile to Embedded C client - *******************************************************************************/ - -#ifndef MQTTUNSUBSCRIBE_H_ -#define MQTTUNSUBSCRIBE_H_ - -#if !defined(DLLImport) - #define DLLImport -#endif -#if !defined(DLLExport) - #define DLLExport -#endif - -DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, - int count, MQTTString topicFilters[]); - -DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[], - unsigned char* buf, int len); - -DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid); - -DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len); - -#endif /* MQTTUNSUBSCRIBE_H_ */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/Messages.h b/src/communication/pub_gps/include/paho_mqtt_3c/Messages.h deleted file mode 100644 index 08f292f..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/Messages.h +++ /dev/null @@ -1,24 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2013 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - *******************************************************************************/ - -#if !defined(MESSAGES_H) -#define MESSAGES_H - -#include "Log.h" - -const char* Messages_get(int, enum LOG_LEVELS); - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/OsWrapper.h b/src/communication/pub_gps/include/paho_mqtt_3c/OsWrapper.h deleted file mode 100644 index f657ab1..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/OsWrapper.h +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016, 2017 logi.cals GmbH - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Gunter Raidl - timer support for VxWorks - * Rainer Poisel - reusability - *******************************************************************************/ - -#if !defined(OSWRAPPER_H) -#define OSWRAPPER_H - -#if defined(_WRS_KERNEL) -#include - -#define lstat stat - -typedef unsigned long useconds_t; -void usleep(useconds_t useconds); - -#define timersub(a, b, result) \ - do \ - { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) \ - { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000L; \ - } \ - } while (0) -#endif /* defined(_WRS_KERNEL) */ - -#endif /* OSWRAPPER_H */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/SHA1.h b/src/communication/pub_gps/include/paho_mqtt_3c/SHA1.h deleted file mode 100644 index f8e8abd..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/SHA1.h +++ /dev/null @@ -1,91 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 Wind River Systems, Inc. All Rights Reserved. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Keith Holman - initial implementation and documentation - *******************************************************************************/ - -#if !defined(SHA1_H) -#define SHA1_H - -#if defined(OPENSSL) -#include - -/** SHA-1 Digest Length */ -#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH - -#else /* if defined(OPENSSL) */ - -#if defined(WIN32) || defined(WIN64) -#include -#include -typedef struct SHA_CTX_S -{ - HCRYPTPROV hProv; - HCRYPTHASH hHash; -} SHA_CTX; -#else /* if defined(WIN32) || defined(WIN64) */ - -#include -typedef struct SHA_CTX_S { - uint32_t h[5]; - union { - uint32_t w[16]; - uint8_t buffer[64]; - }; - unsigned int size; - unsigned int total; -} SHA_CTX; -#endif /* else if defined(WIN32) || defined(WIN64) */ - -#include - -/** SHA-1 Digest Length (number of bytes in SHA1) */ -#define SHA1_DIGEST_LENGTH (160/8) - -/** - * Initializes the SHA1 hashing algorithm - * - * @param[in,out] ctx hashing context structure - * - * @see SHA1_Update - * @see SHA1_Final - */ -int SHA1_Init(SHA_CTX *ctx); - -/** - * Updates a block to the SHA1 hash - * - * @param[in,out] ctx hashing context structure - * @param[in] data block of data to hash - * @param[in] len length of block to hash - * - * @see SHA1_Init - * @see SHA1_Final - */ -int SHA1_Update(SHA_CTX *ctx, const void *data, size_t len); - -/** - * Produce final SHA1 hash - * - * @param[out] md SHA1 hash produced (must be atleast - * @p SHA1_DIGEST_LENGTH in length) - * @param[in,out] ctx hashing context structure - * - * @see SHA1_Init - * @see SHA1_Final - */ -int SHA1_Final(unsigned char *md, SHA_CTX *ctx); - -#endif /* if defined(OPENSSL) */ -#endif /* SHA1_H */ - diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/SSLSocket.h b/src/communication/pub_gps/include/paho_mqtt_3c/SSLSocket.h deleted file mode 100644 index 09547fd..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/SSLSocket.h +++ /dev/null @@ -1,52 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs, Allan Stockdill-Mander - initial implementation - * Ian Craggs - SNI support - * Ian Craggs - post connect checks and CApath - *******************************************************************************/ -#if !defined(SSLSOCKET_H) -#define SSLSOCKET_H - -#if defined(WIN32) || defined(WIN64) - #define ssl_mutex_type HANDLE -#else - #include - #include - #define ssl_mutex_type pthread_mutex_t -#endif - -#include -#include "SocketBuffer.h" -#include "Clients.h" - -#define URI_SSL "ssl://" - -/** if we should handle openssl initialization (bool_value == 1) or depend on it to be initalized externally (bool_value == 0) */ -void SSLSocket_handleOpensslInit(int bool_value); - -int SSLSocket_initialize(void); -void SSLSocket_terminate(void); -int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, const char* hostname, size_t hostname_len); - -int SSLSocket_getch(SSL* ssl, int socket, char* c); -char *SSLSocket_getdata(SSL* ssl, int socket, size_t bytes, size_t* actual_len); - -int SSLSocket_close(networkHandles* net); -int SSLSocket_putdatas(SSL* ssl, int socket, char* buf0, size_t buf0len, int count, char** buffers, size_t* buflens, int* frees); -int SSLSocket_connect(SSL* ssl, int sock, const char* hostname, int verify, int (*cb)(const char *str, size_t len, void *u), void* u); - -int SSLSocket_getPendingRead(void); -int SSLSocket_continueWrite(pending_writes* pw); - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/Socket.h b/src/communication/pub_gps/include/paho_mqtt_3c/Socket.h deleted file mode 100644 index e042069..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/Socket.h +++ /dev/null @@ -1,145 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2014 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial implementation and documentation - * Ian Craggs - async client updates - *******************************************************************************/ - -#if !defined(SOCKET_H) -#define SOCKET_H - -#include - -#if defined(WIN32) || defined(WIN64) -#include -#include -#define MAXHOSTNAMELEN 256 -#if !defined(SSLSOCKET_H) -#undef EAGAIN -#define EAGAIN WSAEWOULDBLOCK -#undef EINTR -#define EINTR WSAEINTR -#undef EINPROGRESS -#define EINPROGRESS WSAEINPROGRESS -#undef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK -#undef ENOTCONN -#define ENOTCONN WSAENOTCONN -#undef ECONNRESET -#define ECONNRESET WSAECONNRESET -#undef ETIMEDOUT -#define ETIMEDOUT WAIT_TIMEOUT -#endif -#define ioctl ioctlsocket -#define socklen_t int -#else -#define INVALID_SOCKET SOCKET_ERROR -#include -#if !defined(_WRS_KERNEL) -#include -#include -#include -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define ULONG size_t -#endif - -#include "mutex_type.h" /* Needed for mutex_type */ - -/** socket operation completed successfully */ -#define TCPSOCKET_COMPLETE 0 -#if !defined(SOCKET_ERROR) - /** error in socket operation */ - #define SOCKET_ERROR -1 -#endif -/** must be the same as SOCKETBUFFER_INTERRUPTED */ -#define TCPSOCKET_INTERRUPTED -22 -#define SSL_FATAL -3 - -#if !defined(INET6_ADDRSTRLEN) -#define INET6_ADDRSTRLEN 46 /** only needed for gcc/cygwin on windows */ -#endif - - -#if !defined(max) -#define max(A,B) ( (A) > (B) ? (A):(B)) -#endif - -#include "LinkedList.h" - -/*BE -def FD_SET -{ - 128 n8 "data" -} - -def SOCKETS -{ - FD_SET "rset" - FD_SET "rset_saved" - n32 dec "maxfdp1" - n32 ptr INTList "clientsds" - n32 ptr INTItem "cur_clientsds" - n32 ptr INTList "connect_pending" - n32 ptr INTList "write_pending" - FD_SET "pending_wset" -} -BE*/ - - -/** - * Structure to hold all socket data for the module - */ -typedef struct -{ - fd_set rset, /**< socket read set (see select doc) */ - rset_saved; /**< saved socket read set */ - int maxfdp1; /**< max descriptor used +1 (again see select doc) */ - List* clientsds; /**< list of client socket descriptors */ - ListElement* cur_clientsds; /**< current client socket descriptor (iterator) */ - List* connect_pending; /**< list of sockets for which a connect is pending */ - List* write_pending; /**< list of sockets for which a write is pending */ - fd_set pending_wset; /**< socket pending write set for select */ -} Sockets; - - -void Socket_outInitialize(void); -void Socket_outTerminate(void); -int Socket_getReadySocket(int more_work, struct timeval *tp, mutex_type mutex); -int Socket_getch(int socket, char* c); -char *Socket_getdata(int socket, size_t bytes, size_t* actual_len); -int Socket_putdatas(int socket, char* buf0, size_t buf0len, int count, char** buffers, size_t* buflens, int* frees); -void Socket_close(int socket); -int Socket_new(const char* addr, size_t addr_len, int port, int* socket); - -int Socket_noPendingWrites(int socket); -char* Socket_getpeer(int sock); - -void Socket_addPendingWrite(int socket); -void Socket_clearPendingWrite(int socket); - -typedef void Socket_writeComplete(int socket, int rc); -void Socket_setWriteCompleteCallback(Socket_writeComplete*); - -#endif /* SOCKET_H */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/SocketBuffer.h b/src/communication/pub_gps/include/paho_mqtt_3c/SocketBuffer.h deleted file mode 100644 index f7702dc..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/SocketBuffer.h +++ /dev/null @@ -1,84 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2014 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - * Ian Craggs, Allan Stockdill-Mander - SSL updates - *******************************************************************************/ - -#if !defined(SOCKETBUFFER_H) -#define SOCKETBUFFER_H - -#if defined(WIN32) || defined(WIN64) -#include -#else -#include -#endif - -#if defined(OPENSSL) -#include -#endif - -#if defined(WIN32) || defined(WIN64) - typedef WSABUF iobuf; -#else - typedef struct iovec iobuf; -#endif - -typedef struct -{ - int socket; - unsigned int index; - size_t headerlen; - char fixed_header[5]; /**< header plus up to 4 length bytes */ - size_t buflen, /**< total length of the buffer */ - datalen; /**< current length of data in buf */ - char* buf; -} socket_queue; - -typedef struct -{ - int socket, count; - size_t total; -#if defined(OPENSSL) - SSL* ssl; -#endif - size_t bytes; - iobuf iovecs[5]; - int frees[5]; -} pending_writes; - -#define SOCKETBUFFER_COMPLETE 0 -#if !defined(SOCKET_ERROR) - #define SOCKET_ERROR -1 -#endif -#define SOCKETBUFFER_INTERRUPTED -22 /* must be the same value as TCPSOCKET_INTERRUPTED */ - -void SocketBuffer_initialize(void); -void SocketBuffer_terminate(void); -void SocketBuffer_cleanup(int socket); -char* SocketBuffer_getQueuedData(int socket, size_t bytes, size_t* actual_len); -int SocketBuffer_getQueuedChar(int socket, char* c); -void SocketBuffer_interrupted(int socket, size_t actual_len); -char* SocketBuffer_complete(int socket); -void SocketBuffer_queueChar(int socket, char c); - -#if defined(OPENSSL) -void SocketBuffer_pendingWrite(int socket, SSL* ssl, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes); -#else -void SocketBuffer_pendingWrite(int socket, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes); -#endif -pending_writes* SocketBuffer_getWrite(int socket); -int SocketBuffer_writeComplete(int socket); -pending_writes* SocketBuffer_updateWrite(int socket, char* topic, char* payload); - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/StackTrace.h b/src/communication/pub_gps/include/paho_mqtt_3c/StackTrace.h deleted file mode 100644 index 21a0a64..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/StackTrace.h +++ /dev/null @@ -1,71 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2017 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - *******************************************************************************/ - -#ifndef STACKTRACE_H_ -#define STACKTRACE_H_ - -#include -#include "Log.h" -#include "Thread.h" - -#if defined(NOSTACKTRACE) -#define FUNC_ENTRY -#define FUNC_ENTRY_NOLOG -#define FUNC_ENTRY_MED -#define FUNC_ENTRY_MAX -#define FUNC_EXIT -#define FUNC_EXIT_NOLOG -#define FUNC_EXIT_MED -#define FUNC_EXIT_MAX -#define FUNC_EXIT_RC(x) -#define FUNC_EXIT_MED_RC(x) -#define FUNC_EXIT_MAX_RC(x) -#else -#if defined(WIN32) || defined(WIN64) -#define inline __inline -#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM) -#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1) -#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM) -#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM) -#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM) -#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1) -#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM) -#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM) -#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM) -#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM) -#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM) -#else -#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM) -#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1) -#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM) -#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM) -#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM) -#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1) -#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM) -#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM) -#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM) -#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM) -#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM) -#endif -#endif - -void StackTrace_entry(const char* name, int line, enum LOG_LEVELS trace); -void StackTrace_exit(const char* name, int line, void* return_value, enum LOG_LEVELS trace); - -void StackTrace_printStack(FILE* dest); -char* StackTrace_get(thread_id_type, char* buf, int bufsize); - -#endif /* STACKTRACE_H_ */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/Thread.h b/src/communication/pub_gps/include/paho_mqtt_3c/Thread.h deleted file mode 100644 index 88fd008..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/Thread.h +++ /dev/null @@ -1,75 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial implementation - * Ian Craggs, Allan Stockdill-Mander - async client updates - * Ian Craggs - fix for bug #420851 - * Ian Craggs - change MacOS semaphore implementation - *******************************************************************************/ -#include "MQTTClient.h" - -#if !defined(THREAD_H) -#define THREAD_H - -#include "mutex_type.h" /* Needed for mutex_type */ - -#if defined(WIN32) || defined(WIN64) - #include - #define thread_type HANDLE - #define thread_id_type DWORD - #define thread_return_type DWORD - #define thread_fn LPTHREAD_START_ROUTINE - #define cond_type HANDLE - #define sem_type HANDLE - #undef ETIMEDOUT - #define ETIMEDOUT WSAETIMEDOUT -#else - #include - - #define thread_type pthread_t - #define thread_id_type pthread_t - #define thread_return_type void* - typedef thread_return_type (*thread_fn)(void*); - typedef struct { pthread_cond_t cond; pthread_mutex_t mutex; } cond_type_struct; - typedef cond_type_struct *cond_type; - #if defined(OSX) - #include - typedef dispatch_semaphore_t sem_type; - #else - #include - typedef sem_t *sem_type; - #endif - - cond_type Thread_create_cond(void); - int Thread_signal_cond(cond_type); - int Thread_wait_cond(cond_type condvar, int timeout); - int Thread_destroy_cond(cond_type); -#endif - -DLLExport thread_type Thread_start(thread_fn, void*); - -DLLExport mutex_type Thread_create_mutex(); -DLLExport int Thread_lock_mutex(mutex_type); -DLLExport int Thread_unlock_mutex(mutex_type); -void Thread_destroy_mutex(mutex_type); - -DLLExport thread_id_type Thread_getid(); - -sem_type Thread_create_sem(void); -int Thread_wait_sem(sem_type sem, int timeout); -int Thread_check_sem(sem_type sem); -int Thread_post_sem(sem_type sem); -int Thread_destroy_sem(sem_type sem); - - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/Tree.h b/src/communication/pub_gps/include/paho_mqtt_3c/Tree.h deleted file mode 100644 index bbbd014..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/Tree.h +++ /dev/null @@ -1,115 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2013 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial implementation and documentation - *******************************************************************************/ - - -#if !defined(TREE_H) -#define TREE_H - -#include /* for size_t definition */ - -/*BE -defm defTree(T) // macro to define a tree - -def T concat Node -{ - n32 ptr T concat Node "parent" - n32 ptr T concat Node "left" - n32 ptr T concat Node "right" - n32 ptr T id2str(T) - n32 suppress "size" -} - - -def T concat Tree -{ - struct - { - n32 ptr T concat Node suppress "root" - n32 ptr DATA suppress "compare" - } - struct - { - n32 ptr T concat Node suppress "root" - n32 ptr DATA suppress "compare" - } - n32 dec "count" - n32 dec suppress "size" -} - -endm - -defTree(INT) -defTree(STRING) -defTree(TMP) - -BE*/ - -/** - * Structure to hold all data for one list element - */ -typedef struct NodeStruct -{ - struct NodeStruct *parent, /**< pointer to parent tree node, in case we need it */ - *child[2]; /**< pointers to child tree nodes 0 = left, 1 = right */ - void* content; /**< pointer to element content */ - size_t size; /**< size of content */ - unsigned int red : 1; -} Node; - - -/** - * Structure to hold all data for one tree - */ -typedef struct -{ - struct - { - Node *root; /**< root node pointer */ - int (*compare)(void*, void*, int); /**< comparison function */ - } index[2]; - int indexes, /**< no of indexes into tree */ - count; /**< no of items */ - size_t size; /**< heap storage used */ - unsigned int heap_tracking : 1; /**< switch on heap tracking for this tree? */ - unsigned int allow_duplicates : 1; /**< switch to allow duplicate entries */ -} Tree; - - -Tree* TreeInitialize(int(*compare)(void*, void*, int)); -void TreeInitializeNoMalloc(Tree* aTree, int(*compare)(void*, void*, int)); -void TreeAddIndex(Tree* aTree, int(*compare)(void*, void*, int)); - -void* TreeAdd(Tree* aTree, void* content, size_t size); - -void* TreeRemove(Tree* aTree, void* content); - -void* TreeRemoveKey(Tree* aTree, void* key); -void* TreeRemoveKeyIndex(Tree* aTree, void* key, int index); - -void* TreeRemoveNodeIndex(Tree* aTree, Node* aNode, int index); - -void TreeFree(Tree* aTree); - -Node* TreeFind(Tree* aTree, void* key); -Node* TreeFindIndex(Tree* aTree, void* key, int index); - -Node* TreeNextElement(Tree* aTree, Node* curnode); - -int TreeIntCompare(void* a, void* b, int); -int TreePtrCompare(void* a, void* b, int); -int TreeStringCompare(void* a, void* b, int); - -#endif diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/VersionInfo.h.in b/src/communication/pub_gps/include/paho_mqtt_3c/VersionInfo.h.in deleted file mode 100644 index 5b91bf3..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/VersionInfo.h.in +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef VERSIONINFO_H -#define VERSIONINFO_H - -#define BUILD_TIMESTAMP "@BUILD_TIMESTAMP@" -#define CLIENT_VERSION "@CLIENT_VERSION@" - -#endif /* VERSIONINFO_H */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/WebSocket.h b/src/communication/pub_gps/include/paho_mqtt_3c/WebSocket.h deleted file mode 100644 index 33cc844..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/WebSocket.h +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 Wind River Systems, Inc. All Rights Reserved. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Keith Holman - initial implementation and documentation - *******************************************************************************/ - -#if !defined(WEBSOCKET_H) -#define WEBSOCKET_H - -#include "Clients.h" - -/** - * WebSocket op codes - * @{ - */ -#define WebSocket_OP_CONTINUE 0x0 /* 0000 - continue frame */ -#define WebSocket_OP_TEXT 0x1 /* 0001 - text frame */ -#define WebSocket_OP_BINARY 0x2 /* 0010 - binary frame */ -#define WebSocket_OP_CLOSE 0x8 /* 1000 - close frame */ -#define WebSocket_OP_PING 0x9 /* 1001 - ping frame */ -#define WebSocket_OP_PONG 0xA /* 1010 - pong frame */ -/** @} */ - -/** - * Various close status codes - * @{ - */ -#define WebSocket_CLOSE_NORMAL 1000 -#define WebSocket_CLOSE_GOING_AWAY 1001 -#define WebSocket_CLOSE_PROTOCOL_ERROR 1002 -#define WebSocket_CLOSE_UNKNOWN_DATA 1003 -#define WebSocket_CLOSE_RESERVED 1004 -#define WebSocket_CLOSE_NO_STATUS_CODE 1005 /* reserved: not to be used */ -#define WebSocket_CLOSE_ABNORMAL 1006 /* reserved: not to be used */ -#define WebSocket_CLOSE_BAD_DATA 1007 -#define WebSocket_CLOSE_POLICY 1008 -#define WebSocket_CLOSE_MSG_TOO_BIG 1009 -#define WebSocket_CLOSE_NO_EXTENSION 1010 -#define WebScoket_CLOSE_UNEXPECTED 1011 -#define WebSocket_CLOSE_TLS_FAIL 1015 /* reserved: not be used */ -/** @} */ - -/* closes a websocket connection */ -void WebSocket_close(networkHandles *net, int status_code, const char *reason); - -/* sends upgrade request */ -int WebSocket_connect(networkHandles *net, const char *uri); - -/* calculates the extra data required in a packet to hold a WebSocket frame header */ -size_t WebSocket_calculateFrameHeaderSize(networkHandles *net, int mask_data, - size_t data_len); - -/* obtain data from network socket */ -int WebSocket_getch(networkHandles *net, char* c); -char *WebSocket_getdata(networkHandles *net, size_t bytes, size_t* actual_len); - -/* send data out, in websocket format only if required */ -int WebSocket_putdatas(networkHandles* net, char* buf0, size_t buf0len, - int count, char** buffers, size_t* buflens, int* freeData); - -/* releases any resources used by the websocket system */ -void WebSocket_terminate(void); - -/* handles websocket upgrade request */ -int WebSocket_upgrade(networkHandles *net); - -#endif /* WEBSOCKET_H */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/mutex_type.h b/src/communication/pub_gps/include/paho_mqtt_3c/mutex_type.h deleted file mode 100644 index 5760b37..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/mutex_type.h +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *******************************************************************************/ -#if !defined(_MUTEX_TYPE_H_) -#define _MUTEX_TYPE_H_ - -#if defined(WIN32) || defined(WIN64) - #include - #define mutex_type HANDLE -#else - #include - #define mutex_type pthread_mutex_t* -#endif - -#endif /* _MUTEX_TYPE_H_ */ diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/pubsub_opts.h b/src/communication/pub_gps/include/paho_mqtt_3c/pubsub_opts.h deleted file mode 100644 index a506a68..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/pubsub_opts.h +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012, 2018 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial contribution - * Guilherme Maciel Ferreira - add keep alive option - *******************************************************************************/ - -#if !defined(PUBSUB_OPTS_H) -#define PUBSUB_OPTS_H - -#include "MQTTAsync.h" -#include "MQTTClientPersistence.h" - -struct pubsub_opts -{ - /* debug app options */ - int publisher; /* publisher app? */ - int quiet; - int verbose; - int tracelevel; - char* delimiter; - int maxdatalen; - /* message options */ - char* message; - char* filename; - int stdin_lines; - int stdlin_complete; - int null_message; - /* MQTT options */ - int MQTTVersion; - char* topic; - char* clientid; - int qos; - int retained; - char* username; - char* password; - char* host; - char* port; - char* connection; - int keepalive; - /* will options */ - char* will_topic; - char* will_payload; - int will_qos; - int will_retain; - /* TLS options */ - int insecure; - char* capath; - char* cert; - char* cafile; - char* key; - char* keypass; - char* ciphers; - /* MQTT V5 options */ - int message_expiry; - struct { - char *name; - char *value; - } user_property; -}; - -typedef struct -{ - const char* name; - const char* value; -} pubsub_opts_nameValue; - -//void usage(struct pubsub_opts* opts, const char* version, const char* program_name); -void usage(struct pubsub_opts* opts, pubsub_opts_nameValue* name_values, const char* program_name); -int getopts(int argc, char** argv, struct pubsub_opts* opts); -char* readfile(int* data_len, struct pubsub_opts* opts); -void logProperties(MQTTProperties *props); - -#endif - - diff --git a/src/communication/pub_gps/include/paho_mqtt_3c/utf-8.h b/src/communication/pub_gps/include/paho_mqtt_3c/utf-8.h deleted file mode 100644 index 8bce4b3..0000000 --- a/src/communication/pub_gps/include/paho_mqtt_3c/utf-8.h +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2013 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - *******************************************************************************/ - -#if !defined(UTF8_H) -#define UTF8_H - -int UTF8_validate(int len, const char *data); -int UTF8_validateString(const char* string); - -#endif diff --git a/src/communication/pub_gps/include/pub_gps/json.h b/src/communication/pub_gps/include/pub_gps/json.h deleted file mode 100644 index d95fe6e..0000000 --- a/src/communication/pub_gps/include/pub_gps/json.h +++ /dev/null @@ -1,2351 +0,0 @@ -/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/). -/// It is intended to be used with #include "json/json.h" - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and -The JsonCpp Authors, and is released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors - -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. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. - -*/ - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - - - - - -#ifndef JSON_AMALGAMATED_H_INCLUDED -# define JSON_AMALGAMATED_H_INCLUDED -/// If defined, indicates that the source file is amalgamated -/// to prevent private header inclusion. -#define JSON_IS_AMALGAMATION - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/version.h -// ////////////////////////////////////////////////////////////////////// - -#ifndef JSON_VERSION_H_INCLUDED -#define JSON_VERSION_H_INCLUDED - -// Note: version must be updated in three places when doing a release. This -// annoying process ensures that amalgamate, CMake, and meson all report the -// correct version. -// 1. /meson.build -// 2. /include/json/version.h -// 3. /CMakeLists.txt -// IMPORTANT: also update the SOVERSION!! - -#define JSONCPP_VERSION_STRING "1.9.5" -#define JSONCPP_VERSION_MAJOR 1 -#define JSONCPP_VERSION_MINOR 9 -#define JSONCPP_VERSION_PATCH 5 -#define JSONCPP_VERSION_QUALIFIER -#define JSONCPP_VERSION_HEXA \ - ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ - (JSONCPP_VERSION_PATCH << 8)) - -#ifdef JSONCPP_USING_SECURE_MEMORY -#undef JSONCPP_USING_SECURE_MEMORY -#endif -#define JSONCPP_USING_SECURE_MEMORY 0 -// If non-zero, the library zeroes any memory that it has allocated before -// it frees its memory. - -#endif // JSON_VERSION_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/version.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/allocator.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_ALLOCATOR_H_INCLUDED -#define JSON_ALLOCATOR_H_INCLUDED - -#include -#include - -#pragma pack(push) -#pragma pack() - -namespace Json { -template class SecureAllocator { -public: - // Type definitions - using value_type = T; - using pointer = T*; - using const_pointer = const T*; - using reference = T&; - using const_reference = const T&; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - - /** - * Allocate memory for N items using the standard allocator. - */ - pointer allocate(size_type n) { - // allocate using "global operator new" - return static_cast(::operator new(n * sizeof(T))); - } - - /** - * Release memory which was allocated for N items at pointer P. - * - * The memory block is filled with zeroes before being released. - */ - void deallocate(pointer p, size_type n) { - // memset_s is used because memset may be optimized away by the compiler - memset_s(p, n * sizeof(T), 0, n * sizeof(T)); - // free using "global operator delete" - ::operator delete(p); - } - - /** - * Construct an item in-place at pointer P. - */ - template void construct(pointer p, Args&&... args) { - // construct using "placement new" and "perfect forwarding" - ::new (static_cast(p)) T(std::forward(args)...); - } - - size_type max_size() const { return size_t(-1) / sizeof(T); } - - pointer address(reference x) const { return std::addressof(x); } - - const_pointer address(const_reference x) const { return std::addressof(x); } - - /** - * Destroy an item in-place at pointer P. - */ - void destroy(pointer p) { - // destroy using "explicit destructor" - p->~T(); - } - - // Boilerplate - SecureAllocator() {} - template SecureAllocator(const SecureAllocator&) {} - template struct rebind { using other = SecureAllocator; }; -}; - -template -bool operator==(const SecureAllocator&, const SecureAllocator&) { - return true; -} - -template -bool operator!=(const SecureAllocator&, const SecureAllocator&) { - return false; -} - -} // namespace Json - -#pragma pack(pop) - -#endif // JSON_ALLOCATOR_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/allocator.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/config.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_CONFIG_H_INCLUDED -#define JSON_CONFIG_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include - -// If non-zero, the library uses exceptions to report bad input instead of C -// assertion macros. The default is to use exceptions. -#ifndef JSON_USE_EXCEPTION -#define JSON_USE_EXCEPTION 1 -#endif - -// Temporary, tracked for removal with issue #982. -#ifndef JSON_USE_NULLREF -#define JSON_USE_NULLREF 1 -#endif - -/// If defined, indicates that the source file is amalgamated -/// to prevent private header inclusion. -/// Remarks: it is automatically defined in the generated amalgamated header. -// #define JSON_IS_AMALGAMATION - -// Export macros for DLL visibility -#if defined(JSON_DLL_BUILD) -#if defined(_MSC_VER) || defined(__MINGW32__) -#define JSON_API __declspec(dllexport) -#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING -#elif defined(__GNUC__) || defined(__clang__) -#define JSON_API __attribute__((visibility("default"))) -#endif // if defined(_MSC_VER) - -#elif defined(JSON_DLL) -#if defined(_MSC_VER) || defined(__MINGW32__) -#define JSON_API __declspec(dllimport) -#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING -#endif // if defined(_MSC_VER) -#endif // ifdef JSON_DLL_BUILD - -#if !defined(JSON_API) -#define JSON_API -#endif - -#if defined(_MSC_VER) && _MSC_VER < 1800 -#error \ - "ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities" -#endif - -#if defined(_MSC_VER) && _MSC_VER < 1900 -// As recommended at -// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 -extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size, - const char* format, ...); -#define jsoncpp_snprintf msvc_pre1900_c99_snprintf -#else -#define jsoncpp_snprintf std::snprintf -#endif - -// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for -// integer -// Storages, and 64 bits integer support is disabled. -// #define JSON_NO_INT64 1 - -// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools. -// C++11 should be used directly in JSONCPP. -#define JSONCPP_OVERRIDE override - -#ifdef __clang__ -#if __has_extension(attribute_deprecated_with_message) -#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) -#endif -#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc) -#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) -#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) -#endif // GNUC version -#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates - // MSVC) -#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) -#endif // __clang__ || __GNUC__ || _MSC_VER - -#if !defined(JSONCPP_DEPRECATED) -#define JSONCPP_DEPRECATED(message) -#endif // if !defined(JSONCPP_DEPRECATED) - -#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6)) -#define JSON_USE_INT64_DOUBLE_CONVERSION 1 -#endif - -#if !defined(JSON_IS_AMALGAMATION) - -#include "allocator.h" -#include "version.h" - -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { -using Int = int; -using UInt = unsigned int; -#if defined(JSON_NO_INT64) -using LargestInt = int; -using LargestUInt = unsigned int; -#undef JSON_HAS_INT64 -#else // if defined(JSON_NO_INT64) -// For Microsoft Visual use specific types as long long is not supported -#if defined(_MSC_VER) // Microsoft Visual Studio -using Int64 = __int64; -using UInt64 = unsigned __int64; -#else // if defined(_MSC_VER) // Other platforms, use long long -using Int64 = int64_t; -using UInt64 = uint64_t; -#endif // if defined(_MSC_VER) -using LargestInt = Int64; -using LargestUInt = UInt64; -#define JSON_HAS_INT64 -#endif // if defined(JSON_NO_INT64) - -template -using Allocator = - typename std::conditional, - std::allocator>::type; -using String = std::basic_string, Allocator>; -using IStringStream = - std::basic_istringstream; -using OStringStream = - std::basic_ostringstream; -using IStream = std::istream; -using OStream = std::ostream; -} // namespace Json - -// Legacy names (formerly macros). -using JSONCPP_STRING = Json::String; -using JSONCPP_ISTRINGSTREAM = Json::IStringStream; -using JSONCPP_OSTRINGSTREAM = Json::OStringStream; -using JSONCPP_ISTREAM = Json::IStream; -using JSONCPP_OSTREAM = Json::OStream; - -#endif // JSON_CONFIG_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/config.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/forwards.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_FORWARDS_H_INCLUDED -#define JSON_FORWARDS_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "config.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -// writer.h -class StreamWriter; -class StreamWriterBuilder; -class Writer; -class FastWriter; -class StyledWriter; -class StyledStreamWriter; - -// reader.h -class Reader; -class CharReader; -class CharReaderBuilder; - -// json_features.h -class Features; - -// value.h -using ArrayIndex = unsigned int; -class StaticString; -class Path; -class PathArgument; -class Value; -class ValueIteratorBase; -class ValueIterator; -class ValueConstIterator; - -} // namespace Json - -#endif // JSON_FORWARDS_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/forwards.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/json_features.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_FEATURES_H_INCLUDED -#define JSON_FEATURES_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "forwards.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -#pragma pack(push) -#pragma pack() - -namespace Json { - -/** \brief Configuration passed to reader and writer. - * This configuration object can be used to force the Reader or Writer - * to behave in a standard conforming way. - */ -class JSON_API Features { -public: - /** \brief A configuration that allows all features and assumes all strings - * are UTF-8. - * - C & C++ comments are allowed - * - Root object can be any JSON value - * - Assumes Value strings are encoded in UTF-8 - */ - static Features all(); - - /** \brief A configuration that is strictly compatible with the JSON - * specification. - * - Comments are forbidden. - * - Root object must be either an array or an object value. - * - Assumes Value strings are encoded in UTF-8 - */ - static Features strictMode(); - - /** \brief Initialize the configuration like JsonConfig::allFeatures; - */ - Features(); - - /// \c true if comments are allowed. Default: \c true. - bool allowComments_{true}; - - /// \c true if root must be either an array or an object value. Default: \c - /// false. - bool strictRoot_{false}; - - /// \c true if dropped null placeholders are allowed. Default: \c false. - bool allowDroppedNullPlaceholders_{false}; - - /// \c true if numeric object key are allowed. Default: \c false. - bool allowNumericKeys_{false}; -}; - -} // namespace Json - -#pragma pack(pop) - -#endif // JSON_FEATURES_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/json_features.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/value.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_H_INCLUDED -#define JSON_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "forwards.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -// Conditional NORETURN attribute on the throw functions would: -// a) suppress false positives from static code analysis -// b) possibly improve optimization opportunities. -#if !defined(JSONCPP_NORETURN) -#if defined(_MSC_VER) && _MSC_VER == 1800 -#define JSONCPP_NORETURN __declspec(noreturn) -#else -#define JSONCPP_NORETURN [[noreturn]] -#endif -#endif - -// Support for '= delete' with template declarations was a late addition -// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2 -// even though these declare themselves to be c++11 compilers. -#if !defined(JSONCPP_TEMPLATE_DELETE) -#if defined(__clang__) && defined(__apple_build_version__) -#if __apple_build_version__ <= 8000042 -#define JSONCPP_TEMPLATE_DELETE -#endif -#elif defined(__clang__) -#if __clang_major__ == 3 && __clang_minor__ <= 8 -#define JSONCPP_TEMPLATE_DELETE -#endif -#endif -#if !defined(JSONCPP_TEMPLATE_DELETE) -#define JSONCPP_TEMPLATE_DELETE = delete -#endif -#endif - -#include -#include -#include -#include -#include -#include - -// Disable warning C4251: : needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(push) -#pragma warning(disable : 4251 4275) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#pragma pack(push) -#pragma pack() - -/** \brief JSON (JavaScript Object Notation). - */ -namespace Json { - -#if JSON_USE_EXCEPTION -/** Base class for all exceptions we throw. - * - * We use nothing but these internally. Of course, STL can throw others. - */ -class JSON_API Exception : public std::exception { -public: - Exception(String msg); - ~Exception() noexcept override; - char const* what() const noexcept override; - -protected: - String msg_; -}; - -/** Exceptions which the user cannot easily avoid. - * - * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input - * - * \remark derived from Json::Exception - */ -class JSON_API RuntimeError : public Exception { -public: - RuntimeError(String const& msg); -}; - -/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. - * - * These are precondition-violations (user bugs) and internal errors (our bugs). - * - * \remark derived from Json::Exception - */ -class JSON_API LogicError : public Exception { -public: - LogicError(String const& msg); -}; -#endif - -/// used internally -JSONCPP_NORETURN void throwRuntimeError(String const& msg); -/// used internally -JSONCPP_NORETURN void throwLogicError(String const& msg); - -/** \brief Type of the value held by a Value object. - */ -enum ValueType { - nullValue = 0, ///< 'null' value - intValue, ///< signed integer value - uintValue, ///< unsigned integer value - realValue, ///< double value - stringValue, ///< UTF-8 string value - booleanValue, ///< bool value - arrayValue, ///< array value (ordered list) - objectValue ///< object value (collection of name/value pairs). -}; - -enum CommentPlacement { - commentBefore = 0, ///< a comment placed on the line before a value - commentAfterOnSameLine, ///< a comment just after a value on the same line - commentAfter, ///< a comment on the line after a value (only make sense for - /// root value) - numberOfCommentPlacement -}; - -/** \brief Type of precision for formatting of real values. - */ -enum PrecisionType { - significantDigits = 0, ///< we set max number of significant digits in string - decimalPlaces ///< we set max number of digits after "." in string -}; - -/** \brief Lightweight wrapper to tag static string. - * - * Value constructor and objectValue member assignment takes advantage of the - * StaticString and avoid the cost of string duplication when storing the - * string or the member name. - * - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ -class JSON_API StaticString { -public: - explicit StaticString(const char* czstring) : c_str_(czstring) {} - - operator const char*() const { return c_str_; } - - const char* c_str() const { return c_str_; } - -private: - const char* c_str_; -}; - -/** \brief Represents a JSON value. - * - * This class is a discriminated union wrapper that can represents a: - * - signed integer [range: Value::minInt - Value::maxInt] - * - unsigned integer (range: 0 - Value::maxUInt) - * - double - * - UTF-8 string - * - boolean - * - 'null' - * - an ordered list of Value - * - collection of name/value pairs (javascript object) - * - * The type of the held value is represented by a #ValueType and - * can be obtained using type(). - * - * Values of an #objectValue or #arrayValue can be accessed using operator[]() - * methods. - * Non-const methods will automatically create the a #nullValue element - * if it does not exist. - * The sequence of an #arrayValue will be automatically resized and initialized - * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. - * - * The get() methods can be used to obtain default value in the case the - * required element does not exist. - * - * It is possible to iterate over the list of member keys of an object using - * the getMemberNames() method. - * - * \note #Value string-length fit in size_t, but keys must be < 2^30. - * (The reason is an implementation detail.) A #CharReader will raise an - * exception if a bound is exceeded to avoid security holes in your app, - * but the Value API does *not* check bounds. That is the responsibility - * of the caller. - */ -class JSON_API Value { - friend class ValueIteratorBase; - -public: - using Members = std::vector; - using iterator = ValueIterator; - using const_iterator = ValueConstIterator; - using UInt = Json::UInt; - using Int = Json::Int; -#if defined(JSON_HAS_INT64) - using UInt64 = Json::UInt64; - using Int64 = Json::Int64; -#endif // defined(JSON_HAS_INT64) - using LargestInt = Json::LargestInt; - using LargestUInt = Json::LargestUInt; - using ArrayIndex = Json::ArrayIndex; - - // Required for boost integration, e. g. BOOST_TEST - using value_type = std::string; - -#if JSON_USE_NULLREF - // Binary compatibility kludges, do not use. - static const Value& null; - static const Value& nullRef; -#endif - - // null and nullRef are deprecated, use this instead. - static Value const& nullSingleton(); - - /// Minimum signed integer value that can be stored in a Json::Value. - static constexpr LargestInt minLargestInt = - LargestInt(~(LargestUInt(-1) / 2)); - /// Maximum signed integer value that can be stored in a Json::Value. - static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2); - /// Maximum unsigned integer value that can be stored in a Json::Value. - static constexpr LargestUInt maxLargestUInt = LargestUInt(-1); - - /// Minimum signed int value that can be stored in a Json::Value. - static constexpr Int minInt = Int(~(UInt(-1) / 2)); - /// Maximum signed int value that can be stored in a Json::Value. - static constexpr Int maxInt = Int(UInt(-1) / 2); - /// Maximum unsigned int value that can be stored in a Json::Value. - static constexpr UInt maxUInt = UInt(-1); - -#if defined(JSON_HAS_INT64) - /// Minimum signed 64 bits int value that can be stored in a Json::Value. - static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2)); - /// Maximum signed 64 bits int value that can be stored in a Json::Value. - static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2); - /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. - static constexpr UInt64 maxUInt64 = UInt64(-1); -#endif // defined(JSON_HAS_INT64) - /// Default precision for real value for string representation. - static constexpr UInt defaultRealPrecision = 17; - // The constant is hard-coded because some compiler have trouble - // converting Value::maxUInt64 to a double correctly (AIX/xlC). - // Assumes that UInt64 is a 64 bits integer. - static constexpr double maxUInt64AsDouble = 18446744073709551615.0; -// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler -// when using gcc and clang backend compilers. CZString -// cannot be defined as private. See issue #486 -#ifdef __NVCC__ -public: -#else -private: -#endif -#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - class CZString { - public: - enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; - CZString(ArrayIndex index); - CZString(char const* str, unsigned length, DuplicationPolicy allocate); - CZString(CZString const& other); - CZString(CZString&& other) noexcept; - ~CZString(); - CZString& operator=(const CZString& other); - CZString& operator=(CZString&& other) noexcept; - - bool operator<(CZString const& other) const; - bool operator==(CZString const& other) const; - ArrayIndex index() const; - // const char* c_str() const; ///< \deprecated - char const* data() const; - unsigned length() const; - bool isStaticString() const; - - private: - void swap(CZString& other); - - struct StringStorage { - unsigned policy_ : 2; - unsigned length_ : 30; // 1GB max - }; - - char const* cstr_; // actually, a prefixed string, unless policy is noDup - union { - ArrayIndex index_; - StringStorage storage_; - }; - }; - -public: - typedef std::map ObjectValues; -#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - -public: - /** - * \brief Create a default Value of the given type. - * - * This is a very useful constructor. - * To create an empty array, pass arrayValue. - * To create an empty object, pass objectValue. - * Another Value can then be set to this one by assignment. - * This is useful since clear() and resize() will not alter types. - * - * Examples: - * \code - * Json::Value null_value; // null - * Json::Value arr_value(Json::arrayValue); // [] - * Json::Value obj_value(Json::objectValue); // {} - * \endcode - */ - Value(ValueType type = nullValue); - Value(Int value); - Value(UInt value); -#if defined(JSON_HAS_INT64) - Value(Int64 value); - Value(UInt64 value); -#endif // if defined(JSON_HAS_INT64) - Value(double value); - Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) - Value(const char* begin, const char* end); ///< Copy all, incl zeroes. - /** - * \brief Constructs a value from a static string. - * - * Like other value string constructor but do not duplicate the string for - * internal storage. The given string must remain alive after the call to - * this constructor. - * - * \note This works only for null-terminated strings. (We cannot change the - * size of this class, so we have nowhere to store the length, which might be - * computed later for various operations.) - * - * Example of usage: - * \code - * static StaticString foo("some text"); - * Json::Value aValue(foo); - * \endcode - */ - Value(const StaticString& value); - Value(const String& value); - Value(bool value); - Value(std::nullptr_t ptr) = delete; - Value(const Value& other); - Value(Value&& other) noexcept; - ~Value(); - - /// \note Overwrite existing comments. To preserve comments, use - /// #swapPayload(). - Value& operator=(const Value& other); - Value& operator=(Value&& other) noexcept; - - /// Swap everything. - void swap(Value& other); - /// Swap values but leave comments and source offsets in place. - void swapPayload(Value& other); - - /// copy everything. - void copy(const Value& other); - /// copy values but leave comments and source offsets in place. - void copyPayload(const Value& other); - - ValueType type() const; - - /// Compare payload only, not comments etc. - bool operator<(const Value& other) const; - bool operator<=(const Value& other) const; - bool operator>=(const Value& other) const; - bool operator>(const Value& other) const; - bool operator==(const Value& other) const; - bool operator!=(const Value& other) const; - int compare(const Value& other) const; - - const char* asCString() const; ///< Embedded zeroes could cause you trouble! -#if JSONCPP_USING_SECURE_MEMORY - unsigned getCStringLength() const; // Allows you to understand the length of - // the CString -#endif - String asString() const; ///< Embedded zeroes are possible. - /** Get raw char* of string-value. - * \return false if !string. (Seg-fault if str or end are NULL.) - */ - bool getString(char const** begin, char const** end) const; - Int asInt() const; - UInt asUInt() const; -#if defined(JSON_HAS_INT64) - Int64 asInt64() const; - UInt64 asUInt64() const; -#endif // if defined(JSON_HAS_INT64) - LargestInt asLargestInt() const; - LargestUInt asLargestUInt() const; - float asFloat() const; - double asDouble() const; - bool asBool() const; - - bool isNull() const; - bool isBool() const; - bool isInt() const; - bool isInt64() const; - bool isUInt() const; - bool isUInt64() const; - bool isIntegral() const; - bool isDouble() const; - bool isNumeric() const; - bool isString() const; - bool isArray() const; - bool isObject() const; - - /// The `as` and `is` member function templates and specializations. - template T as() const JSONCPP_TEMPLATE_DELETE; - template bool is() const JSONCPP_TEMPLATE_DELETE; - - bool isConvertibleTo(ValueType other) const; - - /// Number of values in array or object - ArrayIndex size() const; - - /// \brief Return true if empty array, empty object, or null; - /// otherwise, false. - bool empty() const; - - /// Return !isNull() - explicit operator bool() const; - - /// Remove all object members and array elements. - /// \pre type() is arrayValue, objectValue, or nullValue - /// \post type() is unchanged - void clear(); - - /// Resize the array to newSize elements. - /// New elements are initialized to null. - /// May only be called on nullValue or arrayValue. - /// \pre type() is arrayValue or nullValue - /// \post type() is arrayValue - void resize(ArrayIndex newSize); - - ///@{ - /// Access an array element (zero based index). If the array contains less - /// than index element, then null value are inserted in the array so that - /// its size is index+1. - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - Value& operator[](ArrayIndex index); - Value& operator[](int index); - ///@} - - ///@{ - /// Access an array element (zero based index). - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - const Value& operator[](ArrayIndex index) const; - const Value& operator[](int index) const; - ///@} - - /// If the array contains at least index+1 elements, returns the element - /// value, otherwise returns defaultValue. - Value get(ArrayIndex index, const Value& defaultValue) const; - /// Return true if index < size(). - bool isValidIndex(ArrayIndex index) const; - /// \brief Append value to array at the end. - /// - /// Equivalent to jsonvalue[jsonvalue.size()] = value; - Value& append(const Value& value); - Value& append(Value&& value); - - /// \brief Insert value in array at specific index - bool insert(ArrayIndex index, const Value& newValue); - bool insert(ArrayIndex index, Value&& newValue); - - /// Access an object value by name, create a null member if it does not exist. - /// \note Because of our implementation, keys are limited to 2^30 -1 chars. - /// Exceeding that will cause an exception. - Value& operator[](const char* key); - /// Access an object value by name, returns null if there is no member with - /// that name. - const Value& operator[](const char* key) const; - /// Access an object value by name, create a null member if it does not exist. - /// \param key may contain embedded nulls. - Value& operator[](const String& key); - /// Access an object value by name, returns null if there is no member with - /// that name. - /// \param key may contain embedded nulls. - const Value& operator[](const String& key) const; - /** \brief Access an object value by name, create a null member if it does not - * exist. - * - * If the object has no entry for that name, then the member name used to - * store the new entry is not duplicated. - * Example of use: - * \code - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - Value& operator[](const StaticString& key); - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - Value get(const char* key, const Value& defaultValue) const; - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - /// \note key may contain embedded nulls. - Value get(const char* begin, const char* end, - const Value& defaultValue) const; - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - /// \param key may contain embedded nulls. - Value get(const String& key, const Value& defaultValue) const; - /// Most general and efficient version of isMember()const, get()const, - /// and operator[]const - /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 - Value const* find(char const* begin, char const* end) const; - /// Most general and efficient version of object-mutators. - /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 - /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. - Value* demand(char const* begin, char const* end); - /// \brief Remove and return the named member. - /// - /// Do nothing if it did not exist. - /// \pre type() is objectValue or nullValue - /// \post type() is unchanged - void removeMember(const char* key); - /// Same as removeMember(const char*) - /// \param key may contain embedded nulls. - void removeMember(const String& key); - /// Same as removeMember(const char* begin, const char* end, Value* removed), - /// but 'key' is null-terminated. - bool removeMember(const char* key, Value* removed); - /** \brief Remove the named map member. - * - * Update 'removed' iff removed. - * \param key may contain embedded nulls. - * \return true iff removed (no exceptions) - */ - bool removeMember(String const& key, Value* removed); - /// Same as removeMember(String const& key, Value* removed) - bool removeMember(const char* begin, const char* end, Value* removed); - /** \brief Remove the indexed array element. - * - * O(n) expensive operations. - * Update 'removed' iff removed. - * \return true if removed (no exceptions) - */ - bool removeIndex(ArrayIndex index, Value* removed); - - /// Return true if the object has a member named key. - /// \note 'key' must be null-terminated. - bool isMember(const char* key) const; - /// Return true if the object has a member named key. - /// \param key may contain embedded nulls. - bool isMember(const String& key) const; - /// Same as isMember(String const& key)const - bool isMember(const char* begin, const char* end) const; - - /// \brief Return a list of the member names. - /// - /// If null, return an empty list. - /// \pre type() is objectValue or nullValue - /// \post if type() was nullValue, it remains nullValue - Members getMemberNames() const; - - /// \deprecated Always pass len. - JSONCPP_DEPRECATED("Use setComment(String const&) instead.") - void setComment(const char* comment, CommentPlacement placement) { - setComment(String(comment, strlen(comment)), placement); - } - /// Comments must be //... or /* ... */ - void setComment(const char* comment, size_t len, CommentPlacement placement) { - setComment(String(comment, len), placement); - } - /// Comments must be //... or /* ... */ - void setComment(String comment, CommentPlacement placement); - bool hasComment(CommentPlacement placement) const; - /// Include delimiters and embedded newlines. - String getComment(CommentPlacement placement) const; - - String toStyledString() const; - - const_iterator begin() const; - const_iterator end() const; - - iterator begin(); - iterator end(); - - // Accessors for the [start, limit) range of bytes within the JSON text from - // which this value was parsed, if any. - void setOffsetStart(ptrdiff_t start); - void setOffsetLimit(ptrdiff_t limit); - ptrdiff_t getOffsetStart() const; - ptrdiff_t getOffsetLimit() const; - -private: - void setType(ValueType v) { - bits_.value_type_ = static_cast(v); - } - bool isAllocated() const { return bits_.allocated_; } - void setIsAllocated(bool v) { bits_.allocated_ = v; } - - void initBasic(ValueType type, bool allocated = false); - void dupPayload(const Value& other); - void releasePayload(); - void dupMeta(const Value& other); - - Value& resolveReference(const char* key); - Value& resolveReference(const char* key, const char* end); - - // struct MemberNamesTransform - //{ - // typedef const char *result_type; - // const char *operator()( const CZString &name ) const - // { - // return name.c_str(); - // } - //}; - - union ValueHolder { - LargestInt int_; - LargestUInt uint_; - double real_; - bool bool_; - char* string_; // if allocated_, ptr to { unsigned, char[] }. - ObjectValues* map_; - } value_; - - struct { - // Really a ValueType, but types should agree for bitfield packing. - unsigned int value_type_ : 8; - // Unless allocated_, string_ must be null-terminated. - unsigned int allocated_ : 1; - } bits_; - - class Comments { - public: - Comments() = default; - Comments(const Comments& that); - Comments(Comments&& that) noexcept; - Comments& operator=(const Comments& that); - Comments& operator=(Comments&& that) noexcept; - bool has(CommentPlacement slot) const; - String get(CommentPlacement slot) const; - void set(CommentPlacement slot, String comment); - - private: - using Array = std::array; - std::unique_ptr ptr_; - }; - Comments comments_; - - // [start, limit) byte offsets in the source JSON text from which this Value - // was extracted. - ptrdiff_t start_; - ptrdiff_t limit_; -}; - -template <> inline bool Value::as() const { return asBool(); } -template <> inline bool Value::is() const { return isBool(); } - -template <> inline Int Value::as() const { return asInt(); } -template <> inline bool Value::is() const { return isInt(); } - -template <> inline UInt Value::as() const { return asUInt(); } -template <> inline bool Value::is() const { return isUInt(); } - -#if defined(JSON_HAS_INT64) -template <> inline Int64 Value::as() const { return asInt64(); } -template <> inline bool Value::is() const { return isInt64(); } - -template <> inline UInt64 Value::as() const { return asUInt64(); } -template <> inline bool Value::is() const { return isUInt64(); } -#endif - -template <> inline double Value::as() const { return asDouble(); } -template <> inline bool Value::is() const { return isDouble(); } - -template <> inline String Value::as() const { return asString(); } -template <> inline bool Value::is() const { return isString(); } - -/// These `as` specializations are type conversions, and do not have a -/// corresponding `is`. -template <> inline float Value::as() const { return asFloat(); } -template <> inline const char* Value::as() const { - return asCString(); -} - -/** \brief Experimental and untested: represents an element of the "path" to - * access a node. - */ -class JSON_API PathArgument { -public: - friend class Path; - - PathArgument(); - PathArgument(ArrayIndex index); - PathArgument(const char* key); - PathArgument(String key); - -private: - enum Kind { kindNone = 0, kindIndex, kindKey }; - String key_; - ArrayIndex index_{}; - Kind kind_{kindNone}; -}; - -/** \brief Experimental and untested: represents a "path" to access a node. - * - * Syntax: - * - "." => root node - * - ".[n]" => elements at index 'n' of root node (an array value) - * - ".name" => member named 'name' of root node (an object value) - * - ".name1.name2.name3" - * - ".[0][1][2].name1[3]" - * - ".%" => member name is provided as parameter - * - ".[%]" => index is provided as parameter - */ -class JSON_API Path { -public: - Path(const String& path, const PathArgument& a1 = PathArgument(), - const PathArgument& a2 = PathArgument(), - const PathArgument& a3 = PathArgument(), - const PathArgument& a4 = PathArgument(), - const PathArgument& a5 = PathArgument()); - - const Value& resolve(const Value& root) const; - Value resolve(const Value& root, const Value& defaultValue) const; - /// Creates the "path" to access the specified node and returns a reference on - /// the node. - Value& make(Value& root) const; - -private: - using InArgs = std::vector; - using Args = std::vector; - - void makePath(const String& path, const InArgs& in); - void addPathInArg(const String& path, const InArgs& in, - InArgs::const_iterator& itInArg, PathArgument::Kind kind); - static void invalidPath(const String& path, int location); - - Args args_; -}; - -/** \brief base class for Value iterators. - * - */ -class JSON_API ValueIteratorBase { -public: - using iterator_category = std::bidirectional_iterator_tag; - using size_t = unsigned int; - using difference_type = int; - using SelfType = ValueIteratorBase; - - bool operator==(const SelfType& other) const { return isEqual(other); } - - bool operator!=(const SelfType& other) const { return !isEqual(other); } - - difference_type operator-(const SelfType& other) const { - return other.computeDistance(*this); - } - - /// Return either the index or the member name of the referenced value as a - /// Value. - Value key() const; - - /// Return the index of the referenced Value, or -1 if it is not an - /// arrayValue. - UInt index() const; - - /// Return the member name of the referenced Value, or "" if it is not an - /// objectValue. - /// \note Avoid `c_str()` on result, as embedded zeroes are possible. - String name() const; - - /// Return the member name of the referenced Value. "" if it is not an - /// objectValue. - /// \deprecated This cannot be used for UTF-8 strings, since there can be - /// embedded nulls. - JSONCPP_DEPRECATED("Use `key = name();` instead.") - char const* memberName() const; - /// Return the member name of the referenced Value, or NULL if it is not an - /// objectValue. - /// \note Better version than memberName(). Allows embedded nulls. - char const* memberName(char const** end) const; - -protected: - /*! Internal utility functions to assist with implementing - * other iterator functions. The const and non-const versions - * of the "deref" protected methods expose the protected - * current_ member variable in a way that can often be - * optimized away by the compiler. - */ - const Value& deref() const; - Value& deref(); - - void increment(); - - void decrement(); - - difference_type computeDistance(const SelfType& other) const; - - bool isEqual(const SelfType& other) const; - - void copy(const SelfType& other); - -private: - Value::ObjectValues::iterator current_; - // Indicates that iterator is for a null value. - bool isNull_{true}; - -public: - // For some reason, BORLAND needs these at the end, rather - // than earlier. No idea why. - ValueIteratorBase(); - explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); -}; - -/** \brief const iterator for object and array value. - * - */ -class JSON_API ValueConstIterator : public ValueIteratorBase { - friend class Value; - -public: - using value_type = const Value; - // typedef unsigned int size_t; - // typedef int difference_type; - using reference = const Value&; - using pointer = const Value*; - using SelfType = ValueConstIterator; - - ValueConstIterator(); - ValueConstIterator(ValueIterator const& other); - -private: - /*! \internal Use by Value to create an iterator. - */ - explicit ValueConstIterator(const Value::ObjectValues::iterator& current); - -public: - SelfType& operator=(const ValueIteratorBase& other); - - SelfType operator++(int) { - SelfType temp(*this); - ++*this; - return temp; - } - - SelfType operator--(int) { - SelfType temp(*this); - --*this; - return temp; - } - - SelfType& operator--() { - decrement(); - return *this; - } - - SelfType& operator++() { - increment(); - return *this; - } - - reference operator*() const { return deref(); } - - pointer operator->() const { return &deref(); } -}; - -/** \brief Iterator for object and array value. - */ -class JSON_API ValueIterator : public ValueIteratorBase { - friend class Value; - -public: - using value_type = Value; - using size_t = unsigned int; - using difference_type = int; - using reference = Value&; - using pointer = Value*; - using SelfType = ValueIterator; - - ValueIterator(); - explicit ValueIterator(const ValueConstIterator& other); - ValueIterator(const ValueIterator& other); - -private: - /*! \internal Use by Value to create an iterator. - */ - explicit ValueIterator(const Value::ObjectValues::iterator& current); - -public: - SelfType& operator=(const SelfType& other); - - SelfType operator++(int) { - SelfType temp(*this); - ++*this; - return temp; - } - - SelfType operator--(int) { - SelfType temp(*this); - --*this; - return temp; - } - - SelfType& operator--() { - decrement(); - return *this; - } - - SelfType& operator++() { - increment(); - return *this; - } - - /*! The return value of non-const iterators can be - * changed, so the these functions are not const - * because the returned references/pointers can be used - * to change state of the base class. - */ - reference operator*() const { return const_cast(deref()); } - pointer operator->() const { return const_cast(&deref()); } -}; - -inline void swap(Value& a, Value& b) { a.swap(b); } - -} // namespace Json - -#pragma pack(pop) - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // JSON_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/value.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/reader.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_READER_H_INCLUDED -#define JSON_READER_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "json_features.h" -#include "value.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include - -// Disable warning C4251: : needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(push) -#pragma warning(disable : 4251) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#pragma pack(push) -#pragma pack() - -namespace Json { - -/** \brief Unserialize a JSON document into a - * Value. - * - * \deprecated Use CharReader and CharReaderBuilder. - */ - -class JSON_API Reader { -public: - using Char = char; - using Location = const Char*; - - /** \brief An error tagged with where in the JSON text it was encountered. - * - * The offsets give the [start, limit) range of bytes within the text. Note - * that this is bytes, not codepoints. - */ - struct StructuredError { - ptrdiff_t offset_start; - ptrdiff_t offset_limit; - String message; - }; - - /** \brief Constructs a Reader allowing all features for parsing. - * \deprecated Use CharReader and CharReaderBuilder. - */ - Reader(); - - /** \brief Constructs a Reader allowing the specified feature set for parsing. - * \deprecated Use CharReader and CharReaderBuilder. - */ - Reader(const Features& features); - - /** \brief Read a Value from a JSON - * document. - * - * \param document UTF-8 encoded string containing the document - * to read. - * \param[out] root Contains the root value of the document if it - * was successfully parsed. - * \param collectComments \c true to collect comment and allow writing - * them back during serialization, \c false to - * discard comments. This parameter is ignored - * if Features::allowComments_ is \c false. - * \return \c true if the document was successfully parsed, \c false if an - * error occurred. - */ - bool parse(const std::string& document, Value& root, - bool collectComments = true); - - /** \brief Read a Value from a JSON - * document. - * - * \param beginDoc Pointer on the beginning of the UTF-8 encoded - * string of the document to read. - * \param endDoc Pointer on the end of the UTF-8 encoded string - * of the document to read. Must be >= beginDoc. - * \param[out] root Contains the root value of the document if it - * was successfully parsed. - * \param collectComments \c true to collect comment and allow writing - * them back during serialization, \c false to - * discard comments. This parameter is ignored - * if Features::allowComments_ is \c false. - * \return \c true if the document was successfully parsed, \c false if an - * error occurred. - */ - bool parse(const char* beginDoc, const char* endDoc, Value& root, - bool collectComments = true); - - /// \brief Parse from input stream. - /// \see Json::operator>>(std::istream&, Json::Value&). - bool parse(IStream& is, Value& root, bool collectComments = true); - - /** \brief Returns a user friendly string that list errors in the parsed - * document. - * - * \return Formatted error message with the list of errors with their - * location in the parsed document. An empty string is returned if no error - * occurred during parsing. - * \deprecated Use getFormattedErrorMessages() instead (typo fix). - */ - JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") - String getFormatedErrorMessages() const; - - /** \brief Returns a user friendly string that list errors in the parsed - * document. - * - * \return Formatted error message with the list of errors with their - * location in the parsed document. An empty string is returned if no error - * occurred during parsing. - */ - String getFormattedErrorMessages() const; - - /** \brief Returns a vector of structured errors encountered while parsing. - * - * \return A (possibly empty) vector of StructuredError objects. Currently - * only one error can be returned, but the caller should tolerate multiple - * errors. This can occur if the parser recovers from a non-fatal parse - * error and then encounters additional errors. - */ - std::vector getStructuredErrors() const; - - /** \brief Add a semantic error message. - * - * \param value JSON Value location associated with the error - * \param message The error message. - * \return \c true if the error was successfully added, \c false if the Value - * offset exceeds the document size. - */ - bool pushError(const Value& value, const String& message); - - /** \brief Add a semantic error message with extra context. - * - * \param value JSON Value location associated with the error - * \param message The error message. - * \param extra Additional JSON Value location to contextualize the error - * \return \c true if the error was successfully added, \c false if either - * Value offset exceeds the document size. - */ - bool pushError(const Value& value, const String& message, const Value& extra); - - /** \brief Return whether there are any errors. - * - * \return \c true if there are no errors to report \c false if errors have - * occurred. - */ - bool good() const; - -private: - enum TokenType { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo { - public: - Token token_; - String message_; - Location extra_; - }; - - using Errors = std::deque; - - bool readToken(Token& token); - void skipSpaces(); - bool match(const Char* pattern, int patternLength); - bool readComment(); - bool readCStyleComment(); - bool readCppStyleComment(); - bool readString(); - void readNumber(); - bool readValue(); - bool readObject(Token& token); - bool readArray(Token& token); - bool decodeNumber(Token& token); - bool decodeNumber(Token& token, Value& decoded); - bool decodeString(Token& token); - bool decodeString(Token& token, String& decoded); - bool decodeDouble(Token& token); - bool decodeDouble(Token& token, Value& decoded); - bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, - unsigned int& unicode); - bool decodeUnicodeEscapeSequence(Token& token, Location& current, - Location end, unsigned int& unicode); - bool addError(const String& message, Token& token, Location extra = nullptr); - bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const String& message, Token& token, - TokenType skipUntilToken); - void skipUntilSpace(); - Value& currentValue(); - Char getNextChar(); - void getLocationLineAndColumn(Location location, int& line, - int& column) const; - String getLocationLineAndColumn(Location location) const; - void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); - - static bool containsNewLine(Location begin, Location end); - static String normalizeEOL(Location begin, Location end); - - using Nodes = std::stack; - Nodes nodes_; - Errors errors_; - String document_; - Location begin_{}; - Location end_{}; - Location current_{}; - Location lastValueEnd_{}; - Value* lastValue_{}; - String commentsBefore_; - Features features_; - bool collectComments_{}; -}; // Reader - -/** Interface for reading JSON from a char array. - */ -class JSON_API CharReader { -public: - virtual ~CharReader() = default; - /** \brief Read a Value from a JSON - * document. The document must be a UTF-8 encoded string containing the - * document to read. - * - * \param beginDoc Pointer on the beginning of the UTF-8 encoded string - * of the document to read. - * \param endDoc Pointer on the end of the UTF-8 encoded string of the - * document to read. Must be >= beginDoc. - * \param[out] root Contains the root value of the document if it was - * successfully parsed. - * \param[out] errs Formatted error messages (if not NULL) a user - * friendly string that lists errors in the parsed - * document. - * \return \c true if the document was successfully parsed, \c false if an - * error occurred. - */ - virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, - String* errs) = 0; - - class JSON_API Factory { - public: - virtual ~Factory() = default; - /** \brief Allocate a CharReader via operator new(). - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - virtual CharReader* newCharReader() const = 0; - }; // Factory -}; // CharReader - -/** \brief Build a CharReader implementation. - * - * Usage: - * \code - * using namespace Json; - * CharReaderBuilder builder; - * builder["collectComments"] = false; - * Value value; - * String errs; - * bool ok = parseFromStream(builder, std::cin, &value, &errs); - * \endcode - */ -class JSON_API CharReaderBuilder : public CharReader::Factory { -public: - // Note: We use a Json::Value so that we can add data-members to this class - // without a major version bump. - /** Configuration of this builder. - * These are case-sensitive. - * Available settings (case-sensitive): - * - `"collectComments": false or true` - * - true to collect comment and allow writing them back during - * serialization, false to discard comments. This parameter is ignored - * if allowComments is false. - * - `"allowComments": false or true` - * - true if comments are allowed. - * - `"allowTrailingCommas": false or true` - * - true if trailing commas in objects and arrays are allowed. - * - `"strictRoot": false or true` - * - true if root must be either an array or an object value - * - `"allowDroppedNullPlaceholders": false or true` - * - true if dropped null placeholders are allowed. (See - * StreamWriterBuilder.) - * - `"allowNumericKeys": false or true` - * - true if numeric object keys are allowed. - * - `"allowSingleQuotes": false or true` - * - true if '' are allowed for strings (both keys and values) - * - `"stackLimit": integer` - * - Exceeding stackLimit (recursive depth of `readValue()`) will cause an - * exception. - * - This is a security issue (seg-faults caused by deeply nested JSON), so - * the default is low. - * - `"failIfExtra": false or true` - * - If true, `parse()` returns false when extra non-whitespace trails the - * JSON value in the input string. - * - `"rejectDupKeys": false or true` - * - If true, `parse()` returns false when a key is duplicated within an - * object. - * - `"allowSpecialFloats": false or true` - * - If true, special float values (NaNs and infinities) are allowed and - * their values are lossfree restorable. - * - `"skipBom": false or true` - * - If true, if the input starts with the Unicode byte order mark (BOM), - * it is skipped. - * - * You can examine 'settings_` yourself to see the defaults. You can also - * write and read them just like any JSON Value. - * \sa setDefaults() - */ - Json::Value settings_; - - CharReaderBuilder(); - ~CharReaderBuilder() override; - - CharReader* newCharReader() const override; - - /** \return true if 'settings' are legal and consistent; - * otherwise, indicate bad settings via 'invalid'. - */ - bool validate(Json::Value* invalid) const; - - /** A simple way to update a specific setting. - */ - Value& operator[](const String& key); - - /** Called by ctor, but you can use this to reset settings_. - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults - */ - static void setDefaults(Json::Value* settings); - /** Same as old Features::strictMode(). - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode - */ - static void strictMode(Json::Value* settings); -}; - -/** Consume entire stream and use its begin/end. - * Someday we might have a real StreamReader, but for now this - * is convenient. - */ -bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root, - String* errs); - -/** \brief Read from 'sin' into 'root'. - * - * Always keep comments from the input JSON. - * - * This can be used to read a file into a particular sub-object. - * For example: - * \code - * Json::Value root; - * cin >> root["dir"]["file"]; - * cout << root; - * \endcode - * Result: - * \verbatim - * { - * "dir": { - * "file": { - * // The input stream JSON would be nested here. - * } - * } - * } - * \endverbatim - * \throw std::exception on parse error. - * \see Json::operator<<() - */ -JSON_API IStream& operator>>(IStream&, Value&); - -} // namespace Json - -#pragma pack(pop) - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // JSON_READER_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/reader.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/writer.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_WRITER_H_INCLUDED -#define JSON_WRITER_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "value.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include - -// Disable warning C4251: : needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4251) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#pragma pack(push) -#pragma pack() - -namespace Json { - -class Value; - -/** - * - * Usage: - * \code - * using namespace Json; - * void writeToStdout(StreamWriter::Factory const& factory, Value const& value) - * { std::unique_ptr const writer( factory.newStreamWriter()); - * writer->write(value, &std::cout); - * std::cout << std::endl; // add lf and flush - * } - * \endcode - */ -class JSON_API StreamWriter { -protected: - OStream* sout_; // not owned; will not delete -public: - StreamWriter(); - virtual ~StreamWriter(); - /** Write Value into document as configured in sub-class. - * Do not take ownership of sout, but maintain a reference during function. - * \pre sout != NULL - * \return zero on success (For now, we always return zero, so check the - * stream instead.) \throw std::exception possibly, depending on - * configuration - */ - virtual int write(Value const& root, OStream* sout) = 0; - - /** \brief A simple abstract factory. - */ - class JSON_API Factory { - public: - virtual ~Factory(); - /** \brief Allocate a CharReader via operator new(). - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - virtual StreamWriter* newStreamWriter() const = 0; - }; // Factory -}; // StreamWriter - -/** \brief Write into stringstream, then return string, for convenience. - * A StreamWriter will be created from the factory, used, and then deleted. - */ -String JSON_API writeString(StreamWriter::Factory const& factory, - Value const& root); - -/** \brief Build a StreamWriter implementation. - -* Usage: -* \code -* using namespace Json; -* Value value = ...; -* StreamWriterBuilder builder; -* builder["commentStyle"] = "None"; -* builder["indentation"] = " "; // or whatever you like -* std::unique_ptr writer( -* builder.newStreamWriter()); -* writer->write(value, &std::cout); -* std::cout << std::endl; // add lf and flush -* \endcode -*/ -class JSON_API StreamWriterBuilder : public StreamWriter::Factory { -public: - // Note: We use a Json::Value so that we can add data-members to this class - // without a major version bump. - /** Configuration of this builder. - * Available settings (case-sensitive): - * - "commentStyle": "None" or "All" - * - "indentation": "". - * - Setting this to an empty string also omits newline characters. - * - "enableYAMLCompatibility": false or true - * - slightly change the whitespace around colons - * - "dropNullPlaceholders": false or true - * - Drop the "null" string from the writer's output for nullValues. - * Strictly speaking, this is not valid JSON. But when the output is being - * fed to a browser's JavaScript, it makes for smaller output and the - * browser can handle the output just fine. - * - "useSpecialFloats": false or true - * - If true, outputs non-finite floating point values in the following way: - * NaN values as "NaN", positive infinity as "Infinity", and negative - * infinity as "-Infinity". - * - "precision": int - * - Number of precision digits for formatting of real values. - * - "precisionType": "significant"(default) or "decimal" - * - Type of precision for formatting of real values. - * - "emitUTF8": false or true - * - If true, outputs raw UTF8 strings instead of escaping them. - - * You can examine 'settings_` yourself - * to see the defaults. You can also write and read them just like any - * JSON Value. - * \sa setDefaults() - */ - Json::Value settings_; - - StreamWriterBuilder(); - ~StreamWriterBuilder() override; - - /** - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - StreamWriter* newStreamWriter() const override; - - /** \return true if 'settings' are legal and consistent; - * otherwise, indicate bad settings via 'invalid'. - */ - bool validate(Json::Value* invalid) const; - /** A simple way to update a specific setting. - */ - Value& operator[](const String& key); - - /** Called by ctor, but you can use this to reset settings_. - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults - */ - static void setDefaults(Json::Value* settings); -}; - -/** \brief Abstract class for writers. - * \deprecated Use StreamWriter. (And really, this is an implementation detail.) - */ -class JSON_API Writer { -public: - virtual ~Writer(); - - virtual String write(const Value& root) = 0; -}; - -/** \brief Outputs a Value in JSON format - *without formatting (not human friendly). - * - * The JSON document is written in a single line. It is not intended for 'human' - *consumption, - * but may be useful to support feature such as RPC where bandwidth is limited. - * \sa Reader, Value - * \deprecated Use StreamWriterBuilder. - */ -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4996) // Deriving from deprecated class -#endif -class JSON_API FastWriter - : public Writer { -public: - FastWriter(); - ~FastWriter() override = default; - - void enableYAMLCompatibility(); - - /** \brief Drop the "null" string from the writer's output for nullValues. - * Strictly speaking, this is not valid JSON. But when the output is being - * fed to a browser's JavaScript, it makes for smaller output and the - * browser can handle the output just fine. - */ - void dropNullPlaceholders(); - - void omitEndingLineFeed(); - -public: // overridden from Writer - String write(const Value& root) override; - -private: - void writeValue(const Value& value); - - String document_; - bool yamlCompatibilityEnabled_{false}; - bool dropNullPlaceholders_{false}; - bool omitEndingLineFeed_{false}; -}; -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -/** \brief Writes a Value in JSON format in a - *human friendly way. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per - *line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value - *types, - * and all the values fit on one lines, then print the array on a single - *line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputted according to their - *#CommentPlacement. - * - * \sa Reader, Value, Value::setComment() - * \deprecated Use StreamWriterBuilder. - */ -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4996) // Deriving from deprecated class -#endif -class JSON_API - StyledWriter : public Writer { -public: - StyledWriter(); - ~StyledWriter() override = default; - -public: // overridden from Writer - /** \brief Serialize a Value in JSON format. - * \param root Value to serialize. - * \return String containing the JSON document that represents the root value. - */ - String write(const Value& root) override; - -private: - void writeValue(const Value& value); - void writeArrayValue(const Value& value); - bool isMultilineArray(const Value& value); - void pushValue(const String& value); - void writeIndent(); - void writeWithIndent(const String& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(const Value& root); - void writeCommentAfterValueOnSameLine(const Value& root); - static bool hasCommentForValue(const Value& value); - static String normalizeEOL(const String& text); - - using ChildValues = std::vector; - - ChildValues childValues_; - String document_; - String indentString_; - unsigned int rightMargin_{74}; - unsigned int indentSize_{3}; - bool addChildValues_{false}; -}; -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -/** \brief Writes a Value in JSON format in a - human friendly way, - to a stream rather than to a string. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per - line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value - types, - * and all the values fit on one lines, then print the array on a single - line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputted according to their - #CommentPlacement. - * - * \sa Reader, Value, Value::setComment() - * \deprecated Use StreamWriterBuilder. - */ -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4996) // Deriving from deprecated class -#endif -class JSON_API - StyledStreamWriter { -public: - /** - * \param indentation Each level will be indented by this amount extra. - */ - StyledStreamWriter(String indentation = "\t"); - ~StyledStreamWriter() = default; - -public: - /** \brief Serialize a Value in JSON format. - * \param out Stream to write to. (Can be ostringstream, e.g.) - * \param root Value to serialize. - * \note There is no point in deriving from Writer, since write() should not - * return a value. - */ - void write(OStream& out, const Value& root); - -private: - void writeValue(const Value& value); - void writeArrayValue(const Value& value); - bool isMultilineArray(const Value& value); - void pushValue(const String& value); - void writeIndent(); - void writeWithIndent(const String& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(const Value& root); - void writeCommentAfterValueOnSameLine(const Value& root); - static bool hasCommentForValue(const Value& value); - static String normalizeEOL(const String& text); - - using ChildValues = std::vector; - - ChildValues childValues_; - OStream* document_; - String indentString_; - unsigned int rightMargin_{74}; - String indentation_; - bool addChildValues_ : 1; - bool indented_ : 1; -}; -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#if defined(JSON_HAS_INT64) -String JSON_API valueToString(Int value); -String JSON_API valueToString(UInt value); -#endif // if defined(JSON_HAS_INT64) -String JSON_API valueToString(LargestInt value); -String JSON_API valueToString(LargestUInt value); -String JSON_API valueToString( - double value, unsigned int precision = Value::defaultRealPrecision, - PrecisionType precisionType = PrecisionType::significantDigits); -String JSON_API valueToString(bool value); -String JSON_API valueToQuotedString(const char* value); - -/// \brief Output using the StyledStreamWriter. -/// \see Json::operator>>() -JSON_API OStream& operator<<(OStream&, const Value& root); - -} // namespace Json - -#pragma pack(pop) - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // JSON_WRITER_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/writer.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/assertions.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_ASSERTIONS_H_INCLUDED -#define JSON_ASSERTIONS_H_INCLUDED - -#include -#include - -#if !defined(JSON_IS_AMALGAMATION) -#include "config.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -/** It should not be possible for a maliciously designed file to - * cause an abort() or seg-fault, so these macros are used only - * for pre-condition violations and internal logic errors. - */ -#if JSON_USE_EXCEPTION - -// @todo <= add detail about condition in exception -#define JSON_ASSERT(condition) \ - do { \ - if (!(condition)) { \ - Json::throwLogicError("assert json failed"); \ - } \ - } while (0) - -#define JSON_FAIL_MESSAGE(message) \ - do { \ - OStringStream oss; \ - oss << message; \ - Json::throwLogicError(oss.str()); \ - abort(); \ - } while (0) - -#else // JSON_USE_EXCEPTION - -#define JSON_ASSERT(condition) assert(condition) - -// The call to assert() will show the failure message in debug builds. In -// release builds we abort, for a core-dump or debugger. -#define JSON_FAIL_MESSAGE(message) \ - { \ - OStringStream oss; \ - oss << message; \ - assert(false && oss.str().c_str()); \ - abort(); \ - } - -#endif - -#define JSON_ASSERT_MESSAGE(condition, message) \ - do { \ - if (!(condition)) { \ - JSON_FAIL_MESSAGE(message); \ - } \ - } while (0) - -#endif // JSON_ASSERTIONS_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/assertions.h -// ////////////////////////////////////////////////////////////////////// - - - - - -#endif //ifndef JSON_AMALGAMATED_H_INCLUDED diff --git a/src/communication/pub_gps/include/pub_gps/pub_gps_node.hpp b/src/communication/pub_gps/include/pub_gps/pub_gps_node.hpp deleted file mode 100644 index c355994..0000000 --- a/src/communication/pub_gps/include/pub_gps/pub_gps_node.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __PUB_GPS_NODE_H__ -#define __PUB_GPS_NODE_H__ - -struct GPS -{ - double lng; // 经度 - double lat; // 维度 - float course; // 航向角 范围[0°, 360°],0°为正北方向,精度:0.1 - int mode; // 差分状态(定位)0:未定位 1:单点解 2:浮点解 3:固定解 -}; - -extern GPS gps_mes; - -#endif \ No newline at end of file diff --git a/src/communication/pub_gps/lib/libpaho-mqtt3c-static.a b/src/communication/pub_gps/lib/libpaho-mqtt3c-static.a deleted file mode 100644 index cbfe668bbd98960f14a5de00f1e56355eb5714a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 331658 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 B@|XYs diff --git a/src/communication/pub_gps/lib/libpaho-mqtt3c.a b/src/communication/pub_gps/lib/libpaho-mqtt3c.a deleted file mode 100644 index 9f7e1d546ea4e97802a5315594654d9253c3c74c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 362166 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 V;4*64TXPB>y4*{{k{*rA+_; diff --git a/src/communication/pub_gps/package.xml b/src/communication/pub_gps/package.xml deleted file mode 100644 index 68460d8..0000000 --- a/src/communication/pub_gps/package.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - pub_gps - 0.0.0 - TODO: Package description - zxwl - TODO: License declaration - - ament_cmake - - rclcpp - std_msgs - sweeper_interfaces - - ament_lint_auto - ament_lint_common - - - ament_cmake - - \ No newline at end of file diff --git a/src/communication/pub_gps/src/jsoncpp.cpp b/src/communication/pub_gps/src/jsoncpp.cpp deleted file mode 100644 index 89b7bc0..0000000 --- a/src/communication/pub_gps/src/jsoncpp.cpp +++ /dev/null @@ -1,5342 +0,0 @@ -/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/). -/// It is intended to be used with #include "json/json.h" - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and -The JsonCpp Authors, and is released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors - -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. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. - -*/ - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - - - - - - -#include "json.h" - -#ifndef JSON_IS_AMALGAMATION -#error "Compile with -I PATH_TO_JSON_DIRECTORY" -#endif - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED -#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include -#endif - -// Also support old flag NO_LOCALE_SUPPORT -#ifdef NO_LOCALE_SUPPORT -#define JSONCPP_NO_LOCALE_SUPPORT -#endif - -#ifndef JSONCPP_NO_LOCALE_SUPPORT -#include -#endif - -/* This header provides common string manipulation support, such as UTF-8, - * portable conversion from/to string... - * - * It is an internal header that must not be exposed. - */ - -namespace Json { -static inline char getDecimalPoint() { -#ifdef JSONCPP_NO_LOCALE_SUPPORT - return '\0'; -#else - struct lconv* lc = localeconv(); - return lc ? *(lc->decimal_point) : '\0'; -#endif -} - -/// Converts a unicode code-point to UTF-8. -static inline String codePointToUTF8(unsigned int cp) { - String result; - - // based on description from http://en.wikipedia.org/wiki/UTF-8 - - if (cp <= 0x7f) { - result.resize(1); - result[0] = static_cast(cp); - } else if (cp <= 0x7FF) { - result.resize(2); - result[1] = static_cast(0x80 | (0x3f & cp)); - result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); - } else if (cp <= 0xFFFF) { - result.resize(3); - result[2] = static_cast(0x80 | (0x3f & cp)); - result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); - } else if (cp <= 0x10FFFF) { - result.resize(4); - result[3] = static_cast(0x80 | (0x3f & cp)); - result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); - result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); - } - - return result; -} - -enum { - /// Constant that specify the size of the buffer that must be passed to - /// uintToString. - uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 -}; - -// Defines a char buffer for use with uintToString(). -using UIntToStringBuffer = char[uintToStringBufferSize]; - -/** Converts an unsigned integer to string. - * @param value Unsigned integer to convert to string - * @param current Input/Output string buffer. - * Must have at least uintToStringBufferSize chars free. - */ -static inline void uintToString(LargestUInt value, char*& current) { - *--current = 0; - do { - *--current = static_cast(value % 10U + static_cast('0')); - value /= 10; - } while (value != 0); -} - -/** Change ',' to '.' everywhere in buffer. - * - * We had a sophisticated way, but it did not work in WinCE. - * @see https://github.com/open-source-parsers/jsoncpp/pull/9 - */ -template Iter fixNumericLocale(Iter begin, Iter end) { - for (; begin != end; ++begin) { - if (*begin == ',') { - *begin = '.'; - } - } - return begin; -} - -template void fixNumericLocaleInput(Iter begin, Iter end) { - char decimalPoint = getDecimalPoint(); - if (decimalPoint == '\0' || decimalPoint == '.') { - return; - } - for (; begin != end; ++begin) { - if (*begin == '.') { - *begin = decimalPoint; - } - } -} - -/** - * Return iterator that would be the new end of the range [begin,end), if we - * were to delete zeros in the end of string, but not the last zero before '.'. - */ -template -Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) { - for (; begin != end; --end) { - if (*(end - 1) != '0') { - return end; - } - // Don't delete the last zero before the decimal point. - if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') { - if (precision) { - return end; - } - return end - 2; - } - } - return end; -} - -} // namespace Json - -#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors -// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include "json_tool.h" -#include -#include -#include -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#if __cplusplus >= 201103L - -#if !defined(sscanf) -#define sscanf std::sscanf -#endif - -#endif //__cplusplus - -#if defined(_MSC_VER) -#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES -#endif //_MSC_VER - -#if defined(_MSC_VER) -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile -// time to change the stack limit -#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) -#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 -#endif - -static size_t const stackLimit_g = - JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() - -namespace Json { - -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -using CharReaderPtr = std::unique_ptr; -#else -using CharReaderPtr = std::auto_ptr; -#endif - -// Implementation of class Features -// //////////////////////////////// - -Features::Features() = default; - -Features Features::all() { return {}; } - -Features Features::strictMode() { - Features features; - features.allowComments_ = false; - features.strictRoot_ = true; - features.allowDroppedNullPlaceholders_ = false; - features.allowNumericKeys_ = false; - return features; -} - -// Implementation of class Reader -// //////////////////////////////// - -bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { - return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); -} - -// Class Reader -// ////////////////////////////////////////////////////////////////// - -Reader::Reader() : features_(Features::all()) {} - -Reader::Reader(const Features& features) : features_(features) {} - -bool Reader::parse(const std::string& document, Value& root, - bool collectComments) { - document_.assign(document.begin(), document.end()); - const char* begin = document_.c_str(); - const char* end = begin + document_.length(); - return parse(begin, end, root, collectComments); -} - -bool Reader::parse(std::istream& is, Value& root, bool collectComments) { - // std::istream_iterator begin(is); - // std::istream_iterator end; - // Those would allow streamed input from a file, if parse() were a - // template function. - - // Since String is reference-counted, this at least does not - // create an extra copy. - String doc(std::istreambuf_iterator(is), {}); - return parse(doc.data(), doc.data() + doc.size(), root, collectComments); -} - -bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = nullptr; - lastValue_ = nullptr; - commentsBefore_.clear(); - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - bool successful = readValue(); - Token token; - skipCommentTokens(token); - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool Reader::readValue() { - // readValue() may call itself only if it calls readObject() or ReadArray(). - // These methods execute nodes_.push() just before and nodes_.pop)() just - // after calling readValue(). parse() executes one nodes_.push(), so > instead - // of >=. - if (nodes_.size() > stackLimit_g) - throwRuntimeError("Exceeded stackLimit in readValue()."); - - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_.clear(); - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenFalse: { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNull: { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // Else, fall through... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - return successful; -} - -void Reader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool Reader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - token.type_ = tokenNumber; - readNumber(); - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return ok; -} - -void Reader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -bool Reader::match(const Char* pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool Reader::readComment() { - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if (c == '*') - successful = readCStyleComment(); - else if (c == '/') - successful = readCppStyleComment(); - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (c != '*' || !containsNewLine(commentBegin, current_)) - placement = commentAfterOnSameLine; - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) { - String normalized; - normalized.reserve(static_cast(end - begin)); - Reader::Location current = begin; - while (current != end) { - char c = *current++; - if (c == '\r') { - if (current != end && *current == '\n') - // convert dos EOL - ++current; - // convert Mac EOL - normalized += '\n'; - } else { - normalized += c; - } - } - return normalized; -} - -void Reader::addComment(Location begin, Location end, - CommentPlacement placement) { - assert(collectComments_); - const String& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != nullptr); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool Reader::readCStyleComment() { - while ((current_ + 1) < end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - } - return getNextChar() == '/'; -} - -bool Reader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -void Reader::readNumber() { - Location p = current_; - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : '\0'; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } -} - -bool Reader::readString() { - Char c = '\0'; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - -bool Reader::readObject(Token& token) { - Token tokenName; - String name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object - return true; - name.clear(); - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); - } else { - break; - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover("Missing ':' after object member name", colon, - tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover("Missing ',' or '}' in object declaration", - comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover("Missing '}' or object member name", tokenName, - tokenObjectEnd); -} - -bool Reader::readArray(Token& token) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - skipSpaces(); - if (current_ != end_ && *current_ == ']') // empty array - { - Token endArray; - readToken(endArray); - return true; - } - int index = 0; - for (;;) { - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token currentToken; - // Accept Comment after last item in the array. - ok = readToken(currentToken); - while (currentToken.type_ == tokenComment && ok) { - ok = readToken(currentToken); - } - bool badTokenType = (currentToken.type_ != tokenArraySeparator && - currentToken.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover("Missing ',' or ']' in array declaration", - currentToken, tokenArrayEnd); - } - if (currentToken.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool Reader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - bool isNegative = *current == '-'; - if (isNegative) - ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of - // them. - Value::LargestUInt maxIntegerValue = - isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 - : Value::maxLargestUInt; - Value::LargestUInt threshold = maxIntegerValue / 10; - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - auto digit(static_cast(c - '0')); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, b) this is the last digit, and - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > maxIntegerValue % 10) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - if (isNegative && value == maxIntegerValue) - decoded = Value::minLargestInt; - else if (isNegative) - decoded = -Value::LargestInt(value); - else if (value <= Value::LargestUInt(Value::maxInt)) - decoded = Value::LargestInt(value); - else - decoded = value; - return true; -} - -bool Reader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - String buffer(token.start_, token.end_); - IStringStream is(buffer); - if (!(is >> value)) { - if (value == std::numeric_limits::max()) - value = std::numeric_limits::infinity(); - else if (value == std::numeric_limits::lowest()) - value = -std::numeric_limits::infinity(); - else if (!std::isinf(value)) - return addError( - "'" + String(token.start_, token.end_) + "' is not a number.", token); - } - decoded = value; - return true; -} - -bool Reader::decodeString(Token& token) { - String decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeString(Token& token, String& decoded) { - decoded.reserve(static_cast(token.end_ - token.start_ - 2)); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool Reader::decodeUnicodeCodePoint(Token& token, Location& current, - Location end, unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, current); - if (*(current++) == '\\' && *(current++) == 'u') { - unsigned int surrogatePair; - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, current); - } - return true; -} - -bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current, - Location end, - unsigned int& ret_unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", token, - current); - int unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, current); - } - ret_unicode = static_cast(unicode); - return true; -} - -bool Reader::addError(const String& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool Reader::recoverFromError(TokenType skipUntilToken) { - size_t const errorCount = errors_.size(); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool Reader::addErrorAndRecover(const String& message, Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& Reader::currentValue() { return *(nodes_.top()); } - -Reader::Char Reader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void Reader::getLocationLineAndColumn(Location location, int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -String Reader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; - jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); - return buffer; -} - -// Deprecated. Preserved for backward compatibility -String Reader::getFormatedErrorMessages() const { - return getFormattedErrorMessages(); -} - -String Reader::getFormattedErrorMessages() const { - String formattedMessage; - for (const auto& error : errors_) { - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector Reader::getStructuredErrors() const { - std::vector allErrors; - for (const auto& error : errors_) { - Reader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -bool Reader::pushError(const Value& value, const String& message) { - ptrdiff_t const length = end_ - begin_; - if (value.getOffsetStart() > length || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = nullptr; - errors_.push_back(info); - return true; -} - -bool Reader::pushError(const Value& value, const String& message, - const Value& extra) { - ptrdiff_t const length = end_ - begin_; - if (value.getOffsetStart() > length || value.getOffsetLimit() > length || - extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool Reader::good() const { return errors_.empty(); } - -// Originally copied from the Features class (now deprecated), used internally -// for features implementation. -class OurFeatures { -public: - static OurFeatures all(); - bool allowComments_; - bool allowTrailingCommas_; - bool strictRoot_; - bool allowDroppedNullPlaceholders_; - bool allowNumericKeys_; - bool allowSingleQuotes_; - bool failIfExtra_; - bool rejectDupKeys_; - bool allowSpecialFloats_; - bool skipBom_; - size_t stackLimit_; -}; // OurFeatures - -OurFeatures OurFeatures::all() { return {}; } - -// Implementation of class Reader -// //////////////////////////////// - -// Originally copied from the Reader class (now deprecated), used internally -// for implementing JSON reading. -class OurReader { -public: - using Char = char; - using Location = const Char*; - struct StructuredError { - ptrdiff_t offset_start; - ptrdiff_t offset_limit; - String message; - }; - - explicit OurReader(OurFeatures const& features); - bool parse(const char* beginDoc, const char* endDoc, Value& root, - bool collectComments = true); - String getFormattedErrorMessages() const; - std::vector getStructuredErrors() const; - -private: - OurReader(OurReader const&); // no impl - void operator=(OurReader const&); // no impl - - enum TokenType { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenNaN, - tokenPosInf, - tokenNegInf, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo { - public: - Token token_; - String message_; - Location extra_; - }; - - using Errors = std::deque; - - bool readToken(Token& token); - void skipSpaces(); - void skipBom(bool skipBom); - bool match(const Char* pattern, int patternLength); - bool readComment(); - bool readCStyleComment(bool* containsNewLineResult); - bool readCppStyleComment(); - bool readString(); - bool readStringSingleQuote(); - bool readNumber(bool checkInf); - bool readValue(); - bool readObject(Token& token); - bool readArray(Token& token); - bool decodeNumber(Token& token); - bool decodeNumber(Token& token, Value& decoded); - bool decodeString(Token& token); - bool decodeString(Token& token, String& decoded); - bool decodeDouble(Token& token); - bool decodeDouble(Token& token, Value& decoded); - bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, - unsigned int& unicode); - bool decodeUnicodeEscapeSequence(Token& token, Location& current, - Location end, unsigned int& unicode); - bool addError(const String& message, Token& token, Location extra = nullptr); - bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const String& message, Token& token, - TokenType skipUntilToken); - void skipUntilSpace(); - Value& currentValue(); - Char getNextChar(); - void getLocationLineAndColumn(Location location, int& line, - int& column) const; - String getLocationLineAndColumn(Location location) const; - void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); - - static String normalizeEOL(Location begin, Location end); - static bool containsNewLine(Location begin, Location end); - - using Nodes = std::stack; - - Nodes nodes_{}; - Errors errors_{}; - String document_{}; - Location begin_ = nullptr; - Location end_ = nullptr; - Location current_ = nullptr; - Location lastValueEnd_ = nullptr; - Value* lastValue_ = nullptr; - bool lastValueHasAComment_ = false; - String commentsBefore_{}; - - OurFeatures const features_; - bool collectComments_ = false; -}; // OurReader - -// complete copy of Read impl, for OurReader - -bool OurReader::containsNewLine(OurReader::Location begin, - OurReader::Location end) { - return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); -} - -OurReader::OurReader(OurFeatures const& features) : features_(features) {} - -bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = nullptr; - lastValue_ = nullptr; - commentsBefore_.clear(); - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - // skip byte order mark if it exists at the beginning of the UTF-8 text. - skipBom(features_.skipBom_); - bool successful = readValue(); - nodes_.pop(); - Token token; - skipCommentTokens(token); - if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) { - addError("Extra non-whitespace after JSON value.", token); - return false; - } - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool OurReader::readValue() { - // To preserve the old behaviour we cast size_t to int. - if (nodes_.size() > features_.stackLimit_) - throwRuntimeError("Exceeded stackLimit in readValue()."); - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_.clear(); - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenFalse: { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNull: { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNaN: { - Value v(std::numeric_limits::quiet_NaN()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenPosInf: { - Value v(std::numeric_limits::infinity()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNegInf: { - Value v(-std::numeric_limits::infinity()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // else, fall through ... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValueHasAComment_ = false; - lastValue_ = ¤tValue(); - } - - return successful; -} - -void OurReader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool OurReader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '\'': - if (features_.allowSingleQuotes_) { - token.type_ = tokenString; - ok = readStringSingleQuote(); - } else { - // If we don't allow single quotes, this is a failure case. - ok = false; - } - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - token.type_ = tokenNumber; - readNumber(false); - break; - case '-': - if (readNumber(true)) { - token.type_ = tokenNumber; - } else { - token.type_ = tokenNegInf; - ok = features_.allowSpecialFloats_ && match("nfinity", 7); - } - break; - case '+': - if (readNumber(true)) { - token.type_ = tokenNumber; - } else { - token.type_ = tokenPosInf; - ok = features_.allowSpecialFloats_ && match("nfinity", 7); - } - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case 'N': - if (features_.allowSpecialFloats_) { - token.type_ = tokenNaN; - ok = match("aN", 2); - } else { - ok = false; - } - break; - case 'I': - if (features_.allowSpecialFloats_) { - token.type_ = tokenPosInf; - ok = match("nfinity", 7); - } else { - ok = false; - } - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return ok; -} - -void OurReader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -void OurReader::skipBom(bool skipBom) { - // The default behavior is to skip BOM. - if (skipBom) { - if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) { - begin_ += 3; - current_ = begin_; - } - } -} - -bool OurReader::match(const Char* pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool OurReader::readComment() { - const Location commentBegin = current_ - 1; - const Char c = getNextChar(); - bool successful = false; - bool cStyleWithEmbeddedNewline = false; - - const bool isCStyleComment = (c == '*'); - const bool isCppStyleComment = (c == '/'); - if (isCStyleComment) { - successful = readCStyleComment(&cStyleWithEmbeddedNewline); - } else if (isCppStyleComment) { - successful = readCppStyleComment(); - } - - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - - if (!lastValueHasAComment_) { - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (isCppStyleComment || !cStyleWithEmbeddedNewline) { - placement = commentAfterOnSameLine; - lastValueHasAComment_ = true; - } - } - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -String OurReader::normalizeEOL(OurReader::Location begin, - OurReader::Location end) { - String normalized; - normalized.reserve(static_cast(end - begin)); - OurReader::Location current = begin; - while (current != end) { - char c = *current++; - if (c == '\r') { - if (current != end && *current == '\n') - // convert dos EOL - ++current; - // convert Mac EOL - normalized += '\n'; - } else { - normalized += c; - } - } - return normalized; -} - -void OurReader::addComment(Location begin, Location end, - CommentPlacement placement) { - assert(collectComments_); - const String& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != nullptr); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool OurReader::readCStyleComment(bool* containsNewLineResult) { - *containsNewLineResult = false; - - while ((current_ + 1) < end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - if (c == '\n') - *containsNewLineResult = true; - } - - return getNextChar() == '/'; -} - -bool OurReader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -bool OurReader::readNumber(bool checkInf) { - Location p = current_; - if (checkInf && p != end_ && *p == 'I') { - current_ = ++p; - return false; - } - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : '\0'; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - return true; -} -bool OurReader::readString() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - -bool OurReader::readStringSingleQuote() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '\'') - break; - } - return c == '\''; -} - -bool OurReader::readObject(Token& token) { - Token tokenName; - String name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && - (name.empty() || - features_.allowTrailingCommas_)) // empty object or trailing comma - return true; - name.clear(); - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); - } else { - break; - } - if (name.length() >= (1U << 30)) - throwRuntimeError("keylength >= 2^30"); - if (features_.rejectDupKeys_ && currentValue().isMember(name)) { - String msg = "Duplicate key: '" + name + "'"; - return addErrorAndRecover(msg, tokenName, tokenObjectEnd); - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover("Missing ':' after object member name", colon, - tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover("Missing ',' or '}' in object declaration", - comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover("Missing '}' or object member name", tokenName, - tokenObjectEnd); -} - -bool OurReader::readArray(Token& token) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - int index = 0; - for (;;) { - skipSpaces(); - if (current_ != end_ && *current_ == ']' && - (index == 0 || - (features_.allowTrailingCommas_ && - !features_.allowDroppedNullPlaceholders_))) // empty array or trailing - // comma - { - Token endArray; - readToken(endArray); - return true; - } - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token currentToken; - // Accept Comment after last item in the array. - ok = readToken(currentToken); - while (currentToken.type_ == tokenComment && ok) { - ok = readToken(currentToken); - } - bool badTokenType = (currentToken.type_ != tokenArraySeparator && - currentToken.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover("Missing ',' or ']' in array declaration", - currentToken, tokenArrayEnd); - } - if (currentToken.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool OurReader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - const bool isNegative = *current == '-'; - if (isNegative) { - ++current; - } - - // We assume we can represent the largest and smallest integer types as - // unsigned integers with separate sign. This is only true if they can fit - // into an unsigned integer. - static_assert(Value::maxLargestInt <= Value::maxLargestUInt, - "Int must be smaller than UInt"); - - // We need to convert minLargestInt into a positive number. The easiest way - // to do this conversion is to assume our "threshold" value of minLargestInt - // divided by 10 can fit in maxLargestInt when absolute valued. This should - // be a safe assumption. - static_assert(Value::minLargestInt <= -Value::maxLargestInt, - "The absolute value of minLargestInt must be greater than or " - "equal to maxLargestInt"); - static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt, - "The absolute value of minLargestInt must be only 1 magnitude " - "larger than maxLargest Int"); - - static constexpr Value::LargestUInt positive_threshold = - Value::maxLargestUInt / 10; - static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10; - - // For the negative values, we have to be more careful. Since typically - // -Value::minLargestInt will cause an overflow, we first divide by 10 and - // then take the inverse. This assumes that minLargestInt is only a single - // power of 10 different in magnitude, which we check above. For the last - // digit, we take the modulus before negating for the same reason. - static constexpr auto negative_threshold = - Value::LargestUInt(-(Value::minLargestInt / 10)); - static constexpr auto negative_last_digit = - Value::UInt(-(Value::minLargestInt % 10)); - - const Value::LargestUInt threshold = - isNegative ? negative_threshold : positive_threshold; - const Value::UInt max_last_digit = - isNegative ? negative_last_digit : positive_last_digit; - - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - - const auto digit(static_cast(c - '0')); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, meaning value == threshold, - // b) this is the last digit, or - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > max_last_digit) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - - if (isNegative) { - // We use the same magnitude assumption here, just in case. - const auto last_digit = static_cast(value % 10); - decoded = -Value::LargestInt(value / 10) * 10 - last_digit; - } else if (value <= Value::LargestUInt(Value::maxLargestInt)) { - decoded = Value::LargestInt(value); - } else { - decoded = value; - } - - return true; -} - -bool OurReader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - const String buffer(token.start_, token.end_); - IStringStream is(buffer); - if (!(is >> value)) { - if (value == std::numeric_limits::max()) - value = std::numeric_limits::infinity(); - else if (value == std::numeric_limits::lowest()) - value = -std::numeric_limits::infinity(); - else if (!std::isinf(value)) - return addError( - "'" + String(token.start_, token.end_) + "' is not a number.", token); - } - decoded = value; - return true; -} - -bool OurReader::decodeString(Token& token) { - String decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeString(Token& token, String& decoded) { - decoded.reserve(static_cast(token.end_ - token.start_ - 2)); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current, - Location end, unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, current); - if (*(current++) == '\\' && *(current++) == 'u') { - unsigned int surrogatePair; - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, current); - } - return true; -} - -bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current, - Location end, - unsigned int& ret_unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", token, - current); - int unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, current); - } - ret_unicode = static_cast(unicode); - return true; -} - -bool OurReader::addError(const String& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool OurReader::recoverFromError(TokenType skipUntilToken) { - size_t errorCount = errors_.size(); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool OurReader::addErrorAndRecover(const String& message, Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& OurReader::currentValue() { return *(nodes_.top()); } - -OurReader::Char OurReader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void OurReader::getLocationLineAndColumn(Location location, int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -String OurReader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; - jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); - return buffer; -} - -String OurReader::getFormattedErrorMessages() const { - String formattedMessage; - for (const auto& error : errors_) { - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector OurReader::getStructuredErrors() const { - std::vector allErrors; - for (const auto& error : errors_) { - OurReader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -class OurCharReader : public CharReader { - bool const collectComments_; - OurReader reader_; - -public: - OurCharReader(bool collectComments, OurFeatures const& features) - : collectComments_(collectComments), reader_(features) {} - bool parse(char const* beginDoc, char const* endDoc, Value* root, - String* errs) override { - bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); - if (errs) { - *errs = reader_.getFormattedErrorMessages(); - } - return ok; - } -}; - -CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } -CharReaderBuilder::~CharReaderBuilder() = default; -CharReader* CharReaderBuilder::newCharReader() const { - bool collectComments = settings_["collectComments"].asBool(); - OurFeatures features = OurFeatures::all(); - features.allowComments_ = settings_["allowComments"].asBool(); - features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool(); - features.strictRoot_ = settings_["strictRoot"].asBool(); - features.allowDroppedNullPlaceholders_ = - settings_["allowDroppedNullPlaceholders"].asBool(); - features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); - features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); - - // Stack limit is always a size_t, so we get this as an unsigned int - // regardless of it we have 64-bit integer support enabled. - features.stackLimit_ = static_cast(settings_["stackLimit"].asUInt()); - features.failIfExtra_ = settings_["failIfExtra"].asBool(); - features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); - features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); - features.skipBom_ = settings_["skipBom"].asBool(); - return new OurCharReader(collectComments, features); -} - -bool CharReaderBuilder::validate(Json::Value* invalid) const { - static const auto& valid_keys = *new std::set{ - "collectComments", - "allowComments", - "allowTrailingCommas", - "strictRoot", - "allowDroppedNullPlaceholders", - "allowNumericKeys", - "allowSingleQuotes", - "stackLimit", - "failIfExtra", - "rejectDupKeys", - "allowSpecialFloats", - "skipBom", - }; - for (auto si = settings_.begin(); si != settings_.end(); ++si) { - auto key = si.name(); - if (valid_keys.count(key)) - continue; - if (invalid) - (*invalid)[key] = *si; - else - return false; - } - return invalid ? invalid->empty() : true; -} - -Value& CharReaderBuilder::operator[](const String& key) { - return settings_[key]; -} -// static -void CharReaderBuilder::strictMode(Json::Value* settings) { - //! [CharReaderBuilderStrictMode] - (*settings)["allowComments"] = false; - (*settings)["allowTrailingCommas"] = false; - (*settings)["strictRoot"] = true; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; - (*settings)["failIfExtra"] = true; - (*settings)["rejectDupKeys"] = true; - (*settings)["allowSpecialFloats"] = false; - (*settings)["skipBom"] = true; - //! [CharReaderBuilderStrictMode] -} -// static -void CharReaderBuilder::setDefaults(Json::Value* settings) { - //! [CharReaderBuilderDefaults] - (*settings)["collectComments"] = true; - (*settings)["allowComments"] = true; - (*settings)["allowTrailingCommas"] = true; - (*settings)["strictRoot"] = false; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; - (*settings)["failIfExtra"] = false; - (*settings)["rejectDupKeys"] = false; - (*settings)["allowSpecialFloats"] = false; - (*settings)["skipBom"] = true; - //! [CharReaderBuilderDefaults] -} - -////////////////////////////////// -// global functions - -bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root, - String* errs) { - OStringStream ssin; - ssin << sin.rdbuf(); - String doc = ssin.str(); - char const* begin = doc.data(); - char const* end = begin + doc.size(); - // Note that we do not actually need a null-terminator. - CharReaderPtr const reader(fact.newCharReader()); - return reader->parse(begin, end, root, errs); -} - -IStream& operator>>(IStream& sin, Value& root) { - CharReaderBuilder b; - String errs; - bool ok = parseFromStream(b, sin, &root, &errs); - if (!ok) { - throwRuntimeError(errs); - } - return sin; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -// included by json_value.cpp - -namespace Json { - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIteratorBase -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIteratorBase::ValueIteratorBase() : current_() {} - -ValueIteratorBase::ValueIteratorBase( - const Value::ObjectValues::iterator& current) - : current_(current), isNull_(false) {} - -Value& ValueIteratorBase::deref() { return current_->second; } -const Value& ValueIteratorBase::deref() const { return current_->second; } - -void ValueIteratorBase::increment() { ++current_; } - -void ValueIteratorBase::decrement() { --current_; } - -ValueIteratorBase::difference_type -ValueIteratorBase::computeDistance(const SelfType& other) const { - // Iterator for null value are initialized using the default - // constructor, which initialize current_ to the default - // std::map::iterator. As begin() and end() are two instance - // of the default std::map::iterator, they can not be compared. - // To allow this, we handle this comparison specifically. - if (isNull_ && other.isNull_) { - return 0; - } - - // Usage of std::distance is not portable (does not compile with Sun Studio 12 - // RogueWave STL, - // which is the one used by default). - // Using a portable hand-made version for non random iterator instead: - // return difference_type( std::distance( current_, other.current_ ) ); - difference_type myDistance = 0; - for (Value::ObjectValues::iterator it = current_; it != other.current_; - ++it) { - ++myDistance; - } - return myDistance; -} - -bool ValueIteratorBase::isEqual(const SelfType& other) const { - if (isNull_) { - return other.isNull_; - } - return current_ == other.current_; -} - -void ValueIteratorBase::copy(const SelfType& other) { - current_ = other.current_; - isNull_ = other.isNull_; -} - -Value ValueIteratorBase::key() const { - const Value::CZString czstring = (*current_).first; - if (czstring.data()) { - if (czstring.isStaticString()) - return Value(StaticString(czstring.data())); - return Value(czstring.data(), czstring.data() + czstring.length()); - } - return Value(czstring.index()); -} - -UInt ValueIteratorBase::index() const { - const Value::CZString czstring = (*current_).first; - if (!czstring.data()) - return czstring.index(); - return Value::UInt(-1); -} - -String ValueIteratorBase::name() const { - char const* keey; - char const* end; - keey = memberName(&end); - if (!keey) - return String(); - return String(keey, end); -} - -char const* ValueIteratorBase::memberName() const { - const char* cname = (*current_).first.data(); - return cname ? cname : ""; -} - -char const* ValueIteratorBase::memberName(char const** end) const { - const char* cname = (*current_).first.data(); - if (!cname) { - *end = nullptr; - return nullptr; - } - *end = cname + (*current_).first.length(); - return cname; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueConstIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueConstIterator::ValueConstIterator() = default; - -ValueConstIterator::ValueConstIterator( - const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueConstIterator::ValueConstIterator(ValueIterator const& other) - : ValueIteratorBase(other) {} - -ValueConstIterator& ValueConstIterator:: -operator=(const ValueIteratorBase& other) { - copy(other); - return *this; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIterator::ValueIterator() = default; - -ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueIterator::ValueIterator(const ValueConstIterator& other) - : ValueIteratorBase(other) { - throwRuntimeError("ConstIterator to Iterator should never be allowed."); -} - -ValueIterator::ValueIterator(const ValueIterator& other) = default; - -ValueIterator& ValueIterator::operator=(const SelfType& other) { - copy(other); - return *this; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include - -// Provide implementation equivalent of std::snprintf for older _MSC compilers -#if defined(_MSC_VER) && _MSC_VER < 1900 -#include -static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size, - const char* format, va_list ap) { - int count = -1; - if (size != 0) - count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); - if (count == -1) - count = _vscprintf(format, ap); - return count; -} - -int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size, - const char* format, ...) { - va_list ap; - va_start(ap, format); - const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap); - va_end(ap); - return count; -} -#endif - -// Disable warning C4702 : unreachable code -#if defined(_MSC_VER) -#pragma warning(disable : 4702) -#endif - -#define JSON_ASSERT_UNREACHABLE assert(false) - -namespace Json { -template -static std::unique_ptr cloneUnique(const std::unique_ptr& p) { - std::unique_ptr r; - if (p) { - r = std::unique_ptr(new T(*p)); - } - return r; -} - -// This is a walkaround to avoid the static initialization of Value::null. -// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of -// 8 (instead of 4) as a bit of future-proofing. -#if defined(__ARMEL__) -#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) -#else -#define ALIGNAS(byte_alignment) -#endif - -// static -Value const& Value::nullSingleton() { - static Value const nullStatic; - return nullStatic; -} - -#if JSON_USE_NULLREF -// for backwards compatibility, we'll leave these global references around, but -// DO NOT use them in JSONCPP library code any more! -// static -Value const& Value::null = Value::nullSingleton(); - -// static -Value const& Value::nullRef = Value::nullSingleton(); -#endif - -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -template -static inline bool InRange(double d, T min, U max) { - // The casts can lose precision, but we are looking only for - // an approximate range. Might fail on edge cases though. ~cdunn - return d >= static_cast(min) && d <= static_cast(max); -} -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -static inline double integerToDouble(Json::UInt64 value) { - return static_cast(Int64(value / 2)) * 2.0 + - static_cast(Int64(value & 1)); -} - -template static inline double integerToDouble(T value) { - return static_cast(value); -} - -template -static inline bool InRange(double d, T min, U max) { - return d >= integerToDouble(min) && d <= integerToDouble(max); -} -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - -/** Duplicates the specified string value. - * @param value Pointer to the string to duplicate. Must be zero-terminated if - * length is "unknown". - * @param length Length of the value. if equals to unknown, then it will be - * computed using strlen(value). - * @return Pointer on the duplicate instance of string. - */ -static inline char* duplicateStringValue(const char* value, size_t length) { - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - if (length >= static_cast(Value::maxInt)) - length = Value::maxInt - 1; - - auto newString = static_cast(malloc(length + 1)); - if (newString == nullptr) { - throwRuntimeError("in Json::Value::duplicateStringValue(): " - "Failed to allocate string value buffer"); - } - memcpy(newString, value, length); - newString[length] = 0; - return newString; -} - -/* Record the length as a prefix. - */ -static inline char* duplicateAndPrefixStringValue(const char* value, - unsigned int length) { - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - - sizeof(unsigned) - 1U, - "in Json::Value::duplicateAndPrefixStringValue(): " - "length too big for prefixing"); - size_t actualLength = sizeof(length) + length + 1; - auto newString = static_cast(malloc(actualLength)); - if (newString == nullptr) { - throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " - "Failed to allocate string value buffer"); - } - *reinterpret_cast(newString) = length; - memcpy(newString + sizeof(unsigned), value, length); - newString[actualLength - 1U] = - 0; // to avoid buffer over-run accidents by users later - return newString; -} -inline static void decodePrefixedString(bool isPrefixed, char const* prefixed, - unsigned* length, char const** value) { - if (!isPrefixed) { - *length = static_cast(strlen(prefixed)); - *value = prefixed; - } else { - *length = *reinterpret_cast(prefixed); - *value = prefixed + sizeof(unsigned); - } -} -/** Free the string duplicated by - * duplicateStringValue()/duplicateAndPrefixStringValue(). - */ -#if JSONCPP_USING_SECURE_MEMORY -static inline void releasePrefixedStringValue(char* value) { - unsigned length = 0; - char const* valueDecoded; - decodePrefixedString(true, value, &length, &valueDecoded); - size_t const size = sizeof(unsigned) + length + 1U; - memset(value, 0, size); - free(value); -} -static inline void releaseStringValue(char* value, unsigned length) { - // length==0 => we allocated the strings memory - size_t size = (length == 0) ? strlen(value) : length; - memset(value, 0, size); - free(value); -} -#else // !JSONCPP_USING_SECURE_MEMORY -static inline void releasePrefixedStringValue(char* value) { free(value); } -static inline void releaseStringValue(char* value, unsigned) { free(value); } -#endif // JSONCPP_USING_SECURE_MEMORY - -} // namespace Json - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ValueInternals... -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -#if !defined(JSON_IS_AMALGAMATION) - -#include "json_valueiterator.inl" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -#if JSON_USE_EXCEPTION -Exception::Exception(String msg) : msg_(std::move(msg)) {} -Exception::~Exception() noexcept = default; -char const* Exception::what() const noexcept { return msg_.c_str(); } -RuntimeError::RuntimeError(String const& msg) : Exception(msg) {} -LogicError::LogicError(String const& msg) : Exception(msg) {} -JSONCPP_NORETURN void throwRuntimeError(String const& msg) { - throw RuntimeError(msg); -} -JSONCPP_NORETURN void throwLogicError(String const& msg) { - throw LogicError(msg); -} -#else // !JSON_USE_EXCEPTION -JSONCPP_NORETURN void throwRuntimeError(String const& msg) { - std::cerr << msg << std::endl; - abort(); -} -JSONCPP_NORETURN void throwLogicError(String const& msg) { - std::cerr << msg << std::endl; - abort(); -} -#endif - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CZString -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -// Notes: policy_ indicates if the string was allocated when -// a string is stored. - -Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {} - -Value::CZString::CZString(char const* str, unsigned length, - DuplicationPolicy allocate) - : cstr_(str) { - // allocate != duplicate - storage_.policy_ = allocate & 0x3; - storage_.length_ = length & 0x3FFFFFFF; -} - -Value::CZString::CZString(const CZString& other) { - cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr - ? duplicateStringValue(other.cstr_, other.storage_.length_) - : other.cstr_); - storage_.policy_ = - static_cast( - other.cstr_ - ? (static_cast(other.storage_.policy_) == - noDuplication - ? noDuplication - : duplicate) - : static_cast(other.storage_.policy_)) & - 3U; - storage_.length_ = other.storage_.length_; -} - -Value::CZString::CZString(CZString&& other) noexcept - : cstr_(other.cstr_), index_(other.index_) { - other.cstr_ = nullptr; -} - -Value::CZString::~CZString() { - if (cstr_ && storage_.policy_ == duplicate) { - releaseStringValue(const_cast(cstr_), - storage_.length_ + 1U); // +1 for null terminating - // character for sake of - // completeness but not actually - // necessary - } -} - -void Value::CZString::swap(CZString& other) { - std::swap(cstr_, other.cstr_); - std::swap(index_, other.index_); -} - -Value::CZString& Value::CZString::operator=(const CZString& other) { - cstr_ = other.cstr_; - index_ = other.index_; - return *this; -} - -Value::CZString& Value::CZString::operator=(CZString&& other) noexcept { - cstr_ = other.cstr_; - index_ = other.index_; - other.cstr_ = nullptr; - return *this; -} - -bool Value::CZString::operator<(const CZString& other) const { - if (!cstr_) - return index_ < other.index_; - // return strcmp(cstr_, other.cstr_) < 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - unsigned min_len = std::min(this_len, other_len); - JSON_ASSERT(this->cstr_ && other.cstr_); - int comp = memcmp(this->cstr_, other.cstr_, min_len); - if (comp < 0) - return true; - if (comp > 0) - return false; - return (this_len < other_len); -} - -bool Value::CZString::operator==(const CZString& other) const { - if (!cstr_) - return index_ == other.index_; - // return strcmp(cstr_, other.cstr_) == 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - if (this_len != other_len) - return false; - JSON_ASSERT(this->cstr_ && other.cstr_); - int comp = memcmp(this->cstr_, other.cstr_, this_len); - return comp == 0; -} - -ArrayIndex Value::CZString::index() const { return index_; } - -// const char* Value::CZString::c_str() const { return cstr_; } -const char* Value::CZString::data() const { return cstr_; } -unsigned Value::CZString::length() const { return storage_.length_; } -bool Value::CZString::isStaticString() const { - return storage_.policy_ == noDuplication; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::Value -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -/*! \internal Default constructor initialization must be equivalent to: - * memset( this, 0, sizeof(Value) ) - * This optimization is used in ValueInternalMap fast allocator. - */ -Value::Value(ValueType type) { - static char const emptyString[] = ""; - initBasic(type); - switch (type) { - case nullValue: - break; - case intValue: - case uintValue: - value_.int_ = 0; - break; - case realValue: - value_.real_ = 0.0; - break; - case stringValue: - // allocated_ == false, so this is safe. - value_.string_ = const_cast(static_cast(emptyString)); - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(); - break; - case booleanValue: - value_.bool_ = false; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -Value::Value(Int value) { - initBasic(intValue); - value_.int_ = value; -} - -Value::Value(UInt value) { - initBasic(uintValue); - value_.uint_ = value; -} -#if defined(JSON_HAS_INT64) -Value::Value(Int64 value) { - initBasic(intValue); - value_.int_ = value; -} -Value::Value(UInt64 value) { - initBasic(uintValue); - value_.uint_ = value; -} -#endif // defined(JSON_HAS_INT64) - -Value::Value(double value) { - initBasic(realValue); - value_.real_ = value; -} - -Value::Value(const char* value) { - initBasic(stringValue, true); - JSON_ASSERT_MESSAGE(value != nullptr, - "Null Value Passed to Value Constructor"); - value_.string_ = duplicateAndPrefixStringValue( - value, static_cast(strlen(value))); -} - -Value::Value(const char* begin, const char* end) { - initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(begin, static_cast(end - begin)); -} - -Value::Value(const String& value) { - initBasic(stringValue, true); - value_.string_ = duplicateAndPrefixStringValue( - value.data(), static_cast(value.length())); -} - -Value::Value(const StaticString& value) { - initBasic(stringValue); - value_.string_ = const_cast(value.c_str()); -} - -Value::Value(bool value) { - initBasic(booleanValue); - value_.bool_ = value; -} - -Value::Value(const Value& other) { - dupPayload(other); - dupMeta(other); -} - -Value::Value(Value&& other) noexcept { - initBasic(nullValue); - swap(other); -} - -Value::~Value() { - releasePayload(); - value_.uint_ = 0; -} - -Value& Value::operator=(const Value& other) { - Value(other).swap(*this); - return *this; -} - -Value& Value::operator=(Value&& other) noexcept { - other.swap(*this); - return *this; -} - -void Value::swapPayload(Value& other) { - std::swap(bits_, other.bits_); - std::swap(value_, other.value_); -} - -void Value::copyPayload(const Value& other) { - releasePayload(); - dupPayload(other); -} - -void Value::swap(Value& other) { - swapPayload(other); - std::swap(comments_, other.comments_); - std::swap(start_, other.start_); - std::swap(limit_, other.limit_); -} - -void Value::copy(const Value& other) { - copyPayload(other); - dupMeta(other); -} - -ValueType Value::type() const { - return static_cast(bits_.value_type_); -} - -int Value::compare(const Value& other) const { - if (*this < other) - return -1; - if (*this > other) - return 1; - return 0; -} - -bool Value::operator<(const Value& other) const { - int typeDelta = type() - other.type(); - if (typeDelta) - return typeDelta < 0; - switch (type()) { - case nullValue: - return false; - case intValue: - return value_.int_ < other.value_.int_; - case uintValue: - return value_.uint_ < other.value_.uint_; - case realValue: - return value_.real_ < other.value_.real_; - case booleanValue: - return value_.bool_ < other.value_.bool_; - case stringValue: { - if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { - return other.value_.string_ != nullptr; - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, - &other_str); - unsigned min_len = std::min(this_len, other_len); - JSON_ASSERT(this_str && other_str); - int comp = memcmp(this_str, other_str, min_len); - if (comp < 0) - return true; - if (comp > 0) - return false; - return (this_len < other_len); - } - case arrayValue: - case objectValue: { - auto thisSize = value_.map_->size(); - auto otherSize = other.value_.map_->size(); - if (thisSize != otherSize) - return thisSize < otherSize; - return (*value_.map_) < (*other.value_.map_); - } - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator<=(const Value& other) const { return !(other < *this); } - -bool Value::operator>=(const Value& other) const { return !(*this < other); } - -bool Value::operator>(const Value& other) const { return other < *this; } - -bool Value::operator==(const Value& other) const { - if (type() != other.type()) - return false; - switch (type()) { - case nullValue: - return true; - case intValue: - return value_.int_ == other.value_.int_; - case uintValue: - return value_.uint_ == other.value_.uint_; - case realValue: - return value_.real_ == other.value_.real_; - case booleanValue: - return value_.bool_ == other.value_.bool_; - case stringValue: { - if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { - return (value_.string_ == other.value_.string_); - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, - &other_str); - if (this_len != other_len) - return false; - JSON_ASSERT(this_str && other_str); - int comp = memcmp(this_str, other_str, this_len); - return comp == 0; - } - case arrayValue: - case objectValue: - return value_.map_->size() == other.value_.map_->size() && - (*value_.map_) == (*other.value_.map_); - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator!=(const Value& other) const { return !(*this == other); } - -const char* Value::asCString() const { - JSON_ASSERT_MESSAGE(type() == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == nullptr) - return nullptr; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - return this_str; -} - -#if JSONCPP_USING_SECURE_MEMORY -unsigned Value::getCStringLength() const { - JSON_ASSERT_MESSAGE(type() == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == 0) - return 0; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - return this_len; -} -#endif - -bool Value::getString(char const** begin, char const** end) const { - if (type() != stringValue) - return false; - if (value_.string_ == nullptr) - return false; - unsigned length; - decodePrefixedString(this->isAllocated(), this->value_.string_, &length, - begin); - *end = *begin + length; - return true; -} - -String Value::asString() const { - switch (type()) { - case nullValue: - return ""; - case stringValue: { - if (value_.string_ == nullptr) - return ""; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - return String(this_str, this_len); - } - case booleanValue: - return value_.bool_ ? "true" : "false"; - case intValue: - return valueToString(value_.int_); - case uintValue: - return valueToString(value_.uint_); - case realValue: - return valueToString(value_.real_); - default: - JSON_FAIL_MESSAGE("Type is not convertible to string"); - } -} - -Value::Int Value::asInt() const { - switch (type()) { - case intValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); - return Int(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); - return Int(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), - "double out of Int range"); - return Int(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int."); -} - -Value::UInt Value::asUInt() const { - switch (type()) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); - return UInt(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); - return UInt(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), - "double out of UInt range"); - return UInt(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt."); -} - -#if defined(JSON_HAS_INT64) - -Value::Int64 Value::asInt64() const { - switch (type()) { - case intValue: - return Int64(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); - return Int64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), - "double out of Int64 range"); - return Int64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int64."); -} - -Value::UInt64 Value::asUInt64() const { - switch (type()) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); - return UInt64(value_.int_); - case uintValue: - return UInt64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), - "double out of UInt64 range"); - return UInt64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); -} -#endif // if defined(JSON_HAS_INT64) - -LargestInt Value::asLargestInt() const { -#if defined(JSON_NO_INT64) - return asInt(); -#else - return asInt64(); -#endif -} - -LargestUInt Value::asLargestUInt() const { -#if defined(JSON_NO_INT64) - return asUInt(); -#else - return asUInt64(); -#endif -} - -double Value::asDouble() const { - switch (type()) { - case intValue: - return static_cast(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return integerToDouble(value_.uint_); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return value_.real_; - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0 : 0.0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to double."); -} - -float Value::asFloat() const { - switch (type()) { - case intValue: - return static_cast(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - // This can fail (silently?) if the value is bigger than MAX_FLOAT. - return static_cast(integerToDouble(value_.uint_)); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return static_cast(value_.real_); - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0F : 0.0F; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to float."); -} - -bool Value::asBool() const { - switch (type()) { - case booleanValue: - return value_.bool_; - case nullValue: - return false; - case intValue: - return value_.int_ != 0; - case uintValue: - return value_.uint_ != 0; - case realValue: { - // According to JavaScript language zero or NaN is regarded as false - const auto value_classification = std::fpclassify(value_.real_); - return value_classification != FP_ZERO && value_classification != FP_NAN; - } - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to bool."); -} - -bool Value::isConvertibleTo(ValueType other) const { - switch (other) { - case nullValue: - return (isNumeric() && asDouble() == 0.0) || - (type() == booleanValue && !value_.bool_) || - (type() == stringValue && asString().empty()) || - (type() == arrayValue && value_.map_->empty()) || - (type() == objectValue && value_.map_->empty()) || - type() == nullValue; - case intValue: - return isInt() || - (type() == realValue && InRange(value_.real_, minInt, maxInt)) || - type() == booleanValue || type() == nullValue; - case uintValue: - return isUInt() || - (type() == realValue && InRange(value_.real_, 0, maxUInt)) || - type() == booleanValue || type() == nullValue; - case realValue: - return isNumeric() || type() == booleanValue || type() == nullValue; - case booleanValue: - return isNumeric() || type() == booleanValue || type() == nullValue; - case stringValue: - return isNumeric() || type() == booleanValue || type() == stringValue || - type() == nullValue; - case arrayValue: - return type() == arrayValue || type() == nullValue; - case objectValue: - return type() == objectValue || type() == nullValue; - } - JSON_ASSERT_UNREACHABLE; - return false; -} - -/// Number of values in array or object -ArrayIndex Value::size() const { - switch (type()) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - case stringValue: - return 0; - case arrayValue: // size of the array is highest index + 1 - if (!value_.map_->empty()) { - ObjectValues::const_iterator itLast = value_.map_->end(); - --itLast; - return (*itLast).first.index() + 1; - } - return 0; - case objectValue: - return ArrayIndex(value_.map_->size()); - } - JSON_ASSERT_UNREACHABLE; - return 0; // unreachable; -} - -bool Value::empty() const { - if (isNull() || isArray() || isObject()) - return size() == 0U; - return false; -} - -Value::operator bool() const { return !isNull(); } - -void Value::clear() { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue || - type() == objectValue, - "in Json::Value::clear(): requires complex value"); - start_ = 0; - limit_ = 0; - switch (type()) { - case arrayValue: - case objectValue: - value_.map_->clear(); - break; - default: - break; - } -} - -void Value::resize(ArrayIndex newSize) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, - "in Json::Value::resize(): requires arrayValue"); - if (type() == nullValue) - *this = Value(arrayValue); - ArrayIndex oldSize = size(); - if (newSize == 0) - clear(); - else if (newSize > oldSize) - for (ArrayIndex i = oldSize; i < newSize; ++i) - (*this)[i]; - else { - for (ArrayIndex index = newSize; index < oldSize; ++index) { - value_.map_->erase(index); - } - JSON_ASSERT(size() == newSize); - } -} - -Value& Value::operator[](ArrayIndex index) { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == arrayValue, - "in Json::Value::operator[](ArrayIndex): requires arrayValue"); - if (type() == nullValue) - *this = Value(arrayValue); - CZString key(index); - auto it = value_.map_->lower_bound(key); - if (it != value_.map_->end() && (*it).first == key) - return (*it).second; - - ObjectValues::value_type defaultValue(key, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - return (*it).second; -} - -Value& Value::operator[](int index) { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index): index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -const Value& Value::operator[](ArrayIndex index) const { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == arrayValue, - "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); - if (type() == nullValue) - return nullSingleton(); - CZString key(index); - ObjectValues::const_iterator it = value_.map_->find(key); - if (it == value_.map_->end()) - return nullSingleton(); - return (*it).second; -} - -const Value& Value::operator[](int index) const { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index) const: index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -void Value::initBasic(ValueType type, bool allocated) { - setType(type); - setIsAllocated(allocated); - comments_ = Comments{}; - start_ = 0; - limit_ = 0; -} - -void Value::dupPayload(const Value& other) { - setType(other.type()); - setIsAllocated(false); - switch (type()) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if (other.value_.string_ && other.isAllocated()) { - unsigned len; - char const* str; - decodePrefixedString(other.isAllocated(), other.value_.string_, &len, - &str); - value_.string_ = duplicateAndPrefixStringValue(str, len); - setIsAllocated(true); - } else { - value_.string_ = other.value_.string_; - } - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(*other.value_.map_); - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -void Value::releasePayload() { - switch (type()) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if (isAllocated()) - releasePrefixedStringValue(value_.string_); - break; - case arrayValue: - case objectValue: - delete value_.map_; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -void Value::dupMeta(const Value& other) { - comments_ = other.comments_; - start_ = other.start_; - limit_ = other.limit_; -} - -// Access an object value by name, create a null member if it does not exist. -// @pre Type of '*this' is object or null. -// @param key is null-terminated. -Value& Value::resolveReference(const char* key) { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == objectValue, - "in Json::Value::resolveReference(): requires objectValue"); - if (type() == nullValue) - *this = Value(objectValue); - CZString actualKey(key, static_cast(strlen(key)), - CZString::noDuplication); // NOTE! - auto it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -// @param key is not null-terminated. -Value& Value::resolveReference(char const* key, char const* end) { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == objectValue, - "in Json::Value::resolveReference(key, end): requires objectValue"); - if (type() == nullValue) - *this = Value(objectValue); - CZString actualKey(key, static_cast(end - key), - CZString::duplicateOnCopy); - auto it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -Value Value::get(ArrayIndex index, const Value& defaultValue) const { - const Value* value = &((*this)[index]); - return value == &nullSingleton() ? defaultValue : *value; -} - -bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } - -Value const* Value::find(char const* begin, char const* end) const { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, - "in Json::Value::find(begin, end): requires " - "objectValue or nullValue"); - if (type() == nullValue) - return nullptr; - CZString actualKey(begin, static_cast(end - begin), - CZString::noDuplication); - ObjectValues::const_iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) - return nullptr; - return &(*it).second; -} -Value* Value::demand(char const* begin, char const* end) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, - "in Json::Value::demand(begin, end): requires " - "objectValue or nullValue"); - return &resolveReference(begin, end); -} -const Value& Value::operator[](const char* key) const { - Value const* found = find(key, key + strlen(key)); - if (!found) - return nullSingleton(); - return *found; -} -Value const& Value::operator[](const String& key) const { - Value const* found = find(key.data(), key.data() + key.length()); - if (!found) - return nullSingleton(); - return *found; -} - -Value& Value::operator[](const char* key) { - return resolveReference(key, key + strlen(key)); -} - -Value& Value::operator[](const String& key) { - return resolveReference(key.data(), key.data() + key.length()); -} - -Value& Value::operator[](const StaticString& key) { - return resolveReference(key.c_str()); -} - -Value& Value::append(const Value& value) { return append(Value(value)); } - -Value& Value::append(Value&& value) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, - "in Json::Value::append: requires arrayValue"); - if (type() == nullValue) { - *this = Value(arrayValue); - } - return this->value_.map_->emplace(size(), std::move(value)).first->second; -} - -bool Value::insert(ArrayIndex index, const Value& newValue) { - return insert(index, Value(newValue)); -} - -bool Value::insert(ArrayIndex index, Value&& newValue) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, - "in Json::Value::insert: requires arrayValue"); - ArrayIndex length = size(); - if (index > length) { - return false; - } - for (ArrayIndex i = length; i > index; i--) { - (*this)[i] = std::move((*this)[i - 1]); - } - (*this)[index] = std::move(newValue); - return true; -} - -Value Value::get(char const* begin, char const* end, - Value const& defaultValue) const { - Value const* found = find(begin, end); - return !found ? defaultValue : *found; -} -Value Value::get(char const* key, Value const& defaultValue) const { - return get(key, key + strlen(key), defaultValue); -} -Value Value::get(String const& key, Value const& defaultValue) const { - return get(key.data(), key.data() + key.length(), defaultValue); -} - -bool Value::removeMember(const char* begin, const char* end, Value* removed) { - if (type() != objectValue) { - return false; - } - CZString actualKey(begin, static_cast(end - begin), - CZString::noDuplication); - auto it = value_.map_->find(actualKey); - if (it == value_.map_->end()) - return false; - if (removed) - *removed = std::move(it->second); - value_.map_->erase(it); - return true; -} -bool Value::removeMember(const char* key, Value* removed) { - return removeMember(key, key + strlen(key), removed); -} -bool Value::removeMember(String const& key, Value* removed) { - return removeMember(key.data(), key.data() + key.length(), removed); -} -void Value::removeMember(const char* key) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, - "in Json::Value::removeMember(): requires objectValue"); - if (type() == nullValue) - return; - - CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication); - value_.map_->erase(actualKey); -} -void Value::removeMember(const String& key) { removeMember(key.c_str()); } - -bool Value::removeIndex(ArrayIndex index, Value* removed) { - if (type() != arrayValue) { - return false; - } - CZString key(index); - auto it = value_.map_->find(key); - if (it == value_.map_->end()) { - return false; - } - if (removed) - *removed = it->second; - ArrayIndex oldSize = size(); - // shift left all items left, into the place of the "removed" - for (ArrayIndex i = index; i < (oldSize - 1); ++i) { - CZString keey(i); - (*value_.map_)[keey] = (*this)[i + 1]; - } - // erase the last one ("leftover") - CZString keyLast(oldSize - 1); - auto itLast = value_.map_->find(keyLast); - value_.map_->erase(itLast); - return true; -} - -bool Value::isMember(char const* begin, char const* end) const { - Value const* value = find(begin, end); - return nullptr != value; -} -bool Value::isMember(char const* key) const { - return isMember(key, key + strlen(key)); -} -bool Value::isMember(String const& key) const { - return isMember(key.data(), key.data() + key.length()); -} - -Value::Members Value::getMemberNames() const { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == objectValue, - "in Json::Value::getMemberNames(), value must be objectValue"); - if (type() == nullValue) - return Value::Members(); - Members members; - members.reserve(value_.map_->size()); - ObjectValues::const_iterator it = value_.map_->begin(); - ObjectValues::const_iterator itEnd = value_.map_->end(); - for (; it != itEnd; ++it) { - members.push_back(String((*it).first.data(), (*it).first.length())); - } - return members; -} - -static bool IsIntegral(double d) { - double integral_part; - return modf(d, &integral_part) == 0.0; -} - -bool Value::isNull() const { return type() == nullValue; } - -bool Value::isBool() const { return type() == booleanValue; } - -bool Value::isInt() const { - switch (type()) { - case intValue: -#if defined(JSON_HAS_INT64) - return value_.int_ >= minInt && value_.int_ <= maxInt; -#else - return true; -#endif - case uintValue: - return value_.uint_ <= UInt(maxInt); - case realValue: - return value_.real_ >= minInt && value_.real_ <= maxInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isUInt() const { - switch (type()) { - case intValue: -#if defined(JSON_HAS_INT64) - return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); -#else - return value_.int_ >= 0; -#endif - case uintValue: -#if defined(JSON_HAS_INT64) - return value_.uint_ <= maxUInt; -#else - return true; -#endif - case realValue: - return value_.real_ >= 0 && value_.real_ <= maxUInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isInt64() const { -#if defined(JSON_HAS_INT64) - switch (type()) { - case intValue: - return true; - case uintValue: - return value_.uint_ <= UInt64(maxInt64); - case realValue: - // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a - // double, so double(maxInt64) will be rounded up to 2^63. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && - value_.real_ < double(maxInt64) && IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isUInt64() const { -#if defined(JSON_HAS_INT64) - switch (type()) { - case intValue: - return value_.int_ >= 0; - case uintValue: - return true; - case realValue: - // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a - // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && - IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isIntegral() const { - switch (type()) { - case intValue: - case uintValue: - return true; - case realValue: -#if defined(JSON_HAS_INT64) - // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a - // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && - value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); -#else - return value_.real_ >= minInt && value_.real_ <= maxUInt && - IsIntegral(value_.real_); -#endif // JSON_HAS_INT64 - default: - break; - } - return false; -} - -bool Value::isDouble() const { - return type() == intValue || type() == uintValue || type() == realValue; -} - -bool Value::isNumeric() const { return isDouble(); } - -bool Value::isString() const { return type() == stringValue; } - -bool Value::isArray() const { return type() == arrayValue; } - -bool Value::isObject() const { return type() == objectValue; } - -Value::Comments::Comments(const Comments& that) - : ptr_{cloneUnique(that.ptr_)} {} - -Value::Comments::Comments(Comments&& that) noexcept - : ptr_{std::move(that.ptr_)} {} - -Value::Comments& Value::Comments::operator=(const Comments& that) { - ptr_ = cloneUnique(that.ptr_); - return *this; -} - -Value::Comments& Value::Comments::operator=(Comments&& that) noexcept { - ptr_ = std::move(that.ptr_); - return *this; -} - -bool Value::Comments::has(CommentPlacement slot) const { - return ptr_ && !(*ptr_)[slot].empty(); -} - -String Value::Comments::get(CommentPlacement slot) const { - if (!ptr_) - return {}; - return (*ptr_)[slot]; -} - -void Value::Comments::set(CommentPlacement slot, String comment) { - if (slot >= CommentPlacement::numberOfCommentPlacement) - return; - if (!ptr_) - ptr_ = std::unique_ptr(new Array()); - (*ptr_)[slot] = std::move(comment); -} - -void Value::setComment(String comment, CommentPlacement placement) { - if (!comment.empty() && (comment.back() == '\n')) { - // Always discard trailing newline, to aid indentation. - comment.pop_back(); - } - JSON_ASSERT(!comment.empty()); - JSON_ASSERT_MESSAGE( - comment[0] == '\0' || comment[0] == '/', - "in Json::Value::setComment(): Comments must start with /"); - comments_.set(placement, std::move(comment)); -} - -bool Value::hasComment(CommentPlacement placement) const { - return comments_.has(placement); -} - -String Value::getComment(CommentPlacement placement) const { - return comments_.get(placement); -} - -void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } - -void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } - -ptrdiff_t Value::getOffsetStart() const { return start_; } - -ptrdiff_t Value::getOffsetLimit() const { return limit_; } - -String Value::toStyledString() const { - StreamWriterBuilder builder; - - String out = this->hasComment(commentBefore) ? "\n" : ""; - out += Json::writeString(builder, *this); - out += '\n'; - - return out; -} - -Value::const_iterator Value::begin() const { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->begin()); - break; - default: - break; - } - return {}; -} - -Value::const_iterator Value::end() const { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->end()); - break; - default: - break; - } - return {}; -} - -Value::iterator Value::begin() { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->begin()); - break; - default: - break; - } - return iterator(); -} - -Value::iterator Value::end() { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->end()); - break; - default: - break; - } - return iterator(); -} - -// class PathArgument -// ////////////////////////////////////////////////////////////////// - -PathArgument::PathArgument() = default; - -PathArgument::PathArgument(ArrayIndex index) - : index_(index), kind_(kindIndex) {} - -PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {} - -PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {} - -// class Path -// ////////////////////////////////////////////////////////////////// - -Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2, - const PathArgument& a3, const PathArgument& a4, - const PathArgument& a5) { - InArgs in; - in.reserve(5); - in.push_back(&a1); - in.push_back(&a2); - in.push_back(&a3); - in.push_back(&a4); - in.push_back(&a5); - makePath(path, in); -} - -void Path::makePath(const String& path, const InArgs& in) { - const char* current = path.c_str(); - const char* end = current + path.length(); - auto itInArg = in.begin(); - while (current != end) { - if (*current == '[') { - ++current; - if (*current == '%') - addPathInArg(path, in, itInArg, PathArgument::kindIndex); - else { - ArrayIndex index = 0; - for (; current != end && *current >= '0' && *current <= '9'; ++current) - index = index * 10 + ArrayIndex(*current - '0'); - args_.push_back(index); - } - if (current == end || *++current != ']') - invalidPath(path, int(current - path.c_str())); - } else if (*current == '%') { - addPathInArg(path, in, itInArg, PathArgument::kindKey); - ++current; - } else if (*current == '.' || *current == ']') { - ++current; - } else { - const char* beginName = current; - while (current != end && !strchr("[.", *current)) - ++current; - args_.push_back(String(beginName, current)); - } - } -} - -void Path::addPathInArg(const String& /*path*/, const InArgs& in, - InArgs::const_iterator& itInArg, - PathArgument::Kind kind) { - if (itInArg == in.end()) { - // Error: missing argument %d - } else if ((*itInArg)->kind_ != kind) { - // Error: bad argument type - } else { - args_.push_back(**itInArg++); - } -} - -void Path::invalidPath(const String& /*path*/, int /*location*/) { - // Error: invalid path. -} - -const Value& Path::resolve(const Value& root) const { - const Value* node = &root; - for (const auto& arg : args_) { - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) { - // Error: unable to resolve path (array value expected at position... ) - return Value::nullSingleton(); - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: unable to resolve path (object value expected at position...) - return Value::nullSingleton(); - } - node = &((*node)[arg.key_]); - if (node == &Value::nullSingleton()) { - // Error: unable to resolve path (object has no member named '' at - // position...) - return Value::nullSingleton(); - } - } - } - return *node; -} - -Value Path::resolve(const Value& root, const Value& defaultValue) const { - const Value* node = &root; - for (const auto& arg : args_) { - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) - return defaultValue; - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) - return defaultValue; - node = &((*node)[arg.key_]); - if (node == &Value::nullSingleton()) - return defaultValue; - } - } - return *node; -} - -Value& Path::make(Value& root) const { - Value* node = &root; - for (const auto& arg : args_) { - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray()) { - // Error: node is not an array at position ... - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: node is not an object at position... - } - node = &((*node)[arg.key_]); - } - } - return *node; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include "json_tool.h" -#include -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if __cplusplus >= 201103L -#include -#include - -#if !defined(isnan) -#define isnan std::isnan -#endif - -#if !defined(isfinite) -#define isfinite std::isfinite -#endif - -#else -#include -#include - -#if defined(_MSC_VER) -#if !defined(isnan) -#include -#define isnan _isnan -#endif - -#if !defined(isfinite) -#include -#define isfinite _finite -#endif - -#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES - -#endif //_MSC_VER - -#if defined(__sun) && defined(__SVR4) // Solaris -#if !defined(isfinite) -#include -#define isfinite finite -#endif -#endif - -#if defined(__hpux) -#if !defined(isfinite) -#if defined(__ia64) && !defined(finite) -#define isfinite(x) \ - ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x))) -#endif -#endif -#endif - -#if !defined(isnan) -// IEEE standard states that NaN values will not compare to themselves -#define isnan(x) ((x) != (x)) -#endif - -#if !defined(__APPLE__) -#if !defined(isfinite) -#define isfinite finite -#endif -#endif -#endif - -#if defined(_MSC_VER) -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -namespace Json { - -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -using StreamWriterPtr = std::unique_ptr; -#else -using StreamWriterPtr = std::auto_ptr; -#endif - -String valueToString(LargestInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - if (value == Value::minLargestInt) { - uintToString(LargestUInt(Value::maxLargestInt) + 1, current); - *--current = '-'; - } else if (value < 0) { - uintToString(LargestUInt(-value), current); - *--current = '-'; - } else { - uintToString(LargestUInt(value), current); - } - assert(current >= buffer); - return current; -} - -String valueToString(LargestUInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - uintToString(value, current); - assert(current >= buffer); - return current; -} - -#if defined(JSON_HAS_INT64) - -String valueToString(Int value) { return valueToString(LargestInt(value)); } - -String valueToString(UInt value) { return valueToString(LargestUInt(value)); } - -#endif // # if defined(JSON_HAS_INT64) - -namespace { -String valueToString(double value, bool useSpecialFloats, - unsigned int precision, PrecisionType precisionType) { - // Print into the buffer. We need not request the alternative representation - // that always has a decimal point because JSON doesn't distinguish the - // concepts of reals and integers. - if (!isfinite(value)) { - static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"}, - {"null", "-1e+9999", "1e+9999"}}; - return reps[useSpecialFloats ? 0 : 1] - [isnan(value) ? 0 : (value < 0) ? 1 : 2]; - } - - String buffer(size_t(36), '\0'); - while (true) { - int len = jsoncpp_snprintf( - &*buffer.begin(), buffer.size(), - (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f", - precision, value); - assert(len >= 0); - auto wouldPrint = static_cast(len); - if (wouldPrint >= buffer.size()) { - buffer.resize(wouldPrint + 1); - continue; - } - buffer.resize(wouldPrint); - break; - } - - buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); - - // try to ensure we preserve the fact that this was given to us as a double on - // input - if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { - buffer += ".0"; - } - - // strip the zero padding from the right - if (precisionType == PrecisionType::decimalPlaces) { - buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end(), precision), - buffer.end()); - } - - return buffer; -} -} // namespace - -String valueToString(double value, unsigned int precision, - PrecisionType precisionType) { - return valueToString(value, false, precision, precisionType); -} - -String valueToString(bool value) { return value ? "true" : "false"; } - -static bool doesAnyCharRequireEscaping(char const* s, size_t n) { - assert(s || !n); - - return std::any_of(s, s + n, [](unsigned char c) { - return c == '\\' || c == '"' || c < 0x20 || c > 0x7F; - }); -} - -static unsigned int utf8ToCodepoint(const char*& s, const char* e) { - const unsigned int REPLACEMENT_CHARACTER = 0xFFFD; - - unsigned int firstByte = static_cast(*s); - - if (firstByte < 0x80) - return firstByte; - - if (firstByte < 0xE0) { - if (e - s < 2) - return REPLACEMENT_CHARACTER; - - unsigned int calculated = - ((firstByte & 0x1F) << 6) | (static_cast(s[1]) & 0x3F); - s += 1; - // oversized encoded characters are invalid - return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; - } - - if (firstByte < 0xF0) { - if (e - s < 3) - return REPLACEMENT_CHARACTER; - - unsigned int calculated = ((firstByte & 0x0F) << 12) | - ((static_cast(s[1]) & 0x3F) << 6) | - (static_cast(s[2]) & 0x3F); - s += 2; - // surrogates aren't valid codepoints itself - // shouldn't be UTF-8 encoded - if (calculated >= 0xD800 && calculated <= 0xDFFF) - return REPLACEMENT_CHARACTER; - // oversized encoded characters are invalid - return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated; - } - - if (firstByte < 0xF8) { - if (e - s < 4) - return REPLACEMENT_CHARACTER; - - unsigned int calculated = ((firstByte & 0x07) << 18) | - ((static_cast(s[1]) & 0x3F) << 12) | - ((static_cast(s[2]) & 0x3F) << 6) | - (static_cast(s[3]) & 0x3F); - s += 3; - // oversized encoded characters are invalid - return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; - } - - return REPLACEMENT_CHARACTER; -} - -static const char hex2[] = "000102030405060708090a0b0c0d0e0f" - "101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f" - "303132333435363738393a3b3c3d3e3f" - "404142434445464748494a4b4c4d4e4f" - "505152535455565758595a5b5c5d5e5f" - "606162636465666768696a6b6c6d6e6f" - "707172737475767778797a7b7c7d7e7f" - "808182838485868788898a8b8c8d8e8f" - "909192939495969798999a9b9c9d9e9f" - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" - "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; - -static String toHex16Bit(unsigned int x) { - const unsigned int hi = (x >> 8) & 0xff; - const unsigned int lo = x & 0xff; - String result(4, ' '); - result[0] = hex2[2 * hi]; - result[1] = hex2[2 * hi + 1]; - result[2] = hex2[2 * lo]; - result[3] = hex2[2 * lo + 1]; - return result; -} - -static void appendRaw(String& result, unsigned ch) { - result += static_cast(ch); -} - -static void appendHex(String& result, unsigned ch) { - result.append("\\u").append(toHex16Bit(ch)); -} - -static String valueToQuotedStringN(const char* value, size_t length, - bool emitUTF8 = false) { - if (value == nullptr) - return ""; - - if (!doesAnyCharRequireEscaping(value, length)) - return String("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to String is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL - String result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - char const* end = value + length; - for (const char* c = value; c != end; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something.) - // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); - if (codepoint < 0x20) { - appendHex(result, codepoint); - } else { - appendRaw(result, codepoint); - } - } else { - unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c` - if (codepoint < 0x20) { - appendHex(result, codepoint); - } else if (codepoint < 0x80) { - appendRaw(result, codepoint); - } else if (codepoint < 0x10000) { - // Basic Multilingual Plane - appendHex(result, codepoint); - } else { - // Extended Unicode. Encode 20 bits as a surrogate pair. - codepoint -= 0x10000; - appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff)); - appendHex(result, 0xdc00 + (codepoint & 0x3ff)); - } - } - } break; - } - } - result += "\""; - return result; -} - -String valueToQuotedString(const char* value) { - return valueToQuotedStringN(value, strlen(value)); -} - -// Class Writer -// ////////////////////////////////////////////////////////////////// -Writer::~Writer() = default; - -// Class FastWriter -// ////////////////////////////////////////////////////////////////// - -FastWriter::FastWriter() - - = default; - -void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } - -void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } - -void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } - -String FastWriter::write(const Value& root) { - document_.clear(); - writeValue(root); - if (!omitEndingLineFeed_) - document_ += '\n'; - return document_; -} - -void FastWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - if (!dropNullPlaceholders_) - document_ += "null"; - break; - case intValue: - document_ += valueToString(value.asLargestInt()); - break; - case uintValue: - document_ += valueToString(value.asLargestUInt()); - break; - case realValue: - document_ += valueToString(value.asDouble()); - break; - case stringValue: { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - document_ += valueToQuotedStringN(str, static_cast(end - str)); - break; - } - case booleanValue: - document_ += valueToString(value.asBool()); - break; - case arrayValue: { - document_ += '['; - ArrayIndex size = value.size(); - for (ArrayIndex index = 0; index < size; ++index) { - if (index > 0) - document_ += ','; - writeValue(value[index]); - } - document_ += ']'; - } break; - case objectValue: { - Value::Members members(value.getMemberNames()); - document_ += '{'; - for (auto it = members.begin(); it != members.end(); ++it) { - const String& name = *it; - if (it != members.begin()) - document_ += ','; - document_ += valueToQuotedStringN(name.data(), name.length()); - document_ += yamlCompatibilityEnabled_ ? ": " : ":"; - writeValue(value[name]); - } - document_ += '}'; - } break; - } -} - -// Class StyledWriter -// ////////////////////////////////////////////////////////////////// - -StyledWriter::StyledWriter() = default; - -String StyledWriter::write(const Value& root) { - document_.clear(); - addChildValues_ = false; - indentString_.clear(); - writeCommentBeforeValue(root); - writeValue(root); - writeCommentAfterValueOnSameLine(root); - document_ += '\n'; - return document_; -} - -void StyledWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str))); - else - pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - auto it = members.begin(); - for (;;) { - const String& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - document_ += " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledWriter::writeArrayValue(const Value& value) { - size_t size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultilineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - ArrayIndex index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - writeIndent(); - writeValue(childValue); - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - document_ += "[ "; - for (size_t index = 0; index < size; ++index) { - if (index > 0) - document_ += ", "; - document_ += childValues_[index]; - } - document_ += " ]"; - } - } -} - -bool StyledWriter::isMultilineArray(const Value& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - !childValue.empty()); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledWriter::pushValue(const String& value) { - if (addChildValues_) - childValues_.push_back(value); - else - document_ += value; -} - -void StyledWriter::writeIndent() { - if (!document_.empty()) { - char last = document_[document_.length() - 1]; - if (last == ' ') // already indented - return; - if (last != '\n') // Comments may add new-line - document_ += '\n'; - } - document_ += indentString_; -} - -void StyledWriter::writeWithIndent(const String& value) { - writeIndent(); - document_ += value; -} - -void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); } - -void StyledWriter::unindent() { - assert(indentString_.size() >= indentSize_); - indentString_.resize(indentString_.size() - indentSize_); -} - -void StyledWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - document_ += '\n'; - writeIndent(); - const String& comment = root.getComment(commentBefore); - String::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - document_ += *iter; - if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) - writeIndent(); - ++iter; - } - - // Comments are stripped of trailing newlines, so add one here - document_ += '\n'; -} - -void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - document_ += " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - document_ += '\n'; - document_ += root.getComment(commentAfter); - document_ += '\n'; - } -} - -bool StyledWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -// Class StyledStreamWriter -// ////////////////////////////////////////////////////////////////// - -StyledStreamWriter::StyledStreamWriter(String indentation) - : document_(nullptr), indentation_(std::move(indentation)), - addChildValues_(), indented_(false) {} - -void StyledStreamWriter::write(OStream& out, const Value& root) { - document_ = &out; - addChildValues_ = false; - indentString_.clear(); - indented_ = true; - writeCommentBeforeValue(root); - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *document_ << "\n"; - document_ = nullptr; // Forget the stream, for safety. -} - -void StyledStreamWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str))); - else - pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - auto it = members.begin(); - for (;;) { - const String& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - *document_ << " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledStreamWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultilineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *document_ << "[ "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *document_ << ", "; - *document_ << childValues_[index]; - } - *document_ << " ]"; - } - } -} - -bool StyledStreamWriter::isMultilineArray(const Value& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - !childValue.empty()); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledStreamWriter::pushValue(const String& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *document_ << value; -} - -void StyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - *document_ << '\n' << indentString_; -} - -void StyledStreamWriter::writeWithIndent(const String& value) { - if (!indented_) - writeIndent(); - *document_ << value; - indented_ = false; -} - -void StyledStreamWriter::indent() { indentString_ += indentation_; } - -void StyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) - writeIndent(); - const String& comment = root.getComment(commentBefore); - String::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *document_ << *iter; - if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would include newline - *document_ << indentString_; - ++iter; - } - indented_ = false; -} - -void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - *document_ << ' ' << root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *document_ << root.getComment(commentAfter); - } - indented_ = false; -} - -bool StyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -////////////////////////// -// BuiltStyledStreamWriter - -/// Scoped enums are not available until C++11. -struct CommentStyle { - /// Decide whether to write comments. - enum Enum { - None, ///< Drop all comments. - Most, ///< Recover odd behavior of previous versions (not implemented yet). - All ///< Keep all comments. - }; -}; - -struct BuiltStyledStreamWriter : public StreamWriter { - BuiltStyledStreamWriter(String indentation, CommentStyle::Enum cs, - String colonSymbol, String nullSymbol, - String endingLineFeedSymbol, bool useSpecialFloats, - bool emitUTF8, unsigned int precision, - PrecisionType precisionType); - int write(Value const& root, OStream* sout) override; - -private: - void writeValue(Value const& value); - void writeArrayValue(Value const& value); - bool isMultilineArray(Value const& value); - void pushValue(String const& value); - void writeIndent(); - void writeWithIndent(String const& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(Value const& root); - void writeCommentAfterValueOnSameLine(Value const& root); - static bool hasCommentForValue(const Value& value); - - using ChildValues = std::vector; - - ChildValues childValues_; - String indentString_; - unsigned int rightMargin_; - String indentation_; - CommentStyle::Enum cs_; - String colonSymbol_; - String nullSymbol_; - String endingLineFeedSymbol_; - bool addChildValues_ : 1; - bool indented_ : 1; - bool useSpecialFloats_ : 1; - bool emitUTF8_ : 1; - unsigned int precision_; - PrecisionType precisionType_; -}; -BuiltStyledStreamWriter::BuiltStyledStreamWriter( - String indentation, CommentStyle::Enum cs, String colonSymbol, - String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats, - bool emitUTF8, unsigned int precision, PrecisionType precisionType) - : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs), - colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)), - endingLineFeedSymbol_(std::move(endingLineFeedSymbol)), - addChildValues_(false), indented_(false), - useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8), - precision_(precision), precisionType_(precisionType) {} -int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) { - sout_ = sout; - addChildValues_ = false; - indented_ = true; - indentString_.clear(); - writeCommentBeforeValue(root); - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *sout_ << endingLineFeedSymbol_; - sout_ = nullptr; - return 0; -} -void BuiltStyledStreamWriter::writeValue(Value const& value) { - switch (value.type()) { - case nullValue: - pushValue(nullSymbol_); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, - precisionType_)); - break; - case stringValue: { - // Is NULL is possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - pushValue( - valueToQuotedStringN(str, static_cast(end - str), emitUTF8_)); - else - pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - auto it = members.begin(); - for (;;) { - String const& name = *it; - Value const& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent( - valueToQuotedStringN(name.data(), name.length(), emitUTF8_)); - *sout_ << colonSymbol_; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value); - if (isMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - Value const& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *sout_ << "["; - if (!indentation_.empty()) - *sout_ << " "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *sout_ << ((!indentation_.empty()) ? ", " : ","); - *sout_ << childValues_[index]; - } - if (!indentation_.empty()) - *sout_ << " "; - *sout_ << "]"; - } - } -} - -bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - Value const& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - !childValue.empty()); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void BuiltStyledStreamWriter::pushValue(String const& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *sout_ << value; -} - -void BuiltStyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - - if (!indentation_.empty()) { - // In this case, drop newlines too. - *sout_ << '\n' << indentString_; - } -} - -void BuiltStyledStreamWriter::writeWithIndent(String const& value) { - if (!indented_) - writeIndent(); - *sout_ << value; - indented_ = false; -} - -void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } - -void BuiltStyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { - if (cs_ == CommentStyle::None) - return; - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) - writeIndent(); - const String& comment = root.getComment(commentBefore); - String::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *sout_ << *iter; - if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would write extra newline - *sout_ << indentString_; - ++iter; - } - indented_ = false; -} - -void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine( - Value const& root) { - if (cs_ == CommentStyle::None) - return; - if (root.hasComment(commentAfterOnSameLine)) - *sout_ << " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *sout_ << root.getComment(commentAfter); - } -} - -// static -bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -/////////////// -// StreamWriter - -StreamWriter::StreamWriter() : sout_(nullptr) {} -StreamWriter::~StreamWriter() = default; -StreamWriter::Factory::~Factory() = default; -StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } -StreamWriterBuilder::~StreamWriterBuilder() = default; -StreamWriter* StreamWriterBuilder::newStreamWriter() const { - const String indentation = settings_["indentation"].asString(); - const String cs_str = settings_["commentStyle"].asString(); - const String pt_str = settings_["precisionType"].asString(); - const bool eyc = settings_["enableYAMLCompatibility"].asBool(); - const bool dnp = settings_["dropNullPlaceholders"].asBool(); - const bool usf = settings_["useSpecialFloats"].asBool(); - const bool emitUTF8 = settings_["emitUTF8"].asBool(); - unsigned int pre = settings_["precision"].asUInt(); - CommentStyle::Enum cs = CommentStyle::All; - if (cs_str == "All") { - cs = CommentStyle::All; - } else if (cs_str == "None") { - cs = CommentStyle::None; - } else { - throwRuntimeError("commentStyle must be 'All' or 'None'"); - } - PrecisionType precisionType(significantDigits); - if (pt_str == "significant") { - precisionType = PrecisionType::significantDigits; - } else if (pt_str == "decimal") { - precisionType = PrecisionType::decimalPlaces; - } else { - throwRuntimeError("precisionType must be 'significant' or 'decimal'"); - } - String colonSymbol = " : "; - if (eyc) { - colonSymbol = ": "; - } else if (indentation.empty()) { - colonSymbol = ":"; - } - String nullSymbol = "null"; - if (dnp) { - nullSymbol.clear(); - } - if (pre > 17) - pre = 17; - String endingLineFeedSymbol; - return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol, - endingLineFeedSymbol, usf, emitUTF8, pre, - precisionType); -} - -bool StreamWriterBuilder::validate(Json::Value* invalid) const { - static const auto& valid_keys = *new std::set{ - "indentation", - "commentStyle", - "enableYAMLCompatibility", - "dropNullPlaceholders", - "useSpecialFloats", - "emitUTF8", - "precision", - "precisionType", - }; - for (auto si = settings_.begin(); si != settings_.end(); ++si) { - auto key = si.name(); - if (valid_keys.count(key)) - continue; - if (invalid) - (*invalid)[key] = *si; - else - return false; - } - return invalid ? invalid->empty() : true; -} - -Value& StreamWriterBuilder::operator[](const String& key) { - return settings_[key]; -} -// static -void StreamWriterBuilder::setDefaults(Json::Value* settings) { - //! [StreamWriterBuilderDefaults] - (*settings)["commentStyle"] = "All"; - (*settings)["indentation"] = "\t"; - (*settings)["enableYAMLCompatibility"] = false; - (*settings)["dropNullPlaceholders"] = false; - (*settings)["useSpecialFloats"] = false; - (*settings)["emitUTF8"] = false; - (*settings)["precision"] = 17; - (*settings)["precisionType"] = "significant"; - //! [StreamWriterBuilderDefaults] -} - -String writeString(StreamWriter::Factory const& factory, Value const& root) { - OStringStream sout; - StreamWriterPtr const writer(factory.newStreamWriter()); - writer->write(root, &sout); - return sout.str(); -} - -OStream& operator<<(OStream& sout, Value const& root) { - StreamWriterBuilder builder; - StreamWriterPtr const writer(builder.newStreamWriter()); - writer->write(root, &sout); - return sout; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - diff --git a/src/communication/pub_gps/src/pub_gps_node.cpp b/src/communication/pub_gps/src/pub_gps_node.cpp deleted file mode 100644 index 6bbe8e9..0000000 --- a/src/communication/pub_gps/src/pub_gps_node.cpp +++ /dev/null @@ -1,305 +0,0 @@ -#include "MQTTClient.h" -#include "rclcpp/rclcpp.hpp" -#include "sweeper_interfaces/msg/rtk.hpp" -#include "json.h" -#include "pub_gps_node.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct MqttConf -{ - std::string address; // 形如 tcp://ip:port - std::string client_id; // 客户端 ID - std::string user; - std::string password; - std::string pub_gps_topic; - int qos = 1; - long timeout_ms = 10000L; - int reconnect_interval = 5000; // 重连间隔(ms) -} g_conf; - -GPS gps_mes; -// 增加连接状态标志,确保线程安全 -static bool is_connected = false; -static pthread_mutex_t connect_mutex = PTHREAD_MUTEX_INITIALIZER; - -// 检查连接状态 -bool check_connection(MQTTClient client) -{ - pthread_mutex_lock(&connect_mutex); - int state = MQTTClient_isConnected(client); - is_connected = (state == 1); - pthread_mutex_unlock(&connect_mutex); - return is_connected; -} - -// 设置连接状态 -void set_connected(bool connected) -{ - pthread_mutex_lock(&connect_mutex); - is_connected = connected; - pthread_mutex_unlock(&connect_mutex); -} - -// 重连函数 -bool reconnect_client(MQTTClient *client) -{ - MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; - conn_opts.keepAliveInterval = 20; - conn_opts.cleansession = 1; - conn_opts.username = g_conf.user.c_str(); - conn_opts.password = g_conf.password.c_str(); - - int rc; - // 尝试重连,最多尝试5次 - for (int i = 0; i < 5; ++i) - { - std::cerr << "[MQTT] Reconnecting... (attempt " << i + 1 << "/5)" << std::endl; - rc = MQTTClient_connect(*client, &conn_opts); - if (rc == MQTTCLIENT_SUCCESS) - { - set_connected(true); - std::cout << "[MQTT] Reconnected successfully" << std::endl; - return true; - } - std::cerr << "[MQTT] Reconnect failed, rc=" << rc << ". Retrying in " - << g_conf.reconnect_interval << "ms..." << std::endl; - usleep(g_conf.reconnect_interval * 1000); - } - return false; -} - -void *mqtt_pub_gps(void *arg) -{ - (void)arg; - MQTTClient client = nullptr; - MQTTClient_deliveryToken token_d_m; - int rc; - - // 初始化客户端 - if ((rc = MQTTClient_create(&client, - g_conf.address.c_str(), - g_conf.client_id.c_str(), - MQTTCLIENT_PERSISTENCE_NONE, - nullptr)) != MQTTCLIENT_SUCCESS) - { - std::cerr << "Failed to create client, rc=" << rc << std::endl; - return nullptr; - } - - // 初始连接 - if (!reconnect_client(&client)) - { - std::cerr << "[MQTT] Failed to establish initial connection" << std::endl; - MQTTClient_destroy(&client); - return nullptr; - } - - MQTTClient_message pubmsg = MQTTClient_message_initializer; - pubmsg.qos = g_conf.qos; - pubmsg.retained = 0; - - Json::Value root_st; - Json::FastWriter json_writer; - unsigned char msg_st[256] = {0}; - - while (true) - { - // 检查连接状态,断开则尝试重连 - if (!check_connection(client)) - { - std::cerr << "[MQTT] Connection lost. Attempting to reconnect..." << std::endl; - - // 先断开旧连接 - MQTTClient_disconnect(client, 1000); - - // 重连失败则销毁客户端重新创建 - if (!reconnect_client(&client)) - { - std::cerr << "[MQTT] All reconnection attempts failed. Recreating client..." << std::endl; - MQTTClient_destroy(&client); - - // 重新创建客户端 - if ((rc = MQTTClient_create(&client, - g_conf.address.c_str(), - g_conf.client_id.c_str(), - MQTTCLIENT_PERSISTENCE_NONE, - nullptr)) != MQTTCLIENT_SUCCESS) - { - std::cerr << "Failed to recreate client, rc=" << rc << std::endl; - usleep(g_conf.reconnect_interval * 1000); - continue; - } - - // 再次尝试连接 - if (!reconnect_client(&client)) - { - usleep(g_conf.reconnect_interval * 1000); - continue; - } - } - } - - root_st.clear(); - - root_st["lng"] = [&] - { std::ostringstream s; s<( - std::chrono::system_clock::now().time_since_epoch()) - .count(); - - std::string json_string = json_writer.write(root_st); - memcpy(msg_st, json_string.c_str(), json_string.size()); - pubmsg.payload = msg_st; - pubmsg.payloadlen = static_cast(json_string.size()); - - // 发布消息 - if (check_connection(client)) - { - rc = MQTTClient_publishMessage(client, - g_conf.pub_gps_topic.c_str(), - &pubmsg, - &token_d_m); - if (rc == MQTTCLIENT_SUCCESS) - { - // std::cout << "[MQTT] Published to topic: " << g_conf.pub_gps_topic - // << "\n msg: " << json_string << std::endl; - MQTTClient_waitForCompletion(client, token_d_m, g_conf.timeout_ms); - } - else - { - std::cerr << "[MQTT] publish failed, rc=" << rc << std::endl; - set_connected(false); // 发布失败标记为断开连接 - } - } - - usleep(200000); // 200 ms - } - - // 清理资源 - MQTTClient_disconnect(client, 10000); - MQTTClient_destroy(&client); - pthread_mutex_destroy(&connect_mutex); - return nullptr; -} - -class pub_gps_node : public rclcpp::Node -{ -public: - explicit pub_gps_node(const std::string &name) : Node(name) - { - RCLCPP_INFO(this->get_logger(), "%s 节点已启动.", name.c_str()); - gps_subscribe_ = this->create_subscription( - "rtk_message", 10, - std::bind(&pub_gps_node::command_callback, this, std::placeholders::_1)); - } - -private: - void command_callback(const sweeper_interfaces::msg::Rtk::SharedPtr msg) - { - gps_mes.lat = msg->lat; - gps_mes.lng = msg->lon; - gps_mes.course = msg->head; - - if (msg->p_quality == 5) - gps_mes.mode = 2; - else if (msg->p_quality == 4) - gps_mes.mode = 3; - else - gps_mes.mode = msg->p_quality; - } - rclcpp::Subscription::SharedPtr gps_subscribe_; -}; - -std::string generate_mqtt_client_id() -{ - // 获取当前时间戳(以毫秒为单位) - auto now = std::chrono::system_clock::now(); - auto millis = std::chrono::duration_cast(now.time_since_epoch()).count(); - - // 生成一个 4 位随机数 - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> dis(1000, 9999); - int random_num = dis(gen); - - // 拼接成 client ID - std::ostringstream oss; - oss << "client_" << millis << "_" << std::setw(4) << std::setfill('0') << random_num; - - return oss.str(); -} - -bool load_config(const std::string &path) -{ - Json::Reader reader; - Json::Value root; - std::ifstream in(path, std::ios::binary); - if (!in.is_open()) - { - std::cerr << "[config] open " << path << " failed\n"; - return false; - } - if (!reader.parse(in, root)) - { - std::cerr << "[config] parse json failed\n"; - return false; - } - - const auto &m = root["mqtt"]; - std::string ip = m["external_net_address"].asString(); // tcp://36.153.162.171 - int port = m["external_net_port"].asInt(); // 19683 - // std::string ip = m["inter_net_address"].asString(); // tcp://192.168.4.196 - // int port = m["inter_net_port"].asInt(); // 11883 - - g_conf.address = ip + ":" + std::to_string(port); - g_conf.client_id = generate_mqtt_client_id(); - g_conf.user = m["mqtt_user"].asString(); - g_conf.password = m["mqtt_password"].asString(); - g_conf.pub_gps_topic = m["pub_gps_topic"].asString(); - - // 从配置读取重连间隔,默认5000ms - if (m.isMember("reconnect_interval")) - { - g_conf.reconnect_interval = m["reconnect_interval"].asInt(); - } - - return true; -} - -int main(int argc, char **argv) -{ - if (!load_config("config.json")) - return -1; - - // 初始化互斥锁 - pthread_mutex_init(&connect_mutex, nullptr); - - pthread_t mqtt_thread; - pthread_create(&mqtt_thread, nullptr, mqtt_pub_gps, nullptr); - - rclcpp::init(argc, argv); - rclcpp::spin(std::make_shared("pub_gps_node")); - rclcpp::shutdown(); - - // 清理资源 - pthread_mutex_destroy(&connect_mutex); - return 0; -} \ No newline at end of file