~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to src/corelib/io/qipaddress.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Intel Corporation
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the QtCore module of the Qt Toolkit.
 
7
**
 
8
** $QT_BEGIN_LICENSE:LGPL$
 
9
** Commercial License Usage
 
10
** Licensees holding valid commercial Qt licenses may use this file in
 
11
** accordance with the commercial license agreement provided with the
 
12
** Software or, alternatively, in accordance with the terms contained in
 
13
** a written agreement between you and Digia.  For licensing terms and
 
14
** conditions see http://qt.digia.com/licensing.  For further information
 
15
** use the contact form at http://qt.digia.com/contact-us.
 
16
**
 
17
** GNU Lesser General Public License Usage
 
18
** Alternatively, this file may be used under the terms of the GNU Lesser
 
19
** General Public License version 2.1 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL included in the
 
21
** packaging of this file.  Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 2.1 requirements
 
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
24
**
 
25
** In addition, as a special exception, Digia gives you certain additional
 
26
** rights.  These rights are described in the Digia Qt LGPL Exception
 
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
28
**
 
29
** GNU General Public License Usage
 
30
** Alternatively, this file may be used under the terms of the GNU
 
31
** General Public License version 3.0 as published by the Free Software
 
32
** Foundation and appearing in the file LICENSE.GPL included in the
 
33
** packaging of this file.  Please review the following information to
 
34
** ensure the GNU General Public License version 3.0 requirements will be
 
35
** met: http://www.gnu.org/copyleft/gpl.html.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include "qipaddress_p.h"
 
43
#include "private/qlocale_tools_p.h"
 
44
#include "qvarlengtharray.h"
 
45
 
 
46
QT_BEGIN_NAMESPACE
 
47
namespace QIPAddressUtils {
 
48
 
 
49
static QString number(quint8 val, int base = 10)
 
50
{
 
51
    QChar zero(0x30);
 
52
    return val ? qulltoa(val, base, zero) : zero;
 
53
}
 
54
 
 
55
typedef QVarLengthArray<char, 64> Buffer;
 
56
static bool checkedToAscii(Buffer &buffer, const QChar *begin, const QChar *end)
 
57
{
 
58
    const ushort *const ubegin = reinterpret_cast<const ushort *>(begin);
 
59
    const ushort *const uend = reinterpret_cast<const ushort *>(end);
 
60
    const ushort *src = ubegin;
 
61
 
 
62
    buffer.resize(uend - ubegin + 1);
 
63
    char *dst = buffer.data();
 
64
 
 
65
    while (src != uend) {
 
66
        if (*src >= 0x7f)
 
67
            return false;
 
68
        *dst++ = *src++;
 
69
    }
 
70
    *dst = '\0';
 
71
    return true;
 
72
}
 
73
 
 
74
static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptLeadingZero);
 
75
bool parseIp4(IPv4Address &address, const QChar *begin, const QChar *end)
 
76
{
 
77
    Q_ASSERT(begin != end);
 
78
    Buffer buffer;
 
79
    if (!checkedToAscii(buffer, begin, end))
 
80
        return false;
 
81
 
 
82
    const char *ptr = buffer.data();
 
83
    return parseIp4Internal(address, ptr, true);
 
84
}
 
85
 
 
86
static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptLeadingZero)
 
87
{
 
88
    address = 0;
 
89
    int dotCount = 0;
 
90
    while (dotCount < 4) {
 
91
        if (!acceptLeadingZero && *ptr == '0' &&
 
92
                ptr[1] != '.' && ptr[1] != '\0')
 
93
            return false;
 
94
 
 
95
        const char *endptr;
 
96
        bool ok;
 
97
        quint64 ll = qstrtoull(ptr, &endptr, 0, &ok);
 
98
        quint32 x = ll;
 
99
        if (!ok || endptr == ptr || ll != x)
 
100
            return false;
 
101
 
 
102
        if (*endptr == '.' || dotCount == 3) {
 
103
            if (x & ~0xff)
 
104
                return false;
 
105
            address <<= 8;
 
106
        } else if (dotCount == 2) {
 
107
            if (x & ~0xffff)
 
108
                return false;
 
109
            address <<= 16;
 
110
        } else if (dotCount == 1) {
 
111
            if (x & ~0xffffff)
 
112
                return false;
 
113
            address <<= 24;
 
114
        }
 
115
        address |= x;
 
116
 
 
117
        if (dotCount == 3 && *endptr != '\0')
 
118
            return false;
 
119
        else if (dotCount == 3 || *endptr == '\0')
 
120
            return true;
 
121
        ++dotCount;
 
122
        ptr = endptr + 1;
 
123
    }
 
124
    return false;
 
125
}
 
