- Main Page
- Related Pages
- Classes
- Files
- Examples

- File List
- File Members

# skype-string.cpp

Go to the documentation of this file.

    00001
    00002 #include "skype-string.h"
    00003
    00004 #ifndef _GNU_SOURCE
    00005 #define _GNU_SOURCE
    00006 #endif
    00007
    00008 #include <stdlib.h>
    00009 #include <string.h>
    00010 #include <stdio.h>
    00011
    00012 #ifdef _WIN32
    00013 #ifndef snprintf
    00014     #define snprintf _snprintf
    00015 #endif
    00016 #ifndef strtoull
    00017     #define strtoull _strtoui64
    00018 #endif
    00019 #endif
    00020
    00021 /** \cond INTERNAL */
    00022 // Tune for "malloc count" vs. "total memory allocation" tradeoff
    00023 // Affects mostly string concatenation
    00024 // 0 means no preallocation
    00025 #ifndef SE_STRING_DELTA
    00026 #define SE_STRING_DELTA 0
    00027 #endif
    00028
    00029 // Used to adjust the malloc-ed size to the highest multiple of 16
    00030 #define CALC_SIZE(x) ((x) / 16 + 1) * 16 + 16 * SE_STRING_DELTA
    00031 // NB: original version: #define CALC_SIZE(x) (x) + 25
    00032
    00033 class SEString::Data
    00034 {
    00035 public:
    00036         unsigned int ref;
    00037         char* str;
    00038         size_t real_size;
    00039         bool isBin; // when true, the string contains binary data
    00040         SEMutex lock;
    00041 };
    00042
    00043 SEString::SEString(unsigned int buf)
    00044 {
    00045         d = new Data();
    00046
    00047         d->ref = 1;
    00048         // we don't add DELTA since this constructor is always called with the exact size of the string
    00049         d->str = (char*)malloc(buf + 1);
    00050         d->real_size = buf;
    00051         d->isBin = false;
    00052 }
    00053
    00054 // char    escaped
    00055 // "        \"
    00056 // ,        \,      (don't forget to escape commas as they are used to mark lists)
    00057 // \        \ \     (slash slash)
    00058 // 0x00     \0      (all null characters are translated to slash and zero (number zero))
    00059
    00060 SEString SEString::escape() const
    00061 {
    00062         if (isNull())
    00063                 return *this;
    00064
    00065         size_t new_size = 0;
    00066         size_t mylen = length();
    00067
    00068         for (size_t n = 0; n < mylen; n++) {
    00069                 if ((',' == d->str[n]) || ('"' == d->str[n]) ||('\\' == d->str[n]))
    00070                         new_size++;
    00071         }
    00072
    00073         new_size += mylen;
    00074
    00075         SEString str(new_size + 1);
    00076
    00077         char* s_from = d->str;
    00078         char* to = str.d->str;
    00079
    00080         while (*s_from) {
    00081                 if ((',' == *s_from) || ('"' == *s_from) || ('\\' == *s_from)) {
    00082                         *to = '\\';
    00083                         to++;
    00084                 }
    00085
    00086                 *to = *s_from;
    00087
    00088                 to++;
    00089                 s_from++;
    00090         }
    00091
    00092         *to = '\0';
    00093
    00094         return str;
    00095 }
    00096
    00097 SEString SEString::unescape() const
    00098 {
    00099         if (isNull())
    00100                 return *this;
    00101
    00102         size_t mylen = length();
    00103
    00104         SEString str(mylen + 1);
    00105
    00106         size_t to = 0;
    00107         size_t cur = 0;
    00108         size_t len = mylen;
    00109
    00110         while (cur < len) {
    00111                 if ('\\' == d->str[cur]) {
    00112                         cur++;
    00113                 }
    00114
    00115                 str.d->str[to++] = d->str[cur++];
    00116         }
    00117
    00118         str.d->str[to++] = '\0';
    00119
    00120         return str;
    00121 }
    00122
    00123 // custom function to optimize SEStringDict::format
    00124 const SEString SEString::keyValue(const SEString& key, const SEString& value) // static
    00125 {
    00126         if (key.isNull())
    00127                 return SEString();
    00128
    00129         size_t keylen = key.length();
    00130         size_t vallen = value.length();
    00131
    00132         SEString str(keylen + 2 + vallen + 3);
    00133
    00134         char * ptr = str.d->str;
    00135
    00136         strcpy(ptr, key.d->str);
    00137         ptr += keylen;
    00138         strcpy(ptr, "=\"");
    00139         ptr += 2;
    00140         if (!value.isNull()) { // or should we not send the pair at all?
    00141                 strcpy(ptr, value.d->str);
    00142                 ptr += vallen;
    00143         }
    00144         strcpy(ptr, "\" ");
    00145
    00146         return str;
    00147 }
    00148
    00149 void SEString::markAsBinary()
    00150 {
    00151         if (d) d->isBin = true;
    00152 }
    00153 /** \endcond */
    00154
    00155 SEString::operator const char*() const
    00156 {
    00157         static const char* str_null = "";
    00158
    00159         if (isNull())
    00160                 return str_null;
    00161         else
    00162                 return d->str;
    00163 }
    00164
    00165 size_t SEString::length() const
    00166 {
    00167         if (isNull())
    00168                 return 0;
    00169         else
    00170                 return strlen(d->str);
    00171 }
    00172
    00173 bool SEString::isBinary() const
    00174 {
    00175         return (d && d->isBin);
    00176 }
    00177
    00178 bool SEString::startWith(const SEString& str) const
    00179 {
    00180         if (isNull())
    00181                 return false;
    00182
    00183         size_t strlen = str.length();
    00184
    00185         if (!strlen) // same as (str.isEmpty())
    00186                 return true;
    00187
    00188         return (0 == strncmp(d->str, str.d->str, strlen));
    00189 }
    00190
    00191 SEString SEString::substr(int s_from, int to) const
    00192 {
    00193         if (isNull())
    00194                 return *this;
    00195
    00196         if (s_from < 0)
    00197                 s_from = 0;
    00198
    00199         size_t len = length();
    00200
    00201         if (to >= int(len))
    00202                 to = len - 1 ;
    00203
    00204         if (to < 0) {
    00205                 to = len + to - 1;
    00206         }
    00207
    00208         if (to < s_from) {
    00209                 int tmp = to;
    00210                 to = s_from;
    00211                 s_from = tmp;
    00212         }
    00213
    00214         int newl = to - s_from + 1;
    00215
    00216         SEString tmp(newl + 1);
    00217
    00218         strncpy(tmp.d->str, d->str + s_from, newl);
    00219         tmp.d->str[newl] = 0;
    00220
    00221         return tmp;
    00222 }
    00223
    00224 SEString SEString::right(unsigned int len) const
    00225 {
    00226         if (isNull())
    00227                 return *this;
    00228
    00229         size_t mylen = length();
    00230         if (len > mylen)
    00231                 len = mylen;
    00232
    00233         SEString tmp(len + 1);
    00234
    00235         strcpy(tmp.d->str, d->str + mylen - len);
    00236
    00237         return tmp;
    00238 }
    00239
    00240 SEString SEString::trim(const SEString& str) const
    00241 {
    00242         size_t strlen = str.length();
    00243
    00244         if (!strlen || !startWith(str)) // same as (str.isEmpty() || !startWith(str))
    00245                 return *this;
    00246         else
    00247                 return right(length() - strlen);
    00248 }
    00249
    00250 const SEString SEString::from(int n) // static
    00251 {
    00252         char res[12];
    00253
    00254         snprintf(res, 12, "%d", n);
    00255
    00256         return SEString(res);
    00257 }
    00258
    00259 const SEString SEString::from(uint64 n) // static
    00260 {
    00261         char res[24];
    00262
    00263         snprintf(res, 24, "%llu", n);
    00264
    00265         return SEString(res);
    00266 }
    00267
    00268 const SEString SEString::from(unsigned char chr) // static
    00269 {
    00270         char res[2];
    00271
    00272         res[0] = chr;
    00273         res[1] = '\0';
    00274
    00275         return SEString(res);
    00276 }
    00277
    00278 const SEString SEString::from(unsigned int u, unsigned int base) // static
    00279 {
    00280         char res[11];
    00281
    00282         if (16 == base)
    00283                 snprintf(res, 11, "%X", u);
    00284         else
    00285                 snprintf(res, 11, "%u", u);
    00286
    00287         return SEString(res);
    00288 }
    00289
    00290 const SEString SEString::from(bool b) // static
    00291 {
    00292         char res[2];
    00293
    00294         res[1] = '\0';
    00295
    00296         if (b)
    00297                 res[0] = '1';
    00298         else
    00299                 res[0] = '0';
    00300
    00301         return SEString(res);
    00302 }
    00303
    00304 const SEString SEString::from(char *bin, unsigned int len) // static
    00305 {
    00306         // For binaries, we escape immediately to allow it to survive all the string operations
    00307         size_t new_size = 0;
    00308         unsigned int i;
    00309
    00310         for (i = 0; i < len; i++) {
    00311                 if (('\0' == bin[i]) || ('\\' == bin[i]) || (',' == bin[i]) || ('"' == bin[i]))
    00312                         new_size++;
    00313         }
    00314         new_size += len;
    00315
    00316         SEString str(new_size + 1); // 1 for end of string null char
    00317         str.markAsBinary();
    00318
    00319         char* to = str.d->str;
    00320
    00321         for (i = 0; i < len; i++) {
    00322                 if ('\0' == bin[i]) { // null is escaped differently
    00323                         *to = '\\';
    00324                         to++;
    00325                         *to = '0';
    00326                         to++;
    00327                         continue;
    00328                 }
    00329                 // normal escaping like in escape()
    00330                 if ((',' == bin[i]) || ('"' == bin[i]) || ('\\' == bin[i])) {
    00331                         *to = '\\';
    00332                         to++;
    00333                 }
    00334                 *to = bin[i];
    00335                 to++;
    00336         }
    00337
    00338         *to = '\0';
    00339
    00340         return str;
    00341 }
    00342
    00343 bool SEString::toBool() const
    00344 {
    00345         if (isNull())
    00346                 return false;
    00347
    00348         return atoi(d->str) != 0;
    00349 }
    00350
    00351 int SEString::toInt() const
    00352 {
    00353         if (isNull())
    00354                 return 0;
    00355
    00356         return atoi(d->str);
    00357 }
    00358
    00359 unsigned int SEString::toUInt() const
    00360 {
    00361         if (isNull())
    00362                 return 0;
    00363
    00364         return strtoul(d->str, NULL, 10);
    00365 }
    00366
    00367 SEString::uint64 SEString::toUInt64() const
    00368 {
    00369         if (isNull())
    00370                 return 0;
    00371
    00372         return strtoull(d->str, NULL, 10);
    00373 }
    00374
    00375 size_t SEString::toBinary(char *bin) const
    00376 {
    00377         if (isNull())
    00378                 return 0;
    00379
    00380         // Check we actually have a binary
    00381         if (!isBinary())
    00382                 return 0;
    00383
    00384         // For a binary, we didn't unescape in the low-level SEStringDict::parse, but we do it here only
    00385         size_t to = 0;
    00386         size_t cur = 0;
    00387         size_t len = length();
    00388
    00389         while (cur < len) {
    00390                 if ('\\' == d->str[cur]) {
    00391                         cur++;
    00392
    00393                         if ('0' == d->str[cur]) {   // escaped null
    00394                                 bin[to++] = '\0';
    00395                                 cur++;
    00396                                 continue;
    00397                         }
    00398                 }
    00399
    00400                 bin[to++] = d->str[cur++];
    00401         }
    00402
    00403         return to;
    00404 }
    00405
    00406 SEString SEString::getHexRepresentation() const
    00407 {
    00408         // check we actually have a binary
    00409         if (!isBinary()) return SEString();
    00410         // convert to binary
    00411         char * ps = (char *)malloc(length());
    00412         size_t len = 2 * toBinary(ps);
    00413         // convert to hexa
    00414         static const char hex[17] = "0123456789abcdef";
    00415         SEString str(len);
    00416         unsigned char *ptr = (unsigned char *)ps;
    00417         unsigned int count = 0;
    00418         for (; count < len; ptr++) {
    00419                 str.d->str[count++] = hex[*ptr >> 4];
    00420                 str.d->str[count++] = hex[*ptr & 0xf];
    00421         }
    00422         str.d->str[count] = 0;
    00423         // free temp buf
    00424         free(ps);
    00425         return str;
    00426 }
    00427
    00428 SEString& SEString::operator+=(const SEString &str)
    00429 {
    00430         if (isNull())
    00431                 return (*this = str);
    00432         if (str.isNull())
    00433                 return (*this);
    00434
    00435         detach();
    00436
    00437         size_t l = length();
    00438
    00439         char* str_new  = se_realloc(l + str.length() + 1);
    00440
    00441         if (str_new) {
    00442                 strcpy(str_new + l, str.d->str);
    00443
    00444                 d->str = str_new;
    00445         }
    00446
    00447         return *this;
    00448 }
    00449
    00450 SEString& SEString::operator+=(const char* str)
    00451 {
    00452         if (isNull())
    00453                 return (*this = str);
    00454         if (str == NULL)
    00455                 return (*this);
    00456
    00457         detach();
    00458
    00459         size_t l = length();
    00460         size_t l2 = strlen(str);
    00461
    00462         char* str_new = se_realloc(l + l2 + 1);
    00463
    00464         if (str_new) {
    00465                 strcpy(str_new + l, str);
    00466
    00467                 d->str = str_new;
    00468         }
    00469
    00470         return *this;
    00471 }
    00472
    00473 SEString& SEString::operator=(const SEString& str)
    00474 {
    00475         Data* strd = const_cast<SEString&>(str).d_ref(); // shall be mutable
    00476         d_unref();
    00477         d = strd;
    00478
    00479         return *this;
    00480 }
    00481
    00482 SEString& SEString::operator=(const char* str)
    00483 {
    00484         d_unref();
    00485
    00486         if (str) {
    00487                 d = new Data();
    00488                 d->ref = 1;
    00489                 d->real_size = CALC_SIZE(strlen(str) + 1);
    00490                 d->str = (char*)malloc(d->real_size);
    00491                 strcpy(d->str, str);
    00492                 d->isBin = false;
    00493         } else {
    00494                 d = 0;
    00495         }
    00496
    00497         return *this;
    00498 }
    00499
    00500 /** \cond INTERNAL */
    00501 SEString::Data* SEString::d_ref()
    00502 {
    00503         SEMutexLock lock_string(mutex);
    00504         if (0 == d)
    00505                 return d;
    00506
    00507         d->lock.Acquire();
    00508
    00509         d->ref++;
    00510
    00511         d->lock.Release();
    00512         return d;
    00513 }
    00514
    00515 void SEString::d_unref()
    00516 {
    00517         SEMutexLock lock_string(mutex);
    00518         if (0 == d)
    00519                 return;
    00520
    00521         SEMutex* lock = &d->lock;
    00522
    00523         lock->Acquire();
    00524
    00525         if (d->ref > 1)
    00526                 d->ref--;
    00527         else {
    00528                 Data* tmp_d = d;
    00529                 d = 0;
    00530                 lock->Release();
    00531                 free(tmp_d->str);
    00532                 delete tmp_d;
    00533                 return;
    00534         }
    00535
    00536         lock->Release();
    00537 }
    00538
    00539 void SEString::detach()
    00540 {
    00541         SEMutexLock lock_string(mutex);
    00542         if (0 == d)
    00543                 return;
    00544
    00545         SEMutex* lock = &d->lock;
    00546         lock->Acquire();
    00547
    00548         if (1 != d->ref) {
    00549
    00550                 d->ref--;
    00551
    00552                 size_t sz = CALC_SIZE(strlen(d->str) + 1);
    00553                 char* buf = (char*)malloc(sz);
    00554                 strcpy(buf, d->str);
    00555                 lock->Release();
    00556
    00557                 Data* d_new = new Data();
    00558                 d_new->ref = 1;
    00559                 d_new->real_size = sz;
    00560                 d_new->str = buf;
    00561                 d_new->isBin = d->isBin;
    00562
    00563                 d = d_new;
    00564                 return;
    00565         }
    00566
    00567         lock->Release();
    00568 }
    00569 /** \endcond */
    00570
    00571 SEString SEString::deepCopy() const
    00572 {
    00573         SEString tmp = *this;
    00574
    00575         tmp.detach();
    00576
    00577         return tmp;
    00578 }
    00579
    00580 unsigned int SEString::hash(unsigned int hash_size) const
    00581 {
    00582         if (isNull())
    00583                 return 0;
    00584
    00585         const char *ptr;
    00586         unsigned int val;
    00587
    00588         val = 0;
    00589         ptr = d->str;
    00590
    00591         while (*ptr) {
    00592                 int tmp;
    00593                 val = (val << 4) + (*ptr);
    00594                 tmp = (val & 0xf0000000);
    00595                 if (tmp) {
    00596                         val = val ^ (tmp >> 24);
    00597                         val = val ^ tmp;
    00598                 }
    00599
    00600                 ptr++;
    00601         }
    00602
    00603         return val % hash_size;
    00604 }
    00605
    00606 bool SEString::equals(const SEString& str) const
    00607 {
    00608         if (isNull() && str.isNull())
    00609                 return true;
    00610
    00611         else if (isNull() || str.isNull())
    00612                 return false;
    00613
    00614         return (0 == strcmp(d->str, str.d->str));
    00615 }
    00616
    00617 bool SEString::equals(const char* str) const
    00618 {
    00619         if (isNull() && (0 == str))
    00620                 return true;
    00621
    00622         if (isNull() || (0 == str))
    00623                 return false;
    00624
    00625         return (0 == strcmp(str, d->str));
    00626 }
    00627
    00628 int SEString::find(char c) const
    00629 {
    00630         if (isNull())
    00631                 return -1;
    00632
    00633         char* found = strchr(d->str, c);
    00634
    00635         if (0 == found)
    00636                 return -1;
    00637
    00638         return (found - d->str);
    00639 }
    00640
    00641 int SEString::find(int startpos, char c) const
    00642 {
    00643         if (isNull())
    00644                 return -1;
    00645
    00646         char* found = strchr(d->str+startpos, c);
    00647
    00648         if (0 == found)
    00649                 return -1;
    00650
    00651         return (found - d->str);
    00652 }
    00653
    00654 /** \cond INTERNAL */
    00655 char* SEString::se_realloc(size_t new_size)
    00656 {
    00657         if (d->real_size >= new_size)
    00658                 return d->str;
    00659         else {
    00660                 d->real_size = CALC_SIZE(new_size);
    00661
    00662                 return (char*)::realloc(d->str, d->real_size);
    00663         }
    00664 }
    00665 /** \endcond */
    00666
    00667 void SEString::Format(const char *format, va_list arglist)
    00668 {
    00669         const unsigned int bufsize = 1024;
    00670         char buffer [bufsize], *buf = buffer;
    00671         unsigned int requested = vsnprintf (buf, bufsize, format, arglist);
    00672         if (requested >= bufsize) {
    00673                 buf = new char[requested + 1];
    00674                 requested = vsnprintf(buf, requested + 1, format, arglist);
    00675                 *this = buf; //copy
    00676                 delete [] buf;
    00677         } else {
    00678                 *this = buf; //copy
    00679         }
    00680 }
    00681
    00682 #ifdef SE_STRING_TEST_PROGRAM
    00683 int main(char **, int)
    00684 {
    00685         int i;
    00686         SEString strings[] = {
    00687                 "Hello World!",
    00688                 "Hel,lo\\ World!",
    00689                 "Hel\"lo Wo\\9rld!",
    00690                 "Hel,lo Wo\\0rld!",
    00691                 SEString()
    00692         };
    00693         for (i = 0; !strings[i].isNull(); i++) {
    00694                 SEString escaped = strings[i].escape();
    00695                 SEString unescaped = escaped.unescape();
    00696                 if (strcmp((const char*)strings[i], (const char*)unescaped))
    00697                         printf("String Failed:\n%s\n%s\n%s\n\n", (const char*)strings[i], (const char*)escaped, (const char*)unescaped);
    00698         }
    00699
    00700         // 0x5c = '\\', 0x30 = '0', 0x00 = 0, 0x22 = '"'
    00701         const char bins[] = {
    00702                 '1', '2', '3', '4', '5', '6', '7', '8' ,
    00703                 '1', '2', 0x5c, 0x30, '5', '6', '7', '8' ,
    00704                 '1', '2', 0x5c, 0x30, 0x5c, 0x5c, 0x5c, '8' ,
    00705                 '1', '2', 0x5c, 0x30, '5', '6', '7', '8' ,
    00706                 '1', '2', 0x00, '4', '5', '6', '7', '8' ,
    00707                 '1', 0x5c, 0x00, 0x5c, '5', '6', 0x5c, 0x5c ,
    00708                 '1', 0x5c, 0x00, 0x00, '5', 0x00, 0x5c, '8' ,
    00709                 0x00, '2', 0x5c, 0x30, '5', 0x22, 0x22, '8' ,
    00710                 0x5c, '2', 0x5c, 0x30, '5', 0x22, 0x22, 0x00 ,
    00711                 0x00, 0x00, 0x5c, 0x30, '5', 0x22, 0x22, 0x5c ,
    00712                 'E'
    00713         };
    00714         size_t bins_len = 8;
    00715         for (i = 0; bins[i] != 'E'; i += bins_len) {
    00716                 SEString escaped = SEString::from((char*)(bins + i), bins_len);
    00717                 char *unescaped = (char *)malloc(escaped.length());
    00718                 size_t unescaped_len = escaped.toBinary(unescaped);
    00719                 //printf("%d, escaped.length()=%d unescaped_len=%d\n", i/bins_len, escaped.length(), unescaped_len);
    00720                 if ( (memcmp((char*)(bins + i), unescaped, bins_len)) || (unescaped_len != bins_len) )
    00721                         printf("Binary Failed: index %d\n", i/bins_len);
    00722                 //printf("%s\n", (const char*)escaped.getHexRepresentation());
    00723                 free(unescaped);
    00724         }
    00725
    00726 }
    00727 #endif

All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

(c) Skype Technologies S.A. Confidential/Proprietary

Last updated: Fri Jan 27 2012