Darwin-Streaming-Server/CommonUtilitiesLib/SDPUtils.cpp

371 lines
11 KiB
C++
Raw Normal View History

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