author | zautrix <zautrix> | 2004-06-26 19:01:18 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2004-06-26 19:01:18 (UTC) |
commit | b9aad1f15dc600e4dbe4c62d3fcced6363188ba3 (patch) (unidiff) | |
tree | 2c3d4004fb21c72cba65793859f9bcd8ffd3a49c /microkde/kurl.cpp | |
download | kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.zip kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.tar.gz kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.tar.bz2 |
Initial revision
-rw-r--r-- | microkde/kurl.cpp | 1942 |
1 files changed, 1942 insertions, 0 deletions
diff --git a/microkde/kurl.cpp b/microkde/kurl.cpp new file mode 100644 index 0000000..2574e25 --- a/dev/null +++ b/microkde/kurl.cpp | |||
@@ -0,0 +1,1942 @@ | |||
1 | /* | ||
2 | Copyright (C) 1999 Torben Weis <weis@kde.org> | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Library General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 2 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this library; see the file COPYING.LIB. If not, write to | ||
16 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
17 | Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include "kurl.h" | ||
21 | |||
22 | #ifndef KDE_QT_ONLY | ||
23 | #include <kdebug.h> | ||
24 | #include <kglobal.h> | ||
25 | //US#include <kidna.h> | ||
26 | #endif | ||
27 | |||
28 | #include <stdio.h> | ||
29 | #include <assert.h> | ||
30 | #include <ctype.h> | ||
31 | #include <stdlib.h> | ||
32 | #ifdef _WIN32_ | ||
33 | |||
34 | #else | ||
35 | #include <unistd.h> | ||
36 | #endif | ||
37 | #include <qurl.h> | ||
38 | #include <qdir.h> | ||
39 | #include <qstringlist.h> | ||
40 | #include <qregexp.h> | ||
41 | //US#include <qstylesheet.h> | ||
42 | #include <qmap.h> | ||
43 | #include <qtextcodec.h> | ||
44 | |||
45 | static const QString fileProt = "file"; | ||
46 | |||
47 | static QTextCodec * codecForHint( int encoding_hint /* not 0 ! */ ) | ||
48 | { | ||
49 | return QTextCodec::codecForMib( encoding_hint ); | ||
50 | } | ||
51 | |||
52 | static QString encode( const QString& segment, bool encode_slash, int encoding_hint ) | ||
53 | { | ||
54 | const char *encode_string; | ||
55 | if (encode_slash) | ||
56 | encode_string = "<>#@\"&%?={}|^~[]\'`\\:+/"; | ||
57 | else | ||
58 | encode_string = "<>#@\"&%?={}|^~[]\'`\\:+"; | ||
59 | |||
60 | QCString local; | ||
61 | if (encoding_hint==0) | ||
62 | local = segment.local8Bit(); | ||
63 | else | ||
64 | { | ||
65 | QTextCodec * textCodec = codecForHint( encoding_hint ); | ||
66 | if (!textCodec) | ||
67 | local = segment.local8Bit(); | ||
68 | else | ||
69 | local = textCodec->fromUnicode( segment ); | ||
70 | } | ||
71 | |||
72 | int old_length = local.length(); | ||
73 | |||
74 | if ( !old_length ) | ||
75 | return segment.isNull() ? QString::null : QString(""); // differenciate null and empty | ||
76 | |||
77 | // a worst case approximation | ||
78 | QChar *new_segment = new QChar[ old_length * 3 + 1 ]; | ||
79 | int new_length = 0; | ||
80 | |||
81 | for ( int i = 0; i < old_length; i++ ) | ||
82 | { | ||
83 | // 'unsave' and 'reserved' characters | ||
84 | // according to RFC 1738, | ||
85 | // 2.2. URL Character Encoding Issues (pp. 3-4) | ||
86 | // WABA: Added non-ascii | ||
87 | unsigned char character = local[i]; | ||
88 | if ( (character <= 32) || (character >= 127) || | ||
89 | strchr(encode_string, character) ) | ||
90 | { | ||
91 | new_segment[ new_length++ ] = '%'; | ||
92 | |||
93 | unsigned int c = character / 16; | ||
94 | c += (c > 9) ? ('A' - 10) : '0'; | ||
95 | new_segment[ new_length++ ] = c; | ||
96 | |||
97 | c = character % 16; | ||
98 | c += (c > 9) ? ('A' - 10) : '0'; | ||
99 | new_segment[ new_length++ ] = c; | ||
100 | |||
101 | } | ||
102 | else | ||
103 | new_segment[ new_length++ ] = local[i]; | ||
104 | } | ||
105 | |||
106 | QString result = QString(new_segment, new_length); | ||
107 | delete [] new_segment; | ||
108 | return result; | ||
109 | } | ||
110 | |||
111 | static QString encodeHost( const QString& segment, bool encode_slash, int encoding_hint ) | ||
112 | { | ||
113 | // Hostnames are encoded differently | ||
114 | // we use the IDNA transformation instead | ||
115 | |||
116 | // Note: when merging qt-addon, use QResolver::domainToAscii here | ||
117 | #ifndef KDE_QT_ONLY | ||
118 | Q_UNUSED( encode_slash ); | ||
119 | Q_UNUSED( encoding_hint ); | ||
120 | return KIDNA::toAscii(segment); | ||
121 | #else | ||
122 | return encode(segment, encode_slash, encoding_hint); | ||
123 | #endif | ||
124 | } | ||
125 | |||
126 | static int hex2int( unsigned int _char ) | ||
127 | { | ||
128 | if ( _char >= 'A' && _char <='F') | ||
129 | return _char - 'A' + 10; | ||
130 | if ( _char >= 'a' && _char <='f') | ||
131 | return _char - 'a' + 10; | ||
132 | if ( _char >= '0' && _char <='9') | ||
133 | return _char - '0'; | ||
134 | return -1; | ||
135 | } | ||
136 | |||
137 | // WABA: The result of lazy_encode isn't usable for a URL which | ||
138 | // needs to satisfies RFC requirements. However, the following | ||
139 | // operation will make it usable again: | ||
140 | // encode(decode(...)) | ||
141 | // | ||
142 | // As a result one can see that url.prettyURL() does not result in | ||
143 | // a RFC compliant URL but that the following sequence does: | ||
144 | // KURL(url.prettyURL()).url() | ||
145 | |||
146 | |||
147 | static QString lazy_encode( const QString& segment ) | ||
148 | { | ||
149 | int old_length = segment.length(); | ||
150 | |||
151 | if ( !old_length ) | ||
152 | return QString::null; | ||
153 | |||
154 | // a worst case approximation | ||
155 | QChar *new_segment = new QChar[ old_length * 3 + 1 ]; | ||
156 | int new_length = 0; | ||
157 | |||
158 | for ( int i = 0; i < old_length; i++ ) | ||
159 | { | ||
160 | unsigned int character = segment[i].unicode(); // Don't use latin1() | ||
161 | // It returns 0 for non-latin1 values | ||
162 | // Small set of really ambiguous chars | ||
163 | if ((character < 32) || // Low ASCII | ||
164 | ((character == '%') && // The escape character itself | ||
165 | (i+2 < old_length) && // But only if part of a valid escape sequence! | ||
166 | (hex2int(segment[i+1].unicode())!= -1) && | ||
167 | (hex2int(segment[i+2].unicode())!= -1)) || | ||
168 | (character == '?') || // Start of query delimiter | ||
169 | (character == '@') || // Username delimiter | ||
170 | (character == '#') || // Start of reference delimiter | ||
171 | ((character == 32) && (i+1 == old_length))) // A trailing space | ||
172 | { | ||
173 | new_segment[ new_length++ ] = '%'; | ||
174 | |||
175 | unsigned int c = character / 16; | ||
176 | c += (c > 9) ? ('A' - 10) : '0'; | ||
177 | new_segment[ new_length++ ] = c; | ||
178 | |||
179 | c = character % 16; | ||
180 | c += (c > 9) ? ('A' - 10) : '0'; | ||
181 | new_segment[ new_length++ ] = c; | ||
182 | } | ||
183 | else | ||
184 | new_segment[ new_length++ ] = segment[i]; | ||
185 | } | ||
186 | |||
187 | QString result = QString(new_segment, new_length); | ||
188 | delete [] new_segment; | ||
189 | return result; | ||
190 | } | ||
191 | |||
192 | static void decode( const QString& segment, QString &decoded, QString &encoded, int encoding_hint=0, bool updateDecoded = true ) | ||
193 | { | ||
194 | decoded = QString::null; | ||
195 | encoded = segment; | ||
196 | |||
197 | int old_length = segment.length(); | ||
198 | if ( !old_length ) | ||
199 | return; | ||
200 | |||
201 | QTextCodec *textCodec = 0; | ||
202 | if (encoding_hint) | ||
203 | textCodec = codecForHint( encoding_hint ); | ||
204 | |||
205 | if (!textCodec) | ||
206 | textCodec = QTextCodec::codecForLocale(); | ||
207 | |||
208 | QCString csegment = textCodec->fromUnicode(segment); | ||
209 | // Check if everything went ok | ||
210 | if (textCodec->toUnicode(csegment) != segment) | ||
211 | { | ||
212 | // Uh oh | ||
213 | textCodec = codecForHint( 106 ); // Fall back to utf-8 | ||
214 | csegment = textCodec->fromUnicode(segment); | ||
215 | } | ||
216 | old_length = csegment.length(); | ||
217 | |||
218 | int new_length = 0; | ||
219 | int new_length2 = 0; | ||
220 | |||
221 | // make a copy of the old one | ||
222 | char *new_segment = new char[ old_length + 1 ]; | ||
223 | QChar *new_usegment = new QChar[ old_length * 3 + 1 ]; | ||
224 | |||
225 | int i = 0; | ||
226 | while( i < old_length ) | ||
227 | { | ||
228 | bool bReencode = false; | ||
229 | unsigned char character = csegment[ i++ ]; | ||
230 | if ((character <= ' ') || (character > 127)) | ||
231 | bReencode = true; | ||
232 | |||
233 | new_usegment [ new_length2++ ] = character; | ||
234 | if (character == '%' ) | ||
235 | { | ||
236 | int a = i+1 < old_length ? hex2int( csegment[i] ) : -1; | ||
237 | int b = i+1 < old_length ? hex2int( csegment[i+1] ) : -1; | ||
238 | if ((a == -1) || (b == -1)) // Only replace if sequence is valid | ||
239 | { | ||
240 | // Contains stray %, make sure to re-encode! | ||
241 | bReencode = true; | ||
242 | } | ||
243 | else | ||
244 | { | ||
245 | // Valid %xx sequence | ||
246 | character = a * 16 + b; // Replace with value of %dd | ||
247 | if (!character && updateDecoded) | ||
248 | break; // Stop at %00 | ||
249 | |||
250 | new_usegment [ new_length2++ ] = (unsigned char) csegment[i++]; | ||
251 | new_usegment [ new_length2++ ] = (unsigned char) csegment[i++]; | ||
252 | } | ||
253 | } | ||
254 | if (bReencode) | ||
255 | { | ||
256 | new_length2--; | ||
257 | new_usegment [ new_length2++ ] = '%'; | ||
258 | |||
259 | unsigned int c = character / 16; | ||
260 | c += (c > 9) ? ('A' - 10) : '0'; | ||
261 | new_usegment[ new_length2++ ] = c; | ||
262 | |||
263 | c = character % 16; | ||
264 | c += (c > 9) ? ('A' - 10) : '0'; | ||
265 | new_usegment[ new_length2++ ] = c; | ||
266 | } | ||
267 | |||
268 | new_segment [ new_length++ ] = character; | ||
269 | } | ||
270 | new_segment [ new_length ] = 0; | ||
271 | |||
272 | encoded = QString( new_usegment, new_length2); | ||
273 | |||
274 | // Encoding specified | ||
275 | if (updateDecoded) | ||
276 | { | ||
277 | QByteArray array; | ||
278 | array.setRawData(new_segment, new_length); | ||
279 | decoded = textCodec->toUnicode( array, new_length ); | ||
280 | array.resetRawData(new_segment, new_length); | ||
281 | QCString validate = textCodec->fromUnicode(decoded); | ||
282 | |||
283 | if (strcmp(validate.data(), new_segment) != 0) | ||
284 | { | ||
285 | decoded = QString::fromLocal8Bit(new_segment, new_length); | ||
286 | } | ||
287 | } | ||
288 | |||
289 | delete [] new_segment; | ||
290 | delete [] new_usegment; | ||
291 | } | ||
292 | |||
293 | static QString decode(const QString &segment, int encoding_hint = 0) | ||
294 | { | ||
295 | QString result; | ||
296 | QString tmp; | ||
297 | decode(segment, result, tmp, encoding_hint); | ||
298 | return result; | ||
299 | } | ||
300 | |||
301 | static QString cleanpath(const QString &path, bool cleanDirSeparator=true) | ||
302 | { | ||
303 | if (path.isEmpty()) return QString::null; | ||
304 | int len = path.length(); | ||
305 | bool slash = (len && path[len-1] == '/') || | ||
306 | (len > 1 && path[len-2] == '/' && path[len-1] == '.'); | ||
307 | |||
308 | // The following code cleans up directory path much like | ||
309 | // QDir::cleanDirPath() except it can be made to ignore multiple | ||
310 | // directory separators by setting the flag to false. That fixes | ||
311 | // bug# 15044, mail.altavista.com and other similar brain-dead server | ||
312 | // implementations that do not follow what has been specified in | ||
313 | // RFC 2396!! (dA) | ||
314 | QString result; | ||
315 | int cdUp, orig_pos, pos; | ||
316 | |||
317 | cdUp = 0; | ||
318 | pos = orig_pos = len; | ||
319 | while ( pos && (pos = path.findRev('/',--pos)) != -1 ) | ||
320 | { | ||
321 | len = orig_pos - pos - 1; | ||
322 | if ( len == 2 && path[pos+1] == '.' && path[pos+2] == '.' ) | ||
323 | cdUp++; | ||
324 | else | ||
325 | { | ||
326 | // Ignore any occurances of '.' | ||
327 | // This includes entries that simply do not make sense like /..../ | ||
328 | if ( (len || !cleanDirSeparator) && | ||
329 | (len != 1 || path[pos+1] != '.' ) ) | ||
330 | { | ||
331 | if ( !cdUp ) | ||
332 | result.prepend(path.mid(pos, len+1)); | ||
333 | else | ||
334 | cdUp--; | ||
335 | } | ||
336 | } | ||
337 | orig_pos = pos; | ||
338 | } | ||
339 | |||
340 | if ( result.isEmpty() ) | ||
341 | result = "/"; | ||
342 | else if ( slash && result.at(result.length()-1) != '/' ) | ||
343 | result.append('/'); | ||
344 | |||
345 | return result; | ||
346 | } | ||
347 | |||
348 | bool KURL::isRelativeURL(const QString &_url) | ||
349 | { | ||
350 | int len = _url.length(); | ||
351 | if (!len) return true; // Very short relative URL. | ||
352 | const QChar *str = _url.unicode(); | ||
353 | |||
354 | // Absolute URL must start with alpha-character | ||
355 | if (!isalpha(str[0].latin1())) | ||
356 | return true; // Relative URL | ||
357 | |||
358 | for(int i = 1; i < len; i++) | ||
359 | { | ||
360 | char c = str[i].latin1(); // Note: non-latin1 chars return 0! | ||
361 | if (c == ':') | ||
362 | return false; // Absolute URL | ||
363 | |||
364 | // Protocol part may only contain alpha, digit, + or - | ||
365 | if (!isalpha(c) && !isdigit(c) && (c != '+') && (c != '-')) | ||
366 | return true; // Relative URL | ||
367 | } | ||
368 | // URL did not contain ':' | ||
369 | return true; // Relative URL | ||
370 | } | ||
371 | |||
372 | KURL::List::List(const KURL &url) | ||
373 | { | ||
374 | append( url ); | ||
375 | } | ||
376 | |||
377 | KURL::List::List(const QStringList &list) | ||
378 | { | ||
379 | for (QStringList::ConstIterator it = list.begin(); | ||
380 | it != list.end(); | ||
381 | it++) | ||
382 | { | ||
383 | append( KURL(*it) ); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | QStringList KURL::List::toStringList() const | ||
388 | { | ||
389 | QStringList lst; | ||
390 | for( KURL::List::ConstIterator it = begin(); | ||
391 | it != end(); | ||
392 | it++) | ||
393 | { | ||
394 | lst.append( (*it).url() ); | ||
395 | } | ||
396 | return lst; | ||
397 | } | ||
398 | |||
399 | |||
400 | KURL::KURL() | ||
401 | { | ||
402 | reset(); | ||
403 | } | ||
404 | |||
405 | KURL::~KURL() | ||
406 | { | ||
407 | } | ||
408 | |||
409 | |||
410 | KURL::KURL( const QString &url, int encoding_hint ) | ||
411 | { | ||
412 | reset(); | ||
413 | parse( url, encoding_hint ); | ||
414 | } | ||
415 | |||
416 | KURL::KURL( const char * url, int encoding_hint ) | ||
417 | { | ||
418 | reset(); | ||
419 | parse( QString::fromLatin1(url), encoding_hint ); | ||
420 | } | ||
421 | |||
422 | KURL::KURL( const QCString& url, int encoding_hint ) | ||
423 | { | ||
424 | reset(); | ||
425 | parse( QString::fromLatin1(url), encoding_hint ); | ||
426 | } | ||
427 | |||
428 | KURL::KURL( const KURL& _u ) | ||
429 | { | ||
430 | *this = _u; | ||
431 | } | ||
432 | |||
433 | QDataStream & operator<< (QDataStream & s, const KURL & a) | ||
434 | { | ||
435 | QString QueryForWire=a.m_strQuery_encoded; | ||
436 | if (!a.m_strQuery_encoded.isNull()) | ||
437 | QueryForWire.prepend("?"); | ||
438 | |||
439 | s << a.m_strProtocol << a.m_strUser << a.m_strPass << a.m_strHost | ||
440 | << a.m_strPath << a.m_strPath_encoded << QueryForWire << a.m_strRef_encoded | ||
441 | << Q_INT8(a.m_bIsMalformed ? 1 : 0) << a.m_iPort; | ||
442 | return s; | ||
443 | } | ||
444 | |||
445 | QDataStream & operator>> (QDataStream & s, KURL & a) | ||
446 | { | ||
447 | Q_INT8 malf; | ||
448 | QString QueryFromWire; | ||
449 | s >> a.m_strProtocol >> a.m_strUser >> a.m_strPass >> a.m_strHost | ||
450 | >> a.m_strPath >> a.m_strPath_encoded >> QueryFromWire >> a.m_strRef_encoded | ||
451 | >> malf >> a.m_iPort; | ||
452 | a.m_bIsMalformed = (malf != 0); | ||
453 | |||
454 | if ( QueryFromWire.isEmpty() ) | ||
455 | a.m_strQuery_encoded = QString::null; | ||
456 | else | ||
457 | a.m_strQuery_encoded = QueryFromWire.mid(1); | ||
458 | |||
459 | return s; | ||
460 | } | ||
461 | |||
462 | #ifndef QT_NO_NETWORKPROTOCOL | ||
463 | KURL::KURL( const QUrl &u ) | ||
464 | { | ||
465 | *this = u; | ||
466 | } | ||
467 | #endif | ||
468 | |||
469 | KURL::KURL( const KURL& _u, const QString& _rel_url, int encoding_hint ) | ||
470 | { | ||
471 | // WORKAROUND THE RFC 1606 LOOPHOLE THAT ALLOWS | ||
472 | // http:/index.html AS A VALID SYNTAX FOR RELATIVE | ||
473 | // URLS. ( RFC 2396 section 5.2 item # 3 ) | ||
474 | QString rUrl = _rel_url; | ||
475 | int len = _u.m_strProtocol.length(); | ||
476 | if ( !_u.m_strHost.isEmpty() && !rUrl.isEmpty() && | ||
477 | rUrl.find( _u.m_strProtocol, 0, false ) == 0 && | ||
478 | rUrl[len] == ':' && (rUrl[len+1] != '/' || | ||
479 | (rUrl[len+1] == '/' && rUrl[len+2] != '/')) ) | ||
480 | { | ||
481 | rUrl.remove( 0, rUrl.find( ':' ) + 1 ); | ||
482 | } | ||
483 | |||
484 | if ( rUrl.isEmpty() ) | ||
485 | { | ||
486 | *this = _u; | ||
487 | } | ||
488 | else if ( rUrl[0] == '#' ) | ||
489 | { | ||
490 | *this = _u; | ||
491 | QString ref = decode(rUrl.mid(1), encoding_hint); | ||
492 | if ( ref.isNull() ) | ||
493 | ref = ""; // we know there was an (empty) html ref, we saw the '#' | ||
494 | setHTMLRef( ref ); | ||
495 | } | ||
496 | else if ( isRelativeURL( rUrl) ) | ||
497 | { | ||
498 | *this = _u; | ||
499 | m_strQuery_encoded = QString::null; | ||
500 | m_strRef_encoded = QString::null; | ||
501 | if ( rUrl[0] == '/') | ||
502 | { | ||
503 | if ((rUrl.length() > 1) && (rUrl[1] == '/')) | ||
504 | { | ||
505 | m_strHost = QString::null; | ||
506 | } | ||
507 | m_strPath = QString::null; | ||
508 | m_strPath_encoded = QString::null; | ||
509 | } | ||
510 | else if ( rUrl[0] != '?' ) | ||
511 | { | ||
512 | int pos = m_strPath.findRev( '/' ); | ||
513 | if (pos >= 0) | ||
514 | m_strPath.truncate(pos); | ||
515 | m_strPath += '/'; | ||
516 | if (!m_strPath_encoded.isEmpty()) | ||
517 | { | ||
518 | pos = m_strPath_encoded.findRev( '/' ); | ||
519 | if (pos >= 0) | ||
520 | m_strPath_encoded.truncate(pos); | ||
521 | m_strPath_encoded += '/'; | ||
522 | } | ||
523 | } | ||
524 | else | ||
525 | { | ||
526 | if ( m_strPath.isEmpty() ) | ||
527 | m_strPath = '/'; | ||
528 | } | ||
529 | KURL tmp( url() + rUrl, encoding_hint); | ||
530 | *this = tmp; | ||
531 | cleanPath(false); | ||
532 | } | ||
533 | else | ||
534 | { | ||
535 | KURL tmp( rUrl, encoding_hint); | ||
536 | *this = tmp; | ||
537 | // Preserve userinfo if applicable. | ||
538 | if (!_u.m_strUser.isEmpty() && m_strUser.isEmpty() && (_u.m_strHost == m_strHost) && (_u.m_strProtocol == m_strProtocol)) | ||
539 | { | ||
540 | m_strUser = _u.m_strUser; | ||
541 | m_strPass = _u.m_strPass; | ||
542 | } | ||
543 | } | ||
544 | } | ||
545 | |||
546 | void KURL::reset() | ||
547 | { | ||
548 | m_strProtocol = QString::null; | ||
549 | m_strUser = QString::null; | ||
550 | m_strPass = QString::null; | ||
551 | m_strHost = QString::null; | ||
552 | m_strPath = QString::null; | ||
553 | m_strPath_encoded = QString::null; | ||
554 | m_strQuery_encoded = QString::null; | ||
555 | m_strRef_encoded = QString::null; | ||
556 | m_bIsMalformed = true; | ||
557 | m_iPort = 0; | ||
558 | } | ||
559 | |||
560 | bool KURL::isEmpty() const | ||
561 | { | ||
562 | return (m_strPath.isEmpty() && m_strProtocol.isEmpty()); | ||
563 | } | ||
564 | |||
565 | void KURL::parse( const QString& _url, int encoding_hint ) | ||
566 | { | ||
567 | //kdDebug(126) << "parse " << _url << endl; | ||
568 | // Return immediately whenever the given url | ||
569 | // is empty or null. | ||
570 | if ( _url.isEmpty() ) | ||
571 | { | ||
572 | m_strProtocol = _url; | ||
573 | return; | ||
574 | } | ||
575 | |||
576 | QString port; | ||
577 | bool badHostName = false; | ||
578 | int start = 0; | ||
579 | uint len = _url.length(); | ||
580 | const QChar* buf = _url.unicode(); | ||
581 | const QChar* orig = buf; | ||
582 | |||
583 | QChar delim; | ||
584 | QString tmp; | ||
585 | |||
586 | uint pos = 0; | ||
587 | |||
588 | // Node 1: Accept alpha or slash | ||
589 | QChar x = buf[pos++]; | ||
590 | if ( x == '/' ) | ||
591 | goto Node9; | ||
592 | if ( !isalpha( (int)x ) ) | ||
593 | goto NodeErr; | ||
594 | |||
595 | // Node 2: Accept any amount of (alpha|digit|'+'|'-') | ||
596 | // '.' is not currently accepted, because current KURL may be confused. | ||
597 | // Proceed with :// :/ or : | ||
598 | while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) || | ||
599 | buf[pos] == '+' || buf[pos] == '-')) pos++; | ||
600 | |||
601 | if ( pos+2 < len && buf[pos] == ':' && buf[pos+1] == '/' && buf[pos+2] == '/' ) | ||
602 | { | ||
603 | m_strProtocol = QString( orig, pos ).lower(); | ||
604 | pos += 3; | ||
605 | } | ||
606 | else if (pos+1 < len && buf[pos] == ':' ) // Need to always compare length()-1 otherwise KURL passes "http:" as legal!! | ||
607 | { | ||
608 | m_strProtocol = QString( orig, pos ).lower(); | ||
609 | //kdDebug(126)<<"setting protocol to "<<m_strProtocol<<endl; | ||
610 | pos++; | ||
611 | start = pos; | ||
612 | goto Node9; | ||
613 | } | ||
614 | else | ||
615 | goto NodeErr; | ||
616 | |||
617 | //Node 3: We need at least one character here | ||
618 | if ( pos == len ) | ||
619 | goto NodeErr; | ||
620 | start = pos; | ||
621 | |||
622 | // Node 4: Accept any amount of characters. | ||
623 | if (buf[pos] == '[') // An IPv6 host follows. | ||
624 | goto Node8; | ||
625 | // Terminate on / or @ or ? or # or " or ; or < | ||
626 | x = buf[pos]; | ||
627 | while( (x != ':') && (x != '@') && (x != '/') && (x != '?') && (x != '#') ) | ||
628 | { | ||
629 | if ((x == '\"') || (x == ';') || (x == '<')) | ||
630 | badHostName = true; | ||
631 | if (++pos == len) | ||
632 | break; | ||
633 | x = buf[pos]; | ||
634 | } | ||
635 | if ( pos == len ) | ||
636 | { | ||
637 | if (badHostName) | ||
638 | goto NodeErr; | ||
639 | |||
640 | setHost(decode(QString( buf + start, pos - start ), encoding_hint)); | ||
641 | goto NodeOk; | ||
642 | } | ||
643 | if ( x == '@' ) | ||
644 | { | ||
645 | m_strUser = decode(QString( buf + start, pos - start ), encoding_hint); | ||
646 | pos++; | ||
647 | goto Node7; | ||
648 | } | ||
649 | else if ( (x == '/') || (x == '?') || (x == '#')) | ||
650 | { | ||
651 | if (badHostName) | ||
652 | goto NodeErr; | ||
653 | |||
654 | setHost(decode(QString( buf + start, pos - start ), encoding_hint)); | ||
655 | start = pos; | ||
656 | goto Node9; | ||
657 | } | ||
658 | else if ( x != ':' ) | ||
659 | goto NodeErr; | ||
660 | m_strUser = decode(QString( buf + start, pos - start ), encoding_hint); | ||
661 | pos++; | ||
662 | |||
663 | // Node 5: We need at least one character | ||
664 | if ( pos == len ) | ||
665 | goto NodeErr; | ||
666 | start = pos++; | ||
667 | |||
668 | // Node 6: Read everything until @, /, ? or # | ||
669 | while( (pos < len) && | ||
670 | (buf[pos] != '@') && | ||
671 | (buf[pos] != '/') && | ||
672 | (buf[pos] != '?') && | ||
673 | (buf[pos] != '#')) pos++; | ||
674 | // If we now have a '@' the ':' seperates user and password. | ||
675 | // Otherwise it seperates host and port. | ||
676 | if ( (pos == len) || (buf[pos] != '@') ) | ||
677 | { | ||
678 | // Ok the : was used to separate host and port | ||
679 | if (badHostName) | ||
680 | goto NodeErr; | ||
681 | setHost(m_strUser); | ||
682 | m_strUser = QString::null; | ||
683 | QString tmp( buf + start, pos - start ); | ||
684 | char *endptr; | ||
685 | m_iPort = (unsigned short int)strtol(tmp.ascii(), &endptr, 10); | ||
686 | if ((pos == len) && (strlen(endptr) == 0)) | ||
687 | goto NodeOk; | ||
688 | // there is more after the digits | ||
689 | pos -= strlen(endptr); | ||
690 | start = pos++; | ||
691 | goto Node9; | ||
692 | } | ||
693 | m_strPass = decode(QString( buf + start, pos - start), encoding_hint); | ||
694 | pos++; | ||
695 | |||
696 | // Node 7: We need at least one character | ||
697 | Node7: | ||
698 | if ( pos == len ) | ||
699 | goto NodeErr; | ||
700 | |||
701 | Node8: | ||
702 | if (buf[pos] == '[') | ||
703 | { | ||
704 | // IPv6 address | ||
705 | start = ++pos; // Skip '[' | ||
706 | |||
707 | if (pos == len) | ||
708 | { | ||
709 | badHostName = true; | ||
710 | goto NodeErr; | ||
711 | } | ||
712 | // Node 8b: Read everything until ] or terminate | ||
713 | badHostName = false; | ||
714 | x = buf[pos]; | ||
715 | while( (x != ']') ) | ||
716 | { | ||
717 | if ((x == '\"') || (x == ';') || (x == '<')) | ||
718 | badHostName = true; | ||
719 | if (++pos == len) | ||
720 | { | ||
721 | badHostName = true; | ||
722 | break; | ||
723 | } | ||
724 | x = buf[pos]; | ||
725 | } | ||
726 | if (badHostName) | ||
727 | goto NodeErr; | ||
728 | setHost(decode(QString( buf + start, pos - start ), encoding_hint)); | ||
729 | if (pos < len) pos++; // Skip ']' | ||
730 | if (pos == len) | ||
731 | goto NodeOk; | ||
732 | } | ||
733 | else | ||
734 | { | ||
735 | // Non IPv6 address | ||
736 | start = pos; | ||
737 | |||
738 | // Node 8b: Read everything until / : or terminate | ||
739 | badHostName = false; | ||
740 | x = buf[pos]; | ||
741 | while( (x != ':') && (x != '@') && (x != '/') && (x != '?') && (x != '#') ) | ||
742 | { | ||
743 | if ((x == '\"') || (x == ';') || (x == '<')) | ||
744 | badHostName = true; | ||
745 | if (++pos == len) | ||
746 | break; | ||
747 | x = buf[pos]; | ||
748 | } | ||
749 | if (badHostName) | ||
750 | goto NodeErr; | ||
751 | if ( pos == len ) | ||
752 | { | ||
753 | setHost(decode(QString( buf + start, pos - start ), encoding_hint)); | ||
754 | goto NodeOk; | ||
755 | } | ||
756 | setHost(decode(QString( buf + start, pos - start ), encoding_hint)); | ||
757 | } | ||
758 | x = buf[pos]; | ||
759 | if ( x == '/' ) | ||
760 | { | ||
761 | start = pos++; | ||
762 | goto Node9; | ||
763 | } | ||
764 | else if ( x != ':' ) | ||
765 | goto NodeErr; | ||
766 | pos++; | ||
767 | |||
768 | // Node 8a: Accept at least one digit | ||
769 | if ( pos == len ) | ||
770 | goto NodeErr; | ||
771 | start = pos; | ||
772 | if ( !isdigit( buf[pos++] ) ) | ||
773 | goto NodeErr; | ||
774 | |||
775 | // Node 8b: Accept any amount of digits | ||
776 | while( pos < len && isdigit( buf[pos] ) ) pos++; | ||
777 | port = QString( buf + start, pos - start ); | ||
778 | m_iPort = port.toUShort(); | ||
779 | if ( pos == len ) | ||
780 | goto NodeOk; | ||
781 | start = pos++; | ||
782 | |||
783 | Node9: // parse path until query or reference reached | ||
784 | |||
785 | while( pos < len && buf[pos] != '#' && buf[pos]!='?' ) pos++; | ||
786 | |||
787 | tmp = QString( buf + start, pos - start ); | ||
788 | //kdDebug(126)<<" setting encoded path&query to:"<<tmp<<endl; | ||
789 | setEncodedPath( tmp, encoding_hint ); | ||
790 | |||
791 | if ( pos == len ) | ||
792 | goto NodeOk; | ||
793 | |||
794 | //Node10: // parse query or reference depending on what comes first | ||
795 | delim = (buf[pos++]=='#'?'?':'#'); | ||
796 | |||
797 | start = pos; | ||
798 | |||
799 | while(pos < len && buf[pos]!=delim ) pos++; | ||
800 | |||
801 | tmp = QString(buf + start, pos - start); | ||
802 | if (delim=='#') | ||
803 | setQuery(tmp, encoding_hint); | ||
804 | else | ||
805 | m_strRef_encoded = tmp; | ||
806 | |||
807 | if (pos == len) | ||
808 | goto NodeOk; | ||
809 | |||
810 | //Node11: // feed the rest into the remaining variable | ||
811 | tmp = QString( buf + pos + 1, len - pos - 1); | ||
812 | if (delim == '#') | ||
813 | m_strRef_encoded = tmp; | ||
814 | else | ||
815 | setQuery(tmp, encoding_hint); | ||
816 | |||
817 | NodeOk: | ||
818 | //kdDebug(126)<<"parsing finished. m_strProtocol="<<m_strProtocol<<" m_strHost="<<m_strHost<<" m_strPath="<<m_strPath<<endl; | ||
819 | m_bIsMalformed = false; // Valid URL | ||
820 | |||
821 | //kdDebug()<<"Prot="<<m_strProtocol<<"\nUser="<<m_strUser<<"\nPass="<<m_strPass<<"\nHost="<<m_strHost<<"\nPath="<<m_strPath<<"\nQuery="<<m_strQuery_encoded<<"\nRef="<<m_strRef_encoded<<"\nPort="<<m_iPort<<endl; | ||
822 | if (m_strProtocol.isEmpty()) | ||
823 | { | ||
824 | m_strProtocol = fileProt; | ||
825 | } | ||
826 | return; | ||
827 | |||
828 | NodeErr: | ||
829 | // kdDebug(126) << "KURL couldn't parse URL \"" << _url << "\"" << endl; | ||
830 | reset(); | ||
831 | m_strProtocol = _url; | ||
832 | } | ||
833 | |||
834 | KURL& KURL::operator=( const QString& _url ) | ||
835 | { | ||
836 | reset(); | ||
837 | parse( _url ); | ||
838 | |||
839 | return *this; | ||
840 | } | ||
841 | |||
842 | KURL& KURL::operator=( const char * _url ) | ||
843 | { | ||
844 | reset(); | ||
845 | parse( QString::fromLatin1(_url) ); | ||
846 | |||
847 | return *this; | ||
848 | } | ||
849 | |||
850 | #ifndef QT_NO_NETWORKPROTOCOL | ||
851 | KURL& KURL::operator=( const QUrl & u ) | ||
852 | { | ||
853 | m_strProtocol = u.protocol(); | ||
854 | m_strUser = u.user(); | ||
855 | m_strPass = u.password(); | ||
856 | m_strHost = u.host(); | ||
857 | m_strPath = u.path( FALSE ); | ||
858 | m_strPath_encoded = QString::null; | ||
859 | m_strQuery_encoded = u.query(); | ||
860 | m_strRef_encoded = u.ref(); | ||
861 | m_bIsMalformed = !u.isValid(); | ||
862 | m_iPort = u.port(); | ||
863 | |||
864 | return *this; | ||
865 | } | ||
866 | #endif | ||
867 | |||
868 | KURL& KURL::operator=( const KURL& _u ) | ||
869 | { | ||
870 | m_strProtocol = _u.m_strProtocol; | ||
871 | m_strUser = _u.m_strUser; | ||
872 | m_strPass = _u.m_strPass; | ||
873 | m_strHost = _u.m_strHost; | ||
874 | m_strPath = _u.m_strPath; | ||
875 | m_strPath_encoded = _u.m_strPath_encoded; | ||
876 | m_strQuery_encoded = _u.m_strQuery_encoded; | ||
877 | m_strRef_encoded = _u.m_strRef_encoded; | ||
878 | m_bIsMalformed = _u.m_bIsMalformed; | ||
879 | m_iPort = _u.m_iPort; | ||
880 | |||
881 | return *this; | ||
882 | } | ||
883 | |||
884 | bool KURL::operator==( const KURL& _u ) const | ||
885 | { | ||
886 | if ( isMalformed() || _u.isMalformed() ) | ||
887 | return false; | ||
888 | |||
889 | if ( m_strProtocol == _u.m_strProtocol && | ||
890 | m_strUser == _u.m_strUser && | ||
891 | m_strPass == _u.m_strPass && | ||
892 | m_strHost == _u.m_strHost && | ||
893 | m_strPath == _u.m_strPath && | ||
894 | // The encoded path may be null, but the URLs are still equal (David) | ||
895 | ( m_strPath_encoded.isNull() || _u.m_strPath_encoded.isNull() || | ||
896 | m_strPath_encoded == _u.m_strPath_encoded ) && | ||
897 | m_strQuery_encoded == _u.m_strQuery_encoded && | ||
898 | m_strRef_encoded == _u.m_strRef_encoded && | ||
899 | m_iPort == _u.m_iPort ) | ||
900 | { | ||
901 | return true; | ||
902 | } | ||
903 | |||
904 | return false; | ||
905 | } | ||
906 | |||
907 | bool KURL::operator==( const QString& _u ) const | ||
908 | { | ||
909 | KURL u( _u ); | ||
910 | return ( *this == u ); | ||
911 | } | ||
912 | |||
913 | bool KURL::cmp( const KURL &u, bool ignore_trailing ) const | ||
914 | { | ||
915 | return equals( u, ignore_trailing ); | ||
916 | } | ||
917 | |||
918 | bool KURL::equals( const KURL &_u, bool ignore_trailing ) const | ||
919 | { | ||
920 | if ( isMalformed() || _u.isMalformed() ) | ||
921 | return false; | ||
922 | |||
923 | if ( ignore_trailing ) | ||
924 | { | ||
925 | QString path1 = path(1); | ||
926 | QString path2 = _u.path(1); | ||
927 | if ( path1 != path2 ) | ||
928 | return false; | ||
929 | |||
930 | if ( m_strProtocol == _u.m_strProtocol && | ||
931 | m_strUser == _u.m_strUser && | ||
932 | m_strPass == _u.m_strPass && | ||
933 | m_strHost == _u.m_strHost && | ||
934 | m_strQuery_encoded == _u.m_strQuery_encoded && | ||
935 | m_strRef_encoded == _u.m_strRef_encoded && | ||
936 | m_iPort == _u.m_iPort ) | ||
937 | return true; | ||
938 | |||
939 | return false; | ||
940 | } | ||
941 | |||
942 | return ( *this == _u ); | ||
943 | } | ||
944 | |||
945 | bool KURL::isParentOf( const KURL& _u ) const | ||
946 | { | ||
947 | if ( isMalformed() || _u.isMalformed() ) | ||
948 | return false; | ||
949 | |||
950 | if ( m_strProtocol == _u.m_strProtocol && | ||
951 | m_strUser == _u.m_strUser && | ||
952 | m_strPass == _u.m_strPass && | ||
953 | m_strHost == _u.m_strHost && | ||
954 | m_strQuery_encoded == _u.m_strQuery_encoded && | ||
955 | m_strRef_encoded == _u.m_strRef_encoded && | ||
956 | m_iPort == _u.m_iPort ) | ||
957 | { | ||
958 | if ( path().isEmpty() || _u.path().isEmpty() ) | ||
959 | return false; // can't work with implicit paths | ||
960 | |||
961 | QString p1( cleanpath( path() ) ); | ||
962 | if ( p1.at(p1.length()-1) != '/' ) | ||
963 | p1 += '/'; | ||
964 | QString p2( cleanpath( _u.path() ) ); | ||
965 | if ( p2.at(p2.length()-1) != '/' ) | ||
966 | p2 += '/'; | ||
967 | |||
968 | //kdDebug(126) << "p1=" << p1 << endl; | ||
969 | //kdDebug(126) << "p2=" << p2 << endl; | ||
970 | //kdDebug(126) << "p1.length()=" << p1.length() << endl; | ||
971 | //kdDebug(126) << "p2.left(!$)=" << p2.left( p1.length() ) << endl; | ||
972 | return p2.startsWith( p1 ); | ||
973 | } | ||
974 | return false; | ||
975 | } | ||
976 | |||
977 | void KURL::setFileName( const QString& _txt ) | ||
978 | { | ||
979 | m_strRef_encoded = QString::null; | ||
980 | int i = 0; | ||
981 | while( _txt[i] == '/' ) ++i; | ||
982 | QString tmp; | ||
983 | if ( i ) | ||
984 | tmp = _txt.mid( i ); | ||
985 | else | ||
986 | tmp = _txt; | ||
987 | |||
988 | QString path = m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded; | ||
989 | if ( path.isEmpty() ) | ||
990 | path = "/"; | ||
991 | else | ||
992 | { | ||
993 | int lastSlash = path.findRev( '/' ); | ||
994 | if ( lastSlash == -1) | ||
995 | { | ||
996 | // The first character is not a '/' ??? | ||
997 | // This looks strange ... | ||
998 | path = "/"; | ||
999 | } | ||
1000 | else if ( path.right(1) != "/" ) | ||
1001 | path.truncate( lastSlash+1 ); // keep the "/" | ||
1002 | } | ||
1003 | if (m_strPath_encoded.isEmpty()) | ||
1004 | { | ||
1005 | path += tmp; | ||
1006 | setPath( path ); | ||
1007 | } | ||
1008 | else | ||
1009 | { | ||
1010 | path += encode_string(tmp); | ||
1011 | setEncodedPath( path ); | ||
1012 | } | ||
1013 | cleanPath(); | ||
1014 | } | ||
1015 | |||
1016 | void KURL::cleanPath( bool cleanDirSeparator ) // taken from the old KURL | ||
1017 | { | ||
1018 | m_strPath = cleanpath(m_strPath, cleanDirSeparator); | ||
1019 | // WABA: Is this safe when "/../" is encoded with %? | ||
1020 | m_strPath_encoded = cleanpath(m_strPath_encoded, cleanDirSeparator); | ||
1021 | } | ||
1022 | |||
1023 | static QString trailingSlash( int _trailing, const QString &path ) | ||
1024 | { | ||
1025 | QString result = path; | ||
1026 | |||
1027 | if ( _trailing == 0 ) | ||
1028 | return result; | ||
1029 | else if ( _trailing == 1 ) | ||
1030 | { | ||
1031 | int len = result.length(); | ||
1032 | if ( len == 0 ) | ||
1033 | result = QString::null; | ||
1034 | else if ( result[ len - 1 ] != '/' ) | ||
1035 | result += "/"; | ||
1036 | return result; | ||
1037 | } | ||
1038 | else if ( _trailing == -1 ) | ||
1039 | { | ||
1040 | if ( result == "/" ) | ||
1041 | return result; | ||
1042 | int len = result.length(); | ||
1043 | if ( len != 0 && result[ len - 1 ] == '/' ) | ||
1044 | result.truncate( len - 1 ); | ||
1045 | return result; | ||
1046 | } | ||
1047 | else { | ||
1048 | assert( 0 ); | ||
1049 | return QString::null; | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | void KURL::adjustPath( int _trailing ) | ||
1054 | { | ||
1055 | if (!m_strPath_encoded.isEmpty()) | ||
1056 | { | ||
1057 | m_strPath_encoded = trailingSlash( _trailing, m_strPath_encoded ); | ||
1058 | } | ||
1059 | m_strPath = trailingSlash( _trailing, m_strPath ); | ||
1060 | } | ||
1061 | |||
1062 | |||
1063 | QString KURL::encodedPathAndQuery( int _trailing, bool _no_empty_path, int encoding_hint ) const | ||
1064 | { | ||
1065 | QString tmp; | ||
1066 | if (!m_strPath_encoded.isEmpty() && encoding_hint == 0) | ||
1067 | { | ||
1068 | tmp = trailingSlash( _trailing, m_strPath_encoded ); | ||
1069 | } | ||
1070 | else | ||
1071 | { | ||
1072 | tmp = path( _trailing ); | ||
1073 | if ( _no_empty_path && tmp.isEmpty() ) | ||
1074 | tmp = "/"; | ||
1075 | tmp = encode( tmp, false, encoding_hint ); | ||
1076 | } | ||
1077 | |||
1078 | // TODO apply encoding_hint to the query | ||
1079 | if (!m_strQuery_encoded.isNull()) | ||
1080 | tmp += '?' + m_strQuery_encoded; | ||
1081 | return tmp; | ||
1082 | } | ||
1083 | |||
1084 | void KURL::setEncodedPath( const QString& _txt, int encoding_hint ) | ||
1085 | { | ||
1086 | m_strPath_encoded = _txt; | ||
1087 | |||
1088 | decode( m_strPath_encoded, m_strPath, m_strPath_encoded, encoding_hint ); | ||
1089 | // Throw away encoding for local files, makes file-operations faster. | ||
1090 | if (m_strProtocol == fileProt) | ||
1091 | m_strPath_encoded = QString::null; | ||
1092 | } | ||
1093 | |||
1094 | |||
1095 | void KURL::setEncodedPathAndQuery( const QString& _txt, int encoding_hint ) | ||
1096 | { | ||
1097 | int pos = _txt.find( '?' ); | ||
1098 | if ( pos == -1 ) | ||
1099 | { | ||
1100 | setEncodedPath(_txt, encoding_hint); | ||
1101 | m_strQuery_encoded = QString::null; | ||
1102 | } | ||
1103 | else | ||
1104 | { | ||
1105 | setEncodedPath(_txt.left( pos ), encoding_hint); | ||
1106 | setQuery(_txt.right(_txt.length() - pos - 1), encoding_hint); | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | QString KURL::path( int _trailing ) const | ||
1111 | { | ||
1112 | return trailingSlash( _trailing, path() ); | ||
1113 | } | ||
1114 | |||
1115 | bool KURL::isLocalFile() const | ||
1116 | { | ||
1117 | if ( (m_strProtocol != fileProt ) || hasSubURL() ) | ||
1118 | return false; | ||
1119 | |||
1120 | if (m_strHost.isEmpty() || (m_strHost == "localhost")) | ||
1121 | return true; | ||
1122 | |||
1123 | char hostname[ 256 ]; | ||
1124 | hostname[ 0 ] = '\0'; | ||
1125 | #ifdef _WIN32_ | ||
1126 | // pending LR fixme | ||
1127 | //hostname = "localhost"; | ||
1128 | #else | ||
1129 | if (!gethostname( hostname, 255 )) | ||
1130 | hostname[sizeof(hostname)-1] = '\0'; | ||
1131 | #endif | ||
1132 | for(char *p = hostname; *p; p++) | ||
1133 | *p = tolower(*p); | ||
1134 | |||
1135 | return (m_strHost == hostname); | ||
1136 | } | ||
1137 | |||
1138 | void KURL::setFileEncoding(const QString &encoding) | ||
1139 | { | ||
1140 | if (!isLocalFile()) | ||
1141 | return; | ||
1142 | |||
1143 | QString q = query(); | ||
1144 | |||
1145 | if (!q.isEmpty() && (q[0] == '?')) | ||
1146 | q = q.mid(1); | ||
1147 | |||
1148 | QStringList args = QStringList::split('&', q); | ||
1149 | for(QStringList::Iterator it = args.begin(); | ||
1150 | it != args.end();) | ||
1151 | { | ||
1152 | QString s = decode_string(*it); | ||
1153 | if (s.startsWith("charset=")) | ||
1154 | //US changed erase into remove ??? | ||
1155 | it = args.remove(it); | ||
1156 | else | ||
1157 | ++it; | ||
1158 | } | ||
1159 | if (!encoding.isEmpty()) | ||
1160 | args.append("charset="+encode_string(encoding)); | ||
1161 | |||
1162 | if (args.isEmpty()) | ||
1163 | setQuery(QString::null); | ||
1164 | else | ||
1165 | setQuery(args.join("&")); | ||
1166 | } | ||
1167 | |||
1168 | QString KURL::fileEncoding() const | ||
1169 | { | ||
1170 | if (!isLocalFile()) | ||
1171 | return QString::null; | ||
1172 | |||
1173 | QString q = query(); | ||
1174 | |||
1175 | if (q.isEmpty()) | ||
1176 | return QString::null; | ||
1177 | |||
1178 | if (q[0] == '?') | ||
1179 | q = q.mid(1); | ||
1180 | |||
1181 | QStringList args = QStringList::split('&', q); | ||
1182 | for(QStringList::ConstIterator it = args.begin(); | ||
1183 | it != args.end(); | ||
1184 | ++it) | ||
1185 | { | ||
1186 | QString s = decode_string(*it); | ||
1187 | if (s.startsWith("charset=")) | ||
1188 | return s.mid(8); | ||
1189 | } | ||
1190 | return QString::null; | ||
1191 | } | ||
1192 | |||
1193 | bool KURL::hasSubURL() const | ||
1194 | { | ||
1195 | if ( m_strProtocol.isEmpty() || m_bIsMalformed ) | ||
1196 | return false; | ||
1197 | if (m_strRef_encoded.isEmpty()) | ||
1198 | return false; | ||
1199 | if (m_strRef_encoded.startsWith("gzip:")) | ||
1200 | return true; | ||
1201 | if (m_strRef_encoded.startsWith("bzip:")) | ||
1202 | return true; | ||
1203 | if (m_strRef_encoded.startsWith("bzip2:")) | ||
1204 | return true; | ||
1205 | if (m_strRef_encoded.startsWith("tar:")) | ||
1206 | return true; | ||
1207 | if ( m_strProtocol == "error" ) // anything that starts with error: has suburls | ||
1208 | return true; | ||
1209 | return false; | ||
1210 | } | ||
1211 | |||
1212 | QString KURL::url( int _trailing, int encoding_hint ) const | ||
1213 | { | ||
1214 | if( m_bIsMalformed ) | ||
1215 | { | ||
1216 | // Return the whole url even when the url is | ||
1217 | // malformed. Under such conditions the url | ||
1218 | // is stored in m_strProtocol. | ||
1219 | return m_strProtocol; | ||
1220 | } | ||
1221 | |||
1222 | QString u = m_strProtocol; | ||
1223 | if (!u.isEmpty()) | ||
1224 | u += ":"; | ||
1225 | |||
1226 | if ( hasHost() ) | ||
1227 | { | ||
1228 | u += "//"; | ||
1229 | if ( hasUser() ) | ||
1230 | { | ||
1231 | u += encode(m_strUser, true, encoding_hint); | ||
1232 | if ( hasPass() ) | ||
1233 | { | ||
1234 | u += ":"; | ||
1235 | u += encode(m_strPass, true, encoding_hint); | ||
1236 | } | ||
1237 | u += "@"; | ||
1238 | } | ||
1239 | bool IPv6 = (m_strHost.find(':') != -1); | ||
1240 | if (IPv6) | ||
1241 | u += '[' + m_strHost + ']'; | ||
1242 | else | ||
1243 | u += encodeHost(m_strHost, true, encoding_hint); | ||
1244 | if ( m_iPort != 0 ) { | ||
1245 | QString buffer; | ||
1246 | buffer.sprintf( ":%u", m_iPort ); | ||
1247 | u += buffer; | ||
1248 | } | ||
1249 | } | ||
1250 | |||
1251 | u += encodedPathAndQuery( _trailing, false, encoding_hint ); | ||
1252 | |||
1253 | if ( hasRef() ) | ||
1254 | { | ||
1255 | u += "#"; | ||
1256 | u += m_strRef_encoded; | ||
1257 | } | ||
1258 | |||
1259 | return u; | ||
1260 | } | ||
1261 | |||
1262 | QString KURL::prettyURL( int _trailing ) const | ||
1263 | { | ||
1264 | if( m_bIsMalformed ) | ||
1265 | { | ||
1266 | // Return the whole url even when the url is | ||
1267 | // malformed. Under such conditions the url | ||
1268 | // is stored in m_strProtocol. | ||
1269 | return m_strProtocol; | ||
1270 | } | ||
1271 | |||
1272 | QString u = m_strProtocol; | ||
1273 | if (!u.isEmpty()) | ||
1274 | u += ":"; | ||
1275 | |||
1276 | if ( hasHost() ) | ||
1277 | { | ||
1278 | u += "//"; | ||
1279 | if ( hasUser() ) | ||
1280 | { | ||
1281 | u += lazy_encode(m_strUser); | ||
1282 | // Don't show password! | ||
1283 | u += "@"; | ||
1284 | } | ||
1285 | bool IPv6 = (m_strHost.find(':') != -1); | ||
1286 | if (IPv6) | ||
1287 | { | ||
1288 | u += '[' + m_strHost + ']'; | ||
1289 | } | ||
1290 | else | ||
1291 | { | ||
1292 | u += lazy_encode(m_strHost); | ||
1293 | } | ||
1294 | if ( m_iPort != 0 ) { | ||
1295 | QString buffer; | ||
1296 | buffer.sprintf( ":%u", m_iPort ); | ||
1297 | u += buffer; | ||
1298 | } | ||
1299 | } | ||
1300 | |||
1301 | u += trailingSlash( _trailing, lazy_encode( m_strPath ) ); | ||
1302 | if (!m_strQuery_encoded.isNull()) | ||
1303 | u += '?' + m_strQuery_encoded; | ||
1304 | |||
1305 | if ( hasRef() ) | ||
1306 | { | ||
1307 | u += "#"; | ||
1308 | u += m_strRef_encoded; | ||
1309 | } | ||
1310 | |||
1311 | return u; | ||
1312 | } | ||
1313 | |||
1314 | QString KURL::prettyURL( int _trailing, AdjustementFlags _flags) const | ||
1315 | { | ||
1316 | QString u = prettyURL(_trailing); | ||
1317 | if (_flags & StripFileProtocol && u.startsWith("file:")) | ||
1318 | u.remove(0, 5); | ||
1319 | return u; | ||
1320 | } | ||
1321 | |||
1322 | QString KURL::htmlURL() const | ||
1323 | { | ||
1324 | //US QStyleSheet::escape was not in my Qt distribution. Why ??? | ||
1325 | //US return QStyleSheet::escape(prettyURL()); | ||
1326 | return prettyURL(); | ||
1327 | } | ||
1328 | |||
1329 | KURL::List KURL::split( const KURL& _url ) | ||
1330 | { | ||
1331 | QString ref; | ||
1332 | KURL::List lst; | ||
1333 | KURL url = _url; | ||
1334 | |||
1335 | while(true) | ||
1336 | { | ||
1337 | KURL u = url; | ||
1338 | u.m_strRef_encoded = QString::null; | ||
1339 | lst.append(u); | ||
1340 | if (url.hasSubURL()) | ||
1341 | { | ||
1342 | url = KURL(url.m_strRef_encoded); | ||
1343 | } | ||
1344 | else | ||
1345 | { | ||
1346 | ref = url.m_strRef_encoded; | ||
1347 | break; | ||
1348 | } | ||
1349 | } | ||
1350 | |||
1351 | // Set HTML ref in all URLs. | ||
1352 | KURL::List::Iterator it; | ||
1353 | for( it = lst.begin() ; it != lst.end(); ++it ) | ||
1354 | { | ||
1355 | (*it).m_strRef_encoded = ref; | ||
1356 | } | ||
1357 | |||
1358 | return lst; | ||
1359 | } | ||
1360 | |||
1361 | KURL::List KURL::split( const QString& _url ) | ||
1362 | { | ||
1363 | return split(KURL(_url)); | ||
1364 | } | ||
1365 | |||
1366 | KURL KURL::join( const KURL::List & lst ) | ||
1367 | { | ||
1368 | if (lst.isEmpty()) return KURL(); | ||
1369 | KURL tmp; | ||
1370 | |||
1371 | KURL::List::ConstIterator first = lst.fromLast(); | ||
1372 | for( KURL::List::ConstIterator it = first; it != lst.end(); --it ) | ||
1373 | { | ||
1374 | KURL u(*it); | ||
1375 | if (it != first) | ||
1376 | { | ||
1377 | if (!u.m_strRef_encoded) u.m_strRef_encoded = tmp.url(); | ||
1378 | else u.m_strRef_encoded += "#" + tmp.url(); // Support more than one suburl thingy | ||
1379 | } | ||
1380 | tmp = u; | ||
1381 | } | ||
1382 | |||
1383 | return tmp; | ||
1384 | } | ||
1385 | |||
1386 | QString KURL::fileName( bool _strip_trailing_slash ) const | ||
1387 | { | ||
1388 | QString fname; | ||
1389 | if (hasSubURL()) { // If we have a suburl, then return the filename from there | ||
1390 | KURL::List list = KURL::split(*this); | ||
1391 | KURL::List::Iterator it = list.fromLast(); | ||
1392 | return (*it).fileName(_strip_trailing_slash); | ||
1393 | } | ||
1394 | const QString &path = m_strPath; | ||
1395 | |||
1396 | int len = path.length(); | ||
1397 | if ( len == 0 ) | ||
1398 | return fname; | ||
1399 | |||
1400 | if ( _strip_trailing_slash ) | ||
1401 | { | ||
1402 | while ( len >= 1 && path[ len - 1 ] == '/' ) | ||
1403 | len--; | ||
1404 | } | ||
1405 | else if ( path[ len - 1 ] == '/' ) | ||
1406 | return fname; | ||
1407 | |||
1408 | // Does the path only consist of '/' characters ? | ||
1409 | if ( len == 1 && path[ 0 ] == '/' ) | ||
1410 | return fname; | ||
1411 | |||
1412 | // Skip last n slashes | ||
1413 | int n = 1; | ||
1414 | if (!m_strPath_encoded.isEmpty()) | ||
1415 | { | ||
1416 | // This is hairy, we need the last unencoded slash. | ||
1417 | // Count in the encoded string how many encoded slashes follow the last | ||
1418 | // unencoded one. | ||
1419 | int i = m_strPath_encoded.findRev( '/', len - 1 ); | ||
1420 | QString fileName_encoded = m_strPath_encoded.mid(i+1); | ||
1421 | n += fileName_encoded.contains("%2f", false); | ||
1422 | } | ||
1423 | int i = len; | ||
1424 | do { | ||
1425 | i = path.findRev( '/', i - 1 ); | ||
1426 | } | ||
1427 | while (--n && (i > 0)); | ||
1428 | |||
1429 | // If ( i == -1 ) => the first character is not a '/' | ||
1430 | // So it's some URL like file:blah.tgz, return the whole path | ||
1431 | if ( i == -1 ) { | ||
1432 | if ( len == (int)path.length() ) | ||
1433 | fname = path; | ||
1434 | else | ||
1435 | // Might get here if _strip_trailing_slash is true | ||
1436 | fname = path.left( len ); | ||
1437 | } | ||
1438 | else | ||
1439 | { | ||
1440 | fname = path.mid( i + 1, len - i - 1 ); // TO CHECK | ||
1441 | } | ||
1442 | return fname; | ||
1443 | } | ||
1444 | |||
1445 | void KURL::addPath( const QString& _txt ) | ||
1446 | { | ||
1447 | if (hasSubURL()) | ||
1448 | { | ||
1449 | KURL::List lst = split( *this ); | ||
1450 | KURL &u = lst.last(); | ||
1451 | u.addPath(_txt); | ||
1452 | *this = join( lst ); | ||
1453 | return; | ||
1454 | } | ||
1455 | |||
1456 | m_strPath_encoded = QString::null; | ||
1457 | |||
1458 | if ( _txt.isEmpty() ) | ||
1459 | return; | ||
1460 | |||
1461 | int i = 0; | ||
1462 | int len = m_strPath.length(); | ||
1463 | // NB: avoid three '/' when building a new path from nothing | ||
1464 | if ( len == 0 ) { | ||
1465 | while( _txt[i] == '/' ) ++i; | ||
1466 | } | ||
1467 | // Add the trailing '/' if it is missing | ||
1468 | else if ( _txt[0] != '/' && ( len == 0 || m_strPath[ len - 1 ] != '/' ) ) | ||
1469 | m_strPath += "/"; | ||
1470 | |||
1471 | // No double '/' characters | ||
1472 | i = 0; | ||
1473 | if ( len != 0 && m_strPath[ len - 1 ] == '/' ) | ||
1474 | { | ||
1475 | while( _txt[i] == '/' ) | ||
1476 | ++i; | ||
1477 | } | ||
1478 | |||
1479 | m_strPath += _txt.mid( i ); | ||
1480 | } | ||
1481 | |||
1482 | QString KURL::directory( bool _strip_trailing_slash_from_result, | ||
1483 | bool _ignore_trailing_slash_in_path ) const | ||
1484 | { | ||
1485 | QString result = m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded; | ||
1486 | if ( _ignore_trailing_slash_in_path ) | ||
1487 | result = trailingSlash( -1, result ); | ||
1488 | |||
1489 | if ( result.isEmpty() || result == "/" ) | ||
1490 | return result; | ||
1491 | |||
1492 | int i = result.findRev( "/" ); | ||
1493 | // If ( i == -1 ) => the first character is not a '/' | ||
1494 | // So it's some URL like file:blah.tgz, with no path | ||
1495 | if ( i == -1 ) | ||
1496 | return QString::null; | ||
1497 | |||
1498 | if ( i == 0 ) | ||
1499 | { | ||
1500 | result = "/"; | ||
1501 | return result; | ||
1502 | } | ||
1503 | |||
1504 | if ( _strip_trailing_slash_from_result ) | ||
1505 | result = result.left( i ); | ||
1506 | else | ||
1507 | result = result.left( i + 1 ); | ||
1508 | |||
1509 | if (!m_strPath_encoded.isEmpty()) | ||
1510 | result = decode(result); | ||
1511 | |||
1512 | return result; | ||
1513 | } | ||
1514 | |||
1515 | |||
1516 | bool KURL::cd( const QString& _dir ) | ||
1517 | { | ||
1518 | if ( _dir.isEmpty() || m_bIsMalformed ) | ||
1519 | return false; | ||
1520 | |||
1521 | if (hasSubURL()) | ||
1522 | { | ||
1523 | KURL::List lst = split( *this ); | ||
1524 | KURL &u = lst.last(); | ||
1525 | u.cd(_dir); | ||
1526 | *this = join( lst ); | ||
1527 | return true; | ||
1528 | } | ||
1529 | |||
1530 | // absolute path ? | ||
1531 | if ( _dir[0] == '/' ) | ||
1532 | { | ||
1533 | m_strPath_encoded = QString::null; | ||
1534 | m_strPath = _dir; | ||
1535 | setHTMLRef( QString::null ); | ||
1536 | m_strQuery_encoded = QString::null; | ||
1537 | return true; | ||
1538 | } | ||
1539 | |||
1540 | // Users home directory on the local disk ? | ||
1541 | if ( ( _dir[0] == '~' ) && ( m_strProtocol == fileProt )) | ||
1542 | { | ||
1543 | m_strPath_encoded = QString::null; | ||
1544 | m_strPath = QDir::homeDirPath(); | ||
1545 | m_strPath += "/"; | ||
1546 | m_strPath += _dir.right(m_strPath.length() - 1); | ||
1547 | setHTMLRef( QString::null ); | ||
1548 | m_strQuery_encoded = QString::null; | ||
1549 | return true; | ||
1550 | } | ||
1551 | |||
1552 | // relative path | ||
1553 | // we always work on the past of the first url. | ||
1554 | // Sub URLs are not touched. | ||
1555 | |||
1556 | // append '/' if necessary | ||
1557 | QString p = path(1); | ||
1558 | p += _dir; | ||
1559 | p = cleanpath( p ); | ||
1560 | setPath( p ); | ||
1561 | |||
1562 | setHTMLRef( QString::null ); | ||
1563 | m_strQuery_encoded = QString::null; | ||
1564 | |||
1565 | return true; | ||
1566 | } | ||
1567 | |||
1568 | KURL KURL::upURL( ) const | ||
1569 | { | ||
1570 | if (!query().isEmpty()) | ||
1571 | { | ||
1572 | KURL u(*this); | ||
1573 | u.setQuery(QString::null); | ||
1574 | return u; | ||
1575 | }; | ||
1576 | |||
1577 | if (!hasSubURL()) | ||
1578 | { | ||
1579 | KURL u(*this); | ||
1580 | u.cd("../"); | ||
1581 | return u; | ||
1582 | } | ||
1583 | |||
1584 | // We have a subURL. | ||
1585 | KURL::List lst = split( *this ); | ||
1586 | if (lst.isEmpty()) | ||
1587 | return KURL(); // Huh? | ||
1588 | while (true) | ||
1589 | { | ||
1590 | KURL &u = lst.last(); | ||
1591 | QString old = u.path(); | ||
1592 | u.cd("../"); | ||
1593 | if (u.path() != old) | ||
1594 | break; // Finshed. | ||
1595 | if (lst.count() == 1) | ||
1596 | break; // Finished. | ||
1597 | lst.remove(lst.fromLast()); | ||
1598 | } | ||
1599 | return join( lst ); | ||
1600 | } | ||
1601 | |||
1602 | QString KURL::htmlRef() const | ||
1603 | { | ||
1604 | if ( !hasSubURL() ) | ||
1605 | { | ||
1606 | return decode( ref() ); | ||
1607 | } | ||
1608 | |||
1609 | List lst = split( *this ); | ||
1610 | return decode( (*lst.begin()).ref() ); | ||
1611 | } | ||
1612 | |||
1613 | QString KURL::encodedHtmlRef() const | ||
1614 | { | ||
1615 | if ( !hasSubURL() ) | ||
1616 | { | ||
1617 | return ref(); | ||
1618 | } | ||
1619 | |||
1620 | List lst = split( *this ); | ||
1621 | return (*lst.begin()).ref(); | ||
1622 | } | ||
1623 | |||
1624 | void KURL::setHTMLRef( const QString& _ref ) | ||
1625 | { | ||
1626 | if ( !hasSubURL() ) | ||
1627 | { | ||
1628 | m_strRef_encoded = encode( _ref, true, 0 /*?*/); | ||
1629 | return; | ||
1630 | } | ||
1631 | |||
1632 | List lst = split( *this ); | ||
1633 | |||
1634 | (*lst.begin()).setRef( encode( _ref, true, 0 /*?*/) ); | ||
1635 | |||
1636 | *this = join( lst ); | ||
1637 | } | ||
1638 | |||
1639 | bool KURL::hasHTMLRef() const | ||
1640 | { | ||
1641 | if ( !hasSubURL() ) | ||
1642 | { | ||
1643 | return hasRef(); | ||
1644 | } | ||
1645 | |||
1646 | List lst = split( *this ); | ||
1647 | return (*lst.begin()).hasRef(); | ||
1648 | } | ||
1649 | |||
1650 | void | ||
1651 | KURL::setProtocol( const QString& _txt ) | ||
1652 | { | ||
1653 | m_strProtocol = _txt; | ||
1654 | m_bIsMalformed = false; | ||
1655 | } | ||
1656 | |||
1657 | void | ||
1658 | KURL::setUser( const QString& _txt ) | ||
1659 | { | ||
1660 | m_strUser = _txt; | ||
1661 | } | ||
1662 | |||
1663 | void | ||
1664 | KURL::setPass( const QString& _txt ) | ||
1665 | { | ||
1666 | m_strPass = _txt; | ||
1667 | } | ||
1668 | |||
1669 | void | ||
1670 | KURL::setHost( const QString& _txt ) | ||
1671 | { | ||
1672 | #ifndef KDE_QT_ONLY | ||
1673 | m_strHost = KIDNA::toUnicode(_txt); | ||
1674 | if (m_strHost.isEmpty()) | ||
1675 | m_strHost = _txt.lower(); // Probably an invalid hostname, but... | ||
1676 | #else | ||
1677 | m_strHost = _txt.lower(); | ||
1678 | #endif | ||
1679 | } | ||
1680 | |||
1681 | void | ||
1682 | KURL::setPort( unsigned short int _p ) | ||
1683 | { | ||
1684 | m_iPort = _p; | ||
1685 | } | ||
1686 | |||
1687 | void KURL::setPath( const QString & path ) | ||
1688 | { | ||
1689 | if (isEmpty()) | ||
1690 | m_bIsMalformed = false; | ||
1691 | if (m_strProtocol.isEmpty()) | ||
1692 | { | ||
1693 | m_strProtocol = fileProt; | ||
1694 | } | ||
1695 | m_strPath = path; | ||
1696 | m_strPath_encoded = QString::null; | ||
1697 | } | ||
1698 | |||
1699 | void KURL::setDirectory( const QString &dir) | ||
1700 | { | ||
1701 | //US this has to be fixed. endsWith is not available in my distribution | ||
1702 | //US if ( dir.endsWith("/")) | ||
1703 | //US setPath(dir); | ||
1704 | //US else | ||
1705 | setPath(dir+"/"); | ||
1706 | } | ||
1707 | |||
1708 | void KURL::setQuery( const QString &_txt, int encoding_hint) | ||
1709 | { | ||
1710 | if (!_txt.length()) | ||
1711 | { | ||
1712 | m_strQuery_encoded = _txt; | ||
1713 | return; | ||
1714 | } | ||
1715 | if (_txt[0] =='?') | ||
1716 | m_strQuery_encoded = _txt.mid(1); | ||
1717 | else | ||
1718 | m_strQuery_encoded = _txt; | ||
1719 | |||
1720 | int l = m_strQuery_encoded.length(); | ||
1721 | int i = 0; | ||
1722 | QString result; | ||
1723 | while (i < l) | ||
1724 | { | ||
1725 | int s = i; | ||
1726 | // Re-encode. Break encoded string up according to the reserved | ||
1727 | // characters '&:;=/?' and re-encode part by part. | ||
1728 | while(i < l) | ||
1729 | { | ||
1730 | char c = m_strQuery_encoded[i].latin1(); | ||
1731 | if ((c == '&') || (c == ':') || (c == ';') || | ||
1732 | (c == '=') || (c == '/') || (c == '?')) | ||
1733 | break; | ||
1734 | i++; | ||
1735 | } | ||
1736 | if (i > s) | ||
1737 | { | ||
1738 | QString tmp = m_strQuery_encoded.mid(s, i-s); | ||
1739 | QString newTmp; | ||
1740 | decode( tmp, newTmp, tmp, encoding_hint, false ); | ||
1741 | result += tmp; | ||
1742 | } | ||
1743 | if (i < l) | ||
1744 | { | ||
1745 | result += m_strQuery_encoded[i]; | ||
1746 | i++; | ||
1747 | } | ||
1748 | } | ||
1749 | m_strQuery_encoded = result; | ||
1750 | } | ||
1751 | |||
1752 | QString KURL::query() const | ||
1753 | { | ||
1754 | if (m_strQuery_encoded.isNull()) | ||
1755 | return QString::null; | ||
1756 | return '?'+m_strQuery_encoded; | ||
1757 | } | ||
1758 | |||
1759 | QString KURL::decode_string(const QString &str, int encoding_hint) | ||
1760 | { | ||
1761 | return decode(str, encoding_hint); | ||
1762 | } | ||
1763 | |||
1764 | QString KURL::encode_string(const QString &str, int encoding_hint) | ||
1765 | { | ||
1766 | return encode(str, false, encoding_hint); | ||
1767 | } | ||
1768 | |||
1769 | QString KURL::encode_string_no_slash(const QString &str, int encoding_hint) | ||
1770 | { | ||
1771 | return encode(str, true, encoding_hint); | ||
1772 | } | ||
1773 | |||
1774 | bool urlcmp( const QString& _url1, const QString& _url2 ) | ||
1775 | { | ||
1776 | // Both empty ? | ||
1777 | if ( _url1.isEmpty() && _url2.isEmpty() ) | ||
1778 | return true; | ||
1779 | // Only one empty ? | ||
1780 | if ( _url1.isEmpty() || _url2.isEmpty() ) | ||
1781 | return false; | ||
1782 | |||
1783 | KURL::List list1 = KURL::split( _url1 ); | ||
1784 | KURL::List list2 = KURL::split( _url2 ); | ||
1785 | |||
1786 | // Malformed ? | ||
1787 | if ( list1.isEmpty() || list2.isEmpty() ) | ||
1788 | return false; | ||
1789 | |||
1790 | return ( list1 == list2 ); | ||
1791 | } | ||
1792 | |||
1793 | bool urlcmp( const QString& _url1, const QString& _url2, bool _ignore_trailing, bool _ignore_ref ) | ||
1794 | { | ||
1795 | // Both empty ? | ||
1796 | if ( _url1.isEmpty() && _url2.isEmpty() ) | ||
1797 | return true; | ||
1798 | // Only one empty ? | ||
1799 | if ( _url1.isEmpty() || _url2.isEmpty() ) | ||
1800 | return false; | ||
1801 | |||
1802 | KURL::List list1 = KURL::split( _url1 ); | ||
1803 | KURL::List list2 = KURL::split( _url2 ); | ||
1804 | |||
1805 | // Malformed ? | ||
1806 | if ( list1.isEmpty() || list2.isEmpty() ) | ||
1807 | return false; | ||
1808 | |||
1809 | unsigned int size = list1.count(); | ||
1810 | if ( list2.count() != size ) | ||
1811 | return false; | ||
1812 | |||
1813 | if ( _ignore_ref ) | ||
1814 | { | ||
1815 | (*list1.begin()).setRef(QString::null); | ||
1816 | (*list2.begin()).setRef(QString::null); | ||
1817 | } | ||
1818 | |||
1819 | KURL::List::Iterator it1 = list1.begin(); | ||
1820 | KURL::List::Iterator it2 = list2.begin(); | ||
1821 | for( ; it1 != list1.end() ; ++it1, ++it2 ) | ||
1822 | if ( !(*it1).equals( *it2, _ignore_trailing ) ) | ||
1823 | return false; | ||
1824 | |||
1825 | return true; | ||
1826 | } | ||
1827 | /*US we do not need this functions | ||
1828 | |||
1829 | QMap< QString, QString > KURL::queryItems( int options ) const { | ||
1830 | return queryItems(options, 0); | ||
1831 | } | ||
1832 | |||
1833 | QMap< QString, QString > KURL::queryItems( int options, int encoding_hint ) const { | ||
1834 | if ( m_strQuery_encoded.isEmpty() ) | ||
1835 | return QMap<QString,QString>(); | ||
1836 | |||
1837 | QMap< QString, QString > result; | ||
1838 | QStringList items = QStringList::split( '&', m_strQuery_encoded ); | ||
1839 | for ( QStringList::const_iterator it = items.begin() ; it != items.end() ; ++it ) { | ||
1840 | int equal_pos = (*it).find( '=' ); | ||
1841 | if ( equal_pos > 0 ) { // = is not the first char... | ||
1842 | QString name = (*it).left( equal_pos ); | ||
1843 | if ( options & CaseInsensitiveKeys ) | ||
1844 | name = name.lower(); | ||
1845 | QString value = (*it).mid( equal_pos + 1 ); | ||
1846 | if ( value.isEmpty() ) | ||
1847 | result.insert( name, QString::fromLatin1("") ); | ||
1848 | else { | ||
1849 | // ### why is decoding name not neccessary? | ||
1850 | value.replace( '+', ' ' ); // + in queries means space | ||
1851 | result.insert( name, decode_string( value, encoding_hint ) ); | ||
1852 | } | ||
1853 | } else if ( equal_pos < 0 ) { // no = | ||
1854 | QString name = (*it); | ||
1855 | if ( options & CaseInsensitiveKeys ) | ||
1856 | name = name.lower(); | ||
1857 | result.insert( name, QString::null ); | ||
1858 | } | ||
1859 | } | ||
1860 | |||
1861 | return result; | ||
1862 | } | ||
1863 | |||
1864 | QString KURL::queryItem( const QString& _item ) const | ||
1865 | { | ||
1866 | return queryItem( _item, 0 ); | ||
1867 | } | ||
1868 | |||
1869 | QString KURL::queryItem( const QString& _item, int encoding_hint ) const | ||
1870 | { | ||
1871 | QString item = _item + '='; | ||
1872 | if ( m_strQuery_encoded.length() <= 1 ) | ||
1873 | return QString::null; | ||
1874 | |||
1875 | QStringList items = QStringList::split( '&', m_strQuery_encoded ); | ||
1876 | unsigned int _len = item.length(); | ||
1877 | for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it ) | ||
1878 | { | ||
1879 | if ( (*it).startsWith( item ) ) | ||
1880 | { | ||
1881 | if ( (*it).length() > _len ) | ||
1882 | { | ||
1883 | QString str = (*it).mid( _len ); | ||
1884 | str.replace( '+', ' ' ); // + in queries means space. | ||
1885 | return decode_string( str, encoding_hint ); | ||
1886 | } | ||
1887 | else // empty value | ||
1888 | return QString::fromLatin1(""); | ||
1889 | } | ||
1890 | } | ||
1891 | |||
1892 | return QString::null; | ||
1893 | } | ||
1894 | US we do not need this functions*/ | ||
1895 | |||
1896 | void KURL::removeQueryItem( const QString& _item ) | ||
1897 | { | ||
1898 | QString item = _item + '='; | ||
1899 | if ( m_strQuery_encoded.length() <= 1 ) | ||
1900 | return; | ||
1901 | |||
1902 | QStringList items = QStringList::split( '&', m_strQuery_encoded ); | ||
1903 | for ( QStringList::Iterator it = items.begin(); it != items.end(); ) | ||
1904 | { | ||
1905 | if ( (*it).startsWith( item ) || (*it == _item) ) | ||
1906 | { | ||
1907 | QStringList::Iterator deleteIt = it; | ||
1908 | ++it; | ||
1909 | items.remove(deleteIt); | ||
1910 | } | ||
1911 | else | ||
1912 | { | ||
1913 | ++it; | ||
1914 | } | ||
1915 | } | ||
1916 | m_strQuery_encoded = items.join( "&" ); | ||
1917 | } | ||
1918 | |||
1919 | void KURL::addQueryItem( const QString& _item, const QString& _value, int encoding_hint ) | ||
1920 | { | ||
1921 | QString item = _item + '='; | ||
1922 | QString value = encode( _value, true, encoding_hint ); | ||
1923 | |||
1924 | if (!m_strQuery_encoded.isEmpty()) | ||
1925 | m_strQuery_encoded += '&'; | ||
1926 | m_strQuery_encoded += item + value; | ||
1927 | } | ||
1928 | |||
1929 | // static | ||
1930 | KURL KURL::fromPathOrURL( const QString& text ) | ||
1931 | { | ||
1932 | if ( text.isEmpty() ) | ||
1933 | return KURL(); | ||
1934 | |||
1935 | KURL url; | ||
1936 | if ( text[0] == '/' ) | ||
1937 | url.setPath( text ); | ||
1938 | else | ||
1939 | url = text; | ||
1940 | |||
1941 | return url; | ||
1942 | } | ||