You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ta...@apache.org on 2008/12/16 19:56:43 UTC

svn commit: r727119 - in /activemq/activemq-cpp/trunk/src/main/decaf/net: URI.cpp URI.h

Author: tabish
Date: Tue Dec 16 10:56:43 2008
New Revision: 727119

URL: http://svn.apache.org/viewvc?rev=727119&view=rev
Log:
Partially working URI class

Modified:
    activemq/activemq-cpp/trunk/src/main/decaf/net/URI.cpp
    activemq/activemq-cpp/trunk/src/main/decaf/net/URI.h

Modified: activemq/activemq-cpp/trunk/src/main/decaf/net/URI.cpp
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/trunk/src/main/decaf/net/URI.cpp?rev=727119&r1=727118&r2=727119&view=diff
==============================================================================
--- activemq/activemq-cpp/trunk/src/main/decaf/net/URI.cpp (original)
+++ activemq/activemq-cpp/trunk/src/main/decaf/net/URI.cpp Tue Dec 16 10:56:43 2008
@@ -18,10 +18,17 @@
 #include "URI.h"
 
 #include <apr_strings.h>
+#include <apr_lib.h>
 #include <decaf/lang/Integer.h>
+#include <decaf/internal/net/URIHelper.h>
 
+#include <decaf/internal/net/URIEncoderDecoder.h>
+
+using namespace std;
 using namespace decaf;
 using namespace decaf::net;
+using namespace decaf::internal;
+using namespace decaf::internal::net;
 using namespace decaf::lang;
 using namespace decaf::lang::exceptions;
 
@@ -33,10 +40,14 @@
 const std::string URI::allLegal = unreserved + reserved;
 
 ////////////////////////////////////////////////////////////////////////////////
+URI::URI() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
 URI::URI( const std::string& uri ) throw ( URISyntaxException) {
 
-    this->uriString = NULL;
-    this->parseURI( uri );
+    this->uriString = uri;
+    this->parseURI( uri, false );
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -63,7 +74,7 @@
     }
 
     // Now hand of to the main parse function.
-    this->parseURI( uri );
+    this->parseURI( uri, false );
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -72,12 +83,10 @@
           const std::string& path, const std::string& query,
           const std::string& fragment ) throw ( URISyntaxException ) {
 
-    this->uriString = NULL;
-
     if( scheme == "" && userInfo == "" && host == "" &&
         path == "" && query == "" && fragment == "" ) {
 
-        this->uri.path = "";
+        this->uri.setPath( "" );
         return;
     }
 
@@ -141,7 +150,7 @@
         uri.append( quoteComponent( fragment, allLegal ) );
     }
 
-    this->parseURI( uri );
+    this->parseURI( uri, true );
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -149,8 +158,6 @@
           const std::string& path, const std::string& fragment )
             throw ( URISyntaxException ) {
 
-    this->uriString = NULL;
-
     URI::URI( scheme, "", host, -1, path, "", fragment );
 }
 
