7#include <unordered_map>
19int qs_strncmp(
const char* s,
const char* qs,
size_t n);
26size_t qs_parse(
char* qs,
char* qs_kv[],
size_t qs_kv_size,
bool parse_url);
30int qs_decode(
char * qs);
37 char * qs_k2v(
const char * key,
char *
const * qs_kv,
size_t qs_kv_size,
int nth);
42char * qs_scanvalue(
const char * key,
const char * qs,
char * val,
size_t val_len);
48#define CROW_QS_ISHEX(x) ((((x)>='0'&&(x)<='9') || ((x)>='A'&&(x)<='F') || ((x)>='a'&&(x)<='f')) ? 1 : 0)
49#define CROW_QS_HEX2DEC(x) (((x)>='0'&&(x)<='9') ? (x)-48 : ((x)>='A'&&(x)<='F') ? (x)-55 : ((x)>='a'&&(x)<='f') ? (x)-87 : 0)
50#define CROW_QS_ISQSCHR(x) ((((x)=='=')||((x)=='#')||((x)=='&')||((x)=='\0')) ? 0 : 1)
52inline int qs_strncmp(
const char * s,
const char * qs,
size_t n)
54 unsigned char u1, u2, unyb, lnyb;
58 u1 =
static_cast<unsigned char>(*s++);
59 u2 =
static_cast<unsigned char>(*qs++);
61 if ( ! CROW_QS_ISQSCHR(u1) ) { u1 =
'\0'; }
62 if ( ! CROW_QS_ISQSCHR(u2) ) { u2 =
'\0'; }
64 if ( u1 ==
'+' ) { u1 =
' '; }
68 if ( CROW_QS_ISHEX(s[0]) && CROW_QS_ISHEX(s[1]) )
70 unyb =
static_cast<unsigned char>(*s++);
71 lnyb =
static_cast<unsigned char>(*s++);
72 u1 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb);
80 if ( u2 ==
'+' ) { u2 =
' '; }
84 if ( CROW_QS_ISHEX(qs[0]) && CROW_QS_ISHEX(qs[1]) )
86 unyb =
static_cast<unsigned char>(*qs++);
87 lnyb =
static_cast<unsigned char>(*qs++);
88 u2 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb);
101 if ( CROW_QS_ISQSCHR(*qs) )
108inline size_t qs_parse(
char* qs,
char* qs_kv[],
size_t qs_kv_size,
bool parse_url =
true)
113 for(i=0; i<qs_kv_size; i++) qs_kv[i] = NULL;
116 substr_ptr = parse_url ? qs + strcspn(qs,
"?#") : qs;
119 if (substr_ptr[0] !=
'\0')
128 qs_kv[i] = substr_ptr;
129 j = strcspn(substr_ptr,
"&");
130 if ( substr_ptr[j] ==
'\0' ) { i++;
break; }
139 substr_ptr = qs_kv[j] + strcspn(qs_kv[j],
"=&#");
140 if ( substr_ptr[0] ==
'&' || substr_ptr[0] ==
'\0')
141 substr_ptr[0] =
'\0';
143 qs_decode(++substr_ptr);
154inline int qs_decode(
char * qs)
158 while( CROW_QS_ISQSCHR(qs[j]) )
160 if ( qs[j] ==
'+' ) { qs[i] =
' '; }
161 else if ( qs[j] ==
'%' )
164 if ( qs[j+1] ==
'\0' || qs[j+2] ==
'\0' ||
165 ! CROW_QS_ISHEX(qs[j+1]) || ! CROW_QS_ISHEX(qs[j+2]) )
170 qs[i] = (CROW_QS_HEX2DEC(qs[j+1]) * 16) + CROW_QS_HEX2DEC(qs[j+2]);
185inline char * qs_k2v(
const char * key,
char *
const * qs_kv,
size_t qs_kv_size,
int nth = 0)
188 size_t key_len, skip;
190 key_len = strlen(key);
195 for(i=0; i<qs_kv_size; i++)
198 if ( qs_strncmp(key, qs_kv[i], key_len) == 0 )
200 skip = strcspn(qs_kv[i],
"=");
201 if ( qs_kv[i][skip] ==
'=' )
205 return qs_kv[i] + skip;
215inline std::unique_ptr<std::pair<std::string, std::string>> qs_dict_name2kv(
const char * dict_name,
char *
const * qs_kv,
size_t qs_kv_size,
int nth = 0)
218 size_t name_len, skip_to_eq, skip_to_brace_open, skip_to_brace_close;
220 name_len = strlen(dict_name);
225 for(i=0; i<qs_kv_size; i++)
227 if ( strncmp(dict_name, qs_kv[i], name_len) == 0 )
229 skip_to_eq = strcspn(qs_kv[i],
"=");
230 if ( qs_kv[i][skip_to_eq] ==
'=' )
232 skip_to_brace_open = strcspn(qs_kv[i],
"[");
233 if ( qs_kv[i][skip_to_brace_open] ==
'[' )
234 skip_to_brace_open++;
235 skip_to_brace_close = strcspn(qs_kv[i],
"]");
238 if ( skip_to_brace_open == strlen(qs_kv[i]) )
240 const char* open = strstr(qs_kv[i] + name_len,
"%5B");
242 open = strstr(qs_kv[i] + name_len,
"%5b");
243 if ( open && open == qs_kv[i] + name_len )
245 const char* close = strstr(open + 3,
"%5D");
247 close = strstr(open + 3,
"%5d");
248 if ( close && nth == 0 )
250 auto key = std::string(open + 3,
static_cast<size_t>(close - (open + 3)));
251 auto value = std::string(qs_kv[i] + skip_to_eq);
252 return std::unique_ptr<std::pair<std::string, std::string>>(
new std::pair<std::string, std::string>(key, value));
262 if ( skip_to_brace_open <= skip_to_brace_close &&
263 skip_to_brace_open > 0 &&
264 skip_to_brace_close > 0 &&
267 auto key = std::string(qs_kv[i] + skip_to_brace_open, skip_to_brace_close - skip_to_brace_open);
268 auto value = std::string(qs_kv[i] + skip_to_eq);
269 return std::unique_ptr<std::pair<std::string, std::string>>(
new std::pair<std::string, std::string>(key, value));
283inline char * qs_scanvalue(
const char * key,
const char * qs,
char * val,
size_t val_len)
285 const char * tmp= strchr(qs,
'?');
288 if ( tmp !=
nullptr )
291 const size_t key_len = strlen(key);
292 while(*qs !=
'#' && *qs !=
'\0')
294 if ( qs_strncmp(key, qs, key_len) == 0 )
296 qs += strcspn(qs,
"&");
300 if ( qs[0] ==
'\0' )
return nullptr;
302 qs += strcspn(qs,
"=&#");
306 size_t i = strcspn(qs,
"&=#");
308 strncpy_s(val, val_len, qs, (val_len - 1)<(i + 1) ? (val_len - 1) : (i + 1));
310 strncpy(val, qs, (val_len - 1)<(i + 1) ? (val_len - 1) : (i + 1));
333 static const int MAX_KEY_VALUE_PAIRS_COUNT = 256;
340 for (
auto p : qs.key_value_pairs_)
342 key_value_pairs_.push_back((
char*)(p - qs.url_.c_str() + url_.c_str()));
349 key_value_pairs_.clear();
350 for (
auto p : qs.key_value_pairs_)
352 key_value_pairs_.push_back((
char*)(p - qs.url_.c_str() + url_.c_str()));
359 key_value_pairs_ = std::move(qs.key_value_pairs_);
360 char* old_data = (
char*)qs.url_.c_str();
361 url_ = std::move(qs.url_);
362 for (
auto& p : key_value_pairs_)
364 p += (
char*)url_.c_str() - old_data;
371 url_(std::move(params))
376 key_value_pairs_.resize(MAX_KEY_VALUE_PAIRS_COUNT);
377 size_t count = qs_parse(&url_[0], &key_value_pairs_[0], MAX_KEY_VALUE_PAIRS_COUNT, url);
379 key_value_pairs_.resize(count);
380 key_value_pairs_.shrink_to_fit();
385 key_value_pairs_.clear();
389 friend std::ostream& operator<<(std::ostream& os,
const query_string& qs)
392 for (
size_t i = 0; i < qs.key_value_pairs_.size(); ++i)
396 os << qs.key_value_pairs_[i];
406 char*
get(
const std::string& name)
const
408 char* ret = qs_k2v(name.c_str(), key_value_pairs_.data(), key_value_pairs_.size());
413 char*
pop(
const std::string& name)
415 char* ret =
get(name);
418 const std::string key_name = name +
'=';
419 for (
unsigned int i = 0; i < key_value_pairs_.size(); i++)
421 std::string str_item(key_value_pairs_[i]);
422 if (str_item.find(key_name)==0)
424 key_value_pairs_.erase(key_value_pairs_.begin() + i);
436 std::vector<char*>
get_list(
const std::string& name,
bool use_brackets =
true)
const
438 std::vector<char*> ret;
439 std::string plus = name + (use_brackets ?
"[]" :
"");
440 char* element =
nullptr;
445 element = qs_k2v(plus.c_str(), key_value_pairs_.data(), key_value_pairs_.size(), count++);
448 ret.push_back(element);
454 std::vector<char*>
pop_list(
const std::string& name,
bool use_brackets =
true)
456 std::vector<char*> ret =
get_list(name, use_brackets);
457 const size_t name_len = name.length();
460 for (
unsigned int i = 0; i < key_value_pairs_.size(); i++)
462 std::string str_item(key_value_pairs_[i]);
463 if (str_item.find(name)==0) {
464 if (use_brackets && str_item.find(
"[]=",name_len)==name_len) {
465 key_value_pairs_.erase(key_value_pairs_.begin() + i--);
466 }
else if (!use_brackets && str_item.find(
'=',name_len)==name_len ) {
467 key_value_pairs_.erase(key_value_pairs_.begin() + i--);
481 std::unordered_map<std::string, std::string>
get_dict(
const std::string& name)
const
483 std::unordered_map<std::string, std::string> ret;
488 if (
auto element = qs_dict_name2kv(name.c_str(), key_value_pairs_.data(), key_value_pairs_.size(), count++))
489 ret.insert(*element);
497 std::unordered_map<std::string, std::string>
pop_dict(
const std::string& name)
499 const std::string name_value = name +
'[';
500 std::unordered_map<std::string, std::string> ret =
get_dict(name);
503 for (
unsigned int i = 0; i < key_value_pairs_.size(); i++)
505 std::string str_item(key_value_pairs_[i]);
506 if (str_item.find(name_value)==0)
508 key_value_pairs_.erase(key_value_pairs_.begin() + i--);
515 std::vector<std::string> keys()
const
517 std::vector<std::string> keys;
518 keys.reserve(key_value_pairs_.size());
520 for (
const char*
const element : key_value_pairs_)
522 const char* delimiter = strchr(element,
'=');
524 keys.emplace_back(element, delimiter);
526 keys.emplace_back(element);
534 std::vector<char*> key_value_pairs_;
A class to represent any data coming after the ? in the request URL into key-value pairs.
Definition query_string.h:331
std::unordered_map< std::string, std::string > pop_dict(const std::string &name)
Works the same as get_dict() but removes the values from the query string.
Definition query_string.h:497
char * pop(const std::string &name)
Works similar to get() except it removes the item from the query string.
Definition query_string.h:413
std::unordered_map< std::string, std::string > get_dict(const std::string &name) const
Works similar to get_list() except the brackets are mandatory must not be empty.
Definition query_string.h:481
std::vector< char * > get_list(const std::string &name, bool use_brackets=true) const
Returns a list of values, passed as ?name[]=value1&name[]=value2&...name[]=valuen with n being the si...
Definition query_string.h:436
std::vector< char * > pop_list(const std::string &name, bool use_brackets=true)
Similar to get_list() but it removes the.
Definition query_string.h:454
char * get(const std::string &name) const
Get a value from a name, used for ?name=value.
Definition query_string.h:406
The main namespace of the library. In this namespace is defined the most important classes and functi...