hxurl.cpp

来自「symbian 下的helix player源代码」· C++ 代码 · 共 1,517 行 · 第 1/3 页

CPP
1,517
字号
/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: hxurl.cpp,v 1.25.2.4 2004/07/09 01:48:15 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#include "hlxclib/string.h"
#include "hlxclib/stdlib.h"
//#include "hlxclib/stdio.h"
#include <ctype.h>

#include "hxcom.h"
#include "hxtypes.h"
#include "hxresult.h"
#include "hxcomm.h"
#include "tparse.h"
#include "dbcs.h"
#include "protdefs.h"
#include "hxstrutl.h"
#include "hxslist.h"
#include "hxurl.h"
#include "ihxpckts.h"
#include "chxminiccf.h"

#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE		
static const char HX_THIS_FILE[] = __FILE__;
#endif

/* We should really define it in a common header file */
#if defined (_WINDOWS ) || defined (WIN32) || defined(_SYMBIAN)
#define OS_SEPARATOR_CHAR	'\\'
#define OS_SEPARATOR_STRING	"\\"
#elif defined (_UNIX) || defined(_OPENWAVE)
#define OS_SEPARATOR_CHAR	'/'
#define OS_SEPARATOR_STRING	"/"
#elif defined (_MACINTOSH)
#define OS_SEPARATOR_CHAR	':'
#define OS_SEPARATOR_STRING	":"
#else
#error "undefined platform hxurl.cpp"
#endif // defined (_WINDOWS ) || defined (WIN32)

CHXURL::CHXURL (const char* pszURL)
		:m_LastError (HXR_OK)
		,m_pActualURL(NULL)
                ,m_pszURL(NULL)
                ,m_pszEscapedURL(NULL)
		,m_pszOptions (NULL)
		,m_pszHost (NULL)
		,m_pszPort (NULL)
		,m_pszUsername(NULL)
		,m_pszPassword(NULL)
		,m_unProtocol(fileProtocol)
                ,m_unDefaultPort(0)
		,m_bNetworkProtocol (FALSE)
		,m_pszResource (NULL)
		,m_pProperties (NULL)
		,m_pOptions (NULL)
                ,m_pCCF(CreateCCF())
{
    if (m_pCCF)
    {
	m_pCCF->AddRef();
    }
    
    ConstructURL(pszURL);
}

CHXURL::CHXURL (const char* pszURL, IUnknown* pContext)
		:m_LastError (HXR_OK)
		,m_pActualURL(NULL)
                ,m_pszURL(NULL)
                ,m_pszEscapedURL(NULL)
		,m_pszOptions (NULL)
		,m_pszHost (NULL)
		,m_pszPort (NULL)
		,m_pszUsername(NULL)
		,m_pszPassword(NULL)
		,m_unProtocol(fileProtocol)
                ,m_unDefaultPort(0)
		,m_bNetworkProtocol (FALSE)
		,m_pszResource (NULL)
		,m_pProperties (NULL)
		,m_pOptions (NULL)
                ,m_pCCF(0)
{
    if (pContext)
    {
	pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&m_pCCF);
    }
    
    ConstructURL(pszURL);
}

