// @(#)root/base:$Id$
// Author: Gerhard E. Bruckner 15/07/07

/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TUri                                                                 //
//                                                                      //
// This class represents a RFC 3986 compatible URI.                     //
// See http://rfc.net/rfc3986.html.                                     //
// It provides member functions to set and return the different         //
// the different parts of an URI. The functionality is that of          //
// a validating parser.                                                 //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <ctype.h>    // for tolower()
#include "TUri.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TPRegexp.h"

//RFC3986:
// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
const char* const kURI_pchar        = "(?:[[:alpha:][:digit:]-._~!$&'()*+,;=:@]|%[0-9A-Fa-f][0-9A-Fa-f])";

//unreserved characters, see chapter 2.3
const char* const kURI_unreserved   = "[[:alpha:][:digit:]-._~]";

// reserved characters, see chapter
// reserved      = gen-delims / sub-delims
//const char* const kURI_reserved     = "[:/?#[]@!$&'()*+,;=]";

// gen-delims, see chapter 2.2
// delimiters of the generic URI components
//const char* const kURI_gendelims    = "[:/?#[]@]";

// sub-delims, see chapter 2.2
//const char* const kURI_subdelims    = "[!$&'()*+,;=]";


ClassImp(TUri)

//______________________________________________________________________________
TUri::TUri(const TString &uri)
{
   // Constructor that calls SetUri with a complete URI.

   SetUri(uri);
}

//______________________________________________________________________________
TUri::TUri(const char *uri)
{
   // Constructor that calls SetUri with a complete URI.

   SetUri(uri);
}

//______________________________________________________________________________
TUri::TUri(const TUri &uri) : TObject(uri)
{
   // TUri copy ctor.

   fScheme = uri.fScheme;
   fUserinfo = uri.fUserinfo;
   fHost = uri.fHost;
   fPort = uri.fPort;
   fPath = uri.fPath;
   fQuery = uri.fQuery;
   fFragment = uri.fFragment;
   fHasScheme = uri.fHasScheme;
   fHasUserinfo = uri.fHasUserinfo;
   fHasHost = uri.fHasHost;
   fHasPort = uri.fHasPort;
   fHasPath = uri.fHasPath;
   fHasQuery = uri.fHasQuery;
   fHasFragment = uri.fHasFragment;
}

//______________________________________________________________________________
TUri &TUri::operator= (const TUri & rhs)
{
   // TUri assignment operator.

   if (this != &rhs) {
      TObject::operator= (rhs);
      fScheme = rhs.fScheme;
      fUserinfo = rhs.fUserinfo;
      fHost = rhs.fHost;
      fPort = rhs.fPort;
      fPath = rhs.fPath;
      fQuery = rhs.fQuery;
      fFragment = rhs.fFragment;
      fHasScheme = rhs.fHasScheme;
      fHasUserinfo = rhs.fHasUserinfo;
      fHasHost = rhs.fHasHost;
      fHasPort = rhs.fHasPort;
      fHasPath = rhs.fHasPath;
      fHasQuery = rhs.fHasQuery;
      fHasFragment = rhs.fHasFragment;
   }
   return *this;
}

//______________________________________________________________________________
Bool_t operator== (const TUri &u1, const TUri &u2)
{
   // Implementation of a TUri Equivalence operator
   // that uses syntax-based normalisation
   // see chapter 6.2.2.

   // make temporary copies of the operands
   TUri u11 = u1;
   TUri u22 = u2;
   // normalise them
   u11.Normalise();
   u22.Normalise();
   // compare them as TStrings
   return u11.GetUri() == u22.GetUri();
}

//______________________________________________________________________________
const TString TUri::GetUri() const
{
   // Returns the whole URI -
   // an implementation of chapter 5.3 component recomposition.
   // The result URI is composed out of the five basic parts.
   //
   // URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
   // hier-part   = "//" authority path-abempty
   //             / path-absolute
   //             / path-rootless
   //             / path-empty

   TString result = "";
   if (fHasScheme)
      result = fScheme + ":";
   result += GetHierPart();
   if (fHasQuery)
      result += TString("?") + fQuery;
   if (fHasFragment)
      result += TString("#") + fFragment;
   return result;
}

//______________________________________________________________________________
const TString TUri::RemoveDotSegments(const TString &inp)
{
   // This functions implements the "remove_dot_segments" routine
   // of chapter 5.2.4 "for interpreting and removing the
   // special '.' and '..' complete path segments from a
   // referenced path".

   TString source = inp;
   TString sink = TString("");  // sink buffer

   // Step 2 "While the source buffer is not empty, loop as follows:"
   while (source.Length() > 0) {
      // Rule 2.A
      if (TPRegexp("^\\.\\.?/(.*)$").Substitute(source, "/$1") > 0)
         continue;

      // Rule 2.B
      if (TPRegexp("^/\\./(.*)$|^/\\.($)").Substitute(source, "/$1") > 0)
         continue;

      // Rule 2.C
      if (TPRegexp("^/\\.\\./(.*)$|^/\\.\\.($)").Substitute(source, "/$1") > 0) {
         Ssiz_t last = sink.Last('/');
         if (last == -1)
            last = 0;
         sink.Remove(last, sink.Length() - last);
         continue;
      }

      // Rule 2.D
      if (source.CompareTo(".") == 0 || source.CompareTo("..") == 0) {
         source.Remove(0, source.Length() - 11);
         continue;
      }

      // Rule 2.E
      TPRegexp regexp = TPRegexp("^(/?[^/]*)(?:/|$)");
      TObjArray *tokens = regexp.MatchS(source);
      TString segment = ((TObjString*) tokens->At(1))->GetString();
      sink += segment;
      source.Remove(0, segment.Length());
      delete tokens;
   }

   // Step 3: return sink buffer
   return sink;
}

//______________________________________________________________________________
Bool_t TUri::IsAbsolute() const
{
   // Returns kTRUE if instance qualifies as absolute-URI
   // absolute-URI  = scheme ":" hier-part [ "?" query ]
   // cf. Appendix A.

   return (HasScheme() && HasHierPart() && !HasFragment());
}

//______________________________________________________________________________
Bool_t TUri::IsRelative() const
{
   // Returns kTRUE if instance qualifies as relative-ref
   // relative-ref  = relative-part [ "?" query ] [ "#" fragment ]
   // cf. Appendix A.

   return (!HasScheme() && HasRelativePart());
}

//______________________________________________________________________________
Bool_t TUri::IsUri() const
{
   // Returns kTRUE if instance qualifies as URI
   // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
   // cf. Appendix A.

   return (HasScheme() && HasHierPart());
}

//______________________________________________________________________________
Bool_t TUri::IsReference() const
{
   // Returns kTRUE if instance qualifies as URI-reference
   // URI-reference = URI / relative-ref
   // cf. Appendix A.

   return (IsUri() || IsRelative());
}

//______________________________________________________________________________
Bool_t TUri::SetScheme(const TString &scheme)
{
   // Set scheme component of URI:
   // scheme      = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )

   if (!scheme) {
      fHasScheme = kFALSE;
      return kTRUE;
   }
   if (IsScheme(scheme)) {
      fScheme = scheme;
      fHasScheme = kTRUE;
      return kTRUE;
   } else {
      Error("SetScheme", "<scheme> component \"%s\" of URI is not compliant with RFC 3986.", scheme.Data());
      return kFALSE;
   }
}

//______________________________________________________________________________
Bool_t TUri::IsScheme(const TString &string)
{
   // Returns kTRUE if string qualifies as URI scheme:
   // scheme      = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )

   return TPRegexp(
             "^[[:alpha:]][[:alpha:][:digit:]+-.]*$"
          ).Match(string);
}

//______________________________________________________________________________
const TString TUri::GetAuthority() const
{
   // Returns the authority part of the instance:
   // authority   = [ userinfo "@" ] host [ ":" port ]

   TString authority = fHasUserinfo ? fUserinfo + "@" + fHost : fHost;
   if (fHasPort && !fPort.IsNull())
      // add port only if not empty
      authority += TString(":") + TString(fPort);
   return (authority);
}

//______________________________________________________________________________
Bool_t TUri::SetQuery(const TString &query)
{
   // Set query component of URI:
   // query       = *( pchar / "/" / "?" )

   if (!query) {
      fHasQuery = kFALSE;
      return kTRUE;
   }
   if (IsQuery(query)) {
      fQuery = query;
      fHasQuery = kTRUE;
      return kTRUE;
   } else {
      Error("SetQuery", "<query> component \"%s\" of URI is not compliant with RFC 3986.", query.Data());
      return kFALSE;
   }
}

