478 lines
15 KiB
C++
478 lines
15 KiB
C++
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#include <a8/a8.h>
|
|
#include <a8/strutils.h>
|
|
|
|
namespace a8
|
|
{
|
|
|
|
std::string Bin2Hex(const std::string& binstr)
|
|
{
|
|
std::string result;
|
|
for(unsigned int i = 0; i < binstr.size(); i++){
|
|
assert(false);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const char* GetValidStr1(const char* szLine, char **pp, int& iLen, const char* szIngore)
|
|
{
|
|
//skip ingorechars
|
|
*pp = (char*)szLine;
|
|
while(*pp && **pp && strchr(szIngore, **pp)) (*pp)++;
|
|
//read validchars
|
|
iLen = 0;
|
|
while((*pp + iLen) && *(*pp + iLen) && !strchr(szIngore, *(*pp + iLen++))) ;
|
|
if (!strchr(szIngore, *(*pp + iLen))){
|
|
iLen--;
|
|
}
|
|
return *pp + iLen ;
|
|
}
|
|
|
|
std::string GetValidStr(const std::string& strLine, std::string& strVal, const char* szIngore)
|
|
{
|
|
char *pp = NULL;
|
|
int iLen = 0;
|
|
const char *result = a8::GetValidStr1(strLine.c_str(), &pp, iLen, szIngore);
|
|
strVal.assign(pp, iLen);
|
|
return result ? std::string(result) : "";
|
|
}
|
|
|
|
std::string Trim(const std::string& str)
|
|
{
|
|
std::string text = str;
|
|
if(!text.empty()){
|
|
text.erase(0, text.find_first_not_of(" \n\r\t"));
|
|
text.erase(text.find_last_not_of(" \n\r\t") + 1);
|
|
}
|
|
return text;
|
|
}
|
|
|
|
std::string FormatEx(const char* fmt, std::initializer_list<a8::XValue>& args)
|
|
{
|
|
std::string result;
|
|
result.reserve(1024);
|
|
const char *p = fmt;
|
|
auto itr = args.begin();
|
|
while(*p){
|
|
if(*p == '%' && *(p+1)){
|
|
p++;
|
|
switch(*p){
|
|
case 'd':
|
|
assert(itr != args.end());
|
|
result.append(itr->GetString().c_str());
|
|
itr++;
|
|
break;
|
|
case 'f':
|
|
assert(itr != args.end());
|
|
result.append(itr->GetString().c_str());
|
|
itr++;
|
|
break;
|
|
case 's':
|
|
assert(itr != args.end());
|
|
result.append(itr->GetString().c_str());
|
|
itr++;
|
|
break;
|
|
default:{
|
|
result.push_back('%');
|
|
result.push_back(*p);
|
|
}
|
|
}
|
|
}else{
|
|
result.push_back(*p);
|
|
}
|
|
p++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string Format(const char* fmt, std::initializer_list<a8::XValue> args)
|
|
{
|
|
return a8::FormatEx(fmt, args);
|
|
}
|
|
|
|
std::string FormatEx2(const char* fmt, std::vector<a8::XValue>& args)
|
|
{
|
|
std::string result;
|
|
result.reserve(1024);
|
|
const char *p = fmt;
|
|
auto itr = args.begin();
|
|
while(*p){
|
|
if(*p == '%' && *(p+1)){
|
|
p++;
|
|
switch(*p){
|
|
case 'd':
|
|
assert(itr != args.end());
|
|
result.append(itr->GetString().c_str());
|
|
itr++;
|
|
break;
|
|
case 'f':
|
|
assert(itr != args.end());
|
|
result.append(itr->GetString().c_str());
|
|
itr++;
|
|
break;
|
|
case 's':
|
|
assert(itr != args.end());
|
|
result.append(itr->GetString().c_str());
|
|
itr++;
|
|
break;
|
|
default:{
|
|
result.push_back('%');
|
|
result.push_back(*p);
|
|
}
|
|
}
|
|
}else{
|
|
result.push_back(*p);
|
|
}
|
|
p++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string Format2(const char* fmt, std::vector<a8::XValue> args)
|
|
{
|
|
return a8::FormatEx2(fmt, args);
|
|
}
|
|
|
|
void Split(const std::string& str, std::vector<std::string>& list, char separator)
|
|
{
|
|
const char *p = str.c_str();
|
|
const char *pv = p;
|
|
while(*p){
|
|
if(*p == separator){
|
|
if(p > pv){
|
|
list.push_back(std::string(pv, p - pv));
|
|
}else{
|
|
list.push_back("");
|
|
}
|
|
pv = p + 1;
|
|
}
|
|
p++;
|
|
}
|
|
if(*p == separator){
|
|
list.push_back("");
|
|
}else if(p > pv){
|
|
list.push_back(std::string(pv, p - pv));
|
|
}
|
|
}
|
|
|
|
unsigned char FromHex(unsigned char x)
|
|
{
|
|
return isdigit(x) ? x-'0' : x-'A'+10;
|
|
}
|
|
|
|
unsigned char ToHex(unsigned char x)
|
|
{
|
|
return x > 9 ? x + 55 : x + 48;
|
|
}
|
|
|
|
std::string HexEncode(const std::string& str)
|
|
{
|
|
std::string strTemp;
|
|
strTemp.reserve(str.size() * 2);
|
|
for (unsigned int i = 0; i < str.size(); i++) {
|
|
char buf[3] = {'\0'};
|
|
sprintf(buf, "%x", (int)str[i]);
|
|
strTemp += std::string(strTemp);
|
|
}
|
|
return strTemp;
|
|
}
|
|
|
|
bool HexDecode(const std::string& str, std::string& outstr)
|
|
{
|
|
for (unsigned int i = 0; i + 1 < str.size(); i += 2) {
|
|
int int_c = 0;
|
|
char buf[3] = {str[i], str[i + 1], '\0'};
|
|
sscanf(buf, "%x", &int_c);
|
|
outstr.push_back((char)int_c);
|
|
}
|
|
return str.size() % 2 == 0;
|
|
}
|
|
|
|
std::string UrlEncode(const std::string& str)
|
|
{
|
|
std::string strTemp = "";
|
|
size_t length = str.length();
|
|
for (size_t i = 0; i < length; i++) {
|
|
if (isalnum((unsigned char)str[i]) ||
|
|
(str[i] == '-') ||
|
|
(str[i] == '_') ||
|
|
(str[i] == '.') ||
|
|
(str[i] == '~')) {
|
|
strTemp += str[i];
|
|
} else if (str[i] == ' ') {
|
|
strTemp += "+";
|
|
} else {
|
|
strTemp += '%';
|
|
strTemp += ToHex((unsigned char)str[i] >> 4);
|
|
strTemp += ToHex((unsigned char)str[i] % 16);
|
|
}
|
|
}
|
|
return strTemp;
|
|
}
|
|
|
|
std::string UrlDecode(const std::string &sIn)
|
|
{
|
|
std::string sOut;
|
|
for(unsigned int i = 0; i < sIn.size(); i++ ){
|
|
unsigned char ch = 0;
|
|
if(sIn[i] == '%'){
|
|
ch = (a8::FromHex(sIn[i + 1]) << 4);
|
|
ch |= a8::FromHex(sIn[i + 2]);
|
|
i += 2;
|
|
}else if(sIn[i] == '+'){
|
|
ch = ' ';
|
|
}
|
|
else{
|
|
ch = sIn[i];
|
|
}
|
|
sOut += (char)ch;
|
|
}
|
|
return sOut;
|
|
}
|
|
|
|
void ParserQueryStr(char* buf, std::string& url, std::string& querystr)
|
|
{
|
|
char *p_query_start = strstr(buf, "?");
|
|
if (p_query_start) {
|
|
url.assign(buf, p_query_start - buf);
|
|
p_query_start++;
|
|
char *p_query_end = strstr(p_query_start, " ");
|
|
if (p_query_end) {
|
|
querystr.assign(p_query_start, p_query_end - p_query_start);
|
|
} else {
|
|
querystr.assign(p_query_start);
|
|
}
|
|
} else {
|
|
p_query_start = buf;
|
|
char *p_end = strstr(p_query_start, " ");
|
|
if (p_end) {
|
|
url.assign(p_query_start, p_end - p_query_start);
|
|
} else {
|
|
url.assign(p_query_start);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ParserUrlQueryString(const char* querystring, std::map<std::string, a8::XValue>& query)
|
|
{
|
|
if(!querystring || *querystring == 0){
|
|
return;
|
|
}
|
|
std::vector<std::string> params;
|
|
a8::Split(std::string(querystring), params, '&');
|
|
for(unsigned int i = 0; i < params.size(); i++){
|
|
int pos = params[i].find('=');
|
|
if(pos > 0){
|
|
std::string key = params[i].substr(0, pos);
|
|
std::string val = params[i].substr(pos + 1, params[i].size() - pos);
|
|
val = a8::UrlDecode(val);
|
|
// query[key] = a8::XValue(val);
|
|
query.insert(std::pair<std::string, a8::XValue>(key, a8::XValue(val)));
|
|
}
|
|
}
|
|
}
|
|
|
|
void ReplaceString(std::string& basestr, const std::string& srcstr, const std::string& deststr)
|
|
{
|
|
std::string::size_type pos = 0;
|
|
std::string::size_type srcLen = srcstr.size();
|
|
std::string::size_type desLen = deststr.size();
|
|
pos = basestr.find(srcstr, pos);
|
|
while((pos != std::string::npos)){
|
|
basestr.replace(pos, srcLen, deststr);
|
|
pos = basestr.find(srcstr, (pos + desLen));
|
|
}
|
|
}
|
|
|
|
std::string HttpResponse(const std::string& content)
|
|
{
|
|
return HttpResponse(200, content);
|
|
}
|
|
|
|
std::string HttpResponse(int code, const std::string& content)
|
|
{
|
|
std::string response = a8::Format(
|
|
"HTTP/1.1 %d OK\r\n"
|
|
"Connection: close\r\n"
|
|
"Content-Type: text/plain\r\n"
|
|
"Content-Length: %d\r\n\r\n%s",
|
|
{
|
|
code,
|
|
content.size(),
|
|
content
|
|
});
|
|
return response;
|
|
}
|
|
|
|
std::string JsonEscapeString(const std::string& str)
|
|
{
|
|
std::string result;
|
|
result.reserve(str.size() * 2);
|
|
const char* p = str.data();
|
|
while(*p){
|
|
if(*p >=0 && *p < ' '){
|
|
switch(*p){
|
|
case '\b':
|
|
result.append("\\b");
|
|
break;
|
|
case '\t':
|
|
result.append("\\t");
|
|
break;
|
|
case '\n':
|
|
result.append("\\n");
|
|
break;
|
|
case '\f':
|
|
result.append("\\f");
|
|
break;
|
|
case '\r':
|
|
result.append("\\r");
|
|
break;
|
|
default:
|
|
{
|
|
char unicodehex[6] = {'\\', 'u', '0', '0', '0', '0'};
|
|
char *pu = &unicodehex[5];
|
|
int n = *p;
|
|
do{
|
|
*pu-- = "0123456789abcdef"[n % 16];
|
|
n /= 16;
|
|
}while(n);
|
|
result.append(unicodehex);
|
|
}
|
|
}
|
|
}else if (*p == '"'){
|
|
result.append("\\\"");
|
|
}else if (*p == '\\'){
|
|
result.append("\\\\");
|
|
|
|
}else{
|
|
result.push_back(*p);
|
|
}//end if
|
|
p++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string IntToFixedString(int val, int n)
|
|
{
|
|
if (n < 1 || n > 10) {
|
|
abort();
|
|
}
|
|
char buf_fmt[20];
|
|
sprintf(buf_fmt, "%%%dd", n);
|
|
|
|
char buf[20];
|
|
sprintf(buf, buf_fmt, val);
|
|
|
|
std::string result = std::string((char*)buf);
|
|
a8::ReplaceString(result, " ", "0");
|
|
return result;
|
|
}
|
|
|
|
bool ReadStringFromFile(const std::string& filename, std::string& data)
|
|
{
|
|
FILE *fp = fopen(filename.c_str(), "rb");
|
|
if (!fp) {
|
|
return false;
|
|
}
|
|
fseek(fp, 0, SEEK_END);
|
|
int fileSize = ftell(fp);
|
|
if(fileSize){
|
|
char *p = (char*)malloc(fileSize + 1);
|
|
if(p){
|
|
*(p + fileSize) = '\0';
|
|
fseek(fp, 0, SEEK_SET);
|
|
fread(p, 1, fileSize, fp);
|
|
if (fileSize > 0) {
|
|
data.append(p, fileSize);
|
|
}
|
|
free(p);
|
|
}
|
|
}
|
|
fclose(fp);
|
|
return true;
|
|
}
|
|
|
|
int SafeStrCmp(const char* s1, const char* s2)
|
|
{
|
|
return strcmp(s1 ? s1 : "", s2 ? s2 : "");
|
|
}
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wunused-variable"
|
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
|
|
|
size_t GetUtf8Length(const char *str)
|
|
{
|
|
static unsigned char utf8_look_for_table[] =
|
|
{
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
|
|
};
|
|
|
|
#define UTFLEN(x) utf8_look_for_table[(x)]
|
|
|
|
auto utf8_char_len =
|
|
[] (char firstByte) -> int
|
|
{
|
|
const unsigned char kFirstBitMask = 128; // 1000000
|
|
const unsigned char kSecondBitMask = 64; // 0100000
|
|
const unsigned char kThirdBitMask = 32; // 0010000
|
|
const unsigned char kFourthBitMask = 16; // 0001000
|
|
const unsigned char kFifthBitMask = 8; // 0000100
|
|
|
|
std::string::difference_type offset = 1;
|
|
|
|
if (firstByte & kFirstBitMask) { // This means the first byte has a value greater than 127, and so is beyond the ASCII range.
|
|
if (firstByte & kThirdBitMask) { // This means that the first byte has a value greater than 224, and so it must be at least a three-octet code point.
|
|
if (firstByte & kFourthBitMask) { // This means that the first byte has a value greater than 240, and so it must be a four-octet code point.
|
|
offset = 4;
|
|
}else{
|
|
offset = 3;
|
|
}
|
|
}else{
|
|
offset = 2;
|
|
}
|
|
}
|
|
return offset;
|
|
};
|
|
|
|
int clen = strlen(str);
|
|
int len = 0;
|
|
for (const char *ptr = str;
|
|
*ptr!=0&&len<clen;
|
|
len++, ptr+=UTFLEN((unsigned char)*ptr)) ;
|
|
return len;
|
|
}
|
|
#pragma GCC diagnostic pop
|
|
|
|
std::string CopyString(const std::string& str)
|
|
{
|
|
std::string result;
|
|
result += str;
|
|
return result;
|
|
}
|
|
|
|
std::string CopyString(const char* str)
|
|
{
|
|
std::string result(str);
|
|
return result;
|
|
}
|
|
|
|
}
|