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