summaryrefslogtreecommitdiff
path: root/src/qcommon/IpToCountryResolver.c
blob: f2fd97e5f289beebc609ef871ff6a1cd8f9b0bdc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "IpToCountryResolver.h"
#include "q_shared.h"

void convertToCamelCase(char *str)
{
    int upper = 1;
    char *pos = str;
    while (*pos != '\0') {
        if (*pos != ' ') {
            if (upper) {
                (*pos) = toupper(*pos);
                upper = 0;
            }
            else
                (*pos) = tolower(*pos);
        } else {
            upper = 1;
        }
        pos++;
    }
}

IpToCountryInfo *FindCountryInfoUI(unsigned int ip, IpToCountryList *infoList)
{
    int abound = 0;
    int zbound = infoList->size-1;
    int tbound = 0;
    IpToCountryInfo *telement;

    if (infoList->size == 0)
        return NULL;

    while (abound <= zbound)
    {
        tbound = (abound+zbound)/2;
        telement = &infoList->infoArray[tbound];

        if (ip < telement->ipFrom)
            zbound = tbound-1;
        else if (ip > telement->ipTo)
            abound = tbound+1;
        else
            return telement;
    }
    return NULL;
}

IpToCountryInfo *FindCountryInfoB(unsigned int parts[4], unsigned int length, IpToCountryList *infoList)
{
    return FindCountryInfoUI(ipbyte_to_int(parts, length),infoList);
}

IpToCountryInfo *FindCountryInfoS(const char *ip_addr, IpToCountryList *infoList)
{
    return FindCountryInfoUI(ipstr_to_int(ip_addr),infoList);
}

unsigned int ipbyte_to_int(unsigned int parts[4], unsigned int length)
{
    unsigned int val = parts[length-1];

    switch (length) {

	case 1:				/* a -- 32 bits */
		break;

	case 2:				/* a.b -- 8.24 bits */
		if (val > 0xffffff)
			return (0);
		val |= parts[0] << 24;
		break;

	case 3:				/* a.b.c -- 8.8.16 bits */
		if (val > 0xffff)
			return (0);
		val |= (parts[0] << 24) | (parts[1] << 16);
		break;

	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
		if (val > 0xff)
			return (0);
		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
		break;
	}

	return val;
}

unsigned int ipstr_to_int(const char *cp_arg)
{
	register unsigned long val;
	register int base, n;
	register unsigned char c;
	register unsigned const char *cp = (unsigned const char *) cp_arg;
	unsigned int parts[4];
	register unsigned int *pp = parts;

	for (;;) {
		/*
		 * Collect number up to ``.''.
		 * Values are specified as for C:
		 * 0x=hex, 0=octal, other=decimal.
		 */
		val = 0; base = 10;
		if (*cp == '0') {
			if (*++cp == 'x' || *cp == 'X')
				base = 16, cp++;
			else
				base = 8;
		}
		while ((c = *cp) != '\0') {
			if (isascii(c) && isdigit(c)) {
				val = (val * base) + (c - '0');
				cp++;
				continue;
			}
			if (base == 16 && isascii(c) && isxdigit(c)) {
				val = (val << 4) +
					(c + 10 - (islower(c) ? 'a' : 'A'));
				cp++;
				continue;
			}
			break;
		}
		if (*cp == '.') {
			/*
			 * Internet format:
			 *	a.b.c.d
			 *	a.b.c	(with c treated as 16-bits)
			 *	a.b	(with b treated as 24 bits)
			 */
			if (pp >= parts + 3 || val > 0xff)
				return (0);
			*pp++ = val, cp++;
		} else {
		    *pp = val;
			break;
		}
	}
	/*
	 * Check for trailing characters.
	 */
	if (*cp && (!isascii(*cp) || !isspace(*cp)))
		return (0);
	/*
	 * Concoct the address according to
	 * the number of parts specified.
	 */
	n = pp - parts + 1;

    return ipbyte_to_int(parts,n);
}