bool is_safe_char(UCHAR c) { return isalnum(c) || c == '.' || c == '-' || c == '_' || c == '*'; }
char* encode_char_to_hex(char c, char* dist) {
dist[0] = '%';
dist[1] = "0123456789ABCDEF"[(c & 0xF0) >> 4];
dist[2] = "0123456789ABCDEF"[c & 0x0F];
return dist + 2;
}
unsigned url_encode(const char* c, char* dist) {
const char* head = dist;
for (; *c != '\0'; c++, dist++) {
if (is_safe_char(*c))* dist = *c;
else if (*c == ' ')* dist = '+';
else dist = encode_char_to_hex(*c, dist);
}
*dist = '\0';
return dist - head;
}
static const char table[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
char decode_hex_to_char(const char* c) {
// XXX: [0-9a-zA-Z]以外の全ての文字は、0として扱われる (e.g. "%@X" => 0)
return (table[static_cast<unsigned char>(c[1])] << 4) +
table[static_cast<unsigned char>(c[2])];
}
unsigned url_decode(const char* c, char* dist) {
const char* head = dist;
for (; *c != '\0'; c++, dist++) {
switch (*c) {
case '%': *dist = decode_hex_to_char(c); c += 2; break; // XXX: 末尾に'%'が来る不正な文字列が渡された場合の挙動は未定義(ex. "abc%")
case '+': *dist = ' '; break;
default: *dist = *c; break;
}
}
*dist = '\0';
return dist - head;
}