hxurl.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:36k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: hxurl.cpp,v 1.25.2.4 2004/07/09 01:48:15 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "hlxclib/string.h"
  50. #include "hlxclib/stdlib.h"
  51. //#include "hlxclib/stdio.h"
  52. #include <ctype.h>
  53. #include "hxcom.h"
  54. #include "hxtypes.h"
  55. #include "hxresult.h"
  56. #include "hxcomm.h"
  57. #include "tparse.h"
  58. #include "dbcs.h"
  59. #include "protdefs.h"
  60. #include "hxstrutl.h"
  61. #include "hxslist.h"
  62. #include "hxurl.h"
  63. #include "ihxpckts.h"
  64. #include "chxminiccf.h"
  65. #include "hxheap.h"
  66. #ifdef _DEBUG
  67. #undef HX_THIS_FILE
  68. static const char HX_THIS_FILE[] = __FILE__;
  69. #endif
  70. /* We should really define it in a common header file */
  71. #if defined (_WINDOWS ) || defined (WIN32) || defined(_SYMBIAN)
  72. #define OS_SEPARATOR_CHAR '\'
  73. #define OS_SEPARATOR_STRING "\"
  74. #elif defined (_UNIX) || defined(_OPENWAVE)
  75. #define OS_SEPARATOR_CHAR '/'
  76. #define OS_SEPARATOR_STRING "/"
  77. #elif defined (_MACINTOSH)
  78. #define OS_SEPARATOR_CHAR ':'
  79. #define OS_SEPARATOR_STRING ":"
  80. #else
  81. #error "undefined platform hxurl.cpp"
  82. #endif // defined (_WINDOWS ) || defined (WIN32)
  83. CHXURL::CHXURL (const char* pszURL)
  84. :m_LastError (HXR_OK)
  85. ,m_pActualURL(NULL)
  86.                 ,m_pszURL(NULL)
  87.                 ,m_pszEscapedURL(NULL)
  88. ,m_pszOptions (NULL)
  89. ,m_pszHost (NULL)
  90. ,m_pszPort (NULL)
  91. ,m_pszUsername(NULL)
  92. ,m_pszPassword(NULL)
  93. ,m_unProtocol(fileProtocol)
  94.                 ,m_unDefaultPort(0)
  95. ,m_bNetworkProtocol (FALSE)
  96. ,m_pszResource (NULL)
  97. ,m_pProperties (NULL)
  98. ,m_pOptions (NULL)
  99.                 ,m_pCCF(CreateCCF())
  100. {
  101.     if (m_pCCF)
  102.     {
  103. m_pCCF->AddRef();
  104.     }
  105.     
  106.     ConstructURL(pszURL);
  107. }
  108. CHXURL::CHXURL (const char* pszURL, IUnknown* pContext)
  109. :m_LastError (HXR_OK)
  110. ,m_pActualURL(NULL)
  111.                 ,m_pszURL(NULL)
  112.                 ,m_pszEscapedURL(NULL)
  113. ,m_pszOptions (NULL)
  114. ,m_pszHost (NULL)
  115. ,m_pszPort (NULL)
  116. ,m_pszUsername(NULL)
  117. ,m_pszPassword(NULL)
  118. ,m_unProtocol(fileProtocol)
  119.                 ,m_unDefaultPort(0)
  120. ,m_bNetworkProtocol (FALSE)
  121. ,m_pszResource (NULL)
  122. ,m_pProperties (NULL)
  123. ,m_pOptions (NULL)
  124.                 ,m_pCCF(0)
  125. {
  126.     if (pContext)
  127.     {
  128. pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&m_pCCF);
  129.     }
  130.     
  131.     ConstructURL(pszURL);
  132. }
  133. void CHXURL::ConstructURL(const char* pszURL)
  134. {
  135.     char*   pszInputURL = NULL;
  136.     char*   pszTemp = NULL;
  137.     char*   pFragment = NULL;
  138.     char*   pNewURL = NULL;
  139.     char*   pResource = NULL;
  140.     char*   pszDollarSign = NULL;
  141.     HX_ASSERT(pszURL != NULL);
  142.     if (!pszURL)
  143.     {
  144. m_LastError = HXR_INVALID_PATH;
  145. return;
  146.     }
  147.     
  148.     if (!m_pCCF)
  149.     {
  150. m_LastError = HXR_UNEXPECTED;
  151. return;
  152.     }
  153.     pszInputURL = new char[strlen(pszURL) + 1];
  154.     if(!pszInputURL)
  155.     {
  156.         m_LastError = HXR_OUTOFMEMORY;
  157.         return;
  158.     }
  159.     strcpy(pszInputURL, pszURL); /* Flawfinder: ignore */
  160.     // Keep permanent copy of input url
  161.     m_pszEscapedURL = new char[strlen(pszInputURL)+1];
  162.     strcpy(m_pszEscapedURL, pszInputURL); /* Flawfinder: ignore */
  163.     // IHXValues 
  164.     if (m_pCCF)
  165.     {
  166. m_pCCF->CreateInstance(CLSID_IHXValues, (void**)&m_pProperties);
  167. m_pCCF->CreateInstance(CLSID_IHXValues, (void**)&m_pOptions);
  168.     }
  169.     // protocol: determine whether it's network or local
  170.     if (0 == StringNCompare(pszInputURL, "http:", 5))
  171.     {
  172. m_unProtocol = httpProtocol;
  173. m_unDefaultPort = DEFAULT_HTTP_PORT;
  174.     }
  175.     else if (0 == StringNCompare(pszInputURL, "chttp:", 6))
  176.     {
  177. m_unProtocol = httpProtocol;
  178. m_unDefaultPort = DEFAULT_HTTP_PORT;
  179.     }
  180.     else if (0 == StringNCompare(pszInputURL, "pnm:", 4))
  181.     {
  182. m_unProtocol = pnmProtocol;
  183. m_bNetworkProtocol = TRUE;
  184. m_unDefaultPort = DEFAULT_PNA_PORT;
  185.     }
  186.     else if (0 == StringNCompare(pszInputURL, "rtsp:", 5))
  187.     {
  188. m_unProtocol = rtspProtocol;
  189. m_bNetworkProtocol = TRUE;
  190. m_unDefaultPort = DEFAULT_RTSP_PORT;
  191.     }
  192.     else if (0 == StringNCompare(pszInputURL, "helix-sdp:", 10))
  193.     {
  194. m_unProtocol = helixSDPProtocol;
  195. m_bNetworkProtocol = TRUE;
  196. m_unDefaultPort = DEFAULT_RTSP_PORT;
  197.     }
  198.     else if (0 == StringNCompare(pszInputURL, "https:", 6))
  199.     {
  200. m_unProtocol = httpsProtocol;
  201. m_unDefaultPort = DEFAULT_HTTPS_PORT;
  202.     }
  203.     if (m_pProperties)
  204.     {
  205. m_pProperties->SetPropertyULONG32(PROPERTY_PROTOCOL, (ULONG32)m_unProtocol);
  206.     }
  207.     else
  208.     {
  209. m_LastError = HXR_UNEXPECTED;
  210. goto cleanup;
  211.     }
  212.     // no need to further parse helix-sdp protocol
  213.     if (helixSDPProtocol != m_unProtocol)
  214.     {
  215.         // separate fragment from the URL
  216.         if (0!=(pszTemp = (char*) ::HXFindChar(pszInputURL, '#')))
  217.         {
  218.     // save fragment
  219.     pFragment = pszTemp + 1;
  220.     ::SaveStringToHeader(m_pProperties, PROPERTY_FRAGMENT, pFragment);
  221.     *pszTemp = '';
  222.         }
  223.         // HP - allow '$' in directory/file name
  224.         //
  225.         // still need to take care of that obsolete $ sign option:
  226.         // rtsp://moe.cr.prognet.com/ambush.rm$1:00
  227.         // time after the $ is assumed to be the start time.
  228.         //
  229.         // the solution is to compare the string following the $ to 
  230.         // a properly formed time. If the string is a time and only 
  231.         // a time, then we know its the old-style start-time option
  232.         // otherwise, '$' is part of the directory/file name and we
  233.         // will keep it.
  234.         pszDollarSign = (char*) ::HXFindChar(pszInputURL, '$');
  235.         while (pszDollarSign)
  236.         {
  237.     pszTemp = pszDollarSign + 1;
  238.     if (::TimeParse(pszTemp))
  239.     {
  240.         *pszDollarSign = '';
  241.         INT32 lLen = (2 * strlen(pszURL)) + 8;
  242.         pNewURL = new char[lLen];
  243.         memset(pNewURL, 0, lLen);
  244.           
  245.         // upgrade to a new URL
  246.         SafeSprintf(pNewURL, lLen, "%s?start=%s", pszInputURL, pszTemp);
  247.         HX_VECTOR_DELETE(pszInputURL);
  248.         pszInputURL = pNewURL;
  249.         break;
  250.     }
  251.     pszDollarSign = (char*) ::HXFindChar(pszTemp, '$');
  252.         }
  253.     }
  254. #if !defined(_MACINTOSH) && !defined(_MAC_UNIX)
  255.     // on Mac, unescaping can put /'s and ?'s back into file and folder names, which is deadly inside URLs
  256.     //if (0 == StringNCompare(pszInputURL, "file:", 5))
  257.     {
  258. // we only unescape the URL on local source since we are
  259. // *responding* instead of *requesting* for the given source
  260. Unescape(pszInputURL);
  261.     }
  262. #endif
  263.     if (!CompressURL(pszInputURL, m_pszURL))
  264.     {
  265. // make a copy of the URL
  266. m_pszURL = new char[strlen(pszInputURL)+1];
  267. strcpy(m_pszURL, pszInputURL); /* Flawfinder: ignore */
  268.     }
  269.     m_pActualURL = new char[strlen(m_pszURL)+1];
  270.     strcpy(m_pActualURL, m_pszURL); /* Flawfinder: ignore */
  271.     ::SaveStringToHeader(m_pProperties, PROPERTY_URL, m_pszURL);
  272.     // no need to further parse helix-sdp protocol
  273.     if (helixSDPProtocol != m_unProtocol)
  274.     {
  275.         // separate options from the URL
  276.         if (0 != (pszTemp = (char*) ::HXFindChar(m_pszURL, '?')))
  277.         {
  278.     // options
  279.     m_pszOptions = pszTemp + 1;
  280.         }
  281.        
  282.         // collect protocol, host, port and resource info
  283.         ParseURL (m_pszURL);
  284.     
  285.         // collect other options info if it has 
  286.         if (m_pszOptions)
  287.         {
  288.     if (HXR_INCOMPLETE == CollectOptions(m_pszOptions) && m_pszResource)
  289.     {
  290.              // bad options and remove it from the URL
  291.              pszTemp = (char*) ::HXFindChar(m_pszResource, '?');
  292.         if (pszTemp)
  293.         {
  294.     *pszTemp = '';
  295.     ParseResource();
  296.         }
  297.     }
  298.         }   
  299.     }
  300. cleanup:
  301.     HX_VECTOR_DELETE(pszInputURL);
  302. }
  303. CHXURL::~CHXURL ()
  304. {
  305.     HX_VECTOR_DELETE(m_pActualURL);
  306.     HX_VECTOR_DELETE(m_pszURL);
  307.     HX_VECTOR_DELETE(m_pszEscapedURL);
  308.     HX_RELEASE(m_pProperties);
  309.     HX_RELEASE(m_pOptions);
  310.     HX_RELEASE(m_pCCF);
  311. }
  312. CHXURL::CHXURL(const CHXURL& rhs) 
  313.     :m_LastError (HXR_OK)
  314.     ,m_pActualURL(NULL)
  315.     ,m_pszURL(NULL)
  316.     ,m_pszOptions (NULL)
  317.     ,m_pszHost (NULL)
  318.     ,m_pszPort (NULL)
  319.     ,m_pszUsername(NULL)
  320.     ,m_pszPassword(NULL)
  321.     ,m_unProtocol (fileProtocol)
  322.     ,m_bNetworkProtocol (FALSE)
  323.     ,m_pszResource (NULL)
  324.     ,m_pProperties (NULL)
  325.     ,m_pOptions (NULL)
  326.     ,m_pCCF(rhs.m_pCCF)
  327. {
  328.     if (m_pCCF)
  329.     {
  330. m_pCCF->AddRef();
  331.     }
  332.     ConstructURL(rhs.GetEscapedURL());
  333. }
  334. CHXURL& CHXURL::operator=(const CHXURL& rhs)
  335. {
  336.     if (&rhs != this)
  337.     {
  338. // Clean out old data
  339. HX_VECTOR_DELETE(m_pActualURL);
  340. HX_VECTOR_DELETE(m_pszURL);
  341.         HX_VECTOR_DELETE(m_pszEscapedURL);
  342. HX_RELEASE(m_pProperties);
  343. HX_RELEASE(m_pOptions);
  344. HX_RELEASE(m_pCCF);
  345. m_LastError = HXR_OK;
  346. m_pszOptions = NULL;
  347. m_pszHost = NULL;
  348. m_pszPort = NULL;
  349. m_pszUsername = NULL;
  350. m_pszPassword = NULL;
  351. m_unProtocol = fileProtocol;
  352. m_bNetworkProtocol = FALSE;
  353. m_pszResource = NULL;
  354. ConstructURL(rhs.GetEscapedURL());
  355. m_pCCF = rhs.m_pCCF;
  356. if (m_pCCF)
  357. {
  358.     m_pCCF->AddRef();
  359. }
  360.     }
  361.     return *this;
  362. }
  363. HX_RESULT CHXURL::ParseURL (char* pszURL)
  364. {
  365.     char* pszOption = NULL;
  366.     char* pszTemp = NULL;
  367.     char* pszSlash = NULL;
  368.     char* pszCursor = NULL;    
  369.     if (HXR_OK != m_LastError)
  370.     {
  371. goto cleanup;
  372.     }
  373.     pszCursor = pszURL;
  374.     
  375.     //
  376.     // let's start
  377.     //
  378.     // find the scheme - note that ParseURL only succeeds
  379.     // for absolute URLs
  380.     m_LastError = HXR_INVALID_PROTOCOL; // assume the worst
  381.     pszTemp = (char *) FindURLSchemeEnd(pszURL);
  382.     if (pszTemp)
  383.     {
  384. char* pScheme = new_string(pszURL, pszTemp - pszURL);
  385. m_LastError = HXR_OK;
  386. ::SaveStringToHeader(m_pProperties, PROPERTY_SCHEME, pScheme);
  387. delete[] pScheme;
  388.     }
  389.     if(HXR_OK != m_LastError)
  390.     {
  391. goto cleanup;
  392.     }
  393.     pszCursor = pszTemp + 1;
  394.   
  395.     if(strncmp(pszCursor, "//", 2) == 0)
  396.     {
  397. pszCursor += 2; // skip '//'
  398.     }
  399.     else if(strncmp(pszCursor, "/", 1) == 0)
  400.     {
  401. pszCursor += 1; // skip '/' (ill-formed url?)
  402.     }
  403.     if (fileProtocol == m_unProtocol)
  404.     {
  405. // resource
  406. if (*(m_pszResource = pszCursor) == '')
  407. {
  408.     m_LastError = HXR_INVALID_URL_PATH;
  409.     goto cleanup;
  410. }
  411.     }
  412.     // network URL + http
  413.     else
  414.     {
  415. // First check for optional username and password parameters.
  416. // The colon is also optional if either username or password
  417. // is not given Form in context:
  418. // protocol://username:password@host:port/resource (From RFC
  419. // 1738)
  420. pszTemp = (char*) ::HXFindChar(pszCursor, ':');
  421. pszSlash = (char*) ::HXFindChar(pszCursor, '/');
  422. pszOption = (char*) ::HXFindChar(pszCursor, '@');
  423. // There is a username or password if we see a '@' character
  424. // according to RFC 1738 this is a reserved character
  425. if (pszOption && pszOption < pszSlash)
  426. {
  427.     // Username
  428.     if (*(m_pszUsername = pszCursor) == '')
  429.     {
  430. m_LastError = HXR_INVALID_URL_HOST;
  431. goto cleanup;
  432.     }
  433.     // If the is a ':' and it is before the '@' then we have a
  434.     // password, so zero terminate the username and move the
  435.     // cursor to the password
  436.     if (pszTemp && (pszTemp < pszOption))
  437.     {
  438. *pszTemp = '';
  439. pszCursor = pszTemp+1;
  440.     }
  441.     // There is no ':' so move the cursor to the '@' character
  442.     // so it will be a zero terminated empty string
  443.     else
  444. pszCursor = pszOption;
  445.     // Password
  446.     if (*(m_pszPassword = pszCursor) == '')
  447.     {
  448. m_LastError = HXR_INVALID_URL_HOST;
  449. goto cleanup;
  450.     }
  451.     // Zero terminate password and move the cursor to the hostname
  452.     *pszOption = '';
  453.     if (m_pszUsername)
  454.     {
  455. ::SaveStringToHeader(m_pProperties, PROPERTY_USERNAME, m_pszUsername);
  456.     }
  457.     if (m_pszPassword)
  458.     {
  459. ::SaveStringToHeader(m_pProperties, PROPERTY_PASSWORD, m_pszPassword);
  460.     }
  461.     pszCursor = pszOption+1;
  462. }
  463. // host
  464. if (*(m_pszHost = pszCursor) == '')
  465. {
  466.     m_LastError = HXR_INVALID_URL_HOST;
  467.     goto cleanup;
  468. }
  469. // port
  470. pszTemp = (char*) ::HXFindChar(pszCursor, '/');
  471. if (pszTemp)
  472. {
  473.     *pszTemp = '';
  474.     pszCursor = pszTemp+1;
  475. }
  476. else
  477. {
  478.     // it's legal to have RTSP or HTTP URLs with no resource.
  479.             // The correct behavior for RTSP would be not to flag this as
  480.             // an error but the client core treats the lack of a resource
  481.             // as a failure. The correct change would be to have the client
  482.             // core check explicitly for a resource but legacy code rears its
  483.             // ugly head... so we flag the error (client core is happy) but
  484.             // go ahead and parse the rest of the headers (so you can still 
  485.             // get the host:port if you need to). */
  486.     if (m_unProtocol != httpProtocol && m_unProtocol != rtspProtocol)
  487.     {
  488. m_LastError = HXR_INVALID_URL_PATH;                
  489.     }
  490.     pszCursor = NULL;
  491. }
  492. // port
  493. pszTemp = (char*) ::HXFindChar(m_pszHost, ':');
  494. if (pszTemp)
  495. {
  496.     *pszTemp = '';
  497.   
  498.     if (*(m_pszPort = pszTemp+1) == '')
  499.     {
  500. m_LastError = HXR_INVALID_URL_HOST;
  501. goto cleanup;
  502.     }
  503. }
  504. if (m_pszHost)
  505. {
  506.     ::SaveStringToHeader(m_pProperties, PROPERTY_HOST, m_pszHost);
  507. }
  508. if (m_pszPort)
  509. {
  510.     m_pProperties->SetPropertyULONG32(PROPERTY_PORT, (ULONG32)atol(m_pszPort));
  511. }
  512. else if (m_unDefaultPort > 0)
  513. {
  514.     m_pProperties->SetPropertyULONG32(PROPERTY_PORT, (ULONG32)m_unDefaultPort);
  515. }
  516. if (pszCursor && (*(m_pszResource = pszCursor) == '' && m_unProtocol != httpProtocol && m_unProtocol != rtspProtocol))
  517. {
  518.     m_LastError = HXR_INVALID_URL_PATH;
  519.     goto cleanup;
  520. }
  521.     }
  522.     //
  523.     // other options?
  524.     //
  525.     /*
  526.     // 1.0 player
  527.     if (pszTemp = (char*) ::HXFindChar(pszCursor, '$'))
  528.     {
  529. *pszTemp = '';
  530. pszCursor = pszTemp+1;
  531. if (*(m_pszStartTime = pszCursor) == '')
  532. {
  533.     m_LastError = HXR_FAILED;
  534.     goto cleanup;
  535. }
  536.     }
  537.     */
  538. cleanup:
  539.     ParseResource();
  540.     return m_LastError;
  541. }
  542. void
  543. CHXURL::TrimOffSpaces(char*& pszString)
  544. {
  545.     if( NULL == pszString ) 
  546.         return;
  547.     
  548.     char* pszValue = pszString;
  549.     char* pszCursor = pszString;
  550.     
  551.     // trim off the leading spaces 
  552.     while (*pszCursor == ' ')
  553.     {
  554.         pszCursor++;
  555.     }
  556.     pszValue = pszCursor;
  557.     // trim off the tailing spaces
  558.     if( strlen(pszCursor) != 0 )
  559.     {
  560.         pszCursor = pszCursor + strlen(pszCursor) - 1;
  561.         
  562.         while (*pszCursor == ' ' )
  563.         {
  564.             pszCursor--;
  565.         }
  566.         ++pszCursor;
  567.         if( *pszCursor != '' )
  568.             *pszCursor = '';
  569.     }
  570.     
  571.     pszString = pszValue;
  572. }
  573. HX_RESULT
  574. CHXURL::CollectOptions (char* pszOptions)
  575. {
  576.     HX_RESULT hr = HXR_OK;
  577.     char*   pszCursor = NULL;
  578.     char*   pszKey = NULL;
  579.     char*   pszValue = NULL;
  580.     char*   pszTemp = NULL;
  581.     BOOL    bValueQuoted = FALSE;
  582.   
  583.     if (HXR_OK != m_LastError)
  584.     {
  585. return m_LastError;
  586.     }
  587.     pszCursor = pszOptions;
  588.     char* pszEndOptions = pszOptions + strlen(pszOptions);
  589.     // let's start parsing
  590.     while (pszCursor < pszEndOptions)
  591.     {
  592. //
  593. // collect one value pair at a time
  594. //
  595. // <key>="<value>" or <key>=<value> 
  596. pszKey = pszCursor;
  597. if (!(pszTemp = (char*) ::HXFindChar(pszCursor, '=')))
  598. {
  599.     hr = HXR_FAILED;
  600.     goto cleanup;
  601. }
  602. *pszTemp = '';
  603. pszCursor = pszTemp + 1;
  604. // remove all the spaces between '=' and actual value
  605. while (*pszCursor == ' ')
  606. {
  607.     pszCursor++;
  608. }
  609. // "<value>"
  610. if (*pszCursor == '"')
  611. {
  612.     bValueQuoted = TRUE;
  613.     pszCursor += 1;
  614. }
  615. pszValue = pszCursor;
  616. if (bValueQuoted)
  617. {
  618.     if (!(pszTemp = (char*) ::HXFindChar(pszCursor, '"')))
  619.     {
  620. hr = HXR_INCOMPLETE;
  621. goto cleanup;
  622.     }
  623.     *pszTemp = '';
  624.     pszCursor = pszTemp + 1;
  625. }
  626. if ((pszTemp = (char*) ::HXFindChar(pszCursor, '&')) != 0)
  627. {
  628.     *pszTemp = '';
  629.     
  630.     // move cursor to the next pair
  631.     pszCursor = pszTemp + 1;
  632. }
  633. else
  634. {
  635.     // move cursor to the end of this URL
  636.     pszCursor += strlen(pszValue);
  637. }
  638. // trim off leading/tailing spaces
  639. TrimOffSpaces(pszKey);
  640. TrimOffSpaces(pszValue);
  641.         // decode each value (option) since it may be URL-encoded.
  642.         CHXString strUnescapedOptionValue;
  643.         CHXURL::decodeURL(pszValue, strUnescapedOptionValue);
  644.         pszValue = (char *)(const char *)strUnescapedOptionValue;
  645. // save to the header
  646. if (!strcasecmp("Start", pszKey)
  647.     || !strcasecmp("End", pszKey)
  648.     || !strcasecmp("Delay", pszKey)
  649.     || !strcasecmp("Duration", pszKey))
  650. {
  651.     m_pOptions->SetPropertyULONG32(pszKey, (ULONG32) ::TimeParse(pszValue) * 100);
  652. }
  653. else if (bValueQuoted || !IsNumber(pszValue))
  654. {
  655.     IHXBuffer* pBuffer = NULL;
  656.     if (m_pCCF)
  657.     {
  658. m_pCCF->CreateInstance(CLSID_IHXBuffer, (void**)&pBuffer);
  659.     }
  660.     if (!pBuffer)
  661.     {
  662. hr = HXR_OUTOFMEMORY;
  663. goto cleanup;
  664.     }
  665.     pBuffer->Set((UCHAR*)pszValue, strlen(pszValue)+1);
  666.     m_pOptions->SetPropertyBuffer(pszKey, (IHXBuffer*) pBuffer);
  667.     pBuffer->Release();
  668. }
  669. else
  670. {
  671.     m_pOptions->SetPropertyULONG32(pszKey, (ULONG32) atol(pszValue));
  672. }
  673. bValueQuoted = FALSE;
  674. pszKey = NULL;
  675. pszValue = NULL;
  676.     }
  677.     
  678. cleanup:
  679.     return hr;
  680. }
  681. BOOL
  682. CHXURL::IsTimeValue (char* pszValue)
  683. {
  684.     int     i = 0;
  685.     char*   pszData = NULL;
  686.     char*   pszTemp = NULL;
  687.     // time value format: hh:mm:ss
  688.     if (isdigit(*pszValue) &&
  689. isdigit(*(pszValue+1)) &&
  690. *(pszValue+2) == ':' &&
  691. isdigit(*(pszValue+3)) &&
  692. isdigit(*(pszValue+4)) &&
  693. *(pszValue+5) == ':' &&
  694. isdigit(*(pszValue+6)) &&
  695. isdigit(*(pszValue+7)))
  696.     {
  697. for (i = 0; i < 3; i++)
  698. {
  699.     pszData = pszValue;
  700.     if (i < 2)
  701.     {
  702. pszTemp = (char*) ::HXFindChar(pszValue, ':');
  703. pszTemp = '';
  704.     }
  705.     switch (i)
  706.     {
  707.     case 0: // hh
  708. if (atoi(pszData) >= 24)
  709. {
  710.     return FALSE;
  711. }
  712. break;
  713.     case 1: // mm
  714. if (atoi(pszData) >= 60)
  715. {
  716.     return FALSE;
  717. }
  718. break;
  719.     case 2: // ss
  720. if (atoi(pszData) >= 60)
  721. {
  722.     return FALSE;
  723. }
  724. break;
  725.     default:
  726. break;
  727.     }
  728.     pszValue = pszTemp + 1;
  729. }
  730. return TRUE;
  731.     }
  732.     return FALSE;
  733. }    
  734. BOOL
  735. CHXURL::IsNumber(char* pszValue)
  736. {
  737.     char* pszCursor = pszValue;
  738.     while (*pszCursor != '')
  739.     {
  740. if (!isdigit(*pszCursor))
  741. {
  742.     return FALSE;
  743. }
  744. pszCursor++;
  745.     }
  746.     return TRUE;
  747. }
  748. // case insensitive compare
  749. int
  750. CHXURL::StringNCompare (const char* pszStr1, const char* pszStr2, size_t nChars)
  751. {
  752. #ifdef _WINDOWS
  753.     return strnicmp (pszStr1, pszStr2, nChars);
  754. #elif defined(_MACINTOSH)
  755.     return strnicmp (pszStr1, pszStr2, nChars);
  756. #elif defined(_UNIX) || defined(_OPENWAVE)
  757.     return strncasecmp (pszStr1, pszStr2, nChars);
  758. #elif defined(_SYMBIAN)
  759.     return strnicmp(pszStr1, pszStr2, nChars);
  760. #elif
  761. #   error "undefined platform....."    
  762. #else
  763.     return -1;
  764. #endif
  765. }
  766. void
  767. CHXURL::AddOption(char* pKey, char* pValue)
  768. {
  769.     // trim off leading/tailing spaces
  770.     TrimOffSpaces(pKey);
  771.     TrimOffSpaces(pValue);
  772.     
  773.     // save to the header
  774.     if (IsNumber(pValue))
  775.     {
  776. m_pOptions->SetPropertyULONG32(pKey, (ULONG32) atol(pValue));
  777.     }
  778.     else
  779.     {
  780. IHXBuffer*  pBuffer = NULL;
  781. if (m_pCCF)
  782. {
  783.     m_pCCF->CreateInstance(CLSID_IHXBuffer, (void**)&pBuffer);
  784. }
  785. if (pBuffer)
  786. {
  787.     pBuffer->Set((UCHAR*)pValue, strlen(pValue)+1);
  788.     m_pOptions->SetPropertyBuffer(pKey, (IHXBuffer*) pBuffer);
  789.     pBuffer->Release();
  790. }
  791.     }
  792. }
  793. void
  794. CHXURL::AddOption(char* pKey, UINT32 ulValue)
  795. {
  796.     TrimOffSpaces(pKey);
  797.     m_pOptions->SetPropertyULONG32(pKey, ulValue);
  798. }
  799. IHXValues*
  800. CHXURL::GetProperties(void)
  801. {
  802.     if (m_pProperties)
  803.     {
  804. m_pProperties->AddRef();
  805.     }
  806.     return m_pProperties;
  807. }
  808. IHXValues*
  809. CHXURL::GetOptions(void)
  810. {
  811.     if (m_pOptions)
  812.     {
  813. m_pOptions->AddRef();
  814.     }
  815.     return m_pOptions;
  816. }
  817. char*
  818. CHXURL::GetAltURL(BOOL& bDefault)
  819. {
  820.     IHXBuffer* pValue = NULL;
  821.     char* pAltURL = NULL;
  822.     char* pURL = NULL;
  823.     char* pCursor1 = NULL;
  824.     char* pCursor2 = NULL;
  825.     bDefault = FALSE;
  826.     if (HXR_OK != m_LastError)
  827.     {
  828. goto cleanup;
  829.     }
  830.     // retrieve Alt-URL if it exists in the option list
  831.     if (HXR_OK == m_pOptions->GetPropertyBuffer("altURL", pValue) && pValue)
  832.     {     
  833. // allocate mem. for m_pszAltURL
  834. pAltURL = new char[pValue->GetSize()];
  835. SafeStrCpy(pAltURL, (const char*)pValue->GetBuffer(), pValue->GetSize());
  836.     }
  837.     else if (HXR_OK == m_pProperties->GetPropertyBuffer("url", pValue) && pValue)
  838.     {
  839. if (m_unProtocol == pnmProtocol ||
  840.     m_unProtocol == rtspProtocol)
  841. {
  842.     bDefault = TRUE;
  843.     
  844.     // The +1 is NOT for the NULL terminator since the size already has space for it.  The +1 is actually because
  845.     // if the URL contains a pnm:// the code below will potentially add a http:// which is one more character than
  846.     // a pnm URL.  A rtsp:// URL will work correctly 
  847.             INT32 lSize = pValue->GetSize() + 1;
  848.     pAltURL = new char[lSize];
  849.     memset(pAltURL, 0, lSize);
  850.     pURL = (char*)pValue->GetBuffer();
  851.     
  852.     switch (m_unProtocol)
  853.     {
  854.     case pnmProtocol:
  855. SafeSprintf(pAltURL, lSize, "http:%s", pURL + 4);
  856. break;
  857.     case rtspProtocol:
  858. SafeSprintf(pAltURL, lSize, "http:%s", pURL + 5);
  859. break;
  860.     default:
  861. break;
  862.     }
  863.     // exclude the port from the URL
  864.     if (m_pszPort)
  865.     {
  866. pCursor1 = strstr(pAltURL, m_pszPort);
  867.                 pCursor2 = pCursor1 + strlen(m_pszPort);
  868.                 pCursor1--; // back up over the ':'
  869.                 
  870.                 while(*pCursor2)
  871.                 {
  872.                     *pCursor1++ = *pCursor2++;
  873.                 }
  874.                 *pCursor1 = '';
  875.     }
  876. }
  877.     }
  878. cleanup:
  879.     HX_RELEASE(pValue);
  880.     return pAltURL;
  881. }
  882. void
  883. CHXURL::ParseResource(void)
  884. {
  885.     char* pszTemp = NULL;
  886.     char* pResource = NULL;
  887.     char* pPath = NULL;
  888.     char* pFullPath = NULL;
  889.     if (m_pszResource && (*m_pszResource != ''))
  890.     {
  891. ::SaveStringToHeader(m_pProperties, PROPERTY_RESOURCE, m_pszResource);
  892. ::StrAllocCopy(pResource, m_pszResource);
  893. pszTemp = ::HXFindChar(pResource, '?');
  894. if (pszTemp)
  895. {
  896.     *pszTemp = '';
  897. }
  898.         pFullPath = new char[strlen(pResource) + 2];
  899. SafeSprintf(pFullPath, strlen(pResource)+2, "/%s", pResource);
  900. ::SaveStringToHeader(m_pProperties, PROPERTY_FULLPATH, pFullPath);
  901. pszTemp = ::HXReverseFindChar(pResource, '/');
  902. if (pszTemp)
  903. {
  904.     *pszTemp = '';
  905.     
  906.     pPath = new char[strlen(pResource)+2];
  907.     SafeSprintf(pPath, strlen(pResource)+2, "/%s", pResource);
  908.     ::SaveStringToHeader(m_pProperties, PROPERTY_PATH, pPath);
  909. }
  910. else
  911. {
  912.     ::SaveStringToHeader(m_pProperties, PROPERTY_PATH, "/");
  913. }
  914. HX_VECTOR_DELETE(pFullPath);
  915. HX_VECTOR_DELETE(pPath);
  916. HX_VECTOR_DELETE(pResource);
  917.     }
  918.     else if (m_unProtocol == rtspProtocol)
  919.     {
  920. ::SaveStringToHeader(m_pProperties, PROPERTY_RESOURCE, "");
  921. ::SaveStringToHeader(m_pProperties, PROPERTY_FULLPATH, "");
  922. ::SaveStringToHeader(m_pProperties, PROPERTY_PATH, "");
  923.     }
  924. }
  925. HX_RESULT
  926. CHXURL::GeneratePrefixRootFragment(const char* pURL, CHXString& urlPrefix, 
  927.    CHXString& urlRoot, char*& pURLFragment)
  928. {
  929.     BOOL bHasHost = FALSE;
  930.     CHXURL urlObj(pURL);
  931.     IHXValues* pHeader = urlObj.GetProperties();
  932.     if(!pHeader)
  933.     {
  934. return HXR_FAIL;
  935.     }
  936.     IHXBuffer* pBuffer = 0;
  937.     ULONG32 ulTemp;
  938.     if(HXR_OK == pHeader->GetPropertyBuffer(PROPERTY_SCHEME, pBuffer))
  939.     {
  940. urlPrefix = (const char*)pBuffer->GetBuffer();
  941. urlPrefix += "://";
  942. pBuffer->Release();
  943.     }
  944.     if(HXR_OK == pHeader->GetPropertyBuffer(PROPERTY_HOST, pBuffer))
  945.     {
  946. urlPrefix += (const char*)pBuffer->GetBuffer();
  947. pBuffer->Release();
  948. bHasHost = TRUE;
  949.     }
  950.     if(HXR_OK == pHeader->GetPropertyULONG32(PROPERTY_PORT, ulTemp))
  951.     {
  952.   char szTemp[10]; /* Flawfinder: ignore */
  953. SafeSprintf(szTemp, sizeof(szTemp), ":%d", (UINT16)ulTemp);
  954. urlPrefix += szTemp;
  955.     }
  956.     // set root
  957.     urlRoot = urlPrefix;
  958.     if(bHasHost)
  959.     {
  960. urlPrefix += "/";
  961.     }
  962.     if(HXR_OK == pHeader->GetPropertyBuffer(PROPERTY_RESOURCE, pBuffer))
  963.     {
  964. const char* pResource = (const char*)pBuffer->GetBuffer();
  965. const char  cDelimiter1  = '/';
  966. const char  cDelimiter2  = '\';
  967. const char  cOSDelimiter = OS_SEPARATOR_CHAR;
  968. CHXString   strURLWork = pResource; 
  969. char* pFirstChar    = strURLWork.GetBuffer(strURLWork.GetLength());
  970. char* pLastChar     = NULL;
  971. char* pOptions     = NULL;
  972. char* pFragment     = NULL;
  973. pOptions = strchr(pFirstChar, '?');
  974. if (pOptions)
  975. {
  976.     pLastChar = pOptions -1;
  977. }
  978. else
  979. {
  980.     pLastChar = pFirstChar + strlen(pFirstChar)-1;
  981. }
  982. while ((pLastChar > pFirstChar) && 
  983.    (*pLastChar != cDelimiter1) && (*pLastChar != cDelimiter2) &&
  984.    (*pLastChar != cOSDelimiter))
  985. {
  986. pLastChar--;
  987. }
  988. // If we hit a delimiter before hitting the end, back up one character!
  989. if(pLastChar > pFirstChar) 
  990. {
  991.     *(++pLastChar) = '';
  992.     
  993.     urlPrefix += pFirstChar;
  994. }
  995. pBuffer->Release();
  996.     }
  997.     if(HXR_OK == pHeader->GetPropertyBuffer(PROPERTY_FRAGMENT, pBuffer))
  998.     {
  999. const char* pFragment = (const char*)pBuffer->GetBuffer();
  1000. pURLFragment = new_string(pFragment);
  1001. pBuffer->Release();
  1002.     }
  1003.     HX_RELEASE(pHeader);
  1004.     return HXR_OK;
  1005. }
  1006. BOOL 
  1007. CHXURL::CompressURL(const char* pURL, char*& pCompressURL)
  1008. {
  1009.     HX_ASSERT(pURL != NULL);
  1010.     if (!pURL)
  1011.     {
  1012. return FALSE;
  1013.     }
  1014.     pCompressURL     = NULL;
  1015.     BOOL bNeedToCompress    = FALSE; 
  1016.     char separator1     = '\';
  1017.     char separator2     = '/';
  1018.     char* pWalker     = (char*) pURL;
  1019.     while (*pWalker)
  1020.     {
  1021. /* 
  1022.  *   /./ || /. || ./ || . || 
  1023.  *   /../ || /.. || ../ || ..
  1024.  */
  1025. if ((*pWalker     == separator1 || *pWalker == separator2) &&
  1026.     (*(pWalker+1)   == '.') &&
  1027.     ((*(pWalker+2)   == separator1 || *(pWalker+2) == separator2) ||
  1028.      ((*(pWalker+2)   == '.') &&
  1029.      (*(pWalker+3)   == separator1 || *(pWalker+3) == separator2))))
  1030. {
  1031.     // we need to commpress it
  1032.     bNeedToCompress = TRUE;
  1033.     break;
  1034. }
  1035. /* Do not process options in the URL (stuff after ?) */
  1036. if (*pWalker == '?')
  1037. {
  1038.     break;
  1039. }
  1040. pWalker++;
  1041.     }
  1042.     if (!bNeedToCompress)
  1043.     {
  1044. return FALSE;
  1045.     }
  1046.     UINT32 ulURLLength;
  1047.     char* pTempURL;
  1048.     char* pOptions;
  1049.     ulURLLength = strlen(pURL) + 1;
  1050.     pTempURL = new char[ulURLLength];
  1051.     ::strcpy(pTempURL, pURL); /* Flawfinder: ignore */
  1052.     pOptions = strchr(pTempURL, '?');
  1053.     /* We will only compress till before the options and then paste the options
  1054.      * at the end
  1055.      */
  1056.     if (pOptions)
  1057.     {
  1058. *pOptions = '';
  1059.     }
  1060.     CHXSimpleList* pList;
  1061.     char* pToken;
  1062.     UINT16 uNumToBeDiscarded;
  1063.     CHXSimpleList* pNewList;
  1064.     
  1065.     pList    = new CHXSimpleList;
  1066.     pNewList = new CHXSimpleList;
  1067.     uNumToBeDiscarded = 0;
  1068.     pWalker = pToken = pTempURL;    
  1069.     while (*pWalker)
  1070.     {
  1071. if (*pWalker == '/' || *pWalker == '\')
  1072. {
  1073.     *pWalker = '';
  1074.     pList->AddTail(pToken);
  1075.     pToken = pWalker+1;
  1076. }
  1077. pWalker++;
  1078.     }
  1079.     pList->AddTail(pToken);
  1080.     while (pList->GetCount() > 0)
  1081.     {
  1082. pToken = (char*) pList->RemoveTail();
  1083. if (::strcmp(pToken, ".") == 0)
  1084. {
  1085.     /* ignore it */    
  1086. }
  1087. else if (::strcmp(pToken, "..") == 0)
  1088. {
  1089.     uNumToBeDiscarded++;
  1090. }
  1091. else if (uNumToBeDiscarded > 0)
  1092. {
  1093.     uNumToBeDiscarded--;
  1094. }
  1095. else
  1096. {
  1097.     pNewList->AddTail(pToken);
  1098. }
  1099.     }
  1100. // /Valid content that starts with "../../" will trigger this, so turn it off
  1101. // unless someone wants to refine it:
  1102. #if defined(ALLOW_IRRITATING_ASSERTS_FOR_VALID_CONTENT)
  1103.     // This will trigger with malformed urls with two additional ellipses(..)
  1104.     HX_ASSERT(uNumToBeDiscarded == 0 && pNewList->GetCount() > 0);
  1105. #endif
  1106.     if (uNumToBeDiscarded > 0 || pNewList->GetCount() == 0)
  1107.     {
  1108. bNeedToCompress = FALSE;
  1109. goto exit;
  1110.     }
  1111.     pCompressURL = new char[ulURLLength];
  1112.     *pCompressURL = '';
  1113.     while (pNewList->GetCount() > 0)
  1114.     {
  1115. pToken = (char*) pNewList->RemoveTail();
  1116. SafeStrCat(pCompressURL, (const char*) pToken, ulURLLength);
  1117. if (!pNewList->IsEmpty())
  1118. {
  1119.     SafeStrCat(pCompressURL, "/", ulURLLength);
  1120. }
  1121.     }
  1122.     if (pOptions)
  1123.     {
  1124. SafeStrCat(pCompressURL, "?", ulURLLength);
  1125. SafeStrCat(pCompressURL, (const char*) (pOptions+1), ulURLLength);
  1126.     }
  1127. exit:
  1128.     HX_VECTOR_DELETE(pTempURL);
  1129.     HX_DELETE(pList);
  1130.     HX_DELETE(pNewList);
  1131.     return bNeedToCompress;
  1132. }
  1133. HX_RESULT
  1134. CHXURL::encodeURL(const char* pURL, CHXString& encodedURL)
  1135. {
  1136.     HX_RESULT rc = HXR_OK;
  1137.     char    hexBuf[3] = {0}; /* Flawfinder: ignore */
  1138.     char*   pEncodeBuf = new char[(strlen(pURL)+1)*3];    // overkill
  1139.     char*   pEncodePtr = pEncodeBuf;
  1140.     const   char* pURLPtr = pURL;
  1141.     while(*pURLPtr)
  1142.     {
  1143.      // according to the URL encoding spec. from
  1144. // http://www.isi.edu/in-notes/rfc1738.txt
  1145. if (*pURLPtr <= 0x1f ||
  1146.     *pURLPtr >= 0x7f ||
  1147.     HXIsEqual(pURLPtr, ' ') ||
  1148. //     HXIsEqual(pURLPtr, '<') ||
  1149. //     HXIsEqual(pURLPtr, '>') ||
  1150. //     HXIsEqual(pURLPtr, '"') ||
  1151. //     HXIsEqual(pURLPtr, '#') ||
  1152. //     HXIsEqual(pURLPtr, '%') ||
  1153.     HXIsEqual(pURLPtr, '{') ||
  1154.     HXIsEqual(pURLPtr, '}') ||
  1155.     HXIsEqual(pURLPtr, '|') ||
  1156.     HXIsEqual(pURLPtr, '\') ||
  1157.     HXIsEqual(pURLPtr, '^') ||
  1158.     HXIsEqual(pURLPtr, '~') ||
  1159.     HXIsEqual(pURLPtr, '[') ||
  1160.     HXIsEqual(pURLPtr, ']') ||
  1161.     HXIsEqual(pURLPtr, '`') ||
  1162.     HXIsEqual(pURLPtr, ',') ||
  1163.     HXIsEqual(pURLPtr, ';'))
  1164. {     
  1165.     SafeSprintf(hexBuf, sizeof(hexBuf), "%02x", (UCHAR)*pURLPtr);
  1166.     *pEncodePtr++ = '%';
  1167.     *pEncodePtr++ = hexBuf[0];
  1168.     *pEncodePtr++ = hexBuf[1];
  1169.     
  1170.     if (HXIsLeadByte(*pURLPtr))
  1171.     {
  1172. SafeSprintf(hexBuf, sizeof(hexBuf), "%02x", (UCHAR)*(pURLPtr+1));
  1173. *pEncodePtr++ = '%';
  1174. *pEncodePtr++ = hexBuf[0];
  1175. *pEncodePtr++ = hexBuf[1];
  1176.     }     
  1177. }
  1178. else
  1179. {
  1180.     *pEncodePtr++ = *pURLPtr;
  1181. }
  1182. pURLPtr = HXGetNextChar(pURLPtr) ;
  1183.     }
  1184.     *pEncodePtr = '';
  1185.     encodedURL = pEncodeBuf;
  1186.     delete[] pEncodeBuf;
  1187.     return rc;
  1188. }
  1189. HX_RESULT
  1190. CHXURL::decodeURL(const char* pURL, CHXString& decodedURL)
  1191. {
  1192.     HX_RESULT rc = HXR_OK;
  1193.     //XXXBAB - reimplement using CHXString::GetBuffer()/SetBuffer()
  1194.     // to avoid memcpy
  1195.     char* pDecodeBuf = new char[strlen(pURL)+1];
  1196.     char* pDecodePtr = pDecodeBuf;
  1197.     const char* pURLPtr = pURL;
  1198.     while(*pURLPtr)
  1199.     {
  1200. switch(*pURLPtr)
  1201. {
  1202.     case '%':
  1203.     {
  1204. char hexBuf[3]; /* Flawfinder: ignore */
  1205. if(pURLPtr[1] &&    // check for overbound condition
  1206.    pURLPtr[2])
  1207. {
  1208.     pURLPtr++;  // walk past '%'
  1209.     hexBuf[0] = *pURLPtr++;
  1210.     hexBuf[1] = *pURLPtr;
  1211.     hexBuf[2] = '';
  1212.     *pDecodePtr++ = (char)strtol(hexBuf, NULL, 16);
  1213. }
  1214.     }
  1215.     break;
  1216.     default:
  1217.     {
  1218. *pDecodePtr++ = *pURLPtr;
  1219.     }
  1220.     break;
  1221. }
  1222. pURLPtr++;
  1223.     }
  1224.     *pDecodePtr = '';
  1225.     decodedURL = pDecodeBuf;
  1226.     delete[] pDecodeBuf;
  1227.     return rc;
  1228. }
  1229. const char* CHXURL::FindURLSchemeEnd(const char *pszURL)
  1230. {
  1231.     const char *pszTemp;
  1232.     for (pszTemp = pszURL; *pszTemp; pszTemp++)
  1233.     {
  1234. if(*pszTemp == ':')
  1235. {
  1236.     return pszTemp;
  1237. }
  1238. else if(*pszTemp == '$' ||
  1239. *pszTemp == '#' ||
  1240. *pszTemp == '?' ||
  1241. *pszTemp == '/' ||
  1242. *pszTemp == '\')
  1243. {
  1244.     return NULL;
  1245. }
  1246.     }
  1247.     
  1248.     return NULL;
  1249. }
  1250. void
  1251. CHXURL::Unescape(char* s)
  1252. {
  1253. /*
  1254.  * Remove URL hex escapes from s... done in place.  The basic concept for
  1255.  * this routine is borrowed from the WWW library HTUnEscape() routine.
  1256.  */
  1257.     char* p = NULL;
  1258.     BOOL bProcessingOptionsPastQuestionMark = FALSE;
  1259.     for (p = s; *s != ''; ++s)
  1260.     {
  1261.         if ( (!bProcessingOptionsPastQuestionMark) && (*s == '%') )
  1262. {
  1263.     if (*++s != '') 
  1264.     {
  1265. *p = Unhex( *s ) << 4;
  1266.     }
  1267.     if (*++s != '') 
  1268.     {
  1269. *p++ += Unhex( *s );
  1270.     }
  1271. else 
  1272. {
  1273.             if (*s == '?')
  1274.             {
  1275.                 bProcessingOptionsPastQuestionMark = TRUE;
  1276.             }
  1277.     *p++ = *s;
  1278. }
  1279.     }
  1280.     *p = '';
  1281. }
  1282. int
  1283. CHXURL::Unhex(char c)
  1284. {
  1285.     return (c >= '0' && c <= '9' ? c - '0'
  1286.     : c >= 'A' && c <= 'F' ? c - 'A' + 10
  1287.     : c - 'a' + 10 );
  1288. }
  1289. void 
  1290. CHXURL::TestCompressURL()
  1291. {
  1292. #ifdef _DEBUG
  1293.     /* Brad made me do it...:( */
  1294.     char* pTestCompressURL = NULL;
  1295.     BOOL bTestCompress = FALSE;
  1296.     CHXURL url("blah");
  1297.     
  1298.     HX_VERIFY(url.CompressURL("http://blah.real.com/test/../foo.smi", pTestCompressURL) == TRUE &&
  1299.       ::strcmp(pTestCompressURL, "http://blah.real.com/foo.smi") == 0);
  1300.     HX_VECTOR_DELETE(pTestCompressURL);
  1301.     HX_VERIFY(url.CompressURL("http://blah.real.com/test/foo.smi?foo/../.", pTestCompressURL) == FALSE);
  1302.     HX_VECTOR_DELETE(pTestCompressURL);
  1303.     HX_VERIFY(url.CompressURL("http://blah.real.com/test/./foo.smi", pTestCompressURL) == TRUE &&
  1304.       ::strcmp(pTestCompressURL, "http://blah.real.com/test/foo.smi") == 0);
  1305.     HX_VECTOR_DELETE(pTestCompressURL);
  1306.     HX_VERIFY(url.CompressURL("http://blah.real.com/test/.blah/foo.smi", pTestCompressURL) == FALSE);
  1307.     HX_VECTOR_DELETE(pTestCompressURL);
  1308.     HX_VERIFY(url.CompressURL("http://blah.real.com/test/..foo.smi", pTestCompressURL) == FALSE);
  1309.     HX_VECTOR_DELETE(pTestCompressURL);
  1310.     HX_VERIFY(url.CompressURL("rtsp://blah.real.com/test/blah/../../foo.smi?end=./../blah", pTestCompressURL)  == TRUE &&
  1311.       ::strcmp(pTestCompressURL, "rtsp://blah.real.com/foo.smi?end=./../blah") == 0);
  1312.     HX_VECTOR_DELETE(pTestCompressURL);
  1313. #endif
  1314. }
  1315. IHXCommonClassFactory* CHXURL::CreateCCF()
  1316. {
  1317.     return  new CHXMiniCCF();
  1318. }