rtsppars.cpp
Upload User: dangjiwu
Upload Date: 2013-07-19
Package Size: 42019k
Code Size: 23k
Category:

Symbian

Development Platform:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: rtsppars.cpp,v 1.9.30.1 2004/07/09 02:04:52 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/stdlib.h"
  50. //#include "hlxclib/stdio.h"
  51. #include "hxcom.h"
  52. #include "hxtypes.h"
  53. #include "hxassert.h"
  54. #include "debug.h"
  55. #include "hxstrutl.h"
  56. #include "hxstring.h"
  57. #include "hxslist.h"
  58. #include "mimehead.h"
  59. #include "rtsppars.h"
  60. #include "smpte.h"
  61. #include "nptime.h"
  62. #include "rtspmsg.h"
  63. #include "chxpckts.h"
  64. #include "hxauth.h"
  65. #include "hxheap.h"
  66. #ifdef _DEBUG
  67. #undef HX_THIS_FILE
  68. static const char HX_THIS_FILE[] = __FILE__;
  69. #endif
  70. RTSPParser::RTSPParser()
  71. {
  72. }
  73. RTSPParser::~RTSPParser()
  74. {
  75.     clearMessageLines();
  76. }
  77. /*
  78.  * Extract major/minor version info
  79.  */
  80. int 
  81. RTSPParser::parseProtocolVersion(const CHXString& prot,
  82.     int& majorVersion, int& minorVersion)
  83. {
  84.     if(strncasecmp(prot, "RTSP/", 5) != 0)
  85.      return 0;
  86.     int nVerOffset = prot.Find('.');
  87.     if(nVerOffset > 5)
  88.     {
  89. CHXString majVersion = prot.Mid(5, nVerOffset-5);
  90. majorVersion = (int)strtol(majVersion, 0, 10);
  91. CHXString minVersion = prot.Mid(nVerOffset+1);
  92. minorVersion = (int)strtol(minVersion, 0, 10);
  93. return 1;
  94.     }
  95.     return 0;
  96. }
  97. /*
  98.  * Parse option in form 'value *[;name[=value]]'
  99.  */
  100. int 
  101. RTSPParser::parseHeaderValue(const char* pValue, MIMEHeader* pHeader)
  102. {
  103.     if(strlen(pValue) == 0)
  104. return 0;
  105.     MIMEInputStream input(pValue, strlen(pValue));
  106.     MIMEScanner scanner(input);
  107.     MIMEHeaderValue* pHeaderValue = 0;
  108.     MIMEToken tok = scanner.nextToken(";=");
  109.     while(tok.hasValue())
  110.     {
  111. if(!pHeaderValue)
  112. {
  113.     CHXString attribute = tok.value();
  114.     pHeaderValue = new MIMEHeaderValue;
  115.     if(!pHeaderValue)
  116.     {
  117.         return 0;
  118.     }
  119.     if(tok.lastChar() == '=')
  120.     {
  121. tok = scanner.nextToken(";");
  122. CHXString value = tok.value();
  123. pHeaderValue->addParameter(attribute, value);
  124.     }
  125.     else
  126.     {
  127. pHeaderValue->addParameter(attribute);
  128.     }
  129. }
  130. else if(tok.lastChar() == '=')
  131. {
  132.     CHXString attribute = tok.value();
  133.     tok = scanner.nextToken(";");
  134.     CHXString value = tok.value();
  135.     pHeaderValue->addParameter(attribute, value);
  136. }
  137. else
  138. {
  139.     CHXString attribute = tok.value();
  140.     pHeaderValue->addParameter(attribute, "");
  141. }
  142. tok = scanner.nextToken("=;");
  143.     }
  144.     if(pHeaderValue)
  145. pHeader->addHeaderValue(pHeaderValue);
  146.     return 0;
  147. }
  148. int
  149. RTSPParser::parseRangeValue(const char* pValue, MIMEHeader* pHeader)
  150. {
  151.     MIMEInputStream input(pValue, strlen(pValue));
  152.     MIMEScanner scanner(input);
  153.     MIMEToken nextTok = scanner.nextToken("=");
  154.     if(strcasecmp(nextTok.value(), "smpte") == 0)
  155.     {
  156. UINT32 tBegin = RTSP_PLAY_RANGE_BLANK;
  157. UINT32 tEnd = RTSP_PLAY_RANGE_BLANK;
  158. nextTok = scanner.nextToken("-");
  159. if(nextTok.hasValue())
  160. {
  161.     SMPTETimeCode tCode1(nextTok.value());
  162.     tBegin = UINT32(tCode1);
  163. }
  164. if((nextTok.lastChar() != MIMEToken::T_EOL) ||
  165.    (nextTok.lastChar() != MIMEToken::T_EOF))
  166. {
  167.     nextTok = scanner.nextToken("n");
  168.     if(nextTok.hasValue())
  169.     {
  170. SMPTETimeCode tCode2(nextTok.value());
  171. tEnd = UINT32(tCode2);
  172.     }
  173. }
  174. pHeader->addHeaderValue(new RTSPRange(tBegin, tEnd,
  175.     RTSPRange::TR_SMPTE));
  176.     }
  177.     else if(strcasecmp(nextTok.value(), "npt") == 0)
  178.     {
  179. UINT32 tBegin = RTSP_PLAY_RANGE_BLANK;
  180. UINT32 tEnd = RTSP_PLAY_RANGE_BLANK;
  181. nextTok = scanner.nextToken("-");
  182. if(nextTok.hasValue())
  183. {
  184.     NPTime t1(nextTok.value());
  185.     tBegin = UINT32(t1);
  186. }
  187. if((nextTok.lastChar() != MIMEToken::T_EOL) ||
  188.    (nextTok.lastChar() != MIMEToken::T_EOF))
  189. {
  190.     nextTok = scanner.nextToken("n");
  191.     if(nextTok.hasValue())
  192.     {
  193. NPTime t2(nextTok.value());
  194. tEnd = UINT32(t2);
  195.     }
  196. }
  197. pHeader->addHeaderValue(new RTSPRange(tBegin, tEnd,
  198.     RTSPRange::TR_NPT));
  199.     }
  200.     else if(strcasecmp(nextTok.value(), "clock") == 0)
  201.     {
  202. //XXXBAB fill this in
  203.     }
  204.     return 0;
  205. }
  206. int
  207. RTSPParser::parseAuthenticationValue(const char* pValue, MIMEHeader* pHeader)
  208. {
  209.     MIMEInputStream input(pValue, strlen(pValue));
  210.     MIMEScanner scanner(input);
  211.     MIMEToken nextTok = scanner.nextToken(" ");
  212.     if(strcasecmp(nextTok.value(), "HXPrivate") == 0)
  213.     {
  214. nextTok = scanner.nextToken("=");
  215. if(strcasecmp(nextTok.value(), "nonce") == 0)
  216. {
  217.     nextTok = scanner.nextToken();
  218.     pHeader->addHeaderValue(new RTSPAuthentication(nextTok.value(),
  219. RTSPAuthentication::AU_HX_PRIVATE));
  220. }
  221.     }
  222.     return 0;
  223. }
  224. int
  225. RTSPParser::parsePEPInfoHeaderValues(const char* pValue, MIMEHeader* pHeader)
  226. {
  227.     MIMEInputStream input(pValue, strlen(pValue));
  228.     MIMEScanner scanner(input);
  229.     BOOL bStrengthMust = FALSE;
  230.     MIMEToken nextTok = scanner.nextToken(" {}");
  231.     while(nextTok.lastChar() != MIMEToken::T_EOF)
  232.     {
  233. if(strcasecmp(nextTok.value(), "strength") == 0)
  234. {
  235.     nextTok = scanner.nextToken(" }");
  236.     if(strcasecmp(nextTok.value(), "must") == 0)
  237.     {
  238. bStrengthMust = TRUE;
  239. break;
  240.     }
  241. }
  242. nextTok = scanner.nextToken(" {}");
  243.     }
  244.     pHeader->addHeaderValue(new RTSPPEPInfo(bStrengthMust));
  245.     return 0;
  246. }
  247. int
  248. RTSPParser::parseRTPInfoHeaderValues(const char* pValue, MIMEHeader* pHeader)
  249. {
  250.     // There is a bug in RFC2326 related to the ambiguity of "url=" parameter in
  251.     // RTP-Info. More details can be found at:
  252.     // http://sourceforge.net/tracker/index.php?func=detail&group_id=23194&atid=377744&aid=448521
  253.     //
  254.     // For now, we only can do the best we can:
  255.     // 1. find stream URL entry based on ",url="
  256.     // 2. read "url", "seq" and "rtptime" within the stream URL entry
  257.     if (!pValue || 0 == strlen(pValue))
  258.     {
  259.         return 0;
  260.     }
  261.     const char* pCurrentEntry = NULL;
  262.     const char* pNextEntry = NULL;
  263.     CHXString   value = pValue;
  264.     CHXString   entry;
  265.     pCurrentEntry = strstr(pValue, "url=");
  266.     // RTP-Info starts with "url="
  267.     HX_ASSERT(pCurrentEntry == pValue);
  268.     while (pNextEntry = NextRTPInfoEntry(pCurrentEntry+4, "url=", ','))
  269.     {
  270.         // retreive stream URL entry
  271.         entry = value.Mid(pCurrentEntry - pValue, pNextEntry - pCurrentEntry);
  272.         // retrieve "url", "seq" and "rtptime"
  273.         SetRTPInfoEntry(entry, pHeader);
  274.         
  275.         pCurrentEntry = pNextEntry;
  276.     }
  277.     entry = value.Mid(pCurrentEntry - pValue);
  278.     SetRTPInfoEntry(entry, pHeader);
  279.     return 0;
  280. }
  281. const char*
  282. RTSPParser::NextRTPInfoEntry(const char* pValue, const char* pTarget, const char cDelimiter)
  283. {
  284.     const char* pEntry = NULL;
  285.     while (pEntry = strstr(pValue, pTarget))
  286.     {
  287.         const char* pTemp = pEntry;
  288.         // a valid entry should begin with:
  289.         // ",url=" OR ", url="
  290.         // rewind and skip all the spaces in between
  291.         while (*(--pTemp) == ' ') {}
  292.         // the first non-space character should be the delimiter
  293.         if (*pTemp == cDelimiter)
  294.         {
  295.             break;
  296.         }
  297.         // not valid entry, keep looking 
  298.         else
  299.         {
  300.             pValue = pEntry + strlen(pTarget);
  301.         }
  302.     }
  303.     return pEntry;
  304. }
  305. int 
  306. RTSPParser::ReadRTPInfoEntry(CHXString      in, 
  307.                              INT32          i,
  308.                              INT32          length,
  309.                              CHXString&     out)
  310. {
  311.     UINT32 ulLength = 0;
  312.     CHXString temp;
  313.     if (length > 0)
  314.     {
  315.         temp = in.Mid(i, length);
  316.     }
  317.     else
  318.     {
  319.         temp = in.Mid(i);
  320.     }
  321.     temp.TrimLeft();
  322.     temp.TrimRight();
  323.     ulLength = temp.GetLength();
  324.     // remove trailing ',' or ';' in case there is any
  325.     if (temp[ulLength-1] == ',' || temp[ulLength-1] == ';')
  326.     {
  327.         out = temp.Mid(0, ulLength-1);
  328.         out.TrimRight();
  329.     }
  330.     else
  331.     {
  332.         out = temp;
  333.     }
  334.     return 0;
  335. }
  336. int
  337. RTSPParser::SetRTPInfoEntry(CHXString in, MIMEHeader* pHeader)
  338. {
  339.     INT32 lURL = -1, lSeq = -1, lRTPTime = -1;
  340.     CHXString URLValue, SeqValue, RTPTimeValue;
  341.     MIMEHeaderValue* pHeaderValue = new MIMEHeaderValue;
  342.     const char* pIn = (const char*)in;    
  343.     const char* pSeq = NextRTPInfoEntry(pIn, "seq=", ';');
  344.     const char* pRTPTime = NextRTPInfoEntry(pIn, "rtptime=", ';');
  345.     lURL = in.Find("url=");
  346.     HX_ASSERT(lURL == 0);
  347.     if (pSeq)
  348.     {
  349.         lSeq = pSeq - pIn;
  350.     }
  351.     if (pRTPTime)
  352.     {
  353.         lRTPTime = pRTPTime - pIn;
  354.     }
  355.     // both seq and rtptime are present
  356.     if (lSeq > 0 && lRTPTime > 0)
  357.     {
  358.         // url;seq;rtptime
  359.         if (lRTPTime > lSeq)
  360.         {
  361.             ReadRTPInfoEntry(in, lURL+4, lSeq-lURL-5, URLValue);
  362.             ReadRTPInfoEntry(in, lSeq+4, lRTPTime-lSeq-5, SeqValue);
  363.             ReadRTPInfoEntry(in, lRTPTime+8, -1, RTPTimeValue);
  364.         }
  365.         // url;rtptime;seq
  366.         else
  367.         {
  368.             ReadRTPInfoEntry(in, lURL+4, lRTPTime-lURL-5, URLValue);
  369.             ReadRTPInfoEntry(in, lRTPTime+8, lSeq-lRTPTime-9, RTPTimeValue);
  370.             ReadRTPInfoEntry(in, lSeq+4, -1, SeqValue);
  371.         }
  372.     }
  373.     // url;seq
  374.     else if (lSeq > 0)
  375.     {
  376.         ReadRTPInfoEntry(in, lURL+4, lSeq-lURL-5, URLValue);
  377.         ReadRTPInfoEntry(in, lSeq+4, -1, SeqValue);
  378.     }
  379.     // url;rtptime
  380.     else if (lRTPTime > 0)
  381.     {
  382.         ReadRTPInfoEntry(in, lURL+4, lRTPTime-lURL-5, URLValue);
  383.         ReadRTPInfoEntry(in, lRTPTime+8, -1, RTPTimeValue);
  384.     }
  385.     // invalid case, either seq or rtptime has to be present
  386.     else
  387.     {
  388.         HX_ASSERT(FALSE);
  389.     }
  390.     if (!URLValue.IsEmpty())
  391.     {
  392.         pHeaderValue->addParameter("url", URLValue);
  393.     }
  394.     if (!SeqValue.IsEmpty())
  395.     {
  396.         pHeaderValue->addParameter("seq", SeqValue);
  397.     }
  398.     if (!RTPTimeValue.IsEmpty())
  399.     {
  400.         pHeaderValue->addParameter("rtptime", RTPTimeValue);
  401.     }
  402.     pHeader->addHeaderValue(pHeaderValue);
  403.     return 0;
  404. }
  405. int
  406. RTSPParser::parseBackChannelValue(const char* pValue, MIMEHeader* pHeader)
  407. {
  408.     MIMEInputStream input(pValue, strlen(pValue));
  409.     MIMEScanner scanner(input);
  410.     MIMEToken nextTok = scanner.nextToken();
  411.     pHeader->addHeaderValue(new MIMEHeaderValue(nextTok.value()));
  412.     return 0;
  413. }
  414. int
  415. RTSPParser::parseAlertValue(const char* pValue, MIMEHeader* pHeader)
  416. {
  417.     MIMEInputStream input(pValue, strlen(pValue));
  418.     MIMEScanner scanner(input);
  419.     MIMEToken nextTok;
  420.     MIMEHeaderValue* pHeaderValue = new MIMEHeaderValue;
  421.     // Parse Alert number
  422.     nextTok = scanner.nextToken(";");
  423.     if (nextTok.hasValue())
  424.     {
  425. pHeaderValue->addParameter(nextTok.value(), "");
  426.     }
  427.     // Parse Alert text
  428.     nextTok = scanner.nextToken("");
  429.     if (nextTok.hasValue())
  430.     {
  431. pHeaderValue->addParameter(nextTok.value(), "");
  432.     }
  433.     pHeader->addHeaderValue(pHeaderValue);
  434.     return 0;
  435. }
  436. /*
  437.  * Parse header values as list of comma separated values
  438.  */
  439. int 
  440. RTSPParser::defaultParseHeaderValues(const char* pValue, MIMEHeader* pHeader)
  441. {
  442.     MIMEInputStream input(pValue, strlen(pValue));
  443.     MIMEScanner scanner(input);
  444.     
  445.     MIMEToken nextTok = scanner.nextToken(",");
  446.     while(nextTok.hasValue())
  447.     {
  448. parseHeaderValue(nextTok.value(), pHeader);
  449. if((nextTok.lastChar() == MIMEToken::T_EOL) ||
  450.    (nextTok.lastChar() == MIMEToken::T_EOF))
  451.     return 0;
  452. nextTok = scanner.nextToken(",");
  453.     }
  454.     return 0;
  455. }
  456. int
  457. RTSPParser::parseWWWAuthenticateHeaderValues(const char* pValue, 
  458.      MIMEHeader* pHeader)
  459. {
  460. /*
  461.  * Not needed anymore, authentication model has changed
  462.  * 
  463.  */
  464.     return 0;
  465. }
  466. int
  467. RTSPParser::parseDigestAuthorizationHeaderValues(const char* pValue,
  468.  MIMEHeader* pHeader)
  469. {
  470. /*
  471.  * Not needed anymore, authentication model has changed
  472.  * 
  473.  */
  474.     return 0;
  475. }
  476. /*
  477.  * construct a MIMEHeader and add header values to it
  478.  * format: 'HeaderName: option, option=value;option=value, option'
  479.  */
  480. MIMEHeader* 
  481. RTSPParser::parseHeader(CHXString& str)
  482. {
  483.     MIMEHeader* pHeader = 0;
  484.     MIMEInputStream input(str);
  485.     MIMEScanner scanner(input);
  486.     MIMEToken nextTok = scanner.nextToken(":");
  487.     if(nextTok.hasValue())
  488.     {
  489. pHeader = new MIMEHeader(nextTok.value());
  490. nextTok = scanner.nextToken("n");
  491. if(strcasecmp(pHeader->name(), "Range") == 0)
  492. {
  493.     parseRangeValue(nextTok.value(), pHeader);
  494. }
  495. else if
  496. (
  497.     (strcasecmp(pHeader->name(), "WWW-Authenticate") == 0)
  498.     ||
  499.     (strcasecmp(pHeader->name(), "Authenticate") == 0)
  500.     ||
  501.     (strcasecmp(pHeader->name(), "Authorization") == 0)
  502.     ||
  503.     // XXX HP get the absolute redirect URL which could 
  504.     // contain ',' and would be treated as field separater
  505.     // in defaultParseHeaderValues()
  506.     (strcasecmp(pHeader->name(), "Location") == 0)
  507.             ||
  508.             (strcasecmp(pHeader->name(), "Content-base") == 0)
  509. )
  510. {
  511.     MIMEHeaderValue* pHeaderValue = new MIMEHeaderValue;
  512.     if(pHeaderValue)
  513.     {
  514. pHeaderValue->addParameter(nextTok.value());
  515. pHeader->addHeaderValue(pHeaderValue);
  516.     }
  517. }
  518. else if((strcasecmp(pHeader->name(), "PEP-Info") == 0) ||
  519.         (strcasecmp(pHeader->name(), "C-PEP-Info") == 0))
  520. {
  521.     parsePEPInfoHeaderValues(nextTok.value(), pHeader);
  522. }
  523.         else if(strcasecmp(pHeader->name(), "RTP-Info") == 0)
  524.         {
  525.             parseRTPInfoHeaderValues(nextTok.value(), pHeader);
  526.         }
  527. else if(strcasecmp(pHeader->name(), "BackChannel") == 0)
  528. {
  529.     parseBackChannelValue(nextTok.value(), pHeader);
  530. }
  531. else if(strcasecmp(pHeader->name(), "Alert") == 0)
  532. {
  533.     parseAlertValue(nextTok.value(), pHeader);
  534. }
  535. else
  536. {
  537.     defaultParseHeaderValues(nextTok.value(), pHeader);
  538. }
  539.     }
  540.     return pHeader;
  541. }
  542. /*
  543.  * Parse request line in format 'METHOD URL VERSION SEQ_NO'
  544.  */
  545. RTSPRequestMessage*
  546. RTSPParser::parseRequestLine(CHXString& str)
  547. {
  548.     int majorVersion, minorVersion;
  549.     RTSPRequestMessage* pReqMsg = 0;
  550.     MIMEInputStream input(str);
  551.     MIMEScanner scanner(input);
  552.     // build message
  553.     MIMEToken nextTok = scanner.nextToken();
  554.     const char* pMsgName = nextTok.value();
  555.     if(strcasecmp(pMsgName, "SETUP") == 0)
  556.     {
  557. pReqMsg = new RTSPSetupMessage;
  558.     }
  559.     else if(strcasecmp(pMsgName, "REDIRECT") == 0)
  560.     {
  561. pReqMsg = new RTSPRedirectMessage;
  562.     }
  563.     else if(strcasecmp(pMsgName, "PLAY") == 0)
  564.     {
  565. pReqMsg = new RTSPPlayMessage;
  566.     }
  567.     else if(strcasecmp(pMsgName, "PAUSE") == 0)
  568.     {
  569. pReqMsg = new RTSPPauseMessage;
  570.     }
  571.     else if(strcasecmp(pMsgName, "SET_PARAMETER") == 0)
  572.     {
  573. pReqMsg = new RTSPSetParamMessage;
  574.     }
  575.     else if(strcasecmp(pMsgName, "GET_PARAMETER") == 0)
  576.     {
  577. pReqMsg = new RTSPGetParamMessage;
  578.     }
  579.     else if(strcasecmp(pMsgName, "TEARDOWN") == 0)
  580.     {
  581. pReqMsg = new RTSPTeardownMessage;
  582.     }
  583.     else if(strcasecmp(pMsgName, "DESCRIBE") == 0)
  584.     {
  585. pReqMsg = new RTSPDescribeMessage;
  586.     }
  587.     else if(strcasecmp(pMsgName, "OPTIONS") == 0)
  588.     {
  589. pReqMsg = new RTSPOptionsMessage;
  590.     }
  591.     else if(strcasecmp(pMsgName, "RECORD") == 0)
  592.     {
  593. pReqMsg = new RTSPRecordMessage;
  594.     }
  595.     else if(strcasecmp(pMsgName, "ANNOUNCE") == 0)
  596.     {
  597. pReqMsg = new RTSPAnnounceMessage;
  598.     }
  599.     else
  600.     {
  601. pReqMsg = new RTSPUnknownMessage;
  602.     }
  603.     // get URL
  604.     nextTok = scanner.nextToken(" ");
  605.     pReqMsg->setURL(nextTok.value());
  606.     // get version info
  607.     nextTok = scanner.nextToken();
  608.     if(parseProtocolVersion(nextTok.value(), majorVersion, minorVersion))
  609.     {
  610. pReqMsg->setVersion(majorVersion, minorVersion);
  611.     }
  612.     else
  613.     {
  614. pReqMsg->setVersion(0,0); // indicate bad version
  615.     }
  616.     
  617.     return pReqMsg;
  618. }
  619. /*
  620.  * Parse response line in format 'VERSION ERR_CODE SEQ_NO ERR_MSG'
  621.  */
  622. RTSPResponseMessage*
  623. RTSPParser::parseResponseLine(CHXString& str)
  624. {
  625.     int majorVersion, minorVersion;
  626.     RTSPResponseMessage* pRespMsg = 0;
  627.     MIMEInputStream input(str);
  628.     MIMEScanner scanner(input);
  629.     MIMEToken nextTok = scanner.nextToken();
  630.     pRespMsg = new RTSPResponseMessage;
  631.     if(parseProtocolVersion(nextTok.value(), 
  632. majorVersion, minorVersion))
  633.     {
  634. pRespMsg->setVersion(majorVersion, minorVersion);
  635.     }
  636.     else
  637.     {
  638. pRespMsg->setVersion(0,0); // indicate bad version
  639.     }
  640.     // get error code
  641.     nextTok = scanner.nextToken();
  642.     pRespMsg->setErrorCode(nextTok.value());
  643.     // get error message
  644.     nextTok = scanner.nextToken("n");
  645.     pRespMsg->setErrorMsg(nextTok.value());
  646.     return pRespMsg;
  647. }
  648. /*
  649.  * Parse response message
  650.  */
  651. RTSPMessage* 
  652. RTSPParser::parseResponse()
  653. {
  654.     RTSPResponseMessage* pRespMsg = 0;
  655.     
  656.     LISTPOSITION pos = m_msglines.GetHeadPosition();
  657.     CHXString* pStr = (CHXString*)m_msglines.GetNext(pos);
  658.     pRespMsg = parseResponseLine(*pStr);
  659.     if(!pRespMsg)
  660. return 0;
  661.     while(pos)
  662.     {
  663. pStr = (CHXString*)m_msglines.GetNext(pos);
  664. MIMEHeader* pHeader = parseHeader(*pStr);
  665. if(pHeader)
  666.     pRespMsg->addHeader(pHeader);
  667.     }
  668.     // get sequence number
  669.     UINT32 seqNo = 0;
  670.     pRespMsg->getHeaderValue("CSeq", seqNo);
  671.     pRespMsg->setSeqNo(seqNo);
  672.     return pRespMsg;
  673. }
  674. /*
  675.  * Parse request message
  676.  */
  677. RTSPMessage* 
  678. RTSPParser::parseRequest()
  679. {
  680.     RTSPRequestMessage* pReqMsg = 0;
  681.     
  682.     LISTPOSITION pos = m_msglines.GetHeadPosition();
  683.     CHXString* pStr = (CHXString*)m_msglines.GetNext(pos);
  684.     pReqMsg = parseRequestLine(*pStr);
  685.     if(!pReqMsg)
  686. return 0;
  687.     while(pos)
  688.     {
  689. pStr = (CHXString*)m_msglines.GetNext(pos);
  690. MIMEHeader* pHeader = parseHeader(*pStr);
  691. if(pHeader)
  692.     pReqMsg->addHeader(pHeader);
  693.     }
  694.     // get sequence number
  695.     UINT32 seqNo = 0;
  696.     pReqMsg->getHeaderValue("CSeq", seqNo);
  697.     pReqMsg->setSeqNo(seqNo);
  698.     return pReqMsg;
  699. }
  700. /*
  701.  * Add each line in message to list m_msglines.
  702.  * Look for two carriage returns to delimit
  703.  * message header.
  704.  */
  705. UINT32 
  706. RTSPParser::scanMessageHeader(const char* pMsg, UINT32 nMsgLen)
  707. {
  708.     // first, get rid of any leading whitespace and <CR><LF> chars
  709.     const char* pCh = pMsg;
  710.     while(*pCh == 'n' || *pCh == 'r' || *pCh == ' ' || *pCh == 't')
  711.     {
  712. pCh++;
  713.     }
  714.     UINT32 offset = pCh - pMsg;
  715.     if(offset > nMsgLen)
  716.     {
  717. return 0;
  718.     }
  719.     MIMEInputStream input(pCh, nMsgLen - offset);
  720.     MIMEScanner scanner(input);
  721.     MIMEToken tok;
  722.     int gotEOL = 0;
  723.     UINT32 scanOffset = 0;
  724.     do
  725.     {
  726. tok = scanner.nextToken("n");
  727. if(tok.lastChar() == MIMEToken::T_EOL)
  728. {
  729.     if(gotEOL && !tok.hasValue())
  730.     {
  731. scanOffset = scanner.offset();
  732. break;
  733.     }
  734.     else
  735.     {
  736. gotEOL = 1;
  737.     }
  738. }
  739. else
  740. {
  741.     gotEOL = 0;
  742. }
  743. m_msglines.AddTail((void*)(new CHXString((const char*)tok.value())));
  744.     } while(tok.lastChar() != MIMEToken::T_EOF);
  745.     if(scanOffset == 0)
  746.     {
  747. return 0;
  748.     }
  749.     else
  750.     {
  751. return scanOffset + offset;
  752.     }
  753. }
  754. /*
  755.  * Parse message pointed to by pMsg with length nMsgLen.
  756.  * If not a complete message, return 0, otherwise return
  757.  * RTSPMessage pointer.
  758.  */
  759. RTSPMessage* 
  760. RTSPParser::parse(const char* pMsg, UINT32& nMsgLen)
  761. {
  762.     RTSPMessage* pRTSPMsg = 0;
  763.     clearMessageLines();
  764.     INT32 msgOffset = scanMessageHeader(pMsg, nMsgLen);
  765.     if(msgOffset > 0)
  766.     {
  767. if(m_msglines.GetCount() == 0)
  768. {
  769.     nMsgLen = 0;
  770.     return 0;
  771. }
  772. CHXString* str = (CHXString*)m_msglines.GetHead();
  773. if(strncasecmp((*str), "RTSP/", 5) == 0)
  774. {
  775.     pRTSPMsg = parseResponse();
  776. }
  777. else 
  778. {
  779.     pRTSPMsg = parseRequest();
  780. }
  781. if(pRTSPMsg)
  782. {
  783.     UINT32 contentLength = 0;
  784.     if(pRTSPMsg->getHeaderValue("Content-length", contentLength))
  785.     {
  786. if((UINT32)msgOffset + contentLength <= (UINT32)nMsgLen)
  787. {
  788.     CHXString content(&pMsg[msgOffset], 
  789.      HX_SAFEUINT(contentLength));
  790.     pRTSPMsg->setContent(content);
  791.     nMsgLen = msgOffset + contentLength;
  792. }
  793. else // content-length not satisfied
  794. {
  795.     // XXXBAB - update nMsglen as number of bytes needed 
  796.     // to complete message
  797.     delete pRTSPMsg;
  798.     pRTSPMsg = 0;
  799.     nMsgLen = 0;
  800. }
  801.     }
  802.     else
  803.     {
  804. nMsgLen = msgOffset;
  805.     }
  806. }
  807.     }
  808.     else
  809.     {
  810. nMsgLen = 0;
  811.     }
  812.     return pRTSPMsg;
  813. }
  814. /*
  815.  * Delete contents of m_msglines
  816.  */
  817. void 
  818. RTSPParser::clearMessageLines()
  819. {
  820.     LISTPOSITION pos = m_msglines.GetHeadPosition();
  821.     while(pos)
  822.     {
  823. CHXString* str = (CHXString*)m_msglines.GetNext(pos);
  824. delete str;
  825.     }
  826.     m_msglines.RemoveAll();
  827. }