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; }