| /*============================================================================== | |
| ds_ASString.cpp | |
| GENERAL DESCRIPTION | |
| A string class with utility functions for parsing AS. | |
| EXTERNALIZED FUNCTIONS | |
| INITIALIZATION AND SEQUENCING REQUIREMENTS | |
| None | |
| Copyright (c) 2014 by Qualcomm Technologies Incorporated. All Rights Reserved. | |
| ==============================================================================*/ | |
| /*============================================================================== | |
| EDIT HISTORY FOR MODULE | |
| This section contains comments describing changes made to the module. | |
| Notice that changes are listed in reverse chronological order. | |
| when who what, where, why | |
| -------- --- ---------------------------------------------------------- | |
| 05/20/15 ml Use memory from modem heap | |
| 04/21/14 ml Created file/Initial version. | |
| ==============================================================================*/ | |
| #include "ds_ASString.h" | |
| //#include "ds_appsrv_mem.h" | |
| //#include "data_msg.h" | |
| #include "mbtk_type.h" | |
| #include <string.h> | |
| #include <stdlib.h> | |
| #include <cctype> // isspace, tolower | |
| // #define DS_ASSTRING_MAX_LEN 4294967295 // uint32 max | |
| #define DS_ASSTRING_MAX_LEN 400000 | |
| static const char AS_ESCAPE_MARK = '&'; | |
| static const char EMPTY_STRING[] = ""; | |
| static const char* ESCAPE_CHARS[] = {"<", ">", "&", "'", """}; | |
| static const char UNESCAPE_CHARS[] = {'<', '>', '&', '\'', '"'}; | |
| static const uint32 NUM_ESCAPE_CHARS = 5; | |
| static bool has_string_at_start(const char* buf, const char* cmp); | |
| static void memscpy(void* dest, size_t destLen, const void* src, size_t srcLen) { | |
| if (srcLen <= destLen) | |
| memcpy(dest, src, srcLen); | |
| } | |
| ASString::ASString() | |
| : str(NULL) { } | |
| ASString::ASString(const char* src) | |
| : str(NULL) | |
| { | |
| if(NULL == src) | |
| { | |
| str = NULL; | |
| return; | |
| } | |
| copy_string(src, strlen(src)); | |
| } | |
| ASString::ASString(const char* src, uint32 len) | |
| : str(NULL) | |
| { | |
| copy_string(src, len); | |
| } | |
| // copy constructor | |
| ASString::ASString(ASString& src) | |
| : str(NULL) | |
| { | |
| copy_string(src.c_str(), src.size()); | |
| } | |
| ASString::ASString(const ASString& src) | |
| : str(NULL) | |
| { | |
| copy_string(src.c_str(), src.size()); | |
| } | |
| ASString::~ASString() | |
| { | |
| if(NULL != str) | |
| { | |
| free(str); | |
| } | |
| } | |
| // Assumes this->str with no memory allocated | |
| void ASString::copy_string(const char* src, uint32 len) | |
| { | |
| if(NULL == src || 0 == len) | |
| { | |
| str = NULL; | |
| return; | |
| } | |
| if(len > DS_ASSTRING_MAX_LEN) | |
| return; | |
| str = (char*)malloc(sizeof(char) * (len + 1)); | |
| if(NULL != str) | |
| { | |
| memscpy(str, len, src, len); | |
| } | |
| } | |
| ASString& ASString::operator=(const ASString& rhs) | |
| { | |
| if(&rhs != this) | |
| { | |
| if(NULL != str) | |
| { | |
| free(str); | |
| str = NULL; | |
| } | |
| if(NULL == rhs.str) | |
| str = NULL; | |
| else | |
| copy_string(rhs.str, rhs.size()); | |
| } | |
| return *this; | |
| } | |
| ASString& ASString::operator=(const char* rhs) | |
| { | |
| if(NULL != str) | |
| { | |
| free(str); | |
| str = NULL; | |
| } | |
| if(NULL == rhs) | |
| str = NULL; | |
| else | |
| copy_string(rhs, strlen(rhs)); | |
| return *this; | |
| } | |
| char ASString::operator[](const int index) const | |
| { | |
| return str[index]; | |
| } | |
| char& ASString::operator[](int index) | |
| { | |
| return str[index]; | |
| } | |
| const char* ASString::c_str() const | |
| { | |
| if(NULL == str) | |
| return EMPTY_STRING; | |
| return str; | |
| } | |
| uint32 ASString::size() const | |
| { | |
| return length(); | |
| } | |
| uint32 ASString::length() const | |
| { | |
| if(NULL == str) | |
| return 0; | |
| return (uint32)strlen(str); | |
| } | |
| bool ASString::empty() const | |
| { | |
| return (0 == length()); | |
| } | |
| void ASString::remove_trailing_spaces() | |
| { | |
| uint32 end = length(); | |
| if(0 == end) | |
| return; | |
| while(0 != end) | |
| { | |
| if(!isspace(str[--end])) | |
| { | |
| end++; | |
| break; | |
| } | |
| } | |
| str[end] = '\0'; | |
| } | |
| bool ASString::resolve_xml_escapes() | |
| { | |
| bool replaced = false; | |
| uint32 counter = 0; | |
| uint32 len = length(); | |
| char* buf = str; | |
| char* new_str = NULL; | |
| if(0 == len) | |
| return true; | |
| new_str = (char*)malloc(sizeof(char) * (len + 1) ); | |
| if(NULL == new_str) | |
| return true; | |
| while('\0' != *buf && counter < len) | |
| { | |
| if(AS_ESCAPE_MARK == *buf) | |
| { | |
| replaced = false; | |
| for(uint32 i=0; i<NUM_ESCAPE_CHARS; i++) | |
| { | |
| if(has_string_at_start(buf, ESCAPE_CHARS[i])) | |
| { | |
| new_str[counter++] = UNESCAPE_CHARS[i]; | |
| buf += strlen(ESCAPE_CHARS[i]); | |
| replaced = true; | |
| break; | |
| } | |
| } | |
| if(!replaced) | |
| { | |
| free(new_str); | |
| return false; | |
| } | |
| } | |
| else | |
| { | |
| new_str[counter++] = *buf; | |
| buf++; | |
| } | |
| } | |
| free(str); | |
| str = new_str; | |
| return true; | |
| } | |
| void ASString::to_lower() | |
| { | |
| uint32 len = length(); | |
| for(uint32 i = 0; i < len; ++i) | |
| { | |
| str[i] = tolower(str[i]); | |
| } | |
| } | |
| bool ASString::limit_cmp(const char* cstr, const uint32 len) const | |
| { | |
| return (0 == strncmp(str, cstr, len)); | |
| } | |
| void ASString::append(const char* append_str) | |
| { | |
| if(NULL == append_str) | |
| return; | |
| append(append_str, strlen(append_str)); | |
| } | |
| void ASString::append(const char* append_str, const uint32 len) | |
| { | |
| uint32 prev_size, new_size; | |
| if(NULL == append_str) | |
| return; | |
| if(strlen(append_str) < len || 0 == len) | |
| return; | |
| prev_size = length(); | |
| new_size = prev_size + len + 1; | |
| if(new_size < prev_size || new_size < len || DS_ASSTRING_MAX_LEN < new_size) // overflow? | |
| { | |
| printf("append - append size too long"); | |
| return; | |
| } | |
| char* tmp = (char*)malloc(sizeof(char) * new_size); | |
| if(NULL == tmp) | |
| { | |
| printf("append - Failed to allocate memory for result string"); | |
| return; | |
| } | |
| if(NULL != str) | |
| { | |
| // copy the current string to the new string. | |
| memscpy(tmp, new_size, str, prev_size); | |
| free(str); | |
| str = NULL; | |
| } | |
| // add the new string | |
| memscpy(tmp+prev_size, new_size - prev_size, append_str, len); | |
| str = tmp; | |
| } | |
| void ASString::append(const ASString& append_str) | |
| { | |
| if(append_str.empty()) | |
| return; | |
| append(append_str.c_str(), append_str.length()); | |
| } | |
| bool operator== (const ASString& lhs, const ASString& rhs) | |
| { | |
| return (0 == strcasecmp(lhs.c_str(), rhs.c_str())); | |
| } | |
| bool operator!= (const ASString& lhs, const ASString& rhs) | |
| { | |
| return (0 != strcasecmp(lhs.c_str(), rhs.c_str())); | |
| } | |
| bool operator== (const ASString& lhs, const char* rhs) | |
| { | |
| return (0 == strcasecmp(lhs.c_str(), rhs)); | |
| } | |
| bool operator!= (const ASString& lhs, const char* rhs) | |
| { | |
| return (0 != strcasecmp(lhs.c_str(), rhs)); | |
| } | |
| /* | |
| res < 0 if lhs < rhs | |
| res == 0 if lhs == rhs | |
| res > 0 if lhs < rhs | |
| */ | |
| bool operator< (const ASString& lhs, const ASString& rhs) | |
| { | |
| return (0 > strcasecmp(lhs.c_str(), rhs.c_str())); | |
| } | |
| bool operator> (const ASString& lhs, const ASString& rhs) | |
| { | |
| return (0 < strcasecmp(lhs.c_str(), rhs.c_str())); | |
| } | |
| static bool has_string_at_start(const char* buf, const char* cmp) | |
| { | |
| return (0 == strncasecmp(buf, cmp, strlen(cmp))); | |
| } | |