//______________________________________________________________________________
Bool_t TUri::IsQuery(const TString &string)
{
   // Returns kTRUE if string qualifies as URI query:
   // query       = *( pchar / "/" / "?" )

   return TPRegexp(
             TString("^([/?]|") + kURI_pchar + ")*$"
          ).Match(string);
}

//______________________________________________________________________________
Bool_t TUri::SetAuthority(const TString &authority)
{
   // Set authority part of URI:
   // authority   = [ userinfo "@" ] host [ ":" port ]
   //
   // Split into components {userinfo@, host, :port},
   // remember that according to the RFC, it is necessary to
   // distinguish between missing component (no delimiter)
   // and empty component (delimiter present).

   if (authority.IsNull()) {
      fHasUserinfo = kFALSE;
      fHasHost = kFALSE;
      fHasPort = kFALSE;
      return kTRUE;
   }
   TPRegexp regexp = TPRegexp("^(?:(.*@))?([^:]*)((?::.*)?)$");
   TObjArray *tokens = regexp.MatchS(authority);

   if (tokens->GetEntries() != 4) {
      Error("SetAuthority", "<authority> component \"%s\" of URI is not compliant with RFC 3986.", authority.Data());
      return kFALSE;
   }

   Bool_t valid = kTRUE;

   // handle userinfo
   TString userinfo = ((TObjString*) tokens->At(1))->GetString();
   if (userinfo.EndsWith("@")) {
      userinfo.Remove(TString::kTrailing, '@');
      valid &= SetUserInfo(userinfo);
   }

   // handle host
   TString host = ((TObjString*) tokens->At(2))->GetString();
   valid &= SetHost(host);

   // handle port
   TString port = ((TObjString*) tokens->At(3))->GetString();
   if (port.BeginsWith(":")) {
      port.Remove(TString::kLeading, ':');
      valid &= SetPort(port);
   }

   return valid;
}

//______________________________________________________________________________
Bool_t TUri::IsAuthority(const TString &string)
{
   // Returns kTRUE if string qualifies as valid URI authority:
   // authority   = [ userinfo "@" ] host [ ":" port ]

   // split into parts {userinfo, host, port}
   TPRegexp regexp = TPRegexp("^(?:(.*)@)?([^:]*)(?::(.*))?$");
   TObjArray *tokens = regexp.MatchS(string);
   TString userinfo = ((TObjString*) tokens->At(1))->GetString();
   TString host = ((TObjString*) tokens->At(2))->GetString();
   TString port;
   // port is optional
   if (tokens->GetEntries() == 4)
      port = ((TObjString*) tokens->At(3))->GetString();
   else
      port = "";
   return (IsHost(host) && IsUserInfo(userinfo) && IsPort(port));
}

//______________________________________________________________________________
Bool_t TUri::SetUserInfo(const TString &userinfo)
{
   // Set userinfo component of URI:
   // userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )

   if (userinfo.IsNull()) {
      fHasUserinfo = kFALSE;
      return kTRUE;
   }
   if (IsUserInfo(userinfo)) {
      fUserinfo = userinfo;
      fHasUserinfo = kTRUE;
      return kTRUE;
   } else {
      Error("SetUserInfo", "<userinfo> component \"%s\" of URI is not compliant with RFC 3986.", userinfo.Data());
      return kFALSE;
   }
}

//______________________________________________________________________________
Bool_t TUri::IsUserInfo(const TString &string)
{
   // Return kTRUE is string qualifies as valid URI userinfo:
   // userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )
   // this equals to pchar without the '@' character

   return (TPRegexp(
              "^" + TString(kURI_pchar) + "*$"
           ).Match(string) > 0 && !TString(string).Contains("@"));
}

//______________________________________________________________________________
Bool_t TUri::SetHost(const TString &host)
{
   // Set host component of URI:
   // RFC 3986:    host = IP-literal / IPv4address / reg-name
   // implemented: host =  IPv4address / reg-name

   if (IsHost(host)) {
      fHost = host;
      fHasHost = kTRUE;
      return kTRUE;
   } else {
      Error("SetHost", "<host> component \"%s\" of URI is not compliant with RFC 3986.", host.Data());
      return kFALSE;
   }
}

