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