@@ -159,8 +166,6 @@
           const std::string& path, const std::string& query,
           const std::string& fragment ) throw ( URISyntaxException ) {
 
-    this->uriString = NULL;
-
     if( scheme != "" && path.length() > 0 && path.at(0) != '/' ) {
          throw URISyntaxException(
             __FILE__, __LINE__, path,
@@ -193,57 +198,228 @@
          uri.append( quoteComponent( fragment, allLegal ) );
      }
 
-     this->parseURI( uri );
+     this->parseURI( uri, false );
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-void URI::parseURI( const std::string& uri ) throw ( URISyntaxException ) {
-
-    // Use APR to perform the main parse.
-    apr_status_t result = apr_uri_parse( pool.getAprPool(),
-        uri.c_str(), &this->uri );
+void URI::parseURI( const std::string& uri, bool forceServer ) throw ( URISyntaxException ) {
 
-    if( result != APR_SUCCESS ) {
-        throw URISyntaxException(
-            __FILE__, __LINE__, uri,
-            "URI::praseURI - URI String %s invalid." );
+    try{
+        this->uri = URIHelper().parseURI( uri, forceServer );
     }
-
-    std::cout << "\n";
-    std::cout << "Original URI String: " << uri << std::endl;
-    std::cout << "\n";
-    std::cout << "Scheme: "
-              << ( this->uri.scheme ? this->uri.scheme : "" ) << std::endl;
-    std::cout << "Host: "
-              << ( this->uri.hostinfo ? this->uri.hostinfo : "" ) << std::endl;
-    std::cout << "User: "
-              << ( this->uri.user ? this->uri.user : "" ) << std::endl;
-    std::cout << "Passwrod: "
-              << ( this->uri.password ? this->uri.password : "" ) << std::endl;
-    std::cout << "Host Name: "
-              << ( this->uri.hostname ? this->uri.hostname : "" ) << std::endl;
-    std::cout << "Port Str: "
-              << ( this->uri.port_str ? this->uri.port_str : "" ) << std::endl;
-    std::cout << "Path: "
-              << ( this->uri.path ? this->uri.path : "" ) << std::endl;
-    std::cout << "Query: "
-              << ( this->uri.query ? this->uri.query : "" ) << std::endl;
-    std::cout << "Fragment: "
-              << ( this->uri.fragment ? this->uri.fragment : "" ) << std::endl;
-    std::cout << "Port: " << this->uri.port << std::endl;
-    std::cout << "Is Initialized: " << this->uri.is_initialized << std::endl;
-    std::cout << "DNS Looked Up: " << this->uri.dns_looked_up << std::endl;
-    std::cout << "DNS Resolved: " << this->uri.dns_resolved << std::endl;
+    DECAF_CATCH_RETHROW( URISyntaxException )
+    DECAF_CATCHALL_THROW( URISyntaxException )
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-int URI::compareTo( DECAF_UNUSED const URI& value ) const {
+int URI::compareTo( const URI& uri ) const {
+
+    int ret = 0;
+
+    // compare schemes
+    if( this->uri.getScheme() == "" && uri.getScheme() != "" ) {
+        return -1;
+    } else if( this->uri.getScheme() != "" && uri.getScheme() == "" ) {
+        return 1;
+    } else if( this->uri.getScheme() != "" && uri.getScheme() != "" ) {
+        ret = apr_strnatcasecmp( this->uri.getScheme().c_str(), uri.getScheme().c_str() );
+        if( ret != 0 ) {
+            return ret;
+        }
+    }
+
+    // compare opacities
+    if( !this->uri.isOpaque() && uri.isOpaque() ) {
+        return -1;
+    } else if( this->uri.isOpaque() && !uri.isOpaque() ) {
+        return 1;
+    } else if( this->uri.isOpaque() && uri.isOpaque() ) {
+        ret = apr_strnatcmp( this->getSchemeSpecificPart().c_str(),
+                             uri.getSchemeSpecificPart().c_str() );
+        if( ret != 0 ) {
+            return ret;
+        }
+    } else {
+
+        // otherwise both must be hierarchical
+
+        // compare authorities
+        if( this->uri.getAuthority() != "" && uri.getAuthority() == "" ) {
+            return 1;
+        } else if( this->uri.getAuthority() == "" && uri.getAuthority() != "" ) {
+            return -1;
+        } else if( this->uri.getAuthority() != "" && uri.getAuthority() != "" ) {
+
+            if( this->uri.getHost() != "" && uri.getHost() != "" ) {
+
+                // both are server based, so compare userinfo, host, port
+                if( this->getUserInfo() != "" && uri.getUserInfo() == "" ) {
+                    return 1;
+                } else if( this->getUserInfo() == "" && uri.getUserInfo() != "" ) {
+                    return -1;
+                } else if( this->getUserInfo() != "" && uri.getUserInfo() != "" ) {
+                    ret = apr_strnatcmp( this->getUserInfo().c_str(),
+                                         uri.getUserInfo().c_str() );
+                    if( ret != 0 ) {
+                        return ret;
+                    }
+                }
+
+                // userinfo's are the same, compare hostname
+                ret = apr_strnatcmp( this->uri.getHost().c_str(), uri.getHost().c_str() );
+                if( ret != 0 ) {
+                    return ret;
+                }
+
+                // compare port
+                if( this->getPort() != uri.getPort() ) {
+                    return getPort() - uri.getPort();
+                }
+
+            } else {
+
+                // one or both are registry based, compare the whole authority
+                ret = apr_strnatcmp( this->uri.getAuthority().c_str(),
+                                     uri.getAuthority().c_str() );
+                if( ret != 0 ) {
+                    return ret;
+                }
+            }
+        }
+
+        // authorities are the same
+        // compare paths
+        ret = apr_strnatcmp( this->getPath().c_str(), uri.getPath().c_str() );
+        if( ret != 0 ) {
+            return ret;
+        }
+
+        // compare queries
+        if( this->getQuery() != "" && uri.getQuery() == "" ) {
+            return 1;
+        } else if( this->getQuery() == "" && uri.getQuery() != "" ) {
+            return -1;
+        } else if( this->getQuery() != "" && uri.getQuery() != "" ) {
+            ret = apr_strnatcmp( this->getQuery().c_str(), uri.getQuery().c_str() );
+            if( ret != 0 ) {
+                return ret;
+            }
+        }
+    }
+
+    // everything else is identical, so compare fragments
+    if( this->getFragment() != "" && uri.getFragment() == "" ) {
+        return 1;
+    } else if( this->getFragment() == "" && uri.getFragment() != "" ) {
+        return -1;
+    } else if( this->getFragment() != "" && uri.getFragment() != "" ) {
+        ret = apr_strnatcmp( this->getFragment().c_str(), uri.getFragment().c_str() );
+        if( ret != 0 ) {
+            return ret;
+        }
+    }
+
+    // identical
     return 0;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-bool URI::equals( const URI& value ) const {
-    return compareTo( value ) == 0 ? true : false;
+bool URI::equals( const URI& uri ) const {
+
+    if( ( uri.getFragment() == "" && this->getFragment() != "" ) ||
+        ( uri.getFragment() != "" && this->getFragment() == "" ) ) {
+
+        return false;
+
+    } else if( uri.getFragment() != "" && this->getFragment() != "" ) {
+
+        if( !equalsHexCaseInsensitive( uri.getFragment(), this->getFragment() ) ) {
+            return false;
+        }
+    }
+
+    if( ( uri.getScheme() == "" && this->getScheme() != "" ) ||
+        ( uri.getScheme() != "" && this->getScheme() == "" ) ) {
+
+        return false;
+
+    } else if( uri.getScheme() != "" && this->getScheme() != "" ) {
+
+        if( apr_strnatcasecmp( uri.getScheme().c_str(), this->getScheme().c_str() ) != 0 ) {
+            return false;
+        }
+    }
+
+    if( uri.isOpaque() && this->isOpaque() ) {
+
+        return equalsHexCaseInsensitive(
+            uri.getSchemeSpecificPart(), this->getSchemeSpecificPart() );
+
+    } else if( !uri.isOpaque() && !this->isOpaque() ) {
+
+        if( !equalsHexCaseInsensitive( this->getPath(), uri.getPath() ) ) {
+            return false;
+        }
+
+        if( ( uri.getQuery() != "" && this->getQuery() == "" ) ||
+            ( uri.getQuery() == "" && this->getQuery() != "" ) ) {
+
+            return false;
+
+        } else if( uri.getQuery() != "" && this->getQuery() != "" ) {
+
+            if( !equalsHexCaseInsensitive( uri.getQuery(), this->getQuery() ) ) {
+                return false;
+            }
+        }
+
+        if( ( uri.getAuthority() != "" && this->getAuthority() == "" ) ||
+            ( uri.getAuthority() == "" && this->getAuthority() != "" ) ) {
+
+            return false;
+
+        } else if( uri.getAuthority() != "" && this->getAuthority() != "" ) {
+
+            if( ( uri.getHost() != "" && this->getHost() == "" ) ||
+                ( uri.getHost() == "" && this->getHost() != "" ) ) {
+
+                return false;
+
+            } else if( uri.getHost() == "" && this->getHost() == "" ) {
+
+                // both are registry based, so compare the whole authority
+                return equalsHexCaseInsensitive( uri.getAuthority(), this->getAuthority() );
+
+            } else { // uri.host != "" && host != "", so server-based
+
+                if( apr_strnatcasecmp( uri.getHost().c_str(), this->getHost().c_str() ) != 0 ) {
+                    return false;
+                }
+
+                if( this->getPort() != uri.getPort() ) {
+                    return false;
+                }
+
+                if( ( uri.getUserInfo() != "" && this->getUserInfo() == "" ) ||
+                    ( uri.getUserInfo() == "" && this->getUserInfo() != "" ) ) {
+
+                    return false;
+
+                } else if( uri.getUserInfo() != "" && this->getUserInfo() != "" ) {
+                    return equalsHexCaseInsensitive( this->getUserInfo(), uri.getUserInfo() );
+                } else {
+                    return true;
+                }
+            }
+        } else {
+            // no authority
+            return true;
+        }
+
+    } else {
+        // one is opaque, the other hierarchical
+        return false;
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -268,19 +444,528 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-std::string URI::quoteComponent( DECAF_UNUSED const std::string& component,
-        DECAF_UNUSED const std::string& legalset ) {
-//    try {
+std::string URI::quoteComponent( const std::string& component,
+                                 const std::string& legalset ) {
+
+    try {
+
         /*
          * Use a different encoder than URLEncoder since: 1. chars like "/",
          * "#", "@" etc needs to be preserved instead of being encoded, 2.
          * UTF-8 char set needs to be used for encoding instead of default
          * platform one
          */
-//        return URIEncoderDecoder.quoteIllegal(component, legalset);
-//    } catch( UnsupportedEncodingException e ) {
-//        throw RuntimeException( e );
-//    }
-    
-    return "";
+        return URIEncoderDecoder::quoteIllegal(component, legalset);
+    }
+    DECAF_CATCH_RETHROW( decaf::lang::Exception )
+    DECAF_CATCHALL_THROW( decaf::lang::Exception )
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::encodeOthers( const std::string& src ) const {
+
+    try {
+        /*
+         * Use a different encoder than URLEncoder since: 1. chars like "/",
+         * "#", "@" etc needs to be preserved instead of being encoded, 2.
+         * UTF-8 char set needs to be used for encoding instead of default
+         * platform one 3. Only other chars need to be converted
+         */
+        return URIEncoderDecoder::encodeOthers( src );
+    }
+    DECAF_CATCH_RETHROW( decaf::lang::Exception )
+    DECAF_CATCHALL_THROW( decaf::lang::Exception )
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::decode( const std::string& src ) const {
+
+    if( src == "" ) {
+        return src;
+    }
+
+    try {
+        return URIEncoderDecoder::decode( src );
+    }
+    DECAF_CATCH_RETHROW( decaf::lang::Exception )
+    DECAF_CATCHALL_THROW( decaf::lang::Exception )
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool URI::equalsHexCaseInsensitive( const std::string& first, const std::string& second ) const {
+
+    if( first.find( '%' ) != second.find( '%' ) ) {
+        return apr_strnatcmp( first.c_str(), second.c_str() ) == 0;
+    }
+
+    unsigned int index = 0;
+    unsigned int previndex = 0;
+
+    while( ( index = first.find( '%', previndex ) ) != string::npos &&
+           second.find( '%', previndex ) == index ) {
+
+        bool match = first.substr( previndex, index - previndex ) ==
+                     second.substr( previndex, index - previndex );
+
+        if( !match ) {
+            return false;
+        }
+
+        match = apr_strnatcasecmp( first.substr( index + 1, 3 ).c_str(),
+                                   second.substr( index + 1, 3 ).c_str() ) == 0;
+
+        if( !match ) {
+            return false;
+        }
+
+        index += 3;
+        previndex = index;
+    }
+
+    return first.substr( previndex ) == second.substr( previndex );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::convertHexToLowerCase( const std::string& s ) const {
+
+    string result = "";
+
+    if( s.find('%') == string::npos ) {
+        return s;
+    }
+
+    unsigned int index = 0;
+    unsigned int previndex = 0;
+
+    while( ( index = s.find( '%', previndex ) ) != string::npos ) {
+        result.append( s.substr( previndex, ( index - previndex ) + 1 ) );
+
+        string temp = s.substr( index + 1, 3 );
+
+        for( size_t i = 0; i < temp.length(); ++i ) {
+            result.append( 1, (char)apr_tolower( temp.at(i) ) );
+        }
+
+        index += 3;
+        previndex = index;
+    }
+
+    return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::normalize( const std::string& path ) const {
+
+    // count the number of '/'s, to determine number of segments
+    unsigned int index = -1;
+    unsigned int pathlen = path.length();
+    unsigned int size = 0;
+
+    if( pathlen > 0 && path.at(0) != '/' ) {
+        size++;
+    }
+
+    while( ( index = path.find( '/', index + 1 ) ) != string::npos ) {
+        if( index + 1 < pathlen && path.at( index + 1 ) != '/' ) {
+            size++;
+        }
+    }
+
+    std::vector<string> seglist;
+    std::vector<bool> include;
+
+    // break the path into segments and store in the list
+    unsigned int current = 0;
+    unsigned int index2 = 0;
+
+    index = ( pathlen > 0 && path.at(0) == '/' ) ? 1 : 0;
+    while( ( index2 = path.find( '/', index + 1 ) ) != string::npos ) {
+        seglist[current++] = path.substr( index, index2 - index );
+        index = index2 + 1;
+    }
+
+    // if current==size, then the last character was a slash
+    // and there are no more segments
+    if( current < size ) {
+        seglist[current] = path.substr( index );
+    }
+
+    // determine which segments get included in the normalized path
+    for( unsigned int i = 0; i < size; i++ ) {
+
+        include[i] = true;
+
+        if( seglist[i] == ".." ) {
+
+            int remove = i - 1;
+
+            // search back to find a segment to remove, if possible
+            while( remove > -1 && !include[remove] ) {
+                remove--;
+            }
+
+            // if we find a segment to remove, remove it and the ".."
+            // segment
+            if( remove > -1 && !( seglist[remove] == "..")  ) {
+                include[remove] = false;
+                include[i] = false;
+            }
+
+        } else if( seglist[i] == "." ) {
+            include[i] = false;
+        }
+    }
+
+    // put the path back together
+    string newpath;
+    if( path.at(0) == '/' ) {
+        newpath.append( "/" );
+    }
+
+    for( unsigned int i = 0; i < seglist.size(); i++ ) {
+        if( include[i] ) {
+            newpath.append( seglist[i] );
+            newpath.append( "/" );
+        }
+    }
+
+    // if we used at least one segment and the path previously ended with
+    // a slash and the last segment is still used, then delete the extra
+    // trailing '/'
+    if( !path.at( path.length() ) == '/' && seglist.size() > 0 &&
+        include[seglist.size() - 1] ) {
+
+        newpath.erase( newpath.length() - 1, 1 );
+    }
+
+    string result = newpath;
+
+    // check for a ':' in the first segment if one exists,
+    // prepend "./" to normalize
+    index = result.find(':');
+    index2 = result.find('/');
+
+    if( index != string::npos && ( index < index2 || index2 == string::npos ) ) {
+        newpath.insert( 0, "./" );
+        result = newpath;
+    }
+
+    return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URI::normalize() const {
+
+    if( isOpaque() ) {
+        return *this;
+    }
+
+    string normalizedPath = normalize( this->uri.getPath() );
+
+    // if the path is already normalized, return this
+    if( this->uri.getPath() == normalizedPath ) {
+        return *this;
+    }
+
+    // get an exact copy of the URI re-calculate the scheme specific part
+    // since the path of the normalized URI is different from this URI.
+    URI result = *this;
+    result.uri.setPath( normalizedPath );
+    result.setSchemeSpecificPart();
+
+    return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URI::setSchemeSpecificPart() {
+
+    // ssp = [//authority][path][?query]
+    string ssp;
+
+    if( this->uri.getAuthority() != "" ) {
+        ssp.append( string("//") + this->uri.getAuthority() );
+    }
+
+    if( this->uri.getPath() != "" ) {
+        ssp.append( this->uri.getPath() );
+    }
+
+    if( this->uri.getQuery() != "" ) {
+        ssp.append( "?" + this->uri.getQuery() );
+    }
+
+    this->uri.setSchemeSpecificPart( ssp );
+
+    // reset string, so that it can be re-calculated correctly when asked.
+    this->uriString = "";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URI::parseServerAuthority() const throw( URISyntaxException ) {
+
+    URI newURI = *this;
+
+    if( newURI.uri.isServerAuthority() ) {
+        newURI.uri = URIHelper().parseAuthority( true, this->uri.getAuthority() );
+    }
+
+    return newURI;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URI::relativize( const URI& relative ) const {
+
+    if( relative.isOpaque() || this->isOpaque() ) {
+        return relative;
+    }
+
+    if( this->uri.getScheme() == "" ? relative.uri.getScheme() != "" :
+        this->uri.getScheme() != relative.uri.getScheme() ) {
+
+        return relative;
+    }
+
+    if( this->uri.getAuthority() == "" ? relative.uri.getAuthority() != "" :
+        this->uri.getAuthority() != relative.uri.getAuthority() ) {
+
+        return relative;
+    }
+
+    // normalize both paths
+    string thisPath = normalize( this->uri.getPath() );
+    string relativePath = normalize( relative.uri.getPath() );
+
+    /*
+     * if the paths aren't equal, then we need to determine if this URI's
+     * path is a parent path (begins with) the relative URI's path
+     */
+    if( thisPath != relativePath ) {
+
+        // if this URI's path doesn't end in a '/', add one
+        if( thisPath.at( thisPath.length() ) != '/' ) {
+            thisPath = thisPath + '/';
+        }
+
+        /*
+         * if the relative URI's path doesn't start with this URI's path,
+         * then just return the relative URI; the URIs have nothing in
+         * common
+         */
+        if( relativePath.find( thisPath ) != 0 ) {
+            return relative;
+        }
+    }
+
+    URI result;
+    result.uri.setFragment( relative.uri.getFragment() );
+    result.uri.setQuery( relative.uri.getQuery() );
+    // the result URI is the remainder of the relative URI's path
+    result.uri.setPath( relativePath.substr( thisPath.length() ) );
+
+    return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URI::resolve( const URI& relative ) const {
+
+    if( relative.isAbsolute() || this->isOpaque() ) {
+        return relative;
+    }
+
+    URI result;
+    if( relative.uri.getPath() == "" && relative.uri.getScheme() == "" &&
+        relative.uri.getAuthority() == "" && relative.uri.getQuery() == "" &&
+        relative.uri.getFragment() != "" ) {
+
+        // if the relative URI only consists of fragment,
+        // the resolved URI is very similar to this URI,
+        // except that it has the fragment from the relative URI.
+        result = *this;
+        result.uri.setFragment( relative.uri.getFragment() );
+        // no need to re-calculate the scheme specific part,
+        // since fragment is not part of scheme specific part.
+        return result;
+    }
+
+    if( relative.uri.getAuthority() != "" ) {
+
+        // if the relative URI has authority,
+        // the resolved URI is almost the same as the relative URI,
+        // except that it has the scheme of this URI.
+        result = *this;
+        result.uri.setScheme( this->uri.getScheme() );
+        result.uri.setAbsolute( this->uri.isAbsolute() );
+
+    } else {
+
+        // since relative URI has no authority,
+        // the resolved URI is very similar to this URI,
+        // except that it has the query and fragment of the relative URI,
+        // and the path is different.
+        result = *this;
+        result.uri.setFragment( relative.uri.getFragment() );
+        result.uri.setQuery( relative.uri.getQuery() );
+
+        if( relative.uri.getPath().at(0) == '/' ) {
+            result.uri.setPath( relative.uri.getPath() );
+        } else {
+            // resolve a relative reference
+            int endindex = this->uri.getPath().find_last_of('/') + 1;
+            result.uri.setPath( normalize(
+                this->uri.getPath().substr( 0, endindex ) + relative.uri.getPath() ) );
+        }
+
+        // re-calculate the scheme specific part since
+        // query and path of the resolved URI is different from this URI.
+        result.setSchemeSpecificPart();
+    }
+
+    return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URI::resolve( const std::string& relative ) const
+    throw ( lang::exceptions::IllegalArgumentException ) {
+
+    return resolve( create( relative ) );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+string URI::toString() const {
+
+    if( this->uriString == "" ) {
+
+        string result = "";
+
+        if( this->uri.getScheme() != "" ) {
+            result.append( this->uri.getScheme() );
+            result.append( ":" );
+        }
+
+        if( this->isOpaque() ) {
+            result.append( this->uri.getSchemeSpecificPart() );
+        } else {
+
+            if( this->uri.getAuthority() != "" ) {
+                result.append( "//" );
+                result.append( this->uri.getAuthority() );
+            }
+
+            if( this->uri.getPath() != "" ) {
+                result.append( this->uri.getPath() );
+            }
+
+            if( this->uri.getQuery() != "" ) {
+                result.append( "?" );
+                result.append( this->uri.getQuery() );
+            }
+        }
+
+        if( this->uri.getFragment() != "" ) {
+            result.append( "#" );
+            result.append( this->uri.getFragment() );
+        }
+
+        this->uriString = result;
+    }
+
+    return this->uriString;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URL URI::toURL() const
+    throw ( MalformedURLException, lang::exceptions::IllegalArgumentException ) {
+
+    if( !this->isAbsolute() ) {
+        throw IllegalArgumentException(
+            __FILE__, __LINE__,
+            "URI is not absolute, cannot convert to an URL." );
+    }
+
+    return URL( this->toString() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getAuthority() const {
+    return this->decode( this->uri.getAuthority() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getFragment() const {
+    return this->decode( this->uri.getFragment() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getHost() const {
+    return this->uri.getHost();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getPath() const {
+    return this->decode( this->uri.getPath() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int URI::getPort() const {
+    return this->uri.getPort();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getQuery() const {
+    return this->decode( this->uri.getQuery() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawAuthority() const {
+    return this->uri.getAuthority();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawFragment() const {
+    return this->uri.getFragment();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawPath() const {
+    return this->uri.getPath();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawQuery() const {
+    return this->uri.getQuery();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawSchemeSpecificPart() const {
+    return this->uri.getSchemeSpecificPart();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawUserInfo() const {
+    return this->uri.getUserInfo();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getScheme() const {
+    return this->uri.getScheme();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getSchemeSpecificPart() const {
+    return this->decode( this->uri.getSchemeSpecificPart() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getUserInfo() const {
+    return this->decode( this->uri.getUserInfo() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool URI::isAbsolute() const {
+    return this->uri.isAbsolute();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool URI::isOpaque() const {
+    return this->uri.isOpaque();
 }

Modified: activemq/activemq-cpp/trunk/src/main/decaf/net/URI.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/trunk/src/main/decaf/net/URI.h?rev=727119&r1=727118&r2=727119&view=diff
==============================================================================
--- activemq/activemq-cpp/trunk/src/main/decaf/net/URI.h (original)
+++ activemq/activemq-cpp/trunk/src/main/decaf/net/URI.h Tue Dec 16 10:56:43 2008
@@ -24,9 +24,8 @@
 #include <decaf/net/URISyntaxException.h>
 #include <decaf/net/MalformedURLException.h>
 #include <decaf/net/URL.h>
+#include <decaf/internal/net/URIType.h>
 #include <string>
-#include <apr_uri.h>
-#include <decaf/internal/AprPool.h>
 
 namespace decaf{
 namespace net{
@@ -37,12 +36,11 @@
     class DECAF_API URI : public lang::Comparable<URI> {
     private:
 
-        // Apr Data for parsing the uri.
-        apr_uri_t uri;
-        internal::AprPool pool;
+        // The structure that holds the parsed URI data.
+        decaf::internal::net::URIType uri;
 
         // The original string entered from URI( string ), empty if not set.
-        const char* uriString;
+        mutable std::string uriString;
 
         static const std::string unreserved;
         static const std::string punct;
@@ -66,7 +64,7 @@
          */
         URI( const std::string& scheme,
              const std::string& ssp,
-             const std::string& fragment) throw ( URISyntaxException );
+             const std::string& fragment ) throw ( URISyntaxException );
 
         /**
          * Constructs a URI from the given components.
@@ -329,7 +327,7 @@
          * @returns The resulting URI
          * @throws IllegalArgumentException - If the given string violates RFC 2396
          */
-        URI resolve( const std::string& str )
+        URI resolve( const std::string& str ) const
             throw ( lang::exceptions::IllegalArgumentException );
 
         /**
@@ -368,7 +366,7 @@
          * @param uri - The URI to be resolved against this URI
          * @returns The resulting URI
          */
-        URI resolve( const URI& uri );
+        URI resolve( const URI& uri ) const;
 
         /**
          * Returns the content of this URI as a string.
@@ -410,6 +408,13 @@
         static URI create( const std::string uri )
             throw ( lang::exceptions::IllegalArgumentException );
 
+    protected:
+
+        /**
+         * Default Constructor
+         */
+        URI();
+
     private:
 
         /**
@@ -417,9 +422,10 @@
          * URISyntaxException if things fail.
          *
          * @param uri - the URI to parse
+         * @param forceServer - should a server authority be enforced.
          * @throws URISyntaxException if an error occurs.
          */
-        void parseURI( const std::string& uri ) throw ( URISyntaxException );
+        void parseURI( const std::string& uri, bool forceServer ) throw ( URISyntaxException );
 
         /*
          * Quote illegal chars for each component, but not the others
@@ -431,6 +437,56 @@
         std::string quoteComponent( const std::string& component,
                                     const std::string& legalset );
 
+        /*
+         * Encode unicode chars that are not part of US-ASCII char set into the
+         * escaped form
+         *
+         * i.e. The Euro currency symbol is encoded as "%E2%82%AC".
+         *
+         * @param component java.lang.String the component to be converted @param
+         * legalset java.lang.String the legal character set allowed in the
+         * component s @return java.lang.String the converted string
+         */
+        std::string encodeOthers( const std::string& src ) const;
+
+        /**
+         * Decode an encoded URI String.
+         *
+         * @param src - the encoded string
+         * @return the unencoded string version of src.
+         */
+        std::string decode( const std::string& src ) const;
+
+        /**
+         * Compare the Two Hexadecimal encoded strings and return if they are equal.
+         *
+         * @param first - First String to compare.
+         * @param second - The second string to compare.
+         */
+        bool equalsHexCaseInsensitive( const std::string& first,
+                                       const std::string& second ) const;
+
+        /*
+         * Takes a string that may contain hex sequences like %F1 or %2b and
+         * converts the hex values following the '%' to lowercase.
+         *
+         * @param s - String to convert the hex in.
+         */
+        std::string convertHexToLowerCase( const std::string& s ) const;
+
+        /*
+         * Normalize path, and return the resulting string.
+         *
+         * @param path - the path value to normalize.
+         */
+        std::string normalize( const std::string& path ) const;
+
+        /**
+         * Helper method used to re-calculate the scheme specific part of the
+         * resolved or normalized URIs
+         */
+        void setSchemeSpecificPart();
+
     };
 
 }}