371 lines
11 KiB
C++
371 lines
11 KiB
C++
|
/*
|
||
|
*
|
||
|
* @APPLE_LICENSE_HEADER_START@
|
||
|
*
|
||
|
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
||
|
*
|
||
|
* This file contains Original Code and/or Modifications of Original Code
|
||
|
* as defined in and that are subject to the Apple Public Source License
|
||
|
* Version 2.0 (the 'License'). You may not use this file except in
|
||
|
* compliance with the License. Please obtain a copy of the License at
|
||
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||
|
* file.
|
||
|
*
|
||
|
* The Original Code and all software distributed under the License are
|
||
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||
|
* Please see the License for the specific language governing rights and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
* @APPLE_LICENSE_HEADER_END@
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "SDPUtils.h"
|
||
|
|
||
|
#include "OS.h"
|
||
|
#include "StrPtrLen.h"
|
||
|
#include "ResizeableStringFormatter.h"
|
||
|
#include "StringParser.h"
|
||
|
#include "ResizeableStringFormatter.h"
|
||
|
#include "StringParser.h"
|
||
|
#include "OSMemory.h"
|
||
|
|
||
|
|
||
|
SInt32 SDPContainer::AddHeaderLine (StrPtrLen *theLinePtr)
|
||
|
{
|
||
|
Assert(theLinePtr);
|
||
|
UInt32 thisLine = fNumUsedLines;
|
||
|
Assert(fNumUsedLines < fNumSDPLines);
|
||
|
fSDPLineArray[thisLine].Set(theLinePtr->Ptr, theLinePtr->Len);
|
||
|
fNumUsedLines++;
|
||
|
if (fNumUsedLines == fNumSDPLines)
|
||
|
{
|
||
|
SDPLine *tempSDPLineArray = NEW SDPLine[fNumSDPLines * 2];
|
||
|
for (int i = 0; i < fNumSDPLines; i++)
|
||
|
{
|
||
|
tempSDPLineArray[i].Set(fSDPLineArray[i].Ptr,fSDPLineArray[i].Len);
|
||
|
}
|
||
|
delete [] fSDPLineArray;
|
||
|
fSDPLineArray = tempSDPLineArray;
|
||
|
fNumSDPLines = (fNumUsedLines * 2);
|
||
|
}
|
||
|
|
||
|
return thisLine;
|
||
|
}
|
||
|
|
||
|
SInt32 SDPContainer::FindHeaderLineType(char id, SInt32 start)
|
||
|
{
|
||
|
SInt32 theIndex = -1;
|
||
|
|
||
|
if (start >= fNumUsedLines || start < 0)
|
||
|
return -1;
|
||
|
|
||
|
for (int i = start; i < fNumUsedLines; i++)
|
||
|
{ if (fSDPLineArray[i].GetHeaderType() == id)
|
||
|
{ theIndex = i;
|
||
|
fCurrentLine = theIndex;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return theIndex;
|
||
|
}
|
||
|
|
||
|
SDPLine* SDPContainer::GetNextLine()
|
||
|
{
|
||
|
if (fCurrentLine < fNumUsedLines)
|
||
|
{ fCurrentLine ++;
|
||
|
return &fSDPLineArray[fCurrentLine];
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
|
||
|
}
|
||
|
|
||
|
SDPLine* SDPContainer::GetLine(SInt32 lineIndex)
|
||
|
{
|
||
|
|
||
|
if (lineIndex > -1 && lineIndex < fNumUsedLines)
|
||
|
{ return &fSDPLineArray[lineIndex];
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void SDPContainer::SetLine(SInt32 index)
|
||
|
{
|
||
|
if (index > -1 && index < fNumUsedLines)
|
||
|
{ fCurrentLine = index;
|
||
|
}
|
||
|
else
|
||
|
Assert(0);
|
||
|
|
||
|
}
|
||
|
|
||
|
void SDPContainer::Parse()
|
||
|
{
|
||
|
char* validChars = "vosiuepcbtrzkam";
|
||
|
char nameValueSeparator = '=';
|
||
|
|
||
|
Bool16 valid = true;
|
||
|
|
||
|
StringParser sdpParser(&fSDPBuffer);
|
||
|
StrPtrLen line;
|
||
|
StrPtrLen fieldName;
|
||
|
StrPtrLen space;
|
||
|
Bool16 foundLine = false;
|
||
|
|
||
|
while ( sdpParser.GetDataRemaining() != 0 )
|
||
|
{
|
||
|
foundLine = sdpParser.GetThruEOL(&line); // Read each line
|
||
|
if (!foundLine)
|
||
|
{ break;
|
||
|
}
|
||
|
StringParser lineParser(&line);
|
||
|
|
||
|
lineParser.ConsumeWhitespace();//skip over leading whitespace
|
||
|
if (lineParser.GetDataRemaining() == 0) // must be an empty line
|
||
|
continue;
|
||
|
|
||
|
char firstChar = lineParser.PeekFast();
|
||
|
if (firstChar == '\0')
|
||
|
continue; //skip over blank lines
|
||
|
|
||
|
fFieldStr[ (UInt8)firstChar] = firstChar;
|
||
|
switch (firstChar)
|
||
|
{
|
||
|
case 'v': fReqLines |= kV;
|
||
|
break;
|
||
|
|
||
|
case 's': fReqLines |= kS ;
|
||
|
break;
|
||
|
|
||
|
case 't': fReqLines |= kT ;
|
||
|
break;
|
||
|
|
||
|
case 'o': fReqLines |= kO ;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
lineParser.ConsumeUntil(&fieldName, nameValueSeparator);
|
||
|
if ((fieldName.Len != 1) || (::strchr(validChars, fieldName.Ptr[0]) == NULL))
|
||
|
{
|
||
|
valid = false; // line doesn't begin with one of the valid characters followed by an "="
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!lineParser.Expect(nameValueSeparator))
|
||
|
{
|
||
|
valid = false; // line doesn't have the "=" after the first char
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
lineParser.ConsumeUntil(&space, StringParser::sWhitespaceMask);
|
||
|
|
||
|
if (space.Len != 0)
|
||
|
{
|
||
|
valid = false; // line has whitespace after the "="
|
||
|
break;
|
||
|
}
|
||
|
AddHeaderLine(&line);
|
||
|
}
|
||
|
|
||
|
if (fNumUsedLines == 0) // didn't add any lines
|
||
|
{ valid = false;
|
||
|
}
|
||
|
fValid = valid;
|
||
|
|
||
|
}
|
||
|
|
||
|
void SDPContainer::Initialize()
|
||
|
{
|
||
|
fCurrentLine = 0;
|
||
|
fNumUsedLines = 0;
|
||
|
delete [] fSDPLineArray;
|
||
|
fSDPLineArray = NEW SDPLine[fNumSDPLines];
|
||
|
fValid = false;
|
||
|
fReqLines = 0;
|
||
|
::memset(fFieldStr, sizeof(fFieldStr), 0);
|
||
|
}
|
||
|
|
||
|
Bool16 SDPContainer::SetSDPBuffer(char *sdpBuffer)
|
||
|
{
|
||
|
|
||
|
Initialize();
|
||
|
if (sdpBuffer != NULL)
|
||
|
{ fSDPBuffer.Set(sdpBuffer);
|
||
|
Parse();
|
||
|
}
|
||
|
|
||
|
return IsSDPBufferValid();
|
||
|
}
|
||
|
|
||
|
Bool16 SDPContainer::SetSDPBuffer(StrPtrLen *sdpBufferPtr)
|
||
|
{
|
||
|
Initialize();
|
||
|
if (sdpBufferPtr != NULL)
|
||
|
{ fSDPBuffer.Set(sdpBufferPtr->Ptr, sdpBufferPtr->Len);
|
||
|
Parse();
|
||
|
}
|
||
|
|
||
|
return IsSDPBufferValid();
|
||
|
}
|
||
|
|
||
|
|
||
|
void SDPContainer::PrintLine(SInt32 lineIndex)
|
||
|
{
|
||
|
StrPtrLen *printLinePtr = GetLine(lineIndex);
|
||
|
if (printLinePtr)
|
||
|
{ printLinePtr->PrintStr();
|
||
|
qtss_printf("\n");
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void SDPContainer::PrintAllLines()
|
||
|
{
|
||
|
if (fNumUsedLines > 0)
|
||
|
{ for (int i = 0; i < fNumUsedLines; i++)
|
||
|
PrintLine(i);
|
||
|
}
|
||
|
else
|
||
|
qtss_printf("SDPContainer::PrintAllLines no lines\n");
|
||
|
}
|
||
|
|
||
|
Bool16 SDPLineSorter::ValidateSessionHeader(StrPtrLen *theHeaderLinePtr)
|
||
|
{
|
||
|
if (NULL == theHeaderLinePtr || 0 == theHeaderLinePtr->Len || NULL== theHeaderLinePtr->Ptr)
|
||
|
return false;
|
||
|
|
||
|
// check for a duplicate range line.
|
||
|
StrPtrLen currentSessionHeader(fSDPSessionHeaders.GetBufPtr(), fSDPSessionHeaders.GetBytesWritten());
|
||
|
if ( 'a' == theHeaderLinePtr->Ptr[0] && theHeaderLinePtr->FindString("a=range") && currentSessionHeader.FindString("a=range"))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
char SDPLineSorter::sSessionOrderedLines[] = "vosiuepcbtrzka"; // chars are order dependent: declared by rfc 2327
|
||
|
char SDPLineSorter::sessionSingleLines[] = "vtosiuepcbzk"; // return only 1 of each of these session field types
|
||
|
StrPtrLen SDPLineSorter::sEOL("\r\n");
|
||
|
StrPtrLen SDPLineSorter::sMaxBandwidthTag("b=AS:");
|
||
|
|
||
|
SDPLineSorter::SDPLineSorter(SDPContainer *rawSDPContainerPtr, Float32 adjustMediaBandwidthPercent, SDPContainer *insertMediaLinesArray) : fSessionLineCount(0),fSDPSessionHeaders(NULL,0), fSDPMediaHeaders(NULL,0)
|
||
|
{
|
||
|
|
||
|
Assert(rawSDPContainerPtr != NULL);
|
||
|
if (NULL == rawSDPContainerPtr)
|
||
|
return;
|
||
|
|
||
|
StrPtrLen theSDPData(rawSDPContainerPtr->fSDPBuffer.Ptr,rawSDPContainerPtr->fSDPBuffer.Len);
|
||
|
StrPtrLen *theMediaStart = rawSDPContainerPtr->GetLine(rawSDPContainerPtr->FindHeaderLineType('m',0));
|
||
|
if (theMediaStart && theMediaStart->Ptr && theSDPData.Ptr)
|
||
|
{
|
||
|
UInt32 mediaLen = theSDPData.Len - (UInt32) (theMediaStart->Ptr - theSDPData.Ptr);
|
||
|
char *mediaStartPtr= theMediaStart->Ptr;
|
||
|
fMediaHeaders.Set(mediaStartPtr,mediaLen);
|
||
|
StringParser sdpParser(&fMediaHeaders);
|
||
|
SDPLine sdpLine;
|
||
|
Bool16 foundLine = false;
|
||
|
Bool16 newMediaSection = true;
|
||
|
SDPLine *insertLine = NULL;
|
||
|
|
||
|
while (sdpParser.GetDataRemaining() > 0)
|
||
|
{
|
||
|
foundLine = sdpParser.GetThruEOL(&sdpLine);
|
||
|
if (!foundLine)
|
||
|
{ break;
|
||
|
}
|
||
|
if (sdpLine.GetHeaderType() == 'm' )
|
||
|
newMediaSection = true;
|
||
|
|
||
|
if (insertMediaLinesArray && newMediaSection && (sdpLine.GetHeaderType() == 'a') )
|
||
|
{
|
||
|
newMediaSection = false;
|
||
|
for (insertLine = insertMediaLinesArray->GetLine(0); insertLine ; insertLine = insertMediaLinesArray->GetNextLine() )
|
||
|
fSDPMediaHeaders.Put(*insertLine);
|
||
|
}
|
||
|
|
||
|
if ( ( 'b' == sdpLine.GetHeaderType()) && (1.0 != adjustMediaBandwidthPercent) )
|
||
|
{
|
||
|
StringParser bLineParser(&sdpLine);
|
||
|
bLineParser.ConsumeUntilDigit();
|
||
|
UInt32 bandwidth = (UInt32) (.5 + (adjustMediaBandwidthPercent * (Float32) bLineParser.ConsumeInteger() ) );
|
||
|
if (bandwidth < 1)
|
||
|
bandwidth = 1;
|
||
|
|
||
|
char bandwidthStr[10];
|
||
|
qtss_snprintf(bandwidthStr,sizeof(bandwidthStr) -1, "%"_U32BITARG_"", bandwidth);
|
||
|
bandwidthStr[sizeof(bandwidthStr) -1] = 0;
|
||
|
|
||
|
fSDPMediaHeaders.Put(sMaxBandwidthTag);
|
||
|
fSDPMediaHeaders.Put(bandwidthStr);
|
||
|
}
|
||
|
else
|
||
|
fSDPMediaHeaders.Put(sdpLine);
|
||
|
|
||
|
fSDPMediaHeaders.Put(SDPLineSorter::sEOL);
|
||
|
}
|
||
|
fMediaHeaders.Set(fSDPMediaHeaders.GetBufPtr(),fSDPMediaHeaders.GetBytesWritten());
|
||
|
}
|
||
|
|
||
|
fSessionLineCount = rawSDPContainerPtr->FindHeaderLineType('m',0);
|
||
|
if (fSessionLineCount < 0) // didn't find it use the whole buffer
|
||
|
{ fSessionLineCount = rawSDPContainerPtr->GetNumLines();
|
||
|
}
|
||
|
|
||
|
for (SInt16 sessionLineIndex = 0; sessionLineIndex < fSessionLineCount; sessionLineIndex++)
|
||
|
fSessionSDPContainer.AddHeaderLine( (StrPtrLen *) rawSDPContainerPtr->GetLine(sessionLineIndex));
|
||
|
|
||
|
//qtss_printf("\nSession raw Lines:\n"); fSessionSDPContainer.PrintAllLines();
|
||
|
|
||
|
SInt16 numHeaderTypes = sizeof(SDPLineSorter::sSessionOrderedLines) -1;
|
||
|
Bool16 addLine = true;
|
||
|
for (SInt16 fieldTypeIndex = 0; fieldTypeIndex < numHeaderTypes; fieldTypeIndex ++)
|
||
|
{
|
||
|
SInt32 lineIndex = fSessionSDPContainer.FindHeaderLineType(SDPLineSorter::sSessionOrderedLines[fieldTypeIndex], 0);
|
||
|
StrPtrLen *theHeaderLinePtr = fSessionSDPContainer.GetLine(lineIndex);
|
||
|
|
||
|
while (theHeaderLinePtr != NULL)
|
||
|
{
|
||
|
addLine = this->ValidateSessionHeader(theHeaderLinePtr);
|
||
|
if (addLine)
|
||
|
{
|
||
|
fSDPSessionHeaders.Put(*theHeaderLinePtr);
|
||
|
fSDPSessionHeaders.Put(SDPLineSorter::sEOL);
|
||
|
}
|
||
|
|
||
|
if (NULL != ::strchr(sessionSingleLines, theHeaderLinePtr->Ptr[0] ) ) // allow 1 of this type: use first found
|
||
|
break; // move on to next line type
|
||
|
|
||
|
lineIndex = fSessionSDPContainer.FindHeaderLineType(SDPLineSorter::sSessionOrderedLines[fieldTypeIndex], lineIndex + 1);
|
||
|
theHeaderLinePtr = fSessionSDPContainer.GetLine(lineIndex);
|
||
|
}
|
||
|
}
|
||
|
fSessionHeaders.Set(fSDPSessionHeaders.GetBufPtr(),fSDPSessionHeaders.GetBytesWritten());
|
||
|
|
||
|
}
|
||
|
|
||
|
char* SDPLineSorter::GetSortedSDPCopy()
|
||
|
{
|
||
|
char* fullbuffCopy = NEW char[fSessionHeaders.Len + fMediaHeaders.Len + 2];
|
||
|
SInt32 buffPos = 0;
|
||
|
memcpy(&fullbuffCopy[buffPos], fSessionHeaders.Ptr,fSessionHeaders.Len);
|
||
|
buffPos += fSessionHeaders.Len;
|
||
|
memcpy(&fullbuffCopy[buffPos], fMediaHeaders.Ptr,fMediaHeaders.Len);
|
||
|
buffPos += fMediaHeaders.Len;
|
||
|
fullbuffCopy[buffPos] = 0;
|
||
|
|
||
|
return fullbuffCopy;
|
||
|
}
|
||
|
|
||
|
|