565 lines
15 KiB
C++
565 lines
15 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@
|
|
*
|
|
*/
|
|
/*
|
|
File: StrPtrLen.cpp
|
|
|
|
Contains: Implementation of class defined in StrPtrLen.h.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
#include <ctype.h>
|
|
#include "StrPtrLen.h"
|
|
#include "MyAssert.h"
|
|
#include "OS.h"
|
|
#include "OSMemory.h"
|
|
|
|
|
|
UInt8 StrPtrLen::sCaseInsensitiveMask[] =
|
|
{
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, //0-9
|
|
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, //10-19
|
|
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, //20-29
|
|
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, //30-39
|
|
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, //40-49
|
|
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, //50-59
|
|
60, 61, 62, 63, 64, 97, 98, 99, 100, 101, //60-69 //stop on every character except a letter
|
|
102, 103, 104, 105, 106, 107, 108, 109, 110, 111, //70-79
|
|
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, //80-89
|
|
122, 91, 92, 93, 94, 95, 96, 97, 98, 99, //90-99
|
|
100, 101, 102, 103, 104, 105, 106, 107, 108, 109, //100-109
|
|
110, 111, 112, 113, 114, 115, 116, 117, 118, 119, //110-119
|
|
120, 121, 122, 123, 124, 125, 126, 127, 128, 129 //120-129
|
|
};
|
|
|
|
UInt8 StrPtrLen::sNonPrintChars[] =
|
|
{
|
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, //0-9 // stop
|
|
0, 1, 1, 0, 1, 1, 1, 1, 1, 1, //10-19 //'\r' & '\n' are not stop conditions
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //20-29
|
|
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, //30-39
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40-49
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //50-59
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //60-69
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //70-79
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //80-89
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //90-99
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //100-109
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //110-119
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //120-129
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //130-139
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140-149
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150-159
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160-169
|
|
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, //170-179
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //180-189
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //190-199
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //200-209
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //210-219
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //220-229
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //230-239
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //240-249
|
|
1, 1, 1, 1, 1, 1 //250-255
|
|
};
|
|
|
|
char* StrPtrLen::GetAsCString() const
|
|
{
|
|
// convert to a "NEW'd" zero terminated char array
|
|
// caler is reponsible for the newly allocated memory
|
|
char *theString = NEW char[Len+1];
|
|
|
|
if ( Ptr && Len > 0 )
|
|
::memcpy( theString, Ptr, Len );
|
|
|
|
theString[Len] = 0;
|
|
|
|
return theString;
|
|
}
|
|
|
|
|
|
Bool16 StrPtrLen::Equal(const StrPtrLen &compare) const
|
|
{
|
|
if (NULL == compare.Ptr && NULL == Ptr )
|
|
return true;
|
|
|
|
if ((NULL == compare.Ptr) || (NULL == Ptr))
|
|
return false;
|
|
|
|
if ((compare.Len == Len) && (memcmp(compare.Ptr, Ptr, Len) == 0))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
Bool16 StrPtrLen::Equal(const char* compare) const
|
|
{
|
|
if (NULL == compare && NULL == Ptr )
|
|
return true;
|
|
|
|
if ((NULL == compare) || (NULL == Ptr))
|
|
return false;
|
|
|
|
if ((::strlen(compare) == Len) && (memcmp(compare, Ptr, Len) == 0))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
Bool16 StrPtrLen::NumEqualIgnoreCase(const char* compare, const UInt32 len) const
|
|
{
|
|
// compare thru the first "len: bytes
|
|
Assert(compare != NULL);
|
|
|
|
if (len <= Len)
|
|
{
|
|
for (UInt32 x = 0; x < len; x++)
|
|
if (sCaseInsensitiveMask[ (UInt8) Ptr[x]] != sCaseInsensitiveMask[(UInt8) compare[x]])
|
|
return false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Bool16 StrPtrLen::EqualIgnoreCase(const char* compare, const UInt32 len) const
|
|
{
|
|
Assert(compare != NULL);
|
|
if (len == Len)
|
|
{
|
|
for (UInt32 x = 0; x < len; x++)
|
|
if (sCaseInsensitiveMask[(UInt8) Ptr[x]] != sCaseInsensitiveMask[(UInt8) compare[x]])
|
|
return false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
char *StrPtrLen::FindStringCase(char *queryCharStr, StrPtrLen *resultStr, Bool16 caseSensitive) const
|
|
{
|
|
// Be careful about exiting this method from the middle. This routine deletes allocated memory at the end.
|
|
//
|
|
|
|
if (resultStr)
|
|
resultStr->Set(NULL,0);
|
|
|
|
Assert (NULL != queryCharStr);
|
|
if (NULL == queryCharStr) return NULL;
|
|
if (NULL == Ptr) return NULL;
|
|
if (0 == Len) return NULL;
|
|
|
|
|
|
StrPtrLen queryStr(queryCharStr);
|
|
char *editSource = NULL;
|
|
char *resultChar = NULL;
|
|
char lastSourceChar = Ptr[Len -1];
|
|
|
|
if (lastSourceChar != 0) // need to modify for termination.
|
|
{ editSource = NEW char[Len + 1]; // Ptr could be a static string so make a copy
|
|
::memcpy( editSource, Ptr, Len );
|
|
editSource[Len] = 0; // this won't work on static strings so we are modifing a new string here
|
|
}
|
|
|
|
char *queryString = queryCharStr;
|
|
char *dupSourceString = NULL;
|
|
char *dupQueryString = NULL;
|
|
char *sourceString = Ptr;
|
|
UInt32 foundLen = 0;
|
|
|
|
if (editSource != NULL) // a copy of the source ptr and len 0 terminated
|
|
sourceString = editSource;
|
|
|
|
if (!caseSensitive)
|
|
{ dupSourceString = ::strdup(sourceString);
|
|
dupQueryString = ::strdup(queryCharStr);
|
|
if (dupSourceString && dupQueryString)
|
|
{ sourceString = StrPtrLen(dupSourceString).ToUpper();
|
|
queryString = StrPtrLen(dupQueryString).ToUpper();
|
|
resultChar = ::strstr(sourceString,queryString);
|
|
|
|
::free(dupSourceString);
|
|
::free(dupQueryString);
|
|
}
|
|
}
|
|
else
|
|
{ resultChar = ::strstr(sourceString,queryString);
|
|
}
|
|
|
|
if (resultChar != NULL) // get the start offset
|
|
{ foundLen = resultChar - sourceString;
|
|
resultChar = Ptr + foundLen; // return a pointer in the source buffer
|
|
if (resultChar > (Ptr + Len)) // make sure it is in the buffer
|
|
resultChar = NULL;
|
|
}
|
|
|
|
if (editSource != NULL)
|
|
delete [] editSource;
|
|
|
|
if (resultStr != NULL && resultChar != NULL)
|
|
resultStr->Set(resultChar,queryStr.Len);
|
|
|
|
#if STRPTRLENTESTING
|
|
qtss_printf("StrPtrLen::FindStringCase found string=%s\n",resultChar);
|
|
#endif
|
|
|
|
return resultChar;
|
|
}
|
|
|
|
|
|
UInt32 StrPtrLen::RemoveWhitespace()
|
|
{
|
|
if (Ptr == NULL || Len == 0)
|
|
return 0;
|
|
|
|
char *EndPtr = Ptr + Len; // one past last char
|
|
char *destPtr = Ptr;
|
|
char *srcPtr = Ptr;
|
|
|
|
Len = 0;
|
|
while (srcPtr < EndPtr)
|
|
{
|
|
|
|
if (*srcPtr != ' ' && *srcPtr != '\t')
|
|
{
|
|
if (srcPtr != destPtr)
|
|
*destPtr = *srcPtr;
|
|
|
|
destPtr++;
|
|
Len ++;
|
|
}
|
|
srcPtr ++;
|
|
}
|
|
|
|
return Len;
|
|
}
|
|
|
|
UInt32 StrPtrLen::TrimLeadingWhitespace()
|
|
{
|
|
if (Ptr == NULL || Len == 0)
|
|
return 0;
|
|
|
|
char *EndPtr = Ptr + Len; //one past last char
|
|
|
|
while (Ptr < EndPtr)
|
|
{
|
|
if (*Ptr != ' ' && *Ptr != '\t')
|
|
break;
|
|
|
|
Ptr += 1;
|
|
Len -= 1;
|
|
}
|
|
|
|
return Len;
|
|
}
|
|
|
|
UInt32 StrPtrLen::TrimTrailingWhitespace()
|
|
{
|
|
if (Ptr == NULL || Len == 0)
|
|
return 0;
|
|
|
|
char *theCharPtr = Ptr + (Len - 1); // last char
|
|
|
|
while (theCharPtr >= Ptr)
|
|
{
|
|
if (*theCharPtr != ' ' && *theCharPtr != '\t')
|
|
break;
|
|
|
|
theCharPtr -= 1;
|
|
Len -= 1;
|
|
}
|
|
|
|
return Len;
|
|
}
|
|
|
|
void StrPtrLen::PrintStr()
|
|
{
|
|
char *thestr = GetAsCString();
|
|
|
|
UInt32 i = 0;
|
|
for (; i < Len; i ++)
|
|
{
|
|
if (StrPtrLen::sNonPrintChars[(UInt8) Ptr[i]])
|
|
{ thestr[i] = 0;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (thestr != NULL)
|
|
{
|
|
qtss_printf(thestr);
|
|
delete thestr;
|
|
}
|
|
}
|
|
|
|
void StrPtrLen::PrintStr(char *appendStr)
|
|
{
|
|
StrPtrLen::PrintStr();
|
|
if (appendStr != NULL)
|
|
qtss_printf(appendStr);
|
|
}
|
|
|
|
void StrPtrLen::PrintStr(char* prependStr, char *appendStr)
|
|
{
|
|
if (prependStr != NULL)
|
|
qtss_printf(prependStr);
|
|
|
|
StrPtrLen::PrintStr();
|
|
|
|
if (appendStr != NULL)
|
|
qtss_printf(appendStr);
|
|
}
|
|
|
|
|
|
void StrPtrLen::PrintStrEOL(char* stopStr, char *appendStr)
|
|
{
|
|
|
|
|
|
char *thestr = GetAsCString();
|
|
|
|
SInt32 i = 0;
|
|
for (; i < (SInt32) Len; i ++)
|
|
{
|
|
if (StrPtrLen::sNonPrintChars[(UInt8) Ptr[i]])
|
|
{ thestr[i] = 0;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; thestr[i] != 0 ; i ++)
|
|
{
|
|
if (thestr[i] == '%' && thestr[i+1] != '%' )
|
|
{ thestr[i] = '$';
|
|
}
|
|
}
|
|
|
|
SInt32 stopLen = 0;
|
|
if (stopStr != NULL)
|
|
stopLen = ::strlen(stopStr);
|
|
|
|
if (stopLen > 0 && stopLen <= i)
|
|
{
|
|
char* stopPtr = ::strstr(thestr, stopStr);
|
|
if (stopPtr != NULL)
|
|
{ stopPtr += stopLen;
|
|
*stopPtr = 0;
|
|
i = stopPtr - thestr;
|
|
}
|
|
}
|
|
|
|
char * theStrLine = thestr;
|
|
char * nextLine = NULL;
|
|
char * theChar = NULL;
|
|
static char *cr="\\r";
|
|
static char *lf="\\n\n";
|
|
SInt32 tempLen = i;
|
|
for (i = 0; i < tempLen; i ++)
|
|
{
|
|
if (theStrLine[i] == '\r')
|
|
{ theChar = cr;
|
|
theStrLine[i] = 0;
|
|
nextLine = &theStrLine[i+1];
|
|
}
|
|
else if (theStrLine[i] == '\n')
|
|
{ theChar = lf;
|
|
theStrLine[i] = 0;
|
|
nextLine = &theStrLine[i+1];
|
|
}
|
|
|
|
if (nextLine != NULL)
|
|
{
|
|
qtss_printf(theStrLine);
|
|
qtss_printf(theChar);
|
|
|
|
theStrLine = nextLine;
|
|
nextLine = NULL;
|
|
tempLen -= (i+1);
|
|
i = -1;
|
|
}
|
|
}
|
|
qtss_printf(theStrLine);
|
|
delete thestr;
|
|
|
|
if (appendStr != NULL)
|
|
qtss_printf(appendStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if STRPTRLENTESTING
|
|
Bool16 StrPtrLen::Test()
|
|
{
|
|
static char* test1 = "2347.;.][';[;]abcdefghijklmnopqrstuvwxyz#%#$$#";
|
|
static char* test2 = "2347.;.][';[;]ABCDEFGHIJKLMNOPQRSTUVWXYZ#%#$$#";
|
|
static char* test3 = "Content-Type:";
|
|
static char* test4 = "cONTent-TYPe:";
|
|
static char* test5 = "cONTnnt-TYPe:";
|
|
static char* test6 = "cONTent-TY";
|
|
|
|
static char* test7 = "ontent-Type:";
|
|
static char* test8 = "ONTent-TYPe:";
|
|
static char* test9 = "-TYPe:";
|
|
static char* test10 = ":";
|
|
|
|
StrPtrLen theVictim1(test1, strlen(test1));
|
|
if (!theVictim1.EqualIgnoreCase(test2, strlen(test2)))
|
|
return false;
|
|
|
|
if (theVictim1.EqualIgnoreCase(test3, strlen(test3)))
|
|
return false;
|
|
if (!theVictim1.EqualIgnoreCase(test1, strlen(test1)))
|
|
return false;
|
|
|
|
StrPtrLen theVictim2(test3, strlen(test3));
|
|
if (!theVictim2.EqualIgnoreCase(test4, strlen(test4)))
|
|
return false;
|
|
if (theVictim2.EqualIgnoreCase(test5, strlen(test5)))
|
|
return false;
|
|
if (theVictim2.EqualIgnoreCase(test6, strlen(test6)))
|
|
return false;
|
|
|
|
StrPtrLen outResultStr;
|
|
if (!theVictim1.FindStringIgnoreCase(test2, &outResultStr))
|
|
return false;
|
|
if (theVictim1.FindStringIgnoreCase(test3, &outResultStr))
|
|
return false;
|
|
if (!theVictim1.FindStringIgnoreCase(test1, &outResultStr))
|
|
return false;
|
|
if (!theVictim2.FindStringIgnoreCase(test4))
|
|
return false;
|
|
if (theVictim2.FindStringIgnoreCase(test5))
|
|
return false;
|
|
if (!theVictim2.FindStringIgnoreCase(test6))
|
|
return false;
|
|
if (!theVictim2.FindStringIgnoreCase(test7))
|
|
return false;
|
|
if (!theVictim2.FindStringIgnoreCase(test8))
|
|
return false;
|
|
if (!theVictim2.FindStringIgnoreCase(test9))
|
|
return false;
|
|
if (!theVictim2.FindStringIgnoreCase(test10))
|
|
return false;
|
|
|
|
if (theVictim1.FindString(test2, &outResultStr))
|
|
return false;
|
|
if (theVictim1.FindString(test3, &outResultStr))
|
|
return false;
|
|
if (!theVictim1.FindString(test1, &outResultStr))
|
|
return false;
|
|
if (theVictim2.FindString(test4))
|
|
return false;
|
|
if (theVictim2.FindString(test5))
|
|
return false;
|
|
if (theVictim2.FindString(test6))
|
|
return false;
|
|
if (!theVictim2.FindString(test7))
|
|
return false;
|
|
if (theVictim2.FindString(test8))
|
|
return false;
|
|
if (theVictim2.FindString(test9))
|
|
return false;
|
|
if (!theVictim2.FindString(test10))
|
|
return false;
|
|
|
|
StrPtrLen query;
|
|
query.Set(test2);
|
|
if (theVictim1.FindString(query, &outResultStr))
|
|
return false;
|
|
if (outResultStr.Len > 0)
|
|
return false;
|
|
if (outResultStr.Ptr != NULL)
|
|
return false;
|
|
|
|
query.Set(test3);
|
|
if (theVictim1.FindString(query, &outResultStr))
|
|
return false;
|
|
if (outResultStr.Len > 0)
|
|
return false;
|
|
if (outResultStr.Ptr != NULL)
|
|
return false;
|
|
|
|
query.Set(test1);
|
|
if (!theVictim1.FindString(query, &outResultStr))
|
|
return false;
|
|
if (!outResultStr.Equal(query))
|
|
return false;
|
|
|
|
query.Set(test4);
|
|
if (query.Equal(theVictim2.FindString(query)))
|
|
return false;
|
|
|
|
query.Set(test5);
|
|
if (query.Equal(theVictim2.FindString(query)))
|
|
return false;
|
|
|
|
query.Set(test6);
|
|
if (query.Equal(theVictim2.FindString(query)))
|
|
return false;
|
|
|
|
query.Set(test7);
|
|
if (!query.Equal(theVictim2.FindString(query)))
|
|
return false;
|
|
|
|
query.Set(test8);
|
|
if (query.Equal(theVictim2.FindString(query)))
|
|
return false;
|
|
|
|
query.Set(test9);
|
|
if (query.Equal(theVictim2.FindString(query)))
|
|
return false;
|
|
|
|
query.Set(test10);
|
|
if (!query.Equal(theVictim2.FindString(query)))
|
|
return false;
|
|
|
|
query.Set(test10);
|
|
if (!query.Equal(theVictim2.FindString(query)))
|
|
return false;
|
|
|
|
StrPtrLen partialStaticSource(test1,5);
|
|
query.Set("abcd");
|
|
if (query.Equal(partialStaticSource.FindString(query)))
|
|
return false;
|
|
|
|
query.Set("47");
|
|
if (query.Equal(partialStaticSource.FindString(query))) // success = !equal because the char str is longer than len
|
|
return false;
|
|
|
|
if (query.FindString(partialStaticSource.FindString(query))) // success = !found because the 0 term src is not in query
|
|
return false;
|
|
|
|
partialStaticSource.FindString(query,&outResultStr);
|
|
if (!outResultStr.Equal(query)) // success =found the result Ptr and Len is the same as the query
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
#endif
|