126
 
 
127
void toString(QString &appendTo, IPv4Address address)
 
128
{
 
129
    // reconstructing is easy
 
130
    // use the fast operator% that pre-calculates the size
 
131
    appendTo += number(address >> 24)
 
132
                % QLatin1Char('.')
 
133
                % number(address >> 16)
 
134
                % QLatin1Char('.')
 
135
                % number(address >> 8)
 
136
                % QLatin1Char('.')
 
137
                % number(address);
 
138
}
 
139
 
 
140
bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end)
 
141
{
 
142
    Q_ASSERT(begin != end);
 
143
    Buffer buffer;
 
144
    if (!checkedToAscii(buffer, begin, end))
 
145
        return false;
 
146
 
 
147
    const char *ptr = buffer.data();
 
148
 
 
149
    // count the colons
 
150
    int colonCount = 0;
 
151
    int dotCount = 0;
 
152
    while (*ptr) {
 
153
        if (*ptr == ':')
 
154
            ++colonCount;
 
155
        if (*ptr == '.')
 
156
            ++dotCount;
 
157
        ++ptr;
 
158
    }
 
159
    // IPv4-in-IPv6 addresses are stricter in what they accept
 
160
    if (dotCount != 0 && dotCount != 3)
 
161
        return false;
 
162
 
 
163
    memset(address, 0, sizeof address);
 
164
    if (colonCount == 2 && end - begin == 2) // "::"
 
165
        return true;
 
166
 
 
167
    // if there's a double colon ("::"), this is how many zeroes it means
 
168
    int zeroWordsToFill;
 
169
    ptr = buffer.data();
 
170
 
 
171
    // there are two cases where 8 colons are allowed: at the ends
 
172
    // so test that before the colon-count test
 
173
    if ((ptr[0] == ':' && ptr[1] == ':') ||
 
174
            (ptr[end - begin - 2] == ':' && ptr[end - begin - 1] == ':')) {
 
175
        zeroWordsToFill = 9 - colonCount;
 
176
    } else if (colonCount < 2 || colonCount > 7) {
 
177
        return false;
 
178
    } else {
 
179
        zeroWordsToFill = 8 - colonCount;
 
180
    }
 
181
    if (dotCount)
 
182
        --zeroWordsToFill;
 
183
 
 
184
    int pos = 0;
 
185
    while (pos < 15) {
 
186
        const char *endptr;
 
187
        bool ok;
 
188
        quint64 ll = qstrtoull(ptr, &endptr, 16, &ok);
 
189
        quint16 x = ll;
 
190
 
 
191
        if (ptr == endptr) {
 
192
            // empty field, we hope it's "::"
 
193
            if (zeroWordsToFill < 1)
 
194
                return false;
 
195
            if (pos == 0 || pos == colonCount * 2) {
 
196
                if (ptr[0] == '\0' || ptr[1] != ':')
 
197
                    return false;
 
198
                ++ptr;
 
199
            }
 
200
            pos += zeroWordsToFill * 2;
 
201
            zeroWordsToFill = 0;
 
202
            ++ptr;
 
203
            continue;
 
204
        }
 
205
        if (!ok || ll != x)
 
206
            return false;
 
207
 
 
208
        if (*endptr == '.') {
 
209
            // this could be an IPv4 address
 
210
            // it's only valid in the last element
 
211
            if (pos != 12)
 
212
                return false;
 
213
 
 
214
            IPv4Address ip4;
 
215
            if (!parseIp4Internal(ip4, ptr, false))
 
216
                return false;
 
217
 
 
218
            address[12] = ip4 >> 24;
 
219
            address[13] = ip4 >> 16;
 
220
            address[14] = ip4 >> 8;
 
221
            address[15] = ip4;
 
222
            return true;
 
223
        }
 
224
 
 
225
        address[pos++] = x >> 8;
 
226
        address[pos++] = x & 0xff;
 
227
 
 
228
        if (*endptr == '\0')
 
229
            break;
 
230
        if (*endptr != ':')
 
231
            return false;
 
232
        ptr = endptr + 1;
 
233
    }
 
234
    return pos == 16;
 
235
}
 
236
 
 
237
static inline QChar toHex(uchar c)
 
238
{
 
239
    return ushort(c > 9 ? c + 'a' - 0xA : c + '0');
 
240
}
 
241
 
 
242
void toString(QString &appendTo, IPv6Address address)
 
