rtsppars.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:22k
源码类别:

Symbian

开发平台:

C/C++

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