void XalanParsedURI::resolve()

in src/xalanc/PlatformSupport/XalanParsedURI.cpp [169:301]


void XalanParsedURI::resolve(
    const XalanParsedURI &base
)
{
    if (base.isSchemeDefined() == false)
    {
        // Protect against a base URI that is relative...
        // This might become an assert or an exception.
    }
    // Handle references to the current document (step 2)
    else if ((m_defined & (d_scheme | d_authority | d_query)) == 0 &&
        m_path.empty())
    {
        m_defined = base.m_defined;
        if (base.m_defined & d_scheme)
            m_scheme    = base.m_scheme;
        if (base.m_defined & d_authority)
            m_authority = base.m_authority;

        m_path      = base.m_path;

        if (base.m_defined & d_query)
            m_query     = base.m_query;

        // There is an error/unclarity in the specification in step 2 in that
        // it doesn't state that the fragment should be inherited; however
        // it is clear from the examples that it should be
        if (!(m_defined & d_fragment))
        {
            m_fragment = base.m_fragment;
        }

        m_defined |= base.m_defined;
    }
    // A defined scheme component implies that this is an absolute URI (step 3)
    // Also allow a scheme without authority that matches the base scheme to be 
    // interpreted as a relative URI
    else if (!(m_defined & d_scheme) || ( 
            (base.m_defined & d_scheme) && !(m_defined & d_authority) 
            && equalsIgnoreCaseASCII(m_scheme, base.m_scheme)))
    {
        // Inherit the base scheme
        if (base.m_defined & d_scheme)
        {
            m_scheme = base.m_scheme;
            m_defined |= d_scheme;
        }

        // Step 4: If the authority is unm_defined then inherit it, otherwise skip to step 7
        if (!(m_defined & d_authority))
        {
            // Inherit the base authority
            if (base.m_defined & d_authority)
            {
                m_authority = base.m_authority;
                m_defined |= d_authority;
            }

            // Step 5: if the path starts with a / then it is absolute
            if (!(m_path.length() > 0 && m_path[0] == XalanUnicode::charSolidus))
            {
                // Step 6: merge relative path components

                // a) strip off characters after the right most slash in the base path
                XalanDOMString::size_type pathEnd = base.m_path.length();
                while (pathEnd > 0 && base.m_path[pathEnd - 1] != XalanUnicode::charSolidus)
                {
                    --pathEnd;
                }

                if (pathEnd > 0) 
                {
                    // b) append relative path
                    // This inserts the path portion from base...
                    m_path.insert(0, base.m_path, 0, pathEnd);
                }
                else
                {
                    // TODO, maybe raise an error here as this
                    // is a severely wonky looking URI
                }

                // c)->g remove various "./" and "../" segments
                for (XalanDOMString::size_type index = 0; index < m_path.length(); ) 
                {
                    // remove '<segment>/../' and ./
                    if (m_path[index] == XalanUnicode::charFullStop) 
                    {
                        if (index < m_path.length()-1 && 
                            m_path[index+1] == XalanUnicode::charSolidus) // ./
                        {
                            m_path.erase(index,2);
                            continue;
                        } 
                        else if (index == m_path.length()-1) // trailing /.
                        {
                            m_path.erase(index,1);
                            continue;
                        } 
                        // Note: also strips leading ../ in an attempt to get 
                        // something out of a bad m_path
                        else if (index < m_path.length()-2 && 
                                    m_path[index+1] == XalanUnicode::charFullStop && 
                                    m_path[index+2] == XalanUnicode::charSolidus) // ../
                        { 
                            const XalanDOMString::size_type     end = index + 2;
                            if (index > 0) --index;
                            for ( ; index > 0 && m_path[index-1] != XalanUnicode::charSolidus; index--) 
                                ;
                            if (index > 0) --index;
                            m_path.erase(index, end - index);
                            continue;
                        } 
                        else if (index == m_path.length()-2 && 
                                    m_path[index+1] == XalanUnicode::charFullStop) // trailing /..
                        {
                            const XalanDOMString::size_type     end = index + 2;
                            if (index > 0) --index;
                            for ( ; index > 0 && m_path[index-1] != XalanUnicode::charSolidus; index--) 
                                ;
                            m_path.erase(index, end - index);
                            continue;
                        }
                    }
                    for ( ; index < m_path.length() && m_path[index] != XalanUnicode::charSolidus ; ++index)
                    {
                    }
                    ++index;
                }
            }
        }
    }
}