243
{
 
244
    // the longest IPv6 address possible is:
 
245
    //   "1111:2222:3333:4444:5555:6666:255.255.255.255"
 
246
    // however, this function never generates that. The longest it does
 
247
    // generate without an IPv4 address is:
 
248
    //   "1111:2222:3333:4444:5555:6666:7777:8888"
 
249
    // and the longest with an IPv4 address is:
 
250
    //   "::ffff:255.255.255.255"
 
251
    static const int Ip6AddressMaxLen = sizeof "1111:2222:3333:4444:5555:6666:7777:8888";
 
252
    static const int Ip6WithIp4AddressMaxLen = sizeof "::ffff:255.255.255.255";
 
253
 
 
254
    // check for the special cases
 
255
    const quint64 zeroes[] = { 0, 0 };
 
256
    bool embeddedIp4 = false;
 
257
 
 
258
    // we consider embedded IPv4 for:
 
259
    //  ::ffff:x.x.x.x
 
260
    //  ::x.x.x.y  except if the x are 0 too
 
261
    if (memcmp(address, zeroes, 10) == 0) {
 
262
        if (address[10] == 0xff && address[11] == 0xff) {
 
263
            embeddedIp4 = true;
 
264
        } else if (address[10] == 0 && address[11] == 0) {
 
265
            if (address[12] != 0 || address[13] != 0 || address[14] != 0) {
 
266
                embeddedIp4 = true;
 
267
            } else if (address[15] == 0) {
 
268
                appendTo.append(QLatin1String("::"));
 
269
                return;
 
270
            }
 
271
        }
 
272
    }
 
273
 
 
274
    // QString::reserve doesn't shrink, so it's fine to us
 
275
    appendTo.reserve(appendTo.size() +
 
276
                     (embeddedIp4 ? Ip6WithIp4AddressMaxLen : Ip6AddressMaxLen));
 
277
 
 
278
    // for finding where to place the "::"
 
279
    int zeroRunLength = 0; // in octets
 
280
    int zeroRunOffset = 0; // in octets
 
281
    for (int i = 0; i < 16; i += 2) {
 
282
        if (address[i] == 0 && address[i + 1] == 0) {
 
283
            // found a zero, scan forward to see how many more there are
 
284
            int j;
 
285
            for (j = i; j < 16; j += 2) {
 
286
                if (address[j] != 0 || address[j+1] != 0)
 
287
                    break;
 
288
            }
 
289
 
 
290
            if (j - i > zeroRunLength) {
 
291
                zeroRunLength = j - i;
 
292
                zeroRunOffset = i;
 
293
                i = j;
 
294
            }
 
295
        }
 
296
    }
 
297
 
 
298
    const QChar colon = ushort(':');
 
299
    if (zeroRunLength < 4)
 
300
        zeroRunOffset = -1;
 
301
    else if (zeroRunOffset == 0)
 
302
        appendTo.append(colon);
 
303
 
 
304
    for (int i = 0; i < 16; i += 2) {
 
305
        if (i == zeroRunOffset) {
 
306
            appendTo.append(colon);
 
307
            i += zeroRunLength - 2;
 
308
            continue;
 
309
        }
 
310
 
 
311
        if (i == 12 && embeddedIp4) {
 
312
            IPv4Address ip4 = address[12] << 24 |
 
313
                              address[13] << 16 |
 
314
                              address[14] << 8 |
 
315
                              address[15];
 
316
            toString(appendTo, ip4);
 
317
            return;
 
318
        }
 
319
 
 
320
        if (address[i]) {
 
321
            if (address[i] >> 4) {
 
322
                appendTo.append(toHex(address[i] >> 4));
 
323
                appendTo.append(toHex(address[i] & 0xf));
 
324
                appendTo.append(toHex(address[i + 1] >> 4));
 
325
                appendTo.append(toHex(address[i + 1] & 0xf));
 
326
            } else if (address[i] & 0xf) {
 
327
                appendTo.append(toHex(address[i] & 0xf));
 
328
                appendTo.append(toHex(address[i + 1] >> 4));
 
329
                appendTo.append(toHex(address[i + 1] & 0xf));
 
330
            }
 
331
        } else if (address[i + 1] >> 4) {
 
332
            appendTo.append(toHex(address[i + 1] >> 4));
 
333
            appendTo.append(toHex(address[i + 1] & 0xf));
 
334
        } else {
 
335
            appendTo.append(toHex(address[i + 1] & 0xf));
 
336
        }
 
337
 
 
338
        if (i != 14)
 
339
            appendTo.append(colon);
 
340
    }
 
341
}
 
342
 
 
343
}
 
344
QT_END_NAMESPACE