mirror of
https://github.com/idolpx/libMeatloaf.git
synced 2025-12-05 20:28:50 -05:00
291 lines
7.0 KiB
C++
291 lines
7.0 KiB
C++
/*
|
|
* EdUrlParser.cpp
|
|
*
|
|
* Created on: Nov 25, 2014
|
|
* Author: netmind
|
|
*/
|
|
|
|
|
|
#include "EdUrlParser.h"
|
|
|
|
|
|
#define CHECK_LEN_END(POS, LEN) if(POS>=LEN) {_url_errorno=100;goto __PARSE_END;}
|
|
#define WALK_SP(POS, LEN, BUF) for(;POS<LEN && BUF[POS]==' ';POS++)
|
|
#define WALK_UNTIL(POS, LEN, BUF, DELC) for(;POS<LEN && BUF[POS]!=DELC;POS++)
|
|
#define WALK_UNTIL2(POS, LEN, BUF, DELI1, DELI2) for(;POS<LEN && BUF[POS]!=DELI1 && BUF[POS]!=DELI2 ;POS++)
|
|
#define WALK_UNTIL3(POS, LEN, BUF, DELI1, DELI2, DELI3) for(;POS<LEN && BUF[POS]!=DELI1 && BUF[POS]!=DELI2 && BUF[POS]!=DELI3;POS++)
|
|
#define CHECK_REMAIN_END(POS, LEN, REQ_LEN) if(LEN-POS < REQ_LEN) {_url_errorno=100; goto __PARSE_END; }
|
|
#define WALK_CHAR(POS, BUF, DELI) if(BUF[POS++] != DELI) goto __PARSE_END
|
|
|
|
|
|
|
|
int __kv_callback_map(void* list, string k, string v);
|
|
int __kv_callback_vec(void* list, string k, string v);
|
|
|
|
EdUrlParser::EdUrlParser() {
|
|
}
|
|
|
|
EdUrlParser::~EdUrlParser() {
|
|
}
|
|
|
|
|
|
|
|
string EdUrlParser::urlDecode(const string &str) {
|
|
int _url_errorno = 0;
|
|
size_t pos = 0, per = 0;
|
|
size_t len = str.size();
|
|
const char* buf = str.c_str();
|
|
string decstr;
|
|
_url_errorno = 0;
|
|
for (per = pos = 0;;) {
|
|
WALK_UNTIL2(pos, len, buf, '%', '+');
|
|
decstr.append(buf, per, pos - per);
|
|
if (pos >= len)
|
|
goto __PARSE_END;
|
|
if (buf[pos] == '%') {
|
|
CHECK_REMAIN_END(pos, len, 3);
|
|
|
|
char c;
|
|
if(false == EdUrlParser::toChar(buf + pos + 1, &c))
|
|
{
|
|
_url_errorno = 200;
|
|
goto __PARSE_END;
|
|
}
|
|
|
|
decstr.push_back(c);
|
|
pos += 3;
|
|
per = pos;
|
|
|
|
if (pos >= len)
|
|
goto __PARSE_END;
|
|
} else if (buf[pos] == '+') {
|
|
decstr.push_back(' ');
|
|
pos++;
|
|
per = pos;
|
|
}
|
|
}
|
|
__PARSE_END: if (_url_errorno != 0)
|
|
return "";
|
|
return decstr;
|
|
|
|
}
|
|
|
|
string EdUrlParser::urlEncode(const string &s) {
|
|
const char *ptr = s.c_str();
|
|
string enc;
|
|
char c;
|
|
char phex[3] = { '%' };
|
|
for (size_t i = 0; i < s.size(); i++) {
|
|
c = ptr[i];
|
|
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|
|
|| (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '*'
|
|
|| c == '.') {
|
|
enc.push_back(c);
|
|
} else if (c == ' ') {
|
|
enc.push_back('+');
|
|
} else {
|
|
toHex(phex + 1, c);
|
|
enc.append(phex, 0, 3);
|
|
}
|
|
}
|
|
return enc;
|
|
}
|
|
|
|
void EdUrlParser::toHex(char* desthex, char c) {
|
|
static char hextable[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
|
|
'9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
|
desthex[0] = hextable[c >> 4];
|
|
desthex[1] = hextable[c & 0x0f];
|
|
}
|
|
|
|
// #prgamas are to ignore warnings about variables being set and not used
|
|
//__BEGIN_IGNORE_UNUSEDVARS
|
|
int EdUrlParser::parsePath(vector<string>* folders, string pathstr) {
|
|
int _url_errorno = 0;
|
|
int path_pos = 0;
|
|
size_t pos = 0;
|
|
size_t len = pathstr.size();
|
|
const char* str = pathstr.c_str();
|
|
string name;
|
|
|
|
for (pos = 0;;) {
|
|
WALK_CHAR(pos, str, '/');
|
|
path_pos = pos;
|
|
CHECK_LEN_END(pos, len);
|
|
WALK_UNTIL(pos, len, str, '/');
|
|
name = pathstr.substr(path_pos, pos - path_pos);
|
|
folders->push_back(name);
|
|
}
|
|
__PARSE_END: return folders->size();
|
|
}
|
|
//__END_IGNORE_UNUSEDVARS
|
|
|
|
//__BEGIN_IGNORE_UNUSEDVARS
|
|
void EdUrlParser::parse() {
|
|
int _url_errorno = 0;
|
|
const char *str = mRawUrl.c_str();
|
|
|
|
size_t pos, len;
|
|
int scheme_pos, host_pos, port_pos, path_pos, param_pos, tag_pos;
|
|
pos = 0;
|
|
len = mRawUrl.size();
|
|
WALK_SP(pos, len, str); // remove preceding spaces.
|
|
if (str[pos] == '/') {
|
|
goto __PARSE_HOST;
|
|
}
|
|
|
|
// start protocol scheme
|
|
scheme_pos = pos;
|
|
WALK_UNTIL(pos, len, str, ':');
|
|
CHECK_LEN_END(pos, len);
|
|
scheme = mRawUrl.substr(scheme_pos, pos - scheme_pos);
|
|
CHECK_REMAIN_END(pos, len, 3);
|
|
WALK_CHAR(pos, str, ':');
|
|
WALK_CHAR(pos, str, '/');
|
|
|
|
// start host address
|
|
__PARSE_HOST:
|
|
WALK_CHAR(pos, str, '/');
|
|
host_pos = pos;
|
|
WALK_UNTIL3(pos, len, str, ':', '/', '?');
|
|
if (pos < len) {
|
|
hostName = mRawUrl.substr(host_pos, pos - host_pos);
|
|
if (str[pos] == ':')
|
|
goto __PARSE_PORT;
|
|
if (str[pos] == '/')
|
|
goto __PARSE_PATH;
|
|
if (str[pos] == '?')
|
|
goto __PARSE_PARAM;
|
|
} else {
|
|
hostName = mRawUrl.substr(host_pos, pos - host_pos);
|
|
}
|
|
|
|
__PARSE_PORT:
|
|
WALK_CHAR(pos, str, ':');
|
|
port_pos = pos;
|
|
WALK_UNTIL2(pos, len, str, '/', '?');
|
|
port = mRawUrl.substr(port_pos, pos - port_pos);
|
|
CHECK_LEN_END(pos, len);
|
|
if (str[pos] == '?')
|
|
goto __PARSE_PARAM;
|
|
__PARSE_PATH: path_pos = pos;
|
|
WALK_UNTIL(pos, len, str, '?');
|
|
path = mRawUrl.substr(path_pos, pos - path_pos);
|
|
CHECK_LEN_END(pos, len);
|
|
__PARSE_PARAM:
|
|
WALK_CHAR(pos, str, '?');
|
|
param_pos = pos;
|
|
WALK_UNTIL(pos, len, str, '#');
|
|
query = mRawUrl.substr(param_pos, pos - param_pos);
|
|
CHECK_LEN_END(pos, len);
|
|
|
|
// start parsing fragment
|
|
WALK_CHAR(pos, str, '#');
|
|
tag_pos = pos;
|
|
fragment = mRawUrl.substr(tag_pos, len - tag_pos);
|
|
__PARSE_END: return;
|
|
}
|
|
//__END_IGNORE_UNUSEDVARS
|
|
|
|
EdUrlParser* EdUrlParser::parseUrl(const string &urlstr) {
|
|
EdUrlParser *url = new EdUrlParser;
|
|
url->mRawUrl = urlstr;
|
|
url->parse();
|
|
return url;
|
|
}
|
|
|
|
bool EdUrlParser::toChar(const char* hex, char *result) {
|
|
unsigned char nible[2];
|
|
unsigned char c, base;
|
|
for (int i = 0; i < 2; i++) {
|
|
c = hex[i];
|
|
if (c >= '0' && c <= '9') {
|
|
base = '0';
|
|
} else if (c >= 'A' && c <= 'F') {
|
|
base = 'A' - 10;
|
|
} else if (c >= 'a' && c <= 'f') {
|
|
base = 'a' - 10;
|
|
} else {
|
|
return false;
|
|
}
|
|
nible[i] = c - base;
|
|
}
|
|
*result = ((nible[0] << 4) | nible[1]);
|
|
return true;
|
|
}
|
|
|
|
size_t EdUrlParser::parseKeyValueMap(unordered_map<string, string> *kvmap, const string &rawstr, bool strict) {
|
|
return parseKeyValue(rawstr, __kv_callback_map, kvmap, strict);
|
|
}
|
|
|
|
size_t EdUrlParser::parseKeyValueList(vector< query_kv_t > *kvvec, const string &rawstr, bool strict) {
|
|
return parseKeyValue(rawstr, __kv_callback_vec, kvvec, strict);
|
|
}
|
|
|
|
size_t EdUrlParser::parseKeyValue(const string &rawstr, __kv_callback kvcb, void* obj, bool strict) {
|
|
|
|
int _url_errorno = 0;
|
|
const char *str = rawstr.c_str();
|
|
size_t pos, len, item_len;
|
|
pos = 0;
|
|
len = rawstr.size();
|
|
|
|
string key, val;
|
|
size_t key_pos;
|
|
WALK_SP(pos, len, str);
|
|
CHECK_LEN_END(pos, len);
|
|
key_pos = pos;
|
|
item_len = 0;
|
|
for(;;) {
|
|
WALK_UNTIL2(pos, len, str, '=', '&');
|
|
if(pos >= len || str[pos] == '&') {
|
|
// Be careful for boundary check error to be caused. !!!
|
|
// *** Do not access str[] any more in this block. !!!
|
|
|
|
val = rawstr.substr(key_pos, pos-key_pos);
|
|
|
|
if(strict == true) {
|
|
if(key.empty() == false && val.empty()==false) {
|
|
kvcb(obj, key, val);
|
|
item_len++;
|
|
}
|
|
} else if(!(key.empty()==true && val.empty()==true)){
|
|
kvcb(obj, key, val);
|
|
item_len++;
|
|
}
|
|
|
|
key.clear();val.clear();
|
|
if(pos >= len) goto __PARSE_END;
|
|
pos++;
|
|
key_pos = pos;
|
|
}
|
|
else if(str[pos] == '=') {
|
|
key = rawstr.substr(key_pos, pos-key_pos);
|
|
pos++;
|
|
key_pos = pos;
|
|
}
|
|
}
|
|
__PARSE_END:
|
|
if(_url_errorno != 0 )
|
|
return -1;
|
|
return item_len;
|
|
}
|
|
|
|
|
|
int __kv_callback_map(void* list, string k, string v) {
|
|
auto *map = (unordered_map<string, string>*)list;
|
|
(*map)[k] = v;
|
|
return map->size();
|
|
}
|
|
|
|
int __kv_callback_vec(void* list, string k, string v) {
|
|
auto *vec = (vector<query_kv_t>*)list;
|
|
query_kv_t t ={k, v};
|
|
vec->push_back(t);
|
|
return vec->size();
|
|
}
|
|
|
|
bool EdUrlParser::isValidUrl()
|
|
{
|
|
return !scheme.empty() && !(path.empty() && port.empty());
|
|
} |