/* * * @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 #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