]> git.saurik.com Git - wxWidgets.git/blame - src/common/uri.cpp
More wxUSE_STATTEXT fixes
[wxWidgets.git] / src / common / uri.cpp
CommitLineData
dd65d8c8
RN
1/////////////////////////////////////////////////////////////////////////////
2// Name: uri.cpp
3// Purpose: Implementation of a uri parser
4// Author: Ryan Norton
5// Created: 10/26/04
6// RCS-ID: $Id$
7// Copyright: (c) 2004 Ryan Norton
8// Licence: wxWindows
9/////////////////////////////////////////////////////////////////////////////
10
11// ===========================================================================
12// declarations
13// ===========================================================================
14
15// ---------------------------------------------------------------------------
16// headers
17// ---------------------------------------------------------------------------
18
19#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
20 #pragma implementation "uri.h"
21#endif
22
23// For compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
25
26#ifdef __BORLANDC__
27 #pragma hdrstop
28#endif
29
30#include "wx/uri.h"
31
32// ---------------------------------------------------------------------------
33// definitions
34// ---------------------------------------------------------------------------
35
36IMPLEMENT_CLASS(wxURI, wxObject);
37
38// ===========================================================================
39// implementation
40// ===========================================================================
41
42// ---------------------------------------------------------------------------
43// utilities
44// ---------------------------------------------------------------------------
45
46// ---------------------------------------------------------------------------
47//
48// wxURI
49//
50// ---------------------------------------------------------------------------
51
52// ---------------------------------------------------------------------------
53// Constructors
54// ---------------------------------------------------------------------------
55
56wxURI::wxURI() : m_hostType(wxURI_REGNAME), m_fields(0)
57{
58}
846978d7 59
dd65d8c8
RN
60wxURI::wxURI(const wxString& uri) : m_hostType(wxURI_REGNAME), m_fields(0)
61{
62 Create(uri);
63}
64
60431236 65wxURI::wxURI(const wxURI& uri) : wxObject(), m_hostType(wxURI_REGNAME), m_fields(0)
dd65d8c8 66{
b60b2ec8 67 Assign(uri);
dd65d8c8
RN
68}
69
70// ---------------------------------------------------------------------------
71// Destructor and cleanup
72// ---------------------------------------------------------------------------
73
74wxURI::~wxURI()
75{
76 Clear();
77}
78
79void wxURI::Clear()
80{
4860d40d 81 m_scheme = m_userinfo = m_server = m_port = m_path =
525d8583 82 m_query = m_fragment = wxEmptyString;
dd65d8c8
RN
83
84 m_hostType = wxURI_REGNAME;
85
86 m_fields = 0;
87}
88
89// ---------------------------------------------------------------------------
90// Create
91//
846978d7 92// This creates the URI - all we do here is call the main parsing method
dd65d8c8
RN
93// ---------------------------------------------------------------------------
94
86470d43 95const wxChar* wxURI::Create(const wxString& uri)
846978d7 96{
dd65d8c8
RN
97 if (m_fields)
98 Clear();
99
846978d7
WS
100 return Parse(uri);
101}
dd65d8c8
RN
102
103// ---------------------------------------------------------------------------
ce321570 104// Escape Methods
dd65d8c8 105//
846978d7 106// TranslateEscape unencodes a 3 character URL escape sequence
ce321570 107//
dd65d8c8 108// Escape encodes an invalid URI character into a 3 character sequence
ce321570 109//
dd65d8c8
RN
110// IsEscape determines if the input string contains an escape sequence,
111// if it does, then it moves the input string past the escape sequence
ce321570
RN
112//
113// Unescape unencodes all 3 character URL escape sequences in a wxString
dd65d8c8
RN
114// ---------------------------------------------------------------------------
115
86470d43 116wxChar wxURI::TranslateEscape(const wxChar* s)
dd65d8c8
RN
117{
118 wxASSERT_MSG(IsHex(*s) && IsHex(*(s+1)), wxT("Invalid escape!"));
8404931e 119
d8d7193d 120 //<<4 == 16
6356d52a 121 return (wxChar)( CharToHex(*s) << 4 ) | CharToHex(*++s);
dd65d8c8
RN
122}
123
86470d43
RN
124wxString wxURI::Unescape(const wxString& uri)
125{
126 wxString new_uri;
127
128 for(size_t i = 0; i < uri.length(); ++i)
129 {
130 if (uri[i] == wxT('%'))
131 {
132 new_uri += wxURI::TranslateEscape( &(uri.c_str()[i+1]) );
133 i += 2;
134 }
d8d7193d
RN
135 else
136 new_uri += uri[i];
86470d43
RN
137 }
138
139 return new_uri;
140}
141
dd65d8c8
RN
142void wxURI::Escape(wxString& s, const wxChar& c)
143{
144 const wxChar* hdig = wxT("0123456789abcdef");
ce321570 145 s += wxT('%');
dd65d8c8 146 s += hdig[(c >> 4) & 15];
846978d7 147 s += hdig[c & 15];
dd65d8c8
RN
148}
149
150bool wxURI::IsEscape(const wxChar*& uri)
151{
ce321570
RN
152 // pct-encoded = "%" HEXDIG HEXDIG
153 if(*uri == wxT('%') && IsHex(*(uri+1)) && IsHex(*(uri+2)))
dd65d8c8
RN
154 {
155 uri += 3;
156 return true;
157 }
158 else
159 return false;
160}
161
4860d40d
RN
162// ---------------------------------------------------------------------------
163// GetUser
164// GetPassword
165//
166// Gets the username and password via the old URL method.
167// ---------------------------------------------------------------------------
168wxString wxURI::GetUser() const
169{
170 size_t dwPasswordPos = m_userinfo.find(':');
171
172 if (dwPasswordPos == wxString::npos)
173 dwPasswordPos = 0;
174
175 return m_userinfo(0, dwPasswordPos);
176}
177
178wxString wxURI::GetPassword() const
179{
180 size_t dwPasswordPos = m_userinfo.find(':');
181
182 if (dwPasswordPos == wxString::npos)
183 return wxT("");
184 else
185 return m_userinfo(dwPasswordPos+1, m_userinfo.length() + 1);
186}
187
dd65d8c8 188// ---------------------------------------------------------------------------
86470d43 189// BuildURI
dd65d8c8 190//
846978d7 191// BuildURI() builds the entire URI into a useable
dd65d8c8 192// representation, including proper identification characters such as slashes
ce321570
RN
193//
194// BuildUnescapedURI() does the same thing as BuildURI(), only it unescapes
195// the components that accept escape sequences
dd65d8c8
RN
196// ---------------------------------------------------------------------------
197
86470d43 198wxString wxURI::BuildURI() const
846978d7 199{
dd65d8c8
RN
200 wxString ret;
201
202 if (HasScheme())
203 ret = ret + m_scheme + wxT(":");
204
205 if (HasServer())
206 {
207 ret += wxT("//");
208
4860d40d
RN
209 if (HasUserInfo())
210 ret = ret + m_userinfo + wxT("@");
dd65d8c8
RN
211
212 ret += m_server;
213
214 if (HasPort())
215 ret = ret + wxT(":") + m_port;
216 }
217
218 ret += m_path;
219
220 if (HasQuery())
221 ret = ret + wxT("?") + m_query;
222
223 if (HasFragment())
224 ret = ret + wxT("#") + m_fragment;
225
226 return ret;
227}
228
86470d43
RN
229wxString wxURI::BuildUnescapedURI() const
230{
231 wxString ret;
232
233 if (HasScheme())
234 ret = ret + m_scheme + wxT(":");
235
236 if (HasServer())
237 {
238 ret += wxT("//");
239
4860d40d
RN
240 if (HasUserInfo())
241 ret = ret + wxURI::Unescape(m_userinfo) + wxT("@");
86470d43
RN
242
243 if (m_hostType == wxURI_REGNAME)
244 ret += wxURI::Unescape(m_server);
245 else
246 ret += m_server;
247
248 if (HasPort())
249 ret = ret + wxT(":") + m_port;
250 }
251
252 ret += wxURI::Unescape(m_path);
253
254 if (HasQuery())
255 ret = ret + wxT("?") + wxURI::Unescape(m_query);
256
257 if (HasFragment())
258 ret = ret + wxT("#") + wxURI::Unescape(m_fragment);
259
260 return ret;
261}
262
dd65d8c8 263// ---------------------------------------------------------------------------
ce321570 264// Assignment
dd65d8c8
RN
265// ---------------------------------------------------------------------------
266
b60b2ec8
RN
267wxURI& wxURI::Assign(const wxURI& uri)
268{
269 //assign fields
270 m_fields = uri.m_fields;
271
272 //ref over components
273 m_scheme = uri.m_scheme;
4860d40d 274 m_userinfo = uri.m_userinfo;
b60b2ec8
RN
275 m_server = uri.m_server;
276 m_hostType = uri.m_hostType;
277 m_port = uri.m_port;
278 m_path = uri.m_path;
279 m_query = uri.m_query;
280 m_fragment = uri.m_fragment;
dd65d8c8
RN
281
282 return *this;
283}
284
ce321570
RN
285wxURI& wxURI::operator = (const wxURI& uri)
286{
287 return Assign(uri);
288}
289
b60b2ec8 290wxURI& wxURI::operator = (const wxString& string)
846978d7 291{
dd65d8c8
RN
292 Create(string);
293 return *this;
294}
295
ce321570
RN
296// ---------------------------------------------------------------------------
297// Comparison
298// ---------------------------------------------------------------------------
299
dd65d8c8 300bool wxURI::operator == (const wxURI& uri) const
846978d7 301{
dd65d8c8
RN
302 if (HasScheme())
303 {
304 if(m_scheme != uri.m_scheme)
305 return false;
306 }
307 else if (uri.HasScheme())
308 return false;
309
310
311 if (HasServer())
312 {
4860d40d 313 if (HasUserInfo())
dd65d8c8 314 {
4860d40d 315 if (m_userinfo != uri.m_userinfo)
dd65d8c8
RN
316 return false;
317 }
4860d40d 318 else if (uri.HasUserInfo())
dd65d8c8
RN
319 return false;
320
321 if (m_server != uri.m_server ||
322 m_hostType != uri.m_hostType)
323 return false;
324
325 if (HasPort())
326 {
327 if(m_port != uri.m_port)
328 return false;
329 }
330 else if (uri.HasPort())
331 return false;
332 }
333 else if (uri.HasServer())
334 return false;
335
336
337 if (HasPath())
338 {
339 if(m_path != uri.m_path)
340 return false;
341 }
342 else if (uri.HasPath())
343 return false;
344
345 if (HasQuery())
346 {
347 if (m_query != uri.m_query)
348 return false;
349 }
350 else if (uri.HasQuery())
351 return false;
352
353 if (HasFragment())
354 {
355 if (m_fragment != uri.m_fragment)
356 return false;
357 }
358 else if (uri.HasFragment())
359 return false;
360
361 return true;
362}
363
364// ---------------------------------------------------------------------------
365// IsReference
366//
367// if there is no authority or scheme, it is a reference
368// ---------------------------------------------------------------------------
369
370bool wxURI::IsReference() const
371{ return !HasScheme() || !HasServer(); }
372
373// ---------------------------------------------------------------------------
374// Parse
375//
376// Master URI parsing method. Just calls the individual parsing methods
377//
378// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
379// URI-reference = URI / relative-URITestCase
380// ---------------------------------------------------------------------------
381
382const wxChar* wxURI::Parse(const wxChar* uri)
383{
384 uri = ParseScheme(uri);
385 uri = ParseAuthority(uri);
386 uri = ParsePath(uri);
387 uri = ParseQuery(uri);
388 return ParseFragment(uri);
389}
390
391// ---------------------------------------------------------------------------
392// ParseXXX
393//
394// Individual parsers for each URI component
395// ---------------------------------------------------------------------------
396
397const wxChar* wxURI::ParseScheme(const wxChar* uri)
398{
399 wxASSERT(uri != NULL);
400
401 //copy of the uri - used for figuring out
402 //length of each component
403 const wxChar* uricopy = uri;
404
405 //Does the uri have a scheme (first character alpha)?
406 if (IsAlpha(*uri))
407 {
408 m_scheme += *uri++;
409
410 //scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
846978d7 411 while (IsAlpha(*uri) || IsDigit(*uri) ||
ce321570
RN
412 *uri == wxT('+') ||
413 *uri == wxT('-') ||
846978d7
WS
414 *uri == wxT('.'))
415 {
416 m_scheme += *uri++;
dd65d8c8
RN
417 }
418
419 //valid scheme?
ce321570 420 if (*uri == wxT(':'))
846978d7 421 {
dd65d8c8
RN
422 //mark the scheme as valid
423 m_fields |= wxURI_SCHEME;
424
425 //move reference point up to input buffer
426 uricopy = ++uri;
427 }
846978d7 428 else
dd65d8c8 429 //relative uri with relative path reference
525d8583 430 m_scheme = wxEmptyString;
dd65d8c8 431 }
846978d7 432// else
dd65d8c8
RN
433 //relative uri with _possible_ relative path reference
434
435 return uricopy;
436}
437
438const wxChar* wxURI::ParseAuthority(const wxChar* uri)
439{
440 // authority = [ userinfo "@" ] host [ ":" port ]
846978d7 441 if (*uri == wxT('/') && *(uri+1) == wxT('/'))
dd65d8c8
RN
442 {
443 uri += 2;
444
4860d40d 445 uri = ParseUserInfo(uri);
dd65d8c8
RN
446 uri = ParseServer(uri);
447 return ParsePort(uri);
448 }
449
450 return uri;
451}
452
4860d40d 453const wxChar* wxURI::ParseUserInfo(const wxChar* uri)
dd65d8c8
RN
454{
455 wxASSERT(uri != NULL);
456
457 //copy of the uri - used for figuring out
458 //length of each component
459 const wxChar* uricopy = uri;
460
461 // userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
846978d7 462 while(*uri && *uri != wxT('@') && *uri != wxT('/') && *uri != wxT('#') && *uri != wxT('?'))
dd65d8c8 463 {
846978d7 464 if(IsUnreserved(*uri) || IsEscape(uri) ||
ce321570 465 IsSubDelim(*uri) || *uri == wxT(':'))
4860d40d 466 m_userinfo += *uri++;
dd65d8c8 467 else
4860d40d 468 Escape(m_userinfo, *uri++);
dd65d8c8
RN
469 }
470
ce321570 471 if(*uri == wxT('@'))
dd65d8c8
RN
472 {
473 //valid userinfo
4860d40d 474 m_fields |= wxURI_USERINFO;
dd65d8c8
RN
475
476 uricopy = ++uri;
477 }
478 else
4860d40d 479 m_userinfo = wxEmptyString;
dd65d8c8
RN
480
481 return uricopy;
482}
483
484const wxChar* wxURI::ParseServer(const wxChar* uri)
485{
486 wxASSERT(uri != NULL);
487
488 //copy of the uri - used for figuring out
489 //length of each component
490 const wxChar* uricopy = uri;
491
492 // host = IP-literal / IPv4address / reg-name
493 // IP-literal = "[" ( IPv6address / IPvFuture ) "]"
ce321570 494 if (*uri == wxT('['))
dd65d8c8 495 {
e854db32
RN
496 ++uri; //some compilers don't support *&ing a ++*
497 if (ParseIPv6address(uri) && *uri == wxT(']'))
dd65d8c8
RN
498 {
499 ++uri;
500 m_hostType = wxURI_IPV6ADDRESS;
846978d7 501
dd65d8c8 502 wxStringBufferLength theBuffer(m_server, uri - uricopy);
2c09fb3b 503 wxTmemcpy(theBuffer, uricopy, uri-uricopy);
dd65d8c8
RN
504 theBuffer.SetLength(uri-uricopy);
505 }
506 else
507 {
508 uri = uricopy;
509
e854db32
RN
510 ++uri; //some compilers don't support *&ing a ++*
511 if (ParseIPvFuture(uri) && *uri == wxT(']'))
dd65d8c8
RN
512 {
513 ++uri;
846978d7
WS
514 m_hostType = wxURI_IPVFUTURE;
515
dd65d8c8 516 wxStringBufferLength theBuffer(m_server, uri - uricopy);
2c09fb3b 517 wxTmemcpy(theBuffer, uricopy, uri-uricopy);
dd65d8c8
RN
518 theBuffer.SetLength(uri-uricopy);
519 }
846978d7 520 else
dd65d8c8
RN
521 uri = uricopy;
522 }
523 }
846978d7 524 else
dd65d8c8
RN
525 {
526 if (ParseIPv4address(uri))
527 {
528 m_hostType = wxURI_IPV4ADDRESS;
529
530 wxStringBufferLength theBuffer(m_server, uri - uricopy);
2c09fb3b 531 wxTmemcpy(theBuffer, uricopy, uri-uricopy);
dd65d8c8
RN
532 theBuffer.SetLength(uri-uricopy);
533 }
846978d7 534 else
dd65d8c8
RN
535 uri = uricopy;
536 }
537
538 if(m_hostType == wxURI_REGNAME)
539 {
540 uri = uricopy;
541 // reg-name = *( unreserved / pct-encoded / sub-delims )
846978d7 542 while(*uri && *uri != wxT('/') && *uri != wxT(':') && *uri != wxT('#') && *uri != wxT('?'))
dd65d8c8
RN
543 {
544 if(IsUnreserved(*uri) || IsEscape(uri) || IsSubDelim(*uri))
545 m_server += *uri++;
546 else
547 Escape(m_server, *uri++);
846978d7 548 }
dd65d8c8
RN
549 }
550
551 //mark the server as valid
552 m_fields |= wxURI_SERVER;
553
554 return uri;
555}
556
846978d7 557
dd65d8c8
RN
558const wxChar* wxURI::ParsePort(const wxChar* uri)
559{
560 wxASSERT(uri != NULL);
561
562 // port = *DIGIT
ce321570 563 if(*uri == wxT(':'))
dd65d8c8
RN
564 {
565 ++uri;
846978d7 566 while(IsDigit(*uri))
dd65d8c8
RN
567 {
568 m_port += *uri++;
846978d7 569 }
dd65d8c8
RN
570
571 //mark the port as valid
572 m_fields |= wxURI_PORT;
573 }
574
575 return uri;
576}
577
8404931e 578const wxChar* wxURI::ParsePath(const wxChar* uri, bool bReference, bool bNormalize)
dd65d8c8
RN
579{
580 wxASSERT(uri != NULL);
581
582 //copy of the uri - used for figuring out
583 //length of each component
584 const wxChar* uricopy = uri;
585
586 /// hier-part = "//" authority path-abempty
587 /// / path-absolute
588 /// / path-rootless
589 /// / path-empty
590 ///
591 /// relative-part = "//" authority path-abempty
592 /// / path-absolute
593 /// / path-noscheme
594 /// / path-empty
595 ///
596 /// path-abempty = *( "/" segment )
597 /// path-absolute = "/" [ segment-nz *( "/" segment ) ]
598 /// path-noscheme = segment-nz-nc *( "/" segment )
599 /// path-rootless = segment-nz *( "/" segment )
600 /// path-empty = 0<pchar>
601 ///
602 /// segment = *pchar
603 /// segment-nz = 1*pchar
604 /// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
605 /// ; non-zero-length segment without any colon ":"
606 ///
607 /// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
ce321570 608 if (*uri == wxT('/'))
dd65d8c8
RN
609 {
610 m_path += *uri++;
611
846978d7
WS
612 while(*uri && *uri != wxT('#') && *uri != wxT('?'))
613 {
dd65d8c8 614 if( IsUnreserved(*uri) || IsSubDelim(*uri) || IsEscape(uri) ||
ce321570 615 *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/'))
846978d7
WS
616 m_path += *uri++;
617 else
618 Escape(m_path, *uri++);
dd65d8c8
RN
619 }
620
621 if (bNormalize)
622 {
623 wxStringBufferLength theBuffer(m_path, m_path.length() + 1);
d21d3f21 624#if wxUSE_STL
2c09fb3b 625 wxTmemcpy(theBuffer, m_path.c_str(), m_path.length()+1);
d21d3f21 626#endif
dd65d8c8
RN
627 Normalize(theBuffer, true);
628 theBuffer.SetLength(wxStrlen(theBuffer));
629 }
630 //mark the path as valid
631 m_fields |= wxURI_PATH;
632 }
633 else if(*uri) //Relative path
634 {
635 if (bReference)
636 {
637 //no colon allowed
846978d7 638 while(*uri && *uri != wxT('#') && *uri != wxT('?'))
dd65d8c8
RN
639 {
640 if(IsUnreserved(*uri) || IsSubDelim(*uri) || IsEscape(uri) ||
ce321570 641 *uri == wxT('@') || *uri == wxT('/'))
846978d7
WS
642 m_path += *uri++;
643 else
644 Escape(m_path, *uri++);
dd65d8c8 645 }
846978d7 646 }
dd65d8c8
RN
647 else
648 {
846978d7 649 while(*uri && *uri != wxT('#') && *uri != wxT('?'))
dd65d8c8
RN
650 {
651 if(IsUnreserved(*uri) || IsSubDelim(*uri) || IsEscape(uri) ||
ce321570 652 *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/'))
846978d7
WS
653 m_path += *uri++;
654 else
655 Escape(m_path, *uri++);
dd65d8c8
RN
656 }
657 }
658
659 if (uri != uricopy)
846978d7 660 {
dd65d8c8
RN
661 if (bNormalize)
662 {
663 wxStringBufferLength theBuffer(m_path, m_path.length() + 1);
d21d3f21 664#if wxUSE_STL
2c09fb3b 665 wxTmemcpy(theBuffer, m_path.c_str(), m_path.length()+1);
d21d3f21 666#endif
dd65d8c8
RN
667 Normalize(theBuffer);
668 theBuffer.SetLength(wxStrlen(theBuffer));
669 }
670
671 //mark the path as valid
672 m_fields |= wxURI_PATH;
673 }
674 }
675
676 return uri;
677}
678
679
680const wxChar* wxURI::ParseQuery(const wxChar* uri)
681{
682 wxASSERT(uri != NULL);
683
684 // query = *( pchar / "/" / "?" )
ce321570 685 if (*uri == wxT('?'))
dd65d8c8
RN
686 {
687 ++uri;
ce321570 688 while(*uri && *uri != wxT('#'))
dd65d8c8
RN
689 {
690 if (IsUnreserved(*uri) || IsSubDelim(*uri) || IsEscape(uri) ||
ce321570 691 *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/') || *uri == wxT('?'))
846978d7 692 m_query += *uri++;
dd65d8c8 693 else
846978d7 694 Escape(m_query, *uri++);
dd65d8c8
RN
695 }
696
697 //mark the server as valid
698 m_fields |= wxURI_QUERY;
699 }
700
701 return uri;
702}
703
704
705const wxChar* wxURI::ParseFragment(const wxChar* uri)
706{
707 wxASSERT(uri != NULL);
708
709 // fragment = *( pchar / "/" / "?" )
ce321570 710 if (*uri == wxT('#'))
dd65d8c8
RN
711 {
712 ++uri;
713 while(*uri)
714 {
715 if (IsUnreserved(*uri) || IsSubDelim(*uri) || IsEscape(uri) ||
ce321570 716 *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/') || *uri == wxT('?'))
846978d7 717 m_fragment += *uri++;
dd65d8c8 718 else
846978d7 719 Escape(m_fragment, *uri++);
dd65d8c8
RN
720 }
721
722 //mark the server as valid
723 m_fields |= wxURI_FRAGMENT;
724 }
725
726 return uri;
727}
728
729// ---------------------------------------------------------------------------
ce321570 730// Resolve
dd65d8c8 731//
ce321570 732// Builds missing components of this uri from a base uri
dd65d8c8 733//
ce321570
RN
734// A version of the algorithm outlined in the RFC is used here
735// (it is shown in comments)
736//
846978d7 737// Note that an empty URI inherits all components
dd65d8c8
RN
738// ---------------------------------------------------------------------------
739
8404931e 740void wxURI::Resolve(const wxURI& base, int flags)
dd65d8c8 741{
846978d7 742 wxASSERT_MSG(!base.IsReference(),
dd65d8c8
RN
743 wxT("wxURI to inherit from must not be a reference!"));
744
ce321570 745 // If we arn't being strict, enable the older (pre-RFC2396)
dd65d8c8
RN
746 // loophole that allows this uri to inherit other
747 // properties from the base uri - even if the scheme
748 // is defined
8404931e
VZ
749 if ( !(flags & wxURI_STRICT) &&
750 HasScheme() && base.HasScheme() &&
751 m_scheme == base.m_scheme )
846978d7 752 {
dd65d8c8
RN
753 m_fields -= wxURI_SCHEME;
754 }
755
756
757 // Do nothing if this is an absolute wxURI
758 // if defined(R.scheme) then
759 // T.scheme = R.scheme;
760 // T.authority = R.authority;
761 // T.path = remove_dot_segments(R.path);
762 // T.query = R.query;
763 if (HasScheme())
764 {
765 return;
766 }
767
ea4daac4 768 //No scheme - inherit
dd65d8c8
RN
769 m_scheme = base.m_scheme;
770 m_fields |= wxURI_SCHEME;
771
772 // All we need to do for relative URIs with an
773 // authority component is just inherit the scheme
774 // if defined(R.authority) then
775 // T.authority = R.authority;
776 // T.path = remove_dot_segments(R.path);
777 // T.query = R.query;
778 if (HasServer())
779 {
780 return;
781 }
782
783 //No authority - inherit
4860d40d 784 if (base.HasUserInfo())
dd65d8c8 785 {
4860d40d
RN
786 m_userinfo = base.m_userinfo;
787 m_fields |= wxURI_USERINFO;
dd65d8c8 788 }
846978d7 789
dd65d8c8
RN
790 m_server = base.m_server;
791 m_hostType = base.m_hostType;
792 m_fields |= wxURI_SERVER;
846978d7 793
dd65d8c8
RN
794 if (base.HasPort())
795 {
796 m_port = base.m_port;
797 m_fields |= wxURI_PORT;
798 }
846978d7 799
dd65d8c8
RN
800
801 // Simple path inheritance from base
802 if (!HasPath())
803 {
804 // T.path = Base.path;
805 m_path = base.m_path;
806 m_fields |= wxURI_PATH;
846978d7 807
dd65d8c8
RN
808
809 // if defined(R.query) then
810 // T.query = R.query;
811 // else
812 // T.query = Base.query;
813 // endif;
814 if (!HasQuery())
815 {
816 m_query = base.m_query;
817 m_fields |= wxURI_QUERY;
818 }
819 }
820 else
821 {
822 // if (R.path starts-with "/") then
823 // T.path = remove_dot_segments(R.path);
824 // else
825 // T.path = merge(Base.path, R.path);
826 // T.path = remove_dot_segments(T.path);
827 // endif;
828 // T.query = R.query;
ce321570 829 if (m_path[0u] != wxT('/'))
dd65d8c8 830 {
ea4daac4 831 //Merge paths
dd65d8c8
RN
832 const wxChar* op = m_path.c_str();
833 const wxChar* bp = base.m_path.c_str() + base.m_path.Length();
834
835 //not a ending directory? move up
ce321570 836 if (base.m_path[0] && *(bp-1) != wxT('/'))
dd65d8c8
RN
837 UpTree(base.m_path, bp);
838
839 //normalize directories
846978d7 840 while(*op == wxT('.') && *(op+1) == wxT('.') &&
ce321570 841 (*(op+2) == '\0' || *(op+2) == wxT('/')) )
dd65d8c8
RN
842 {
843 UpTree(base.m_path, bp);
844
845 if (*(op+2) == '\0')
846 op += 2;
847 else
848 op += 3;
849 }
850
846978d7 851 m_path = base.m_path.substr(0, bp - base.m_path.c_str()) +
ba5a47ae 852 m_path.substr((op - m_path.c_str()), m_path.Length());
dd65d8c8
RN
853 }
854 }
ce321570 855
846978d7 856 //T.fragment = R.fragment;
dd65d8c8
RN
857}
858
859// ---------------------------------------------------------------------------
846978d7 860// UpTree
dd65d8c8 861//
ce321570 862// Moves a URI path up a directory
dd65d8c8
RN
863// ---------------------------------------------------------------------------
864
ce321570 865//static
dd65d8c8
RN
866void wxURI::UpTree(const wxChar* uristart, const wxChar*& uri)
867{
ce321570 868 if (uri != uristart && *(uri-1) == wxT('/'))
dd65d8c8
RN
869 {
870 uri -= 2;
871 }
846978d7 872
dd65d8c8
RN
873 for(;uri != uristart; --uri)
874 {
ce321570 875 if (*uri == wxT('/'))
dd65d8c8
RN
876 {
877 ++uri;
878 break;
879 }
880 }
881
882 //!!!TODO:HACK!!!//
ce321570 883 if (uri == uristart && *uri == wxT('/'))
dd65d8c8
RN
884 ++uri;
885 //!!!//
886}
887
ce321570
RN
888// ---------------------------------------------------------------------------
889// Normalize
890//
891// Normalizes directories in-place
892//
893// I.E. ./ and . are ignored
894//
895// ../ and .. are removed if a directory is before it, along
896// with that directory (leading .. and ../ are kept)
897// ---------------------------------------------------------------------------
898
899//static
8404931e 900void wxURI::Normalize(wxChar* s, bool bIgnoreLeads)
dd65d8c8
RN
901{
902 wxChar* cp = s;
903 wxChar* bp = s;
904
ce321570 905 if(s[0] == wxT('/'))
dd65d8c8
RN
906 ++bp;
907
908 while(*cp)
909 {
ce321570
RN
910 if (*cp == wxT('.') && (*(cp+1) == wxT('/') || *(cp+1) == '\0')
911 && (bp == cp || *(cp-1) == wxT('/')))
dd65d8c8
RN
912 {
913 //. _or_ ./ - ignore
914 if (*(cp+1) == '\0')
915 cp += 1;
916 else
917 cp += 2;
918 }
846978d7 919 else if (*cp == wxT('.') && *(cp+1) == wxT('.') &&
ce321570
RN
920 (*(cp+2) == wxT('/') || *(cp+2) == '\0')
921 && (bp == cp || *(cp-1) == wxT('/')))
dd65d8c8
RN
922 {
923 //.. _or_ ../ - go up the tree
924 if (s != bp)
925 {
926 UpTree((const wxChar*)bp, (const wxChar*&)s);
927
928 if (*(cp+2) == '\0')
929 cp += 2;
930 else
931 cp += 3;
932 }
933 else if (!bIgnoreLeads)
934
935 {
936 *bp++ = *cp++;
937 *bp++ = *cp++;
938 if (*cp)
939 *bp++ = *cp++;
940
941 s = bp;
942 }
943 else
944 {
945 if (*(cp+2) == '\0')
946 cp += 2;
947 else
948 cp += 3;
949 }
950 }
951 else
846978d7 952 *s++ = *cp++;
dd65d8c8
RN
953 }
954
955 *s = '\0';
956}
957
958// ---------------------------------------------------------------------------
ce321570
RN
959// ParseH16
960//
961// Parses 1 to 4 hex values. Returns true if the first character of the input
846978d7 962// string is a valid hex character. It is the caller's responsability to move
ce321570
RN
963// the input string back to its original position on failure.
964// ---------------------------------------------------------------------------
965
966bool wxURI::ParseH16(const wxChar*& uri)
967{
968 // h16 = 1*4HEXDIG
969 if(!IsHex(*++uri))
970 return false;
971
972 if(IsHex(*++uri) && IsHex(*++uri) && IsHex(*++uri))
973 ++uri;
974
975 return true;
976}
977
978// ---------------------------------------------------------------------------
979// ParseIPXXX
980//
846978d7
WS
981// Parses a certain version of an IP address and moves the input string past
982// it. Returns true if the input string contains the proper version of an ip
983// address. It is the caller's responsability to move the input string back
ce321570 984// to its original position on failure.
dd65d8c8
RN
985// ---------------------------------------------------------------------------
986
987bool wxURI::ParseIPv4address(const wxChar*& uri)
988{
989 //IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
990 //
991 //dec-octet = DIGIT ; 0-9
992 // / %x31-39 DIGIT ; 10-99
993 // / "1" 2DIGIT ; 100-199
994 // / "2" %x30-34 DIGIT ; 200-249
995 // / "25" %x30-35 ; 250-255
996 size_t iIPv4 = 0;
997 if (IsDigit(*uri))
998 {
999 ++iIPv4;
1000
846978d7 1001
dd65d8c8
RN
1002 //each ip part must be between 0-255 (dupe of version in for loop)
1003 if( IsDigit(*++uri) && IsDigit(*++uri) &&
1004 //100 or less (note !)
846978d7
WS
1005 !( (*(uri-2) < wxT('2')) ||
1006 //240 or less
1007 (*(uri-2) == wxT('2') &&
ce321570 1008 (*(uri-1) < wxT('5') || (*(uri-1) == wxT('5') && *uri <= wxT('5')))
dd65d8c8
RN
1009 )
1010 )
1011 )
1012 {
1013 return false;
1014 }
1015
1016 if(IsDigit(*uri))++uri;
1017
1018 //compilers should unroll this loop
1019 for(; iIPv4 < 4; ++iIPv4)
1020 {
ce321570 1021 if (*uri != wxT('.') || !IsDigit(*++uri))
dd65d8c8
RN
1022 break;
1023
1024 //each ip part must be between 0-255
1025 if( IsDigit(*++uri) && IsDigit(*++uri) &&
1026 //100 or less (note !)
846978d7
WS
1027 !( (*(uri-2) < wxT('2')) ||
1028 //240 or less
1029 (*(uri-2) == wxT('2') &&
ce321570 1030 (*(uri-1) < wxT('5') || (*(uri-1) == wxT('5') && *uri <= wxT('5')))
dd65d8c8
RN
1031 )
1032 )
1033 )
1034 {
1035 return false;
1036 }
1037 if(IsDigit(*uri))++uri;
1038 }
1039 }
1040 return iIPv4 == 4;
1041}
1042
dd65d8c8
RN
1043bool wxURI::ParseIPv6address(const wxChar*& uri)
1044{
1045 // IPv6address = 6( h16 ":" ) ls32
1046 // / "::" 5( h16 ":" ) ls32
1047 // / [ h16 ] "::" 4( h16 ":" ) ls32
1048 // / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
1049 // / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
1050 // / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
1051 // / [ *4( h16 ":" ) h16 ] "::" ls32
1052 // / [ *5( h16 ":" ) h16 ] "::" h16
1053 // / [ *6( h16 ":" ) h16 ] "::"
1054
1055 size_t numPrefix = 0,
1056 maxPostfix;
1057
1058 bool bEndHex = false;
1059
1060 for( ; numPrefix < 6; ++numPrefix)
1061 {
1062 if(!ParseH16(uri))
1063 {
1064 --uri;
1065 bEndHex = true;
1066 break;
1067 }
846978d7 1068
ce321570 1069 if(*uri != wxT(':'))
dd65d8c8
RN
1070 {
1071 break;
1072 }
1073 }
1074
1075 if(!bEndHex && !ParseH16(uri))
1076 {
1077 --uri;
1078
1079 if (numPrefix)
1080 return false;
1081
ce321570 1082 if (*uri == wxT(':'))
dd65d8c8 1083 {
ce321570 1084 if (*++uri != wxT(':'))
dd65d8c8
RN
1085 return false;
1086
1087 maxPostfix = 5;
1088 }
1089 else
1090 maxPostfix = 6;
1091 }
1092 else
1093 {
ce321570 1094 if (*uri != wxT(':') || *(uri+1) != wxT(':'))
dd65d8c8
RN
1095 {
1096 if (numPrefix != 6)
1097 return false;
1098
ce321570 1099 while (*--uri != wxT(':')) {}
dd65d8c8
RN
1100 ++uri;
1101
1102 const wxChar* uristart = uri;
1103 //parse ls32
1104 // ls32 = ( h16 ":" h16 ) / IPv4address
846978d7 1105 if (ParseH16(uri) && *uri == wxT(':') && ParseH16(uri))
dd65d8c8
RN
1106 return true;
1107
1108 uri = uristart;
1109
1110 if (ParseIPv4address(uri))
1111 return true;
1112 else
1113 return false;
1114 }
1115 else
1116 {
1117 uri += 2;
846978d7 1118
dd65d8c8
RN
1119 if (numPrefix > 3)
1120 maxPostfix = 0;
1121 else
1122 maxPostfix = 4 - numPrefix;
1123 }
1124 }
1125
1126 bool bAllowAltEnding = maxPostfix == 0;
1127
1128 for(; maxPostfix != 0; --maxPostfix)
1129 {
ce321570 1130 if(!ParseH16(uri) || *uri != wxT(':'))
dd65d8c8
RN
1131 return false;
1132 }
1133
1134 if(numPrefix <= 4)
1135 {
1136 const wxChar* uristart = uri;
1137 //parse ls32
1138 // ls32 = ( h16 ":" h16 ) / IPv4address
846978d7 1139 if (ParseH16(uri) && *uri == wxT(':') && ParseH16(uri))
dd65d8c8
RN
1140 return true;
1141
1142 uri = uristart;
1143
1144 if (ParseIPv4address(uri))
1145 return true;
1146
1147 uri = uristart;
846978d7 1148
dd65d8c8
RN
1149 if (!bAllowAltEnding)
1150 return false;
1151 }
1152
1153 if(numPrefix <= 5 && ParseH16(uri))
1154 return true;
1155
1156 return true;
1157}
1158
1159bool wxURI::ParseIPvFuture(const wxChar*& uri)
1160{
1161 // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
ce321570 1162 if (*++uri != wxT('v') || !IsHex(*++uri))
dd65d8c8
RN
1163 return false;
1164
1165 while (IsHex(*++uri)) {}
1166
ce321570 1167 if (*uri != wxT('.') || !(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == wxT(':')))
dd65d8c8
RN
1168 return false;
1169
ce321570 1170 while(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == wxT(':')) {}
dd65d8c8
RN
1171
1172 return true;
1173}
1174
1175
1176// ---------------------------------------------------------------------------
ce321570
RN
1177// CharToHex
1178//
846978d7 1179// Converts a character into a numeric hexidecimal value, or 0 if the
ce321570 1180// passed in character is not a valid hex character
dd65d8c8
RN
1181// ---------------------------------------------------------------------------
1182
ce321570 1183//static
409a7ba7 1184wxChar wxURI::CharToHex(const wxChar& c)
dd65d8c8 1185{
1676a194
WS
1186 if ((c >= wxT('A')) && (c <= wxT('Z'))) return wxChar(c - wxT('A') + 0x0A);
1187 if ((c >= wxT('a')) && (c <= wxT('z'))) return wxChar(c - wxT('a') + 0x0a);
1188 if ((c >= wxT('0')) && (c <= wxT('9'))) return wxChar(c - wxT('0') + 0x00);
dd65d8c8 1189
846978d7 1190 return 0;
dd65d8c8
RN
1191}
1192
ce321570
RN
1193// ---------------------------------------------------------------------------
1194// IsXXX
1195//
1196// Returns true if the passed in character meets the criteria of the method
1197// ---------------------------------------------------------------------------
1198
dd65d8c8
RN
1199//! unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1200bool wxURI::IsUnreserved (const wxChar& c)
846978d7 1201{ return IsAlpha(c) || IsDigit(c) ||
ce321570
RN
1202 c == wxT('-') ||
1203 c == wxT('.') ||
1204 c == wxT('_') ||
1205 c == wxT('~') //tilde
846978d7 1206 ;
dd65d8c8
RN
1207}
1208
1209bool wxURI::IsReserved (const wxChar& c)
846978d7 1210{
dd65d8c8
RN
1211 return IsGenDelim(c) || IsSubDelim(c);
1212}
1213
1214//! gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
1215bool wxURI::IsGenDelim (const wxChar& c)
1216{
ce321570
RN
1217 return c == wxT(':') ||
1218 c == wxT('/') ||
1219 c == wxT('?') ||
1220 c == wxT('#') ||
1221 c == wxT('[') ||
1222 c == wxT(']') ||
1223 c == wxT('@');
dd65d8c8
RN
1224}
1225
1226//! sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1227//! / "*" / "+" / "," / ";" / "="
1228bool wxURI::IsSubDelim (const wxChar& c)
1229{
ce321570
RN
1230 return c == wxT('!') ||
1231 c == wxT('$') ||
1232 c == wxT('&') ||
1233 c == wxT('\'') ||
1234 c == wxT('(') ||
1235 c == wxT(')') ||
1236 c == wxT('*') ||
1237 c == wxT('+') ||
1238 c == wxT(',') ||
1239 c == wxT(';') ||
846978d7 1240 c == wxT('=')
dd65d8c8
RN
1241 ;
1242}
1243
1244bool wxURI::IsHex(const wxChar& c)
ce321570 1245{ return IsDigit(c) || (c >= wxT('a') && c <= wxT('f')) || (c >= wxT('A') && c <= wxT('F')); }
dd65d8c8
RN
1246
1247bool wxURI::IsAlpha(const wxChar& c)
ce321570 1248{ return (c >= wxT('a') && c <= wxT('z')) || (c >= wxT('A') && c <= wxT('Z')); }
dd65d8c8
RN
1249
1250bool wxURI::IsDigit(const wxChar& c)
ce321570 1251{ return c >= wxT('0') && c <= wxT('9'); }
dd65d8c8
RN
1252
1253
1254// ---------------------------------------------------------------------------
1255//
00a1d2e0 1256// wxURL Compatibility
dd65d8c8 1257//
dd65d8c8
RN
1258// ---------------------------------------------------------------------------
1259
1260#if wxUSE_URL
1261
86470d43
RN
1262#if WXWIN_COMPATIBILITY_2_4
1263
dd65d8c8
RN
1264#include "wx/url.h"
1265
a6fb8636
WS
1266wxString wxURL::GetProtocolName() const
1267{
1268 return m_scheme;
1269}
1270
1271wxString wxURL::GetHostName() const
1272{
1273 return m_server;
1274}
1275
1276wxString wxURL::GetPath() const
1277{
1278 return m_path;
1279}
1280
997ba01b
RN
1281//Note that this old code really doesn't convert to a URI that well and looks
1282//more like a dirty hack than anything else...
1283
1284wxString wxURL::ConvertToValidURI(const wxString& uri, const wxChar* delims)
dd65d8c8 1285{
997ba01b
RN
1286 wxString out_str;
1287 wxString hexa_code;
1288 size_t i;
1289
1290 for (i = 0; i < uri.Len(); i++)
1291 {
1292 wxChar c = uri.GetChar(i);
1293
1294 if (c == wxT(' '))
1295 {
1296 // GRG, Apr/2000: changed to "%20" instead of '+'
1297
1298 out_str += wxT("%20");
1299 }
1300 else
1301 {
1302 // GRG, Apr/2000: modified according to the URI definition (RFC 2396)
1303 //
1304 // - Alphanumeric characters are never escaped
1305 // - Unreserved marks are never escaped
1306 // - Delimiters must be escaped if they appear within a component
1307 // but not if they are used to separate components. Here we have
1308 // no clear way to distinguish between these two cases, so they
1309 // are escaped unless they are passed in the 'delims' parameter
1310 // (allowed delimiters).
1311
1312 static const wxChar marks[] = wxT("-_.!~*()'");
1313
1314 if ( !wxIsalnum(c) && !wxStrchr(marks, c) && !wxStrchr(delims, c) )
1315 {
1316 hexa_code.Printf(wxT("%%%02X"), c);
1317 out_str += hexa_code;
1318 }
1319 else
1320 {
1321 out_str += c;
1322 }
1323 }
1324 }
1325
1326 return out_str;
dd65d8c8
RN
1327}
1328
1329wxString wxURL::ConvertFromURI(const wxString& uri)
1330{
86470d43 1331 return wxURI::Unescape(uri);
dd65d8c8
RN
1332}
1333
86470d43
RN
1334#endif //WXWIN_COMPATIBILITY_2_4
1335
dd65d8c8
RN
1336#endif //wxUSE_URL
1337
1338//end of uri.cpp
1339
1340
1341