blob: 3e340397bbcb6541a3d6a2e9e26e29d8a77e665d [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "rtsp_par_com.h"
#include "oscl_string_utils.h"
#include "rtsp_range_utils.h"
OSCL_EXPORT_REF void
RTSPIncomingMessage::reset()
{
RTSPGenericMessage::reset();
#ifdef RTSP_PLAYLIST_SUPPORT
playlistRangeField.setPtrLen("", 0);
playlistRangeFieldIsSet = false;
// need to figure out how to store all the error fields.. we may not actually need to
playlistErrorFieldIsSet = false;
playlistErrorFieldCount = 0;
for (int ii = 0; ii < RTSP_MAX_NUMBER_OF_PLAYLIST_ERROR_ENTRIES; ++ii)
{
playlistErrorField[ii].setPtrLen("", 0);
}
supportedFieldIsSet = false;
numOfSupportedEntries = 0;
for (int jj = 0; jj < RTSP_MAX_NUMBER_OF_SUPPORTED_ENTRIES; ++jj)
{
supportedField[jj].setPtrLen("", 0);
}
playlistRangeUrl.setPtrLen("", 0);
playlistRangeClipIndex = 0;
playlistRangeClipOffset = 0;
playlistRangeNptTime = 0;
#endif
amMalformed = RTSPOk;
rtspVersionString = "";
}
void
RTSPIncomingMessage::parseFirstFields()
{
char * endOfString;
// The first thing to do is to parse the status line;
// the rest of the parsing (regular fields) can be parsed out by
// parseNextPortion() method, since it has to know how to do that anyway.
// We also have to find out if Content-length is there, etc.
// so, let's set up the pointers first
//
secondaryBufferSpace = secondaryBuffer;
if (CHAR_CR == *secondaryBufferSpace)
{
++secondaryBufferSpace;
}
if (CHAR_LF == *secondaryBufferSpace)
{
++secondaryBufferSpace;
}
#ifdef SIMPLE_HTTP_SUPPORT
if (secondaryBufferSizeUsed >= 4)
{// Real http cloaking. H\02\00\00
if (('H' != secondaryBufferSpace[0])
|| ('T' != secondaryBufferSpace[1])
|| ('T' != secondaryBufferSpace[2])
|| ('P' != secondaryBufferSpace[3])
)
{
if ('H' == secondaryBufferSpace[0])
{//HTTP_RESPONSE
uint32 nOptionLen = secondaryBufferSpace[1];
secondaryBufferSpace += (2 + nOptionLen);
}
/* TBD
else if('r' == secondaryBufferSpace[0])
{//HTTP_RV_RESPONSE
}
*/
}
}
#endif
numPtrFields = 0;
char * wordPtr[3] = { NULL, NULL, NULL };
char * endOfLine;
int wordCount;
bool wordCountTrigger;
for (endOfLine = secondaryBufferSpace, wordCount = 0, wordCountTrigger = true;
(endOfLine < secondaryBufferSpace + secondaryBufferSizeUsed)
&& (CHAR_CR != *endOfLine)
&& (CHAR_LF != *endOfLine);
++endOfLine
)
{
switch (wordCountTrigger)
{
case true: // if non-space, then it's a beginning of a new word
{
if ((*endOfLine >= 0x09 && *endOfLine <= 0x0D) || *endOfLine == 0x20)
{ // spaces
}
else
{ // word
if (3 > wordCount)
{
wordPtr[wordCount] = endOfLine;
}
++wordCount;
// uncock the trigger
wordCountTrigger = false;
}
break;
}
case false: // if space, then cock the trigger
{
if ((*endOfLine >= 0x09 && *endOfLine <= 0x0D) || *endOfLine == 0x20)
{ // yeah, space
wordCountTrigger = true;
}
else
{ // still a word
}
break;
}
default:
// ERROR: internal inconsistency, a switch on a boolean should not hit
// this point
;;
}
}
if (3 > wordCount)
{ // only two words in the status line - error
amMalformed = RTSPErrorSyntax;
return;
}
if (CHAR_CR == *endOfLine)
{
*(endOfLine++) = CHAR_NULL;
if (CHAR_LF == *endOfLine)
{
*(endOfLine++) = CHAR_NULL;
}
}
else if (CHAR_LF == *endOfLine)
{
*(endOfLine++) = CHAR_NULL;
}
else
{
// ran to the end of input, didn't find a single newline....
// most probably the message was too big to handle, but parser still
// created a message hoping that at least something can be found...
//
amMalformed = RTSPErrorSyntax;
return;
}
// figure out the format of the message - request or response?
//
// make out the first word... don't forget about '$'
//
//// endOfString = secondaryBufferSpace;
//// while( ! isspace(*endOfString) )
//// ++endOfString;
endOfString = wordPtr[1];
while (--endOfString >= secondaryBufferSpace
&& ((*endOfString >= 0x09 && *endOfString <= 0x0D) || *endOfString == 0x20)
)
{
*endOfString = CHAR_NULL;
}
//// *endOfString = CHAR_NULL;
//// StrCSumPtrLen firstWordPLSS = secondaryBufferSpace;
StrCSumPtrLen firstWordPLSS = wordPtr[0];
if (('R' == *(wordPtr[0]))
&& ('T' == *(wordPtr[0] + 1))
&& ('S' == *(wordPtr[0] + 2))
&& ('P' == *(wordPtr[0] + 3))
&& ('/' == *(wordPtr[0] + 4))
)
{
// it has to be a response
//
msgType = RTSPResponseMsg;
rtspVersionString = firstWordPLSS;
// if there is a mismatch, let the Engine know about it and stop parsing
if (rtspVersionString != RTSPVersionString)
{
amMalformed = RTSPErrorVersion;
return;
}
// get the code
//// secondaryBufferSpace = endOfString+1;
//// while( isspace(*secondaryBufferSpace) )
//// {
//// ++secondaryBufferSpace;
//// }
//// statusCode = atoi( secondaryBufferSpace );
uint32 atoi_tmp;
PV_atoi(wordPtr[1], 'd', atoi_tmp);
statusCode = (RTSPStatusCode)atoi_tmp;
// get the reason string
//// while( ! isspace( *secondaryBufferSpace ) )
//// {
//// ++secondaryBufferSpace;
//// }
//// while( isspace( *secondaryBufferSpace ) )
//// {
//// ++secondaryBufferSpace;
//// }
//// endOfString = secondaryBufferSpace;
//// while( (CHAR_CR != *endOfString)
//// && (CHAR_LF != *endOfString)
//// )
//// {
//// ++endOfString;
//// }
//// *endOfString = CHAR_NULL;
//// reasonString = secondaryBufferSpace;
reasonString = wordPtr[2];
// now, resync to the next line
//// secondaryBufferSpace = endOfString+1;
//// if( CHAR_LF == *secondaryBufferSpace )
//// {
//// ++secondaryBufferSpace;
//// }
secondaryBufferSpace = endOfLine;
}
#ifdef SIMPLE_HTTP_SUPPORT
else if (('H' == *(wordPtr[0]))
&& ('T' == *(wordPtr[0] + 1))
&& ('T' == *(wordPtr[0] + 2))
&& ('P' == *(wordPtr[0] + 3))
&& ('/' == *(wordPtr[0] + 4))
)
{
msgType = RTSPResponseMsg;
rtspVersionString = firstWordPLSS;
// if there is a mismatch, let the Engine know about it and stop parsing
if ((rtspVersionString != HTTPVersion_1_0_String)
&& (rtspVersionString != HTTPVersion_1_1_String))
{
amMalformed = RTSPErrorVersion;
return;
}
uint32 atoi_tmp;
PV_atoi(wordPtr[1], 'd', atoi_tmp);
statusCode = (RTSPStatusCode)atoi_tmp;
reasonString = wordPtr[2];
secondaryBufferSpace = endOfLine;
}
#endif
else
{ // okay, it could be a request
// but for requests there must be exactly three words on the
// status line
if (3 != wordCount)
{
amMalformed = RTSPErrorSyntax;
return;
}
msgType = RTSPRequestMsg;
methodString = firstWordPLSS;
if (firstWordPLSS == RtspRequestMethodStringDescribe)
{
method = METHOD_DESCRIBE;
}
else if (firstWordPLSS == RtspRequestMethodStringGetParameter)
{
method = METHOD_GET_PARAMETER;
}
else if (firstWordPLSS == RtspRequestMethodStringOptions)
{
method = METHOD_OPTIONS;
}
else if (firstWordPLSS == RtspRequestMethodStringPause)
{
method = METHOD_PAUSE;
}
else if (firstWordPLSS == RtspRequestMethodStringPlay)
{
method = METHOD_PLAY;
}
else if (firstWordPLSS == RtspRequestMethodStringSetup)
{
method = METHOD_SETUP;
}
else if (firstWordPLSS == RtspRequestMethodStringRecord)
{
method = METHOD_RECORD;
}
else if (firstWordPLSS == RtspRequestMethodStringTeardown)
{
method = METHOD_TEARDOWN;
}
else if (firstWordPLSS == RtspRequestMethodStringEndOfStream)
{
method = METHOD_END_OF_STREAM;
}
/* TBD: add Announce, SetParameter and Redirect later
else if( firstWordPLSS == RtspRequestMethodStringAnnounce )
{
method = METHOD_ANNOUNCE;
}
*/
else if (firstWordPLSS == RtspRequestMethodStringSetParameter)
{
method = METHOD_SET_PARAMETER;
}
else if (firstWordPLSS == RtspRequestMethodStringRedirect) //SS
{
method = METHOD_REDIRECT; ////SS
}
// now, we could put binary data here, but it's not exactly the same
// thing; since it requires special care, let's not confuse things by
// putting generic-looking stuff here
else
{
method = METHOD_UNRECOGNIZED;
}
// get the URI
//// secondaryBufferSpace = endOfString +1;
//// while( isspace( *secondaryBufferSpace ) )
//// {
//// ++secondaryBufferSpace;
//// }
//// endOfString = secondaryBufferSpace;
//// while( ! isspace( *endOfString ) )
//// {
//// ++endOfString;
//// }
//// *endOfString = CHAR_NULL;
//// originalURI = secondaryBufferSpace;
endOfString = wordPtr[2];
while ((--endOfString) >= wordPtr[1]
&& ((*endOfString >= 0x09 && *endOfString <= 0x0D) || *endOfString == 0x20)
)
{
*endOfString = CHAR_NULL;
}
originalURI = wordPtr[1];
// get the RTSP version
//// secondaryBufferSpace = endOfString +1;
//// while( isspace( *secondaryBufferSpace ) )
//// {
//// ++secondaryBufferSpace;
//// }
//// endOfString = secondaryBufferSpace;
//// while( !isspace(*endOfString) )
//// {
//// ++endOfString;
//// }
//// *endOfString = CHAR_NULL;
//// rtspVersionString = secondaryBufferSpace;
endOfString = endOfLine;
while (--endOfString >= wordPtr[2]
&& (((*endOfString >= 0x09 && *endOfString <= 0x0D) || *endOfString == 0x20)
|| CHAR_NULL == *endOfString
)
)
{
*endOfString = CHAR_NULL;
}
rtspVersionString = wordPtr[2];
// if there is a mismatch, let the Engine know about it and stop parsing
if (rtspVersionString != RTSPVersionString)
{
amMalformed = RTSPErrorVersion;
return;
}
// now, resync to the next line
//// secondaryBufferSpace = endOfString + 1;
//// if( CHAR_LF == *secondaryBufferSpace )
//// {
//// ++secondaryBufferSpace;
//// }
secondaryBufferSpace = endOfLine;
// extra URI validation
{
if (1 == originalURI.length())
{ // Is it a star
if (CHAR_STAR != originalURI.c_str()[0])
{
amMalformed = RTSPErrorSyntax;
return;
}
}
else
{ // it's a normal URI
// let's validate the scheme
char colonStr[2];
colonStr[0] = CHAR_COLON;
colonStr[1] = NULL_TERM_CHAR;
const char * colonPtr = oscl_strstr(originalURI.c_str(), colonStr);
if (NULL == colonPtr)
{
// no colon
amMalformed = RTSPErrorSyntax;
return;
}
// now, the first character of the scheme is a character
const char * ptr = originalURI.c_str();
if (!((*ptr >= 'A' && *ptr <= 'Z') || (*ptr >= 'a' && *ptr <= 'z')))
{
// the URI doesn't start with a character
amMalformed = RTSPErrorSyntax;
return;
}
// the rest of the characters must be either characters, or
// plus/minus, or dots...
for (++ptr; ptr < colonPtr; ++ptr)
{
if (!(((*ptr >= 'A' && *ptr <= 'Z') || (*ptr >= 'a' && *ptr <= 'z'))
|| (*ptr >= '0' || *ptr <= '9')
|| CHAR_PLUS == *ptr
|| CHAR_MINUS == *ptr
|| CHAR_DOT == *ptr
))
{
amMalformed = RTSPErrorSyntax;
return;
}
}
}
}
// finish off the URI processing
{
// look for the base
uint32 ii;
int32 ee;
uint32 length = originalURI.length();
for (ii = 0; ii < length; ++ii)
{
if (CHAR_SLASH == originalURI.c_str()[ii])
{
if (CHAR_SLASH != originalURI.c_str()[++ii])
{
break;
}
else
{ // no, it's a separator, skip over it, continue
}
}
}
originalURIBase = originalURI.c_str() + ii;
// look for the control candidate
for (ee = originalURIBase.length() - 1;
ee >= 0;
--ee
)
{
if ((CHAR_SLASH == originalURIBase.c_str()[ee])
|| (CHAR_SEMICOLON == originalURIBase.c_str()[ee])
)
{
break;
}
}
originalURIControlCandidate = originalURIBase.c_str() + ee + 1;
}
}
// determine the total number of fields remaining to be seen
endOfString = secondaryBuffer + secondaryBufferSizeUsed;
*(--endOfString) = CHAR_NULL;
--secondaryBufferSizeUsed;
if (CHAR_CR == *(endOfString - 1))
{
*(--endOfString) = CHAR_NULL;
--secondaryBufferSizeUsed;
}
totalFields = 0;
for (char * ptr = secondaryBufferSpace; ptr < endOfString; ++ptr)
{
if (CHAR_LF == *ptr)
{
++totalFields;
}
else if (CHAR_CR == *ptr)
{
if (CHAR_LF != *(ptr + 1))
{
++totalFields;
}
}
}
totalFieldsParsed = 0;
parseNextPortion();
if (getTotalFields() != getTotalFieldsParsed())
{
amMalformed = RTSPErrorTooManyFields;
}
}
bool
RTSPIncomingMessage::parseNextPortion()
{
if (totalFieldsParsed == totalFields)
{
return false;
}
char * endOfMessage = secondaryBuffer + secondaryBufferSizeUsed;
char * ptr = secondaryBufferSpace;
// printf ("parcom::parseNextPortion: secondaryBuffer is \n %s \n",secondaryBuffer);
for (numPtrFields = 0;
(numPtrFields < RTSP_MAX_NUMBER_OF_FIELDS) && (ptr < endOfMessage);
++numPtrFields)
{
char *endOfValue = ptr;
while (CHAR_LF != *(endOfValue)
&& CHAR_CR != *(endOfValue)
&& CHAR_NULL != *(endOfValue))
{
++endOfValue;
}
if (CHAR_CR == *(endOfValue) && CHAR_LF == *(endOfValue + 1))
{
// need to increment endOfValue for CR-LF, because
// it is needed later to step into the next field by shifting by 1
*(endOfValue) = CHAR_NULL;
*(++endOfValue) = CHAR_NULL;
}
else
{
*endOfValue = CHAR_NULL;
}
char * separator = ptr;
while ((CHAR_COLON != *separator) && (CHAR_NULL != *separator))
{
++separator;
}
if (CHAR_COLON != *separator)
{
//amMalformed = RTSPErrorSyntax;
//ignore the unknown lines
ptr = endOfValue + 1;
continue;
}
else
{
*separator = CHAR_NULL;
// get name pointer
char * namePtr = ptr;
// eat through trailing whitespace
for (char * wPtr1 = separator - 1;
(wPtr1 >= namePtr) && ((*wPtr1 >= 0x09 && *wPtr1 <= 0x0D) || *wPtr1 == 0x20);
--wPtr1)
{
*wPtr1 = CHAR_NULL;
}
// eat through leading whitespace
while ((*namePtr >= 0x09 && *namePtr <= 0x0D) || *namePtr == 0x20)
{
++namePtr;
}
// get value pointer
char * valuePtr = separator + 1;
// eat through trailing whitespace
for (char * wPtr2 = endOfValue - 1;
(wPtr2 > separator)
&& ((*wPtr2 >= 0x09 && *wPtr2 <= 0x0D) || *wPtr2 == 0x20);
--wPtr2)
{
*wPtr2 = CHAR_NULL;
}
//eat through leading whitespace
while ((*valuePtr >= 0x09 && *valuePtr <= 0x0D) || *valuePtr == 0x20)
{
++valuePtr;
}
// all right, set the pointers
fieldKeys[ numPtrFields ] = namePtr;
fieldVals[ numPtrFields ] = valuePtr;
// determine if we are supposed to recognize this
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldSessionId))
{
{
StrPtrLen tmp = fieldVals[ numPtrFields ];
int Len = tmp.length();
char * beginPtr = (char*)tmp.c_str();
char * endPtr = beginPtr + Len;
while (beginPtr < endPtr)
{
if (*beginPtr == ';')
{//we got timeout field
while (beginPtr < endPtr)
{
if ((*beginPtr == 't') && (beginPtr[6] == 't'))
{//a little bit validation
beginPtr += 8;
PV_atoi(beginPtr, 'd', timeout);
beginPtr = endPtr;
}
beginPtr++;
}
}
beginPtr++;
}
}
sessionId = fieldVals[ numPtrFields ];
sessionIdIsSet = true;
}
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldCSeq))
{
PV_atoi(valuePtr, 'd', cseq);
cseqIsSet = true;
}
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldBufferSize
))
{
PV_atoi(valuePtr, 'd', bufferSize);
bufferSizeIsSet = true;
}
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldContentType))
{
contentType = fieldVals[ numPtrFields ];
contentTypeIsSet = true;
}
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldContentBase))
{
contentBase = fieldVals[ numPtrFields ];
contentBaseMode = CONTENT_BASE_SET;
}
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldContentLength))
{
PV_atoi(valuePtr, 'd', contentLength);
contentLengthIsSet = true;
}
if (fieldKeys[ numPtrFields].isCIEquivalentTo(
RtspRecognizedFieldUserAgent))
{
userAgent = fieldVals[ numPtrFields ];
userAgentIsSet = true;
}
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldAccept))
{
accept = fieldVals[ numPtrFields ];
acceptIsSet = true;
}
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldRequire))
{
require = fieldVals[ numPtrFields ];
requireIsSet = true;
}
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldRTPInfo
))
{
parseRTPInfo(numPtrFields);
}
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldRange))
{
parseRtspRange(fieldVals[ numPtrFields].c_str(), fieldVals[ numPtrFields].length(), range);
rangeIsSet = true;
}
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldTransport))
{
parseTransport(numPtrFields);
}
#ifdef RTSP_PLAYLIST_SUPPORT
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldSupported))
{
parseSupported(fieldVals[ numPtrFields].c_str(), fieldVals[ numPtrFields].length() + 1);
supportedFieldIsSet = true;
}
#endif
}
ptr = endOfValue + 1;
}
totalFieldsParsed += numPtrFields;
secondaryBufferSpace = ptr;
return true;
}
#ifdef RTSP_PLAYLIST_SUPPORT
void
RTSPIncomingMessage::parseSupported(const char *supportedString, int length)
{
const StrPtrLen methodEosString("method.eos");
const StrPtrLen comPvPlaylistString("com.pv.server_playlist");
const char *end = supportedString + length;
char *sptr;//, *eptr;
sptr = (char*)supportedString;
while ((sptr < end) && (numOfSupportedEntries < RTSP_MAX_NUMBER_OF_SUPPORTED_ENTRIES))
{
char * separator = sptr;
while ((CHAR_COMMA != *separator)
&& (CHAR_NULL != *separator)
&& (separator < end)
)
{
++separator;
}
if (CHAR_COMMA == *separator)
{
// make sure there is a terminating char
// in the other case, there will already be one because its the end of the line
// and the field parsing that called this function put one there
*separator = CHAR_NULL;
}
// get name pointer
char * namePtr = sptr;
// eat through trailing whitespace
for (char * wPtr1 = separator - 1;
(wPtr1 >= namePtr)
&& ((*wPtr1 >= 0x09 && *wPtr1 <= 0x0D) || *wPtr1 == 0x20);
--wPtr1)
{
*wPtr1 = CHAR_NULL;
}
// eat through leading whitespace
while ((*namePtr >= 0x09 && *namePtr <= 0x0D) || *namePtr == 0x20)
{
++namePtr;
}
supportedField[numOfSupportedEntries++] = namePtr;
if (!oscl_strncmp(namePtr, methodEosString.c_str(), methodEosString.length()))
{
methodEosIsSet = true;
}
else if (!oscl_strncmp(namePtr, comPvPlaylistString.c_str(), comPvPlaylistString.length()))
{
comPvServerPlaylistIsSet = true;
}
sptr = separator + 1;
} // end while
}
#endif /* RTSP_PLAYLIST_SUPPORT */
// relevant constants
const int MIN_CHANNEL_VALUE = 0;
const int MAX_CHANNEL_VALUE = 255;
const int PORT_MIN_VALUE = 0;
const int PORT_MAX_VALUE = 65535;
#define interleaved_str "interleaved="
#define interleaved_str_len 12
#define client_port_str "client_port="
#define client_port_str_len 12
#define server_port_str "server_port="
#define server_port_str_len 12
#define ttl_str "ttl="
#define ttl_str_len 4
#define mode_str "mode="
#define mode_str_len 5
#define port_str "port="
#define port_str_len 5
#define layers_str "layers="
#define layers_str_len 7
#define ssrc_str "ssrc="
#define ssrc_str_len 5
#define destination_str "destination"
#define destination_str_len 11
void
RTSPIncomingMessage::parseTransport(uint16 fieldIdx)
{
char * cPtr;
char * finishPtr;
cPtr = const_cast<char*>(fieldVals[ fieldIdx ].c_str());
finishPtr = cPtr + fieldVals[ fieldIdx ].length();
do
{
parseOneTransportEntry(cPtr, finishPtr);
}
while (RTSPOk == amMalformed
&& cPtr < finishPtr
);
}
void
RTSPIncomingMessage::parseOneTransportEntry(char*& trans, char *final_end)
{
const char *startPtr, *endPtr, *nxtPtr;
char *transSepPtr;
// check the counter
//
if (RTSP_MAX_NUMBER_OF_TRANSPORT_ENTRIES == numOfTransportEntries)
{ // limit reached
amMalformed = RTSPErrorSyntax; // should it be different?
return;
}
RtspTransport* rtspTrans = transport + numOfTransportEntries;
numOfTransportEntries++;
startPtr = trans;
if (*startPtr == ',')
{
// skip over any starting commas
++startPtr;
}
rtspTrans->appendIsSet = false;
rtspTrans->channelIsSet = false;
rtspTrans->client_portIsSet = false;
rtspTrans->deliveryIsSet = false;
rtspTrans->layersIsSet = false;
rtspTrans->modeIsSet = false;
rtspTrans->portIsSet = false;
rtspTrans->profileIsSet = false;
rtspTrans->protocolIsSet = false;
rtspTrans->transportTypeIsSet = false;
rtspTrans->server_portIsSet = false;
rtspTrans->ttlIsSet = false;
rtspTrans->destinationIsSet = false;
// see if there is a tranport list separator
transSepPtr = OSCL_CONST_CAST(char*, oscl_strstr(startPtr, ","));
if (transSepPtr)
{
const char *quotePtr = oscl_strstr(startPtr, "\"");
if (quotePtr && quotePtr < transSepPtr)
{
// this may be a comma in the mode list -- so find the end of the mode list
const char *quote_end = oscl_strstr(quotePtr + 1, "\"");
if (quote_end)
{
// look for another comma
if (NULL != (transSepPtr = OSCL_CONST_CAST(char*, oscl_strstr(quote_end, ","))))
{
// temporarily write a terminator to separate the transport specs.
*transSepPtr = '\0';
}
}
}
else
{
// temporarily write a terminator to separate the transport specs.
*transSepPtr = '\0';
}
}
// for (; startPtr < final_end && isspace(*startPtr); ++startPtr);
for (; startPtr < final_end && ((*startPtr >= 0x09 && *startPtr <= 0x0D) || *startPtr == 0x20); ++startPtr);
do
{
if (NULL == (endPtr = oscl_strstr(startPtr, "/")))
{
endPtr = final_end;
}
rtspTrans->protocolIsSet = true;
if (!oscl_strncmp(startPtr, "RTP", endPtr - startPtr))
{
rtspTrans->protocol = RtspTransport::RTP_PROTOCOL;
}
else if (!oscl_strncmp(startPtr, "x-pn-tng", endPtr - startPtr))
{
rtspTrans->protocol = RtspTransport::RDT_PROTOCOL;
}
else
{
rtspTrans->protocol = RtspTransport::UNKNOWN_PROTOCOL;
}
if (endPtr == final_end)
{
break;
}
// increment the startPtr past the separator
startPtr = endPtr + 1;
// look for either the '/' or ';' separators
endPtr = oscl_strstr(startPtr, "/");
const char *endPtr2 = oscl_strstr(startPtr, ";");
if (!endPtr)
{
endPtr = endPtr2;
}
if (endPtr2 && endPtr2 < endPtr)
{
endPtr = endPtr2;
}
if (!endPtr)
{
endPtr = final_end;
}
rtspTrans->profile = RtspTransport::UNKNOWN_PROFILE;
rtspTrans->profileIsSet = true;
if (!oscl_strncmp(startPtr, "AVP", endPtr - startPtr))
{
rtspTrans->profile = RtspTransport::AVP_PROFILE;
}
else if (!oscl_strncmp(startPtr, "tcp", endPtr - startPtr))
{//RDT "x-pn-tng/tcp"
rtspTrans->profile = RtspTransport::TCP_PROFILE;
}
if (*endPtr == '/')
{
// there is an optional transport spec
startPtr = endPtr + 1;
if (NULL == (endPtr = oscl_strstr(startPtr, ";")))
{
endPtr = final_end;
}
rtspTrans->transportType = RtspTransport::UNKNOWN_TRANSPORT;
rtspTrans->transportTypeIsSet = true;
if (!oscl_strncmp(startPtr, "UDP", endPtr - startPtr))
{
rtspTrans->transportType = RtspTransport::UDP_TRANSPORT;
}
else if (!oscl_strncmp(startPtr, "TCP", endPtr - startPtr))
{
rtspTrans->transportType = RtspTransport::TCP_TRANSPORT;
}
}
if (endPtr == final_end)
{
break;
}
// increment the startPtr past the separator
startPtr = endPtr + 1;
}
while (0); // only go through this once
while (startPtr < final_end)
{
for (; startPtr < final_end && ((*startPtr >= 0x09 && *startPtr <= 0x0D) || *startPtr == 0x20); ++startPtr);
char *sepPtr;
// find the next separator
if (NULL == (sepPtr = (char*)(endPtr = oscl_strstr(startPtr, ";"))))
{
endPtr = final_end;
}
if (sepPtr)
{
*sepPtr = '\0';
}
if (!oscl_strncmp(startPtr, "unicast", endPtr - startPtr))
{
rtspTrans->delivery = RtspTransport::UNICAST_DELIVERY;
rtspTrans->deliveryIsSet = true;
}
if (!oscl_strncmp(startPtr, "multicast", endPtr - startPtr))
{
rtspTrans->delivery = RtspTransport::MULTICAST_DELIVERY;
rtspTrans->deliveryIsSet = true;
}
else if (!oscl_strncmp(startPtr, "append", endPtr - startPtr))
{
rtspTrans->append = true;
rtspTrans->appendIsSet = true;
}
else if (!oscl_strncmp(startPtr, destination_str,
destination_str_len))
{
nxtPtr = startPtr + destination_str_len;
char *curEndPtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "="));
if (curEndPtr)
{
nxtPtr = curEndPtr + 1;
// skip leading whitespace
for (; nxtPtr < endPtr && ((*nxtPtr >= 0x09 && *nxtPtr <= 0x0D) || *nxtPtr == 0x20); ++nxtPtr);
// now find the end
for (curEndPtr = (char*)nxtPtr; curEndPtr < endPtr && !((*curEndPtr >= 0x09 && *curEndPtr <= 0x0D) || *curEndPtr == 0x20);
++curEndPtr);
if (curEndPtr - nxtPtr > 0)
{
if (curEndPtr < endPtr)
{
*curEndPtr = '\0';
}
else if (sepPtr)
{
// clear sepPtr so it won't overwrite the NULL character
sepPtr = NULL;
}
rtspTrans->destination.setPtrLen(nxtPtr,
curEndPtr - nxtPtr);
rtspTrans->destinationIsSet = true;
}
}
}
else if (!oscl_strncmp(startPtr, interleaved_str,
interleaved_str_len))
{
int tmp;
nxtPtr = startPtr + interleaved_str_len;
char *curEndPtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "-"));
if (curEndPtr) *curEndPtr = '\0';
uint32 atoi_tmp;
PV_atoi(nxtPtr, 'd', atoi_tmp);
tmp = atoi_tmp;
if (tmp < MIN_CHANNEL_VALUE || tmp > MAX_CHANNEL_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->channel1 = tmp;
if (!curEndPtr)
{
if (rtspTrans->channel1 >= MAX_CHANNEL_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->channel2 = rtspTrans->channel1 + 1;
rtspTrans->channelIsSet = true;
}
else
{
nxtPtr = curEndPtr + 1;
*curEndPtr = '-';
PV_atoi(nxtPtr, 'd', atoi_tmp);
tmp = atoi_tmp;
if (tmp < MIN_CHANNEL_VALUE || tmp > MAX_CHANNEL_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->channel2 = tmp;
rtspTrans->channelIsSet = true;
}
}
else if (!oscl_strncmp(startPtr, client_port_str,
client_port_str_len))
{
int tmp;
uint32 atoi_tmp;
nxtPtr = startPtr + client_port_str_len;
char *curEndPtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "-"));
if (curEndPtr) *curEndPtr = '\0';
PV_atoi(nxtPtr, 'd', atoi_tmp);
tmp = atoi_tmp;
if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->client_port1 = tmp;
if (!curEndPtr)
{
if (rtspTrans->client_port1 >= PORT_MAX_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->client_port2 = rtspTrans->client_port1 + 1;
rtspTrans->client_portIsSet = true;
}
else
{
nxtPtr = curEndPtr + 1;
*curEndPtr = '-';
PV_atoi(nxtPtr, 'd', atoi_tmp);
tmp = atoi_tmp;
if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->client_port2 = tmp;
rtspTrans->client_portIsSet = true;
}
}
else if (!oscl_strncmp(startPtr, server_port_str,
server_port_str_len))
{
int tmp;
uint32 atoi_tmp;
nxtPtr = startPtr + server_port_str_len;
char *curEndPtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "-"));
if (curEndPtr) *curEndPtr = '\0';
PV_atoi(nxtPtr, 'd', atoi_tmp);
tmp = atoi_tmp;
if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->server_port1 = tmp;
if (!curEndPtr)
{
if (rtspTrans->server_port1 >= PORT_MAX_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->server_port2 = rtspTrans->server_port1 + 1;
rtspTrans->server_portIsSet = true;
}
else
{
nxtPtr = curEndPtr + 1;
*curEndPtr = '-';
PV_atoi(nxtPtr, 'd', atoi_tmp);
tmp = atoi_tmp;
if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->server_port2 = tmp;
rtspTrans->server_portIsSet = true;
}
}
else if (!oscl_strncmp(startPtr, ttl_str, ttl_str_len))
{
nxtPtr = startPtr + ttl_str_len;
int tmp;
uint32 atoi_tmp;
PV_atoi(nxtPtr, 'd', atoi_tmp);
tmp = atoi_tmp;
if (tmp < 0 || tmp > 255)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->ttl = tmp;
rtspTrans->ttlIsSet = true;
}
else if (!oscl_strncmp(startPtr, mode_str, mode_str_len))
{
rtspTrans->mode.play_mode = false;
rtspTrans->mode.record_mode = false;
nxtPtr = startPtr + mode_str_len;
rtspTrans->modeIsSet = true;
char *quotePtr = NULL;
const char *wordEndPtr;
if (*nxtPtr == '\"')
{
++nxtPtr;
if (NULL != (quotePtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "\""))))
{
*quotePtr = '\0';
}
}
while (nxtPtr < endPtr)
{
if (NULL == (wordEndPtr = oscl_strstr(nxtPtr, ",")))
{
wordEndPtr = endPtr;
}
if (!oscl_strncmp(nxtPtr, "PLAY", wordEndPtr - nxtPtr))
{
rtspTrans->mode.play_mode = true;
}
else if (!oscl_strncmp(nxtPtr, "RECORD", wordEndPtr - nxtPtr))
{
rtspTrans->mode.record_mode = true;
}
nxtPtr = wordEndPtr + 1;
}
if (quotePtr)
{
*quotePtr = '\"';
}
}
else if (!oscl_strncmp(startPtr, port_str, port_str_len))
{
int tmp;
uint32 atoi_tmp;
nxtPtr = startPtr + port_str_len;
char *curEndPtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "-"));
if (curEndPtr) *curEndPtr = '\0';
PV_atoi(nxtPtr, 'd', atoi_tmp);
tmp = atoi_tmp;
if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->port1 = tmp;
if (!curEndPtr)
{
if (rtspTrans->port1 >= PORT_MAX_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->port2 = rtspTrans->port1 + 1;
rtspTrans->portIsSet = true;
}
else
{
nxtPtr = curEndPtr + 1;
*curEndPtr = '-';
PV_atoi(nxtPtr, 'd', atoi_tmp);
tmp = atoi_tmp;
if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->port2 = tmp;
rtspTrans->portIsSet = true;
}
}
else if (!oscl_strncmp(startPtr, layers_str, layers_str_len))
{
nxtPtr = startPtr + layers_str_len;
PV_atoi(nxtPtr, 'd', rtspTrans->layers);
rtspTrans->layersIsSet = true;
}
else if (!oscl_strncmp(startPtr, ssrc_str, ssrc_str_len))
{
nxtPtr = startPtr + ssrc_str_len;
rtspTrans->ssrc = 0;
rtspTrans->ssrcIsSet = false;
if (!PV_atoi(nxtPtr, 'x', rtspTrans->ssrc))
{
amMalformed = RTSPErrorSyntax;
if (sepPtr)
{
*sepPtr = ';';
};
break;
}
rtspTrans->ssrcIsSet = true;
}
if (sepPtr)
{
*sepPtr = ';';
}
startPtr = endPtr + 1;
}
if (transSepPtr)
{
// put the separator character back
*transSepPtr = ',';
trans = transSepPtr;
}
else
{
trans = final_end;
}
}
void
RTSPIncomingMessage::parseRTPInfo(uint16 fieldIdx)
{
char * cPtr;
char * finishPtr;
cPtr = const_cast<char*>(fieldVals[ fieldIdx ].c_str());
finishPtr = cPtr + fieldVals[ fieldIdx ].length();
do
{
parseOneRTPInfoEntry(cPtr, finishPtr);
}
while (RTSPOk == amMalformed
&& cPtr < finishPtr
);
}
void
RTSPIncomingMessage::parseOneRTPInfoEntry(char * & cPtr, char * finishPtr)
{
bool getOut;
char * subFieldName;
char * separator;
char * endOfIt;
// check the counter
//
if (RTSP_MAX_NUMBER_OF_RTP_INFO_ENTRIES == numOfRtpInfoEntries)
{ // limit reached
amMalformed = RTSPErrorSyntax; // should it be different?
return;
}
++numOfRtpInfoEntries;
// skip comma, if necessary
//
if (CHAR_COMMA == *cPtr)
{
++cPtr;
}
getOut = false;
while ((!getOut) && cPtr < finishPtr && CHAR_COMMA != *cPtr)
{
// reset pointers
subFieldName = NULL;
separator = NULL;
endOfIt = NULL;
// skip whitespace
while (cPtr < finishPtr
&& (CHAR_SPACE == *cPtr
|| CHAR_TAB == *cPtr
|| CHAR_SEMICOLON == *cPtr
|| CHAR_NULL == *cPtr
)
)
{
++cPtr;
}
if (cPtr >= finishPtr || CHAR_COMMA == *cPtr)
{
return;
}
// we see the beginning
subFieldName = cPtr;
// get the separator
while (cPtr < finishPtr
&& CHAR_EQUAL != *cPtr
)
{
++cPtr;
}
if (cPtr >= finishPtr)
{
return;
}
// we see the separator
separator = cPtr;
// get the end of it
while (cPtr < finishPtr
&& CHAR_SEMICOLON != *cPtr
&& CHAR_SPACE != *cPtr
&& CHAR_TAB != *cPtr
&& CHAR_COMMA != *cPtr
)
{
++cPtr;
}
endOfIt = cPtr;
if (3 == separator - subFieldName)
{ // url?
if (('u' == (subFieldName[0] | OSCL_ASCII_CASE_MAGIC_BIT))
&& ('r' == (subFieldName[1] | OSCL_ASCII_CASE_MAGIC_BIT))
&& ('l' == (subFieldName[2] | OSCL_ASCII_CASE_MAGIC_BIT))
)
{
rtpInfo[ numOfRtpInfoEntries-1 ].url.setPtrLen(
separator + 1,
endOfIt - separator - 1
);
rtpInfo[ numOfRtpInfoEntries-1 ].urlIsSet = true;
if (CHAR_COMMA == *endOfIt)
{
getOut = true;
}
*endOfIt = CHAR_NULL;
if (getOut)
{
// skip ahead beyond the whitespace
// since we overwrote the comma with a NULL
while (cPtr < finishPtr
&& (CHAR_SPACE == *cPtr
|| CHAR_TAB == *cPtr
|| CHAR_SEMICOLON == *cPtr
|| CHAR_NULL == *cPtr
)
)
{
++cPtr;
}
}
}
// or, maybe, seq?
else if (('s' == (subFieldName[0] | OSCL_ASCII_CASE_MAGIC_BIT))
&& ('e' == (subFieldName[1] | OSCL_ASCII_CASE_MAGIC_BIT))
&& ('q' == (subFieldName[2] | OSCL_ASCII_CASE_MAGIC_BIT))
)
{
uint32 atoi_tmp;
PV_atoi(separator + 1, 'd', atoi_tmp);
rtpInfo[ numOfRtpInfoEntries-1 ].seq = (RtpSeqType)atoi_tmp;
rtpInfo[ numOfRtpInfoEntries-1 ].seqIsSet = true;
}
else
{
amMalformed = RTSPErrorSyntax;
return;
}
}
else if (7 == separator - subFieldName)
{ // rtptime?
if (('r' == (subFieldName[0] | OSCL_ASCII_CASE_MAGIC_BIT))
&& ('t' == (subFieldName[1] | OSCL_ASCII_CASE_MAGIC_BIT))
&& ('p' == (subFieldName[2] | OSCL_ASCII_CASE_MAGIC_BIT))
&& ('t' == (subFieldName[3] | OSCL_ASCII_CASE_MAGIC_BIT))
&& ('i' == (subFieldName[4] | OSCL_ASCII_CASE_MAGIC_BIT))
&& ('m' == (subFieldName[5] | OSCL_ASCII_CASE_MAGIC_BIT))
&& ('e' == (subFieldName[6] | OSCL_ASCII_CASE_MAGIC_BIT))
)
{
uint32 rtptime = 0;
PV_atoi((separator + 1), 'd', rtptime);
rtpInfo[ numOfRtpInfoEntries-1 ].rtptime = rtptime;
rtpInfo[ numOfRtpInfoEntries-1 ].rtptimeIsSet = true;
}
else
{
amMalformed = RTSPErrorSyntax;
return;
}
}
else
{
amMalformed = RTSPErrorSyntax;
return;
}
cPtr = endOfIt;
}
}
#if (defined(ASF_STREAMING) || defined(RTSP_PLAYLIST_SUPPORT))
OSCL_EXPORT_REF bool
RTSPIncomingMessage::parseEntityBody(RTSPEntityBody * entityBody)
{
char * endOfMessage = (char *) entityBody->ptr + entityBody->len;
char * ptr;
for (ptr = (char *) entityBody->ptr;
ptr < endOfMessage ;
++numPtrFields
)
{
char * endOfValue = ptr;
while (CHAR_LF != *(endOfValue)
&& CHAR_CR != *(endOfValue)
&& CHAR_NULL != *(endOfValue))
{
++endOfValue;
}
if (CHAR_CR == *(endOfValue) && CHAR_LF == *(endOfValue + 1))
{
// need to increment endOfValue for CR-LF, because
// it is needed later to step into the next field by shifting by 1
*(endOfValue) = CHAR_NULL;
*(++endOfValue) = CHAR_NULL;
}
else
{
*endOfValue = CHAR_NULL;
}
char * separator = ptr;
while ((CHAR_COLON != *separator)
&& (CHAR_NULL != *separator)
)
{
++separator;
}
if (CHAR_COLON != *separator)
{
amMalformed = RTSPErrorSyntax;
}
else
{ // field is pretty much normal
*separator = CHAR_NULL;
// get name pointer
char * namePtr = ptr;
// eat through trailing whitespace
for (char * wPtr1 = separator - 1;
(wPtr1 >= namePtr)
&& ((*wPtr1 >= 0x09 && *wPtr1 <= 0x0D) || *wPtr1 == 0x20);
--wPtr1)
{
*wPtr1 = CHAR_NULL;
}
// eat through leading whitespace
while ((*namePtr >= 0x09 && *namePtr <= 0x0D) || *namePtr == 0x20)
{
++namePtr;
}
// get value pointer
char * valuePtr = separator + 1;
// eat through trailing whitespace
for (char * wPtr2 = endOfValue - 1;
(wPtr2 > separator)
&& ((*wPtr2 >= 0x09 && *wPtr2 <= 0x0D) || *wPtr2 == 0x20);
--wPtr2)
{
*wPtr2 = CHAR_NULL;
}
//eat through leading whitespace
while ((*valuePtr >= 0x09 && *valuePtr <= 0x0D) || *valuePtr == 0x20)
{
++valuePtr;
}
// set the pointers
fieldKeys[ numPtrFields ] = namePtr;
fieldVals[ numPtrFields ] = valuePtr;
// now, figure out if we are supposed to recognize this
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldSessionId))
{
sessionId = fieldVals[ numPtrFields ];
sessionIdIsSet = true;
}
//RTSP_PAR_COM_CONSTANTS_H_
#define RtspRecognizedFieldEOF "EOF"
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldEOF))
{
eofField = fieldVals[ numPtrFields ];
eofFieldIsSet = true;
}
#ifdef RTSP_PLAYLIST_SUPPORT
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldPlaylistRange))
{
playlistRangeField = fieldVals[ numPtrFields ]; // not sure we really need to store this, but do it for now anyway
playlistRangeFieldIsSet = true;
// now parse the entry
/*playlistRangeField.setPtrLen("",0);
playlistRangeFieldIsSet = false;
playlistErrorFieldIsSet = false;
playlistErrorFieldCount = 0;
playlistRangeUrl.setPtrLen("",0);
playlistRangeClipIndex=0;
playlistRangeClipOffset=0;
playlistRangeNptTime=0;*/
char* curr = valuePtr; // set curr to the start of the entry after the colon, whitespace was already removed
StrPtrLen eStr;
eStr = curr;
// look for playlist_play_time
const StrPtrLen RtspPlaylistPlayTimeStr = "playlist_play_time";
if (0 && RtspPlaylistPlayTimeStr.isCIPrefixOf(eStr))
{
curr += 18; // move past "playlist_play_time"
// eat through leading whitespace
while ((*curr >= 0x09 && *curr <= 0x0D) || *curr == 0x20)
{
++curr;
}
if (*curr != CHAR_EQUAL)
{
// problem
}
// could be more whitespace
while ((*curr >= 0x09 && *curr <= 0x0D) || *curr == 0x20)
{
++curr;
}
if (*curr != CHAR_LT)
{
// problem
}
++curr; // move past '<'
// could be even more whitespace
while ((*curr >= 0x09 && *curr <= 0x0D) || *curr == 0x20)
{
++curr;
}
// now comes the url
// find the end first
char* end = curr;
while (*end != CHAR_COMMA)
{
++end;
}
char* endtmp = end;
// may have trailing whitespace
if (*(endtmp - 1) == 0x09 || *(endtmp - 1) == 0x0D || *(endtmp - 1) == 0x20)
{
--endtmp;
while ((*endtmp >= 0x09 && *endtmp <= 0x0D) || *endtmp == 0x20)
{
--endtmp;
}
// will be on a non space char, move it over
++endtmp;
}
// to do - not sure if we need a '\0' here..
playlistRangeUrl.setPtrLen(curr, endtmp - curr);
curr = end + 1;
// next should be the clip index
// of course, could be more whitespace
while ((*curr >= 0x09 && *curr <= 0x0D) || *curr == 0x20)
{
++curr;
}
// find next comma
end = curr;
while (*end != CHAR_COMMA)
{
++end;
}
// may have trailing whitespace
// dont worry about it for now atoi should be ok
/*if(*(end-1) == 0x09 ||*(end-1) == 0x0D ||*(end-1) == 0x20)
{
--end;
while( (*end >= 0x09 && *end <= 0x0D) || *end == 0x20 )
{
--end;
}
// will be on a non space char, move it over
++end;
}*/
// finally get the value
uint32 atoi_tmp;
PV_atoi(curr, 'd', atoi_tmp);
playlistRangeClipIndex = atoi_tmp;
curr = end + 1;
// next should be the clip offset
// of course, could be more whitespace
while ((*curr >= 0x09 && *curr <= 0x0D) || *curr == 0x20)
{
++curr;
}
// find next comma
end = curr;
while (*end != CHAR_GT)
{
++end;
}
// may have trailing whitespace
// dont worry about it for now atoi should be ok
/*if(*(end-1) == 0x09 ||*(end-1) == 0x0D ||*(end-1) == 0x20)
{
--end;
while( (*end >= 0x09 && *end <= 0x0D) || *end == 0x20 )
{
--end;
}
// will be on a non space char, move it over
++end;
}*/
// finally get the value
PV_atoi(curr, 'd', atoi_tmp);
playlistRangeClipOffset = atoi_tmp;
}
else
{
// problem
}
}
if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
RtspRecognizedFieldPlaylistError))
{
if (playlistErrorFieldCount < RTSP_MAX_NUMBER_OF_PLAYLIST_ERROR_ENTRIES)
{
playlistErrorField[playlistErrorFieldCount++] = fieldVals[ numPtrFields ]; // this needs to be an array since the number can be unbounded
playlistErrorFieldIsSet = true;
}
}
#endif
}
ptr = endOfValue + 1;
}
return true;
}
#endif