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