]> git.saurik.com Git - wxWidgets.git/blob - src/common/uri.cpp
compilation fix for PCH-less builds
[wxWidgets.git] / src / common / uri.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: uri.cpp
3 // Purpose: Implementation of a URI parser
4 // Author: Ryan Norton,
5 // Vadim Zeitlin (UTF-8 URI support, many other changes)
6 // Created: 10/26/04
7 // RCS-ID: $Id$
8 // Copyright: (c) 2004 Ryan Norton,
9 // 2008 Vadim Zeitlin
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 // ===========================================================================
14 // declarations
15 // ===========================================================================
16
17 // ---------------------------------------------------------------------------
18 // headers
19 // ---------------------------------------------------------------------------
20
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23
24 #ifdef __BORLANDC__
25 #pragma hdrstop
26 #endif
27
28 #ifndef WX_PRECOMP
29 #include "wx/crt.h"
30 #include "wx/arrstr.h"
31 #endif
32
33 #include "wx/uri.h"
34
35 // ---------------------------------------------------------------------------
36 // definitions
37 // ---------------------------------------------------------------------------
38
39 IMPLEMENT_CLASS(wxURI, wxObject)
40
41 // ===========================================================================
42 // wxURI implementation
43 // ===========================================================================
44
45 // ---------------------------------------------------------------------------
46 // Constructors and cleanup
47 // ---------------------------------------------------------------------------
48
49 wxURI::wxURI()
50 : m_hostType(wxURI_REGNAME),
51 m_fields(0)
52 {
53 }
54
55 wxURI::wxURI(const wxString& uri)
56 : m_hostType(wxURI_REGNAME),
57 m_fields(0)
58 {
59 Create(uri);
60 }
61
62 bool wxURI::Create(const wxString& uri)
63 {
64 if (m_fields)
65 Clear();
66
67 return Parse(uri.utf8_str());
68 }
69
70 void wxURI::Clear()
71 {
72 m_scheme =
73 m_userinfo =
74 m_server =
75 m_port =
76 m_path =
77 m_query =
78 m_fragment = wxEmptyString;
79
80 m_hostType = wxURI_REGNAME;
81
82 m_fields = 0;
83 }
84
85 // ---------------------------------------------------------------------------
86 // Escaped characters handling
87 // ---------------------------------------------------------------------------
88
89 // Converts a character into a numeric hexadecimal value, or -1 if the passed
90 // in character is not a valid hex character
91
92 /* static */
93 int wxURI::CharToHex(char c)
94 {
95 if ((c >= 'A') && (c <= 'Z'))
96 return c - 'A' + 10;
97 if ((c >= 'a') && (c <= 'z'))
98 return c - 'a' + 10;
99 if ((c >= '0') && (c <= '9'))
100 return c - '0';
101
102 return -1;
103 }
104
105 int wxURI::DecodeEscape(wxString::const_iterator& i)
106 {
107 int hi = CharToHex(*++i);
108 if ( hi == -1 )
109 return -1;
110
111 int lo = CharToHex(*++i);
112 if ( lo == -1 )
113 return -1;
114
115 return (hi << 4) | lo;
116 }
117
118 /* static */
119 wxString wxURI::Unescape(const wxString& uri)
120 {
121 // the unescaped version can't be longer than the original one
122 wxCharBuffer buf(uri.length());
123 char *p = buf.data();
124
125 for ( wxString::const_iterator i = uri.begin(); i != uri.end(); ++i, ++p )
126 {
127 char c = *i;
128 if ( c == '%' )
129 {
130 int n = wxURI::DecodeEscape(i);
131 if ( n == -1 )
132 return wxString();
133
134 wxASSERT_MSG( n >= 0 && n <= 0xff, "unexpected character value" );
135
136 c = wx_static_cast(char, n);
137 }
138
139 *p = c;
140 }
141
142 *p = '\0';
143
144 // by default assume that the URI is in UTF-8, this is the most common
145 // practice
146 wxString s = wxString::FromUTF8(buf);
147 if ( s.empty() )
148 {
149 // if it isn't, use latin-1 as a fallback -- at least this always
150 // succeeds
151 s = wxCSConv(wxFONTENCODING_ISO8859_1).cMB2WC(buf);
152 }
153
154 return s;
155 }
156
157 void wxURI::AppendNextEscaped(wxString& s, const char *& p)
158 {
159 // check for an already encoded character:
160 //
161 // pct-encoded = "%" HEXDIG HEXDIG
162 if ( p[0] == '%' && IsHex(p[1]) && IsHex(p[2]) )
163 {
164 s += *p++;
165 s += *p++;
166 s += *p++;
167 }
168 else // really needs escaping
169 {
170 static const char* hexDigits = "0123456789abcdef";
171
172 const char c = *p++;
173
174 s += '%';
175 s += hexDigits[(c >> 4) & 15];
176 s += hexDigits[c & 15];
177 }
178 }
179
180 // ---------------------------------------------------------------------------
181 // GetUser
182 // GetPassword
183 //
184 // Gets the username and password via the old URL method.
185 // ---------------------------------------------------------------------------
186 wxString wxURI::GetUser() const
187 {
188 size_t dwPasswordPos = m_userinfo.find(':');
189
190 if (dwPasswordPos == wxString::npos)
191 dwPasswordPos = 0;
192
193 return m_userinfo(0, dwPasswordPos);
194 }
195
196 wxString wxURI::GetPassword() const
197 {
198 size_t dwPasswordPos = m_userinfo.find(':');
199
200 if (dwPasswordPos == wxString::npos)
201 return "";
202 else
203 return m_userinfo(dwPasswordPos+1, m_userinfo.length() + 1);
204 }
205
206 // combine all URI fields in a single string, applying funcDecode to each
207 // component which it may make sense to decode (i.e. "unescape")
208 wxString wxURI::DoBuildURI(wxString (*funcDecode)(const wxString&)) const
209 {
210 wxString ret;
211
212 if (HasScheme())
213 ret += m_scheme + ":";
214
215 if (HasServer())
216 {
217 ret += "//";
218
219 if (HasUserInfo())
220 ret += funcDecode(m_userinfo) + "@";
221
222 if (m_hostType == wxURI_REGNAME)
223 ret += funcDecode(m_server);
224 else
225 ret += m_server;
226
227 if (HasPort())
228 ret += ":" + m_port;
229 }
230
231 ret += funcDecode(m_path);
232
233 if (HasQuery())
234 ret += "?" + funcDecode(m_query);
235
236 if (HasFragment())
237 ret += "#" + funcDecode(m_fragment);
238
239 return ret;
240 }
241
242 // ---------------------------------------------------------------------------
243 // Comparison
244 // ---------------------------------------------------------------------------
245
246 bool wxURI::operator==(const wxURI& uri) const
247 {
248 if (HasScheme())
249 {
250 if(m_scheme != uri.m_scheme)
251 return false;
252 }
253 else if (uri.HasScheme())
254 return false;
255
256
257 if (HasServer())
258 {
259 if (HasUserInfo())
260 {
261 if (m_userinfo != uri.m_userinfo)
262 return false;
263 }
264 else if (uri.HasUserInfo())
265 return false;
266
267 if (m_server != uri.m_server ||
268 m_hostType != uri.m_hostType)
269 return false;
270
271 if (HasPort())
272 {
273 if(m_port != uri.m_port)
274 return false;
275 }
276 else if (uri.HasPort())
277 return false;
278 }
279 else if (uri.HasServer())
280 return false;
281
282
283 if (HasPath())
284 {
285 if(m_path != uri.m_path)
286 return false;
287 }
288 else if (uri.HasPath())
289 return false;
290
291 if (HasQuery())
292 {
293 if (m_query != uri.m_query)
294 return false;
295 }
296 else if (uri.HasQuery())
297 return false;
298
299 if (HasFragment())
300 {
301 if (m_fragment != uri.m_fragment)
302 return false;
303 }
304 else if (uri.HasFragment())
305 return false;
306
307 return true;
308 }
309
310 // ---------------------------------------------------------------------------
311 // IsReference
312 //
313 // if there is no authority or scheme, it is a reference
314 // ---------------------------------------------------------------------------
315
316 bool wxURI::IsReference() const
317 {
318 return !HasScheme() || !HasServer();
319 }
320
321 // ---------------------------------------------------------------------------
322 // Parse
323 //
324 // Master URI parsing method. Just calls the individual parsing methods
325 //
326 // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
327 // URI-reference = URI / relative
328 // ---------------------------------------------------------------------------
329
330 bool wxURI::Parse(const char *uri)
331 {
332 uri = ParseScheme(uri);
333 if ( uri )
334 uri = ParseAuthority(uri);
335 if ( uri )
336 uri = ParsePath(uri);
337 if ( uri )
338 uri = ParseQuery(uri);
339 if ( uri )
340 uri = ParseFragment(uri);
341
342 // we only succeed if we parsed the entire string
343 return uri && *uri == '\0';
344 }
345
346 const char* wxURI::ParseScheme(const char *uri)
347 {
348 const char * const start = uri;
349
350 // assume that we have a scheme if we have the valid start of it
351 if ( IsAlpha(*uri) )
352 {
353 m_scheme += *uri++;
354
355 //scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
356 while (IsAlpha(*uri) || IsDigit(*uri) ||
357 *uri == '+' ||
358 *uri == '-' ||
359 *uri == '.')
360 {
361 m_scheme += *uri++;
362 }
363
364 //valid scheme?
365 if (*uri == ':')
366 {
367 //mark the scheme as valid
368 m_fields |= wxURI_SCHEME;
369
370 //move reference point up to input buffer
371 ++uri;
372 }
373 else // no valid scheme finally
374 {
375 uri = start; // rewind
376 m_scheme.clear();
377 }
378 }
379 //else: can't have schema, possible a relative URI
380
381 return uri;
382 }
383
384 const char* wxURI::ParseAuthority(const char* uri)
385 {
386 // authority = [ userinfo "@" ] host [ ":" port ]
387 if ( uri[0] == '/' && uri[1] == '/' )
388 {
389 //skip past the two slashes
390 uri += 2;
391
392 // ############# DEVIATION FROM RFC #########################
393 // Don't parse the server component for file URIs
394 if(m_scheme != "file")
395 {
396 //normal way
397 uri = ParseUserInfo(uri);
398 uri = ParseServer(uri);
399 return ParsePort(uri);
400 }
401 }
402
403 return uri;
404 }
405
406 const char* wxURI::ParseUserInfo(const char* uri)
407 {
408 const char * const start = uri;
409
410 // userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
411 while ( *uri && *uri != '@' && *uri != '/' && *uri != '#' && *uri != '?' )
412 {
413 if ( IsUnreserved(*uri) || IsSubDelim(*uri) || *uri == ':' )
414 m_userinfo += *uri++;
415 else
416 AppendNextEscaped(m_userinfo, uri);
417 }
418
419 if ( *uri++ == '@' )
420 {
421 // valid userinfo
422 m_fields |= wxURI_USERINFO;
423 }
424 else
425 {
426 uri = start; // rewind
427 m_userinfo.clear();
428 }
429
430 return uri;
431 }
432
433 const char* wxURI::ParseServer(const char* uri)
434 {
435 const char * const start = uri;
436
437 // host = IP-literal / IPv4address / reg-name
438 // IP-literal = "[" ( IPv6address / IPvFuture ) "]"
439 if (*uri == '[')
440 {
441 ++uri;
442 if (ParseIPv6address(uri) && *uri == ']')
443 {
444 m_hostType = wxURI_IPV6ADDRESS;
445
446 m_server.assign(start, uri - start - 1);
447 ++uri;
448 }
449 else
450 {
451 uri = start + 1; // skip the leading '[' again
452
453 if (ParseIPvFuture(uri) && *uri == ']')
454 {
455 m_hostType = wxURI_IPVFUTURE;
456
457 m_server.assign(start, uri - start - 1);
458 ++uri;
459 }
460 else // unrecognized IP literal
461 {
462 uri = start;
463 }
464 }
465 }
466 else // IPv4 or a reg-name
467 {
468 if (ParseIPv4address(uri))
469 {
470 m_hostType = wxURI_IPV4ADDRESS;
471
472 m_server.assign(start, uri - start - 1);
473 }
474 else
475 {
476 uri = start;
477 }
478 }
479
480 if ( m_hostType == wxURI_REGNAME )
481 {
482 uri = start;
483 // reg-name = *( unreserved / pct-encoded / sub-delims )
484 while ( *uri && *uri != '/' && *uri != ':' && *uri != '#' && *uri != '?' )
485 {
486 if ( IsUnreserved(*uri) || IsSubDelim(*uri) )
487 m_server += *uri++;
488 else
489 AppendNextEscaped(m_server, uri);
490 }
491 }
492
493 m_fields |= wxURI_SERVER;
494
495 return uri;
496 }
497
498
499 const char* wxURI::ParsePort(const char* uri)
500 {
501 // port = *DIGIT
502 if( *uri == ':' )
503 {
504 ++uri;
505 while ( IsDigit(*uri) )
506 {
507 m_port += *uri++;
508 }
509
510 m_fields |= wxURI_PORT;
511 }
512
513 return uri;
514 }
515
516 const char* wxURI::ParsePath(const char* uri)
517 {
518 /// hier-part = "//" authority path-abempty
519 /// / path-absolute
520 /// / path-rootless
521 /// / path-empty
522 ///
523 /// relative-part = "//" authority path-abempty
524 /// / path-absolute
525 /// / path-noscheme
526 /// / path-empty
527 ///
528 /// path-abempty = *( "/" segment )
529 /// path-absolute = "/" [ segment-nz *( "/" segment ) ]
530 /// path-noscheme = segment-nz-nc *( "/" segment )
531 /// path-rootless = segment-nz *( "/" segment )
532 /// path-empty = 0<pchar>
533 ///
534 /// segment = *pchar
535 /// segment-nz = 1*pchar
536 /// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
537 /// ; non-zero-length segment without any colon ":"
538 ///
539 /// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
540
541 if ( IsEndPath(*uri) )
542 return uri;
543
544 const bool isAbs = *uri == '/';
545 if ( isAbs )
546 m_path += *uri++;
547
548 wxArrayString segments;
549 wxString segment;
550 for ( ;; )
551 {
552 const bool endPath = IsEndPath(*uri);
553 if ( endPath || *uri == '/' )
554 {
555 // end of a segment, look at what we got
556 if ( segment == ".." )
557 {
558 if ( !segments.empty() && *segments.rbegin() != ".." )
559 segments.pop_back();
560 else if ( !isAbs )
561 segments.push_back("..");
562 }
563 else if ( segment == "." )
564 {
565 // normally we ignore "." but the last one should be taken into
566 // account as "path/." is the same as "path/" and not just "path"
567 if ( endPath )
568 segments.push_back("");
569 }
570 else // normal segment
571 {
572 segments.push_back(segment);
573 }
574
575 if ( endPath )
576 break;
577
578 segment.clear();
579 ++uri;
580 continue;
581 }
582
583 if ( IsUnreserved(*uri) || IsSubDelim(*uri) || *uri == ':' || *uri == '@' )
584 segment += *uri++;
585 else
586 AppendNextEscaped(segment, uri);
587 }
588
589 m_path += wxJoin(segments, '/', '\0');
590 m_fields |= wxURI_PATH;
591
592 return uri;
593 }
594
595
596 const char* wxURI::ParseQuery(const char* uri)
597 {
598 // query = *( pchar / "/" / "?" )
599 if ( *uri == '?' )
600 {
601 ++uri;
602 while ( *uri && *uri != '#' )
603 {
604 if ( IsUnreserved(*uri) || IsSubDelim(*uri) ||
605 *uri == ':' || *uri == '@' || *uri == '/' || *uri == '?' )
606 m_query += *uri++;
607 else
608 AppendNextEscaped(m_query, uri);
609 }
610
611 m_fields |= wxURI_QUERY;
612 }
613
614 return uri;
615 }
616
617
618 const char* wxURI::ParseFragment(const char* uri)
619 {
620 // fragment = *( pchar / "/" / "?" )
621 if ( *uri == '#' )
622 {
623 ++uri;
624 while ( *uri )
625 {
626 if ( IsUnreserved(*uri) || IsSubDelim(*uri) ||
627 *uri == ':' || *uri == '@' || *uri == '/' || *uri == '?')
628 m_fragment += *uri++;
629 else
630 AppendNextEscaped(m_fragment, uri);
631 }
632
633 m_fields |= wxURI_FRAGMENT;
634 }
635
636 return uri;
637 }
638
639 // ---------------------------------------------------------------------------
640 // Resolve
641 //
642 // Builds missing components of this uri from a base uri
643 //
644 // A version of the algorithm outlined in the RFC is used here
645 // (it is shown in comments)
646 //
647 // Note that an empty URI inherits all components
648 // ---------------------------------------------------------------------------
649
650 /* static */
651 wxArrayString wxURI::SplitInSegments(const wxString& path)
652 {
653 return wxSplit(path, '/', '\0' /* no escape character */);
654 }
655
656 void wxURI::Resolve(const wxURI& base, int flags)
657 {
658 wxASSERT_MSG(!base.IsReference(),
659 "wxURI to inherit from must not be a reference!");
660
661 // If we aren't being strict, enable the older (pre-RFC2396) loophole that
662 // allows this uri to inherit other properties from the base uri - even if
663 // the scheme is defined
664 if ( !(flags & wxURI_STRICT) &&
665 HasScheme() && base.HasScheme() &&
666 m_scheme == base.m_scheme )
667 {
668 m_fields -= wxURI_SCHEME;
669 }
670
671
672 // Do nothing if this is an absolute wxURI
673 // if defined(R.scheme) then
674 // T.scheme = R.scheme;
675 // T.authority = R.authority;
676 // T.path = remove_dot_segments(R.path);
677 // T.query = R.query;
678 if (HasScheme())
679 return;
680
681 //No scheme - inherit
682 m_scheme = base.m_scheme;
683 m_fields |= wxURI_SCHEME;
684
685 // All we need to do for relative URIs with an
686 // authority component is just inherit the scheme
687 // if defined(R.authority) then
688 // T.authority = R.authority;
689 // T.path = remove_dot_segments(R.path);
690 // T.query = R.query;
691 if (HasServer())
692 return;
693
694 //No authority - inherit
695 if (base.HasUserInfo())
696 {
697 m_userinfo = base.m_userinfo;
698 m_fields |= wxURI_USERINFO;
699 }
700
701 m_server = base.m_server;
702 m_hostType = base.m_hostType;
703 m_fields |= wxURI_SERVER;
704
705 if (base.HasPort())
706 {
707 m_port = base.m_port;
708 m_fields |= wxURI_PORT;
709 }
710
711
712 // Simple path inheritance from base
713 if (!HasPath())
714 {
715 // T.path = Base.path;
716 m_path = base.m_path;
717 m_fields |= wxURI_PATH;
718
719
720 // if defined(R.query) then
721 // T.query = R.query;
722 // else
723 // T.query = Base.query;
724 // endif;
725 if (!HasQuery())
726 {
727 m_query = base.m_query;
728 m_fields |= wxURI_QUERY;
729 }
730 }
731 else if ( m_path.empty() || m_path[0u] != '/' )
732 {
733 // if (R.path starts-with "/") then
734 // T.path = remove_dot_segments(R.path);
735 // else
736 // T.path = merge(Base.path, R.path);
737 // T.path = remove_dot_segments(T.path);
738 // endif;
739 // T.query = R.query;
740 //
741 // So we don't do anything for absolute paths and implement merge for
742 // the relative ones
743
744 wxArrayString our(SplitInSegments(m_path)),
745 result(SplitInSegments(base.m_path));
746
747 if ( !result.empty() )
748 result.pop_back();
749
750 if ( our.empty() )
751 {
752 // if we have an empty path it means we were constructed from a "."
753 // string or something similar (e.g. "././././"), it should count
754 // as (empty) segment
755 our.push_back("");
756 }
757
758 const wxArrayString::const_iterator end = our.end();
759 for ( wxArrayString::const_iterator i = our.begin(); i != end; ++i )
760 {
761 if ( i->empty() || *i == "." )
762 {
763 // as in ParsePath(), while normally we ignore the empty
764 // segments, we need to take account of them at the end
765 if ( i == end - 1 )
766 result.push_back("");
767 continue;
768 }
769
770 if ( *i == ".." )
771 {
772 if ( !result.empty() )
773 {
774 result.pop_back();
775
776 if ( i == end - 1 )
777 result.push_back("");
778 }
779 //else: just ignore, extra ".." don't accumulate
780 }
781 else
782 {
783 if ( result.empty() )
784 {
785 // ensure that the resulting path will always be absolute
786 result.push_back("");
787 }
788
789 result.push_back(*i);
790 }
791 }
792
793 m_path = wxJoin(result, '/', '\0');
794 }
795
796 //T.fragment = R.fragment;
797 }
798
799 // ---------------------------------------------------------------------------
800 // ParseH16
801 //
802 // Parses 1 to 4 hex values. Returns true if the first character of the input
803 // string is a valid hex character. It is the caller's responsibility to move
804 // the input string back to its original position on failure.
805 // ---------------------------------------------------------------------------
806
807 bool wxURI::ParseH16(const char*& uri)
808 {
809 // h16 = 1*4HEXDIG
810 if(!IsHex(*++uri))
811 return false;
812
813 if(IsHex(*++uri) && IsHex(*++uri) && IsHex(*++uri))
814 ++uri;
815
816 return true;
817 }
818
819 // ---------------------------------------------------------------------------
820 // ParseIPXXX
821 //
822 // Parses a certain version of an IP address and moves the input string past
823 // it. Returns true if the input string contains the proper version of an ip
824 // address. It is the caller's responsability to move the input string back
825 // to its original position on failure.
826 // ---------------------------------------------------------------------------
827
828 bool wxURI::ParseIPv4address(const char*& uri)
829 {
830 //IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
831 //
832 //dec-octet = DIGIT ; 0-9
833 // / %x31-39 DIGIT ; 10-99
834 // / "1" 2DIGIT ; 100-199
835 // / "2" %x30-34 DIGIT ; 200-249
836 // / "25" %x30-35 ; 250-255
837 size_t iIPv4 = 0;
838 if (IsDigit(*uri))
839 {
840 ++iIPv4;
841
842
843 //each ip part must be between 0-255 (dupe of version in for loop)
844 if( IsDigit(*++uri) && IsDigit(*++uri) &&
845 //100 or less (note !)
846 !( (*(uri-2) < '2') ||
847 //240 or less
848 (*(uri-2) == '2' &&
849 (*(uri-1) < '5' || (*(uri-1) == '5' && *uri <= '5'))
850 )
851 )
852 )
853 {
854 return false;
855 }
856
857 if(IsDigit(*uri))++uri;
858
859 //compilers should unroll this loop
860 for(; iIPv4 < 4; ++iIPv4)
861 {
862 if (*uri != '.' || !IsDigit(*++uri))
863 break;
864
865 //each ip part must be between 0-255
866 if( IsDigit(*++uri) && IsDigit(*++uri) &&
867 //100 or less (note !)
868 !( (*(uri-2) < '2') ||
869 //240 or less
870 (*(uri-2) == '2' &&
871 (*(uri-1) < '5' || (*(uri-1) == '5' && *uri <= '5'))
872 )
873 )
874 )
875 {
876 return false;
877 }
878 if(IsDigit(*uri))++uri;
879 }
880 }
881 return iIPv4 == 4;
882 }
883
884 bool wxURI::ParseIPv6address(const char*& uri)
885 {
886 // IPv6address = 6( h16 ":" ) ls32
887 // / "::" 5( h16 ":" ) ls32
888 // / [ h16 ] "::" 4( h16 ":" ) ls32
889 // / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
890 // / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
891 // / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
892 // / [ *4( h16 ":" ) h16 ] "::" ls32
893 // / [ *5( h16 ":" ) h16 ] "::" h16
894 // / [ *6( h16 ":" ) h16 ] "::"
895
896 size_t numPrefix = 0,
897 maxPostfix;
898
899 bool bEndHex = false;
900
901 for( ; numPrefix < 6; ++numPrefix)
902 {
903 if(!ParseH16(uri))
904 {
905 --uri;
906 bEndHex = true;
907 break;
908 }
909
910 if(*uri != ':')
911 {
912 break;
913 }
914 }
915
916 if(!bEndHex && !ParseH16(uri))
917 {
918 --uri;
919
920 if (numPrefix)
921 return false;
922
923 if (*uri == ':')
924 {
925 if (*++uri != ':')
926 return false;
927
928 maxPostfix = 5;
929 }
930 else
931 maxPostfix = 6;
932 }
933 else
934 {
935 if (*uri != ':' || *(uri+1) != ':')
936 {
937 if (numPrefix != 6)
938 return false;
939
940 while (*--uri != ':') {}
941 ++uri;
942
943 const char * const start = uri;
944 //parse ls32
945 // ls32 = ( h16 ":" h16 ) / IPv4address
946 if (ParseH16(uri) && *uri == ':' && ParseH16(uri))
947 return true;
948
949 uri = start;
950
951 if (ParseIPv4address(uri))
952 return true;
953 else
954 return false;
955 }
956 else
957 {
958 uri += 2;
959
960 if (numPrefix > 3)
961 maxPostfix = 0;
962 else
963 maxPostfix = 4 - numPrefix;
964 }
965 }
966
967 bool bAllowAltEnding = maxPostfix == 0;
968
969 for(; maxPostfix != 0; --maxPostfix)
970 {
971 if(!ParseH16(uri) || *uri != ':')
972 return false;
973 }
974
975 if(numPrefix <= 4)
976 {
977 const char * const start = uri;
978 //parse ls32
979 // ls32 = ( h16 ":" h16 ) / IPv4address
980 if (ParseH16(uri) && *uri == ':' && ParseH16(uri))
981 return true;
982
983 uri = start;
984
985 if (ParseIPv4address(uri))
986 return true;
987
988 uri = start;
989
990 if (!bAllowAltEnding)
991 return false;
992 }
993
994 if(numPrefix <= 5 && ParseH16(uri))
995 return true;
996
997 return true;
998 }
999
1000 bool wxURI::ParseIPvFuture(const char*& uri)
1001 {
1002 // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
1003 if (*++uri != 'v' || !IsHex(*++uri))
1004 return false;
1005
1006 while (IsHex(*++uri))
1007 ;
1008
1009 if (*uri != '.' || !(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == ':'))
1010 return false;
1011
1012 while(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == ':') {}
1013
1014 return true;
1015 }
1016
1017
1018 // ---------------------------------------------------------------------------
1019 // IsXXX
1020 //
1021 // Returns true if the passed in character meets the criteria of the method
1022 // ---------------------------------------------------------------------------
1023
1024 // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1025 bool wxURI::IsUnreserved(char c)
1026 {
1027 return IsAlpha(c) ||
1028 IsDigit(c) ||
1029 c == '-' ||
1030 c == '.' ||
1031 c == '_' ||
1032 c == '~'
1033 ;
1034 }
1035
1036 bool wxURI::IsReserved(char c)
1037 {
1038 return IsGenDelim(c) || IsSubDelim(c);
1039 }
1040
1041 // gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
1042 bool wxURI::IsGenDelim(char c)
1043 {
1044 return c == ':' ||
1045 c == '/' ||
1046 c == '?' ||
1047 c == '#' ||
1048 c == '[' ||
1049 c == ']' ||
1050 c == '@';
1051 }
1052
1053 // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1054 // / "*" / "+" / "," / ";" / "="
1055 bool wxURI::IsSubDelim(char c)
1056 {
1057 return c == '!' ||
1058 c == '$' ||
1059 c == '&' ||
1060 c == '\'' ||
1061 c == '(' ||
1062 c == ')' ||
1063 c == '*' ||
1064 c == '+' ||
1065 c == ',' ||
1066 c == ';' ||
1067 c == '='
1068 ;
1069 }
1070
1071 bool wxURI::IsHex(char c)
1072 {
1073 return IsDigit(c) ||
1074 (c >= 'a' && c <= 'f') ||
1075 (c >= 'A' && c <= 'F');
1076 }
1077
1078 bool wxURI::IsAlpha(char c)
1079 {
1080 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
1081 }
1082
1083 bool wxURI::IsDigit(char c)
1084 {
1085 return c >= '0' && c <= '9';
1086 }
1087
1088 bool wxURI::IsEndPath(char c)
1089 {
1090 return c == '\0' || c == '#' || c == '?';
1091 }
1092