00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "Qt.h"
00024 #include "Uri.h"
00025 #include "Imports.cpp"
00026
00028 Uri::Uri()
00029 : d (new PrivateData)
00030 {
00031 }
00032
00034
00039 Uri::Uri (const Uri &other)
00040 : d (other.d)
00041 {
00042 }
00043
00045
00049 Uri & Uri::operator= (const Uri &other)
00050 {
00051 d = other.d;
00052 return *this;
00053 }
00054
00056
00062 QByteArray Uri::authority() const
00063 {
00064 QByteArray res;
00065 if (!d->userInfo.isEmpty())
00066 res += d->userInfo + '@';
00067 res += d->host;
00068 if (!d->port.isEmpty())
00069 res += ':' + d->port;
00070 return res;
00071 }
00072
00074 QByteArray Uri::query() const
00075 {
00076 QByteArray query (d->query);
00077 bool decoded = doDecode (query, true);
00078 Q_ASSERT (decoded);
00079 return query;
00080 }
00081
00083
00094 QByteArray Uri::queryItemValue (const QByteArray &key) const
00095 {
00096 foreach (const QueryItem item, queryItems()) {
00097 if (item.first == key)
00098 return item.second;
00099 }
00100 return QByteArray();
00101 }
00102
00104
00109 Uri::QueryItemList Uri::queryItems() const
00110 {
00111 if (d->query.isEmpty())
00112 return QueryItemList();
00113
00114 QueryItemList list;
00115 QList <QByteArray> items = d->query.split ('&');
00116 foreach (QByteArray item, items) {
00117 QList <QByteArray> subitems = item.split ('=');
00118 QByteArray key = subitems.value (0);
00119 QByteArray value = subitems.value (1);
00120 bool decoded = doDecode (key, true);
00121 Q_ASSERT (decoded);
00122 decoded = doDecode (value, true);
00123 Q_ASSERT (decoded);
00124 list += QueryItem (key, value);
00125 }
00126 return list;
00127 }
00128
00130
00138 QByteArray Uri::toQByteArray (Fields fields, bool encode) const
00139 {
00140 QByteArray res;
00141
00142 if (!d->scheme.isNull() && fields & Scheme)
00143 res += d->scheme + ':';
00144
00145 if (!d->host.isNull() && fields & Authority) {
00146 res += "//";
00147 if (!d->userInfo.isNull() && fields & UserInfo)
00148 res += doEncode (d->userInfo, encode, UserInfoEncodeExcludeChars)
00149 += '@';
00150 if (fields & Host)
00151 res += doEncode (d->host, encode, HostEncodeExcludeChars);
00152 if (!d->port.isNull() && fields & Port)
00153 res += ':' + d->port;
00154 }
00155 if (fields & Path)
00156 res += doEncode (d->path, encode, PathEncodeExcludeChars);
00157
00158 if (!d->query.isNull() && fields & Query)
00159 if (encode)
00160 res += '?' + d->query;
00161 else {
00162 QByteArray query = d->query;
00163 bool decoded = doDecode (query, true);
00164 Q_ASSERT (decoded);
00165 res += '?' + query;
00166 }
00167
00168 if (!d->fragment.isNull() && fields & Fragment)
00169 res += '#' + doEncode (d->fragment, encode, FragmentEncodeExcludeChars);
00170
00171 return res;
00172 }
00173
00175
00185 QByteArray Uri::doEncode (const QByteArray &bytes, bool encode,
00186 const QByteArray &charsToExclude)
00187 {
00188 if (encode) {
00189 QByteArray res;
00190
00191 res.reserve (bytes.length() * 3);
00192 foreach (char ch, bytes)
00193 if (shouldEncode (ch, charsToExclude))
00194 res += quoted (ch);
00195 else
00196 res += ch;
00197 return res;
00198 } else
00199 return bytes;
00200 }
00201
00203
00212 bool Uri::shouldEncode (char ch, const QByteArray &charsToExclude)
00213 {
00214 if (ch >= 'a' && ch <= 'z'
00215 || ch >= 'A' && ch <= 'Z'
00216 || ch >= '0' && ch <= '9'
00217 || ch == '-'
00218 || ch == '.'
00219 || ch == '_'
00220 || ch == '~'
00221 || charsToExclude.indexOf(ch) != -1)
00222 return false;
00223 else
00224 return true;
00225 }
00226
00228
00233 char Uri::hex (char ch)
00234 {
00235 static char hexmap[] = "0123456789ABCDEF";
00236 return hexmap [ch & 0x0F];
00237 }
00238
00240
00246 QByteArray Uri::quoted (char ch)
00247 {
00248 return QByteArray ("%") + hex (ch >> 4) + hex (ch);
00249 }
00250
00252
00262 QByteArray Uri::unencoded (Fields fields) const
00263 {
00264 return toQByteArray (fields, false);
00265 }
00266
00268
00299 QByteArray Uri::encoded (Fields fields) const
00300 {
00301 return toQByteArray (fields, true);
00302 }
00303
00324 bool Uri::parse (const QByteArray &bytes, bool decode)
00325 {
00326 QRegExp re ("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?",
00327 Qt::CaseSensitive, QRegExp::RegExp2);
00328 if (re.indexIn (QString::fromLatin1 (bytes)) > -1) {
00329 if (!re.cap (1).isEmpty()) {
00330 d->scheme = re.cap (2).toLatin1();
00331 if (!doDecode (d->scheme, decode))
00332 return false;
00333 }
00334 if (!re.cap (3).isEmpty()) {
00335 if (!parseAuthority (re.cap (4).toLatin1(), decode))
00336 return false;
00337 }
00338 if (!re.cap (5).isEmpty()) {
00339 d->path = re.cap (5).toLatin1();
00340 if (!doDecode (d->path, decode))
00341 return false;
00342 }
00343 if (!re.cap (6).isEmpty()) {
00344 d->query = re.cap (7).toLatin1();
00345
00346
00347 QByteArray query = d->query;
00348 if (!doDecode (query, decode))
00349 return false;
00350 ensureNotNull (d->query);
00351 }
00352 if (!re.cap (8).isEmpty()) {
00353 d->fragment = re.cap (9).toLatin1();
00354 if (!doDecode (d->fragment, decode))
00355 return false;
00356 }
00357 return true;
00358 } else
00359 return false;
00360 }
00361
00363
00381 bool Uri::doDecode (QByteArray &bytes, bool decode)
00382 {
00383 if (decode) {
00384 QByteArray res;
00385
00386 res.reserve (bytes.length());
00387 const char *pos = bytes.constData();
00388 const char *end = bytes.constData() + bytes.length();
00389 for (; pos != end; ++pos) {
00390 if (*pos != '%')
00391 res += *pos;
00392 else if (pos + 2 < end) {
00393 char hex1 = *++pos;
00394 char hex2 = *++pos;
00395 if (fromHex (hex1) && fromHex (hex2))
00396 res += unquoted (hex1, hex2);
00397 else
00398 return false;
00399 } else
00400 return false;
00401 }
00402 bytes = res;
00403 }
00404 ensureNotNull (bytes);
00405 return true;
00406 }
00407
00409
00418 bool Uri::fromHex (char &hex)
00419 {
00420 if (hex >= 'a' && hex <= 'f')
00421 hex -= 'a' - 10;
00422 else if (hex >= 'A' && hex <= 'F')
00423 hex -= 'A' - 10;
00424 else if (hex >= '0' && hex <= '9')
00425 hex -= '0';
00426 else
00427 return false;
00428 return true;
00429 }
00430
00432
00438 char Uri::unquoted (char hex1, char hex2)
00439 {
00440 return hex1 << 4 | hex2;
00441 }
00442
00444
00453 void Uri::setAuthority (const QByteArray &authority)
00454 {
00455 Uri tempUri = *this;
00456 if (tempUri.parseAuthority (authority, false))
00457 *this = tempUri;
00458 else
00459 Q_ASSERT (false);
00460 }
00461
00463
00472 void Uri::setAuthority (const QByteArray &userInfo,
00473 const QByteArray &host,
00474 const QByteArray &port)
00475 {
00476 Q_ASSERT (!host.isEmpty());
00477 d->userInfo = userInfo;
00478 d->host = host;
00479 d->port = port;
00480 }
00481
00483
00491 bool Uri::parseAuthority (const QByteArray &authority, bool decode)
00492 {
00493 int userInfoEnd = authority.indexOf ('@');
00494 if (userInfoEnd >= 0) {
00495 d->userInfo = authority.left (userInfoEnd++);
00496 if (!doDecode (d->userInfo, decode))
00497 return false;
00498 } else
00499 userInfoEnd = 0;
00500 int hostEnd = authority.indexOf (':', userInfoEnd);
00501 if (hostEnd >= 0) {
00502 d->port = authority.mid (hostEnd +1);
00503 if (!doDecode (d->port, decode))
00504 return false;
00505 } else
00506 hostEnd = authority.length();
00507
00508 d->host = authority.mid (userInfoEnd, hostEnd - userInfoEnd);
00509 if (!doDecode (d->host, decode))
00510 return false;
00511
00512
00513 if (d->host.isEmpty()
00514 && (!d->port.isEmpty() || !d->userInfo.isEmpty()))
00515 return false;
00516 else
00517 return true;
00518 }
00519
00521 void Uri::setQuery (const QByteArray &query)
00522 {
00523 d->query = doEncode (query, true, QueryEncodeExcludeChars);
00524 }
00525
00527
00536 void Uri::ensureNotNull (QByteArray &bytes)
00537 {
00538 if (bytes.isNull())
00539 bytes = QByteArray ("");
00540 }
00541
00543
00547 void Uri::appendQuery (const QByteArray &bytes)
00548 {
00549 d->query += doEncode (bytes, true, QueryEncodeExcludeChars);
00550 }
00551
00553
00565 void Uri::appendQueryItem (const QByteArray &key, const QByteArray &value)
00566 {
00567 QByteArray query = d->query;
00568 if (!query.isEmpty())
00569 query += '&';
00570 query += doEncode (key, true, QueryItemEncodeExcludeChars);
00571 if (!value.isEmpty())
00572 query += '=' + doEncode (value, true, QueryItemEncodeExcludeChars);
00573 d->query = query;
00574 }
00575
00579 void Uri::appendQueryItem (const QueryItem &item)
00580 {
00581 appendQueryItem (item.first, item.second);
00582 }
00583
00585
00589 void Uri::appendQueryItems (const QueryItemList &itemList)
00590 {
00591 foreach (QueryItem item, itemList)
00592 appendQueryItem (item);
00593 }
00594
00596
00601 bool Uri::operator== (const Uri &other) const
00602 {
00603 return unencoded() == other.unencoded();
00604 }
00605
00607
00612 bool Uri::operator!= (const Uri &other) const
00613 {
00614 return !(*this == other);
00615 }
00616
00618
00624 Uri Uri::fromUnencoded (const QByteArray &bytes)
00625 {
00626 Uri temp;
00627 if (temp.parse (bytes, false))
00628 return temp;
00629 else
00630 return Uri();
00631 }
00632
00634
00640 Uri Uri::fromEncoded (const QByteArray &bytes)
00641 {
00642 Uri temp;
00643 if (temp.parse (bytes, true))
00644 return temp;
00645 else
00646 return Uri();
00647 }
00648
00649 uint Utils::qHash (const Uri &uri)
00650 {
00651 return qHash (uri.unencoded());
00652 }
00653
00654 const QByteArray Uri::UserInfoEncodeExcludeChars ("!$&'()*+,;=:");
00655 const QByteArray Uri::HostEncodeExcludeChars ("[]:");
00656 const QByteArray Uri::PathEncodeExcludeChars ("!$&'()*+,;=:@/");
00657 const QByteArray Uri::QueryEncodeExcludeChars ("!$&'()*+,;=:@/?");
00658 const QByteArray Uri::QueryItemEncodeExcludeChars ("!$'()*+,;:@/?");
00659 const QByteArray Uri::FragmentEncodeExcludeChars ("!$&'()*+,;=:@/?");