//______________________________________________________________________________
Bool_t TUri::SetPort(const TString &port)
{
   // Set port component of URI:
   // port        = *DIGIT

   if (IsPort(port)) {
      fPort = port;
      fHasPort = kTRUE;
      return kTRUE;
   }
   Error("SetPort", "<port> component \"%s\" of URI is not compliant with RFC 3986.", port.Data());
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TUri::SetPath(const TString &path)
{
   // Set path component of URI:
   // path          = path-abempty    ; begins with "/" or is empty
   //               / path-absolute   ; begins with "/" but not "//"
   //               / path-noscheme   ; begins with a non-colon segment
   //               / path-rootless   ; begins with a segment
   //               / path-empty      ; zero characters

   if (IsPath(path)) {
      fPath = path;
      fHasPath = kTRUE;
      return kTRUE;
   }
   Error("SetPath", "<path> component \"%s\" of URI is not compliant with RFC 3986.", path.Data());
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TUri::SetFragment(const TString &fragment)
{
   // Set fragment component of URI:
   // fragment    = *( pchar / "/" / "?" )

   if (IsFragment(fragment)) {
      fFragment = fragment;
      fHasFragment = kTRUE;
      return kTRUE;
   } else {
      Error("SetFragment", "<fragment> component \"%s\" of URI is not compliant with RFC 3986.", fragment.Data());
      return kFALSE;
   }
}

//______________________________________________________________________________

Bool_t TUri::IsFragment(const TString &string)
{
   // Returns kTRUE if string qualifies as valid fragment component
   // fragment    = *( pchar / "/" / "?" )

   return (TPRegexp(
              "^(" + TString(kURI_pchar) + "|[/?])*$"
           ).Match(string) > 0);
}

//______________________________________________________________________________
void TUri::Print(Option_t *option) const
{
   // Display function,
   // option "d" .. debug output
   // anything else .. simply print URI.

   if (strcmp(option, "d") != 0) {
      Printf("%s", GetUri().Data());
      return ;
   }
   // debug output
   Printf("URI: <%s>", GetUri().Data());
   Printf("(%c) |--scheme---------<%s>", fHasScheme ? 't' : 'f', fScheme.Data());
   Printf("    |--hier-----------<%s>", GetHierPart().Data());
   Printf("(%c)     |--authority------<%s>", HasAuthority() ? 't' : 'f', GetAuthority().Data());
   Printf("(%c)         |--userinfo---<%s>", fHasUserinfo ? 't' : 'f', fUserinfo.Data());
   Printf("(%c)         |--host-------<%s>", fHasHost ? 't' : 'f', fHost.Data());
   Printf("(%c)         |--port-------<%s>", fHasPort ? 't' : 'f', fPort.Data());
   Printf("(%c)     |--path-------<%s>", fHasPath ? 't' : 'f', fPath.Data());
   Printf("(%c) |--query------<%s>", fHasQuery ? 't' : 'f', fQuery.Data());
   Printf("(%c) |--fragment---<%s>", fHasFragment ? 't' : 'f', fFragment.Data());
   printf("path flags: ");
   if (IsPathAbempty(fPath))
      printf("abempty ");
   if (IsPathAbsolute(fPath))
      printf("absolute ");
   if (IsPathRootless(fPath))
      printf("rootless ");
   if (IsPathEmpty(fPath))
      printf("empty ");
   printf("\nURI flags: ");
   if (IsAbsolute())
      printf("absolute-URI ");
   if (IsRelative())
      printf("relative-ref ");
   if (IsUri())
      printf("URI ");
   if (IsReference())
      printf("URI-reference ");
   printf("\n");
}

//______________________________________________________________________________
void TUri::Reset()
{
   // Initialize this URI object.
   // Set all TString members to empty string,
   // set all Bool_t members to kFALSE.

   fScheme = "";
   fUserinfo = "";
   fHost = "";
   fPort = "";
   fPath = "";
   fQuery = "";
   fFragment = "";

   fHasScheme = kFALSE;
   fHasUserinfo = kFALSE;
   fHasHost = kFALSE;
   fHasPort = kFALSE;
   fHasPath = kFALSE;
   fHasQuery = kFALSE;
   fHasFragment = kFALSE;
}

//______________________________________________________________________________
Bool_t TUri::SetUri(const TString &uri)
{
   // Parse URI and set the member variables accordingly,
   // returns kTRUE if URI validates, and kFALSE otherwise:
   // URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
   // hier-part   = "//" authority path-abempty
   //             / path-absolute
   //             / path-rootless
   //             / path-empty
   //

   // Reset member variables
   Reset();

   // regular expression taken from appendix B
   // reference points          12            3  4          5       6   7        8 9
   TPRegexp regexp = TPRegexp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)([?]([^#]*))?(#(.*))?");
   TObjArray *tokens = regexp.MatchS(uri);

   // collect bool values to see if all setters succeed
   Bool_t valid = kTRUE;
   //tokens->Print();
   switch (tokens->GetEntries()) {
      case 10:
         // URI contains fragment delimiter '#'
         valid &= SetFragment(((TObjString*) tokens->At(9))->GetString());
         // fallthrough

      case 8:
         // URI does not contain a fragment delimiter
         // if there is a query delimiter '?', set query
         if (!((TString)((TObjString*) tokens->At(6))->GetString()).IsNull())
            valid &= SetQuery(((TObjString*) tokens->At(7))->GetString());
         // fallthrough

      case 6:
         // URI does not contain fragment or query delimiters
         valid &= SetPath(((TObjString*) tokens->At(5))->GetString());
         // if there is an authority delimiter '//', set authority
         if (!((TString)((TObjString*) tokens->At(3))->GetString()).IsNull())
            valid &= SetAuthority(((TObjString*) tokens->At(4))->GetString());
         // if there is a scheme delimiter ':', set scheme
         if (!((TString)((TObjString*) tokens->At(1))->GetString()).IsNull())
            valid &= SetScheme(((TObjString*) tokens->At(2))->GetString());
         break;

      default:
         // regular expression did not match
         Error("SetUri", "URI \"%s\" is not is not compliant with RFC 3986.", uri.Data());
         valid = kFALSE;
   }

   // reset member variables once again, if one at least setter failed
   if (!valid)
      Reset();

   delete tokens;
   return valid;
}

//______________________________________________________________________________
const TString TUri::GetHierPart() const
{
   // hier-part   = "//" authority path-abempty
   //             / path-absolute
   //             / path-rootless
   //             / path-empty

   if (HasAuthority() && IsPathAbempty(fPath))
      return (TString("//") + GetAuthority() + fPath);
   else
      return fPath;
}

//______________________________________________________________________________
const TString TUri::GetRelativePart() const
{
   // relative-part = "//" authority path-abempty
   //               / path-absolute
   //               / path-noscheme
   //               / path-empty

   if (HasAuthority() && IsPathAbempty(fPath))
      return (TString("//") + GetAuthority() + fPath);
   else
      return fPath;
}

//______________________________________________________________________________
Bool_t TUri::SetHierPart(const TString &hier)
{
   // returns hier-part component of URI
   // hier-part   = "//" authority path-abempty
   //             / path-absolute
   //             / path-rootless
   //             / path-empty
   //

   /*  if ( IsPathAbsolute(hier) || IsPathRootless(hier) || IsPathEmpty(hier) ) {
     SetPath (hier);
     return kTRUE;
    }
    */

   // reference points:         1  2          3
   TPRegexp regexp = TPRegexp("^(//([^/?#]*))?([^?#]*)$");
   TObjArray *tokens = regexp.MatchS(hier);

   if (tokens->GetEntries() == 0) {
      Error("SetHierPart", "<hier-part> component \"%s\" of URI is not compliant with RFC 3986.", hier.Data());
      delete tokens;
      return false;
   }

   TString delm = ((TObjString*) tokens->At(1))->GetString();
   TString auth = ((TObjString*) tokens->At(2))->GetString();
   TString path = ((TObjString*) tokens->At(3))->GetString();

   Bool_t valid = kTRUE;

   if (!delm.IsNull() && IsPathAbempty(path)) {
      // URI contains an authority delimiter '//' ...
      valid &= SetAuthority(auth);
      valid &= SetPath(path);
   } else {
      // URI does not contain an authority
      if (IsPathAbsolute(path) || IsPathRootless(path) || IsPathEmpty(path))
         valid &= SetPath(path);
      else {
         valid = kFALSE;
         Error("SetHierPart", "<hier-part> component \"%s\" of URI is not compliant with RFC 3986.", hier.Data());
      }
   }
   delete tokens;
   return valid;
}

//______________________________________________________________________________
Bool_t TUri::IsHierPart(const TString &string)
{
   // Returns kTRUE if string qualifies as hier-part:
   //
   // hier-part   = "//" authority path-abempty
   //             / path-absolute
   //             / path-rootless
   //             / path-empty

   // use functionality of SetHierPart
   // in order to avoid duplicate code
   TUri uri;
   return (uri.SetHierPart(string));
}

//______________________________________________________________________________
Bool_t TUri::IsRelativePart(const TString &string)
{
   // Returns kTRUE is string qualifies as relative-part:
   // relative-part = "//" authority path-abempty
   //               / path-absolute
   //               / path-noscheme
   //               / path-empty

   // use functionality of SetRelativePart
   // in order to avoid duplicate code
   TUri uri;
   return (uri.SetRelativePart(string));
}

//______________________________________________________________________________
Bool_t TUri::SetRelativePart(const TString &relative)
{
   // Returns kTRUE is string qualifies as relative-part:
   // relative-part = "//" authority path-abempty
   //               / path-absolute
   //               / path-noscheme
   //               / path-empty

   // reference points:         1  2          3
   TPRegexp regexp = TPRegexp("^(//([^/?#]*))?([^?#]*)$");
   TObjArray *tokens = regexp.MatchS(relative);

   if (tokens->GetEntries() == 0) {
      Error("SetRelativePath", "<relative-part> component \"%s\" of URI is not compliant with RFC 3986.", relative.Data());
      delete tokens;
      return false;
   }
   TString delm = ((TObjString*) tokens->At(1))->GetString();
   TString auth = ((TObjString*) tokens->At(2))->GetString();
   TString path = ((TObjString*) tokens->At(3))->GetString();

   Bool_t valid = kTRUE;

   if (!delm.IsNull() && IsPathAbempty(path)) {
      // URI contains an authority delimiter '//' ...
      valid &= SetAuthority(auth);
      valid &= SetPath(path);
   } else {
      // URI does not contain an authority
      if (IsPathAbsolute(path) || IsPathNoscheme(path) || IsPathEmpty(path))
         valid &= SetPath(path);
      else {
         valid = kFALSE;
         Error("SetRelativePath", "<relative-part> component \"%s\" of URI is not compliant with RFC 3986.", relative.Data());
      }
   }
   delete tokens;
   return valid;
}

//______________________________________________________________________________
const TString TUri::PctEncode(const TString &source)
{
   // Percent-encode and return the given string according to RFC 3986
   // in principle, this function cannot fail or produce an error.

   TString sink = "";
   // iterate through source
   for (Int_t i = 0; i < source.Length(); i++) {
      if (IsUnreserved(TString(source(i)))) {
         // unreserved character -> copy
         sink = sink + source[i];
      } else {
         // reserved character -> encode to 2 digit hex
         // preceded by '%'
         char buffer[4];
         sprintf(buffer, "%%%02X", source[i]);
         sink = sink + buffer;
      }
   }
   return sink;
}

//______________________________________________________________________________
Bool_t TUri::IsHost(const TString &string)
{
   // Returns kTRUE if string qualifies as valid host component:
   // host = IP-literal / IPv4address / reg-name
   // implemented: host =  IPv4address / reg-name

   return (IsRegName(string) || IsIpv4(string));
}

//______________________________________________________________________________
Bool_t TUri::IsPath(const TString &string)
{
   // Retruns kTRUE if string qualifies as valid path component:
   // path          = path-abempty    ; begins with "/" or is empty
   //               / path-absolute   ; begins with "/" but not "//"
   //               / path-noscheme   ; begins with a non-colon segment
   //               / path-rootless   ; begins with a segment
   //               / path-empty      ; zero characters

   return (IsPathAbempty(string) ||
           IsPathAbsolute(string) ||
           IsPathNoscheme(string) ||
           IsPathRootless(string) ||
           IsPathEmpty(string));
}

//______________________________________________________________________________
Bool_t TUri::IsPathAbempty(const TString &string)
{
   // Returns kTRUE if string qualifies as valid path-abempty component:
   //    path-abempty  = *( "/" segment )
   //    segment       = *pchar

   return (TPRegexp(
              TString("^(/") + TString(kURI_pchar) + "*)*$"
           ).Match(string) > 0);
}

//______________________________________________________________________________
Bool_t TUri::IsPathAbsolute(const TString &string)
{
   // Returns kTRUE if string qualifies as valid path-absolute component
   //    path-absolute = "/" [ segment-nz *( "/" segment ) ]
   //    segment-nz    = 1*pchar
   //    segment       = *pchar

   return (TPRegexp(
              TString("^/(") + TString(kURI_pchar) + "+(/" + TString(kURI_pchar) + "*)*)?$"
           ).Match(string) > 0);
}

//______________________________________________________________________________
Bool_t TUri::IsPathNoscheme(const TString &string)
{
   // Returns kTRUE if string qualifies as valid path-noscheme component:
   // path-noscheme = segment-nz-nc *( "/" segment )
   // segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
   // segment       = *pchar

   return (TPRegexp(
              TString("^(([[:alpha:][:digit:]-._~!$&'()*+,;=@]|%[0-9A-Fa-f][0-9A-Fa-f])+)(/") + TString(kURI_pchar) + "*)*$"
           ).Match(string) > 0);
}

//______________________________________________________________________________
Bool_t TUri::IsPathRootless(const TString &string)
{
   // Returns kTRUE if string qualifies as valid path-rootless component:
   // path-rootless = segment-nz *( "/" segment )

   return TPRegexp(
             TString("^") + TString(kURI_pchar) + "+(/" + TString(kURI_pchar) + "*)*$"
          ).Match(string);
}

//______________________________________________________________________________
Bool_t TUri::IsPathEmpty(const TString &string)
{
   // Returns kTRUE if string qualifies as valid path-empty component:
   // path-empty    = 0<pchar>
   return TString(string).IsNull();
}

//______________________________________________________________________________
Bool_t TUri::IsPort(const TString &string)
{
   // Returns kTRUE if string qualifies as valid port component:
   // RFC 3986: port        = *DIGIT

   return (TPRegexp("^[[:digit:]]*$").Match(string) > 0);
}

//______________________________________________________________________________
Bool_t TUri::IsRegName(const TString &string)
{
   // Returns kTRUE if string qualifies as valid reg-name:
   //
   //  reg-name    = *( unreserved / pct-encoded / sub-delims )
   //  sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
   //                  / "*" / "+" / "," / ";" / "="
   //

   return (TPRegexp(
              "^([[:alpha:][:digit:]-._~!$&'()*+,;=]|%[0-9A-Fa-f][0-9A-Fa-f])*$").Match(string) > 0);
}

//______________________________________________________________________________
Bool_t TUri::IsIpv4(const TString &string)
{
   // Returns kTRUE, if string holds a valid IPv4 address
   // currently only decimal variant supported.
   // Existence of leadig 0s or numeric range remains unchecked
   // IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet.
   //
   return (TPRegexp(
              "^([[:digit:]]{1,3}[.]){3}[[:digit:]]{1,3}$").Match(string) > 0);
}

//______________________________________________________________________________
Bool_t TUri::IsUnreserved(const TString &string)
{
   // Returns kTRUE, if the given string does not contain
   // RFC 3986 reserved characters
   // unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"

   return (TPRegexp(
              "^" + TString(kURI_unreserved) + "*$").Match(string) > 0);
}

//______________________________________________________________________________
void TUri::Normalise()
{
   // Syntax based normalisation according to
   // RFC chapter 6.2.2.

   // case normalisation of host and scheme
   // cf. chapter 6.2.2.1
   fScheme.ToLower();
   if (fHasHost) {
      TString host = GetHost();
      host.ToLower();
      SetHost(host);
   }
   // percent-encoding normalisation (6.2.2.2) for
   // userinfo, host (reg-name), path, query, fragment
   fUserinfo = PctNormalise(PctDecodeUnreserved(fUserinfo));
   fHost = PctNormalise(PctDecodeUnreserved(fHost));
   fPath = PctNormalise(PctDecodeUnreserved(fPath));
   fQuery = PctNormalise(PctDecodeUnreserved(fQuery));
   fFragment = PctNormalise(PctDecodeUnreserved(fFragment));

   // path segment normalisation (6.2.2.3)
   if (fHasPath)
      SetPath(RemoveDotSegments(GetPath()));
}

//______________________________________________________________________________
TString const TUri::PctDecodeUnreserved(const TString &source)
{
   // Percent-decode the given string according to chapter 2.1
   // we assume a valid pct-encoded string.

   TString sink = "";
   Int_t i = 0;
   while (i < source.Length()) {
      if (source[i] == '%') {
         if (source.Length() < i+2) {
            // abort if out of bounds
            return sink;
         }
         // two hex digits follow -> decode to ASCII
         // upper nibble, bits 4-7
         char c1 = tolower(source[i + 1]) - '0';
         if (c1 > 9) // a-f
            c1 -= 39;
         // lower nibble, bits 0-3
         char c0 = tolower(source[i + 2]) - '0';
         if (c0 > 9) // a-f
            c0 -= 39;
         char decoded = c1 << 4 | c0;
         if (TPRegexp(kURI_unreserved).Match(decoded) > 0) {
            // we have an unreserved character -> store decoded version
            sink = sink + decoded;
         } else {
            // this is a reserved character
            TString pct = source(i,3);
            pct.ToUpper();
            sink = sink + pct;
         }
         // advance 2 characters
         i += 2;
      } else {
         // regular character -> copy
         sink = sink + source[i];
      }
      i++;
   }
   return sink;
}

//______________________________________________________________________________
TString const TUri::PctNormalise(const TString &source)
{
   // Normalise the percent-encoded parts of the string
   // i.e. uppercase the hexadecimal digits
   // %[:alpha:][:alpha:] -> %[:ALPHA:][:ALPHA:]

   TString sink = "";
   Int_t i = 0;
   while (i < source.Length()) {
      if (source[i] == '%') {
         if (source.Length() < i+2) {
            // abort if out of bounds
            return sink;
         }
         TString pct = source(i,3);
         // uppercase the pct part
         pct.ToUpper();
         sink = sink + pct;
         // advance 2 characters
         i += 2;
      } else {
         // regular character -> copy
         sink = sink + source[i];
      }
      i++;
   }
   return sink;
}

//______________________________________________________________________________
TString const TUri::PctDecode(const TString &source)
{
   // Percent-decode the given string according to chapter 2.1
   // we assume a valid pct-encoded string.

   TString sink = "";
   Int_t i = 0;
   while (i < source.Length()) {
      if (source[i] == '%') {
         if (source.Length() < i+2) {
            // abort if out of bounds
            return sink;
         }
         // two hex digits follow -> decode to ASCII
         // upper nibble, bits 4-7
         char c1 = tolower(source[i + 1]) - '0';
         if (c1 > 9) // a-f
            c1 -= 39;
         // lower nibble, bits 0-3
         char c0 = tolower(source[i + 2]) - '0';
         if (c0 > 9) // a-f
            c0 -= 39;
         sink = sink + (char)(c1 << 4 | c0);
         // advance 2 characters
         i += 2;
      } else {
         // regular character -> copy
         sink = sink + source[i];
      }
      i++;
   }
   return sink;
}

//______________________________________________________________________________
TUri TUri::Transform(const TUri &reference, const TUri &base)
{
   // Transform a URI reference into its target URI using
   // given a base URI.
   // This is an implementation of the pseudocode in chapter 5.2.2.

   TUri target;
   if (reference.HasScheme()) {
      target.SetScheme(reference.GetScheme());
      if (reference.HasAuthority())
         target.SetAuthority(reference.GetAuthority());
      if (reference.HasPath())
         target.SetPath(RemoveDotSegments(reference.GetPath()));
      if (reference.HasQuery())
         target.SetQuery(reference.GetQuery());
   } else {
      if (reference.HasAuthority()) {
         target.SetAuthority(reference.GetAuthority());
         if (reference.HasPath())
            target.SetPath(RemoveDotSegments(reference.GetPath()));
         if (reference.HasQuery())
            target.SetQuery(reference.GetQuery());
      } else {
         if (reference.GetPath().IsNull()) {
            target.SetPath(base.GetPath());
            if (reference.HasQuery()) {
               target.SetQuery(reference.GetQuery());
            } else {
               if (base.HasQuery())
                  target.SetQuery(base.GetQuery());
            }
         } else {
            if (reference.GetPath().BeginsWith("/")) {
               target.SetPath(RemoveDotSegments(reference.GetPath()));
            } else {
               target.SetPath(RemoveDotSegments(MergePaths(reference, base)));
            }
            if (reference.HasQuery())
               target.SetQuery(reference.GetQuery());
         }
         if (base.HasAuthority())
            target.SetAuthority(base.GetAuthority());
      }
      if (base.HasScheme())
         target.SetScheme(base.GetScheme());
   }
   if (reference.HasFragment())
      target.SetFragment(reference.GetFragment());
   return target;
}

//______________________________________________________________________________
const TString TUri::MergePaths(const TUri &reference, const TUri &base)
{
   // RFC 3986, 5.3.2.
   // If the base URI has a defined authority component and an empty
   // path, then return a string consisting of "/" concatenated with the
   // reference's path; otherwise,
   // return a string consisting of the reference's path component
   // appended to all but the last segment of the base URI's path (i.e.,
   // excluding any characters after the right-most "/" in the base URI
   // path, or excluding the entire base URI path if it does not contain
   // any "/" characters).

   TString result = "";
   if (base.HasAuthority() && base.GetPath().IsNull()) {
      result = TString("/") + reference.GetPath();
   } else {
      TString basepath = base.GetPath();
      Ssiz_t last = basepath.Last('/');
      if (last == -1)
         result = reference.GetPath();
      else
         result = basepath(0, last + 1) + reference.GetPath();
   }
   return result;
}
 TUri.cxx:1
 TUri.cxx:2
 TUri.cxx:3
 TUri.cxx:4
 TUri.cxx:5
 TUri.cxx:6
 TUri.cxx:7
 TUri.cxx:8
 TUri.cxx:9
 TUri.cxx:10
 TUri.cxx:11
 TUri.cxx:12
 TUri.cxx:13
 TUri.cxx:14
 TUri.cxx:15
 TUri.cxx:16
 TUri.cxx:17
 TUri.cxx:18
 TUri.cxx:19
 TUri.cxx:20
 TUri.cxx:21
 TUri.cxx:22
 TUri.cxx:23
 TUri.cxx:24
 TUri.cxx:25
 TUri.cxx:26
 TUri.cxx:27
 TUri.cxx:28
 TUri.cxx:29
 TUri.cxx:30
 TUri.cxx:31
 TUri.cxx:32
 TUri.cxx:33
 TUri.cxx:34
 TUri.cxx:35
 TUri.cxx:36
 TUri.cxx:37
 TUri.cxx:38
 TUri.cxx:39
 TUri.cxx:40
 TUri.cxx:41
 TUri.cxx:42
 TUri.cxx:43
 TUri.cxx:44
 TUri.cxx:45
 TUri.cxx:46
 TUri.cxx:47
 TUri.cxx:48
 TUri.cxx:49
 TUri.cxx:50
 TUri.cxx:51
 TUri.cxx:52
 TUri.cxx:53
 TUri.cxx:54
 TUri.cxx:55
 TUri.cxx:56
 TUri.cxx:57
 TUri.cxx:58
 TUri.cxx:59
 TUri.cxx:60
 TUri.cxx:61
 TUri.cxx:62
 TUri.cxx:63
 TUri.cxx:64
 TUri.cxx:65
 TUri.cxx:66
 TUri.cxx:67
 TUri.cxx:68
 TUri.cxx:69
 TUri.cxx:70
 TUri.cxx:71
 TUri.cxx:72
 TUri.cxx:73
 TUri.cxx:74
 TUri.cxx:75
 TUri.cxx:76
 TUri.cxx:77
 TUri.cxx:78
 TUri.cxx:79
 TUri.cxx:80
 TUri.cxx:81
 TUri.cxx:82
 TUri.cxx:83
 TUri.cxx:84
 TUri.cxx:85
 TUri.cxx:86
 TUri.cxx:87
 TUri.cxx:88
 TUri.cxx:89
 TUri.cxx:90
 TUri.cxx:91
 TUri.cxx:92
 TUri.cxx:93
 TUri.cxx:94
 TUri.cxx:95
 TUri.cxx:96
 TUri.cxx:97
 TUri.cxx:98
 TUri.cxx:99
 TUri.cxx:100
 TUri.cxx:101
 TUri.cxx:102
 TUri.cxx:103
 TUri.cxx:104
 TUri.cxx:105
 TUri.cxx:106
 TUri.cxx:107
 TUri.cxx:108
 TUri.cxx:109
 TUri.cxx:110
 TUri.cxx:111
 TUri.cxx:112
 TUri.cxx:113
 TUri.cxx:114
 TUri.cxx:115
 TUri.cxx:116
 TUri.cxx:117
 TUri.cxx:118
 TUri.cxx:119
 TUri.cxx:120
 TUri.cxx:121
 TUri.cxx:122
 TUri.cxx:123
 TUri.cxx:124
 TUri.cxx:125
 TUri.cxx:126
 TUri.cxx:127
 TUri.cxx:128
 TUri.cxx:129
 TUri.cxx:130
 TUri.cxx:131
 TUri.cxx:132
 TUri.cxx:133
 TUri.cxx:134
 TUri.cxx:135
 TUri.cxx:136
 TUri.cxx:137
 TUri.cxx:138
 TUri.cxx:139
 TUri.cxx:140
 TUri.cxx:141
 TUri.cxx:142
 TUri.cxx:143
 TUri.cxx:144
 TUri.cxx:145
 TUri.cxx:146
 TUri.cxx:147
 TUri.cxx:148
 TUri.cxx:149
 TUri.cxx:150
 TUri.cxx:151
 TUri.cxx:152
 TUri.cxx:153
 TUri.cxx:154
 TUri.cxx:155
 TUri.cxx:156
 TUri.cxx:157
 TUri.cxx:158
 TUri.cxx:159
 TUri.cxx:160
 TUri.cxx:161
 TUri.cxx:162
 TUri.cxx:163
 TUri.cxx:164
 TUri.cxx:165
 TUri.cxx:166
 TUri.cxx:167
 TUri.cxx:168
 TUri.cxx:169
 TUri.cxx:170
 TUri.cxx:171
 TUri.cxx:172
 TUri.cxx:173
 TUri.cxx:174
 TUri.cxx:175
 TUri.cxx:176
 TUri.cxx:177
 TUri.cxx:178
 TUri.cxx:179
 TUri.cxx:180
 TUri.cxx:181
 TUri.cxx:182
 TUri.cxx:183
 TUri.cxx:184
 TUri.cxx:185
 TUri.cxx:186
 TUri.cxx:187
 TUri.cxx:188
 TUri.cxx:189
 TUri.cxx:190
 TUri.cxx:191
 TUri.cxx:192
 TUri.cxx:193
 TUri.cxx:194
 TUri.cxx:195
 TUri.cxx:196
 TUri.cxx:197
 TUri.cxx:198
 TUri.cxx:199
 TUri.cxx:200
 TUri.cxx:201
 TUri.cxx:202
 TUri.cxx:203
 TUri.cxx:204
 TUri.cxx:205
 TUri.cxx:206
 TUri.cxx:207
 TUri.cxx:208
 TUri.cxx:209
 TUri.cxx:210
 TUri.cxx:211
 TUri.cxx:212
 TUri.cxx:213
 TUri.cxx:214
 TUri.cxx:215
 TUri.cxx:216
 TUri.cxx:217
 TUri.cxx:218
 TUri.cxx:219
 TUri.cxx:220
 TUri.cxx:221
 TUri.cxx:222
 TUri.cxx:223
 TUri.cxx:224
 TUri.cxx:225
 TUri.cxx:226
 TUri.cxx:227
 TUri.cxx:228
 TUri.cxx:229
 TUri.cxx:230
 TUri.cxx:231
 TUri.cxx:232
 TUri.cxx:233
 TUri.cxx:234
 TUri.cxx:235
 TUri.cxx:236
 TUri.cxx:237
 TUri.cxx:238
 TUri.cxx:239
 TUri.cxx:240
 TUri.cxx:241
 TUri.cxx:242
 TUri.cxx:243
 TUri.cxx:244
 TUri.cxx:245
 TUri.cxx:246
 TUri.cxx:247
 TUri.cxx:248
 TUri.cxx:249
 TUri.cxx:250
 TUri.cxx:251
 TUri.cxx:252
 TUri.cxx:253
 TUri.cxx:254
 TUri.cxx:255
 TUri.cxx:256
 TUri.cxx:257
 TUri.cxx:258
 TUri.cxx:259
 TUri.cxx:260
 TUri.cxx:261
 TUri.cxx:262
 TUri.cxx:263
 TUri.cxx:264
 TUri.cxx:265
 TUri.cxx:266
 TUri.cxx:267
 TUri.cxx:268
 TUri.cxx:269
 TUri.cxx:270
 TUri.cxx:271
 TUri.cxx:272
 TUri.cxx:273
 TUri.cxx:274
 TUri.cxx:275
 TUri.cxx:276
 TUri.cxx:277
 TUri.cxx:278
 TUri.cxx:279
 TUri.cxx:280
 TUri.cxx:281
 TUri.cxx:282
 TUri.cxx:283
 TUri.cxx:284
 TUri.cxx:285
 TUri.cxx:286
 TUri.cxx:287
 TUri.cxx:288
 TUri.cxx:289
 TUri.cxx:290
 TUri.cxx:291
 TUri.cxx:292
 TUri.cxx:293
 TUri.cxx:294
 TUri.cxx:295
 TUri.cxx:296
 TUri.cxx:297
 TUri.cxx:298
 TUri.cxx:299
 TUri.cxx:300
 TUri.cxx:301
 TUri.cxx:302
 TUri.cxx:303
 TUri.cxx:304
 TUri.cxx:305
 TUri.cxx:306
 TUri.cxx:307
 TUri.cxx:308
 TUri.cxx:309
 TUri.cxx:310
 TUri.cxx:311
 TUri.cxx:312
 TUri.cxx:313
 TUri.cxx:314
 TUri.cxx:315
 TUri.cxx:316
 TUri.cxx:317
 TUri.cxx:318
 TUri.cxx:319
 TUri.cxx:320
 TUri.cxx:321
 TUri.cxx:322
 TUri.cxx:323
 TUri.cxx:324
 TUri.cxx:325
 TUri.cxx:326
 TUri.cxx:327
 TUri.cxx:328
 TUri.cxx:329
 TUri.cxx:330
 TUri.cxx:331
 TUri.cxx:332
 TUri.cxx:333
 TUri.cxx:334
 TUri.cxx:335
 TUri.cxx:336
 TUri.cxx:337
 TUri.cxx:338
 TUri.cxx:339
 TUri.cxx:340
 TUri.cxx:341
 TUri.cxx:342
 TUri.cxx:343
 TUri.cxx:344
 TUri.cxx:345
 TUri.cxx:346
 TUri.cxx:347
 TUri.cxx:348
 TUri.cxx:349
 TUri.cxx:350
 TUri.cxx:351
 TUri.cxx:352
 TUri.cxx:353
 TUri.cxx:354
 TUri.cxx:355
 TUri.cxx:356
 TUri.cxx:357
 TUri.cxx:358
 TUri.cxx:359
 TUri.cxx:360
 TUri.cxx:361
 TUri.cxx:362
 TUri.cxx:363
 TUri.cxx:364
 TUri.cxx:365
 TUri.cxx:366
 TUri.cxx:367
 TUri.cxx:368
 TUri.cxx:369
 TUri.cxx:370
 TUri.cxx:371
 TUri.cxx:372
 TUri.cxx:373
 TUri.cxx:374
 TUri.cxx:375
 TUri.cxx:376
 TUri.cxx:377
 TUri.cxx:378
 TUri.cxx:379
 TUri.cxx:380
 TUri.cxx:381
 TUri.cxx:382
 TUri.cxx:383
 TUri.cxx:384
 TUri.cxx:385
 TUri.cxx:386
 TUri.cxx:387
 TUri.cxx:388
 TUri.cxx:389
 TUri.cxx:390
 TUri.cxx:391
 TUri.cxx:392
 TUri.cxx:393
 TUri.cxx:394
 TUri.cxx:395
 TUri.cxx:396
 TUri.cxx:397
 TUri.cxx:398
 TUri.cxx:399
 TUri.cxx:400
 TUri.cxx:401
 TUri.cxx:402
 TUri.cxx:403
 TUri.cxx:404
 TUri.cxx:405
 TUri.cxx:406
 TUri.cxx:407
 TUri.cxx:408
 TUri.cxx:409
 TUri.cxx:410
 TUri.cxx:411
 TUri.cxx:412
 TUri.cxx:413
 TUri.cxx:414
 TUri.cxx:415
 TUri.cxx:416
 TUri.cxx:417
 TUri.cxx:418
 TUri.cxx:419
 TUri.cxx:420
 TUri.cxx:421
 TUri.cxx:422
 TUri.cxx:423
 TUri.cxx:424
 TUri.cxx:425
 TUri.cxx:426
 TUri.cxx:427
 TUri.cxx:428
 TUri.cxx:429
 TUri.cxx:430
 TUri.cxx:431
 TUri.cxx:432
 TUri.cxx:433
 TUri.cxx:434
 TUri.cxx:435
 TUri.cxx:436
 TUri.cxx:437
 TUri.cxx:438
 TUri.cxx:439
 TUri.cxx:440
 TUri.cxx:441
 TUri.cxx:442
 TUri.cxx:443
 TUri.cxx:444
 TUri.cxx:445
 TUri.cxx:446
 TUri.cxx:447
 TUri.cxx:448
 TUri.cxx:449
 TUri.cxx:450
 TUri.cxx:451
 TUri.cxx:452
 TUri.cxx:453
 TUri.cxx:454
 TUri.cxx:455
 TUri.cxx:456
 TUri.cxx:457
 TUri.cxx:458
 TUri.cxx:459
 TUri.cxx:460
 TUri.cxx:461
 TUri.cxx:462
 TUri.cxx:463
 TUri.cxx:464
 TUri.cxx:465
 TUri.cxx:466
 TUri.cxx:467
 TUri.cxx:468
 TUri.cxx:469
 TUri.cxx:470
 TUri.cxx:471
 TUri.cxx:472
 TUri.cxx:473
 TUri.cxx:474
 TUri.cxx:475
 TUri.cxx:476
 TUri.cxx:477
 TUri.cxx:478
 TUri.cxx:479
 TUri.cxx:480
 TUri.cxx:481
 TUri.cxx:482
 TUri.cxx:483
 TUri.cxx:484
 TUri.cxx:485
 TUri.cxx:486
 TUri.cxx:487
 TUri.cxx:488
 TUri.cxx:489
 TUri.cxx:490
 TUri.cxx:491
 TUri.cxx:492
 TUri.cxx:493
 TUri.cxx:494
 TUri.cxx:495
 TUri.cxx:496
 TUri.cxx:497
 TUri.cxx:498
 TUri.cxx:499
 TUri.cxx:500
 TUri.cxx:501
 TUri.cxx:502
 TUri.cxx:503
 TUri.cxx:504
 TUri.cxx:505
 TUri.cxx:506
 TUri.cxx:507
 TUri.cxx:508
 TUri.cxx:509
 TUri.cxx:510
 TUri.cxx:511
 TUri.cxx:512
 TUri.cxx:513
 TUri.cxx:514
 TUri.cxx:515
 TUri.cxx:516
 TUri.cxx:517
 TUri.cxx:518
 TUri.cxx:519
 TUri.cxx:520
 TUri.cxx:521
 TUri.cxx:522
 TUri.cxx:523
 TUri.cxx:524
 TUri.cxx:525
 TUri.cxx:526
 TUri.cxx:527
 TUri.cxx:528
 TUri.cxx:529
 TUri.cxx:530
 TUri.cxx:531
 TUri.cxx:532
 TUri.cxx:533
 TUri.cxx:534
 TUri.cxx:535
 TUri.cxx:536
 TUri.cxx:537
 TUri.cxx:538
 TUri.cxx:539
 TUri.cxx:540
 TUri.cxx:541
 TUri.cxx:542
 TUri.cxx:543
 TUri.cxx:544
 TUri.cxx:545
 TUri.cxx:546
 TUri.cxx:547
 TUri.cxx:548
 TUri.cxx:549
 TUri.cxx:550
 TUri.cxx:551
 TUri.cxx:552
 TUri.cxx:553
 TUri.cxx:554
 TUri.cxx:555
 TUri.cxx:556
 TUri.cxx:557
 TUri.cxx:558
 TUri.cxx:559
 TUri.cxx:560
 TUri.cxx:561
 TUri.cxx:562
 TUri.cxx:563
 TUri.cxx:564
 TUri.cxx:565
 TUri.cxx:566
 TUri.cxx:567
 TUri.cxx:568
 TUri.cxx:569
 TUri.cxx:570
 TUri.cxx:571
 TUri.cxx:572
 TUri.cxx:573
 TUri.cxx:574
 TUri.cxx:575
 TUri.cxx:576
 TUri.cxx:577
 TUri.cxx:578
 TUri.cxx:579
 TUri.cxx:580
 TUri.cxx:581
 TUri.cxx:582
 TUri.cxx:583
 TUri.cxx:584
 TUri.cxx:585
 TUri.cxx:586
 TUri.cxx:587
 TUri.cxx:588
 TUri.cxx:589
 TUri.cxx:590
 TUri.cxx:591
 TUri.cxx:592
 TUri.cxx:593
 TUri.cxx:594
 TUri.cxx:595
 TUri.cxx:596
 TUri.cxx:597
 TUri.cxx:598
 TUri.cxx:599
 TUri.cxx:600
 TUri.cxx:601
 TUri.cxx:602
 TUri.cxx:603
 TUri.cxx:604
 TUri.cxx:605
 TUri.cxx:606
 TUri.cxx:607
 TUri.cxx:608
 TUri.cxx:609
 TUri.cxx:610
 TUri.cxx:611
 TUri.cxx:612
 TUri.cxx:613
 TUri.cxx:614
 TUri.cxx:615
 TUri.cxx:616
 TUri.cxx:617
 TUri.cxx:618
 TUri.cxx:619
 TUri.cxx:620
 TUri.cxx:621
 TUri.cxx:622
 TUri.cxx:623
 TUri.cxx:624
 TUri.cxx:625
 TUri.cxx:626
 TUri.cxx:627
 TUri.cxx:628
 TUri.cxx:629
 TUri.cxx:630
 TUri.cxx:631
 TUri.cxx:632
 TUri.cxx:633
 TUri.cxx:634
 TUri.cxx:635
 TUri.cxx:636
 TUri.cxx:637
 TUri.cxx:638
 TUri.cxx:639
 TUri.cxx:640
 TUri.cxx:641
 TUri.cxx:642
 TUri.cxx:643
 TUri.cxx:644
 TUri.cxx:645
 TUri.cxx:646
 TUri.cxx:647
 TUri.cxx:648
 TUri.cxx:649
 TUri.cxx:650
 TUri.cxx:651
 TUri.cxx:652
 TUri.cxx:653
 TUri.cxx:654
 TUri.cxx:655
 TUri.cxx:656
 TUri.cxx:657
 TUri.cxx:658
 TUri.cxx:659
 TUri.cxx:660
 TUri.cxx:661
 TUri.cxx:662
 TUri.cxx:663
 TUri.cxx:664
 TUri.cxx:665
 TUri.cxx:666
 TUri.cxx:667
 TUri.cxx:668
 TUri.cxx:669
 TUri.cxx:670
 TUri.cxx:671
 TUri.cxx:672
 TUri.cxx:673
 TUri.cxx:674
 TUri.cxx:675
 TUri.cxx:676
 TUri.cxx:677
 TUri.cxx:678
 TUri.cxx:679
 TUri.cxx:680
 TUri.cxx:681
 TUri.cxx:682
 TUri.cxx:683
 TUri.cxx:684
 TUri.cxx:685
 TUri.cxx:686
 TUri.cxx:687
 TUri.cxx:688
 TUri.cxx:689
 TUri.cxx:690
 TUri.cxx:691
 TUri.cxx:692
 TUri.cxx:693
 TUri.cxx:694
 TUri.cxx:695
 TUri.cxx:696
 TUri.cxx:697
 TUri.cxx:698
 TUri.cxx:699
 TUri.cxx:700
 TUri.cxx:701
 TUri.cxx:702
 TUri.cxx:703
 TUri.cxx:704
 TUri.cxx:705
 TUri.cxx:706
 TUri.cxx:707
 TUri.cxx:708
 TUri.cxx:709
 TUri.cxx:710
 TUri.cxx:711
 TUri.cxx:712
 TUri.cxx:713
 TUri.cxx:714
 TUri.cxx:715
 TUri.cxx:716
 TUri.cxx:717
 TUri.cxx:718
 TUri.cxx:719
 TUri.cxx:720
 TUri.cxx:721
 TUri.cxx:722
 TUri.cxx:723
 TUri.cxx:724
 TUri.cxx:725
 TUri.cxx:726
 TUri.cxx:727
 TUri.cxx:728
 TUri.cxx:729
 TUri.cxx:730
 TUri.cxx:731
 TUri.cxx:732
 TUri.cxx:733
 TUri.cxx:734
 TUri.cxx:735
 TUri.cxx:736
 TUri.cxx:737
 TUri.cxx:738
 TUri.cxx:739
 TUri.cxx:740
 TUri.cxx:741
 TUri.cxx:742
 TUri.cxx:743
 TUri.cxx:744
 TUri.cxx:745
 TUri.cxx:746
 TUri.cxx:747
 TUri.cxx:748
 TUri.cxx:749
 TUri.cxx:750
 TUri.cxx:751
 TUri.cxx:752
 TUri.cxx:753
 TUri.cxx:754
 TUri.cxx:755
 TUri.cxx:756
 TUri.cxx:757
 TUri.cxx:758
 TUri.cxx:759
 TUri.cxx:760
 TUri.cxx:761
 TUri.cxx:762
 TUri.cxx:763
 TUri.cxx:764
 TUri.cxx:765
 TUri.cxx:766
 TUri.cxx:767
 TUri.cxx:768
 TUri.cxx:769
 TUri.cxx:770
 TUri.cxx:771
 TUri.cxx:772
 TUri.cxx:773
 TUri.cxx:774
 TUri.cxx:775
 TUri.cxx:776
 TUri.cxx:777
 TUri.cxx:778
 TUri.cxx:779
 TUri.cxx:780
 TUri.cxx:781
 TUri.cxx:782
 TUri.cxx:783
 TUri.cxx:784
 TUri.cxx:785
 TUri.cxx:786
 TUri.cxx:787
 TUri.cxx:788
 TUri.cxx:789
 TUri.cxx:790
 TUri.cxx:791
 TUri.cxx:792
 TUri.cxx:793
 TUri.cxx:794
 TUri.cxx:795
 TUri.cxx:796
 TUri.cxx:797
 TUri.cxx:798
 TUri.cxx:799
 TUri.cxx:800
 TUri.cxx:801
 TUri.cxx:802
 TUri.cxx:803
 TUri.cxx:804
 TUri.cxx:805
 TUri.cxx:806
 TUri.cxx:807
 TUri.cxx:808
 TUri.cxx:809
 TUri.cxx:810
 TUri.cxx:811
 TUri.cxx:812
 TUri.cxx:813
 TUri.cxx:814
 TUri.cxx:815
 TUri.cxx:816
 TUri.cxx:817
 TUri.cxx:818
 TUri.cxx:819
 TUri.cxx:820
 TUri.cxx:821
 TUri.cxx:822
 TUri.cxx:823
 TUri.cxx:824
 TUri.cxx:825
 TUri.cxx:826
 TUri.cxx:827
 TUri.cxx:828
 TUri.cxx:829
 TUri.cxx:830
 TUri.cxx:831
 TUri.cxx:832
 TUri.cxx:833
 TUri.cxx:834
 TUri.cxx:835
 TUri.cxx:836
 TUri.cxx:837
 TUri.cxx:838
 TUri.cxx:839
 TUri.cxx:840
 TUri.cxx:841
 TUri.cxx:842
 TUri.cxx:843
 TUri.cxx:844
 TUri.cxx:845
 TUri.cxx:846
 TUri.cxx:847
 TUri.cxx:848
 TUri.cxx:849
 TUri.cxx:850
 TUri.cxx:851
 TUri.cxx:852
 TUri.cxx:853
 TUri.cxx:854
 TUri.cxx:855
 TUri.cxx:856
 TUri.cxx:857
 TUri.cxx:858
 TUri.cxx:859
 TUri.cxx:860
 TUri.cxx:861
 TUri.cxx:862
 TUri.cxx:863
 TUri.cxx:864
 TUri.cxx:865
 TUri.cxx:866
 TUri.cxx:867
 TUri.cxx:868
 TUri.cxx:869
 TUri.cxx:870
 TUri.cxx:871
 TUri.cxx:872
 TUri.cxx:873
 TUri.cxx:874
 TUri.cxx:875
 TUri.cxx:876
 TUri.cxx:877
 TUri.cxx:878
 TUri.cxx:879
 TUri.cxx:880
 TUri.cxx:881
 TUri.cxx:882
 TUri.cxx:883
 TUri.cxx:884
 TUri.cxx:885
 TUri.cxx:886
 TUri.cxx:887
 TUri.cxx:888
 TUri.cxx:889
 TUri.cxx:890
 TUri.cxx:891
 TUri.cxx:892
 TUri.cxx:893
 TUri.cxx:894
 TUri.cxx:895
 TUri.cxx:896
 TUri.cxx:897
 TUri.cxx:898
 TUri.cxx:899
 TUri.cxx:900
 TUri.cxx:901
 TUri.cxx:902
 TUri.cxx:903
 TUri.cxx:904
 TUri.cxx:905
 TUri.cxx:906
 TUri.cxx:907
 TUri.cxx:908
 TUri.cxx:909
 TUri.cxx:910
 TUri.cxx:911
 TUri.cxx:912
 TUri.cxx:913
 TUri.cxx:914
 TUri.cxx:915
 TUri.cxx:916
 TUri.cxx:917
 TUri.cxx:918
 TUri.cxx:919
 TUri.cxx:920
 TUri.cxx:921
 TUri.cxx:922
 TUri.cxx:923
 TUri.cxx:924
 TUri.cxx:925
 TUri.cxx:926
 TUri.cxx:927
 TUri.cxx:928
 TUri.cxx:929
 TUri.cxx:930
 TUri.cxx:931
 TUri.cxx:932
 TUri.cxx:933
 TUri.cxx:934
 TUri.cxx:935
 TUri.cxx:936
 TUri.cxx:937
 TUri.cxx:938
 TUri.cxx:939
 TUri.cxx:940
 TUri.cxx:941
 TUri.cxx:942
 TUri.cxx:943
 TUri.cxx:944
 TUri.cxx:945
 TUri.cxx:946
 TUri.cxx:947
 TUri.cxx:948
 TUri.cxx:949
 TUri.cxx:950
 TUri.cxx:951
 TUri.cxx:952
 TUri.cxx:953
 TUri.cxx:954
 TUri.cxx:955
 TUri.cxx:956
 TUri.cxx:957
 TUri.cxx:958
 TUri.cxx:959
 TUri.cxx:960
 TUri.cxx:961
 TUri.cxx:962
 TUri.cxx:963
 TUri.cxx:964
 TUri.cxx:965
 TUri.cxx:966
 TUri.cxx:967
 TUri.cxx:968
 TUri.cxx:969
 TUri.cxx:970
 TUri.cxx:971
 TUri.cxx:972
 TUri.cxx:973
 TUri.cxx:974
 TUri.cxx:975
 TUri.cxx:976
 TUri.cxx:977
 TUri.cxx:978
 TUri.cxx:979
 TUri.cxx:980
 TUri.cxx:981
 TUri.cxx:982
 TUri.cxx:983
 TUri.cxx:984
 TUri.cxx:985
 TUri.cxx:986
 TUri.cxx:987
 TUri.cxx:988
 TUri.cxx:989
 TUri.cxx:990
 TUri.cxx:991
 TUri.cxx:992
 TUri.cxx:993
 TUri.cxx:994
 TUri.cxx:995
 TUri.cxx:996
 TUri.cxx:997
 TUri.cxx:998
 TUri.cxx:999
 TUri.cxx:1000
 TUri.cxx:1001
 TUri.cxx:1002
 TUri.cxx:1003
 TUri.cxx:1004
 TUri.cxx:1005
 TUri.cxx:1006
 TUri.cxx:1007
 TUri.cxx:1008
 TUri.cxx:1009
 TUri.cxx:1010
 TUri.cxx:1011
 TUri.cxx:1012
 TUri.cxx:1013
 TUri.cxx:1014
 TUri.cxx:1015
 TUri.cxx:1016
 TUri.cxx:1017
 TUri.cxx:1018
 TUri.cxx:1019
 TUri.cxx:1020
 TUri.cxx:1021
 TUri.cxx:1022
 TUri.cxx:1023
 TUri.cxx:1024
 TUri.cxx:1025
 TUri.cxx:1026
 TUri.cxx:1027
 TUri.cxx:1028
 TUri.cxx:1029
 TUri.cxx:1030
 TUri.cxx:1031
 TUri.cxx:1032
 TUri.cxx:1033
 TUri.cxx:1034
 TUri.cxx:1035
 TUri.cxx:1036
 TUri.cxx:1037
 TUri.cxx:1038
 TUri.cxx:1039
 TUri.cxx:1040
 TUri.cxx:1041
 TUri.cxx:1042
 TUri.cxx:1043
 TUri.cxx:1044
 TUri.cxx:1045
 TUri.cxx:1046
 TUri.cxx:1047
 TUri.cxx:1048
 TUri.cxx:1049
 TUri.cxx:1050
 TUri.cxx:1051
 TUri.cxx:1052
 TUri.cxx:1053
 TUri.cxx:1054
 TUri.cxx:1055
 TUri.cxx:1056
 TUri.cxx:1057
 TUri.cxx:1058
 TUri.cxx:1059
 TUri.cxx:1060
 TUri.cxx:1061
 TUri.cxx:1062
 TUri.cxx:1063
 TUri.cxx:1064
 TUri.cxx:1065
 TUri.cxx:1066
 TUri.cxx:1067
 TUri.cxx:1068
 TUri.cxx:1069
 TUri.cxx:1070
 TUri.cxx:1071
 TUri.cxx:1072
 TUri.cxx:1073
 TUri.cxx:1074
 TUri.cxx:1075
 TUri.cxx:1076
 TUri.cxx:1077
 TUri.cxx:1078
 TUri.cxx:1079
 TUri.cxx:1080
 TUri.cxx:1081
 TUri.cxx:1082
 TUri.cxx:1083
 TUri.cxx:1084
 TUri.cxx:1085
 TUri.cxx:1086
 TUri.cxx:1087
 TUri.cxx:1088
 TUri.cxx:1089
 TUri.cxx:1090
 TUri.cxx:1091
 TUri.cxx:1092
 TUri.cxx:1093
 TUri.cxx:1094
 TUri.cxx:1095
 TUri.cxx:1096
 TUri.cxx:1097
 TUri.cxx:1098
 TUri.cxx:1099
 TUri.cxx:1100
 TUri.cxx:1101
 TUri.cxx:1102
 TUri.cxx:1103
 TUri.cxx:1104
 TUri.cxx:1105
 TUri.cxx:1106
 TUri.cxx:1107
 TUri.cxx:1108
 TUri.cxx:1109
 TUri.cxx:1110
 TUri.cxx:1111
 TUri.cxx:1112
 TUri.cxx:1113
 TUri.cxx:1114
 TUri.cxx:1115
 TUri.cxx:1116
 TUri.cxx:1117
 TUri.cxx:1118
 TUri.cxx:1119
 TUri.cxx:1120
 TUri.cxx:1121
 TUri.cxx:1122
 TUri.cxx:1123
 TUri.cxx:1124
 TUri.cxx:1125
 TUri.cxx:1126
 TUri.cxx:1127
 TUri.cxx:1128
 TUri.cxx:1129
 TUri.cxx:1130
 TUri.cxx:1131
 TUri.cxx:1132
 TUri.cxx:1133
 TUri.cxx:1134
 TUri.cxx:1135
 TUri.cxx:1136
 TUri.cxx:1137
 TUri.cxx:1138
 TUri.cxx:1139
 TUri.cxx:1140