blob: 467ff7ab04cc0520947512462924d64e092c493a [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 "oscl_dll.h"
// Define entry point for this DLL
OSCL_DLL_ENTRY_POINT_DEFAULT()
// This function searches for a substring in a string, just like strstr(), but
// with a couple of specific features:
// 1. It is case-insensitive, so "Ces" can be found in the word "success";
// 2. It is looking for substrings left-to-right, and if the string starts
// matching, the state of search gets increased; if the whole string does not
// match, this function does NOT step back; therefore, the string "KoKoMo"
// will not be found correctly in the string "KoKoKoMo"; however, it will
// work for substrings that have unique beginnings that don't repeat
// themselves, such as "Content-length" ('c' is never repeated). Therefore,
// such a search works for "Content-length", which is all that RtspParser
// needs.
//
// This function is not part of OSCL precisely because of its limitations;
// however, these limitations are ok here because they contribute to the
// overall performance by not doing extra steps.
//
// added the size argument to deal with Real cloaking "H\02\00\00" 02/22/06
static inline char *
ci_local_strstr(char * bigString, int32 bigStringSize,
const StrPtrLen & subString
)
{
uint32 state = 0;
uint32 targetState = subString.length();
char * pp;
//char * eos = bigString + oscl_strlen(bigString);
char * eos = bigString + bigStringSize;
for (pp = bigString;
pp != eos;
++pp
)
{
if (OSCL_ASCII_CASE_MAGIC_BIT
== (((*pp) ^(subString.c_str()[state])) | OSCL_ASCII_CASE_MAGIC_BIT)
)
{
++state;
if (state == targetState)
{
return pp - targetState + 1;
}
}
else
{
state = 0;
}
}
return NULL;
}
static inline bool
isspaceNotNL(char ch)
{
if ((CHAR_CR == ch) || (CHAR_LF == ch) || (CHAR_NULL == ch))
{
return false;
}
return (0 != ((ch >= 0x09 && ch <= 0x0D) || ch == 0x20));
}
OSCL_EXPORT_REF RTSPParser::ParserState
RTSPParser::getState()
{
ParserState stateToReturn;
switch (internalState)
{
case IS_WAITING_FOR_REQUEST_MEMORY:
stateToReturn = WAITING_FOR_REQUEST_MEMORY;
break;
case IS_LOOKING_FOR_END_OF_REQUEST:
case IS_CONTINUING_TO_FILL_OUT_ENTITY_BODY:
case IS_SKIPPING_OVER_ENTITY_BODY:
case IS_LOOKING_FOR_RESYNC:
case IS_CONTINUING_TO_FILL_OUT_EMBEDDED_DATA:
case IS_SKIPPING_OVER_EMBEDDED_DATA:
stateToReturn = WAITING_FOR_DATA;
break;
case IS_START_LOOKING_FOR_RESYNC:
stateToReturn = ERROR_REQUEST_TOO_BIG;
internalState = IS_LOOKING_FOR_RESYNC;
break;
case IS_WAITING_FOR_ENTITY_BODY_MEMORY:
stateToReturn = WAITING_FOR_ENTITY_BODY_MEMORY;
break;
case IS_WAITING_FOR_EMBEDDED_DATA_MEMORY:
stateToReturn = WAITING_FOR_EMBEDDED_DATA_MEMORY;
break;
case IS_ERROR_REQUEST_TOO_BIG:
case IS_REQUEST_IS_READY:
// both states are processed the same way,
// except that the state returned is different
//
stateToReturn = (IS_REQUEST_IS_READY == internalState) ?
REQUEST_IS_READY : ERROR_REQUEST_TOO_BIG;
// take care of the entity bodies
if (0 == ebFullSizeExpected)
{ // no eb expected
internalState = IS_WAITING_FOR_REQUEST_MEMORY;
}
else
{ // check to see the nature of the entity body. if it
// is embedded data, change internal state appropriately
if (requestStruct->method != METHOD_BINARY_DATA)
{
internalState = IS_WAITING_FOR_ENTITY_BODY_MEMORY;
}
else
{
internalState = IS_WAITING_FOR_EMBEDDED_DATA_MEMORY;
}
}
continueProcessing();
break;
case IS_ENTITY_BODY_IS_READY:
stateToReturn = ENTITY_BODY_IS_READY;
internalState = IS_WAITING_FOR_REQUEST_MEMORY;
break;
case IS_EMBEDDED_DATA_IS_READY:
stateToReturn = EMBEDDED_DATA_IS_READY;
internalState = IS_WAITING_FOR_REQUEST_MEMORY;
break;
default:
// now, this is an internal error
internalState = IS_INTERNAL_ERROR;
stateToReturn = INTERNAL_ERROR;
}
return stateToReturn;
}
OSCL_EXPORT_REF RTSPParser::RTSPParser()
{
flush();
};
void
RTSPParser::continueProcessing()
{
switch (internalState)
{
case IS_WAITING_FOR_REQUEST_MEMORY:
break;
case IS_LOOKING_FOR_END_OF_REQUEST:
lookForEndOfRequest();
break;
case IS_START_LOOKING_FOR_RESYNC:
case IS_LOOKING_FOR_RESYNC:
lookForResync();
break;
case IS_WAITING_FOR_ENTITY_BODY_MEMORY:
// nothing to do, really
break;
case IS_SKIPPING_OVER_ENTITY_BODY:
skipOverEntityBody();
break;
case IS_STARTING_TO_FILL_OUT_ENTITY_BODY:
startFillingOutEntityBody();
break;
case IS_CONTINUING_TO_FILL_OUT_ENTITY_BODY:
break;
case IS_WAITING_FOR_EMBEDDED_DATA_MEMORY:
break;
case IS_SKIPPING_OVER_EMBEDDED_DATA:
skipOverEmbeddedData();
break;
case IS_STARTING_TO_FILL_OUT_EMBEDDED_DATA:
startFillingOutEmbeddedData();
break;
case IS_CONTINUING_TO_FILL_OUT_EMBEDDED_DATA:
break;
default:
internalState = IS_INTERNAL_ERROR;
}
}
OSCL_EXPORT_REF bool
RTSPParser::registerNewRequestStruct(RTSPIncomingMessage * newRequestStruct)
{
if (IS_WAITING_FOR_REQUEST_MEMORY != internalState)
{
return false;
}
requestStruct = newRequestStruct;
internalState = IS_LOOKING_FOR_END_OF_REQUEST;
continueProcessing();
return true;
}
OSCL_EXPORT_REF const StrPtrLen *
RTSPParser::getDataBufferSpec()
{
if (internalState == IS_LOOKING_FOR_END_OF_REQUEST
|| internalState == IS_START_LOOKING_FOR_RESYNC
|| internalState == IS_LOOKING_FOR_RESYNC
)
{
// normal case - just put stuff into the buffer
dataBufferSpec.setPtrLen(mainBufferSpace,
mainBuffer + RTSP_PARSER_BUFFER_SIZE - mainBufferSpace);
}
else if (internalState == IS_CONTINUING_TO_FILL_OUT_ENTITY_BODY
|| internalState == IS_CONTINUING_TO_FILL_OUT_EMBEDDED_DATA
)
{
// the whole entity body arithmetic is done here, not in
// registerDataWritten(), so here it comes
while (entityBody[ebCurrentIndex].len == ebCurrentOffset)
{
++ebCurrentIndex;
ebCurrentOffset = 0;
}
// so, we are at the appropriate fragment;
// figure out which is smaller
//
uint32 sizePossibleToWrite =
entityBody[ebCurrentIndex].len - ebCurrentOffset;
uint32 sizeLeftToWrite = ebFullSizeExpected - ebSizeCoveredSoFar;
// set the data buffer spec
dataBufferSpec.setPtrLen(
static_cast<char*>(entityBody[ebCurrentIndex].ptr) + ebCurrentOffset,
(sizePossibleToWrite < sizeLeftToWrite) ?
sizePossibleToWrite : sizeLeftToWrite
);
}
else if (IS_SKIPPING_OVER_ENTITY_BODY == internalState)
{
mainBufferEntry = mainBuffer;
mainBufferSpace = mainBuffer;
dataBufferSpec.setPtrLen(mainBufferSpace, RTSP_PARSER_BUFFER_SIZE);
}
else
{
// it's some kind of inconsistency on the Engine's part, or Parser's
// internal error
return NULL;
}
return & dataBufferSpec;
}
void
RTSPParser::lookForEndOfRequest()
{
// eorptr = mainBufferEntry;
uint32 newMessageSize;
*mainBufferSpace = CHAR_NULL;
bool shouldMoveOverToBeginning = false;
// now, it's either a binary data thing, or a regular message
if (CHAR_DOLLAR == *mainBufferEntry)
{
if (mainBufferSpace - mainBufferEntry < 4)
{ // not a complete message
shouldMoveOverToBeginning = true;
}
else
{ // it is a complete thing
requestStruct->msgType = RTSPRequestMsg;
requestStruct->method = METHOD_BINARY_DATA;
requestStruct->contentLength =
((static_cast<uint16>(
(*(reinterpret_cast<unsigned char*>(mainBufferEntry + 2))
))) << 8)
+ static_cast<uint16>(
*(reinterpret_cast<unsigned char*>(mainBufferEntry + 3))
);
requestStruct->contentLengthIsSet = true;
*(mainBufferEntry + 2) = CHAR_NULL;
requestStruct->contentType = mainBufferEntry + 1;
requestStruct->contentTypeIsSet = true;
requestStruct->channelID = static_cast<uint8>(
*(reinterpret_cast<unsigned char*>(mainBufferEntry + 1)));
mainBufferEntry += 4;
eorptr = mainBufferEntry;
ebFullSizeExpected = requestStruct->contentLength;
internalState = IS_REQUEST_IS_READY;
return;
}
}
else
{ // it's a normal message
bool found = false;
for (/*eorptr = mainBufferEntry*/; eorptr < mainBufferSpace - 1; ++eorptr)
{
if (CHAR_LF == *eorptr || CHAR_CR == *eorptr)
{ // it's a possible
// is it two newlines?
if (*eorptr == *(eorptr + 1))
{ // yes, CR-CR or LF-LF format
found = true;
eorptr += 2;
break;
}
else if ((eorptr <= mainBufferSpace - 4)
&& (CHAR_CR == *(eorptr)) && (CHAR_LF == *(eorptr + 1))
&& (CHAR_CR == *(eorptr + 2)) && (CHAR_LF == *(eorptr + 3))
)
{ // yes, MS-WINDOWS format
found = true;
eorptr += 4;
break;
}
// else, continue on
}
}
if (found)
{
// transfer the buffer, if necessary
newMessageSize = eorptr - mainBufferEntry;
// quickly take a peek at content-length
char * cl = ci_local_strstr(mainBufferEntry, newMessageSize,
RtspRecognizedFieldContentLength);
if (NULL == cl)
{ // nothing visible
ebFullSizeExpected = 0;
}
else if (cl >= mainBufferEntry + newMessageSize)
{ // it's not part of this particular message
ebFullSizeExpected = 0;
}
else
{
cl += oscl_strlen(RtspRecognizedFieldContentLength);
while (cl < eorptr && (isspaceNotNL(*cl) || (CHAR_COLON == *cl)))
{
++cl;
}
uint32 atoi_tmp;
PV_atoi(cl, 'd', atoi_tmp);
ebFullSizeExpected = atoi_tmp;
}
// now, on with the moving around ...
if (RTSP_MAX_FULL_REQUEST_SIZE < newMessageSize)
{
// request too big
oscl_memcpy(requestStruct->secondaryBuffer, mainBufferEntry,
RTSP_MAX_FULL_REQUEST_SIZE);
requestStruct->secondaryBuffer[RTSP_MAX_FULL_REQUEST_SIZE] = CHAR_NULL;
requestStruct->secondaryBufferSizeUsed = newMessageSize;
requestStruct->amMalformed = RTSPErrorTooBig;
mainBufferEntry += newMessageSize;
eorptr = mainBufferEntry;
internalState = IS_ERROR_REQUEST_TOO_BIG;
}
else
{
// everything is ok
oscl_memcpy(requestStruct->secondaryBuffer, mainBufferEntry,
newMessageSize);
requestStruct->secondaryBuffer[ newMessageSize ] = CHAR_NULL;
requestStruct->secondaryBufferSizeUsed = newMessageSize;
mainBufferEntry += newMessageSize;
eorptr = mainBufferEntry;
internalState = IS_REQUEST_IS_READY;
}
dealWithLineContinuations(requestStruct);
requestStruct->parseFirstFields();
}
else
{
shouldMoveOverToBeginning = true;
}
}
if (shouldMoveOverToBeginning)
{
// i.e. end of request was not found
int sizeUsedSoFar = mainBufferSpace - mainBufferEntry;
if (RTSP_PARSER_BUFFER_SIZE == sizeUsedSoFar)
{ // we hit the parser's buffer size
internalState = IS_START_LOOKING_FOR_RESYNC;
continueProcessing();
return;
}
if (mainBufferEntry != mainBuffer)
{
oscl_memmove(mainBuffer, mainBufferEntry, sizeUsedSoFar);
mainBufferEntry = mainBuffer;
eorptr = mainBufferEntry;
mainBufferSpace = mainBufferEntry + sizeUsedSoFar;
}
else
{ // rewind eorptr
eorptr -= 4;
eorptr = (eorptr < mainBufferEntry) ? mainBufferEntry : eorptr;
}
}
}
OSCL_EXPORT_REF bool
RTSPParser::registerDataBufferWritten(uint32 sizeWritten)
{
// take care of entity bodies and stuff
if (IS_LOOKING_FOR_END_OF_REQUEST == internalState)
{ // the memory being filled out is Parser's
mainBufferSpace += sizeWritten;
continueProcessing();
return true;
}
else if (IS_CONTINUING_TO_FILL_OUT_ENTITY_BODY == internalState
|| IS_CONTINUING_TO_FILL_OUT_EMBEDDED_DATA == internalState
)
{ // the memory being filled out is Engine's entity body
ebCurrentOffset += sizeWritten;
ebSizeCoveredSoFar += sizeWritten;
if (ebSizeCoveredSoFar == ebFullSizeExpected)
{
eorptr = mainBufferEntry;
if (internalState == IS_CONTINUING_TO_FILL_OUT_ENTITY_BODY)
{
internalState = IS_ENTITY_BODY_IS_READY;
}
else // internalState=IS_CONTINUING_TO_FILL_OUT_EMBEDDED_DATA
{
internalState = IS_EMBEDDED_DATA_IS_READY;
}
}
return true;
}
else if (IS_SKIPPING_OVER_ENTITY_BODY == internalState)
{
mainBufferSpace += sizeWritten;
continueProcessing();
}
else if (IS_START_LOOKING_FOR_RESYNC == internalState
|| IS_LOOKING_FOR_RESYNC == internalState
)
{
mainBufferSpace += sizeWritten;
continueProcessing();
}
else
{
// some kind of error on Engine's part, or Parser's internal inconsistency
return false;
}
return false; // to appease compiler
}
OSCL_EXPORT_REF bool
RTSPParser::registerEntityBody(RTSPEntityBody * newBody)
{
if (IS_WAITING_FOR_ENTITY_BODY_MEMORY != internalState)
{
return false;
}
entityBody = newBody;
if (NULL == entityBody)
{
internalState = IS_SKIPPING_OVER_ENTITY_BODY;
ebSizeCoveredSoFar = 0;
ebCurrentIndex = 0;
ebCurrentOffset = 0;
}
else
{
internalState = IS_STARTING_TO_FILL_OUT_ENTITY_BODY;
ebSizeCoveredSoFar = 0;
ebCurrentIndex = 0;
ebCurrentOffset = 0;
}
continueProcessing();
return true;
}
void
RTSPParser::skipOverEntityBody()
{
uint32 sizeNeededToSkip = ebFullSizeExpected - ebSizeCoveredSoFar;
uint32 sizePossibleToSkip = mainBufferSpace - mainBufferEntry;
uint32 sizeSkipped = (sizeNeededToSkip < sizePossibleToSkip) ?
sizeNeededToSkip : sizePossibleToSkip;
ebSizeCoveredSoFar += sizeSkipped;
mainBufferEntry += sizeSkipped;
if (ebSizeCoveredSoFar == ebFullSizeExpected)
{
eorptr = mainBufferEntry;
internalState = IS_WAITING_FOR_REQUEST_MEMORY;
}
}
void
RTSPParser::startFillingOutEntityBody()
{
while (ebFullSizeExpected != ebSizeCoveredSoFar)
{
// find an appropriate fragment
if (entityBody[ebCurrentIndex].len == ebCurrentOffset)
{
++ebCurrentIndex;
ebCurrentOffset = 0;
continue;
}
uint32 fragmentSizeAvailable = entityBody[ebCurrentIndex].len - ebCurrentOffset;
// decide, which is smaller - size left in the main buffer, or size left
// in the current target buffer
uint32 sizeAvailableForWriting = mainBufferSpace - mainBufferEntry;
uint32 sizeActuallyToBeWritten =
(fragmentSizeAvailable < sizeAvailableForWriting) ?
fragmentSizeAvailable : sizeAvailableForWriting;
// now decide, which is smaller - the previous result or the size actually
// left to fill out
uint32 sizeLeftToWrite = ebFullSizeExpected - ebSizeCoveredSoFar;
sizeActuallyToBeWritten = (sizeActuallyToBeWritten < sizeLeftToWrite) ?
sizeActuallyToBeWritten : sizeLeftToWrite;
if (0 == sizeActuallyToBeWritten)
{ // ran out of available data
// now, further filling out will actually be done by the Engine, we'll
// just direct it to memory within entity body;
//
// this means a change of states
//
internalState = IS_CONTINUING_TO_FILL_OUT_ENTITY_BODY;
return;
}
// memory comes from different sources, so we can copy it without fear of
// overlaps
oscl_memcpy(static_cast<char*>(entityBody[ebCurrentIndex].ptr) + ebCurrentOffset,
mainBufferEntry,
sizeActuallyToBeWritten
);
ebCurrentOffset += sizeActuallyToBeWritten;
mainBufferEntry += sizeActuallyToBeWritten;
ebSizeCoveredSoFar += sizeActuallyToBeWritten;
}
// at this point, either we covered the whole thing, or we didn't
// if we covered the whole thing, we jumped out from the loop according to
// the loop invariant
//
// if, however, we did not fill out the whole thing, then we have already
// returned from within the loop, switching to hungry state
//
// in other words, at this point we could ONLY succeed
eorptr = mainBufferEntry;
internalState = IS_ENTITY_BODY_IS_READY;
}
OSCL_EXPORT_REF bool
RTSPParser::registerEmbeddedDataMemory(RTSPEntityBody * newBody)
{
if (IS_WAITING_FOR_EMBEDDED_DATA_MEMORY != internalState)
{
return false;
}
entityBody = newBody;
if (NULL == entityBody)
{
internalState = IS_SKIPPING_OVER_EMBEDDED_DATA;
ebSizeCoveredSoFar = 0;
ebCurrentIndex = 0;
ebCurrentOffset = 0;
}
else
{
internalState = IS_STARTING_TO_FILL_OUT_EMBEDDED_DATA;
ebSizeCoveredSoFar = 0;
ebCurrentIndex = 0;
ebCurrentOffset = 0;
}
continueProcessing();
return true;
}
void
RTSPParser::skipOverEmbeddedData()
{
uint32 sizeNeededToSkip = ebFullSizeExpected - ebSizeCoveredSoFar;
uint32 sizePossibleToSkip = mainBufferSpace - mainBufferEntry;
uint32 sizeSkipped = (sizeNeededToSkip < sizePossibleToSkip) ?
sizeNeededToSkip : sizePossibleToSkip;
ebSizeCoveredSoFar += sizeSkipped;
mainBufferEntry += sizeSkipped;
if (ebSizeCoveredSoFar == ebFullSizeExpected)
{
eorptr = mainBufferEntry;
internalState = IS_WAITING_FOR_REQUEST_MEMORY;
}
}
void
RTSPParser::startFillingOutEmbeddedData()
{
while (ebFullSizeExpected != ebSizeCoveredSoFar)
{ // find an appropriate fragment
if (entityBody[ebCurrentIndex].len == ebCurrentOffset)
{
++ebCurrentIndex;
ebCurrentOffset = 0;
continue;
}
uint32 fragmentSizeAvailable = entityBody[ebCurrentIndex].len - ebCurrentOffset;
// decide, which is smaller - size left in the main buffer, or size left
// in the current target buffer
//
uint32 sizeAvailableForWriting = mainBufferSpace - mainBufferEntry;
uint32 sizeActuallyToBeWritten =
(fragmentSizeAvailable < sizeAvailableForWriting) ?
fragmentSizeAvailable : sizeAvailableForWriting;
// now decide, which is smaller - the previous result or the size actually
// left to fill out
uint32 sizeLeftToWrite = ebFullSizeExpected - ebSizeCoveredSoFar;
sizeActuallyToBeWritten = (sizeActuallyToBeWritten < sizeLeftToWrite) ?
sizeActuallyToBeWritten : sizeLeftToWrite;
if (0 == sizeActuallyToBeWritten)
{ // ran out of available data
// now, further filling out will actually be done by the Engine, we'll
// just direct it to memory within entity body;
//
// this means a change of states
//
internalState = IS_CONTINUING_TO_FILL_OUT_EMBEDDED_DATA;
return;
}
// memory comes from different sources, so we can copy it without fear of
// overlaps
oscl_memcpy(static_cast<char*>(entityBody[ebCurrentIndex].ptr) + ebCurrentOffset,
mainBufferEntry,
sizeActuallyToBeWritten
);
ebCurrentOffset += sizeActuallyToBeWritten;
mainBufferEntry += sizeActuallyToBeWritten;
ebSizeCoveredSoFar += sizeActuallyToBeWritten;
}
// at this point, either we covered the whole thing, or we didn't
// if we covered the whole thing, we jumped out from the loop according to
// the loop invariant
//
// if, however, we did not fill out the whole thing, then we have already
// returned from within the loop, switching to hungry state
//
// in other words, at this point we could ONLY succeed
eorptr = mainBufferEntry;
internalState = IS_EMBEDDED_DATA_IS_READY;
}
OSCL_EXPORT_REF void
RTSPParser::flush(void)
{
internalState = IS_WAITING_FOR_REQUEST_MEMORY;
mainBufferEntry = mainBuffer;
mainBufferSpace = mainBuffer;
mainBufferSizeUsed = 0;
eorptr = mainBuffer;
mainBuffer[ RTSP_PARSER_BUFFER_SIZE ] = CHAR_NULL;
mainBuffer[ RTSP_PARSER_BUFFER_SIZE+1 ] = CHAR_NULL;
}
void
RTSPParser::dealWithLineContinuations(RTSPIncomingMessage * theStruct)
{
char * cPtr; // current pointer
char * nlEnd; // new-line end pointer
char * finishPtr; // end-of-buffer pointer
finishPtr = theStruct->secondaryBuffer + theStruct->secondaryBufferSizeUsed;
for (cPtr = theStruct->secondaryBuffer;
cPtr < finishPtr;
)
{
// check if this point is suspicious
//
if (CHAR_CR == *cPtr)
{
if (cPtr < finishPtr - 1 // there's room for CR-LF
&& CHAR_LF == *(cPtr + 1) // next char is LF
)
{
nlEnd = cPtr + 1;
// newline, CR-LF
}
else
{
nlEnd = cPtr;
// newline, CR
}
}
else if (CHAR_LF == *cPtr)
{
nlEnd = cPtr;
// newline, LF
}
else
{ // not a newline
++cPtr;
continue;
}
// it was a newline
// now, is there a whitespace after it?
if (nlEnd >= finishPtr // could be no room for a whitespace
|| (CHAR_SPACE != *(nlEnd + 1) // could be a non-whitespace
&& CHAR_TAB != *(nlEnd + 1)
)
)
{
cPtr = nlEnd + 1;
continue;
}
char * sPtr;
for (sPtr = nlEnd + 1;
sPtr < finishPtr
&& (CHAR_SPACE == *sPtr
|| CHAR_TAB == *sPtr
);
++sPtr
)
{ // nothing
;;;;
}
size_t sizeToMove = finishPtr - sPtr + 1;
size_t sizeCut = sPtr - cPtr - 1;
// set a space
* cPtr = CHAR_SPACE;
// move the rest, careful with overlaps
oscl_memmove(cPtr + 1, sPtr, sizeToMove);
// reset the length
theStruct->secondaryBufferSizeUsed -= sizeCut;
// reiterate
finishPtr -= sizeCut;
++cPtr; // safe enough, still one whitespace has been written
continue;
}
}
void
RTSPParser::dealWithFieldRepetitions(RTSPIncomingMessage * theStruct)
{
char * cPtr;
char * finishPtr =
theStruct->secondaryBuffer + theStruct->secondaryBufferSizeUsed;
char * nlEnd;
for (cPtr = theStruct->secondaryBuffer;
cPtr < finishPtr;
++cPtr
)
{
if (CHAR_CR == *cPtr)
{
if (cPtr < finishPtr - 1
&& CHAR_LF == *(cPtr + 1)
)
{
nlEnd = cPtr + 1;
}
else
{
nlEnd = cPtr;
}
}
else if (CHAR_LF == *cPtr)
{
nlEnd = cPtr;
}
else
{
continue;
}
char * fieldNamePtr = nlEnd + 1;
if (fieldNamePtr >= finishPtr
|| CHAR_CR == *fieldNamePtr
|| CHAR_LF == *fieldNamePtr
|| CHAR_SPACE == *fieldNamePtr
|| CHAR_TAB == *fieldNamePtr
)
{
// not a field, an end of message or an empty string
continue;
}
// we have a field
}
}
void
RTSPParser::lookForResync()
{
bool found = false;
for (; eorptr < mainBufferSpace - 1; ++eorptr)
{
if (CHAR_LF == *eorptr || CHAR_CR == *eorptr)
{
if (*eorptr == *(eorptr + 1))
{
found = true;
eorptr += 2;
break;
}
else if ((eorptr <= mainBufferSpace - 4)
&& (CHAR_CR == *(eorptr)) && (CHAR_LF == *(eorptr + 1))
&& (CHAR_CR == *(eorptr + 2)) && (CHAR_LF == *(eorptr + 3))
)
{
found = true;
eorptr += 4;
break;
}
}
}
if (found)
{
mainBufferEntry = eorptr;
if (mainBufferEntry == mainBufferSpace)
{
mainBufferEntry = mainBuffer;
eorptr = mainBufferEntry;
mainBufferSpace = mainBufferEntry;
}
internalState = IS_WAITING_FOR_REQUEST_MEMORY;
continueProcessing();
}
else
{
int sizeToMove = (RTSP_RESYNC_PRESERVE_SIZE < (mainBufferSpace - mainBufferEntry)) ?
RTSP_RESYNC_PRESERVE_SIZE : (mainBufferSpace - mainBufferEntry);
oscl_memmove(mainBuffer, mainBufferSpace - sizeToMove, sizeToMove);
mainBufferEntry = mainBuffer;
mainBufferSpace = mainBufferEntry + sizeToMove;
eorptr = mainBuffer;
}
return;
}