void CHXURL::ConstructURL(const char* pszURL)
{
    char*   pszInputURL = NULL;
    char*   pszTemp = NULL;
    char*   pFragment = NULL;
    char*   pNewURL = NULL;
    char*   pResource = NULL;
    char*   pszDollarSign = NULL;

    HX_ASSERT(pszURL != NULL);

    if (!pszURL)
    {
	m_LastError = HXR_INVALID_PATH;
	return;
    }
    
    if (!m_pCCF)
    {
	m_LastError = HXR_UNEXPECTED;
	return;
    }

    pszInputURL = new char[strlen(pszURL) + 1];
    if(!pszInputURL)
    {
        m_LastError = HXR_OUTOFMEMORY;
        return;
    }
    strcpy(pszInputURL, pszURL); /* Flawfinder: ignore */

    // Keep permanent copy of input url
    m_pszEscapedURL = new char[strlen(pszInputURL)+1];
    strcpy(m_pszEscapedURL, pszInputURL); /* Flawfinder: ignore */

    // IHXValues 
    if (m_pCCF)
    {
	m_pCCF->CreateInstance(CLSID_IHXValues, (void**)&m_pProperties);
	m_pCCF->CreateInstance(CLSID_IHXValues, (void**)&m_pOptions);
    }

    // protocol: determine whether it's network or local
    if (0 == StringNCompare(pszInputURL, "http:", 5))
    {
	m_unProtocol = httpProtocol;
	m_unDefaultPort = DEFAULT_HTTP_PORT;
    }
    else if (0 == StringNCompare(pszInputURL, "chttp:", 6))
    {
	m_unProtocol = httpProtocol;
	m_unDefaultPort = DEFAULT_HTTP_PORT;
    }
    else if (0 == StringNCompare(pszInputURL, "pnm:", 4))
    {
	m_unProtocol = pnmProtocol;
	m_bNetworkProtocol = TRUE;
	m_unDefaultPort = DEFAULT_PNA_PORT;
    }
    else if (0 == StringNCompare(pszInputURL, "rtsp:", 5))
    {
	m_unProtocol = rtspProtocol;
	m_bNetworkProtocol = TRUE;
	m_unDefaultPort = DEFAULT_RTSP_PORT;
    }
    else if (0 == StringNCompare(pszInputURL, "helix-sdp:", 10))
    {
	m_unProtocol = helixSDPProtocol;
	m_bNetworkProtocol = TRUE;
	m_unDefaultPort = DEFAULT_RTSP_PORT;
    }
    else if (0 == StringNCompare(pszInputURL, "https:", 6))
    {
	m_unProtocol = httpsProtocol;
	m_unDefaultPort = DEFAULT_HTTPS_PORT;
    }

    if (m_pProperties)
    {
	m_pProperties->SetPropertyULONG32(PROPERTY_PROTOCOL, (ULONG32)m_unProtocol);
    }
    else
    {
	m_LastError = HXR_UNEXPECTED;
	goto cleanup;
    }

    // no need to further parse helix-sdp protocol
    if (helixSDPProtocol != m_unProtocol)
    {
        // separate fragment from the URL
        if (0!=(pszTemp = (char*) ::HXFindChar(pszInputURL, '#')))
        {
	    // save fragment
	    pFragment = pszTemp + 1;
	    ::SaveStringToHeader(m_pProperties, PROPERTY_FRAGMENT, pFragment);
	    *pszTemp = '\0';
        }

        // HP - allow '$' in directory/file name
        //
        // still need to take care of that obsolete $ sign option:
        // rtsp://moe.cr.prognet.com/ambush.rm$1:00
        // time after the $ is assumed to be the start time.
        //
        // the solution is to compare the string following the $ to 
        // a properly formed time. If the string is a time and only 
        // a time, then we know its the old-style start-time option
        // otherwise, '$' is part of the directory/file name and we
        // will keep it.
        pszDollarSign = (char*) ::HXFindChar(pszInputURL, '$');
        while (pszDollarSign)
        {
	    pszTemp = pszDollarSign + 1;

	    if (::TimeParse(pszTemp))
	    {
	        *pszDollarSign = '\0';
	        INT32 lLen = (2 * strlen(pszURL)) + 8;
	        pNewURL = new char[lLen];
	        memset(pNewURL, 0, lLen);
		          
	        // upgrade to a new URL
	        SafeSprintf(pNewURL, lLen, "%s?start=%s", pszInputURL, pszTemp);

	        HX_VECTOR_DELETE(pszInputURL);
	        pszInputURL = pNewURL;
	        break;
	    }

	    pszDollarSign = (char*) ::HXFindChar(pszTemp, '$');
        }
    }

#if !defined(_MACINTOSH) && !defined(_MAC_UNIX)
    // on Mac, unescaping can put /'s and ?'s back into file and folder names, which is deadly inside URLs
    //if (0 == StringNCompare(pszInputURL, "file:", 5))
    {
	// we only unescape the URL on local source since we are
	// *responding* instead of *requesting* for the given source
	Unescape(pszInputURL);
    }
#endif

    if (!CompressURL(pszInputURL, m_pszURL))
    {
	// make a copy of the URL
	m_pszURL = new char[strlen(pszInputURL)+1];
	strcpy(m_pszURL, pszInputURL); /* Flawfinder: ignore */
    }

    m_pActualURL = new char[strlen(m_pszURL)+1];
    strcpy(m_pActualURL, m_pszURL); /* Flawfinder: ignore */

    ::SaveStringToHeader(m_pProperties, PROPERTY_URL, m_pszURL);

    // no need to further parse helix-sdp protocol
    if (helixSDPProtocol != m_unProtocol)
    {
        // separate options from the URL
        if (0 != (pszTemp = (char*) ::HXFindChar(m_pszURL, '?')))
        {
	    // options
	    m_pszOptions = pszTemp + 1;
        }
       
        // collect protocol, host, port and resource info
        ParseURL (m_pszURL);
    
        // collect other options info if it has 
        if (m_pszOptions)
        {
	    if (HXR_INCOMPLETE == CollectOptions(m_pszOptions) && m_pszResource)
	    {
    	        // bad options and remove it from the URL
    	        pszTemp = (char*) ::HXFindChar(m_pszResource, '?');
	        if (pszTemp)
	        {
		    *pszTemp = '\0';

		    ParseResource();
	        }
	    }
        }   
    }

cleanup:

    HX_VECTOR_DELETE(pszInputURL);
}

CHXURL::~CHXURL ()
{
    HX_VECTOR_DELETE(m_pActualURL);
    HX_VECTOR_DELETE(m_pszURL);
    HX_VECTOR_DELETE(m_pszEscapedURL);

    HX_RELEASE(m_pProperties);
    HX_RELEASE(m_pOptions);

    HX_RELEASE(m_pCCF);
}

