248 lines
7.2 KiB
C++
248 lines
7.2 KiB
C++
#include "GbUtil.h"
|
|
#include "SafeBuf.h"
|
|
#include <string.h>
|
|
#include <sstream>
|
|
|
|
bool cdataEncode(SafeBuf *dstBuf, const char *src) {
|
|
return cdataEncode(dstBuf,src,strlen(src));
|
|
}
|
|
|
|
|
|
bool cdataEncode(SafeBuf *dstBuf, const char *src, size_t len) {
|
|
if(len<3)
|
|
return dstBuf->safeMemcpy(src,len);
|
|
if(!dstBuf->reserve(len))
|
|
return false;
|
|
const char *endptr = src+len;
|
|
const char *early_endptr = endptr-2;
|
|
for(const char *s = src; s<early_endptr; ) {
|
|
bool b;
|
|
if(s[0]!=']' || s[1]!=']' || s[2]!='>') {
|
|
b = dstBuf->pushChar(*s);
|
|
s += 1;
|
|
} else {
|
|
//turn ]]> into ]]>
|
|
b = dstBuf->pushChar(']') &&
|
|
dstBuf->pushChar(']') &&
|
|
dstBuf->pushChar('&') &&
|
|
dstBuf->pushChar('g') &&
|
|
dstBuf->pushChar('t') &&
|
|
dstBuf->pushChar(';');
|
|
s += 3;
|
|
}
|
|
if(!b) return false;
|
|
}
|
|
//handle 2-byte tail
|
|
for(const char *s=early_endptr; s<endptr; s++)
|
|
if(!dstBuf->pushChar(*s))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool urlEncode(SafeBuf *dstBuf, const char *src) {
|
|
return urlEncode(dstBuf, src, strlen(src), false, false);
|
|
}
|
|
|
|
|
|
// non-ascii (<32, >127): requires encoding
|
|
// space, ampersand, quote, plus, percent, hash, less, greater, question, colon, slash: requires encoding.
|
|
// rest: no encoding required
|
|
static const bool s_charRequiresUrlEncoding[256] = {
|
|
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
|
true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ,
|
|
true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ,
|
|
true , false, true , true , false, true , true , false, false, false, false, true , false, false, false, true ,
|
|
false, false, false, false, false, false, false, false, false, false, true , false, true , false, true , true ,
|
|
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
|
|
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
|
|
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
|
|
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true ,
|
|
true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ,
|
|
true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ,
|
|
true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ,
|
|
true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ,
|
|
true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ,
|
|
true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ,
|
|
true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ,
|
|
true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true
|
|
};
|
|
|
|
//s is a url, make it safe for printing to html
|
|
bool urlEncode(SafeBuf *dstBuf,
|
|
const char *src, size_t slen,
|
|
bool requestPath,
|
|
bool encodeApostrophes)
|
|
{
|
|
const char *send = src + slen;
|
|
for(const char *s=src ; s < send ; s++ ) {
|
|
if(*s == '\0' && requestPath) {
|
|
dstBuf->pushChar(*s);
|
|
continue;
|
|
}
|
|
if(*s == '\'' && encodeApostrophes) {
|
|
dstBuf->safeMemcpy("%27",3);
|
|
continue;
|
|
}
|
|
|
|
// skip if no encoding required
|
|
if(!s_charRequiresUrlEncoding[(unsigned char)*s]) {
|
|
dstBuf->pushChar(*s);
|
|
continue;
|
|
}
|
|
// special case for question-mark
|
|
if(*s == '?' && requestPath) {
|
|
dstBuf->pushChar(*s);
|
|
continue;
|
|
}
|
|
|
|
// space to +
|
|
if(*s == ' ') {
|
|
dstBuf->pushChar('+');
|
|
continue;
|
|
}
|
|
|
|
dstBuf->pushChar('%');
|
|
unsigned char v0 = ((unsigned char)*s)/16 ;
|
|
unsigned char v1 = ((unsigned char)*s) & 0x0f ;
|
|
dstBuf->pushChar("0123456789ABCDEF"[v0]);
|
|
dstBuf->pushChar("0123456789ABCDEF"[v1]);
|
|
}
|
|
dstBuf->nullTerm();
|
|
return true; //todo: uhm... aren't we supposed to return success/failure?
|
|
}
|
|
|
|
|
|
|
|
bool printTimeAgo(SafeBuf *sb, time_t ago, time_t now, bool shorthand) {
|
|
if(! sb->reserve(200))
|
|
return false;
|
|
|
|
if(ago<0)
|
|
ago = 0;
|
|
int secs = (int)((ago)/1);
|
|
int mins = (int)((ago)/60);
|
|
int hrs = (int)((ago)/3600);
|
|
int days = (int)((ago)/(3600*24));
|
|
|
|
bool printed = true;
|
|
// print the time ago
|
|
if(shorthand) {
|
|
if(mins == 0)
|
|
sb->safePrintf("%d secs ago",secs);
|
|
else if(mins == 1)
|
|
sb->safePrintf("%d min ago",mins);
|
|
else if (mins < 60)
|
|
sb->safePrintf("%d mins ago",mins);
|
|
else if(hrs == 1)
|
|
sb->safePrintf("%d hr ago",hrs);
|
|
else if(hrs < 24)
|
|
sb->safePrintf("%d hrs ago",hrs);
|
|
else if(days == 1)
|
|
sb->safePrintf("%d day ago",days);
|
|
else if (days < 7)
|
|
sb->safePrintf("%d days ago",days);
|
|
else
|
|
printed = false;
|
|
} else {
|
|
if(mins == 0)
|
|
sb->safePrintf("%d seconds ago",secs);
|
|
else if(mins == 1)
|
|
sb->safePrintf("%d minute ago",mins);
|
|
else if (mins < 60)
|
|
sb->safePrintf("%d minutes ago",mins);
|
|
else if(hrs == 1)
|
|
sb->safePrintf("%d hour ago",hrs);
|
|
else if(hrs < 24)
|
|
sb->safePrintf("%d hours ago",hrs);
|
|
else if(days == 1)
|
|
sb->safePrintf("%d day ago",days);
|
|
else if(days < 7)
|
|
sb->safePrintf("%d days ago",days);
|
|
else
|
|
printed = false;
|
|
}
|
|
|
|
if(!printed && ago > 0) {
|
|
time_t ts = now - ago;
|
|
struct tm tm_buf;
|
|
struct tm *timeStruct = localtime_r(&ts,&tm_buf);
|
|
char tmp[100];
|
|
strftime(tmp,100,"%B %d %Y",timeStruct);
|
|
sb->safeStrcpy(tmp);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
std::vector<std::string> split(const std::string &str, char delimiter) {
|
|
std::vector<std::string> elements;
|
|
std::stringstream ss(str);
|
|
std::string element;
|
|
while (std::getline(ss, element, delimiter)) {
|
|
elements.push_back(element);
|
|
}
|
|
return elements;
|
|
}
|
|
|
|
std::vector<std::string> split(const std::string &str, const std::string &delimiter) {
|
|
std::vector<std::string> elements;
|
|
|
|
size_t start = 0;
|
|
size_t pos = 0;
|
|
do {
|
|
pos = str.find(delimiter, start);
|
|
elements.push_back(str.substr(start, pos - start));
|
|
start = pos + delimiter.length();
|
|
} while (pos != std::string::npos);
|
|
|
|
return elements;
|
|
}
|
|
|
|
bool starts_with(const char *haystack, const char *needle) {
|
|
size_t haystackLen = strlen(haystack);
|
|
size_t needleLen = strlen(needle);
|
|
if (haystackLen < needleLen) {
|
|
return false;
|
|
}
|
|
|
|
return (memcmp(haystack, needle, needleLen) == 0);
|
|
}
|
|
|
|
|
|
uint64_t getCurrentTimeNanoseconds() {
|
|
struct timespec ts_now;
|
|
clock_gettime(CLOCK_REALTIME,&ts_now);
|
|
return ts_now.tv_sec * 1000000000 + ts_now.tv_nsec;
|
|
}
|
|
|
|
const char *formatTime(time_t when, char buf[32]) {
|
|
struct tm t;
|
|
gmtime_r(&when, &t);
|
|
strftime(buf,32,"%Y-%m-%dT%H:%M:%SZ",&t);
|
|
return buf;
|
|
}
|
|
|
|
const char *formatTimeMs(int64_t when, char buf[32]) {
|
|
time_t when_secs = when/1000;
|
|
struct tm t;
|
|
gmtime_r(&when_secs, &t);
|
|
strftime(buf,32,"%Y-%m-%dT%H:%M:%S",&t);
|
|
sprintf(strchr(buf,'\0'),".%03dZ",(int)(when%1000));
|
|
return buf;
|
|
}
|
|
|
|
|
|
bool has_space(const char *start, const char *end) {
|
|
//Simple test only
|
|
for(const char *p=start; p<end; p++)
|
|
if(*p==' ' ||
|
|
*p=='\t' ||
|
|
*p=='\r' ||
|
|
*p=='\n')
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//(inline): bool has_char(const char *start, const char *end, char c);
|