├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── candlesticks.cpp ├── examples ├── private_method.cpp └── public_method.cpp ├── kapi.cpp ├── kapi.hpp ├── kmarketdata.cpp ├── kph.cpp ├── kraken ├── kclient.cpp ├── kclient.hpp ├── ktrade.cpp └── ktrade.hpp ├── krt.cpp └── libjson ├── JSONOptions.h ├── License.txt ├── _internal ├── Dependencies │ ├── libbase64++ │ │ └── libbase64++.h │ └── mempool++ │ │ └── mempool.h └── Source │ ├── JSONAllocator.cpp │ ├── JSONAllocator.h │ ├── JSONChildren.cpp │ ├── JSONChildren.h │ ├── JSONDebug.cpp │ ├── JSONDebug.h │ ├── JSONDefs.h │ ├── JSONDefs │ ├── GNU_C.h │ ├── Strings_Defs.h │ ├── Unknown_C.h │ └── Visual_C.h │ ├── JSONGlobals.h │ ├── JSONIterators.cpp │ ├── JSONMemory.cpp │ ├── JSONMemory.h │ ├── JSONMemoryPool.h │ ├── JSONNode.cpp │ ├── JSONNode.h │ ├── JSONNode_Mutex.cpp │ ├── JSONPreparse.cpp │ ├── JSONPreparse.h │ ├── JSONSharedString.h │ ├── JSONSingleton.h │ ├── JSONStats.h │ ├── JSONStream.cpp │ ├── JSONStream.h │ ├── JSONValidator.cpp │ ├── JSONValidator.h │ ├── JSONWorker.cpp │ ├── JSONWorker.h │ ├── JSONWriter.cpp │ ├── JSON_Base64.h │ ├── NumberToString.h │ ├── internalJSONNode.cpp │ ├── internalJSONNode.h │ └── libjson.cpp └── libjson.h /.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-* 2 | .idea -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8.12) 2 | project (KRAKENAPI) 3 | 4 | add_definitions("-std=c++11") 5 | 6 | #------------------------------------------------------------------------------- 7 | IF (CMAKE_CXX_COMPILER_ID STREQUAL Clang) 8 | add_definitions("-Wno-tautological-compare") 9 | 10 | ENDIF() 11 | 12 | #------------------------------------------------------------------------------- 13 | IF (APPLE) 14 | set (CMAKE_MODULE_LINKER_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress") 15 | ENDIF (APPLE) 16 | 17 | #------------------------------------------------------------------------------- 18 | IF (POLICY CMP0043) 19 | cmake_policy(SET CMP0043 OLD) 20 | ENDIF() 21 | 22 | #------------------------------------------------------------------------------- 23 | # Control CMAKE_BUILD_TYPE, default: Debug 24 | #------------------------------------------------------------------------------- 25 | if (NOT CMAKE_BUILD_TYPE) 26 | set (CMAKE_BUILD_TYPE "Debug" CACHE string "Build type" FORCE) 27 | endif (NOT CMAKE_BUILD_TYPE) 28 | message (STATUS "Build type: " ${CMAKE_BUILD_TYPE}) 29 | 30 | #------------------------------------------------------------------------------- 31 | # Find OpenSSL 32 | #------------------------------------------------------------------------------- 33 | find_package (OpenSSL REQUIRED) 34 | include_directories (${OPENSSL_INCLUDE_DIR}) 35 | list(APPEND LIBS ${OPENSSL_LIBRARIES}) 36 | 37 | #------------------------------------------------------------------------------- 38 | # Find CURL 39 | #------------------------------------------------------------------------------- 40 | find_package (CURL REQUIRED) 41 | include_directories (${CURL_INCLUDE_DIR}) 42 | list(APPEND LIBS ${CURL_LIBRARIES}) 43 | 44 | #------------------------------------------------------------------------------- 45 | # Add library kapi (krakenapi) 46 | #------------------------------------------------------------------------------- 47 | aux_source_directory(kraken KAPI_FILES) 48 | add_library (kapi STATIC ${KAPI_FILES}) 49 | 50 | # set some properties when CMAKE_BUILD_TYPE is "Debug" 51 | set_target_properties (kapi PROPERTIES 52 | COMPILE_DEFINITIONS_DEBUG "JSON_DEBUG;JSON_SAFE;JSON_ISO_STRICT" 53 | DEBUG_POSTFIX "d") 54 | 55 | list (INSERT LIBS 0 kapi) 56 | 57 | #------------------------------------------------------------------------------- 58 | # Add library libjson 59 | #------------------------------------------------------------------------------- 60 | set (LIBJSON_SOURCE_DIR ${CMAKE_HOME_DIRECTORY}/libjson/_internal/Source) 61 | aux_source_directory (${LIBJSON_SOURCE_DIR} LIBJSON_SOURCE_FILES) 62 | add_library (libjson STATIC ${LIBJSON_SOURCE_FILES}) 63 | 64 | # remove "lib" prefix from the name of the libjson archive 65 | set_target_properties (libjson PROPERTIES PREFIX "") 66 | 67 | # set some properties when CMAKE_BUILD_TYPE is "Debug" 68 | set_target_properties (libjson PROPERTIES 69 | COMPILE_DEFINITIONS_DEBUG "JSON_DEBUG;JSON_SAFE;JSON_ISO_STRICT" 70 | DEBUG_POSTFIX "d") 71 | 72 | list (APPEND LIBS libjson) 73 | 74 | #------------------------------------------------------------------------------- 75 | # Add the executable 'kph' 76 | #------------------------------------------------------------------------------- 77 | add_executable (kph kph.cpp) 78 | set_target_properties (kph PROPERTIES 79 | COMPILE_DEFINITIONS_DEBUG "JSON_DEBUG;JSON_SAFE;JSON_ISO_STRICT") 80 | target_link_libraries (kph ${LIBS}) 81 | 82 | #------------------------------------------------------------------------------- 83 | # Add the executable 'krt' 84 | #------------------------------------------------------------------------------- 85 | add_executable (krt krt.cpp) 86 | set_target_properties (krt PROPERTIES 87 | COMPILE_DEFINITIONS_DEBUG "JSON_DEBUG;JSON_SAFE;JSON_ISO_STRICT") 88 | target_link_libraries (krt ${LIBS}) 89 | 90 | #------------------------------------------------------------------------------- 91 | # Add the executable 'private_method' 92 | #------------------------------------------------------------------------------- 93 | add_executable (private_method examples/private_method.cpp kapi.cpp) 94 | set_target_properties (private_method PROPERTIES 95 | COMPILE_DEFINITIONS_DEBUG "JSON_DEBUG;JSON_SAFE;JSON_ISO_STRICT") 96 | target_link_libraries (private_method ${LIBS}) 97 | 98 | #------------------------------------------------------------------------------- 99 | # Add the executable 'public_method' 100 | #------------------------------------------------------------------------------- 101 | add_executable (public_method examples/public_method.cpp kapi.cpp) 102 | set_target_properties (public_method PROPERTIES 103 | COMPILE_DEFINITIONS_DEBUG "JSON_DEBUG;JSON_SAFE;JSON_ISO_STRICT") 104 | target_link_libraries (public_method ${LIBS}) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 - Marco E. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | krakenapi 2 | ========= 3 | 4 | A C++ library for interfacing with the Kraken REST API (kraken.com). 5 | 6 | Other programs 7 | ============== 8 | 9 | krt 10 | --- 11 | 12 | Source file of this program is krt.cpp. 13 | 14 | ### What is krt? 15 | 16 | krt is a program to download Recent Trades from Kraken market data through API. 17 | 18 | ### How trades are displayed? 19 | 20 | Recent trades are printed out to standard output in CSV format. The order of fields is "Time", "Order", "Price" and "Volume". 21 | 22 | ### Command line arguments 23 | 24 | usage: krt \ \[interval\] \[since\] 25 | 26 | krt can get the following command line arguments: 27 | 28 | \ 29 | Asset pair to get trade data for. 30 | 31 | \[since\] 32 | (Optional) the program returns trade data since given id. By default [since] is equal 33 | to "0" to indicate the oldest possible trade data. 34 | 35 | \[interval\] 36 | (Optional) how many seconds the program has to download new trade data. 37 | By default the program doesn't use this parameter and it exits immidiatly after 38 | download trade data. If [interval] is equal to 0 the program will not 39 | use this parameter. 40 | -------------------------------------------------------------------------------- /candlesticks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "kapi.hpp" 8 | #include "libjson/libjson.h" 9 | 10 | using namespace std; 11 | using namespace Kraken; 12 | 13 | //------------------------------------------------------------------------------ 14 | // deals with Kraken trades: 15 | struct Trade { 16 | double price, volume; 17 | time_t time; 18 | char order; 19 | 20 | Trade(JSONNode node) { 21 | price = node[0].as_float(); 22 | volume = node[1].as_float(); 23 | time = node[2].as_int(); 24 | order = node[3].as_string()[0]; 25 | } 26 | }; 27 | 28 | //------------------------------------------------------------------------------ 29 | // prints out a kraken trade: 30 | ostream& operator<<(ostream& os, const Trade& t) 31 | { 32 | return os << '"' 33 | << t.time << "\",\"" 34 | << t.order << "\",\"" 35 | << fixed 36 | << setprecision(5) << t.price << "\",\"" 37 | << setprecision(9) << t.volume << '"'; 38 | } 39 | 40 | //------------------------------------------------------------------------------ 41 | // helper types to map time to a group of trades: 42 | typedef vector Period; 43 | typedef map Period_map; 44 | 45 | //------------------------------------------------------------------------------ 46 | // deal with candlesticks: 47 | struct Candlestick { 48 | double open, close, low, high; 49 | double volume; 50 | time_t time; 51 | }; 52 | 53 | //------------------------------------------------------------------------------ 54 | struct HA_Candlestick : public Candlestick { 55 | 56 | // create a candlestick from current period 57 | HA_Candlestick(const Candlestick& curr) 58 | { 59 | time = curr.time; 60 | volume = curr.volume; 61 | close = (curr.open + curr.close + curr.low + curr.high) / 4; 62 | open = (curr.open + curr.close) / 2; 63 | low = min(curr.low, min(open, close)); 64 | high = max(curr.high, max(open, close)); 65 | } 66 | 67 | // create a HA candlestick from current period 68 | // and WITH a prior HA candlestick 69 | HA_Candlestick(const Candlestick& curr, const HA_Candlestick& prior) 70 | { 71 | time = curr.time; 72 | volume = curr.volume; 73 | close = (curr.open + curr.close + curr.low + curr.high) / 4; 74 | open = (prior.open + prior.close) / 2; 75 | low = min(curr.low, min(open, close)); 76 | high = max(curr.high, max(open, close)); 77 | } 78 | }; 79 | 80 | //------------------------------------------------------------------------------ 81 | // prints out a Candlestick 82 | ostream& operator<<(ostream& os, const Candlestick& c) 83 | { 84 | struct tm timeinfo; 85 | localtime_r(&c.time, &timeinfo); 86 | 87 | return os << c.time << ',' 88 | << fixed << setprecision(5) 89 | << c.open << ',' 90 | << c.high << ',' 91 | << c.low << ',' 92 | << c.close << ',' 93 | << setprecision(9) 94 | << c.volume; 95 | } 96 | 97 | //------------------------------------------------------------------------------ 98 | // downloads recent trades: 99 | string recent_trades(const KAPI& k, const KAPI::Input& i, vector& v) 100 | { 101 | string json_data = k.public_method("Trades", i); 102 | JSONNode root = libjson::parse(json_data); 103 | //cout << json_data << endl; 104 | 105 | // throw an exception if there are errors in the JSON response 106 | if (!root.at("error").empty()) { 107 | std::ostringstream oss; 108 | oss << "Kraken response contains errors: "; 109 | 110 | // append errors to output string stream 111 | for (auto it = root["error"].begin(); it != root["error"].end(); ++it) 112 | oss << endl << " * " << libjson::to_std_string(it->as_string()); 113 | 114 | throw runtime_error(oss.str()); 115 | } 116 | 117 | // throw an exception if result is empty 118 | if (root.at("result").empty()) { 119 | throw runtime_error("Kraken response doesn't contain result data"); 120 | } 121 | 122 | const string& pair = i.at("pair"); 123 | 124 | JSONNode& result = root["result"]; 125 | JSONNode& result_pair = result.at(pair); 126 | 127 | vector output; 128 | for (JSONNode::iterator it = result_pair.begin(); 129 | it != result_pair.end(); ++it) 130 | output.push_back(Trade(*it)); 131 | 132 | output.swap(v); 133 | return libjson::to_std_string( result.at("last").as_string() ); 134 | } 135 | 136 | //------------------------------------------------------------------------------ 137 | // fills a candlestick vector grouping trades by time: 138 | void group_by_time(const vector& trades, 139 | const time_t step, 140 | vector& candlesticks) 141 | { 142 | vector::const_iterator it = trades.begin(); 143 | 144 | while (it != trades.end()) { 145 | Candlestick period; 146 | period.volume = 0; 147 | period.open = it->price; 148 | period.low = it->price; 149 | period.high = it->price; 150 | 151 | // the period time 152 | period.time = it->time - (it->time % step); 153 | 154 | while (it != trades.end() && it->time < (period.time+step)) { 155 | // the lowest price 156 | if (it->price < period.low) 157 | period.low = it->price; 158 | 159 | // the highest price 160 | if (it->price > period.high) 161 | period.high = it->price; 162 | 163 | // sum volumes 164 | period.volume += it->volume; 165 | 166 | // last price is close time 167 | period.close = it->price; 168 | 169 | // next element 170 | it++; 171 | } 172 | 173 | // store period 174 | candlesticks.push_back(period); 175 | 176 | // next group 177 | } 178 | } 179 | 180 | //------------------------------------------------------------------------------ 181 | 182 | int main(int argc, char* argv[]) 183 | { 184 | try { 185 | time_t step = 15*60; // by default 15 minutes 186 | time_t last = 24*60*60; // by default last 24 hours 187 | 188 | // 189 | // usage: prog [seconds] [last] 190 | // 191 | // kph prints out the price history of the in 192 | // the [last] number of seconds. The trade data is 193 | // showed as candlesticks grouped in periods of 194 | // [seconds] seconds. 195 | // 196 | 197 | KAPI::Input input; 198 | input["since"] = "0"; 199 | 200 | switch (argc) { 201 | case 4: 202 | istringstream(argv[3]) >> last; 203 | case 3: 204 | istringstream(argv[2]) >> step; 205 | case 2: 206 | input["pair"] = std::string(argv[1]); 207 | break; 208 | default: 209 | throw std::runtime_error("wrong number of arguments"); 210 | }; 211 | 212 | // initialize kraken lib's resources: 213 | Kraken::initialize(); 214 | KAPI kapi; 215 | 216 | std::vector trades; 217 | std::vector candlesticks; 218 | 219 | recent_trades(kapi, input, trades); 220 | 221 | // group trades by time 222 | group_by_time(trades, step, candlesticks); 223 | 224 | if (!candlesticks.empty()) { 225 | // print candlestick after this threshold 226 | time_t thresh = candlesticks.back().time - last; 227 | 228 | auto it = candlesticks.cbegin(); 229 | HA_Candlestick ha(*it); 230 | if (ha.time > thresh) 231 | cout << ha << endl; 232 | 233 | for (++it; it != candlesticks.cend(); ++it) { 234 | ha = HA_Candlestick(*it, ha); 235 | if (ha.time >= thresh) 236 | cout << ha << endl; 237 | } 238 | } 239 | } 240 | catch(exception& e) { 241 | cerr << "Error: " << e.what() << endl; 242 | } 243 | catch(...) { 244 | cerr << "Unknow exception." << endl; 245 | } 246 | 247 | curl_global_cleanup(); 248 | return 0; 249 | } 250 | -------------------------------------------------------------------------------- /examples/private_method.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../kapi.hpp" 5 | 6 | using namespace std; 7 | using namespace Kraken; 8 | 9 | constexpr char api_key[] = "your API key here"; 10 | constexpr char api_private_key[] = "your API private key here"; 11 | 12 | int main() 13 | { 14 | curl_global_init(CURL_GLOBAL_ALL); 15 | 16 | try { 17 | KAPI kapi(api_key, api_private_key); 18 | KAPI::Input in; 19 | 20 | in.insert(make_pair("pair", "XXBTZUSD")); 21 | in.insert(make_pair("type", "buy")); 22 | in.insert(make_pair("ordertype", "limit")); 23 | in.insert(make_pair("price", "45000.1")); 24 | in.insert(make_pair("volume", "2.1234")); 25 | in.insert(make_pair("leverage", "2:1")); 26 | in.insert(make_pair("close[ordertype]", "stop-loss-limit")); 27 | in.insert(make_pair("close[price]", "38000")); 28 | in.insert(make_pair("close[price2]", "36000")); 29 | 30 | cout << kapi.private_method("AddOrder", in) << endl; 31 | } 32 | catch(exception& e) { 33 | cerr << "Error: " << e.what() << endl; 34 | } 35 | catch(...) { 36 | cerr << "Unknown exception." << endl; 37 | } 38 | 39 | curl_global_cleanup(); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /examples/public_method.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../kapi.hpp" 5 | 6 | using namespace std; 7 | using namespace Kraken; 8 | 9 | //------------------------------------------------------------------------------ 10 | 11 | int main() 12 | { 13 | curl_global_init(CURL_GLOBAL_ALL); 14 | 15 | try { 16 | KAPI kapi; 17 | KAPI::Input in; 18 | 19 | // get recent trades 20 | in.insert(make_pair("pair", "XXBTZEUR")); 21 | cout << kapi.public_method("Trades", in) << endl; 22 | } 23 | catch(exception& e) { 24 | cerr << "Error: " << e.what() << endl; 25 | } 26 | catch(...) { 27 | cerr << "Unknow exception." << endl; 28 | } 29 | 30 | curl_global_cleanup(); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /kapi.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "kapi.hpp" 15 | 16 | #define CURL_VERBOSE 0L //1L = enabled, 0L = disabled 17 | 18 | //------------------------------------------------------------------------------ 19 | 20 | namespace Kraken { 21 | 22 | //------------------------------------------------------------------------------ 23 | // helper function to compute SHA256: 24 | static std::vector sha256(const std::string& data) 25 | { 26 | std::vector digest(SHA256_DIGEST_LENGTH); 27 | 28 | SHA256_CTX ctx; 29 | SHA256_Init(&ctx); 30 | SHA256_Update(&ctx, data.c_str(), data.length()); 31 | SHA256_Final(digest.data(), &ctx); 32 | 33 | return digest; 34 | } 35 | 36 | //------------------------------------------------------------------------------ 37 | // helper function to decode a base64 string to a vector of bytes: 38 | static std::vector b64_decode(const std::string& data) 39 | { 40 | BIO* b64 = BIO_new(BIO_f_base64()); 41 | BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); 42 | 43 | BIO* bmem = BIO_new_mem_buf((void*)data.c_str(),data.length()); 44 | bmem = BIO_push(b64, bmem); 45 | 46 | std::vector output(data.length()); 47 | int decoded_size = BIO_read(bmem, output.data(), output.size()); 48 | BIO_free_all(bmem); 49 | 50 | if (decoded_size < 0) 51 | throw std::runtime_error("failed while decoding base64."); 52 | 53 | return output; 54 | } 55 | 56 | //------------------------------------------------------------------------------ 57 | // helper function to encode a vector of bytes to a base64 string: 58 | static std::string b64_encode(const std::vector& data) 59 | { 60 | BIO* b64 = BIO_new(BIO_f_base64()); 61 | BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); 62 | 63 | BIO* bmem = BIO_new(BIO_s_mem()); 64 | b64 = BIO_push(b64, bmem); 65 | 66 | BIO_write(b64, data.data(), data.size()); 67 | BIO_flush(b64); 68 | 69 | BUF_MEM* bptr = NULL; 70 | BIO_get_mem_ptr(b64, &bptr); 71 | 72 | std::string output(bptr->data, bptr->length); 73 | BIO_free_all(b64); 74 | 75 | return output; 76 | } 77 | 78 | //------------------------------------------------------------------------------ 79 | // helper function to hash with HMAC algorithm: 80 | static std::vector 81 | hmac_sha512(const std::vector& data, 82 | const std::vector& key) 83 | { 84 | unsigned int len = EVP_MAX_MD_SIZE; 85 | std::vector digest(len); 86 | 87 | HMAC_CTX *ctx = HMAC_CTX_new(); 88 | if (ctx == NULL) { 89 | throw std::runtime_error("cannot create HMAC_CTX"); 90 | } 91 | 92 | HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha512(), NULL); 93 | HMAC_Update(ctx, data.data(), data.size()); 94 | HMAC_Final(ctx, digest.data(), &len); 95 | 96 | HMAC_CTX_free(ctx); 97 | 98 | return digest; 99 | } 100 | 101 | 102 | //------------------------------------------------------------------------------ 103 | // builds a query string from KAPI::Input (a=1&b=2&...) 104 | static std::string build_query(const KAPI::Input& input) 105 | { 106 | std::ostringstream oss; 107 | KAPI::Input::const_iterator it = input.begin(); 108 | for (; it != input.end(); ++it) { 109 | if (it != input.begin()) oss << '&'; // delimiter 110 | oss << it->first <<'='<< it->second; 111 | } 112 | 113 | return oss.str(); 114 | } 115 | 116 | //------------------------------------------------------------------------------ 117 | // helper function to create a nonce: 118 | static std::string create_nonce() 119 | { 120 | std::ostringstream oss; 121 | 122 | timeval tp; 123 | if (gettimeofday(&tp, NULL) != 0) { 124 | oss << "gettimeofday() failed: " << strerror(errno); 125 | throw std::runtime_error(oss.str()); 126 | } 127 | else { 128 | // format output string 129 | oss << std::setfill('0') 130 | << std::setw(10) << tp.tv_sec 131 | << std::setw(6) << tp.tv_usec; 132 | } 133 | return oss.str(); 134 | } 135 | 136 | //------------------------------------------------------------------------------ 137 | // constructor with all explicit parameters 138 | KAPI::KAPI(const std::string& key, const std::string& secret, 139 | const std::string& url, const std::string& version) 140 | :key_(key), secret_(secret), url_(url), version_(version) 141 | { 142 | init(); 143 | } 144 | 145 | //------------------------------------------------------------------------------ 146 | // default API base URL and API version 147 | KAPI::KAPI(const std::string& key, const std::string& secret) 148 | :key_(key), secret_(secret), url_("https://api.kraken.com"), version_("0") 149 | { 150 | init(); 151 | } 152 | 153 | //------------------------------------------------------------------------------ 154 | // constructor with empty API key and API secret 155 | KAPI::KAPI() 156 | :key_(""), secret_(""), url_("https://api.kraken.com"), version_("0") 157 | { 158 | init(); 159 | } 160 | 161 | //------------------------------------------------------------------------------ 162 | // initializes libcurl: 163 | void KAPI::init() 164 | { 165 | curl_ = curl_easy_init(); 166 | if (curl_) { 167 | curl_easy_setopt(curl_, CURLOPT_VERBOSE, CURL_VERBOSE); 168 | curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYPEER, 1L); 169 | curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYHOST, 2L); 170 | curl_easy_setopt(curl_, CURLOPT_USERAGENT, "Kraken C++ API Client"); 171 | curl_easy_setopt(curl_, CURLOPT_POST, 1L); 172 | // set callback function 173 | curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, KAPI::write_cb); 174 | } 175 | else { 176 | throw std::runtime_error("can't create curl handle"); 177 | } 178 | } 179 | 180 | //------------------------------------------------------------------------------ 181 | // destructor: 182 | KAPI::~KAPI() 183 | { 184 | curl_easy_cleanup(curl_); 185 | } 186 | 187 | //------------------------------------------------------------------------------ 188 | // returns message signature generated from a URI path, a nonce 189 | // and postdata, message signature is created as a follows: 190 | // 191 | // hmac_sha512(path + sha256(nonce + postdata), b64decode(secret)) 192 | // 193 | // and the result is converted in a base64 string: 194 | std::string KAPI::signature(const std::string& path, 195 | const std::string& nonce, 196 | const std::string& postdata) const 197 | { 198 | // add path to data to encrypt 199 | std::vector data(path.begin(), path.end()); 200 | 201 | // concatenate nonce and postdata and compute SHA256 202 | std::vector nonce_postdata = sha256(nonce + postdata); 203 | 204 | // concatenate path and nonce_postdata (path + sha256(nonce + postdata)) 205 | data.insert(data.end(), nonce_postdata.begin(), nonce_postdata.end()); 206 | 207 | // and compute HMAC 208 | return b64_encode( hmac_sha512(data, b64_decode(secret_)) ); 209 | } 210 | 211 | //------------------------------------------------------------------------------ 212 | // CURL write function callback: 213 | size_t KAPI::write_cb(char* ptr, size_t size, size_t nmemb, void* userdata) 214 | { 215 | std::string* response = reinterpret_cast(userdata); 216 | size_t real_size = size * nmemb; 217 | 218 | response->append(ptr, real_size); 219 | return real_size; 220 | } 221 | 222 | //------------------------------------------------------------------------------ 223 | // deals with public API methods: 224 | std::string KAPI::public_method(const std::string& method, 225 | const KAPI::Input& input) const 226 | { 227 | // build method URL 228 | std::string path = "/" + version_ + "/public/" + method; 229 | std::string method_url = url_ + path + "?" + build_query(input); 230 | curl_easy_setopt(curl_, CURLOPT_URL, method_url.c_str()); 231 | 232 | // reset the http header 233 | curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, NULL); 234 | 235 | // where CURL write callback function stores the response 236 | std::string response; 237 | curl_easy_setopt(curl_, CURLOPT_WRITEDATA, static_cast(&response)); 238 | 239 | // Set GET method 240 | curl_easy_setopt(curl_, CURLOPT_HTTPGET, 1L); 241 | 242 | // perform CURL request 243 | CURLcode result = curl_easy_perform(curl_); 244 | if (result != CURLE_OK) { 245 | std::ostringstream oss; 246 | oss << "curl_easy_perform() failed: "<< curl_easy_strerror(result); 247 | throw std::runtime_error(oss.str()); 248 | } 249 | 250 | return response; 251 | } 252 | 253 | //------------------------------------------------------------------------------ 254 | // deals with private API methods: 255 | std::string KAPI::private_method(const std::string& method, 256 | const KAPI::Input& input) const 257 | { 258 | // build method URL 259 | std::string path = "/" + version_ + "/private/" + method; 260 | std::string method_url = url_ + path; 261 | 262 | curl_easy_setopt(curl_, CURLOPT_URL, method_url.c_str()); 263 | 264 | // create a nonce and and postdata 265 | std::string nonce = create_nonce(); 266 | std::string postdata = "nonce=" + nonce; 267 | 268 | // if 'input' is not empty generate other postdata 269 | if (!input.empty()) 270 | postdata = postdata + "&" + build_query(input); 271 | curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, postdata.c_str()); 272 | 273 | // add custom header 274 | curl_slist* chunk = NULL; 275 | 276 | std::string key_header = "API-Key: " + key_; 277 | std::string sign_header = "API-Sign: " + signature(path, nonce, postdata); 278 | 279 | chunk = curl_slist_append(chunk, key_header.c_str()); 280 | chunk = curl_slist_append(chunk, sign_header.c_str()); 281 | curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, chunk); 282 | 283 | // where CURL write callback function stores the response 284 | std::string response; 285 | curl_easy_setopt(curl_, CURLOPT_WRITEDATA, static_cast(&response)); 286 | 287 | // perform CURL request 288 | CURLcode result = curl_easy_perform(curl_); 289 | 290 | // free the custom headers 291 | curl_slist_free_all(chunk); 292 | 293 | // check perform result 294 | if (result != CURLE_OK) { 295 | std::ostringstream oss; 296 | oss << "curl_easy_perform() failed: " << curl_easy_strerror(result); 297 | throw std::runtime_error(oss.str()); 298 | } 299 | 300 | return response; 301 | } 302 | 303 | //------------------------------------------------------------------------------ 304 | // helper function to initialize Kraken API library's resources: 305 | void initialize() 306 | { 307 | CURLcode code = curl_global_init(CURL_GLOBAL_ALL); 308 | if (code != CURLE_OK) { 309 | std::ostringstream oss; 310 | oss << "curl_global_init() failed: " << curl_easy_strerror(code); 311 | throw std::runtime_error(oss.str()); 312 | } 313 | } 314 | 315 | //------------------------------------------------------------------------------ 316 | // helper function to terminate Kraken API library's resources: 317 | void terminate() 318 | { 319 | curl_global_cleanup(); 320 | } 321 | 322 | //------------------------------------------------------------------------------ 323 | 324 | } //namespace Kraken 325 | 326 | //------------------------------------------------------------------------------ 327 | -------------------------------------------------------------------------------- /kapi.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _KRAKEN_KAPI_HPP_ 2 | #define _KRAKEN_KAPI_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Kraken { 12 | 13 | //------------------------------------------------------------------------------ 14 | 15 | class KAPI { 16 | public: 17 | // helper type to make requests 18 | typedef std::map Input; 19 | 20 | // constructor with all explicit parameters 21 | KAPI(const std::string& key, const std::string& secret, 22 | const std::string& url, const std::string& version); 23 | 24 | // default API base URL and API version 25 | KAPI(const std::string& key, const std::string& secret); 26 | 27 | // constructor with empty API key and API secret 28 | KAPI(); 29 | 30 | // destructor 31 | ~KAPI(); 32 | 33 | // makes public method to kraken.com 34 | std::string public_method(const std::string& method, 35 | const KAPI::Input& input) const; 36 | 37 | // makes private method to kraken.com 38 | std::string private_method(const std::string& method, 39 | const KAPI::Input& input) const; 40 | 41 | 42 | // TODO: public market data 43 | //void time(); 44 | //void assets(); 45 | 46 | private: 47 | // init CURL and other stuffs 48 | void init(); 49 | 50 | // TODO: gather common commands from public_method and 51 | // private_method in a single method: curl_perform 52 | 53 | // create signature for private requests 54 | std::string signature(const std::string& path, 55 | const std::string& nonce, 56 | const std::string& postdata) const; 57 | 58 | // CURL callback 59 | static size_t write_cb(char* ptr, size_t size, 60 | size_t nmemb, void* userdata); 61 | 62 | std::string key_; // API key 63 | std::string secret_; // API secret 64 | std::string url_; // API base URL 65 | std::string version_; // API version 66 | CURL* curl_; // CURL handle 67 | 68 | // disallow copying 69 | KAPI(const KAPI&); 70 | KAPI& operator=(const KAPI&); 71 | }; 72 | 73 | //------------------------------------------------------------------------------ 74 | // helper functions to initialize and terminate Kraken API library. 75 | // KAPI uses CURL, the latter has a no thread-safe function called 76 | // curl_global_init(). 77 | 78 | void initialize(); 79 | void terminate(); 80 | 81 | //------------------------------------------------------------------------------ 82 | 83 | }; // namespace Kraken 84 | 85 | //------------------------------------------------------------------------------ 86 | 87 | #endif 88 | 89 | 90 | -------------------------------------------------------------------------------- /kmarketdata.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "kapi.hpp" 8 | #include "libjson/libjson.h" 9 | 10 | using namespace std; 11 | using namespace Kraken; 12 | 13 | //------------------------------------------------------------------------------ 14 | // deals with Trades: 15 | struct Trade { 16 | double price, volume; 17 | time_t time; 18 | char order; 19 | }; 20 | 21 | //------------------------------------------------------------------------------ 22 | // prints a Trade 23 | ostream& operator<<(ostream& os, const Trade& t) 24 | { 25 | struct tm timeinfo; 26 | gmtime_r(&t.time, &timeinfo); 27 | 28 | char buffer[20]; 29 | strftime(buffer, 20, "%T", &timeinfo); 30 | 31 | return os << buffer << ',' 32 | << t.order << ',' 33 | << fixed 34 | << setprecision(5) << t.price << ',' 35 | << setprecision(9) << t.volume; 36 | } 37 | 38 | //------------------------------------------------------------------------------ 39 | // helper function to load a Trade from a JSONNode: 40 | Trade get_trade(const JSONNode& node) 41 | { 42 | Trade t; 43 | t.price = node[0].as_float(); 44 | t.volume = node[1].as_float(); 45 | t.time = node[2].as_int(); 46 | t.order = node[3].as_string()[0]; 47 | return t; 48 | } 49 | 50 | //------------------------------------------------------------------------------ 51 | // helper types to map time to a group of trades: 52 | typedef vector Period; 53 | typedef map Period_map; 54 | 55 | //------------------------------------------------------------------------------ 56 | // deal with candlesticks: 57 | struct Candlestick { 58 | double open, close, low, high; 59 | double volume; 60 | time_t time; 61 | 62 | // create a HA candlestick from a period of trades 63 | // WITHOUT a prior HA candlestick 64 | Candlestick(time_t t, const Period& p) 65 | : time(t), volume(0) 66 | { 67 | double p_open = p.front().price; 68 | double p_close = p.back().price; 69 | init(p, p_open, p_close); 70 | } 71 | 72 | // create a HA candlestick from a period of trades 73 | // WITH a prior HA candlestick 74 | Candlestick(time_t t, const Period& p, const Candlestick& prior) 75 | : time(t), volume(0) 76 | { 77 | // initialize using prior HA candlestick's open-close values 78 | init(p, prior.open, prior.close); 79 | } 80 | 81 | private: 82 | // initialize the HA candlestick 83 | void init(const Period& p, double ha_open, double ha_close) { 84 | 85 | // return if the Period is empty 86 | if (p.empty()) return; 87 | 88 | // initialize period values 89 | double p_open = p.front().price; 90 | double p_close = p.back().price; 91 | double p_low = min(p_open, p_close); 92 | double p_high = max(p_open, p_close); 93 | 94 | // find low price and high price of the current period 95 | for(Period::const_iterator it = p.begin(); it != p.end(); ++it) { 96 | if (it->price < p_low) p_low = it->price; 97 | if (it->price > p_high) p_high = it->price; 98 | volume += it->volume; 99 | } 100 | 101 | // compute Heikin-Ashi values 102 | close = (p_open + p_close + p_low + p_high) / 4; 103 | open = (ha_open + ha_close) / 2; 104 | low = min(p_low, min(open, close)); 105 | high = max(p_high, max(open, close)); 106 | } 107 | 108 | }; 109 | 110 | //------------------------------------------------------------------------------ 111 | // prints out a Candlestick 112 | ostream& operator<<(ostream& os, const Candlestick& c) 113 | { 114 | struct tm timeinfo; 115 | localtime_r(&c.time, &timeinfo); 116 | 117 | char buffer[20]; 118 | strftime(buffer, 20, "%T", &timeinfo); 119 | 120 | return os << buffer << ',' 121 | << fixed << setprecision(5) 122 | << c.open << ',' 123 | << c.high << ',' 124 | << c.low << ',' 125 | << c.close << ',' 126 | << setprecision(9) 127 | << c.volume; 128 | } 129 | 130 | //------------------------------------------------------------------------------ 131 | // creates candlesticks from a Period_map 132 | void append_candlesticks(const Period_map& pm, vector& c) 133 | { 134 | // if there are no periods do nothing 135 | if (pm.empty()) return; 136 | 137 | Period_map::const_iterator it = pm.begin(); 138 | 139 | if (c.empty()) 140 | c.push_back(Candlestick(it->first, it->second)); 141 | 142 | for (++it; it != pm.end(); ++it) 143 | c.push_back(Candlestick(it->first, it->second, c.back())); 144 | } 145 | 146 | //------------------------------------------------------------------------------ 147 | 148 | int main() 149 | { 150 | curl_global_init(CURL_GLOBAL_ALL); 151 | 152 | try { 153 | KAPI kapi; 154 | KAPI::Input in; 155 | 156 | // get recent trades 157 | in.insert(make_pair("pair", "XLTCZEUR")); 158 | 159 | string json_trades = kapi.public_method("Trades", in); 160 | JSONNode root = libjson::parse(json_trades); 161 | 162 | // check for errors, if they're present an 163 | // exception will be thrown 164 | if (!root.at("error").empty()) { 165 | ostringstream oss; 166 | oss << "Kraken response contains errors: "; 167 | 168 | // append errors to output string stream 169 | for (JSONNode::iterator it = root["error"].begin(); 170 | it != root["error"].end(); ++it) 171 | oss << endl << " * " << libjson::to_std_string(it->as_string()); 172 | 173 | throw runtime_error(oss.str()); 174 | } 175 | else { 176 | // format the output in columns: time, order, price and volume 177 | JSONNode result = root.at("result")[0]; 178 | 179 | time_t step = 3600; 180 | Period_map periods; 181 | 182 | // group results by base time 183 | for (JSONNode::const_iterator it = result.begin(); 184 | it != result.end(); ++it) { 185 | Trade t = get_trade(*it); 186 | time_t x = t.time - (t.time % step); 187 | periods[x].push_back(t); 188 | } 189 | 190 | vector candlesticks; 191 | 192 | // create candlesticks 193 | append_candlesticks(periods, candlesticks); 194 | 195 | // print candlesticks 196 | for (int i = 0; i [seconds] [last] 14 | 15 | where: 16 | 17 | - it's the pair to download from kraken.com 18 | [seconds] - (optional) the seconds of the period (by default 15*60) 19 | [last] - (optional) the last seconds to consider from the last 20 | trade (by default 24*60*60) 21 | 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "kraken/kclient.hpp" 31 | #include "kraken/ktrade.hpp" 32 | #include "libjson/libjson.h" 33 | 34 | using namespace std; 35 | using namespace Kraken; 36 | 37 | //------------------------------------------------------------------------------ 38 | // helper types to map time to a group of trades: 39 | typedef vector Period; 40 | typedef map Period_map; 41 | 42 | //------------------------------------------------------------------------------ 43 | // deal with candlesticks: 44 | struct Candlestick { 45 | double open, close, low, high; 46 | double volume; 47 | time_t time; 48 | }; 49 | 50 | //------------------------------------------------------------------------------ 51 | struct HA_Candlestick : public Candlestick { 52 | 53 | // create a candlestick from current period 54 | HA_Candlestick(const Candlestick& curr) 55 | { 56 | time = curr.time; 57 | volume = curr.volume; 58 | close = (curr.open + curr.close + curr.low + curr.high) / 4; 59 | open = (curr.open + curr.close) / 2; 60 | low = min(curr.low, min(open, close)); 61 | high = max(curr.high, max(open, close)); 62 | } 63 | 64 | // create a HA candlestick from current period 65 | // and WITH a prior HA candlestick 66 | HA_Candlestick(const Candlestick& curr, const HA_Candlestick& prior) 67 | { 68 | time = curr.time; 69 | volume = curr.volume; 70 | close = (curr.open + curr.close + curr.low + curr.high) / 4; 71 | open = (prior.open + prior.close) / 2; 72 | low = min(curr.low, min(open, close)); 73 | high = max(curr.high, max(open, close)); 74 | } 75 | }; 76 | 77 | //------------------------------------------------------------------------------ 78 | // prints out a Candlestick 79 | ostream& operator<<(ostream& os, const Candlestick& c) 80 | { 81 | struct tm timeinfo; 82 | localtime_r(&c.time, &timeinfo); 83 | 84 | return os << c.time << ',' 85 | << fixed << setprecision(5) 86 | << c.open << ',' 87 | << c.high << ',' 88 | << c.low << ',' 89 | << c.close << ',' 90 | << setprecision(9) 91 | << c.volume; 92 | } 93 | 94 | //------------------------------------------------------------------------------ 95 | // fills a candlestick vector grouping trades by time: 96 | void group_by_time(const vector& trades, 97 | const time_t step, 98 | vector& candlesticks) 99 | { 100 | vector::const_iterator it = trades.begin(); 101 | 102 | while (it != trades.end()) { 103 | Candlestick period; 104 | period.volume = 0; 105 | period.open = it->price; 106 | period.low = it->price; 107 | period.high = it->price; 108 | 109 | // the period time 110 | period.time = it->time - (it->time % step); 111 | 112 | while (it != trades.end() && it->time < (period.time+step)) { 113 | // the lowest price 114 | if (it->price < period.low) 115 | period.low = it->price; 116 | 117 | // the highest price 118 | if (it->price > period.high) 119 | period.high = it->price; 120 | 121 | // sum volumes 122 | period.volume += it->volume; 123 | 124 | // last price is close time 125 | period.close = it->price; 126 | 127 | // next element 128 | it++; 129 | } 130 | 131 | // store period 132 | candlesticks.push_back(period); 133 | 134 | // next group 135 | } 136 | } 137 | 138 | //------------------------------------------------------------------------------ 139 | 140 | int main(int argc, char* argv[]) 141 | { 142 | try { 143 | time_t step = 15*60; // by default 15 minutes 144 | time_t last = 24*60*60; // by default last 24 hours 145 | 146 | // 147 | // usage: kph [seconds] [last] 148 | // 149 | // kph prints out the price history of the in 150 | // the [last] number of seconds. The trade data is 151 | // showed as candlesticks grouped in periods of 152 | // [seconds] seconds. 153 | // 154 | 155 | string pair; 156 | 157 | switch (argc) { 158 | case 4: 159 | istringstream(argv[3]) >> last; 160 | case 3: 161 | istringstream(argv[2]) >> step; 162 | case 2: 163 | pair = std::string(argv[1]); 164 | break; 165 | default: 166 | throw std::runtime_error("wrong number of arguments"); 167 | }; 168 | 169 | // initialize kraken lib's resources: 170 | Kraken::initialize(); 171 | 172 | KClient kc; 173 | 174 | vector trades; 175 | kc.trades(pair, "0", trades); 176 | 177 | 178 | // group trades by time 179 | vector candlesticks; 180 | group_by_time(trades, step, candlesticks); 181 | 182 | if (!candlesticks.empty()) { 183 | // print candlestick after this threshold 184 | time_t thresh = candlesticks.back().time - last; 185 | 186 | std::vector::const_iterator it = candlesticks.begin(); 187 | HA_Candlestick ha(*it); 188 | if (ha.time > thresh) 189 | cout << ha << endl; 190 | 191 | for (++it; it != candlesticks.end(); ++it) { 192 | ha = HA_Candlestick(*it, ha); 193 | if (ha.time >= thresh) 194 | cout << ha << endl; 195 | } 196 | } 197 | } 198 | catch(exception& e) { 199 | cerr << "Error: " << e.what() << endl; 200 | return 1; 201 | } 202 | catch(...) { 203 | cerr << "Unknown exception." << endl; 204 | return 1; 205 | } 206 | 207 | curl_global_cleanup(); 208 | return 0; 209 | } 210 | -------------------------------------------------------------------------------- /kraken/kclient.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "kclient.hpp" 15 | #include "../libjson/libjson.h" 16 | 17 | #define CURL_VERBOSE 0L //1L = enabled, 0L = disabled 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | namespace Kraken { 22 | 23 | //------------------------------------------------------------------------------ 24 | // helper function to compute SHA256: 25 | static std::vector sha256(const std::string& data) 26 | { 27 | std::vector digest(SHA256_DIGEST_LENGTH); 28 | 29 | SHA256_CTX ctx; 30 | SHA256_Init(&ctx); 31 | SHA256_Update(&ctx, data.c_str(), data.length()); 32 | SHA256_Final(digest.data(), &ctx); 33 | 34 | return digest; 35 | } 36 | 37 | //------------------------------------------------------------------------------ 38 | // helper function to decode a base64 string to a vector of bytes: 39 | static std::vector b64_decode(const std::string& data) 40 | { 41 | BIO* b64 = BIO_new(BIO_f_base64()); 42 | BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); 43 | 44 | BIO* bmem = BIO_new_mem_buf((void*)data.c_str(),data.length()); 45 | bmem = BIO_push(b64, bmem); 46 | 47 | std::vector output(data.length()); 48 | int decoded_size = BIO_read(bmem, output.data(), output.size()); 49 | BIO_free_all(bmem); 50 | 51 | if (decoded_size < 0) 52 | throw std::runtime_error("failed while decoding base64."); 53 | 54 | return output; 55 | } 56 | 57 | //------------------------------------------------------------------------------ 58 | // helper function to encode a vector of bytes to a base64 string: 59 | static std::string b64_encode(const std::vector& data) 60 | { 61 | BIO* b64 = BIO_new(BIO_f_base64()); 62 | BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); 63 | 64 | BIO* bmem = BIO_new(BIO_s_mem()); 65 | b64 = BIO_push(b64, bmem); 66 | 67 | BIO_write(b64, data.data(), data.size()); 68 | BIO_flush(b64); 69 | 70 | BUF_MEM* bptr = NULL; 71 | BIO_get_mem_ptr(b64, &bptr); 72 | 73 | std::string output(bptr->data, bptr->length); 74 | BIO_free_all(b64); 75 | 76 | return output; 77 | } 78 | 79 | //------------------------------------------------------------------------------ 80 | // helper function to hash with HMAC algorithm: 81 | static std::vector 82 | hmac_sha512(const std::vector& data, 83 | const std::vector& key) 84 | { 85 | unsigned int len = EVP_MAX_MD_SIZE; 86 | std::vector digest(len); 87 | 88 | HMAC_CTX *ctx = HMAC_CTX_new(); 89 | //HMAC_CTX_init(&ctx); 90 | 91 | HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha512(), NULL); 92 | HMAC_Update(ctx, data.data(), data.size()); 93 | HMAC_Final(ctx, digest.data(), &len); 94 | 95 | HMAC_CTX_free(ctx); 96 | //HMAC_CTX_cleanup(&ctx); 97 | 98 | return digest; 99 | } 100 | 101 | 102 | //------------------------------------------------------------------------------ 103 | // builds a query string from KAPI::Input (a=1&b=2&...) 104 | static std::string build_query(const KInput& input) 105 | { 106 | std::ostringstream oss; 107 | KInput::const_iterator it = input.begin(); 108 | for (; it != input.end(); ++it) { 109 | if (it != input.begin()) oss << '&'; // delimiter 110 | oss << it->first <<'='<< it->second; 111 | } 112 | 113 | return oss.str(); 114 | } 115 | 116 | //------------------------------------------------------------------------------ 117 | // helper function to create a nonce: 118 | static std::string create_nonce() 119 | { 120 | std::ostringstream oss; 121 | 122 | timeval tp; 123 | if (gettimeofday(&tp, NULL) != 0) { 124 | oss << "gettimeofday() failed: " << strerror(errno); 125 | throw std::runtime_error(oss.str()); 126 | } 127 | else { 128 | // format output string 129 | oss << std::setfill('0') 130 | << std::setw(10) << tp.tv_sec 131 | << std::setw(6) << tp.tv_usec; 132 | } 133 | return oss.str(); 134 | } 135 | 136 | //------------------------------------------------------------------------------ 137 | // constructor with all explicit parameters 138 | KClient::KClient(const std::string& key, const std::string& secret, 139 | const std::string& url, const std::string& version) 140 | :key_(key), secret_(secret), url_(url), version_(version) 141 | { 142 | init(); 143 | } 144 | 145 | //------------------------------------------------------------------------------ 146 | // default API base URL and API version 147 | KClient::KClient(const std::string& key, const std::string& secret) 148 | :key_(key), secret_(secret), url_("https://api.kraken.com"), version_("0") 149 | { 150 | init(); 151 | } 152 | 153 | //------------------------------------------------------------------------------ 154 | // constructor with empty API key and API secret 155 | KClient::KClient() 156 | :key_(""), secret_(""), url_("https://api.kraken.com"), version_("0") 157 | { 158 | init(); 159 | } 160 | 161 | //------------------------------------------------------------------------------ 162 | // initializes libcurl: 163 | void KClient::init() 164 | { 165 | curl_ = curl_easy_init(); 166 | if (curl_) { 167 | curl_easy_setopt(curl_, CURLOPT_VERBOSE, CURL_VERBOSE); 168 | curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYPEER, 1L); 169 | curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYHOST, 2L); 170 | curl_easy_setopt(curl_, CURLOPT_USERAGENT, "Kraken C++ API Client"); 171 | curl_easy_setopt(curl_, CURLOPT_POST, 1L); 172 | // set callback function 173 | curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, KClient::write_cb); 174 | } 175 | else { 176 | throw std::runtime_error("can't create curl handle"); 177 | } 178 | } 179 | 180 | //------------------------------------------------------------------------------ 181 | // distructor: 182 | KClient::~KClient() 183 | { 184 | curl_easy_cleanup(curl_); 185 | } 186 | 187 | //------------------------------------------------------------------------------ 188 | // returns message signature generated from a URI path, a nonce 189 | // and postdata, message signature is created as a follows: 190 | // 191 | // hmac_sha512(path + sha256(nonce + postdata), b64decode(secret)) 192 | // 193 | // and the result is converted in a base64 string: 194 | std::string KClient::signature(const std::string& path, 195 | const std::string& nonce, 196 | const std::string& postdata) const 197 | { 198 | // add path to data to encrypt 199 | std::vector data(path.begin(), path.end()); 200 | 201 | // concatenate nonce and postdata and compute SHA256 202 | std::vector nonce_postdata = sha256(nonce + postdata); 203 | 204 | // concatenate path and nonce_postdata (path + sha256(nonce + postdata)) 205 | data.insert(data.end(), nonce_postdata.begin(), nonce_postdata.end()); 206 | 207 | // and compute HMAC 208 | return b64_encode( hmac_sha512(data, b64_decode(secret_)) ); 209 | } 210 | 211 | //------------------------------------------------------------------------------ 212 | // CURL write function callback: 213 | size_t KClient::write_cb(char* ptr, size_t size, size_t nmemb, void* userdata) 214 | { 215 | std::string* response = reinterpret_cast(userdata); 216 | size_t real_size = size * nmemb; 217 | 218 | response->append(ptr, real_size); 219 | return real_size; 220 | } 221 | 222 | //------------------------------------------------------------------------------ 223 | // deals with public API methods: 224 | std::string KClient::public_method(const std::string& method, 225 | const KInput& input) const 226 | { 227 | // build method URL 228 | std::string path = "/" + version_ + "/public/" + method; 229 | std::string method_url = url_ + path; 230 | curl_easy_setopt(curl_, CURLOPT_URL, method_url.c_str()); 231 | 232 | // build postdata 233 | std::string postdata = build_query(input); 234 | curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, postdata.c_str()); 235 | 236 | // reset the http header 237 | curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, NULL); 238 | 239 | // where CURL write callback function stores the response 240 | std::string response; 241 | curl_easy_setopt(curl_, CURLOPT_WRITEDATA, static_cast(&response)); 242 | 243 | // perform CURL request 244 | CURLcode result = curl_easy_perform(curl_); 245 | if (result != CURLE_OK) { 246 | std::ostringstream oss; 247 | oss << "curl_easy_perform() failed: "<< curl_easy_strerror(result); 248 | throw std::runtime_error(oss.str()); 249 | } 250 | 251 | return response; 252 | } 253 | 254 | //------------------------------------------------------------------------------ 255 | // deals with private API methods: 256 | std::string KClient::private_method(const std::string& method, 257 | const KInput& input) const 258 | { 259 | // build method URL 260 | std::string path = "/" + version_ + "/private/" + method; 261 | std::string method_url = url_ + path; 262 | 263 | curl_easy_setopt(curl_, CURLOPT_URL, method_url.c_str()); 264 | 265 | // create a nonce and and postdata 266 | std::string nonce = create_nonce(); 267 | std::string postdata = "nonce=" + nonce; 268 | 269 | // if 'input' is not empty generate other postdata 270 | if (!input.empty()) 271 | postdata = postdata + "&" + build_query(input); 272 | curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, postdata.c_str()); 273 | 274 | // add custom header 275 | curl_slist* chunk = NULL; 276 | 277 | std::string key_header = "API-Key: " + key_; 278 | std::string sign_header = "API-Sign: " + signature(path, nonce, postdata); 279 | 280 | chunk = curl_slist_append(chunk, key_header.c_str()); 281 | chunk = curl_slist_append(chunk, sign_header.c_str()); 282 | curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, chunk); 283 | 284 | // where CURL write callback function stores the response 285 | std::string response; 286 | curl_easy_setopt(curl_, CURLOPT_WRITEDATA, static_cast(&response)); 287 | 288 | // perform CURL request 289 | CURLcode result = curl_easy_perform(curl_); 290 | 291 | // free the custom headers 292 | curl_slist_free_all(chunk); 293 | 294 | // check perform result 295 | if (result != CURLE_OK) { 296 | std::ostringstream oss; 297 | oss << "curl_easy_perform() failed: " << curl_easy_strerror(result); 298 | throw std::runtime_error(oss.str()); 299 | } 300 | 301 | return response; 302 | } 303 | 304 | //------------------------------------------------------------------------------ 305 | // downloads recent trade data: 306 | std::string KClient::trades(const std::string& pair, 307 | const std::string& since, 308 | std::vector& output) 309 | { 310 | KInput ki; 311 | ki["pair"] = pair; 312 | ki["since"] = since; 313 | 314 | // download and parse data 315 | json_string data = libjson::to_json_string( public_method("Trades", ki) ); 316 | JSONNode root = libjson::parse(data); 317 | 318 | 319 | 320 | // throw an exception if there are errors in the JSON response 321 | if (!root.at("error").empty()) { 322 | std::ostringstream oss; 323 | oss << "Kraken response contains errors: "; 324 | 325 | // append errors to output string stream 326 | for (JSONNode::const_iterator 327 | it = root["error"].begin(); it != root["error"].end(); ++it) 328 | oss << std::endl << " * " << libjson::to_std_string(it->as_string()); 329 | 330 | throw std::runtime_error(oss.str()); 331 | } 332 | 333 | // throw an exception if result is empty 334 | if (root.at("result").empty()) { 335 | throw std::runtime_error("Kraken response doesn't contain result data"); 336 | } 337 | 338 | 339 | 340 | JSONNode &result = root["result"]; 341 | JSONNode &result_pair = result[0]; 342 | std::string last = libjson::to_std_string( result.at("last").as_string() ); 343 | 344 | std::vector buf; 345 | for (JSONNode::const_iterator 346 | it = result_pair.begin(); it != result_pair.end(); ++it) 347 | buf.push_back(KTrade(*it)); 348 | 349 | output.swap(buf); 350 | return last; 351 | } 352 | 353 | //------------------------------------------------------------------------------ 354 | // helper function to initialize Kraken API library's resources: 355 | void initialize() 356 | { 357 | CURLcode code = curl_global_init(CURL_GLOBAL_ALL); 358 | if (code != CURLE_OK) { 359 | std::ostringstream oss; 360 | oss << "curl_global_init() failed: " << curl_easy_strerror(code); 361 | throw std::runtime_error(oss.str()); 362 | } 363 | } 364 | 365 | //------------------------------------------------------------------------------ 366 | // helper function to terminate Kraken API library's resources: 367 | void terminate() 368 | { 369 | curl_global_cleanup(); 370 | } 371 | 372 | //------------------------------------------------------------------------------ 373 | 374 | }; //namespace Kraken 375 | 376 | //------------------------------------------------------------------------------ 377 | -------------------------------------------------------------------------------- /kraken/kclient.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _KRAKEN_KCLIENT_HPP_ 2 | #define _KRAKEN_KCLIENT_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "ktrade.hpp" 10 | 11 | //------------------------------------------------------------------------------ 12 | 13 | namespace Kraken { 14 | 15 | //------------------------------------------------------------------------------ 16 | // helper type to make requests 17 | typedef std::map KInput; 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | class KClient { 22 | public: 23 | 24 | // constructor with all explicit parameters 25 | KClient(const std::string& key, const std::string& secret, 26 | const std::string& url, const std::string& version); 27 | 28 | // default API base URL and API version 29 | KClient(const std::string& key, const std::string& secret); 30 | 31 | // constructor with empty API key and API secret 32 | KClient(); 33 | 34 | // distructor 35 | ~KClient(); 36 | 37 | // makes public method to kraken.com 38 | std::string public_method(const std::string& method, 39 | const KInput& input) const; 40 | 41 | // makes private method to kraken.com 42 | std::string private_method(const std::string& method, 43 | const KInput& input) const; 44 | 45 | // returns recent Kraken recent trade data 46 | std::string trades(const std::string& pair, const std::string& since, 47 | std::vector& output); 48 | 49 | // TODO: public market data 50 | // void time(); 51 | // void assets(); 52 | // ... 53 | 54 | 55 | private: 56 | // init CURL and other stuffs 57 | void init(); 58 | 59 | // TODO: gather common commands from public_method and 60 | // private_method in a single method: curl_perfom 61 | 62 | // create signature for private requests 63 | std::string signature(const std::string& path, 64 | const std::string& nonce, 65 | const std::string& postdata) const; 66 | 67 | // CURL writefunction callback 68 | static size_t write_cb(char* ptr, size_t size, 69 | size_t nmemb, void* userdata); 70 | 71 | std::string key_; // API key 72 | std::string secret_; // API secret 73 | std::string url_; // API base URL 74 | std::string version_; // API version 75 | CURL* curl_; // CURL handle 76 | 77 | // disallow copying 78 | KClient(const KClient&); 79 | KClient& operator=(const KClient&); 80 | }; 81 | 82 | //------------------------------------------------------------------------------ 83 | // helper functions to initialize and terminate Kraker API library. 84 | // KClient uses CURL, the latter has a no thread-safe function called 85 | // curl_global_init(). 86 | 87 | void initialize(); 88 | void terminate(); 89 | 90 | //------------------------------------------------------------------------------ 91 | 92 | }; // namespace Kraken 93 | 94 | //------------------------------------------------------------------------------ 95 | 96 | #endif 97 | 98 | -------------------------------------------------------------------------------- /kraken/ktrade.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ktrade.hpp" 3 | 4 | //------------------------------------------------------------------------------ 5 | 6 | namespace Kraken { 7 | 8 | //------------------------------------------------------------------------------ 9 | // construct from a JSONNode: 10 | KTrade::KTrade(JSONNode node) 11 | { 12 | price = node[0].as_float(); 13 | volume = node[1].as_float(); 14 | std::istringstream( libjson::to_std_string(node[2].as_string()) ) >> time; 15 | 16 | order = static_cast 17 | ( libjson::to_std_string(node[3].as_string())[0] ); 18 | otype = static_cast 19 | ( libjson::to_std_string(node[4].as_string())[0] ); 20 | 21 | misc = libjson::to_std_string(node[5].as_string()); 22 | } 23 | 24 | //------------------------------------------------------------------------------ 25 | // prints out a KTrade: 26 | std::ostream& operator<<(std::ostream& os, const KTrade& kt) 27 | { 28 | return os << '"' << kt.time << "\",\"" 29 | << static_cast(kt.order) << "\",\"" 30 | << static_cast(kt.otype) << "\",\"" 31 | << std::fixed 32 | << std::setprecision(5) << kt.price << "\",\"" 33 | << std::setprecision(9) << kt.volume << '"'; 34 | } 35 | 36 | //------------------------------------------------------------------------------ 37 | 38 | }; // namespace Kraken 39 | -------------------------------------------------------------------------------- /kraken/ktrade.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _KRAKEN_KTRADE_HPP_ 2 | #define _KRAKEN_KTRADE_HPP_ 3 | 4 | #include 5 | #include 6 | #include "../libjson/libjson.h" 7 | 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace Kraken { 11 | 12 | //------------------------------------------------------------------------------ 13 | // deals with recent trade data: 14 | struct KTrade { 15 | 16 | enum Otype_t { MARKET='m', LIMIT='l' }; 17 | enum Order_t { BUY='b', SELL='s' }; 18 | 19 | double price, volume; 20 | time_t time; 21 | Otype_t otype; 22 | Order_t order; 23 | std::string misc; 24 | 25 | // default ctor 26 | KTrade() :price(0), volume(0), time(0), 27 | otype(KTrade::MARKET), 28 | order(KTrade::BUY) { } 29 | 30 | // construct from a JSONNode 31 | KTrade(JSONNode node); 32 | }; 33 | 34 | //------------------------------------------------------------------------------ 35 | // helper function to print a KTrade 36 | std::ostream& operator<<(std::ostream& os, const KTrade& kt); 37 | 38 | //------------------------------------------------------------------------------ 39 | 40 | }; // namespace Kraken 41 | 42 | //------------------------------------------------------------------------------ 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /krt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "kraken/kclient.hpp" 11 | #include "libjson/libjson.h" 12 | 13 | using namespace std; 14 | using namespace Kraken; 15 | 16 | //------------------------------------------------------------------------------ 17 | // deals with Kraken assets: 18 | struct KAsset { 19 | string name; 20 | string altname; 21 | string aclass; 22 | int decimals; 23 | int display_decimals; 24 | 25 | // construct a KAssets from an JSONNode: 26 | KAsset(const JSONNode& node) { 27 | name = libjson::to_std_string(node.name()); 28 | altname = node["altname"].as_string(); 29 | aclass = node["aclass"].as_string(); 30 | decimals = node["decimals"].as_int(); 31 | display_decimals = node["display_decimals"].as_int(); 32 | } 33 | }; 34 | 35 | //------------------------------------------------------------------------------ 36 | // prints a KAsset: 37 | ostream& operator<<(ostream& os, const KAsset& a) 38 | { 39 | return os << '"' 40 | << a.name << "\",\"" 41 | << a.altname << "\",\"" 42 | << a.aclass << "\",\"" 43 | << a.decimals << "\",\"" 44 | << a.display_decimals 45 | << '"'; 46 | } 47 | 48 | //------------------------------------------------------------------------------ 49 | // deals with Kraken assets: 50 | struct KAsset_pair { 51 | string name; 52 | string altname; 53 | string aclass_base; 54 | string base; 55 | string aclass_quote; 56 | string quote; 57 | string lot; 58 | int pair_decimals; 59 | int lot_decimals; 60 | int lot_multiplier; 61 | // leverage ... 62 | string fees; 63 | string fee_volume_currency; 64 | int margin_call; 65 | int margin_stop; 66 | 67 | // construct a KAssets from an JSONNode: 68 | KAsset_pair(const JSONNode& node) { 69 | name = libjson::to_std_string( node.name() ); 70 | altname = libjson::to_std_string( node["altname"].as_string() ); 71 | aclass_base = libjson::to_std_string( node["aclass_base"].as_string() ); 72 | base = libjson::to_std_string( node["base"].as_string() ); 73 | aclass_quote = libjson::to_std_string( node["aclass_quote"].as_string() ); 74 | quote = libjson::to_std_string( node["quote"].as_string() ); 75 | lot = libjson::to_std_string( node["lot"].as_string() ); 76 | 77 | pair_decimals = node["pair_decimals"].as_int(); 78 | lot_decimals = node["lot_decimals"].as_int(); 79 | lot_multiplier = node["lot_multiplier"].as_int(); 80 | fees = libjson::to_std_string( node["fees"].as_string() ); 81 | 82 | fee_volume_currency 83 | = libjson::to_std_string( node["fee_volume_currency"].as_string() ); 84 | 85 | margin_call = node["margin_call"].as_int(); 86 | margin_stop = node["margin_stop"].as_int(); 87 | } 88 | }; 89 | 90 | //------------------------------------------------------------------------------ 91 | // prints a KAsset_pair: 92 | ostream& operator<<(ostream& os, const KAsset_pair& a) 93 | { 94 | return os << '"' 95 | << a.name << "\",\"" 96 | << a.altname << "\",\"" 97 | << a.aclass_base << "\",\"" 98 | << a.base << "\",\"" 99 | << a.aclass_quote << "\",\"" 100 | << a.quote << "\",\"" 101 | << a.lot << "\",\"" 102 | << a.pair_decimals << "\",\"" 103 | << a.lot_decimals << "\",\"" 104 | << a.lot_multiplier << "\",\"" 105 | << a.fees << "\",\"" 106 | << a.fee_volume_currency << "\",\"" 107 | << a.margin_call << "\",\"" 108 | << a.margin_stop 109 | << '"'; 110 | } 111 | 112 | //------------------------------------------------------------------------------ 113 | 114 | int main(int argc, char* argv[]) 115 | { 116 | try { 117 | 118 | // initialize kraken lib's resources: 119 | Kraken::initialize(); 120 | 121 | // 122 | // command line argument handling: 123 | // 124 | // usage: 125 | // krt [interval] [since] 126 | // 127 | 128 | string pair; 129 | string last = "0"; // by default: the oldest possible trade data 130 | int interval = 0; // by default: krt exits after download trade data 131 | 132 | switch (argc) { 133 | case 4: 134 | last = string(argv[3]); 135 | case 3: 136 | istringstream(argv[2]) >> interval; 137 | case 2: 138 | pair = string(argv[1]); 139 | break; 140 | default: 141 | throw runtime_error("wrong number of arguments"); 142 | }; 143 | 144 | chrono::seconds dura(interval); 145 | 146 | KClient kc; 147 | vector vt; 148 | 149 | while (true) { 150 | // store and print trades 151 | last = kc.trades(pair, last, vt); 152 | for (int i = 0; i < vt.size(); ++i) 153 | cout << vt[i] << endl; 154 | 155 | // exit from the loop if interval is 0 156 | if (interval == 0) break; 157 | 158 | // sleep 159 | this_thread::sleep_for(dura); 160 | } 161 | 162 | // terminate kraken lib's resources 163 | Kraken::terminate(); 164 | } 165 | catch(exception& e) { 166 | cerr << "Error: " << e.what() << endl; 167 | exit(EXIT_FAILURE); 168 | } 169 | catch(...) { 170 | cerr << "Unknown exception." << endl; 171 | exit(EXIT_FAILURE); 172 | } 173 | 174 | return 0; 175 | } 176 | -------------------------------------------------------------------------------- /libjson/License.txt: -------------------------------------------------------------------------------- 1 | This license is also available in Documentation.pdf 2 | 3 | Copyright 2010 Jonathan Wallace. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | THIS SOFTWARE IS PROVIDED BY JONATHAN WALLACE ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JONATHAN WALLACE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | 13 | The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Jonathan Wallace. -------------------------------------------------------------------------------- /libjson/_internal/Dependencies/libbase64++/libbase64++.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBBASE64_CPP_H 2 | #define LIBBASE64_CPP_H 3 | 4 | #include 5 | //#define LIBBASE64_THROW_STD_INVALID_ARGUMENT 6 | 7 | //version info 8 | #define __LIBBASE64_MAJOR__ 1 9 | #define __LIBBASE64_MINOR__ 1 10 | #define __LIBBASE64_PATCH__ 0 11 | #define __LIBBASE64_VERSION__ (__LIBBASE64_MAJOR__ * 10000 + __LIBBASE64_MINOR__ * 100 + __LIBBASE64_PATCH__) 12 | 13 | //code coverage and asserts 14 | #ifdef NDEBUG 15 | #define LIBBASE64_ASSERT(cond, msg) (void)0 16 | #define CREATEBOUNDCHECKER(type, name, ubound, lbound) (void)0 17 | #define GETITEM_BOUNDCHECK(loc, name) (*(loc)) 18 | #else 19 | #include 20 | #define LIBBASE64_ASSERT(cond, msg) if (!(cond)){ std::cerr << msg << std::endl; throw false; } 21 | 22 | template 23 | class libbase64_boundChecker { 24 | public: 25 | libbase64_boundChecker(const T * lbound, const T * ubound) : upperbound(ubound), lowerbound(lbound){}; 26 | T getLocation(const T * loc){ 27 | LIBBASE64_ASSERT(loc < upperbound, "Array index above bounds"); 28 | LIBBASE64_ASSERT(loc >= lowerbound, "Array index below bounds"); 29 | return *loc; 30 | } 31 | private: 32 | const T * lowerbound; 33 | const T * upperbound; 34 | }; 35 | #define CREATEBOUNDCHECKER(type, name, ubound, lbound) libbase64_boundChecker name(ubound, lbound) 36 | #define GETITEM_BOUNDCHECK(loc, name) name.getLocation(loc) 37 | 38 | #ifdef LIBBASE64CODECOVERAGE 39 | #define LIBBASE64CODECOVERAGEBRANCH { static bool f_codeCoverage_ = false; if (f_codeCoverage_ == false){ libbase64::getCoverageHits(true); f_codeCoverage_ = true; } } 40 | #endif 41 | #endif 42 | #ifndef LIBBASE64CODECOVERAGE 43 | #define LIBBASE64CODECOVERAGEBRANCH (void)0 44 | #endif 45 | 46 | //predictive branching optimizations 47 | #ifdef __GNUC__ 48 | #define LIBBASE64_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) 49 | #if (LIBBASE64_GCC_VERSION >= 29600) 50 | #define libbase64_likely(x) __builtin_expect((long)((bool)(x)),1) 51 | #define libbase64_unlikely(x) __builtin_expect((long)((bool)(x)),0) 52 | #endif 53 | #endif 54 | #ifndef libbase64_likely 55 | #define libbase64_likely(x) x 56 | #define libbase64_unlikely(x) x 57 | #endif 58 | 59 | 60 | namespace libbase64 { 61 | #ifdef LIBBASE64CODECOVERAGE //Gets the number of branches that has been made 62 | template 63 | static size_t getCoverageHits(bool inc){ 64 | static size_t hits = 0; 65 | if (inc) ++hits; 66 | return hits; 67 | } 68 | #endif 69 | 70 | //characters used in convertions 71 | namespace libbase64_characters { 72 | template 73 | inline static const T * getChar64(void){ 74 | static const T char64s[64] = { 75 | (T)'A', (T)'B', (T)'C', (T)'D', (T)'E', (T)'F', (T)'G', (T)'H', (T)'I', (T)'J', (T)'K', (T)'L', (T)'M', 76 | (T)'N', (T)'O', (T)'P', (T)'Q', (T)'R', (T)'S', (T)'T', (T)'U', (T)'V', (T)'W', (T)'X', (T)'Y', (T)'Z', 77 | (T)'a', (T)'b', (T)'c', (T)'d', (T)'e', (T)'f', (T)'g', (T)'h', (T)'i', (T)'j', (T)'k', (T)'l', (T)'m', 78 | (T)'n', (T)'o', (T)'p', (T)'q', (T)'r', (T)'s', (T)'t', (T)'u', (T)'v', (T)'w', (T)'x', (T)'y', (T)'z', 79 | (T)'0', (T)'1', (T)'2', (T)'3', (T)'4', (T)'5', (T)'6', (T)'7', (T)'8', (T)'9', (T)'+', (T)'/' 80 | }; 81 | return char64s; 82 | } 83 | 84 | template 85 | inline static T getChar(unsigned char bin){ 86 | CREATEBOUNDCHECKER(T, char64bounds, getChar64(), getChar64() + 64); 87 | return GETITEM_BOUNDCHECK(getChar64() + bin, char64bounds); 88 | } 89 | 90 | template 91 | inline static T toBinary(T c) { 92 | static T binaryConvert[80] = {62,48,49,50,63,52,53,54,55,56,57,58,59,60,61,249,250,251,252,253,254,255,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; 93 | CREATEBOUNDCHECKER(T, binaryConvertsbounds, binaryConvert, binaryConvert + 80); 94 | return GETITEM_BOUNDCHECK(binaryConvert + c - 43, binaryConvertsbounds); 95 | } 96 | 97 | template 98 | static inline T & emptyString(void){ 99 | static T t; 100 | return t; 101 | } 102 | } 103 | 104 | namespace libbase64_Calculator { 105 | inline static size_t getEncodingSize(size_t bytes){ 106 | return (bytes + 2 - ((bytes + 2) % 3)) / 3 * 4; 107 | } 108 | inline static size_t getDecodingSize(size_t res){ 109 | return res * 3 / 4; 110 | } 111 | } 112 | 113 | 114 | /** 115 | * Encodes data into a base64 string of STRINGTYPE 116 | */ 117 | template 118 | static STRINGTYPE encode(const unsigned char * binary, size_t bytes){ 119 | CREATEBOUNDCHECKER(unsigned char, binarybounds, binary, binary + bytes); 120 | 121 | //make sure that there is actually something to encode 122 | if (SAFETY){ 123 | if (libbase64_unlikely(bytes == 0)){ 124 | LIBBASE64CODECOVERAGEBRANCH; 125 | return libbase64_characters::emptyString(); 126 | } 127 | } 128 | 129 | //calculate length and how misaligned it is 130 | size_t misaligned = bytes % 3; 131 | STRINGTYPE result; 132 | result.reserve(libbase64_Calculator::getEncodingSize(bytes)); 133 | 134 | //do all of the ones that are 3 byte aligned 135 | for (size_t i = 0, aligned((bytes - misaligned) / 3); i < aligned; ++i){ 136 | LIBBASE64CODECOVERAGEBRANCH; 137 | result += libbase64_characters::getChar((GETITEM_BOUNDCHECK(binary, binarybounds) & 0xFC) >> 2); 138 | result += libbase64_characters::getChar(((GETITEM_BOUNDCHECK(binary, binarybounds) & 0x03) << 4) + ((GETITEM_BOUNDCHECK(binary + 1, binarybounds) & 0xF0) >> 4)); 139 | result += libbase64_characters::getChar(((GETITEM_BOUNDCHECK(binary + 1, binarybounds) & 0x0F) << 2) + ((GETITEM_BOUNDCHECK(binary + 2, binarybounds) & 0xC0) >> 6)); 140 | result += libbase64_characters::getChar(GETITEM_BOUNDCHECK(binary + 2, binarybounds) & 0x3F); 141 | binary += 3; 142 | } 143 | 144 | //handle any additional characters at the end of it 145 | if (libbase64_likely(misaligned != 0)){ 146 | LIBBASE64CODECOVERAGEBRANCH; 147 | //copy the rest into a temporary buffer, need it for the null terminators 148 | unsigned char temp[3] = { '\0', '\0', '\0' }; 149 | for (unsigned char i = 0; i < (unsigned char)misaligned; ++i){ 150 | LIBBASE64CODECOVERAGEBRANCH; 151 | temp[i] = GETITEM_BOUNDCHECK(binary++, binarybounds); 152 | } 153 | 154 | //now do the final three bytes 155 | result += libbase64_characters::getChar((temp[0] & 0xFC) >> 2); 156 | result += libbase64_characters::getChar(((temp[0] & 0x03) << 4) + ((temp[1] & 0xF0) >> 4)); 157 | if (misaligned == 2){ 158 | LIBBASE64CODECOVERAGEBRANCH; 159 | result += libbase64_characters::getChar(((temp[1] & 0x0F) << 2) + ((temp[2] & 0xC0) >> 6)); 160 | } else { 161 | LIBBASE64CODECOVERAGEBRANCH; 162 | result += (CHARTYPE)'='; 163 | } 164 | result += (CHARTYPE)'='; 165 | } else { 166 | LIBBASE64CODECOVERAGEBRANCH; 167 | } 168 | 169 | LIBBASE64_ASSERT(libbase64_Calculator::getEncodingSize(bytes) == result.length(), "Reserve wasn't the correct guess"); 170 | return result; 171 | } 172 | 173 | template 174 | static std::string decode(const STRINGTYPE & encoded){ 175 | //check length to be sure its acceptable for base64 176 | const size_t length = encoded.length(); 177 | 178 | if (SAFETY){ 179 | if (libbase64_unlikely((length % 4) != 0)){ 180 | LIBBASE64CODECOVERAGEBRANCH; 181 | return libbase64_characters::emptyString(); 182 | } 183 | if (libbase64_unlikely(length == 0)){ 184 | LIBBASE64CODECOVERAGEBRANCH; 185 | return libbase64_characters::emptyString(); 186 | } 187 | 188 | //check to be sure there aren't odd characters or characters in the wrong places 189 | size_t pos = encoded.find_first_not_of(libbase64_characters::getChar64()); 190 | if (libbase64_unlikely(pos != STRINGTYPE::npos)){ 191 | LIBBASE64CODECOVERAGEBRANCH; 192 | if (libbase64_unlikely(encoded[pos] != (CHARTYPE)'=')){ 193 | LIBBASE64CODECOVERAGEBRANCH; //INVALID_CHAR 194 | #ifdef LIBBASE64_THROW_STD_INVALID_ARGUMENT 195 | throw std::invalid_argument("invalid character in base64"); 196 | #else 197 | return libbase64_characters::emptyString(); 198 | #endif 199 | } 200 | if (pos != length - 1){ 201 | LIBBASE64CODECOVERAGEBRANCH; 202 | if (libbase64_unlikely(pos != length - 2)){ 203 | LIBBASE64CODECOVERAGEBRANCH; //EQUAL_WRONG_PLACE 204 | #ifdef LIBBASE64_THROW_STD_INVALID_ARGUMENT 205 | throw std::invalid_argument("equal sign in wrong place in base64"); 206 | #else 207 | return libbase64_characters::emptyString(); 208 | #endif 209 | } 210 | if (libbase64_unlikely(encoded[pos + 1] != (CHARTYPE)'=')){ 211 | LIBBASE64CODECOVERAGEBRANCH; //EQUAL_NOT_LAST 212 | #ifdef LIBBASE64_THROW_STD_INVALID_ARGUMENT 213 | throw std::invalid_argument("invalid character in base64"); 214 | #else 215 | return libbase64_characters::emptyString(); 216 | #endif 217 | } 218 | LIBBASE64CODECOVERAGEBRANCH; 219 | } else { 220 | LIBBASE64CODECOVERAGEBRANCH; 221 | } 222 | } else { 223 | LIBBASE64CODECOVERAGEBRANCH; 224 | } 225 | } 226 | 227 | const CHARTYPE * runner = encoded.data(); 228 | const CHARTYPE * end = runner + encoded.length(); 229 | CREATEBOUNDCHECKER(CHARTYPE, encodedbounds, runner, end); 230 | size_t aligned = length / 4; //don't do the last ones as they might be = padding 231 | std::string result; 232 | --aligned; 233 | result.reserve(libbase64_Calculator::getDecodingSize(length)); 234 | 235 | //first do the ones that can not have any padding 236 | for (unsigned int i = 0; i < aligned; ++i){ 237 | const CHARTYPE second = libbase64_characters::toBinary(GETITEM_BOUNDCHECK(runner + 1, encodedbounds)); 238 | const CHARTYPE third = libbase64_characters::toBinary(GETITEM_BOUNDCHECK(runner + 2, encodedbounds)); 239 | result += (libbase64_characters::toBinary(GETITEM_BOUNDCHECK(runner, encodedbounds)) << 2) + ((second & 0x30) >> 4); 240 | result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2); 241 | result += ((third & 0x3) << 6) + libbase64_characters::toBinary(GETITEM_BOUNDCHECK(runner + 3, encodedbounds)); 242 | runner += 4; 243 | } 244 | 245 | //now do the ones that might have padding, the first two characters can not be padding, so do them quickly 246 | const CHARTYPE second = libbase64_characters::toBinary(GETITEM_BOUNDCHECK(runner + 1, encodedbounds)); 247 | result += (libbase64_characters::toBinary(GETITEM_BOUNDCHECK(runner + 0, encodedbounds)) << 2) + ((second & 0x30) >> 4); 248 | runner += 2; 249 | if ((runner != end) && (*runner != (CHARTYPE)'=')){ //not two = pads 250 | LIBBASE64CODECOVERAGEBRANCH; 251 | const CHARTYPE third = libbase64_characters::toBinary(GETITEM_BOUNDCHECK(runner, encodedbounds)); 252 | result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2); 253 | ++runner; 254 | if ((runner != end) && (*runner != (CHARTYPE)'=')){ //no padding 255 | LIBBASE64CODECOVERAGEBRANCH; 256 | result += ((third & 0x3) << 6) + libbase64_characters::toBinary(GETITEM_BOUNDCHECK(runner, encodedbounds)); 257 | } else { 258 | LIBBASE64CODECOVERAGEBRANCH; 259 | } 260 | } else { 261 | LIBBASE64CODECOVERAGEBRANCH; 262 | } 263 | 264 | LIBBASE64_ASSERT(libbase64_Calculator::getDecodingSize(length) >= result.length(), "Reserve wasn't the correct guess, too small"); 265 | LIBBASE64_ASSERT((result.length() <= 3) || (libbase64_Calculator::getDecodingSize(length) > result.length() - 3), "Reserve wasn't the correct guess, too big"); 266 | return result; 267 | } 268 | } 269 | 270 | #endif 271 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONAllocator.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONAllocator.h" 2 | 3 | #if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL) 4 | #include "JSONMemory.h" 5 | 6 | void * JSONAllocatorRelayer::alloc(size_t bytes) json_nothrow { 7 | return JSONMemory::json_malloc(bytes); 8 | } 9 | 10 | void JSONAllocatorRelayer::dealloc(void * ptr) json_nothrow { 11 | JSONMemory::json_free(ptr); 12 | } 13 | #endif 14 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONAllocator.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_ALLOCATOR_H 2 | #define JSON_ALLOCATOR_H 3 | 4 | #include "JSONStats.h" 5 | #if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL) 6 | 7 | #include 8 | 9 | //need these for the json_nothrow 10 | #include "JSONDefs/Visual_C.h" 11 | #include "JSONDefs/GNU_C.h" 12 | #include "JSONDefs/Unknown_C.h" 13 | 14 | class JSONAllocatorRelayer { 15 | public: 16 | static void * alloc(size_t bytes) json_nothrow json_hot; 17 | static void dealloc(void * ptr) json_nothrow json_hot; 18 | }; 19 | 20 | template class json_allocator; 21 | 22 | // specialize for void: 23 | template <> class json_allocator { 24 | public: 25 | typedef void* pointer; 26 | typedef const void* const_pointer; 27 | // reference to void members are impossible. 28 | typedef void value_type; 29 | template struct rebind { typedef json_allocator other; }; 30 | }; 31 | 32 | template class json_allocator { 33 | public: 34 | typedef size_t size_type; 35 | typedef ptrdiff_t difference_type; 36 | typedef T* pointer; 37 | typedef const T* const_pointer; 38 | typedef T& reference; 39 | typedef const T& const_reference; 40 | typedef T value_type; 41 | template struct rebind { typedef json_allocator other; }; 42 | 43 | //LIBJSON_OBJECT(json_allocator); 44 | 45 | inline json_allocator() json_nothrow { 46 | //LIBJSON_CTOR; 47 | } 48 | inline json_allocator(const json_allocator&) json_nothrow { 49 | //LIBJSON_COPY_CTOR; 50 | } 51 | template inline json_allocator(const json_allocator&) json_nothrow { 52 | //LIBJSON_COPY_CTOR; 53 | } 54 | inline ~json_allocator() json_nothrow { 55 | //LIBJSON_DTOR; 56 | } 57 | 58 | inline pointer address(reference x) const { return &x; } 59 | inline const_pointer address(const_reference x) const { return &x; } 60 | 61 | inline pointer allocate(size_type n, json_allocator::const_pointer = 0) json_hot { 62 | return (pointer)JSONAllocatorRelayer::alloc(n * sizeof(T)); 63 | } 64 | inline void deallocate(pointer p, size_type) json_hot { 65 | JSONAllocatorRelayer::dealloc(p); 66 | } 67 | 68 | inline size_type max_size() const json_nothrow { return 0xEFFFFFFF; } 69 | 70 | inline void construct(pointer p, const T& val){ 71 | new(p)T(val); 72 | }; 73 | inline void destroy(pointer p){ 74 | ((T*)p) -> ~T(); 75 | } 76 | }; 77 | 78 | template inline bool operator==(const json_allocator&, const json_allocator&) json_nothrow { return true; } 79 | template inline bool operator!=(const json_allocator&, const json_allocator&) json_nothrow { return false; } 80 | 81 | #endif 82 | #endif 83 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONChildren.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONChildren.h" 2 | #include "JSONNode.h" 3 | 4 | /* 5 | * reserves a certain number of bytes, in memory saving mode it creates a special 6 | * type of child container that will not autoshrink 7 | */ 8 | void jsonChildren::reserve2(jsonChildren *& mine, json_index_t amount) json_nothrow { 9 | if (mine -> array != 0){ 10 | if (mine -> mycapacity < amount){ 11 | mine -> inc(amount - mine -> mycapacity); 12 | #ifdef JSON_LESS_MEMORY 13 | mine = jsonChildren_Reserved::newChildren_Reserved(mine, amount); 14 | #endif 15 | } 16 | } else { 17 | mine -> reserve(amount); 18 | } 19 | } 20 | 21 | void jsonChildren::inc(void) json_nothrow { 22 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null inc")); 23 | if (json_unlikely(mysize == mycapacity)){ //it's full 24 | if (json_unlikely(mycapacity == 0)){ //the array hasn't been created yet 25 | JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null")); 26 | #ifdef JSON_LESS_MEMORY 27 | array = json_malloc(1); 28 | mycapacity = 1; 29 | #else 30 | array = json_malloc(8); //8 seems average for JSON, and it's only 64 bytes 31 | mycapacity = 8; 32 | #endif 33 | } else { 34 | #ifdef JSON_LESS_MEMORY 35 | mycapacity += 1; //increment the size of the array 36 | #else 37 | mycapacity <<= 1; //double the size of the array 38 | #endif 39 | array = json_realloc(array, mycapacity); 40 | } 41 | } 42 | } 43 | 44 | 45 | void jsonChildren::inc(json_index_t amount) json_nothrow { 46 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null inc(amount)")); 47 | if (json_unlikely(amount == 0)) return; 48 | if (json_likely(mysize + amount >= mycapacity)){ //it's full 49 | if (json_unlikely(mycapacity == 0)){ //the array hasn't been created yet 50 | JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null")); 51 | #ifdef JSON_LESS_MEMORY 52 | array = json_malloc(amount); 53 | mycapacity = amount; 54 | #else 55 | array = json_malloc(amount > 8 ? amount : 8); //8 seems average for JSON, and it's only 64 bytes 56 | mycapacity = amount > 8 ? amount : 8; 57 | #endif 58 | } else { 59 | #ifdef JSON_LESS_MEMORY 60 | mycapacity = mysize + amount; //increment the size of the array 61 | #else 62 | while(mysize + amount > mycapacity){ 63 | mycapacity <<= 1; //double the size of the array 64 | } 65 | #endif 66 | array = json_realloc(array, mycapacity); 67 | } 68 | } 69 | } 70 | 71 | //actually deletes everything within the vector, this is safe to do on an empty or even a null array 72 | void jsonChildren::deleteAll(void) json_nothrow { 73 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null deleteAll")); 74 | json_foreach(this, runner){ 75 | JSON_ASSERT(*runner != (JSONNode*) JSON_TEXT('\0'), JSON_TEXT("a null pointer within the children")); 76 | JSONNode::deleteJSONNode(*runner); //this is why I can't do forward declaration 77 | } 78 | } 79 | 80 | void jsonChildren::doerase(JSONNode ** position, json_index_t number) json_nothrow { 81 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null doerase")); 82 | JSON_ASSERT(array != 0, JSON_TEXT("erasing something from a null array 2")); 83 | JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 2")); 84 | JSON_ASSERT(position + number <= array + mysize, JSON_TEXT("erasing out of bounds 2")); 85 | if (position + number >= array + mysize){ 86 | mysize = (json_index_t)(position - array); 87 | #ifndef JSON_ISO_STRICT 88 | JSON_ASSERT((long long)position - (long long)array >= 0, JSON_TEXT("doing negative allocation")); 89 | #endif 90 | } else { 91 | std::memmove(position, position + number, (mysize - (position - array) - number) * sizeof(JSONNode *)); 92 | mysize -= number; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONChildren.h: -------------------------------------------------------------------------------- 1 | #ifndef JSONCHILDREN_H 2 | #define JSONCHILDREN_H 3 | 4 | #include "JSONMemory.h" 5 | #include "JSONDebug.h" //for JSON_ASSERT macro 6 | 7 | #ifdef JSON_LESS_MEMORY 8 | #ifdef __GNUC__ 9 | #pragma pack(push, 1) 10 | #elif _MSC_VER 11 | #pragma pack(push, jsonChildren, 1) 12 | #endif 13 | #endif 14 | 15 | #define json_foreach(chldrn, itrtr)\ 16 | JSONNode ** itrtr = chldrn -> begin();\ 17 | for(JSONNode ** itrtr##_end = chldrn -> end(); itrtr != itrtr##_end; ++itrtr) 18 | 19 | /* 20 | This class is essentially a vector that has been heavily optimized for the specific purpose 21 | of holding JSONNode children. It acts the same way as a vector, it has a automatically 22 | expanding array. On destruction, this container automatically destroys everything contained 23 | in it as well, so that you libjson doesn't have to do that. 24 | 25 | T is JSONNode*, I can't define it that way directly because JSONNode uses this container, and because 26 | the container deletes the children automatically, forward declaration can't be used 27 | */ 28 | 29 | class JSONNode; //forward declaration 30 | 31 | #ifdef JSON_LESS_MEMORY 32 | #define childrenVirtual virtual 33 | #else 34 | #define childrenVirtual 35 | #endif 36 | 37 | class jsonChildren { 38 | public: 39 | LIBJSON_OBJECT(jsonChildren); 40 | //starts completely empty and the array is not allocated 41 | jsonChildren(void) json_nothrow : array(0), mysize(0), mycapacity(0) { 42 | LIBJSON_CTOR; 43 | } 44 | 45 | #ifdef JSON_LESS_MEMORY 46 | jsonChildren(JSONNode** ar, json_index_t si, json_index_t ca) json_nothrow : array(ar), mysize(si), mycapacity(ca) { 47 | LIBJSON_CTOR; 48 | } 49 | #endif 50 | 51 | //deletes the array and everything that is contained within it (using delete) 52 | childrenVirtual ~jsonChildren(void) json_nothrow { 53 | if (json_unlikely(array != 0)){ //the following function calls are safe, but take more time than a check here 54 | deleteAll(); 55 | libjson_free(array); 56 | } 57 | LIBJSON_DTOR; 58 | } 59 | 60 | //increase the size of the array 61 | void inc(json_index_t amount) json_nothrow; 62 | void inc(void) json_nothrow; 63 | 64 | //Adds something to the vector, doubling the array if necessary 65 | void push_back(JSONNode * item) json_nothrow { 66 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null push_back")); 67 | inc(); 68 | array[mysize++] = item; 69 | } 70 | 71 | //Adds something to the front of the vector, doubling the array if necessary 72 | void push_front(JSONNode * item) json_nothrow { 73 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null push_front")); 74 | inc(); 75 | std::memmove(array + 1, array, mysize++ * sizeof(JSONNode *)); 76 | array[0] = item; 77 | } 78 | 79 | //gets an item out of the vector by it's position 80 | inline JSONNode * operator[] (json_index_t position) const json_nothrow { 81 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null []")); 82 | JSON_ASSERT(position < mysize, JSON_TEXT("Using [] out of bounds")); 83 | JSON_ASSERT(position < mycapacity, JSON_TEXT("Using [] out of bounds")); 84 | JSON_ASSERT(array != 0, JSON_TEXT("Array is null")); 85 | return array[position]; 86 | } 87 | 88 | //returns the allocated capacity, but keep in mind that some might not be valid 89 | inline json_index_t capacity() const json_nothrow { 90 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null capacity")); 91 | return mycapacity; 92 | } 93 | 94 | //returns the number of valid objects within the vector 95 | inline json_index_t size() const json_nothrow { 96 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null size")); 97 | return mysize; 98 | } 99 | 100 | //tests whether or not the vector is empty 101 | inline bool empty() const json_nothrow { 102 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null empty")); 103 | return mysize == 0; 104 | } 105 | 106 | //clears (and deletes) everything from the vector and sets it's size to 0 107 | inline void clear() json_nothrow { 108 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null clear")); 109 | if (json_likely(array != 0)){ //don't bother clearing anything if there is nothing in it 110 | JSON_ASSERT(mycapacity != 0, JSON_TEXT("mycapacity is not zero, but array is null")); 111 | deleteAll(); 112 | mysize = 0; 113 | } 114 | JSON_ASSERT(mysize == 0, JSON_TEXT("mysize is not zero after clear")); 115 | } 116 | 117 | //returns the beginning of the array 118 | inline JSONNode ** begin(void) const json_nothrow { 119 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null begin")); 120 | return array; 121 | } 122 | 123 | //returns the end of the array 124 | inline JSONNode ** end(void) const json_nothrow { 125 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null end")); 126 | return array + mysize; 127 | } 128 | 129 | //makes sure that even after shirnking and expanding, the iterator is in same relative position 130 | template 131 | struct iteratorKeeper { 132 | public: 133 | LIBJSON_OBJECT(jsonChildren::iteratorKeeper); 134 | iteratorKeeper(jsonChildren * pthis, JSONNode ** & position) json_nothrow : 135 | myRelativeOffset(reverse ? (json_index_t)(pthis -> array + (size_t)pthis -> mysize - position) : (json_index_t)(position - pthis -> array)), 136 | myChildren(pthis), 137 | myPos(position){ 138 | LIBJSON_CTOR; 139 | } 140 | 141 | ~iteratorKeeper(void) json_nothrow { 142 | LIBJSON_DTOR; 143 | if (reverse){ 144 | myPos = myChildren -> array + myChildren -> mysize - myRelativeOffset; 145 | } else { 146 | myPos = myChildren -> array + myRelativeOffset; 147 | } 148 | } 149 | private: 150 | iteratorKeeper(const iteratorKeeper &); 151 | iteratorKeeper & operator = (const iteratorKeeper &); 152 | 153 | json_index_t myRelativeOffset; 154 | jsonChildren * myChildren; 155 | JSONNode ** & myPos; 156 | }; 157 | 158 | //This function DOES NOT delete the item it points to 159 | inline void erase(JSONNode ** & position) json_nothrow { 160 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase")); 161 | JSON_ASSERT(array != 0, JSON_TEXT("erasing something from a null array 1")); 162 | JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 1")); 163 | JSON_ASSERT(position <= array + mysize, JSON_TEXT("erasing out of bounds 1")); 164 | std::memmove(position, position + 1, (mysize-- - (position - array) - 1) * sizeof(JSONNode *)); 165 | iteratorKeeper ik(this, position); 166 | shrink(); 167 | } 168 | 169 | //This function DOES NOT delete the item it points to 170 | inline void erase(JSONNode ** & position, json_index_t number) json_nothrow { 171 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase 2")); 172 | doerase(position, number); 173 | iteratorKeeper ik(this, position); 174 | shrink(); 175 | } 176 | 177 | 178 | //This function DOES NOT delete the item it points to 179 | inline void erase(JSONNode ** position, json_index_t number, JSONNode ** & starter) json_nothrow { 180 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase 3")); 181 | doerase(position, number); 182 | iteratorKeeper ik(this, starter); 183 | shrink(); 184 | } 185 | 186 | #ifdef JSON_LIBRARY 187 | void insert(JSONNode ** & position, JSONNode * item) json_nothrow{ 188 | #else 189 | void insert(JSONNode ** & position, JSONNode * item, bool reverse = false) json_nothrow { 190 | #endif 191 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null insert")); 192 | //position isnt relative to array because of realloc 193 | JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 1")); 194 | JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 1")); 195 | #ifndef JSON_LIBRARY 196 | if (reverse){ 197 | iteratorKeeper ik(this, position); 198 | inc(); 199 | } else 200 | #endif 201 | { 202 | iteratorKeeper ik(this, position); 203 | inc(); 204 | } 205 | 206 | std::memmove(position + 1, position, (mysize++ - (position - array)) * sizeof(JSONNode *)); 207 | *position = item; 208 | } 209 | 210 | void insert(JSONNode ** & position, JSONNode ** items, json_index_t num) json_nothrow { 211 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null insert 2")); 212 | JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 2")); 213 | JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 2")); 214 | { 215 | iteratorKeeper ik(this, position); 216 | inc(num); 217 | } 218 | const size_t ptrs = ((JSONNode **)(array + mysize)) - position; 219 | std::memmove(position + num, position, ptrs * sizeof(JSONNode *)); 220 | std::memcpy(position, items, num * sizeof(JSONNode *)); 221 | mysize += num; 222 | } 223 | 224 | inline void reserve(json_index_t amount) json_nothrow { 225 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null reserve")); 226 | JSON_ASSERT(array == 0, JSON_TEXT("reserve is not meant to expand a preexisting array")); 227 | JSON_ASSERT(mycapacity == 0, JSON_TEXT("reservec is not meant to expand a preexisting array")); 228 | JSON_ASSERT(mysize == 0, JSON_TEXT("reserves is not meant to expand a preexisting array")); 229 | array = json_malloc(mycapacity = amount); 230 | } 231 | 232 | //it is static because mine might change pointers entirely 233 | static void reserve2(jsonChildren *& mine, json_index_t amount) json_nothrow; 234 | 235 | //shrinks the array to only as large as it needs to be to hold everything within it 236 | inline childrenVirtual void shrink() json_nothrow { 237 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null shrink")); 238 | if (json_unlikely(mysize == 0)){ //size is zero, we should completely free the array 239 | libjson_free(array); //free does checks for a null pointer, so don't bother checking 240 | array = 0; 241 | #ifdef JSON_LESS_MEMORY 242 | } else { //need to shrink it, using realloc 243 | JSON_ASSERT(array != 0, JSON_TEXT("shrinking a null array that is not size 0")); 244 | array = json_realloc(array, mysize); 245 | #endif 246 | } 247 | mycapacity = mysize; 248 | } 249 | 250 | 251 | inline static void deleteChildren(jsonChildren * ptr) json_nothrow { 252 | #ifdef JSON_MEMORY_CALLBACKS 253 | ptr -> ~jsonChildren(); 254 | libjson_free(ptr); 255 | #else 256 | delete ptr; 257 | #endif 258 | } 259 | 260 | inline static jsonChildren * newChildren(void) { 261 | #ifdef JSON_MEMORY_CALLBACKS 262 | return new(json_malloc(1)) jsonChildren(); 263 | #else 264 | return new jsonChildren(); 265 | #endif 266 | } 267 | 268 | JSONNode ** array; //the expandable array 269 | 270 | json_index_t mysize; //the number of valid items 271 | json_index_t mycapacity; //the number of possible items 272 | JSON_PROTECTED 273 | //to make sure it's not copyable 274 | jsonChildren(const jsonChildren &); 275 | jsonChildren & operator = (const jsonChildren &); 276 | 277 | void deleteAll(void) json_nothrow json_hot; //implemented in JSONNode.cpp 278 | void doerase(JSONNode ** position, json_index_t number) json_nothrow; 279 | }; 280 | 281 | #ifdef JSON_LESS_MEMORY 282 | class jsonChildren_Reserved : public jsonChildren { 283 | public: 284 | LIBJSON_OBJECT(jsonChildren_Reserved); 285 | jsonChildren_Reserved(jsonChildren * orig, json_index_t siz) json_nothrow : jsonChildren(orig -> array, orig -> mysize, orig -> mycapacity), myreserved(siz) { 286 | orig -> array = 0; 287 | deleteChildren(orig); 288 | LIBJSON_CTOR; 289 | } 290 | jsonChildren_Reserved(const jsonChildren_Reserved & orig) json_nothrow : jsonChildren(orig.array, orig.mysize, orig.mycapacity), myreserved(orig.myreserved){ 291 | LIBJSON_COPY_CTOR; 292 | } 293 | inline virtual ~jsonChildren_Reserved() json_nothrow { 294 | LIBJSON_DTOR; 295 | }; 296 | inline virtual void shrink() json_nothrow { 297 | JSON_ASSERT(this != 0, JSON_TEXT("Children is null shrink reserved")); 298 | if (json_unlikely(mysize == 0)){ //size is zero, we should completely free the array 299 | libjson_free(array); //free does checks for a null pointer, so don't bother checking 300 | array = 0; 301 | } else if (mysize > myreserved){ 302 | JSON_ASSERT(array != 0, JSON_TEXT("shrinking a null array that is not size 0")); 303 | array = json_realloc(array, mysize); 304 | } 305 | } 306 | 307 | #ifdef JSON_LESS_MEMORY 308 | inline static jsonChildren * newChildren_Reserved(jsonChildren * orig, json_index_t siz) json_nothrow { 309 | #ifdef JSON_MEMORY_CALLBACKS 310 | return new(json_malloc(1)) jsonChildren_Reserved(orig, siz); 311 | #else 312 | return new jsonChildren_Reserved(orig, siz); 313 | #endif 314 | } 315 | #endif 316 | JSON_PRIVATE 317 | jsonChildren_Reserved & operator = (const jsonChildren_Reserved &); 318 | json_index_t myreserved; 319 | }; 320 | #endif 321 | 322 | #ifdef JSON_LESS_MEMORY 323 | #ifdef __GNUC__ 324 | #pragma pack(pop) 325 | #elif _MSC_VER 326 | #pragma pack(pop, jsonChildren) 327 | #endif 328 | #endif 329 | #endif 330 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONDebug.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONDebug.h" 2 | #ifdef JSON_DEBUG 3 | 4 | #ifdef JSON_STDERROR 5 | #include //need std::cerr 6 | #else 7 | #include "JSONSingleton.h" 8 | //otherwise, use a callback to tell the end user what happened 9 | json_error_callback_t JSONDebug::register_callback(json_error_callback_t callback) json_nothrow { 10 | json_error_callback_t res = JSONSingleton::get(); 11 | JSONSingleton::set(callback); 12 | return res; 13 | } 14 | #endif 15 | 16 | //Something went wrong or an assert failed 17 | void JSONDebug::_JSON_FAIL(const json_string & msg) json_nothrow { 18 | #ifdef JSON_STDERROR //no callback, just use stderror 19 | #ifndef JSON_UNICODE 20 | std::cerr << msg << std::endl; 21 | #else 22 | std::cerr << std::string(msg.begin(), msg.end()) << std::endl; 23 | #endif 24 | #else 25 | if (json_error_callback_t ErrorCallback = JSONSingleton::get()){ //only do anything if the callback is registered 26 | #ifdef JSON_LIBRARY 27 | ErrorCallback(msg.c_str()); 28 | #else 29 | ErrorCallback(msg); 30 | #endif 31 | } 32 | #endif 33 | } 34 | 35 | //asserts that condition is true, more useful than cassert because it lets you keep going 36 | void JSONDebug::_JSON_ASSERT(bool condition, const json_string & msg) json_nothrow { 37 | if (json_unlikely(!condition)){ 38 | _JSON_FAIL(msg); 39 | } 40 | } 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONDebug.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBJSON_GUARD_DEBUG_H 2 | #define LIBJSON_GUARD_DEBUG_H 3 | 4 | #include "JSONDefs.h" 5 | #include "JSONStats.h" 6 | 7 | #ifdef JSON_DEBUG 8 | #ifdef JSON_SAFE 9 | #define JSON_ASSERT_SAFE(condition, msg, code)\ 10 | {\ 11 | if (json_unlikely(!(condition))){\ 12 | JSON_FAIL(msg);\ 13 | code\ 14 | }\ 15 | } 16 | #define JSON_FAIL_SAFE(msg, code)\ 17 | {\ 18 | JSON_FAIL(msg);\ 19 | code\ 20 | } 21 | #else 22 | #define JSON_ASSERT_SAFE(condition, msg, code) JSON_ASSERT(condition, msg) 23 | #define JSON_FAIL_SAFE(msg, code) JSON_FAIL(msg) 24 | #endif 25 | 26 | #define JSON_FAIL(msg) JSONDebug::_JSON_FAIL(msg) 27 | #define JSON_ASSERT(bo, msg) JSONDebug::_JSON_ASSERT(bo, msg) 28 | 29 | class JSONDebug { 30 | public: 31 | #ifndef JSON_STDERROR 32 | static json_error_callback_t register_callback(json_error_callback_t callback) json_nothrow json_cold; 33 | #endif 34 | static void _JSON_FAIL(const json_string & msg) json_nothrow json_cold; 35 | static void _JSON_ASSERT(bool condition, const json_string & msg) json_nothrow json_cold; 36 | }; 37 | #else 38 | #ifdef JSON_SAFE 39 | #define JSON_ASSERT_SAFE(condition, msg, code)\ 40 | {\ 41 | if (json_unlikely(!(condition))){\ 42 | code\ 43 | }\ 44 | } 45 | #define JSON_FAIL_SAFE(msg, code)\ 46 | {\ 47 | code\ 48 | } 49 | #else 50 | #define JSON_ASSERT_SAFE(condition, msg, code) 51 | #define JSON_FAIL_SAFE(msg, code) 52 | #endif 53 | 54 | #define JSON_ASSERT(condition, msg) 55 | #define JSON_FAIL(msg) 56 | #endif 57 | 58 | #endif 59 | 60 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONDefs.h: -------------------------------------------------------------------------------- 1 | #ifndef JSONDEFS_H 2 | #define JSONDEFS_H 3 | 4 | /* 5 | Defines all of the types of functions and various other definitions 6 | that are used in C applications, this is very useful if dynamically loading 7 | the library instead of linking. 8 | */ 9 | 10 | #include "../../JSONOptions.h" 11 | #include "JSONDefs/Unknown_C.h" 12 | #include "JSONDefs/GNU_C.h" 13 | #include "JSONDefs/Visual_C.h" 14 | #include "JSONDefs/Strings_Defs.h" 15 | 16 | #define __LIBJSON_MAJOR__ 7 17 | #define __LIBJSON_MINOR__ 6 18 | #define __LIBJSON_PATCH__ 1 19 | #define __LIBJSON_VERSION__ (__LIBJSON_MAJOR__ * 10000 + __LIBJSON_MINOR__ * 100 + __LIBJSON_PATCH__) 20 | 21 | #define JSON_NULL '\0' 22 | #define JSON_STRING '\1' 23 | #define JSON_NUMBER '\2' 24 | #define JSON_BOOL '\3' 25 | #define JSON_ARRAY '\4' 26 | #define JSON_NODE '\5' 27 | 28 | #ifdef __cplusplus 29 | #if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL) 30 | #include "JSONAllocator.h" 31 | #else 32 | #define json_allocator std::allocator 33 | #endif 34 | 35 | #ifdef JSON_STRING_HEADER 36 | #include JSON_STRING_HEADER 37 | #else 38 | typedef std::basic_string, json_allocator > json_string; 39 | #endif 40 | #endif 41 | #define JSON_MAP(x, y) std::map, json_allocator > > 42 | 43 | #ifdef JSON_NO_EXCEPTIONS 44 | #define json_throw(x) 45 | #define json_try 46 | #define json_catch(exception, code) 47 | #else 48 | #define json_throw(x) throw(x) 49 | #define json_try try 50 | #define json_catch(exception, code) catch(exception){ code } 51 | #endif 52 | 53 | #ifdef JSON_STRICT 54 | #ifndef JSON_UNICODE 55 | #error, JSON_UNICODE is required for JSON_STRICT 56 | #endif 57 | #ifdef JSON_COMMENTS 58 | #error, JSON_COMMENTS is required to be off for JSON_STRICT 59 | #endif 60 | #endif 61 | 62 | #ifdef JSON_ISO_STRICT 63 | #ifdef JSON_UNICODE 64 | #error, You can not use unicode under ANSI Strict C++ 65 | #endif 66 | #else 67 | #ifdef __GNUC__ 68 | #ifdef __STRICT_ANSI__ 69 | #warning, Using -ansi GCC option, but JSON_ISO_STRICT not on, turning it on for you 70 | #define JSON_ISO_STRICT 71 | #endif 72 | #endif 73 | #endif 74 | 75 | 76 | #ifdef JSON_NUMBER_TYPE 77 | typedef JSON_NUMBER_TYPE json_number; 78 | #define JSON_FLOAT_THRESHHOLD 0.00001 79 | #else 80 | #ifdef JSON_LESS_MEMORY 81 | typedef float json_number; 82 | #define JSON_FLOAT_THRESHHOLD 0.00001f 83 | #else 84 | typedef double json_number; 85 | #define JSON_FLOAT_THRESHHOLD 0.00001 86 | #endif 87 | #endif 88 | 89 | 90 | #ifdef JSON_LESS_MEMORY 91 | /* PACKED and BITS stored in compiler specific headers */ 92 | #define START_MEM_SCOPE { 93 | #define END_MEM_SCOPE } 94 | #else 95 | #define PACKED(x) 96 | #define BITS(x) 97 | #define START_MEM_SCOPE 98 | #define END_MEM_SCOPE 99 | #endif 100 | 101 | #if defined JSON_DEBUG || defined JSON_SAFE 102 | #ifdef JSON_LIBRARY 103 | typedef void (*json_error_callback_t)(const json_char *); 104 | #else 105 | typedef void (*json_error_callback_t)(const json_string &); 106 | #endif 107 | #endif 108 | 109 | #ifdef JSON_INDEX_TYPE 110 | typedef JSON_INDEX_TYPE json_index_t; 111 | #else 112 | typedef unsigned int json_index_t; 113 | #endif 114 | 115 | #ifdef JSON_BOOL_TYPE 116 | typedef JSON_BOOL_TYPE json_bool_t; 117 | #else 118 | typedef int json_bool_t; 119 | #endif 120 | 121 | #ifdef JSON_INT_TYPE 122 | typedef JSON_INT_TYPE json_int_t; 123 | #else 124 | typedef long json_int_t; 125 | #endif 126 | 127 | #define JSONSTREAM_SELF (void*)-1 128 | typedef void (*json_stream_e_callback_t)(void * identifier); 129 | 130 | typedef void (*json_mutex_callback_t)(void *); 131 | typedef void (*json_free_t)(void *); 132 | #ifndef JSON_LIBRARY 133 | typedef void * (*json_malloc_t)(size_t); 134 | typedef void * (*json_realloc_t)(void *, size_t); 135 | #else 136 | #define JSONNODE void /* so that JSONNODE* is void* */ 137 | typedef JSONNODE** JSONNODE_ITERATOR; 138 | #ifdef JSON_STREAM 139 | #define JSONSTREAM void 140 | typedef void (*json_stream_callback_t)(JSONNODE *, void * identifier); 141 | #endif 142 | typedef void * (*json_malloc_t)(unsigned long); 143 | typedef void * (*json_realloc_t)(void *, unsigned long); 144 | #endif 145 | 146 | #ifdef JSON_DEBUG 147 | #ifdef NDEBUG 148 | #ifdef __GNUC__ 149 | #warning, Have JSON_DEBUG on in a release build 150 | #else 151 | #error, Have JSON_DEBUG on in a release build 152 | #endif 153 | #endif 154 | #else 155 | #ifndef NDEBUG 156 | #ifdef __GNUC__ 157 | #warning, Release build of libjson, but NDEBUG is not on 158 | #else 159 | #error, Release build of libjson, but NDEBUG is not on 160 | #endif 161 | #endif 162 | #endif 163 | 164 | #ifdef JSON_UNIT_TEST 165 | #define JSON_PRIVATE public: 166 | #define JSON_PROTECTED public: 167 | #else 168 | #define JSON_PRIVATE private: 169 | #define JSON_PROTECTED protected: 170 | #endif 171 | #ifdef JSON_STREAM 172 | #ifndef JSON_READ_PRIORITY 173 | #error, JSON_STREAM also requires JSON_READ_PRIORITY 174 | #endif 175 | #endif 176 | #ifdef JSON_VALIDATE 177 | #ifndef JSON_READ_PRIORITY 178 | #error, JSON_VALIDATE also requires JSON_READ_PRIORITY 179 | #endif 180 | #endif 181 | 182 | #define JSON_TEMP_COMMENT_IDENTIFIER JSON_TEXT('#') 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONDefs/GNU_C.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_GNU_C_HEADER 2 | #define JSON_GNU_C_HEADER 3 | 4 | #ifdef __GNUC__ 5 | 6 | #define json_deprecated(method, warning) method __attribute__((deprecated)) 7 | 8 | #if (__GNUC__ >= 3) 9 | #define JSON_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 10 | #else 11 | #define JSON_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) 12 | #endif 13 | 14 | #if (JSON_GCC_VERSION >= 40300) 15 | #define json_hot __attribute__ ((hot)) 16 | #define json_cold __attribute__ ((cold)) 17 | #define json_pure json_nothrow __attribute__ ((pure, hot)) 18 | #define json_malloc_attr json_nothrow __attribute__ ((malloc, hot)) 19 | 20 | /* Can do priorities */ 21 | #if (JSON_WRITE_PRIORITY == HIGH) 22 | #define json_write_priority __attribute__ ((hot)) 23 | #elif (JSON_WRITE_PRIORITY == LOW) 24 | #define json_write_priority __attribute__ ((cold)) 25 | #else 26 | #define json_write_priority 27 | #endif 28 | 29 | #if (JSON_READ_PRIORITY == HIGH) 30 | #define json_read_priority __attribute__ ((hot)) 31 | #elif (JSON_READ_PRIORITY == LOW) 32 | #define json_read_priority __attribute__ ((cold)) 33 | #else 34 | #define json_read_priority 35 | #endif 36 | 37 | #define json_likely(x) __builtin_expect((long)((bool)(x)),1) 38 | #define json_unlikely(x) __builtin_expect((long)((bool)(x)),0) 39 | #else 40 | #if (JSON_GCC_VERSION >= 29600) 41 | #define json_pure json_nothrow __attribute__ ((pure)) 42 | #define json_likely(x) __builtin_expect((long)((bool)(x)),1) 43 | #define json_unlikely(x) __builtin_expect((long)((bool)(x)),0) 44 | #else 45 | #define json_pure json_nothrow 46 | #define json_likely(x) x 47 | #define json_unlikely(x) x 48 | #endif 49 | 50 | #define json_malloc_attr json_nothrow __attribute__ ((malloc)) 51 | #define json_write_priority 52 | #define json_read_priority 53 | #define json_hot 54 | #define json_cold 55 | #endif 56 | 57 | #define json_nothrow throw() 58 | #define json_throws(x) throw(x) 59 | 60 | #ifdef JSON_LESS_MEMORY 61 | #define PACKED(x) :x __attribute__ ((packed)) 62 | #define BITS(x) :x 63 | #endif 64 | 65 | #endif 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONDefs/Strings_Defs.h: -------------------------------------------------------------------------------- 1 | #ifndef STRINGS_DEFS_HEADER 2 | #define STRINGS_DEFS_HEADER 3 | 4 | #include "../../../JSONOptions.h" 5 | 6 | #ifdef JSON_UNICODE 7 | #define json_char wchar_t 8 | #define json_uchar wchar_t 9 | #ifdef __cplusplus 10 | #include /* need wide characters */ 11 | #ifndef JSON_STRING_HEADER 12 | #include 13 | #endif 14 | #else 15 | #include /* need wide characters */ 16 | #endif 17 | #define JSON_TEXT(s) L ## s 18 | #define json_strlen wcslen 19 | #define json_strcmp wcscmp 20 | #else 21 | #define json_char char 22 | #define json_uchar unsigned char 23 | #ifdef __cplusplus 24 | #ifndef JSON_STRING_HEADER 25 | #include 26 | #endif 27 | #else 28 | #include /* still need it for strlen and such */ 29 | #endif 30 | #define JSON_TEXT(s) s 31 | #define json_strlen strlen 32 | #define json_strcmp strcmp 33 | #endif 34 | 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONDefs/Unknown_C.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_UNKNOWN_C_HEADER 2 | #define JSON_UNKNOWN_C_HEADER 3 | 4 | #if !defined(__GNUC__) && !defined(_MSC_VER) 5 | 6 | #define json_deprecated(method, warning) method 7 | 8 | #define json_nothrow 9 | #define json_throws(x) 10 | #define json_pure json_nothrow 11 | #define json_read_priority 12 | #define json_write_priority 13 | #define json_malloc_attr json_nothrow 14 | #define json_hot 15 | #define json_cold 16 | #define json_likely(x) x 17 | #define json_unlikely(x) x 18 | 19 | #ifdef JSON_LESS_MEMORY 20 | #define PACKED(x) :x 21 | #define BITS(x) :x 22 | #endif 23 | 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONDefs/Visual_C.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_VISUAL_C_HEADER 2 | #define JSON_VISUAL_C_HEADER 3 | 4 | #ifdef _MSC_VER 5 | 6 | #define json_deprecated(method, warning) __declspec(deprecated(warning)) method 7 | 8 | #define json_nothrow 9 | #define json_throws(x) 10 | #define json_pure json_nothrow 11 | #define json_read_priority 12 | #define json_write_priority 13 | #define json_malloc_attr json_nothrow 14 | #define json_hot 15 | #define json_cold 16 | #define json_likely(x) x 17 | #define json_unlikely(x) x 18 | 19 | #ifdef JSON_LESS_MEMORY 20 | #define PACKED(x) :x 21 | #define BITS(x) :x 22 | #endif 23 | 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONGlobals.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_GLOBALS_H 2 | #define JSON_GLOBALS_H 3 | 4 | #include "JSONDefs.h" 5 | 6 | /* 7 | * The use of singletons for globals makes globals not 8 | * actually be initialized until it is first needed, this 9 | * makes the library faster to load, and have a smaller 10 | * memory footprint 11 | */ 12 | 13 | #define json_global_decl(TYPE, NAME, VALUE) \ 14 | class jsonSingleton ## NAME { \ 15 | public: \ 16 | inline static TYPE & getValue() json_nothrow { \ 17 | static jsonSingleton ## NAME single; \ 18 | return single.val; \ 19 | } \ 20 | protected: \ 21 | inline jsonSingleton ## NAME() json_nothrow : val(VALUE) {} \ 22 | TYPE val; \ 23 | } 24 | 25 | #define json_global_decl_strconfig(TYPE, NAME, VALUE) \ 26 | class jsonSingleton ## NAME { \ 27 | public: \ 28 | inline static TYPE & getValue() json_nothrow { \ 29 | static jsonSingleton ## NAME single; \ 30 | return single.val; \ 31 | } \ 32 | protected: \ 33 | inline jsonSingleton ## NAME() json_nothrow { \ 34 | const std::string tmp = std::string(VALUE); \ 35 | val = json_string(tmp.begin(), tmp.end()); \ 36 | } \ 37 | TYPE val; \ 38 | } 39 | 40 | #define json_global(NAME) jsonSingleton ## NAME::getValue() 41 | 42 | #include 43 | json_global_decl(json_string, EMPTY_JSON_STRING, ); 44 | json_global_decl(std::string, EMPTY_STD_STRING, ); 45 | 46 | json_global_decl(json_string, CONST_TRUE, JSON_TEXT("true")); 47 | json_global_decl(json_string, CONST_FALSE, JSON_TEXT("false")); 48 | json_global_decl(json_string, CONST_NULL, JSON_TEXT("null")); 49 | 50 | #ifndef JSON_NEWLINE 51 | json_global_decl(json_string, NEW_LINE, JSON_TEXT("\n")); 52 | #else 53 | json_global_decl_strconfig(json_string, NEW_LINE, JSON_NEWLINE); 54 | #endif 55 | 56 | #ifdef JSON_WRITE_BASH_COMMENTS 57 | json_global_decl(json_string, SINGLELINE_COMMENT, JSON_TEXT("#")); 58 | #else 59 | json_global_decl(json_string, SINGLELINE_COMMENT, JSON_TEXT("//")); 60 | #endif 61 | 62 | #ifdef JSON_INDENT 63 | json_global_decl_strconfig(json_string, INDENT, JSON_INDENT); 64 | #endif 65 | 66 | #ifdef JSON_MUTEX_CALLBACKS 67 | #include 68 | json_global_decl(JSON_MAP(void *, unsigned int), MUTEX_MANAGER, ); 69 | json_global_decl(JSON_MAP(int, JSON_MAP(void *, unsigned int) ), THREAD_LOCKS, ); 70 | #endif 71 | 72 | #ifdef JSON_LIBRARY 73 | #ifdef JSON_MEMORY_MANAGE 74 | #include "JSONMemory.h" 75 | json_global_decl(auto_expand, STRING_HANDLER, ); 76 | json_global_decl(auto_expand_node, NODE_HANDLER, ); 77 | #ifdef JSON_STREAM 78 | json_global_decl(auto_expand_stream, STREAM_HANDLER, ); 79 | #endif 80 | #endif 81 | #endif 82 | 83 | //These are common error responses 84 | json_global_decl(json_string, ERROR_TOO_LONG, JSON_TEXT("Exceeding JSON_SECURITY_MAX_STRING_LENGTH")); 85 | json_global_decl(json_string, ERROR_UNKNOWN_LITERAL, JSON_TEXT("Unknown JSON literal: ")); 86 | json_global_decl(json_string, ERROR_NON_CONTAINER, JSON_TEXT("Calling container method on non-container: ")); 87 | json_global_decl(json_string, ERROR_NON_ITERATABLE, JSON_TEXT("Calling iterator method on non-iteratable: ")); 88 | json_global_decl(json_string, ERROR_NULL_IN_CHILDREN, JSON_TEXT("a null pointer within the children")); 89 | json_global_decl(json_string, ERROR_UNDEFINED, JSON_TEXT("Undefined results: ")); 90 | json_global_decl(json_string, ERROR_LOWER_RANGE, JSON_TEXT(" is outside the lower range of ")); 91 | json_global_decl(json_string, ERROR_UPPER_RANGE, JSON_TEXT(" is outside the upper range of ")); 92 | json_global_decl(json_string, ERROR_NOT_BASE64, JSON_TEXT("Not base64")); 93 | json_global_decl(json_string, ERROR_OUT_OF_MEMORY, JSON_TEXT("Out of memory")); 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONIterators.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONNode.h" 2 | 3 | #ifdef JSON_ITERATORS 4 | #ifdef JSON_REF_COUNT 5 | #define JSON_ASSERT_UNIQUE(x) JSON_ASSERT(internal -> refcount == 1, json_string(JSON_TEXT(x)) + JSON_TEXT(" in non single reference")) 6 | #else 7 | #define JSON_ASSERT_UNIQUE(x) (void)0 8 | #endif 9 | 10 | #ifdef JSON_MUTEX_CALLBACKS 11 | #define JSON_MUTEX_COPY2 ,internal -> mylock 12 | #else 13 | #define JSON_MUTEX_COPY2 14 | #endif 15 | 16 | JSONNode::json_iterator JSONNode::find(const json_string & name_t) json_nothrow { 17 | JSON_CHECK_INTERNAL(); 18 | JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("find")); 19 | makeUniqueInternal(); 20 | if (JSONNode ** res = internal -> at(name_t)){ 21 | return ptr_to_json_iterator(res); 22 | } 23 | return end(); 24 | } 25 | 26 | #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS 27 | JSONNode::json_iterator JSONNode::find_nocase(const json_string & name_t) json_nothrow { 28 | JSON_CHECK_INTERNAL(); 29 | JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("find_nocase")); 30 | makeUniqueInternal(); 31 | if (JSONNode ** res = internal -> at_nocase(name_t)){ 32 | return ptr_to_json_iterator(res); 33 | } 34 | return end(); 35 | } 36 | #endif 37 | 38 | JSONNode::json_iterator JSONNode::erase(json_iterator pos) json_nothrow { 39 | JSON_CHECK_INTERNAL(); 40 | JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("erase")); 41 | JSON_ASSERT_UNIQUE("erase 1"); 42 | JSON_ASSERT_SAFE(pos < end(), JSON_TEXT("erase out of range"), return end();); 43 | JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("erase out of range"), return begin();); 44 | deleteJSONNode(*(json_iterator_ptr(pos))); 45 | internal -> CHILDREN -> erase(json_iterator_ptr(pos)); 46 | return (empty()) ? end() : pos; 47 | } 48 | 49 | JSONNode::json_iterator JSONNode::erase(json_iterator _start, const json_iterator & _end) json_nothrow { 50 | if (_start == _end) return _start; 51 | JSON_CHECK_INTERNAL(); 52 | JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("erase")); 53 | JSON_ASSERT_UNIQUE("erase 3"); 54 | JSON_ASSERT_SAFE(_start <= end(), JSON_TEXT("erase out of lo range"), return end();); 55 | JSON_ASSERT_SAFE(_end <= end(), JSON_TEXT("erase out of hi range"), return end();); 56 | JSON_ASSERT_SAFE(_start >= begin(), JSON_TEXT("erase out of lo range"), return begin();); 57 | JSON_ASSERT_SAFE(_end >= begin(), JSON_TEXT("erase out of hi range"), return begin();); 58 | for (JSONNode ** pos = json_iterator_ptr(_start); pos < json_iterator_ptr(_end); ++pos){ 59 | deleteJSONNode(*pos); 60 | } 61 | 62 | internal -> CHILDREN -> erase(json_iterator_ptr(_start), (json_index_t)(json_iterator_ptr(_end) - json_iterator_ptr(_start))); 63 | return (empty()) ? end() : _start; 64 | } 65 | 66 | #ifdef JSON_LIBRARY 67 | JSONNode::json_iterator JSONNode::insert(json_iterator pos, JSONNode * x) json_nothrow { 68 | #else 69 | JSONNode::json_iterator JSONNode::insert(json_iterator pos, const JSONNode & x) json_nothrow { 70 | #endif 71 | JSON_CHECK_INTERNAL(); 72 | JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insert")); 73 | JSON_ASSERT_UNIQUE("insert 1"); 74 | if (json_iterator_ptr(pos) >= internal -> CHILDREN -> end()){ 75 | internal -> push_back(x); 76 | return end() - 1; 77 | } 78 | JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of lo range"), return begin();); 79 | #ifdef JSON_LIBRARY 80 | internal -> CHILDREN -> insert(json_iterator_ptr(pos), x); 81 | #else 82 | internal -> CHILDREN -> insert(json_iterator_ptr(pos), newJSONNode(x)); 83 | #endif 84 | return pos; 85 | } 86 | 87 | JSONNode::json_iterator JSONNode::insertFFF(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow { 88 | JSON_CHECK_INTERNAL(); 89 | JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insertFFF")); 90 | JSON_ASSERT_UNIQUE("insertFFF"); 91 | JSON_ASSERT_SAFE(pos <= end(), JSON_TEXT("insert out of high range"), return end();); 92 | JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of low range"), return begin();); 93 | const json_index_t num = (json_index_t)(_end - _start); 94 | json_auto mem(num); 95 | JSONNode ** runner = mem.ptr; 96 | for (JSONNode ** po = _start; po < _end; ++po){ 97 | *runner++ = newJSONNode(*(*po) JSON_MUTEX_COPY2); 98 | } 99 | internal -> CHILDREN -> insert(json_iterator_ptr(pos), mem.ptr, num); 100 | return pos; 101 | } 102 | 103 | #ifndef JSON_LIBRARY 104 | JSONNode::const_iterator JSONNode::find(const json_string & name_t) const json_nothrow { 105 | JSON_CHECK_INTERNAL(); 106 | JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("find")); 107 | if (JSONNode ** res = internal -> at(name_t)){ 108 | return JSONNode::const_iterator(res); 109 | } 110 | return JSONNode::const_iterator(internal -> end()); 111 | } 112 | 113 | #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS 114 | JSONNode::const_iterator JSONNode::find_nocase(const json_string & name_t) const json_nothrow { 115 | JSON_CHECK_INTERNAL(); 116 | JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("find_nocase")); 117 | if (JSONNode ** res = internal -> at_nocase(name_t)){ 118 | return JSONNode::const_iterator(res); 119 | } 120 | return JSONNode::const_iterator(internal -> end()); 121 | } 122 | #endif 123 | 124 | JSONNode::reverse_iterator JSONNode::erase(reverse_iterator pos) json_nothrow { 125 | JSON_CHECK_INTERNAL(); 126 | JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("erase")); 127 | JSON_ASSERT_UNIQUE("erase 2"); 128 | JSON_ASSERT_SAFE(pos < rend(), JSON_TEXT("erase out of range"), return rend();); 129 | JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("erase out of range"), return rbegin();); 130 | deleteJSONNode(*(pos.it)); 131 | internal -> CHILDREN -> erase(pos.it); 132 | return (empty()) ? rend() : pos + 1; 133 | } 134 | 135 | JSONNode::reverse_iterator JSONNode::erase(reverse_iterator _start, const reverse_iterator & _end) json_nothrow { 136 | if (_start == _end) return _start; 137 | JSON_CHECK_INTERNAL(); 138 | JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("erase")); 139 | JSON_ASSERT_UNIQUE("erase 4"); 140 | JSON_ASSERT_SAFE(_start <= rend(), JSON_TEXT("erase out of lo range"), return rend();); 141 | JSON_ASSERT_SAFE(_end <= rend(), JSON_TEXT("erase out of hi range"), return rend();); 142 | JSON_ASSERT_SAFE(_start >= rbegin(), JSON_TEXT("erase out of lo range"), return rbegin();); 143 | JSON_ASSERT_SAFE(_end >= rbegin(), JSON_TEXT("erase out of hi range"), return rbegin();); 144 | for (JSONNode ** pos = _start.it; pos > _end.it; --pos){ 145 | deleteJSONNode(*pos); 146 | } 147 | const json_index_t num = (json_index_t)(_start.it - _end.it); 148 | internal -> CHILDREN -> erase(_end.it + 1, num, _start.it); 149 | return (empty()) ? rend() : _start + num; 150 | } 151 | 152 | JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const JSONNode & x) json_nothrow { 153 | JSON_CHECK_INTERNAL(); 154 | JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insert")); 155 | JSON_ASSERT_UNIQUE("insert 1"); 156 | if (pos.it < internal -> CHILDREN -> begin()){ 157 | internal -> push_front(x); 158 | return rend() - 1; 159 | } 160 | JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); 161 | internal -> CHILDREN -> insert(++pos.it, newJSONNode(x), true); 162 | return pos; 163 | } 164 | 165 | JSONNode::reverse_iterator JSONNode::insertRFF(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow { 166 | JSON_CHECK_INTERNAL(); 167 | JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insertRFF")); 168 | JSON_ASSERT_UNIQUE("insert RFF"); 169 | JSON_ASSERT_SAFE(pos <= rend(), JSON_TEXT("insert out of range"), return rend();); 170 | JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); 171 | const json_index_t num = (json_index_t)(_end - _start); 172 | json_auto mem(num); 173 | JSONNode ** runner = mem.ptr + num; 174 | for (JSONNode ** po = _start; po < _end; ++po){ //fill it backwards 175 | *(--runner) = newJSONNode(*(*po) JSON_MUTEX_COPY2); 176 | } 177 | internal -> CHILDREN -> insert(++pos.it, mem.ptr, num); 178 | return pos - num + 1; 179 | } 180 | 181 | JSONNode::iterator JSONNode::insertFRR(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow { 182 | JSON_CHECK_INTERNAL(); 183 | JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insertFRR")); 184 | JSON_ASSERT_UNIQUE("insert FRR"); 185 | JSON_ASSERT_SAFE(pos <= end(), JSON_TEXT("insert out of range"), return end();); 186 | JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of range"), return begin();); 187 | const json_index_t num = (json_index_t)(_start - _end); 188 | json_auto mem(num); 189 | JSONNode ** runner = mem.ptr; 190 | for (JSONNode ** po = _start; po > _end; --po){ 191 | *runner++ = newJSONNode(*(*po) JSON_MUTEX_COPY2); 192 | } 193 | internal -> CHILDREN -> insert(pos.it, mem.ptr, num); 194 | return pos; 195 | } 196 | 197 | JSONNode::reverse_iterator JSONNode::insertRRR(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow { 198 | JSON_CHECK_INTERNAL(); 199 | JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insertRRR")); 200 | JSON_ASSERT_UNIQUE("insert RRR"); 201 | JSON_ASSERT_SAFE(pos <= rend(), JSON_TEXT("insert out of range"), return rend();); 202 | JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); 203 | const json_index_t num = (json_index_t)(_start - _end); 204 | json_auto mem(num); 205 | JSONNode ** runner = mem.ptr; 206 | for (JSONNode ** po = _start; po > _end; --po){ 207 | *runner++ = newJSONNode(*(*po) JSON_MUTEX_COPY2); 208 | } 209 | internal -> CHILDREN -> insert(++pos.it, mem.ptr, num); 210 | return pos - num + 1; 211 | } 212 | #endif 213 | 214 | #endif 215 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONMemory.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONMemory.h" 2 | 3 | #ifdef JSON_MEMORY_MANAGE 4 | #include "JSONNode.h" 5 | void auto_expand::purge(void) json_nothrow { 6 | for(JSON_MAP(void *, void *)::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ 7 | #if defined(JSON_DEBUG) || defined(JSON_SAFE) 8 | void * temp = (void*)i -> first; //because its pass by reference 9 | libjson_free(temp); 10 | #else 11 | libjson_free((void*)i -> first); 12 | #endif 13 | } 14 | } 15 | 16 | void auto_expand_node::purge(void) json_nothrow { 17 | for(JSON_MAP(void *, JSONNode *)::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ 18 | JSONNode::deleteJSONNode((JSONNode *)i -> second); 19 | } 20 | } 21 | 22 | #ifdef JSON_STREAM 23 | #include "JSONStream.h" 24 | void auto_expand_stream::purge(void) json_nothrow { 25 | for(JSON_MAP(void *, JSONStream *)::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ 26 | JSONStream::deleteJSONStream((JSONStream *)i -> second); 27 | } 28 | } 29 | #endif 30 | #endif 31 | 32 | #if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL) 33 | 34 | #ifdef JSON_MEMORY_POOL 35 | #include "JSONMemoryPool.h" 36 | static bucket_pool_8 json_generic_mempool; 37 | 38 | //This class is only meant to initiate the mempool to start out using std::malloc/realloc/free 39 | class mempool_callback_setter { 40 | public: 41 | LIBJSON_OBJECT(mempool_callback_setter); 42 | inline mempool_callback_setter(void) json_nothrow { 43 | ` LIBJSON_CTOR; 44 | mempool_callbacks::set(std::malloc, std::realloc, std::free); 45 | } 46 | private: 47 | inline mempool_callback_setter(const mempool_callback_setter & o); 48 | inline mempool_callback_setter & operator = (const mempool_callback_setter & o); 49 | }; 50 | static mempool_callback_setter __mempoolcallbacksetter; 51 | #endif 52 | 53 | #include "JSONSingleton.h" 54 | 55 | void * JSONMemory::json_malloc(size_t siz) json_nothrow { 56 | #ifdef JSON_MEMORY_POOL 57 | return json_generic_mempool.allocate(siz); 58 | #else 59 | if (json_malloc_t callback = JSONSingleton::get()){ 60 | #if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful 61 | void * result = callback(siz); 62 | JSON_ASSERT(result, JSON_TEXT("Out of memory")); 63 | return result; 64 | #else 65 | return callback(siz); 66 | #endif 67 | } 68 | #if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful 69 | void * result = std::malloc(siz); 70 | JSON_ASSERT(result, JSON_TEXT("Out of memory")); 71 | return result; 72 | #else 73 | return std::malloc(siz); 74 | #endif 75 | #endif 76 | } 77 | 78 | void JSONMemory::json_free(void * ptr) json_nothrow { 79 | #ifdef JSON_MEMORY_POOL 80 | json_generic_mempool.deallocate(ptr); 81 | #else 82 | if (json_free_t callback = JSONSingleton::get()){ 83 | callback(ptr); 84 | } else { 85 | std::free(ptr); 86 | } 87 | #endif 88 | } 89 | 90 | void * JSONMemory::json_realloc(void * ptr, size_t siz) json_nothrow { 91 | #ifdef JSON_MEMORY_POOL 92 | return json_generic_mempool.reallocate(ptr, siz); 93 | #else 94 | if (json_realloc_t callback = JSONSingleton::get()){ 95 | #if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful 96 | void * result = callback(ptr, siz); 97 | JSON_ASSERT(result, JSON_TEXT("Out of memory")); 98 | return result; 99 | #else 100 | return callback(ptr, siz); 101 | #endif 102 | } 103 | #if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful 104 | void * result = std::realloc(ptr, siz); 105 | JSON_ASSERT(result, JSON_TEXT("Out of memory")); 106 | return result; 107 | #else 108 | return std::realloc(ptr, siz); 109 | #endif 110 | #endif 111 | } 112 | 113 | #ifdef JSON_MEMORY_POOL 114 | //it is okay to pass null to these callbacks, no make sure they function exists 115 | static void * malloc_proxy(size_t siz) json_nothrow { 116 | if (json_malloc_t callback = JSONSingleton::get()){ 117 | return callback(siz); 118 | } 119 | return std::malloc(siz); 120 | } 121 | 122 | static void * realloc_proxy(void * ptr, size_t siz) json_nothrow { 123 | if (json_realloc_t callback = JSONSingleton::get()){ 124 | return callback(ptr, siz); 125 | } 126 | return std::realloc(ptr, siz); 127 | } 128 | 129 | static void free_proxy(void * ptr){ 130 | if (json_free_t callback = JSONSingleton::get()){ 131 | callback(ptr); 132 | } else { 133 | std::free(ptr); 134 | } 135 | } 136 | #endif 137 | 138 | 139 | void JSONMemory::registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre) json_nothrow { 140 | JSONSingleton::set(mal); 141 | JSONSingleton::set(real); 142 | JSONSingleton::set(fre); 143 | #ifdef JSON_MEMORY_POOL 144 | mempool_callbacks::set(malloc_proxy, realloc_proxy, free_proxy); 145 | #endif 146 | } 147 | 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONMemory.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_MEMORY_H 2 | #define JSON_MEMORY_H 3 | 4 | #include //for malloc, realloc, and free 5 | #include //for memmove 6 | #include "JSONDebug.h" 7 | 8 | #if defined(JSON_DEBUG) || defined(JSON_SAFE) 9 | #define JSON_FREE_PASSTYPE & 10 | #else 11 | #define JSON_FREE_PASSTYPE 12 | #endif 13 | 14 | #if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL) 15 | class JSONMemory { 16 | public: 17 | static void * json_malloc(size_t siz) json_malloc_attr; 18 | static void * json_realloc(void * ptr, size_t siz) json_malloc_attr; 19 | static void json_free(void * ptr) json_nothrow; 20 | static void registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre) json_nothrow json_cold; 21 | private: 22 | JSONMemory(void); 23 | }; 24 | 25 | template static inline T * json_malloc(size_t count) json_malloc_attr; 26 | template static inline T * json_malloc(size_t count) json_nothrow { 27 | return (T *)JSONMemory::json_malloc(sizeof(T) * count); 28 | } 29 | 30 | template static inline T * json_realloc(T * ptr, size_t count) json_malloc_attr; 31 | template static inline T * json_realloc(T * ptr, size_t count) json_nothrow { 32 | return (T *)JSONMemory::json_realloc(ptr, sizeof(T) * count); 33 | } 34 | 35 | template static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr) json_nothrow { 36 | JSONMemory::json_free(ptr); 37 | #if defined(JSON_DEBUG) || defined(JSON_SAFE) //in debug or safe mode, set the pointer to 0 so that it can't be used again 38 | ptr = 0; 39 | #endif 40 | } 41 | #else 42 | 43 | template static inline T * json_malloc(size_t count) json_malloc_attr; 44 | template static inline T * json_malloc(size_t count) json_nothrow { 45 | #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful 46 | void * result = std::malloc(count * sizeof(T)); 47 | JSON_ASSERT(result != 0, JSON_TEXT("Out of memory")); 48 | #ifdef JSON_NULL_MEMORY 49 | std::memset(result, '\0', count * sizeof(T)); 50 | #endif 51 | return (T *)result; 52 | #else 53 | return (T *)std::malloc(count * sizeof(T)); 54 | #endif 55 | } 56 | 57 | template static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr) json_nothrow { 58 | std::free(ptr); 59 | #if defined(JSON_DEBUG) || defined(JSON_SAFE) //in debug or safe mode, set the pointer to 0 so that it can't be used again 60 | ptr = 0; 61 | #endif 62 | } 63 | 64 | template static inline T * json_realloc(T * ptr, size_t count) json_malloc_attr; 65 | template static inline T * json_realloc(T * ptr, size_t count) json_nothrow { 66 | #ifdef JSON_DEBUG //in debug mode, check the results of realloc to be sure it was successful 67 | void * result = std::realloc(ptr, count * sizeof(T)); 68 | JSON_ASSERT(result != 0, JSON_TEXT("Out of memory")); 69 | return (T *)result; 70 | #else 71 | return (T *)std::realloc(ptr, count * sizeof(T)); 72 | #endif 73 | } 74 | #endif 75 | 76 | #ifdef JSON_MEMORY_MANAGE 77 | #include 78 | class JSONNode; 79 | struct auto_expand { 80 | public: 81 | LIBJSON_OBJECT(auto_expand); 82 | auto_expand(void) json_nothrow : mymap(){ LIBJSON_CTOR;} 83 | ~auto_expand(void) json_nothrow { purge(); LIBJSON_DTOR; } 84 | void purge(void) json_nothrow; 85 | inline void clear(void) json_nothrow { purge(); mymap.clear(); } 86 | inline void * insert(void * ptr) json_nothrow { mymap[ptr] = ptr; return ptr; } 87 | inline void remove(void * ptr) json_nothrow { 88 | JSON_MAP(void *, void *)::iterator i = mymap.find(ptr); 89 | JSON_ASSERT(i != mymap.end(), JSON_TEXT("Removing a non-managed item")); 90 | mymap.erase(i); 91 | } 92 | JSON_MAP(void *, void *) mymap; 93 | private: 94 | auto_expand(const auto_expand &); 95 | auto_expand & operator = (const auto_expand &); 96 | }; 97 | 98 | struct auto_expand_node { 99 | public: 100 | LIBJSON_OBJECT(auto_expand_node); 101 | auto_expand_node(void) json_nothrow : mymap(){ LIBJSON_CTOR; } 102 | ~auto_expand_node(void) json_nothrow { purge(); LIBJSON_DTOR; } 103 | void purge(void) json_nothrow ; 104 | inline void clear(void) json_nothrow { purge(); mymap.clear(); } 105 | inline JSONNode * insert(JSONNode * ptr) json_nothrow { mymap[ptr] = ptr; return ptr; } 106 | inline void remove(void * ptr) json_nothrow { 107 | JSON_MAP(void *, JSONNode *)::iterator i = mymap.find(ptr); 108 | if(json_likely(i != mymap.end())) mymap.erase(i); 109 | } 110 | JSON_MAP(void *, JSONNode *) mymap; 111 | private: 112 | auto_expand_node(const auto_expand_node &); 113 | auto_expand_node & operator = (const auto_expand_node &); 114 | }; 115 | 116 | #ifdef JSON_STREAM 117 | class JSONStream; 118 | struct auto_expand_stream { 119 | public: 120 | LIBJSON_OBJECT(auto_expand_stream); 121 | auto_expand_stream(void) json_nothrow : mymap(){ LIBJSON_CTOR; } 122 | ~auto_expand_stream(void) json_nothrow { purge(); LIBJSON_DTOR; } 123 | void purge(void) json_nothrow ; 124 | inline void clear(void) json_nothrow { purge(); mymap.clear(); } 125 | inline JSONStream * insert(JSONStream * ptr) json_nothrow { mymap[ptr] = ptr; return ptr; } 126 | inline void remove(void * ptr) json_nothrow { 127 | JSON_MAP(void *, JSONStream *)::iterator i = mymap.find(ptr); 128 | if(json_likely(i != mymap.end())) mymap.erase(i); 129 | } 130 | JSON_MAP(void *, JSONStream *) mymap; 131 | private: 132 | auto_expand_stream(const auto_expand_stream &); 133 | auto_expand_stream & operator = (const auto_expand_stream &); 134 | }; 135 | #endif 136 | #endif 137 | 138 | //The C++ way, use an self-deleting pointer and let the optimizer decide when it gets destroyed 139 | template 140 | class json_auto { 141 | public: 142 | LIBJSON_OBJECT(json_auto); 143 | json_auto(void) json_nothrow : ptr(0){ LIBJSON_CTOR; } 144 | json_auto(size_t count) json_nothrow : ptr(json_malloc(count)){ LIBJSON_CTOR; } 145 | json_auto(T * arg) json_nothrow : ptr(arg){ LIBJSON_CTOR; } 146 | ~json_auto(void) json_nothrow { 147 | libjson_free(ptr); 148 | LIBJSON_DTOR; 149 | } 150 | inline void set(T * p) json_nothrow{ 151 | ptr = p; 152 | } 153 | T * ptr; 154 | private: 155 | json_auto(const json_auto &); 156 | json_auto & operator =(const json_auto &); 157 | }; 158 | 159 | //Clears a string, if required, frees the memory 160 | static inline void clearString(json_string & str) json_nothrow { 161 | #ifdef JSON_LESS_MEMORY 162 | json_string().swap(str); 163 | #else 164 | str.clear(); 165 | #endif 166 | } 167 | 168 | //Shrinks a string 169 | static inline void shrinkString(json_string & str) json_nothrow { 170 | #ifdef JSON_LESS_MEMORY 171 | if (str.capacity() != str.length()) str = json_string(str.begin(), str.end()); 172 | #endif 173 | } 174 | 175 | #endif 176 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONMemoryPool.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBJSON_GUARD_MEMORY_POOL_H 2 | #define LIBJSON_GUARD_MEMORY_POOL_H 3 | 4 | #ifdef JSON_MEMORY_POOL 5 | 6 | #include "../Dependencies/mempool++/mempool.h" 7 | 8 | //this macro expands to the number of bytes a pool gets based on block size and number of 32s of the total pool it gets 9 | #define jsonPoolPart(bytes_per_block, thirty_seconds_of_mem) bytes_per_block, ((thirty_seconds_of_mem * JSON_MEMORY_POOL / 32) / bytes_per_block) 10 | 11 | #ifdef JSON_PREPARSE 12 | #define NODEPOOL jsonPoolPart(sizeof(JSONNode), 1) 13 | #define INTERNALNODEPOOL jsonPoolPart(sizeof(internalJSONNode), 3) 14 | #define MEMPOOL_1 jsonPoolPart(8, 2) 15 | #define MEMPOOL_2 jsonPoolPart(16, 2) 16 | #define MEMPOOL_3 jsonPoolPart(32, 2) 17 | #define MEMPOOL_4 jsonPoolPart(64, 2) 18 | #define MEMPOOL_5 jsonPoolPart(128, 3) 19 | #define MEMPOOL_6 jsonPoolPart(256, 4) 20 | #define MEMPOOL_7 jsonPoolPart(512, 5) 21 | #define MEMPOOL_8 jsonPoolPart(4096, 8) 22 | #else 23 | #define NODEPOOL jsonPoolPart(sizeof(JSONNode), 2) 24 | #define INTERNALNODEPOOL jsonPoolPart(sizeof(internalJSONNode), 7) 25 | #define MEMPOOL_1 jsonPoolPart(8, 1) 26 | #define MEMPOOL_2 jsonPoolPart(16, 1) 27 | #define MEMPOOL_3 jsonPoolPart(32, 1) 28 | #define MEMPOOL_4 jsonPoolPart(64, 1) 29 | #define MEMPOOL_5 jsonPoolPart(128, 3) 30 | #define MEMPOOL_6 jsonPoolPart(256, 3) 31 | #define MEMPOOL_7 jsonPoolPart(512, 5) 32 | #define MEMPOOL_8 jsonPoolPart(4096, 8) 33 | #endif 34 | 35 | #endif 36 | 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONNode.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONNode.h" 2 | 3 | #define IMPLEMENT_CTOR(type)\ 4 | JSONNode::JSONNode(const json_string & name_t, type value_t) json_nothrow : internal(internalJSONNode::newInternal()){\ 5 | internal -> Set(value_t);\ 6 | internal -> setname(name_t);\ 7 | LIBJSON_CTOR;\ 8 | } 9 | IMPLEMENT_FOR_ALL_TYPES(IMPLEMENT_CTOR) 10 | 11 | #ifndef JSON_LIBRARY 12 | JSONNode::JSONNode(const json_string & name_t, const json_char * value_t) json_nothrow : internal(internalJSONNode::newInternal()){ 13 | internal -> Set(json_string(value_t)); 14 | internal -> setname(name_t); 15 | LIBJSON_CTOR; 16 | } 17 | #endif 18 | 19 | #if (defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)) 20 | #include "JSONWorker.h" 21 | JSONNode JSONNode::stringType(const json_string & str){ 22 | JSONNode res; 23 | res.set_name(json_global(EMPTY_JSON_STRING)); 24 | #ifdef JSON_LESS_MEMORY 25 | res = JSONWorker::FixString(str, res.internal, false); 26 | #else 27 | res = JSONWorker::FixString(str, res.internal -> _string_encoded); 28 | #endif 29 | return res; 30 | } 31 | 32 | void JSONNode::set_name_(const json_string & newname) json_nothrow { 33 | #ifdef JSON_LESS_MEMORY 34 | json_string _newname = JSONWorker::FixString(newname, internal, true); 35 | #else 36 | json_string _newname = JSONWorker::FixString(newname, internal -> _name_encoded); 37 | #endif 38 | set_name(_newname); 39 | } 40 | #endif 41 | 42 | #ifdef JSON_CASTABLE 43 | JSONNode JSONNode::as_node(void) const json_nothrow { 44 | JSON_CHECK_INTERNAL(); 45 | if (type() == JSON_NODE){ 46 | return *this; 47 | } else if (type() == JSON_ARRAY){ 48 | JSONNode res(duplicate()); 49 | res.internal -> _type = JSON_NODE; 50 | return res; 51 | } 52 | #ifdef JSON_MUTEX_CALLBACKS 53 | if (internal -> mylock != 0){ 54 | JSONNode res(JSON_NODE); 55 | res.set_mutex(internal -> mylock); 56 | return res; 57 | } 58 | #endif 59 | return JSONNode(JSON_NODE); 60 | } 61 | 62 | JSONNode JSONNode::as_array(void) const json_nothrow { 63 | JSON_CHECK_INTERNAL(); 64 | if (type() == JSON_ARRAY){ 65 | return *this; 66 | } else if (type() == JSON_NODE){ 67 | JSONNode res(duplicate()); 68 | res.internal -> _type = JSON_ARRAY; 69 | json_foreach(res.internal -> CHILDREN, runner){ 70 | (*runner) -> clear_name(); 71 | } 72 | return res; 73 | } 74 | #ifdef JSON_MUTEX_CALLBACKS 75 | if (internal -> mylock != 0){ 76 | JSONNode res(JSON_ARRAY); 77 | res.set_mutex(internal -> mylock); 78 | return res; 79 | } 80 | #endif 81 | return JSONNode(JSON_ARRAY); 82 | } 83 | 84 | void JSONNode::cast(char newtype) json_nothrow { 85 | JSON_CHECK_INTERNAL(); 86 | if (newtype == type()) return; 87 | 88 | switch(newtype){ 89 | case JSON_NULL: 90 | nullify(); 91 | return; 92 | case JSON_STRING: 93 | *this = as_string(); 94 | return; 95 | case JSON_NUMBER: 96 | *this = as_float(); 97 | return; 98 | case JSON_BOOL: 99 | *this = as_bool(); 100 | return; 101 | case JSON_ARRAY: 102 | *this = as_array(); 103 | return; 104 | case JSON_NODE: 105 | *this = as_node(); 106 | return; 107 | } 108 | JSON_FAIL(JSON_TEXT("cast to unknown type")); 109 | } 110 | #endif 111 | 112 | //different just to supress the warning 113 | #ifdef JSON_REF_COUNT 114 | void JSONNode::merge(JSONNode & other) json_nothrow { 115 | #else 116 | void JSONNode::merge(JSONNode &) json_nothrow { 117 | #endif 118 | JSON_CHECK_INTERNAL(); 119 | #ifdef JSON_REF_COUNT 120 | if (internal == other.internal) return; 121 | JSON_ASSERT(*this == other, JSON_TEXT("merging two nodes that aren't equal")); 122 | if (internal -> refcount < other.internal -> refcount){ 123 | *this = other; 124 | } else { 125 | other = *this; 126 | } 127 | #endif 128 | } 129 | 130 | #ifdef JSON_REF_COUNT 131 | void JSONNode::merge(JSONNode * other) json_nothrow { 132 | JSON_CHECK_INTERNAL(); 133 | if (internal == other -> internal) return; 134 | *other = *this; 135 | } 136 | 137 | //different just to supress the warning 138 | void JSONNode::merge(unsigned int num, ...) json_nothrow { 139 | #else 140 | void JSONNode::merge(unsigned int, ...) json_nothrow { 141 | #endif 142 | JSON_CHECK_INTERNAL(); 143 | #ifdef JSON_REF_COUNT 144 | va_list args; 145 | va_start(args, num); 146 | for(unsigned int i = 0; i < num; ++i){ 147 | merge(va_arg(args, JSONNode*)); 148 | } 149 | va_end(args); 150 | #endif 151 | } 152 | 153 | JSONNode JSONNode::duplicate(void) const json_nothrow { 154 | JSON_CHECK_INTERNAL(); 155 | JSONNode mycopy(*this); 156 | #ifdef JSON_REF_COUNT 157 | JSON_ASSERT(internal == mycopy.internal, JSON_TEXT("copy ctor failed to ref count correctly")); 158 | mycopy.makeUniqueInternal(); 159 | #endif 160 | JSON_ASSERT(internal != mycopy.internal, JSON_TEXT("makeUniqueInternal failed")); 161 | return mycopy; 162 | } 163 | 164 | JSONNode & JSONNode::at(json_index_t pos) json_throws(std::out_of_range) { 165 | JSON_CHECK_INTERNAL(); 166 | if (json_unlikely(pos >= internal -> size())){ 167 | JSON_FAIL(JSON_TEXT("at() out of bounds")); 168 | json_throw(std::out_of_range(json_global(EMPTY_STD_STRING))); 169 | } 170 | return (*this)[pos]; 171 | } 172 | 173 | const JSONNode & JSONNode::at(json_index_t pos) const json_throws(std::out_of_range) { 174 | JSON_CHECK_INTERNAL(); 175 | if (json_unlikely(pos >= internal -> size())){ 176 | JSON_FAIL(JSON_TEXT("at() const out of bounds")); 177 | json_throw(std::out_of_range(json_global(EMPTY_STD_STRING))); 178 | } 179 | return (*this)[pos]; 180 | } 181 | 182 | JSONNode & JSONNode::operator[](json_index_t pos) json_nothrow { 183 | JSON_CHECK_INTERNAL(); 184 | JSON_ASSERT(pos < internal -> size(), JSON_TEXT("[] out of bounds")); 185 | makeUniqueInternal(); 186 | return *(internal -> at(pos)); 187 | } 188 | 189 | const JSONNode & JSONNode::operator[](json_index_t pos) const json_nothrow { 190 | JSON_CHECK_INTERNAL(); 191 | JSON_ASSERT(pos < internal -> size(), JSON_TEXT("[] const out of bounds")); 192 | return *(internal -> at(pos)); 193 | } 194 | 195 | JSONNode & JSONNode::at(const json_string & name_t) json_throws(std::out_of_range) { 196 | JSON_CHECK_INTERNAL(); 197 | JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("at")); 198 | makeUniqueInternal(); 199 | if (JSONNode ** res = internal -> at(name_t)){ 200 | return *(*res); 201 | } 202 | JSON_FAIL(json_string(JSON_TEXT("at could not find child by name: ")) + name_t); 203 | json_throw(std::out_of_range(json_global(EMPTY_STD_STRING))); 204 | } 205 | 206 | const JSONNode & JSONNode::at(const json_string & name_t) const json_throws(std::out_of_range) { 207 | JSON_CHECK_INTERNAL(); 208 | JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("at")); 209 | if (JSONNode ** res = internal -> at(name_t)){ 210 | return *(*res); 211 | } 212 | JSON_FAIL(json_string(JSON_TEXT("at const could not find child by name: ")) + name_t); 213 | json_throw(std::out_of_range(json_global(EMPTY_STD_STRING))); 214 | } 215 | 216 | #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS 217 | JSONNode & JSONNode::at_nocase(const json_string & name_t) json_throws(std::out_of_range) { 218 | JSON_CHECK_INTERNAL(); 219 | JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("at_nocase")); 220 | makeUniqueInternal(); 221 | if (JSONNode ** res = internal -> at_nocase(name_t)){ 222 | return *(*res); 223 | } 224 | JSON_FAIL(json_string(JSON_TEXT("at_nocase could not find child by name: ")) + name_t); 225 | json_throw(std::out_of_range(json_global(EMPTY_STD_STRING))); 226 | } 227 | 228 | const JSONNode & JSONNode::at_nocase(const json_string & name_t) const json_throws(std::out_of_range) { 229 | JSON_CHECK_INTERNAL(); 230 | JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("at_nocase")); 231 | if (JSONNode ** res = internal -> at_nocase(name_t)){ 232 | return *(*res); 233 | } 234 | JSON_FAIL(json_string(JSON_TEXT("at_nocase const could not find child by name: ")) + name_t); 235 | json_throw(std::out_of_range(json_global(EMPTY_STD_STRING))); 236 | } 237 | #endif 238 | 239 | #ifndef JSON_LIBRARY 240 | struct auto_delete { 241 | public: 242 | auto_delete(JSONNode * node) json_nothrow : mynode(node){}; 243 | ~auto_delete(void) json_nothrow { JSONNode::deleteJSONNode(mynode); }; 244 | JSONNode * mynode; 245 | private: 246 | auto_delete(const auto_delete &); 247 | auto_delete & operator = (const auto_delete &); 248 | }; 249 | #endif 250 | 251 | JSONNode JSON_PTR_LIB JSONNode::pop_back(json_index_t pos) json_throws(std::out_of_range) { 252 | JSON_CHECK_INTERNAL(); 253 | if (json_unlikely(pos >= internal -> size())){ 254 | JSON_FAIL(JSON_TEXT("pop_back out of bounds")); 255 | json_throw(std::out_of_range(json_global(EMPTY_STD_STRING))); 256 | } 257 | makeUniqueInternal(); 258 | #ifdef JSON_LIBRARY 259 | return internal -> pop_back(pos); 260 | #else 261 | auto_delete temp(internal -> pop_back(pos)); 262 | return *temp.mynode; 263 | #endif 264 | } 265 | 266 | JSONNode JSON_PTR_LIB JSONNode::pop_back(const json_string & name_t) json_throws(std::out_of_range) { 267 | JSON_CHECK_INTERNAL(); 268 | JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("pop_back")); 269 | #ifdef JSON_LIBRARY 270 | return internal -> pop_back(name_t); 271 | #else 272 | if (JSONNode * res = internal -> pop_back(name_t)){ 273 | auto_delete temp(res); 274 | return *(temp.mynode); 275 | } 276 | JSON_FAIL(json_string(JSON_TEXT("pop_back const could not find child by name: ")) + name_t); 277 | json_throw(std::out_of_range(json_global(EMPTY_STD_STRING))); 278 | #endif 279 | } 280 | 281 | #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS 282 | JSONNode JSON_PTR_LIB JSONNode::pop_back_nocase(const json_string & name_t) json_throws(std::out_of_range) { 283 | JSON_CHECK_INTERNAL(); 284 | JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("pop_back_no_case")); 285 | #ifdef JSON_LIBRARY 286 | return internal -> pop_back_nocase(name_t); 287 | #else 288 | if (JSONNode * res = internal -> pop_back_nocase(name_t)){ 289 | auto_delete temp(res); 290 | return *(temp.mynode); 291 | } 292 | JSON_FAIL(json_string(JSON_TEXT("pop_back_nocase could not find child by name: ")) + name_t); 293 | json_throw(std::out_of_range(json_global(EMPTY_STD_STRING))); 294 | #endif 295 | } 296 | #endif 297 | 298 | #ifdef JSON_MEMORY_POOL 299 | #include "JSONMemoryPool.h" 300 | memory_pool json_node_mempool; 301 | #endif 302 | 303 | void JSONNode::deleteJSONNode(JSONNode * ptr) json_nothrow { 304 | #ifdef JSON_MEMORY_POOL 305 | ptr -> ~JSONNode(); 306 | json_node_mempool.deallocate((void*)ptr); 307 | #elif defined(JSON_MEMORY_CALLBACKS) 308 | ptr -> ~JSONNode(); 309 | libjson_free(ptr); 310 | #else 311 | delete ptr; 312 | #endif 313 | } 314 | 315 | inline JSONNode * _newJSONNode(const JSONNode & orig) { 316 | #ifdef JSON_MEMORY_POOL 317 | return new((JSONNode*)json_node_mempool.allocate()) JSONNode(orig); 318 | #elif defined(JSON_MEMORY_CALLBACKS) 319 | return new(json_malloc(1)) JSONNode(orig); 320 | #else 321 | return new JSONNode(orig); 322 | #endif 323 | } 324 | 325 | JSONNode * JSONNode::newJSONNode(const JSONNode & orig JSON_MUTEX_COPY_DECL) { 326 | #ifdef JSON_MUTEX_CALLBACKS 327 | if (parentMutex != 0){ 328 | JSONNode * temp = _newJSONNode(orig); 329 | temp -> set_mutex(parentMutex); 330 | return temp; 331 | } 332 | #endif 333 | return _newJSONNode(orig); 334 | } 335 | 336 | JSONNode * JSONNode::newJSONNode(internalJSONNode * internal_t) { 337 | #ifdef JSON_MEMORY_POOL 338 | return new((JSONNode*)json_node_mempool.allocate()) JSONNode(internal_t); 339 | #elif defined(JSON_MEMORY_CALLBACKS) 340 | return new(json_malloc(1)) JSONNode(internal_t); 341 | #else 342 | return new JSONNode(internal_t); 343 | #endif 344 | } 345 | 346 | JSONNode * JSONNode::newJSONNode_Shallow(const JSONNode & orig) { 347 | #ifdef JSON_MEMORY_POOL 348 | return new((JSONNode*)json_node_mempool.allocate()) JSONNode(true, const_cast(orig)); 349 | #elif defined(JSON_MEMORY_CALLBACKS) 350 | return new(json_malloc(1)) JSONNode(true, const_cast(orig)); 351 | #else 352 | return new JSONNode(true, const_cast(orig)); 353 | #endif 354 | } 355 | 356 | 357 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONNode_Mutex.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONNode.h" 2 | #include "JSONGlobals.h" 3 | 4 | #ifdef JSON_MUTEX_CALLBACKS 5 | 6 | json_mutex_callback_t json_lock_callback = 0; 7 | json_mutex_callback_t json_unlock_callback = 0; 8 | void * global_mutex = 0; 9 | void * manager_mutex = 0; 10 | 11 | struct AutoLock { 12 | public: 13 | LIBJSON_OBJECT(AutoLock); 14 | AutoLock(void) json_nothrow { 15 | LIBJSON_CTOR; 16 | json_lock_callback(manager_mutex); 17 | } 18 | ~AutoLock(void) json_nothrow { 19 | LIBJSON_DTOR; 20 | json_unlock_callback(manager_mutex); 21 | } 22 | private: 23 | AutoLock(const AutoLock &); 24 | AutoLock & operator = (const AutoLock &); 25 | }; 26 | 27 | #ifdef JSON_MUTEX_MANAGE 28 | json_mutex_callback_t json_destroy = 0; 29 | 30 | //make sure that the global mutex is taken care of too 31 | struct auto_global { 32 | public: 33 | LIBJSON_OBJECT(auto_global;) 34 | auto_global(void) json_nothrow { LIBJSON_CTOR; } 35 | ~auto_global(void) json_nothrow { 36 | LIBJSON_DTOR; 37 | if (global_mutex){ 38 | JSON_ASSERT_SAFE(json_destroy != 0, JSON_TEXT("No json_destroy in mutex managed mode"), return;); 39 | json_destroy(global_mutex); 40 | } 41 | } 42 | private: 43 | auto_global(const auto_global &); 44 | auto_global & operator = (const auto_global &); 45 | }; 46 | auto_global cleanupGlobal; 47 | #endif 48 | 49 | void JSONNode::register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock) json_nothrow { 50 | json_lock_callback = lock; 51 | json_unlock_callback = unlock; 52 | manager_mutex = manager_lock; 53 | } 54 | 55 | void JSONNode::set_global_mutex(void * mutex) json_nothrow { 56 | global_mutex = mutex; 57 | } 58 | 59 | void JSONNode::set_mutex(void * mutex) json_nothrow { 60 | makeUniqueInternal(); 61 | internal -> _set_mutex(mutex); 62 | } 63 | 64 | void * JSONNode::getThisLock(JSONNode * pthis) json_nothrow { 65 | if (pthis -> internal -> mylock != 0){ 66 | return pthis -> internal -> mylock; 67 | } 68 | JSON_ASSERT(global_mutex != 0, JSON_TEXT("No global_mutex")); //this is safe, because it's just goingi to return 0 anyway 69 | return global_mutex; 70 | } 71 | 72 | void JSONNode::lock(int thread) json_nothrow { 73 | JSON_ASSERT_SAFE(json_lock_callback != 0, JSON_TEXT("No locking callback"), return;); 74 | 75 | AutoLock lockControl; 76 | 77 | //first, figure out what needs to be locked 78 | void * thislock = getThisLock(this); 79 | #ifdef JSON_SAFE 80 | if (json_unlikely(thislock == 0)) return; 81 | #endif 82 | 83 | //make sure that the same thread isn't locking it more than once (possible due to complex ref counting) 84 | JSON_MAP(int, JSON_MAP(void *, unsigned int) )::iterator it = json_global(THREAD_LOCKS).find(thread); 85 | if (it == json_global(THREAD_LOCKS).end()){ 86 | JSON_MAP(void *, unsigned int) newthread; 87 | newthread[thislock] = 1; 88 | json_global(THREAD_LOCKS).insert(std::pair(thread, newthread)); 89 | } else { //this thread already has some things locked, check if the current mutex is 90 | JSON_MAP(void *, unsigned int) & newthread = it -> second; 91 | JSON_MAP(void *, unsigned int)::iterator locker(newthread.find(thislock)); 92 | if (locker == newthread.end()){ //current mutex is not locked, set it to locked 93 | newthread.insert(std::pair(thislock, 1)); 94 | } else { //it's already locked, don't relock it 95 | ++(locker -> second); 96 | return; //don't try to relock, it will deadlock the program 97 | } 98 | } 99 | 100 | //if I need to, lock it 101 | json_lock_callback(thislock); 102 | } 103 | 104 | void JSONNode::unlock(int thread) json_nothrow{ 105 | JSON_ASSERT_SAFE(json_unlock_callback != 0, JSON_TEXT("No unlocking callback"), return;); 106 | 107 | AutoLock lockControl; 108 | 109 | //first, figure out what needs to be locked 110 | void * thislock = getThisLock(this); 111 | #ifdef JSON_SAFE 112 | if (thislock == 0) return; 113 | #endif 114 | 115 | //get it out of the map 116 | JSON_MAP(int, JSON_MAP(void *, unsigned int) )::iterator it = json_global(THREAD_LOCKS).find(thread); 117 | JSON_ASSERT_SAFE(it != json_global(THREAD_LOCKS).end(), JSON_TEXT("thread unlocking something it didn't lock"), return;); 118 | 119 | //get the mutex out of the thread 120 | JSON_MAP(void *, unsigned int) & newthread = it -> second; 121 | JSON_MAP(void *, unsigned int)::iterator locker = newthread.find(thislock); 122 | JSON_ASSERT_SAFE(locker != newthread.end(), JSON_TEXT("thread unlocking mutex it didn't lock"), return;); 123 | 124 | //unlock it 125 | if (--(locker -> second)) return; //other nodes is this same thread still have a lock on it 126 | 127 | //if I need to, unlock it 128 | newthread.erase(locker); 129 | json_unlock_callback(thislock); 130 | 131 | } 132 | 133 | #ifdef JSON_MUTEX_MANAGE 134 | void JSONNode::register_mutex_destructor(json_mutex_callback_t destroy) json_nothrow { 135 | json_destroy = destroy; 136 | } 137 | #endif 138 | 139 | 140 | void internalJSONNode::_set_mutex(void * mutex, bool unset) json_nothrow { 141 | if (unset) _unset_mutex(); //for reference counting 142 | mylock = mutex; 143 | if (mutex != 0){ 144 | #ifdef JSON_MUTEX_MANAGE 145 | JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mutex); 146 | if (it == json_global(MUTEX_MANAGER).end()){ 147 | json_global(MUTEX_MANAGER).insert(std::pair(mutex, 1)); 148 | } else { 149 | ++it -> second; 150 | } 151 | #endif 152 | if (isContainer()){ 153 | json_foreach(CHILDREN, myrunner){ 154 | (*myrunner) -> set_mutex(mutex); 155 | } 156 | } 157 | } 158 | } 159 | 160 | void internalJSONNode::_unset_mutex(void) json_nothrow { 161 | #ifdef JSON_MUTEX_MANAGE 162 | if (mylock != 0){ 163 | JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mylock); 164 | JSON_ASSERT_SAFE(it != json_global(MUTEX_MANAGER).end(), JSON_TEXT("Mutex not managed"), return;); 165 | --it -> second; 166 | if (it -> second == 0){ 167 | JSON_ASSERT_SAFE(json_destroy, JSON_TEXT("You didn't register a destructor for mutexes"), return;); 168 | json_global(MUTEX_MANAGER).erase(it); 169 | } 170 | } 171 | #endif 172 | } 173 | 174 | #ifdef JSON_DEBUG 175 | #ifndef JSON_LIBRARY 176 | JSONNode internalJSONNode::DumpMutex(void) const json_nothrow { 177 | JSONNode mut(JSON_NODE); 178 | mut.set_name(JSON_TEXT("mylock")); 179 | #ifdef JSON_MUTEX_MANAGE 180 | if (mylock != 0){ 181 | mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)mylock))); 182 | JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mylock); 183 | if (it == json_global(MUTEX_MANAGER).end()){ 184 | mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), JSON_TEXT("error")))); 185 | } else { 186 | mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), it -> second))); 187 | } 188 | } else { 189 | mut = (long)mylock; 190 | } 191 | #else 192 | mut = (long)mylock; 193 | #endif 194 | return mut; 195 | } 196 | #endif 197 | #endif 198 | 199 | #else 200 | #ifdef JSON_MUTEX_MANAGE 201 | #error You can not have JSON_MUTEX_MANAGE on without JSON_MUTEX_CALLBACKS 202 | #endif 203 | #endif 204 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONPreparse.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBJSON_GUARD_PREPARSE_H 2 | #define LIBJSON_GUARD_PREPARSE_H 3 | 4 | #include "JSONDebug.h" 5 | #include "JSONNode.h" 6 | 7 | #if (defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)) 8 | 9 | #ifdef JSON_COMMENTS 10 | #define COMMENT_PARAM(name) ,const json_string & name 11 | #else 12 | #define COMMENT_PARAM(name) 13 | #endif 14 | 15 | class JSONPreparse { 16 | public: 17 | static JSONNode isValidNumber(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority; 18 | static JSONNode isValidMember(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority; 19 | static json_string isValidString(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority; 20 | static void isValidNamedObject(json_string::const_iterator & ptr, json_string::const_iterator & end, JSONNode & parent COMMENT_PARAM(comment)) json_read_priority; 21 | static JSONNode isValidObject(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority; 22 | static JSONNode isValidArray(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority; 23 | static JSONNode isValidRoot(const json_string & json) json_throws(std::invalid_argument) json_read_priority; 24 | }; 25 | 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONSharedString.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_SHARED_STRING_H 2 | #define JSON_SHARED_STRING_H 3 | 4 | /* 5 | * This class allows json objects to share string 6 | * Since libjson is a parser, it does a lot of substrings, but since 7 | * a string with all of the information already exists, those substrings 8 | * can be infered by an offset and length and a pointer to the master 9 | * string 10 | * 11 | * EXPERIMENTAL, Not used yet 12 | */ 13 | 14 | #include "JSONDebug.h" 15 | #include "JSONGlobals.h" 16 | #include "JSONMemory.h" 17 | 18 | /* 19 | mallocs: 3351 20 | frees: 3351 21 | reallocs: 3 22 | bytes: 298751 (291 KB) 23 | max bytes at once: 3624 (3 KB) 24 | avg bytes at once: 970 (0 KB) 25 | */ 26 | 27 | #ifdef JSON_LESS_MEMORY 28 | #ifdef __GNUC__ 29 | #pragma pack(push, 1) 30 | #elif _MSC_VER 31 | #pragma pack(push, json_shared_string_pack, 1) 32 | #endif 33 | #endif 34 | 35 | class json_shared_string { 36 | public: 37 | 38 | 39 | struct iterator; 40 | struct const_iterator { 41 | const_iterator(const json_char * p, const json_shared_string * pa) : parent(pa), it(p){} 42 | 43 | inline const_iterator& operator ++(void) json_nothrow { ++it; return *this; } 44 | inline const_iterator& operator --(void) json_nothrow { --it; return *this; } 45 | inline const_iterator& operator +=(long i) json_nothrow { it += i; return *this; } 46 | inline const_iterator& operator -=(long i) json_nothrow { it -= i; return *this; } 47 | inline const_iterator operator ++(int) json_nothrow { 48 | const_iterator result(*this); 49 | ++it; 50 | return result; 51 | } 52 | inline const_iterator operator --(int) json_nothrow { 53 | const_iterator result(*this); 54 | --it; 55 | return result; 56 | } 57 | inline const_iterator operator +(long i) const json_nothrow { 58 | const_iterator result(*this); 59 | result.it += i; 60 | return result; 61 | } 62 | inline const_iterator operator -(long i) const json_nothrow { 63 | const_iterator result(*this); 64 | result.it -= i; 65 | return result; 66 | } 67 | inline const json_char & operator [](size_t pos) const json_nothrow { return it[pos]; }; 68 | inline const json_char & operator *(void) const json_nothrow { return *it; } 69 | inline const json_char * operator ->(void) const json_nothrow { return it; } 70 | inline bool operator == (const const_iterator & other) const json_nothrow { return it == other.it; } 71 | inline bool operator != (const const_iterator & other) const json_nothrow { return it != other.it; } 72 | inline bool operator > (const const_iterator & other) const json_nothrow { return it > other.it; } 73 | inline bool operator >= (const const_iterator & other) const json_nothrow { return it >= other.it; } 74 | inline bool operator < (const const_iterator & other) const json_nothrow { return it < other.it; } 75 | inline bool operator <= (const const_iterator & other) const json_nothrow { return it <= other.it; } 76 | 77 | inline bool operator == (const iterator & other) const json_nothrow { return it == other.it; } 78 | inline bool operator != (const iterator & other) const json_nothrow { return it != other.it; } 79 | inline bool operator > (const iterator & other) const json_nothrow { return it > other.it; } 80 | inline bool operator >= (const iterator & other) const json_nothrow { return it >= other.it; } 81 | inline bool operator < (const iterator & other) const json_nothrow { return it < other.it; } 82 | inline bool operator <= (const iterator & other) const json_nothrow { return it <= other.it; } 83 | 84 | inline const_iterator & operator =(const const_iterator & orig) json_nothrow { it = orig.it; return *this; } 85 | const_iterator (const const_iterator & orig) json_nothrow : it(orig.it) {} 86 | private: 87 | const json_shared_string * parent; 88 | const json_char * it; 89 | friend class json_shared_string; 90 | friend struct iterator; 91 | }; 92 | 93 | struct iterator { 94 | iterator(const json_char * p, const json_shared_string * pa) : parent(pa), it(p){} 95 | 96 | inline iterator& operator ++(void) json_nothrow { ++it; return *this; } 97 | inline iterator& operator --(void) json_nothrow { --it; return *this; } 98 | inline iterator& operator +=(long i) json_nothrow { it += i; return *this; } 99 | inline iterator& operator -=(long i) json_nothrow { it -= i; return *this; } 100 | inline iterator operator ++(int) json_nothrow { 101 | iterator result(*this); 102 | ++it; 103 | return result; 104 | } 105 | inline iterator operator --(int) json_nothrow { 106 | iterator result(*this); 107 | --it; 108 | return result; 109 | } 110 | inline iterator operator +(long i) const json_nothrow { 111 | iterator result(*this); 112 | result.it += i; 113 | return result; 114 | } 115 | inline iterator operator -(long i) const json_nothrow { 116 | iterator result(*this); 117 | result.it -= i; 118 | return result; 119 | } 120 | inline const json_char & operator [](size_t pos) const json_nothrow { return it[pos]; }; 121 | inline const json_char & operator *(void) const json_nothrow { return *it; } 122 | inline const json_char * operator ->(void) const json_nothrow { return it; } 123 | inline bool operator == (const const_iterator & other) const json_nothrow { return it == other.it; } 124 | inline bool operator != (const const_iterator & other) const json_nothrow { return it != other.it; } 125 | inline bool operator > (const const_iterator & other) const json_nothrow { return it > other.it; } 126 | inline bool operator >= (const const_iterator & other) const json_nothrow { return it >= other.it; } 127 | inline bool operator < (const const_iterator & other) const json_nothrow { return it < other.it; } 128 | inline bool operator <= (const const_iterator & other) const json_nothrow { return it <= other.it; } 129 | 130 | inline bool operator == (const iterator & other) const json_nothrow { return it == other.it; } 131 | inline bool operator != (const iterator & other) const json_nothrow { return it != other.it; } 132 | inline bool operator > (const iterator & other) const json_nothrow { return it > other.it; } 133 | inline bool operator >= (const iterator & other) const json_nothrow { return it >= other.it; } 134 | inline bool operator < (const iterator & other) const json_nothrow { return it < other.it; } 135 | inline bool operator <= (const iterator & other) const json_nothrow { return it <= other.it; } 136 | 137 | inline iterator & operator =(const iterator & orig) json_nothrow { it = orig.it; return *this; } 138 | iterator (const iterator & orig) json_nothrow : it(orig.it) {} 139 | private: 140 | const json_shared_string * parent; 141 | const json_char * it; 142 | friend class json_shared_string; 143 | friend struct const_iterator; 144 | }; 145 | 146 | 147 | 148 | inline json_shared_string::iterator begin(void){ 149 | iterator res = iterator(data(), this); 150 | return res; 151 | } 152 | inline json_shared_string::iterator end(void){ 153 | iterator res = iterator(data() + len, this); 154 | return res; 155 | } 156 | inline json_shared_string::const_iterator begin(void) const { 157 | const_iterator res = const_iterator(data(), this); 158 | return res; 159 | } 160 | inline json_shared_string::const_iterator end(void) const { 161 | const_iterator res = const_iterator(data() + len, this); 162 | return res; 163 | } 164 | 165 | 166 | inline json_string::iterator std_begin(void){ 167 | return _str -> mystring.begin() + offset; 168 | } 169 | inline json_string::iterator std_end(void){ 170 | return std_begin() + len; 171 | } 172 | 173 | inline json_string::const_iterator std_begin(void) const{ 174 | return _str -> mystring.begin() + offset; 175 | } 176 | inline json_string::const_iterator std_end(void) const{ 177 | return std_begin() + len; 178 | } 179 | 180 | inline json_shared_string(void) : offset(0), len(0), _str(new(json_malloc(1)) json_shared_string_internal(json_global(EMPTY_JSON_STRING))) {} 181 | 182 | inline json_shared_string(const json_string & str) : offset(0), len(str.length()), _str(new(json_malloc(1)) json_shared_string_internal(str)) {} 183 | 184 | inline json_shared_string(const json_shared_string & str, size_t _offset, size_t _len) : _str(str._str), offset(str.offset + _offset), len(_len) { 185 | ++_str -> refCount; 186 | } 187 | 188 | inline json_shared_string(const json_shared_string & str, size_t _offset) : _str(str._str), offset(str.offset + _offset), len(str.len - _offset) { 189 | ++_str -> refCount; 190 | } 191 | 192 | inline json_shared_string(const iterator & s, const iterator & e) : _str(s.parent -> _str), offset(s.it - s.parent -> _str -> mystring.data()), len(e.it - s.it){ 193 | ++_str -> refCount; 194 | } 195 | 196 | inline ~json_shared_string(void){ 197 | deref(); 198 | } 199 | 200 | inline bool empty(void) const { return len == 0; } 201 | 202 | size_t find(json_char ch, size_t pos = 0) const { 203 | if (_str -> refCount == 1) return _str -> mystring.find(ch, pos); 204 | json_string::const_iterator e = std_end(); 205 | for(json_string::const_iterator b = std_begin() + pos; b != e; ++b){ 206 | if (*b == ch) return b - std_begin(); 207 | } 208 | return json_string::npos; 209 | } 210 | 211 | inline json_char & operator[] (size_t loc){ 212 | return _str -> mystring[loc + offset]; 213 | } 214 | inline json_char operator[] (size_t loc) const { 215 | return _str -> mystring[loc + offset]; 216 | } 217 | inline void clear(){ len = 0; } 218 | inline size_t length() const { return len; } 219 | inline const json_char * c_str() const { return toString().c_str(); } 220 | inline const json_char * data() const { return _str -> mystring.data() + offset; } 221 | 222 | inline bool operator != (const json_shared_string & other) const { 223 | if ((other._str == _str) && (other.len == len) && (other.offset == offset)) return false; 224 | return other.toString() != toString(); 225 | } 226 | 227 | inline bool operator == (const json_shared_string & other) const { 228 | if ((other._str == _str) && (other.len == len) && (other.offset == offset)) return true; 229 | return other.toString() == toString(); 230 | } 231 | 232 | inline bool operator == (const json_string & other) const { 233 | return other == toString(); 234 | } 235 | 236 | json_string & toString(void) const { 237 | //gonna have to do a real substring now anyway, so do it completely 238 | if (_str -> refCount == 1){ 239 | if (offset || len != _str -> mystring.length()){ 240 | _str -> mystring = json_string(std_begin(), std_end()); 241 | } 242 | } else if (offset || len != _str -> mystring.length()){ 243 | --_str -> refCount; //dont use deref because I know its not going to be deleted 244 | _str = new(json_malloc(1)) json_shared_string_internal(json_string(std_begin(), std_end())); 245 | } 246 | offset = 0; 247 | return _str -> mystring; 248 | } 249 | 250 | 251 | inline void assign(const json_shared_string & other, size_t _offset, size_t _len){ 252 | if (other._str != _str){ 253 | deref(); 254 | _str = other._str; 255 | } 256 | ++_str -> refCount; 257 | offset = other.offset + _offset; 258 | len = _len; 259 | } 260 | 261 | json_shared_string(const json_shared_string & other) : _str(other._str), offset(other.offset), len(other.len){ 262 | ++_str -> refCount; 263 | } 264 | 265 | json_shared_string & operator =(const json_shared_string & other){ 266 | if (other._str != _str){ 267 | deref(); 268 | _str = other._str; 269 | ++_str -> refCount; 270 | } 271 | offset = other.offset; 272 | len = other.len; 273 | return *this; 274 | } 275 | 276 | json_shared_string & operator += (const json_char c){ 277 | toString() += c; 278 | ++len; 279 | return *this; 280 | } 281 | 282 | //when doing a plus equal of another string, see if it shares the string and starts where this one left off, in which case just increase len 283 | JSON_PRIVATE 284 | struct json_shared_string_internal { 285 | inline json_shared_string_internal(const json_string & _mystring) : mystring(_mystring), refCount(1) {} 286 | json_string mystring; 287 | size_t refCount PACKED(20); 288 | }; 289 | inline void deref(void){ 290 | if (--_str -> refCount == 0){ 291 | _str -> ~json_shared_string_internal(); 292 | libjson_free(_str); 293 | } 294 | } 295 | mutable json_shared_string_internal * _str; 296 | mutable size_t offset PACKED(20); 297 | mutable size_t len PACKED(20); 298 | }; 299 | 300 | #ifdef JSON_LESS_MEMORY 301 | #ifdef __GNUC__ 302 | #pragma pack(pop) 303 | #elif _MSC_VER 304 | #pragma pack(pop, json_shared_string_pack,) 305 | #endif 306 | #endif 307 | 308 | #endif 309 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONSingleton.h: -------------------------------------------------------------------------------- 1 | #ifndef JSONSINGLETON_H 2 | #define JSONSINGLETON_H 3 | 4 | template class JSONSingleton { 5 | public: 6 | static inline T get(void){ 7 | return get_singleton() -> ptr; 8 | } 9 | static inline void set(T p){ 10 | get_singleton() -> ptr = p; 11 | } 12 | private: 13 | inline JSONSingleton() : ptr(NULL) { } 14 | JSONSingleton(const JSONSingleton &); 15 | JSONSingleton operator = (const JSONSingleton &); 16 | static inline JSONSingleton * get_singleton(void){ 17 | static JSONSingleton instance; 18 | return &instance; 19 | } 20 | T ptr; 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONStats.h: -------------------------------------------------------------------------------- 1 | #ifndef TestSuite_JSONStats_h 2 | #define TestSuite_JSONStats_h 3 | 4 | #include "../../JSONOptions.h" 5 | 6 | #if defined(JSON_UNIT_TEST) || defined(JSON_DEBUG) 7 | #define LIBJSON_OBJECT(name)\ 8 | static size_t & getCtorCounter(void){\ 9 | static size_t count = 0;\ 10 | static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\ 11 | return count;\ 12 | }\ 13 | static size_t & getCopyCtorCounter(void){\ 14 | static size_t count = 0;\ 15 | static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\ 16 | return count;\ 17 | }\ 18 | static size_t & getAssignmentCounter(void){\ 19 | static size_t count = 0;\ 20 | static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\ 21 | return count;\ 22 | }\ 23 | static size_t & getDtorCounter(void){\ 24 | static size_t count = 0;\ 25 | static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\ 26 | return count;\ 27 | } 28 | #define LIBJSON_CTOR getCtorCounter() += 1 29 | #define LIBJSON_COPY_CTOR getCopyCtorCounter() += 1 30 | #define LIBJSON_ASSIGNMENT getAssignmentCounter() += 1 31 | #define LIBJSON_DTOR getDtorCounter() += 1 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | class JSONStats { 38 | public: 39 | ~JSONStats(void){ 40 | std::map & mymap = getMapper(); 41 | std::map::iterator b = mymap.begin(); 42 | std::map::iterator e = mymap.end(); 43 | std::cout << "Counters for libjson:" << std::endl; 44 | for(; b != e; ++b){ 45 | std::cout << " " << b -> second -> _name << std::endl; 46 | std::cout << " Constructor: " << b -> second -> _cTor() << std::endl; 47 | std::cout << " Copy Constructor: " << b -> second -> _ccTor() << std::endl; 48 | std::cout << " Assignment: " << b -> second -> _assign() << std::endl; 49 | std::cout << " Destructor: " << b -> second -> _dTor() << std::endl; 50 | delete b -> second; 51 | } 52 | } 53 | 54 | typedef size_t & (*getCounter_m)(void); 55 | struct objectStructure { 56 | objectStructure(getCounter_m cTor, getCounter_m ccTor, getCounter_m assign, getCounter_m dTor, const std::string & name): 57 | _cTor(cTor), _ccTor(ccTor), _assign(assign), _dTor(dTor), _name(name){} 58 | std::string _name; 59 | getCounter_m _cTor; 60 | getCounter_m _ccTor; 61 | getCounter_m _assign; 62 | getCounter_m _dTor; 63 | }; 64 | static int setCallbacks(getCounter_m cTor, getCounter_m ccTor, getCounter_m assign, getCounter_m dtor, const std::string & name){ 65 | getMapper()[cTor] = new objectStructure (cTor, ccTor, assign, dtor, name); 66 | return 0; 67 | } 68 | 69 | static std::map & getMapper(void) { 70 | static std::map mymap; 71 | return mymap; 72 | } 73 | }; 74 | #else 75 | #define LIBJSON_OBJECT(name) 76 | #define LIBJSON_CTOR (void)0 77 | #define LIBJSON_DTOR (void)0 78 | #define LIBJSON_COPY_CTOR (void)0 79 | #define LIBJSON_ASSIGNMENT (void)0 80 | typedef int JSONStats; 81 | #endif 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONStream.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONStream.h" 2 | 3 | #ifdef JSON_STREAM 4 | #include "JSONWorker.h" 5 | #include "JSONValidator.h" 6 | 7 | 8 | JSONStream::JSONStream(json_stream_callback_t call_p, json_stream_e_callback_t call_e, void * callbackIdentifier) json_nothrow : state(true), call(call_p), err_call(call_e), buffer(), callback_identifier(callbackIdentifier) { 9 | LIBJSON_CTOR; 10 | } 11 | 12 | JSONStream::JSONStream(const JSONStream & orig) json_nothrow : state(orig.state), call(orig.call), err_call(orig.err_call), buffer(orig.buffer), callback_identifier(orig.callback_identifier){ 13 | LIBJSON_COPY_CTOR; 14 | } 15 | 16 | JSONStream & JSONStream::operator =(const JSONStream & orig) json_nothrow { 17 | LIBJSON_ASSIGNMENT; 18 | err_call = orig.err_call; 19 | call = orig.call; 20 | state = orig.state; 21 | buffer = orig.buffer; 22 | callback_identifier = orig.callback_identifier; 23 | return *this; 24 | } 25 | 26 | #ifdef JSON_LIBRARY 27 | JSONStream & JSONStream::operator << (const json_char * str) json_nothrow { 28 | #else 29 | JSONStream & JSONStream::operator << (const json_string & str) json_nothrow { 30 | #endif 31 | if (state){ 32 | buffer += str; 33 | parse(); 34 | } 35 | return *this; 36 | } 37 | 38 | 39 | #define QUOTECASE_STREAM()\ 40 | case JSON_TEXT('\"'):\ 41 | while (*(++p) != JSON_TEXT('\"')){\ 42 | if (json_unlikely(*p == JSON_TEXT('\0'))) return json_string::npos;\ 43 | }\ 44 | break; 45 | 46 | 47 | #define NULLCASE_STREAM()\ 48 | case JSON_TEXT('\0'):\ 49 | return json_string::npos;\ 50 | 51 | 52 | #define BRACKET_STREAM(left, right)\ 53 | case left: {\ 54 | size_t brac = 1;\ 55 | while (brac){\ 56 | switch (*(++p)){\ 57 | case right:\ 58 | --brac;\ 59 | break;\ 60 | case left:\ 61 | ++brac;\ 62 | break;\ 63 | QUOTECASE_STREAM()\ 64 | NULLCASE_STREAM()\ 65 | }\ 66 | }\ 67 | break;}\ 68 | case right:\ 69 | return json_string::npos; 70 | 71 | #if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY))) 72 | #define STREAM_FIND_NEXT_RELEVANT(ch, vt, po) FindNextRelevant(vt, po) 73 | template 74 | size_t JSONStream::FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow { 75 | #else 76 | #define STREAM_FIND_NEXT_RELEVANT(ch, vt, po) FindNextRelevant(ch, vt, po) 77 | size_t JSONStream::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow { 78 | #endif 79 | const json_char * start = value_t.c_str(); 80 | for (const json_char * p = start + pos; *p; ++p){ 81 | if (json_unlikely(*p == ch)) return p - start; 82 | switch (*p){ 83 | BRACKET_STREAM(JSON_TEXT('['), JSON_TEXT(']')) 84 | BRACKET_STREAM(JSON_TEXT('{'), JSON_TEXT('}')) 85 | QUOTECASE_STREAM() 86 | } 87 | }; 88 | return json_string::npos; 89 | } 90 | 91 | void JSONStream::parse(void) json_nothrow { 92 | #ifdef JSON_SECURITY_MAX_STREAM_OBJECTS 93 | size_t objects = 0; 94 | #endif 95 | for(;;){ 96 | size_t pos = buffer.find_first_of(JSON_TEXT("{[")); 97 | if (json_likely(pos != json_string::npos)){ 98 | size_t end = (buffer[pos] == JSON_TEXT('[')) ? STREAM_FIND_NEXT_RELEVANT(JSON_TEXT(']'), buffer, pos + 1) : STREAM_FIND_NEXT_RELEVANT(JSON_TEXT('}'), buffer, pos + 1); 99 | if (end != json_string::npos){ 100 | #ifdef JSON_SECURITY_MAX_STREAM_OBJECTS 101 | if (++objects > JSON_SECURITY_MAX_STREAM_OBJECTS){ 102 | JSON_FAIL(JSON_TEXT("Maximum number of json objects for a stream at once has been reached")); 103 | if (err_call) err_call(getIdentifier()); 104 | state = false; 105 | return; 106 | } 107 | #endif 108 | START_MEM_SCOPE 109 | JSONNode temp(JSONWorker::parse(buffer.substr(pos, end - pos + 1))); 110 | #ifndef JSON_LIBRARY 111 | call(temp, getIdentifier()); 112 | #else 113 | call(&temp, getIdentifier()); 114 | #endif 115 | END_MEM_SCOPE 116 | json_string::iterator beginning = buffer.begin(); 117 | buffer.erase(beginning, beginning + end); 118 | continue; //parse(); //parse the next object too 119 | } 120 | #ifdef JSON_SAFE 121 | else { 122 | //verify that what's in there is at least valid so far 123 | #ifndef JSON_VALIDATE 124 | #error In order to use safe mode and streams, JSON_VALIDATE needs to be defined 125 | #endif 126 | 127 | json_auto s; 128 | size_t len; 129 | s.set(JSONWorker::RemoveWhiteSpace(json_string(buffer.c_str() + pos), len, false)); 130 | 131 | 132 | if (!JSONValidator::isValidPartialRoot(s.ptr)){ 133 | if (err_call) err_call(getIdentifier()); 134 | state = false; 135 | } 136 | } 137 | #endif 138 | } 139 | break; 140 | } 141 | } 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONStream.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBJSON_GUARD_STREAM_H 2 | #define LIBJSON_GUARD_STREAM_H 3 | 4 | #include "JSONDebug.h" 5 | 6 | #ifdef JSON_STREAM 7 | 8 | #ifdef JSON_LESS_MEMORY 9 | #ifdef __GNUC__ 10 | #pragma pack(push, 1) 11 | #elif _MSC_VER 12 | #pragma pack(push, JSONStream_pack, 1) 13 | #endif 14 | #endif 15 | 16 | #ifdef JSON_MEMORY_CALLBACKS 17 | #include "JSONMemory.h" 18 | #endif 19 | 20 | #ifndef JSON_LIBRARY 21 | class JSONNode; //foreward declaration 22 | typedef void (*json_stream_callback_t)(JSONNode &, void *); 23 | #endif 24 | 25 | class JSONStream { 26 | public: 27 | LIBJSON_OBJECT(JSONStream); 28 | JSONStream(json_stream_callback_t call_p, json_stream_e_callback_t call_e = NULL, void * callbackIdentifier = JSONSTREAM_SELF) json_nothrow; 29 | JSONStream(const JSONStream & orig) json_nothrow; 30 | JSONStream & operator =(const JSONStream & orig) json_nothrow; 31 | ~JSONStream(void) json_nothrow { LIBJSON_DTOR; } 32 | #ifdef JSON_LIBRARY 33 | JSONStream & operator << (const json_char * str) json_nothrow; 34 | #else 35 | JSONStream & operator << (const json_string & str) json_nothrow; 36 | #endif 37 | 38 | static void deleteJSONStream(JSONStream * stream) json_nothrow { 39 | #ifdef JSON_MEMORY_CALLBACKS 40 | stream -> ~JSONStream(); 41 | libjson_free(stream); 42 | #else 43 | delete stream; 44 | #endif 45 | } 46 | 47 | static JSONStream * newJSONStream(json_stream_callback_t callback, json_stream_e_callback_t call_e, void * callbackIdentifier) json_nothrow { 48 | #ifdef JSON_MEMORY_CALLBACKS 49 | return new(json_malloc(1)) JSONStream(callback, call_e, callbackIdentifier); 50 | #else 51 | return new JSONStream(callback, call_e, callbackIdentifier); 52 | #endif 53 | } 54 | 55 | inline void reset() json_nothrow { 56 | state = true; 57 | buffer.clear(); 58 | } 59 | JSON_PRIVATE 60 | inline void * getIdentifier(void) json_nothrow { 61 | if (callback_identifier == JSONSTREAM_SELF){ 62 | return (void*)this; 63 | } 64 | return callback_identifier; 65 | } 66 | 67 | #if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY))) 68 | template 69 | static size_t FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow json_read_priority; 70 | #else 71 | static size_t FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow json_read_priority; 72 | #endif 73 | 74 | void parse(void) json_nothrow; 75 | json_string buffer; 76 | json_stream_callback_t call; 77 | json_stream_e_callback_t err_call; 78 | void * callback_identifier; 79 | bool state BITS(1); 80 | }; 81 | 82 | #ifdef JSON_LESS_MEMORY 83 | #ifdef __GNUC__ 84 | #pragma pack(pop) 85 | #elif _MSC_VER 86 | #pragma pack(pop, JSONStream_pack) 87 | #endif 88 | #endif 89 | 90 | #endif 91 | 92 | #endif 93 | 94 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONValidator.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONValidator.h" 2 | 3 | #ifdef JSON_VALIDATE 4 | 5 | inline bool isHex(json_char c) json_pure; 6 | inline bool isHex(json_char c) json_nothrow { 7 | return (((c >= JSON_TEXT('0')) && (c <= JSON_TEXT('9'))) || 8 | ((c >= JSON_TEXT('A')) && (c <= JSON_TEXT('F'))) || 9 | ((c >= JSON_TEXT('a')) && (c <= JSON_TEXT('f')))); 10 | } 11 | 12 | bool JSONValidator::isValidNumber(const json_char * & ptr) json_nothrow { 13 | //ptr points at the first character in the number 14 | //ptr will end up past the last character 15 | bool decimal = false; 16 | bool scientific = false; 17 | 18 | //first letter is weird 19 | switch(*ptr){ 20 | #ifndef JSON_STRICT 21 | case JSON_TEXT('.'): 22 | decimal = true; 23 | break; 24 | case JSON_TEXT('+'): 25 | #endif 26 | case JSON_TEXT('-'): 27 | #ifdef JSON_STRICT 28 | switch(*(ptr + 1)){ 29 | case '.': 30 | case 'e': 31 | case 'E': 32 | case '\0': 33 | return false; 34 | } 35 | break; 36 | #endif 37 | case JSON_TEXT('1'): 38 | case JSON_TEXT('2'): 39 | case JSON_TEXT('3'): 40 | case JSON_TEXT('4'): 41 | case JSON_TEXT('5'): 42 | case JSON_TEXT('6'): 43 | case JSON_TEXT('7'): 44 | case JSON_TEXT('8'): 45 | case JSON_TEXT('9'): 46 | break; 47 | case JSON_TEXT('0'): 48 | ++ptr; 49 | switch(*ptr){ 50 | case JSON_TEXT('.'): 51 | decimal = true; 52 | break; 53 | case JSON_TEXT('e'): 54 | case JSON_TEXT('E'): 55 | scientific = true; 56 | ++ptr; 57 | switch(*ptr){ 58 | case JSON_TEXT('\0'): 59 | return false; 60 | case JSON_TEXT('-'): 61 | case JSON_TEXT('+'): 62 | case JSON_TEXT('0'): 63 | case JSON_TEXT('1'): 64 | case JSON_TEXT('2'): 65 | case JSON_TEXT('3'): 66 | case JSON_TEXT('4'): 67 | case JSON_TEXT('5'): 68 | case JSON_TEXT('6'): 69 | case JSON_TEXT('7'): 70 | case JSON_TEXT('8'): 71 | case JSON_TEXT('9'): 72 | break; 73 | default: 74 | return false; 75 | } 76 | break; 77 | #ifndef JSON_STRICT 78 | case JSON_TEXT('x'): 79 | while(isHex(*++ptr)){}; 80 | return true; 81 | #ifdef JSON_OCTAL 82 | #ifdef __GNUC__ 83 | case JSON_TEXT('0') ... JSON_TEXT('7'): //octal 84 | #else 85 | case JSON_TEXT('0'): 86 | case JSON_TEXT('1'): 87 | case JSON_TEXT('2'): 88 | case JSON_TEXT('3'): 89 | case JSON_TEXT('4'): 90 | case JSON_TEXT('5'): 91 | case JSON_TEXT('6'): 92 | case JSON_TEXT('7'): 93 | #endif 94 | while((*++ptr >= JSON_TEXT('0')) && (*ptr <= JSON_TEXT('7'))){}; 95 | return ((*ptr != JSON_TEXT('8')) && (*ptr != JSON_TEXT('9'))); 96 | case JSON_TEXT('8'): 97 | case JSON_TEXT('9'): 98 | break; 99 | #else 100 | #ifdef __GNUC__ 101 | case JSON_TEXT('0') ... JSON_TEXT('9'): 102 | #else 103 | case JSON_TEXT('0'): 104 | case JSON_TEXT('1'): 105 | case JSON_TEXT('2'): 106 | case JSON_TEXT('3'): 107 | case JSON_TEXT('4'): 108 | case JSON_TEXT('5'): 109 | case JSON_TEXT('6'): 110 | case JSON_TEXT('7'): 111 | case JSON_TEXT('8'): 112 | case JSON_TEXT('9'): 113 | #endif 114 | break; 115 | #endif 116 | #else 117 | #ifdef __GNUC__ 118 | case JSON_TEXT('0') ... JSON_TEXT('9'): 119 | #else 120 | case JSON_TEXT('0'): 121 | case JSON_TEXT('1'): 122 | case JSON_TEXT('2'): 123 | case JSON_TEXT('3'): 124 | case JSON_TEXT('4'): 125 | case JSON_TEXT('5'): 126 | case JSON_TEXT('6'): 127 | case JSON_TEXT('7'): 128 | case JSON_TEXT('8'): 129 | case JSON_TEXT('9'): 130 | #endif 131 | break; 132 | #endif 133 | default: //just a 0 134 | return true; 135 | } 136 | break; 137 | default: 138 | return false; 139 | } 140 | ++ptr; 141 | 142 | //next digits 143 | while (true){ 144 | switch(*ptr){ 145 | case JSON_TEXT('.'): 146 | if (json_unlikely(decimal)) return false; //multiple decimals 147 | if (json_unlikely(scientific)) return false; 148 | decimal = true; 149 | break; 150 | case JSON_TEXT('e'): 151 | case JSON_TEXT('E'): 152 | if (json_likely(scientific)) return false; 153 | scientific = true; 154 | ++ptr; 155 | switch(*ptr){ 156 | case JSON_TEXT('-'): 157 | case JSON_TEXT('+'): 158 | #ifdef __GNUC__ 159 | case JSON_TEXT('0') ... JSON_TEXT('9'): 160 | #else 161 | case JSON_TEXT('0'): 162 | case JSON_TEXT('1'): 163 | case JSON_TEXT('2'): 164 | case JSON_TEXT('3'): 165 | case JSON_TEXT('4'): 166 | case JSON_TEXT('5'): 167 | case JSON_TEXT('6'): 168 | case JSON_TEXT('7'): 169 | case JSON_TEXT('8'): 170 | case JSON_TEXT('9'): 171 | #endif 172 | break; 173 | default: 174 | return false; 175 | } 176 | break; 177 | #ifdef __GNUC__ 178 | case JSON_TEXT('0') ... JSON_TEXT('9'): 179 | #else 180 | case JSON_TEXT('0'): 181 | case JSON_TEXT('1'): 182 | case JSON_TEXT('2'): 183 | case JSON_TEXT('3'): 184 | case JSON_TEXT('4'): 185 | case JSON_TEXT('5'): 186 | case JSON_TEXT('6'): 187 | case JSON_TEXT('7'): 188 | case JSON_TEXT('8'): 189 | case JSON_TEXT('9'): 190 | #endif 191 | break; 192 | default: 193 | return true; 194 | } 195 | ++ptr; 196 | } 197 | return false; 198 | } 199 | 200 | #ifndef JSON_STRICT 201 | #define LETTERCASE(x, y)\ 202 | case JSON_TEXT(x):\ 203 | case JSON_TEXT(y) 204 | #define LETTERCHECK(x, y)\ 205 | if (json_unlikely((*++ptr != JSON_TEXT(x)) && (*ptr != JSON_TEXT(y)))) return false 206 | #else 207 | #define LETTERCASE(x, y)\ 208 | case JSON_TEXT(x) 209 | #define LETTERCHECK(x, y)\ 210 | if (json_unlikely(*++ptr != JSON_TEXT(x))) return false 211 | #endif 212 | bool JSONValidator::isValidMember(const json_char * & ptr DEPTH_PARAM) json_nothrow { 213 | //ptr is on the first character of the member 214 | //ptr will end up immediately after the last character in the member 215 | switch(*ptr){ 216 | case JSON_TEXT('\"'): 217 | return isValidString(++ptr); 218 | case JSON_TEXT('{'): 219 | INC_DEPTH(); 220 | return isValidObject(++ptr DEPTH_ARG(depth_param)); 221 | case JSON_TEXT('['): 222 | INC_DEPTH(); 223 | return isValidArray(++ptr DEPTH_ARG(depth_param)); 224 | LETTERCASE('t', 'T'): 225 | LETTERCHECK('r', 'R'); 226 | LETTERCHECK('u', 'U'); 227 | LETTERCHECK('e', 'E'); 228 | ++ptr; 229 | return true; 230 | LETTERCASE('f', 'F'): 231 | LETTERCHECK('a', 'A'); 232 | LETTERCHECK('l', 'L'); 233 | LETTERCHECK('s', 'S'); 234 | LETTERCHECK('e', 'E'); 235 | ++ptr; 236 | return true; 237 | LETTERCASE('n', 'N'): 238 | LETTERCHECK('u', 'U'); 239 | LETTERCHECK('l', 'L'); 240 | LETTERCHECK('l', 'L'); 241 | ++ptr; 242 | return true; 243 | #ifndef JSON_STRICT 244 | case JSON_TEXT('}'): //null in libjson 245 | case JSON_TEXT(']'): //null in libjson 246 | case JSON_TEXT(','): //null in libjson 247 | return true; 248 | #endif 249 | case JSON_TEXT('\0'): 250 | return false; 251 | } 252 | //a number 253 | return isValidNumber(ptr); 254 | } 255 | 256 | bool JSONValidator::isValidString(const json_char * & ptr) json_nothrow { 257 | //ptr is pointing to the first character after the quote 258 | //ptr will end up behind the closing " 259 | while(true){ 260 | switch(*ptr){ 261 | case JSON_TEXT('\\'): 262 | switch(*(++ptr)){ 263 | case JSON_TEXT('\"'): 264 | case JSON_TEXT('\\'): 265 | case JSON_TEXT('/'): 266 | case JSON_TEXT('b'): 267 | case JSON_TEXT('f'): 268 | case JSON_TEXT('n'): 269 | case JSON_TEXT('r'): 270 | case JSON_TEXT('t'): 271 | break; 272 | case JSON_TEXT('u'): 273 | if (json_unlikely(!isHex(*++ptr))) return false; 274 | if (json_unlikely(!isHex(*++ptr))) return false; 275 | //fallthrough to \x 276 | #ifndef JSON_STRICT 277 | case JSON_TEXT('x'): //hex 278 | #endif 279 | if (json_unlikely(!isHex(*++ptr))) return false; 280 | if (json_unlikely(!isHex(*++ptr))) return false; 281 | break; 282 | #ifdef JSON_OCTAL 283 | #ifdef __GNUC__ 284 | case JSON_TEXT('0') ... JSON_TEXT('7'): //octal 285 | #else 286 | case JSON_TEXT('0'): 287 | case JSON_TEXT('1'): 288 | case JSON_TEXT('2'): 289 | case JSON_TEXT('3'): 290 | case JSON_TEXT('4'): 291 | case JSON_TEXT('5'): 292 | case JSON_TEXT('6'): 293 | case JSON_TEXT('7'): 294 | #endif 295 | if (json_unlikely((*++ptr < JSON_TEXT('0')) || (*ptr > JSON_TEXT('7')))) return false; 296 | if (json_unlikely((*++ptr < JSON_TEXT('0')) || (*ptr > JSON_TEXT('7')))) return false; 297 | break; 298 | #endif 299 | default: 300 | return false; 301 | } 302 | break; 303 | case JSON_TEXT('\"'): 304 | ++ptr; 305 | return true; 306 | case JSON_TEXT('\0'): 307 | return false; 308 | } 309 | ++ptr; 310 | } 311 | return false; 312 | } 313 | 314 | bool JSONValidator::isValidNamedObject(const json_char * &ptr DEPTH_PARAM) json_nothrow { 315 | if (json_unlikely(!isValidString(++ptr))) return false; 316 | if (json_unlikely(*ptr++ != JSON_TEXT(':'))) return false; 317 | if (json_unlikely(!isValidMember(ptr DEPTH_ARG(depth_param)))) return false; 318 | switch(*ptr){ 319 | case JSON_TEXT(','): 320 | return isValidNamedObject(++ptr DEPTH_ARG(depth_param)); 321 | case JSON_TEXT('}'): 322 | ++ptr; 323 | return true; 324 | default: 325 | return false; 326 | } 327 | } 328 | 329 | bool JSONValidator::isValidObject(const json_char * & ptr DEPTH_PARAM) json_nothrow { 330 | //ptr should currently be pointing past the {, so this must be the start of a name, or the closing } 331 | //ptr will end up past the last } 332 | do{ 333 | switch(*ptr){ 334 | case JSON_TEXT('\"'): 335 | return isValidNamedObject(ptr DEPTH_ARG(depth_param)); 336 | case JSON_TEXT('}'): 337 | ++ptr; 338 | return true; 339 | default: 340 | return false; 341 | } 342 | } while (*++ptr); 343 | return false; 344 | } 345 | 346 | bool JSONValidator::isValidArray(const json_char * & ptr DEPTH_PARAM) json_nothrow { 347 | //ptr should currently be pointing past the [, so this must be the start of a member, or the closing ] 348 | //ptr will end up past the last ] 349 | do{ 350 | switch(*ptr){ 351 | case JSON_TEXT(']'): 352 | ++ptr; 353 | return true; 354 | default: 355 | if (json_unlikely(!isValidMember(ptr DEPTH_ARG(depth_param)))) return false; 356 | switch(*ptr){ 357 | case JSON_TEXT(','): 358 | break; 359 | case JSON_TEXT(']'): 360 | ++ptr; 361 | return true; 362 | default: 363 | return false; 364 | } 365 | break; 366 | } 367 | } while (*++ptr); 368 | return false; 369 | } 370 | 371 | bool JSONValidator::isValidRoot(const json_char * json) json_nothrow { 372 | const json_char * ptr = json; 373 | switch(*ptr){ 374 | case JSON_TEXT('{'): 375 | if (json_likely(isValidObject(++ptr DEPTH_ARG(1)))){ 376 | return *ptr == JSON_TEXT('\0'); 377 | } 378 | return false; 379 | case JSON_TEXT('['): 380 | if (json_likely(isValidArray(++ptr DEPTH_ARG(1)))){ 381 | return *ptr == JSON_TEXT('\0'); 382 | } 383 | return false; 384 | } 385 | return false; 386 | } 387 | 388 | #ifdef JSON_STREAM 389 | //It has already been checked for a complete structure, so we know it's not complete 390 | bool JSONValidator::isValidPartialRoot(const json_char * json) json_nothrow { 391 | const json_char * ptr = json; 392 | switch(*ptr){ 393 | case JSON_TEXT('{'): 394 | JSON_ASSERT_SAFE(!isValidObject(++ptr DEPTH_ARG(1)), JSON_TEXT("Partial Object seems to be valid"), ); 395 | return *ptr == JSON_TEXT('\0'); 396 | case JSON_TEXT('['): 397 | JSON_ASSERT_SAFE(!isValidArray(++ptr DEPTH_ARG(1)), JSON_TEXT("Partial Object seems to be valid"), ); 398 | return *ptr == JSON_TEXT('\0'); 399 | } 400 | return false; 401 | } 402 | #endif 403 | 404 | #endif 405 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONValidator.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_VALIDATOR_H 2 | #define JSON_VALIDATOR_H 3 | 4 | #include "JSONDebug.h" 5 | 6 | #ifdef JSON_VALIDATE 7 | 8 | #ifdef JSON_SECURITY_MAX_NEST_LEVEL 9 | #define DEPTH_PARAM ,size_t depth_param 10 | #define DEPTH_ARG(arg) ,arg 11 | #define INC_DEPTH()\ 12 | if (++depth_param > JSON_SECURITY_MAX_NEST_LEVEL){\ 13 | JSON_FAIL(JSON_TEXT("Exceeded JSON_SECURITY_MAX_NEST_LEVEL"));\ 14 | return false;\ 15 | } 16 | #else 17 | #define DEPTH_PARAM 18 | #define DEPTH_ARG(arg) 19 | #define INC_DEPTH() (void)0 20 | #endif 21 | 22 | class JSONValidator { 23 | public: 24 | static bool isValidNumber(const json_char * & ptr) json_nothrow json_read_priority; 25 | static bool isValidMember(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority; 26 | static bool isValidString(const json_char * & ptr) json_nothrow json_read_priority; 27 | static bool isValidNamedObject(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority; 28 | static bool isValidObject(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority; 29 | static bool isValidArray(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority; 30 | static bool isValidRoot(const json_char * json) json_nothrow json_read_priority; 31 | #ifdef JSON_STREAM 32 | static bool isValidPartialRoot(const json_char * json) json_nothrow json_read_priority; 33 | #endif 34 | private: 35 | JSONValidator(void); 36 | }; 37 | 38 | #endif 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONWorker.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_WORKER_H 2 | #define JSON_WORKER_H 3 | 4 | #include "JSONNode.h" 5 | #include "JSONSharedString.h" 6 | 7 | class JSONWorker { 8 | public: 9 | static json_string RemoveWhiteSpaceAndComments(const json_string & value_t, bool escapeQuotes) json_nothrow json_read_priority; 10 | static json_char * RemoveWhiteSpaceAndCommentsC(const json_string & value_t, bool escapeQuotes) json_nothrow json_read_priority; 11 | 12 | #ifdef JSON_READ_PRIORITY 13 | static JSONNode parse(const json_string & json) json_throws(std::invalid_argument) json_read_priority; 14 | static JSONNode parse_unformatted(const json_string & json) json_throws(std::invalid_argument) json_read_priority; 15 | 16 | static JSONNode _parse_unformatted(const json_char * json, const json_char * const end) json_throws(std::invalid_argument) json_read_priority; 17 | 18 | static json_char * RemoveWhiteSpace(const json_string & value_t, size_t & len, bool escapeQuotes) json_nothrow json_read_priority; 19 | 20 | static void DoArray(const internalJSONNode * parent, const json_string & value_t) json_nothrow json_read_priority; 21 | static void DoNode(const internalJSONNode * parent, const json_string & value_t) json_nothrow json_read_priority; 22 | 23 | #ifdef JSON_LESS_MEMORY 24 | #define NAME_ENCODED this, true 25 | #define STRING_ENCODED this, false 26 | static json_string FixString(const json_string & value_t, const internalJSONNode * flag, bool which) json_nothrow json_read_priority; 27 | #else 28 | #define NAME_ENCODED _name_encoded 29 | #define STRING_ENCODED _string_encoded 30 | static json_string FixString(const json_string & value_t, bool & flag) json_nothrow json_read_priority; 31 | #endif 32 | #endif 33 | 34 | #if defined(JSON_READ_PRIORITY) || defined(JSON_STREAM) 35 | #if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY))) 36 | template 37 | static size_t FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow json_read_priority; 38 | #else 39 | static size_t FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow json_read_priority; 40 | #endif 41 | #endif 42 | static void UnfixString(const json_string & value_t, bool flag, json_string & res) json_nothrow; 43 | JSON_PRIVATE 44 | #ifdef JSON_READ_PRIORITY 45 | static json_char Hex(const json_char * & pos) json_nothrow; 46 | static json_uchar UTF8(const json_char * & pos, const json_char * const end) json_nothrow; 47 | #endif 48 | #ifdef JSON_ESCAPE_WRITES 49 | static json_string toUTF8(json_uchar p) json_nothrow; 50 | #endif 51 | #ifdef JSON_UNICODE 52 | static void UTF(const json_char * & pos, json_string & result, const json_char * const end) json_nothrow; 53 | #ifdef JSON_ESCAPE_WRITES 54 | static json_string toSurrogatePair(json_uchar pos) json_nothrow; 55 | #endif 56 | #endif 57 | #ifdef JSON_READ_PRIORITY 58 | static void SpecialChar(const json_char * & pos, const json_char * const end, json_string & res) json_nothrow; 59 | static void NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, bool array) json_nothrow; 60 | #endif 61 | private: 62 | JSONWorker(void); 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSONWriter.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONNode.h" 2 | #ifdef JSON_WRITE_PRIORITY 3 | #include "JSONWorker.h" 4 | #include "JSONGlobals.h" 5 | 6 | extern bool used_ascii_one; 7 | 8 | #ifdef JSON_INDENT 9 | inline json_string makeIndent(unsigned int amount) json_nothrow json_write_priority; 10 | inline json_string makeIndent(unsigned int amount) json_nothrow { 11 | if (amount == 0xFFFFFFFF) return json_global(EMPTY_JSON_STRING); 12 | json_string result; 13 | result.reserve(amount * json_global(INDENT).length()); 14 | for(unsigned int i = 0; i < amount; ++i){ 15 | result += json_global(INDENT); 16 | } 17 | JSON_ASSERT(result.capacity() == amount * json_global(INDENT).length(), JSON_TEXT("makeIndent made a string too big")); 18 | return result; 19 | } 20 | #else 21 | inline json_string makeIndent(unsigned int amount) json_nothrow { 22 | if (amount == 0xFFFFFFFF) return json_global(EMPTY_JSON_STRING); 23 | if (json_likely(amount < 8)){ 24 | static const json_string cache[] = { 25 | json_string(), 26 | json_string(JSON_TEXT("\t")), 27 | json_string(JSON_TEXT("\t\t")), 28 | json_string(JSON_TEXT("\t\t\t")), 29 | json_string(JSON_TEXT("\t\t\t\t")), 30 | json_string(JSON_TEXT("\t\t\t\t\t")), 31 | json_string(JSON_TEXT("\t\t\t\t\t\t")), 32 | json_string(JSON_TEXT("\t\t\t\t\t\t\t")) 33 | }; 34 | return cache[amount]; 35 | } 36 | #ifndef JSON_LESS_MEMORY 37 | if (json_likely(amount < 16)){ 38 | static const json_string cache[] = { 39 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t")), 40 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t")), 41 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t")), 42 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t")), 43 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t")), 44 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t")), 45 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t")), 46 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")) 47 | }; 48 | return cache[amount - 8]; 49 | } 50 | #if JSON_WRITE_PRIORITY == HIGH 51 | if (json_likely(amount < 24)){ 52 | static const json_string cache[] = { 53 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")), 54 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")), 55 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")), 56 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")), 57 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")), 58 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")), 59 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")), 60 | json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")) 61 | }; 62 | return cache[amount - 16]; 63 | } 64 | #endif 65 | #endif 66 | return json_string(amount, JSON_TEXT('\t')); 67 | } 68 | #endif 69 | 70 | void internalJSONNode::WriteName(bool formatted, bool arrayChild, json_string & output) const json_nothrow { 71 | if (!arrayChild){ 72 | output += JSON_TEXT("\""); 73 | JSONWorker::UnfixString(_name, _name_encoded, output); 74 | output += ((formatted) ? JSON_TEXT("\" : ") : JSON_TEXT("\":")); 75 | } 76 | } 77 | 78 | void internalJSONNode::WriteChildren(unsigned int indent, json_string & output) const json_nothrow { 79 | //Iterate through the children and write them 80 | if (json_likely(CHILDREN -> empty())) return; 81 | 82 | json_string indent_plus_one; 83 | //handle whether or not it's formatted JSON 84 | if (indent != 0xFFFFFFFF){ //it's formatted, make the indentation strings 85 | indent_plus_one = json_global(NEW_LINE) + makeIndent(++indent); 86 | } 87 | 88 | //else it's not formatted, leave the indentation strings empty 89 | const size_t size_minus_one = CHILDREN -> size() - 1; 90 | size_t i = 0; 91 | JSONNode ** it = CHILDREN -> begin(); 92 | for(JSONNode ** it_end = CHILDREN -> end(); it != it_end; ++it, ++i){ 93 | 94 | output += indent_plus_one; 95 | (*it) -> internal -> Write(indent, type() == JSON_ARRAY, output); 96 | if (json_likely(i < size_minus_one)) output += JSON_TEXT(','); //the last one does not get a comma, but all of the others do 97 | } 98 | if (indent != 0xFFFFFFFF){ 99 | output += json_global(NEW_LINE); 100 | output += makeIndent(indent - 1); 101 | } 102 | } 103 | 104 | #ifdef JSON_ARRAY_SIZE_ON_ONE_LINE 105 | void internalJSONNode::WriteChildrenOneLine(unsigned int indent, json_string & output) const json_nothrow { 106 | //Iterate through the children and write them 107 | if (json_likely(CHILDREN -> empty())) return; 108 | if ((*CHILDREN -> begin()) -> internal -> isContainer()) return WriteChildren(indent, output); 109 | 110 | json_string comma(JSON_TEXT(",")); 111 | if (indent != 0xFFFFFFFF){ 112 | comma += JSON_TEXT(' '); 113 | } 114 | 115 | //else it's not formatted, leave the indentation strings empty 116 | const size_t size_minus_one = CHILDREN -> size() - 1; 117 | size_t i = 0; 118 | JSONNode ** it = CHILDREN -> begin(); 119 | for(JSONNode ** it_end = CHILDREN -> end(); it != it_end; ++it, ++i){ 120 | (*it) -> internal -> Write(indent, type() == JSON_ARRAY, output); 121 | if (json_likely(i < size_minus_one)) output += comma; //the last one does not get a comma, but all of the others do 122 | } 123 | } 124 | #endif 125 | 126 | #ifdef JSON_COMMENTS 127 | void internalJSONNode::WriteComment(unsigned int indent, json_string & output) const json_nothrow { 128 | if (indent == 0xFFFFFFFF) return; 129 | if (json_likely(_comment.empty())) return; 130 | size_t pos = _comment.find(JSON_TEXT('\n')); 131 | 132 | const json_string current_indent(json_global(NEW_LINE) + makeIndent(indent)); 133 | 134 | if (json_likely(pos == json_string::npos)){ //Single line comment 135 | output += current_indent; 136 | output += json_global(SINGLELINE_COMMENT); 137 | output.append(_comment.begin(), _comment.end()); 138 | output += current_indent; 139 | return; 140 | } 141 | 142 | /* 143 | Multiline comments 144 | */ 145 | output += current_indent; 146 | #if !(defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS)) 147 | const json_string current_indent_plus_one(json_global(NEW_LINE) + makeIndent(indent + 1)); 148 | output += JSON_TEXT("/*"); 149 | output += current_indent_plus_one; 150 | #endif 151 | size_t old = 0; 152 | while(pos != json_string::npos){ 153 | if (json_unlikely(pos && _comment[pos - 1] == JSON_TEXT('\r'))) --pos; 154 | #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) 155 | output += json_global(SINGLELINE_COMMENT); 156 | #endif 157 | output.append(_comment.begin() + old, _comment.begin() + pos); 158 | 159 | #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) 160 | output += current_indent; 161 | #else 162 | output += current_indent_plus_one; 163 | #endif 164 | old = (_comment[pos] == JSON_TEXT('\r')) ? pos + 2 : pos + 1; 165 | pos = _comment.find(JSON_TEXT('\n'), old); 166 | } 167 | #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) 168 | output += json_global(SINGLELINE_COMMENT); 169 | #endif 170 | output.append(_comment.begin() + old, _comment.end()); 171 | output += current_indent; 172 | #if !(defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS)) 173 | output += JSON_TEXT("*/"); 174 | output += current_indent; 175 | #endif 176 | } 177 | #else 178 | inline void internalJSONNode::WriteComment(unsigned int, json_string &) const json_nothrow {} 179 | #endif 180 | 181 | void internalJSONNode::DumpRawString(json_string & output) const json_nothrow { 182 | //first remove the \1 characters 183 | if (used_ascii_one){ //if it hasn't been used yet, don't bother checking 184 | json_string result(_string.begin(), _string.end()); 185 | for(json_string::iterator beg = result.begin(), en = result.end(); beg != en; ++beg){ 186 | if (*beg == JSON_TEXT('\1')) *beg = JSON_TEXT('\"'); 187 | } 188 | output += result; 189 | return; 190 | } else { 191 | output.append(_string.begin(), _string.end()); 192 | } 193 | } 194 | 195 | void internalJSONNode::Write(unsigned int indent, bool arrayChild, json_string & output) const json_nothrow { 196 | const bool formatted = indent != 0xFFFFFFFF; 197 | WriteComment(indent, output); 198 | 199 | #if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY) 200 | if (!(formatted || fetched)){ //It's not formatted or fetched, just do a raw dump 201 | WriteName(false, arrayChild, output); 202 | //first remove the \1 characters 203 | DumpRawString(output); 204 | return; 205 | } 206 | #endif 207 | 208 | WriteName(formatted, arrayChild, output); 209 | //It's either formatted or fetched 210 | switch (_type){ 211 | case JSON_NODE: //got members, write the members 212 | Fetch(); 213 | output += JSON_TEXT("{"); 214 | WriteChildren(indent, output); 215 | output += JSON_TEXT("}"); 216 | return; 217 | case JSON_ARRAY: //write out the child nodes int he array 218 | Fetch(); 219 | output += JSON_TEXT("["); 220 | #ifdef JSON_ARRAY_SIZE_ON_ONE_LINE 221 | if (size() <= JSON_ARRAY_SIZE_ON_ONE_LINE){ 222 | WriteChildrenOneLine(indent, output); 223 | } else { 224 | #endif 225 | WriteChildren(indent, output); 226 | #ifdef JSON_ARRAY_SIZE_ON_ONE_LINE 227 | } 228 | #endif 229 | output += JSON_TEXT("]"); 230 | return; 231 | case JSON_NUMBER: //write out a literal, without quotes 232 | case JSON_NULL: 233 | case JSON_BOOL: 234 | output.append(_string.begin(), _string.end()); 235 | return; 236 | } 237 | 238 | JSON_ASSERT(_type == JSON_STRING, JSON_TEXT("Unknown json node type")); 239 | //If it go here, then it's a json_string 240 | #if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY) 241 | if (json_likely(fetched)){ 242 | #endif 243 | output += JSON_TEXT("\""); 244 | JSONWorker::UnfixString(_string, _string_encoded, output); //It's already been fetched, meaning that it's unescaped 245 | output += JSON_TEXT("\""); 246 | #if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY) 247 | } else { 248 | DumpRawString(output); //it hasn't yet been fetched, so it's already unescaped, just do a dump 249 | } 250 | #endif 251 | } 252 | #endif 253 | -------------------------------------------------------------------------------- /libjson/_internal/Source/JSON_Base64.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBJSON_GUARD_BASE64_H 2 | #define LIBJSON_GUARD_BASE64_H 3 | 4 | #include "JSONDebug.h" 5 | #if defined(JSON_BINARY) || defined(JSON_EXPOSE_BASE64) //if this is not needed, don't waste space compiling it 6 | 7 | #include "../Dependencies/libbase64++/libbase64++.h" 8 | 9 | class JSONBase64 { 10 | public: 11 | inline static json_string json_encode64(const unsigned char * binary, size_t bytes) json_nothrow json_cold; 12 | inline static std::string json_decode64(const json_string & encoded) json_nothrow json_cold; 13 | private: 14 | JSONBase64(void); 15 | }; 16 | 17 | json_string JSONBase64::json_encode64(const unsigned char * binary, size_t bytes) json_nothrow { 18 | #if defined JSON_DEBUG || defined JSON_SAFE 19 | return libbase64::encode(binary, bytes); 20 | #else 21 | return libbase64::encode(binary, bytes); 22 | #endif 23 | } 24 | 25 | std::string JSONBase64::json_decode64(const json_string & encoded) json_nothrow { 26 | #if defined JSON_DEBUG || defined JSON_SAFE 27 | return libbase64::decode(encoded); 28 | #else 29 | return libbase64::decode(encoded); 30 | #endif 31 | } 32 | 33 | 34 | #endif 35 | #endif 36 | --------------------------------------------------------------------------------