C++でURLエンコード&デコード

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