First commit.
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
#include "pch.h"
|
||||
#include "HtmlHelper.hpp"
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
|
||||
// non-localizable. RFC 7231 Date Format
|
||||
;
|
||||
static const char*INVARIANT_WEEK_DAYS[] =
|
||||
{ "Sun","Mon", "Tue", "Wed","Thu", "Fri","Sat"};
|
||||
// non-localizable. RFC 7231 Date Format
|
||||
static const char*INVARIANT_MONTHS[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep","Oct","Nov", "Dec"};
|
||||
// non-localizable. RFC 7231 Date Format
|
||||
static const char*FORMAT = "%s, %02d %s %04d %02d:%02d:%02d GMT";
|
||||
|
||||
std::string HtmlHelper::timeToHttpDate()
|
||||
{
|
||||
return timeToHttpDate(time(nullptr));
|
||||
}
|
||||
|
||||
std::string HtmlHelper::timeToHttpDate(time_t time)
|
||||
{
|
||||
// RFC 7231, IMF-fixdate.
|
||||
|
||||
struct tm gmTm;
|
||||
|
||||
if (gmtime_r(&time,&gmTm) == nullptr)
|
||||
{
|
||||
return "Mon, 01 Jan 1970 00:00:00 GMT";
|
||||
}
|
||||
char szBuffer[sizeof("Mon, 01 Jan 1970 00:00:00 GMT+")];
|
||||
snprintf(szBuffer,sizeof(szBuffer), FORMAT,
|
||||
INVARIANT_MONTHS[gmTm.tm_wday],
|
||||
gmTm.tm_mday,
|
||||
INVARIANT_MONTHS[gmTm.tm_mon],
|
||||
gmTm.tm_year,
|
||||
gmTm.tm_hour,
|
||||
gmTm.tm_min,
|
||||
gmTm.tm_sec);
|
||||
return szBuffer;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int hexN(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9') return c-'0';
|
||||
if (c >= 'a' && c <= 'f') return 10+c-'a';
|
||||
if (c >= 'A' && c <= 'F') return 10+c-'A';
|
||||
throw std::invalid_argument("Malformed URL.");
|
||||
}
|
||||
static char hexChar(char c1, char c2)
|
||||
{
|
||||
return (char)((hexN(c1) << 4) + hexN(c2));
|
||||
}
|
||||
|
||||
class SafeCharacterMap {
|
||||
bool safeCharacter[256];
|
||||
public:
|
||||
SafeCharacterMap()
|
||||
{
|
||||
for (int i = 0; i < 0x20; ++i) {
|
||||
safeCharacter[i] = false;
|
||||
}
|
||||
for (int i = 0x20; i < 0x80; ++i) {
|
||||
safeCharacter[i] = true;
|
||||
}
|
||||
for (int i = 0x80; i < 256; ++i)
|
||||
{
|
||||
safeCharacter[i] = false;
|
||||
}
|
||||
const char *unsafeCharacters = ":/+?=#%@ ";
|
||||
for (const char*p = unsafeCharacters; *p != 0; ++p)
|
||||
{
|
||||
safeCharacter[(uint8_t)*p] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool isSafeCharacter(char c) { return safeCharacter[(uint8_t)c];}
|
||||
} g_safeCharacterMap;
|
||||
|
||||
|
||||
std::string HtmlHelper::encode_url_segment(const char*pStart, const char*pEnd, bool isQuerySegment )
|
||||
{
|
||||
std::stringstream s;
|
||||
encode_url_segment(s,pStart,pEnd,isQuerySegment);
|
||||
return s.str();
|
||||
}
|
||||
|
||||
static char hexChars[] = "0123456789ABCDEF";
|
||||
|
||||
void HtmlHelper::encode_url_segment(std::ostream&os, const char*pStart, const char *pEnd, bool isQuerySegment)
|
||||
{
|
||||
while (pStart != pEnd)
|
||||
{
|
||||
char c = *pStart++;
|
||||
if (g_safeCharacterMap.isSafeCharacter(c))
|
||||
{
|
||||
os << c;
|
||||
} else if (c == ' ' && isQuerySegment)
|
||||
{
|
||||
os << '+';
|
||||
|
||||
os << c;
|
||||
} else {
|
||||
os << '%' << hexChars[(c >> 4) & 0x0f] << hexChars[c & 0x0F];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::string HtmlHelper::decode_url_segment(const char*pStart, const char*pEnd, bool isQuery)
|
||||
{
|
||||
std::stringstream s;
|
||||
auto p = pStart;
|
||||
while (p != pEnd)
|
||||
{
|
||||
char c = *p;
|
||||
++p;
|
||||
if (c == '+')
|
||||
{
|
||||
s << ' ';
|
||||
} else if (c != '%')
|
||||
{
|
||||
s << c;
|
||||
} else {
|
||||
if (pStart+2 < pEnd)
|
||||
{
|
||||
char c1 = *p; ++p;
|
||||
char c2 = *p; ++p;
|
||||
s << hexChar(c1,c2);
|
||||
} else {
|
||||
throw std::invalid_argument("Malformed URL.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return s.str();
|
||||
}
|
||||
|
||||
std::string HtmlHelper::decode_url_segment(const char*text, bool isQuery)
|
||||
{
|
||||
return decode_url_segment(text, text + strlen(text),isQuery);
|
||||
}
|
||||
|
||||
void HtmlHelper::utf32_to_utf8_stream(std::ostream &s, uint32_t uc)
|
||||
{
|
||||
if (uc < 0x80u)
|
||||
{
|
||||
s << (char)uc;
|
||||
} else if (uc < 0x800u) {
|
||||
s << (char)(0xC0 + (uc >> 6));
|
||||
s << (char)(0x80 + (uc & 0x3F));
|
||||
|
||||
} else if (uc < 0x10000u) {
|
||||
s << (char)(0xE0 + (uc >> 12));
|
||||
s << (char)(0x80 + ((uc >> 6) & 0x3F));
|
||||
s << (char)(0x80 + (uc & 0x3F));
|
||||
} else if (uc < 0x0110000) {
|
||||
s << (char)(0xF0 + (uc >> 18));
|
||||
s << (char)(0x80 + ((uc >> 12) & 0x3F));
|
||||
s << (char)(0x80 + ((uc >> 6) & 0x3F));
|
||||
s << (char)(0x80 + (uc & 0x3F));
|
||||
} else {
|
||||
throw std::range_error("Illegal UTF-32 character.");
|
||||
}
|
||||
}
|
||||
|
||||
const std::string ESPECIALS = "()<>@,;:\"/[]?.=";
|
||||
|
||||
#define MAX_FILENAME_LENGTH 96
|
||||
#define MAX_SEGMENT_LENGTH 74 // 75 per RFC2047.2. But leave space for a ';' to allow easier breaking of lines.
|
||||
|
||||
std::string HtmlHelper::Rfc5987EncodeFileName(const std::string&name)
|
||||
{
|
||||
// Encode all characters. Let the browser handle safe-ifying the actual name, since that's os dependent.
|
||||
std::stringstream s;
|
||||
std::string prefix = "UTF-8''";
|
||||
std::string postfix = "";
|
||||
s << prefix;
|
||||
for (char c: name)
|
||||
{
|
||||
uint8_t uc = (uint8_t)c;
|
||||
if (uc < 0x20 || uc >= 0x80 || ESPECIALS.find(c) != std::string::npos)
|
||||
{
|
||||
s << '%' << hexChars[uc >> 4] << hexChars[uc & 0x0F];
|
||||
} else {
|
||||
s << c;
|
||||
}
|
||||
}
|
||||
s << postfix;
|
||||
return s.str();
|
||||
}
|
||||
|
||||
|
||||
#define MAX_FILE_NAME_LENGHT 96
|
||||
|
||||
const std::string SF_SPECIALS = " <>@;:\"\'/[]?=";
|
||||
|
||||
std::string HtmlHelper::SafeFileName(const std::string name)
|
||||
{
|
||||
std::stringstream s;
|
||||
for (char c : name)
|
||||
{
|
||||
uint8_t uc = (uint8_t)c;
|
||||
if (uc < 0x20 || uc >= 0x80 || SF_SPECIALS.find(c) != std::string::npos)
|
||||
{
|
||||
s << '_';
|
||||
}
|
||||
else
|
||||
{
|
||||
s << c;
|
||||
}
|
||||
}
|
||||
return s.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user