int inet6_pton(const char* src, std::uint8_t* dst) {
if (src == nullptr) {
return 0;
}
constexpr char xdigits_l[] = "0123456789abcdef";
constexpr char xdigits_u[] = "0123456789ABCDEF";
const char* xdigits = nullptr;
const char* curtok = nullptr;
constexpr int NS_IN6ADDRSZ = 16;
constexpr int NS_INT16SZ = 2;
std::uint8_t tmp[NS_IN6ADDRSZ] = { 0 };
std::uint8_t* tp = tmp;
std::uint8_t* endp = nullptr;
std::uint8_t* colonp = nullptr;
endp = tp + NS_IN6ADDRSZ;
/* Leading :: requires some special handling. */
if (*src == ':') {
if (*++src != ':') {
return 0;
}
}
int seen_xdigits = 0;
std::size_t val = 0;
char ch = 0;
while ((ch = *src++) != '\0') {
const char* pch = nullptr;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) {
pch = strchr((xdigits = xdigits_u), ch);
}
if (pch != NULL) {
val <<= 4;
val |= (pch - xdigits);
if (++seen_xdigits > 4) {
return 0;
}
continue;
}
if (ch == ':') {
curtok = src;
if (!seen_xdigits) {
if (colonp != nullptr) {
return 0;
}
colonp = tp;
continue;
}
else if (*src == 0) {
return 0;
}
if (tp + NS_INT16SZ > endp) {
return 0;
}
*tp++ = (u_char)(val >> 8) & 0xff; //放在高位上
*tp++ = (u_char)val & 0xff; //放在低位上
seen_xdigits = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + 4) <= endp)) {
std::size_t value = 0;
//自己實現
if (inet4_pton(curtok, value)) {
unsigned char* buf = (unsigned char*)&value;
memcpy(tp, buf, 4);
tp += 4;
seen_xdigits = 0;
break; /*%< '\\' was seen by inet_pton4(). */
}
}
return 0;
}
if (seen_xdigits) {
if (tp + NS_INT16SZ > endp) {
return 0;
}
*tp++ = (u_char)(val >> 8) & 0xff;
*tp++ = (u_char)val & 0xff;
}
if (colonp != NULL) {
const int n = tp - colonp;
if (tp == endp) {
return 0;
}
for (int i = 1; i <= n; i++) {
endp[-i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp) {
return 0;
}
memcpy(dst, tmp, NS_IN6ADDRSZ);
return 1;
}
void inet6_ntop(const u_char* src, std::string& dst) {
constexpr int NS_IN6ADDRSZ = 16;
constexpr int NS_INT16SZ = 2;
char tmp[100] = { 0 };
char* tp = nullptr;
struct { int base, len; } best, cur;
std::size_t words[NS_IN6ADDRSZ / NS_INT16SZ] = { 0 };
memset(words, '\0', sizeof words);
for (int i = 0; i < NS_IN6ADDRSZ; i += 2) {
words[i / 2] = (src[i] << 8) | src[i + 1];
}
best.base = -1;
cur.base = -1;
best.len = 0;
cur.len = 0;
for (int i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
if (words[i] == 0) {
if (cur.base == -1) {
cur.base = i, cur.len = 1;
}
else {
cur.len++;
}
}
else {
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len) {
best = cur;
}
cur.base = -1;
}
}
}
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len) {
best = cur;
}
}
if (best.base != -1 && best.len < 2) {
best.base = -1;
}
/*
* Format the result.
*/
tp = tmp;
for (int i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
/* Are we inside the best run of 0x00's? */
if (best.base != -1 && i >= best.base &&
i < (best.base + best.len)) {
if (i == best.base) {
*tp++ = ':';
}
continue;
}
/* Are we following an initial run of 0x00s or any real hex? */
if (i != 0) {
*tp++ = ':';
}
/* Is this address an encapsulated IPv4? */
if (i == 6 && best.base == 0 &&
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
std::string temp;
temp.resize(20);
memcpy(&temp[0], (char*)src + 12,4);
std::size_t value = 0;
std::size_t* ptr = (std::size_t*)temp.data();
value = *ptr;
inet4_ntop(value, temp);
int len = strlen(temp.c_str());
memcpy(tp, temp.c_str(),len);
tp += len;
break;
}
std::stringstream sstream;
sstream << std::hex << words[i];
int len = strlen(sstream.str().c_str());
memcpy(tp, sstream.str().c_str(), len);
tp +=len;
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) {
*tp++ = ':';
}
*tp++ = '\0';
int len = strlen(tmp);
dst.resize(len);
memcpy(&dst[0], tmp, len);
}
int main(){
//std::string str = "3FFE:2900:D005:0:2AA:FF:FE28:9C5A";
//std::string str = "ffee:198:603:0:396e:4789:8e99:890f";
//std::string str = "0:0:0:0:0:ffff:192.1.56.10";
std::string str = "2a01:198:603:0::";
std::uint8_t data[16] = { 0 };
wheel::unit::inet6_pton(str.c_str(), data);
std::string sss;
net6_ntop(data, sss);
}