| /* ------------------------------------------------------------------ |
| * 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 |
| |