Darwin-Streaming-Server/CommonUtilitiesLib/QueryParamList.cpp
Darren VanBuren 849723c9cf Add even more of the source
This should be about everything needed to build so far?
2017-03-07 17:14:16 -08:00

264 lines
7.4 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 "QueryParamList.h"
#include "StringParser.h"
#include "OSMemory.h"
#include <string.h>
#include <stdlib.h>
#include "SafeStdLib.h"
QueryParamList::QueryParamList( StrPtrLen* querySPL )
{
// ctor from StrPtrLen
fNameValueQueryParamlist = NEW PLDoubleLinkedList<QueryParamListElement>;
this->BulidList( querySPL );
}
QueryParamList::QueryParamList( char* queryString )
{
// ctor from char*
StrPtrLen querySPL( queryString );
fNameValueQueryParamlist = NEW PLDoubleLinkedList<QueryParamListElement>;
this->BulidList( &querySPL );
}
void QueryParamList::BulidList( StrPtrLen* querySPL )
{
// parse the string and build the name/value list from the tokens.
// the string is a 'form' encoded query string ( see rfc - 1808 )
StringParser queryParser( querySPL );
while ( queryParser.GetDataRemaining() > 0 )
{
StrPtrLen theCGIParamName;
StrPtrLen theCGIParamValue;
queryParser.ConsumeUntil(&theCGIParamName, '='); // leaves "=..." in cgiParser, puts item keywd in theCGIParamName
if ( queryParser.GetDataRemaining() > 1 )
{
queryParser.ConsumeLength(&theCGIParamValue, 1 ); // the '='
queryParser.ConsumeUntil(&theCGIParamValue, '&'); // our value will end by here...
AddNameValuePairToList( theCGIParamName.GetAsCString(), theCGIParamValue.GetAsCString() );
queryParser.ConsumeLength(&theCGIParamValue, 1 ); // the '='
}
}
}
static void PrintNameAndValue( PLDoubleLinkedListNode<QueryParamListElement> *node, void *userData )
{
// used by QueryParamList::PrintAll
QueryParamListElement* nvPair = node->fElement;
qtss_printf( "qpl: %s, name %s, val %s\n", (char*)userData, nvPair->mName, nvPair->mValue );
}
void QueryParamList::PrintAll( char *idString )
{
// print name and value of each item in the list, print each pair preceded by "idString"
fNameValueQueryParamlist->ForEach( PrintNameAndValue, idString );
}
static bool CompareStrToName( PLDoubleLinkedListNode<QueryParamListElement> *node, void *userData )
{
/*
make a case insenstitive comparison between "node" name and the userData
used by QueryParamList::DoFindCGIValueForParam
*/
QueryParamListElement* nvPair = node->fElement;
StrPtrLen name( nvPair->mName );
if ( name.EqualIgnoreCase( (char*)userData, strlen( (char*)userData ) ) )
return true;
return false;
}
const char *QueryParamList::DoFindCGIValueForParam( char *name )
{
/*
return the first value where the paramter name matches "name"
use case insenstitive comparison
*/
PLDoubleLinkedListNode<QueryParamListElement>* node;
node = fNameValueQueryParamlist->ForEachUntil( CompareStrToName, name );
if ( node != NULL )
{
QueryParamListElement* nvPair = (QueryParamListElement*)node->fElement;
return nvPair->mValue;
}
return NULL;
}
void QueryParamList::AddNameValuePairToList( char* name, char* value )
{
// add the name/value pair to the by creating the holder struct
// then adding that as the element in the linked list
PLDoubleLinkedListNode<QueryParamListElement>* nvNode;
QueryParamListElement* nvPair;
this->DecodeArg( name );
this->DecodeArg( value );
nvPair = NEW QueryParamListElement( name, value );
// create a node to hold the pair
nvNode = NEW PLDoubleLinkedListNode<QueryParamListElement> ( nvPair );
// add it to the list
fNameValueQueryParamlist->AddNode( nvNode );
}
void QueryParamList::DecodeArg( char *ioCodedPtr )
{
// perform In-Place &hex and + to space decoding of the parameter
// on input, ioCodedPtr mau contain encoded text, on exit ioCodedPtr will be plain text
// on % decoding errors, the
if ( !ioCodedPtr )
return;
char* destPtr;
char* curChar;
short lineState = kLastWasText;
char hexBuff[32];
destPtr = curChar = ioCodedPtr;
while( *curChar )
{
switch( lineState )
{
case kRcvHexDigitOne:
if ( IsHex( *curChar ) )
{
hexBuff[3] = *curChar;
hexBuff[4] = 0;
*destPtr++ = (char)::strtoul( hexBuff, NULL, 0 );
}
else
{ // not a valid encoding
*destPtr++ = '%'; // put back the pct sign
*destPtr++ = hexBuff[2]; // put back the first digit too.
*destPtr++ = *curChar; // and this one!
}
lineState = kLastWasText;
break;
case kLastWasText:
if ( *curChar == '%' )
lineState = kPctEscape;
else
{
if ( *curChar == '+' )
*destPtr++ = ' ';
else
*destPtr++ = *curChar;
}
break;
case kPctEscape:
if ( *curChar == '%' )
{
*destPtr++ = '%';
lineState = kLastWasText;
}
else
{
if ( IsHex( *curChar ) )
{
hexBuff[0] = '0';
hexBuff[1] = 'x';
hexBuff[2] = *curChar;
lineState = kRcvHexDigitOne;
}
else
{
*destPtr++ = '%'; // put back the pct sign
*destPtr++ = *curChar; // and this one!
lineState = kLastWasText;
}
}
break;
}
curChar++;
}
*destPtr = *curChar;
}
Bool16 QueryParamList::IsHex( char c )
{
// return true if char c is a valid hexidecimal digit
// false otherwise.
if ( c >= '0' && c <= '9' )
return true;
if ( c >= 'A' && c <= 'F' )
return true;
if ( c >= 'a' && c <= 'f' )
return true;
return false;
}