CHXURL::CHXURL(const CHXURL& rhs) 		
    :m_LastError (HXR_OK)
    ,m_pActualURL(NULL)
    ,m_pszURL(NULL)
    ,m_pszOptions (NULL)
    ,m_pszHost (NULL)
    ,m_pszPort (NULL)
    ,m_pszUsername(NULL)
    ,m_pszPassword(NULL)
    ,m_unProtocol (fileProtocol)
    ,m_bNetworkProtocol (FALSE)
    ,m_pszResource (NULL)
    ,m_pProperties (NULL)
    ,m_pOptions (NULL)
    ,m_pCCF(rhs.m_pCCF)
{
    if (m_pCCF)
    {
	m_pCCF->AddRef();
    }

    ConstructURL(rhs.GetEscapedURL());
}

CHXURL& CHXURL::operator=(const CHXURL& rhs)
{
    if (&rhs != this)
    {
	// Clean out old data
	HX_VECTOR_DELETE(m_pActualURL);
	HX_VECTOR_DELETE(m_pszURL);
        HX_VECTOR_DELETE(m_pszEscapedURL);
	HX_RELEASE(m_pProperties);
	HX_RELEASE(m_pOptions);
	HX_RELEASE(m_pCCF);
	m_LastError = HXR_OK;
	m_pszOptions = NULL;
	m_pszHost = NULL;
	m_pszPort = NULL;
	m_pszUsername = NULL;
	m_pszPassword = NULL;
	m_unProtocol = fileProtocol;
	m_bNetworkProtocol = FALSE;
	m_pszResource = NULL;

	ConstructURL(rhs.GetEscapedURL());
	m_pCCF = rhs.m_pCCF;

	if (m_pCCF)
	{
	    m_pCCF->AddRef();
	}
    }

    return *this;
}

HX_RESULT CHXURL::ParseURL (char* pszURL)
{
    char* pszOption = NULL;
    char* pszTemp = NULL;
    char* pszSlash = NULL;
    char* pszCursor = NULL;    

    if (HXR_OK != m_LastError)
    {
	goto cleanup;
    }

    pszCursor = pszURL;
    
    //
    // let's start
    //

    // find the scheme - note that ParseURL only succeeds
    // for absolute URLs
    m_LastError = HXR_INVALID_PROTOCOL;	// assume the worst
    pszTemp = (char *) FindURLSchemeEnd(pszURL);
    if (pszTemp)
    {
	char* pScheme = new_string(pszURL, pszTemp - pszURL);

	m_LastError = HXR_OK;
	::SaveStringToHeader(m_pProperties, PROPERTY_SCHEME, pScheme);

	delete[] pScheme;
    }

    if(HXR_OK != m_LastError)
    {
	goto cleanup;
    }

    pszCursor = pszTemp + 1;
  
    if(strncmp(pszCursor, "//", 2) == 0)
    {
	pszCursor += 2;	// skip '//'
    }
    else if(strncmp(pszCursor, "/", 1) == 0)
    {
	pszCursor += 1;	// skip '/' (ill-formed url?)
    }

    if (fileProtocol == m_unProtocol)
    {
	// resource
	if (*(m_pszResource = pszCursor) == '\0')
	{
	    m_LastError = HXR_INVALID_URL_PATH;
	    goto cleanup;
	}
    }
    // network URL + http
    else	
    {
	// First check for optional username and password parameters.
	// The colon is also optional if either username or password
	// is not given Form in context:
	// protocol://username:password@host:port/resource (From RFC
	// 1738)
	pszTemp = (char*) ::HXFindChar(pszCursor, ':');
	pszSlash = (char*) ::HXFindChar(pszCursor, '/');
	pszOption = (char*) ::HXFindChar(pszCursor, '@');

	// There is a username or password if we see a '@' character
	// according to RFC 1738 this is a reserved character
	if (pszOption && pszOption < pszSlash)
	{
	    // Username
	    if (*(m_pszUsername = pszCursor) == '\0')
	    {
		m_LastError = HXR_INVALID_URL_HOST;
		goto cleanup;
	    }

	    // If the is a ':' and it is before the '@' then we have a
	    // password, so zero terminate the username and move the
	    // cursor to the password
	    if (pszTemp && (pszTemp < pszOption))
	    {
		*pszTemp = '\0';
		pszCursor = pszTemp+1;
	    }
	    // There is no ':' so move the cursor to the '@' character
	    // so it will be a zero terminated empty string
	    else
		pszCursor = pszOption;

	    // Password
	    if (*(m_pszPassword = pszCursor) == '\0')
	    {
		m_LastError = HXR_INVALID_URL_HOST;
		goto cleanup;
	    }

	    // Zero terminate password and move the cursor to the hostname
	    *pszOption = '\0';

	    if (m_pszUsername)
	    {
		::SaveStringToHeader(m_pProperties, PROPERTY_USERNAME, m_pszUsername);
	    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?