- 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(size_t 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         int len = length();
    00200
    00201         if (to >= 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(size_t 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(unsigned char chr) // static
    00260 {
    00261         char res[2];
    00262
    00263         res[0] = chr;
    00264         res[1] = '\0';
    00265
    00266         return SEString(res);
    00267 }
    00268
    00269 const SEString SEString::from(unsigned int u, unsigned int base) // static
    00270 {
    00271         char res[11];
    00272
    00273         if (16 == base)
    00274                 snprintf(res, 11, "%X", u);
    00275         else
    00276                 snprintf(res, 11, "%u", u);
    00277
    00278         return SEString(res);
    00279 }
    00280
    00281 const SEString SEString::from(bool b) // static
    00282 {
    00283         char res[2];
    00284
    00285         res[1] = '\0';
    00286
    00287         if (b)
    00288                 res[0] = '1';
    00289         else
    00290                 res[0] = '0';
    00291
    00292         return SEString(res);
    00293 }
    00294
    00295 const SEString SEString::from(char *bin, unsigned int len) // static
    00296 {
    00297         // For binaries, we escape immediately to allow it to survive all the string operations
    00298         size_t new_size = 0;
    00299         unsigned int i;
    00300
    00301         for (i = 0; i < len; i++) {
    00302                 if (('\0' == bin[i]) || ('\\' == bin[i]) || (',' == bin[i]) || ('"' == bin[i]))
    00303                         new_size++;
    00304         }
    00305         new_size += len;
    00306
    00307         SEString str(new_size + 1); // 1 for end of string null char
    00308         str.markAsBinary();
    00309
    00310         char* to = str.d->str;
    00311
    00312         for (i = 0; i < len; i++) {
    00313                 if ('\0' == bin[i]) { // null is escaped differently
    00314                         *to = '\\';
    00315                         to++;
    00316                         *to = '0';
    00317                         to++;
    00318                         continue;
    00319                 }
    00320                 // normal escaping like in escape()
    00321                 if ((',' == bin[i]) || ('"' == bin[i]) || ('\\' == bin[i])) {
    00322                         *to = '\\';
    00323                         to++;
    00324                 }
    00325                 *to = bin[i];
    00326                 to++;
    00327         }
    00328
    00329         *to = '\0';
    00330
    00331         return str;
    00332 }
    00333
    00334 bool SEString::toBool() const
    00335 {
    00336         if (isNull())
    00337                 return false;
    00338
    00339         return atoi(d->str) != 0;
    00340 }
    00341
    00342 int SEString::toInt() const
    00343 {
    00344         if (isNull())
    00345                 return 0;
    00346
    00347         return atoi(d->str);
    00348 }
    00349
    00350 unsigned int SEString::toUInt() const
    00351 {
    00352         if (isNull())
    00353                 return 0;
    00354
    00355         return (unsigned int)strtoul(d->str, NULL, 10);
    00356 }
    00357
    00358 SEString::uint64 SEString::toUInt64() const
    00359 {
    00360         if (isNull())
    00361                 return 0;
    00362
    00363         return strtoull(d->str, NULL, 10);
    00364 }
    00365
    00366 size_t SEString::toBinary(char *bin) const
    00367 {
    00368         if (isNull())
    00369                 return 0;
    00370
    00371         // Check we actually have a binary
    00372         if (!isBinary())
    00373                 return 0;
    00374
    00375         // For a binary, we didn't unescape in the low-level SEStringDict::parse, but we do it here only
    00376         size_t to = 0;
    00377         size_t cur = 0;
    00378         size_t len = length();
    00379
    00380         while (cur < len) {
    00381                 if ('\\' == d->str[cur]) {
    00382                         cur++;
    00383
    00384                         if ('0' == d->str[cur]) {   // escaped null
    00385                                 bin[to++] = '\0';
    00386                                 cur++;
    00387                                 continue;
    00388                         }
    00389                 }
    00390
    00391                 bin[to++] = d->str[cur++];
    00392         }
    00393
    00394         return to;
    00395 }
    00396
    00397 SEString SEString::getHexRepresentation() const
    00398 {
    00399         // check we actually have a binary
    00400         if (!isBinary()) return SEString();
    00401         // convert to binary
    00402         char * ps = (char *)malloc(length());
    00403         size_t len = 2 * toBinary(ps);
    00404         // convert to hexa
    00405         static const char hex[17] = "0123456789abcdef";
    00406         SEString str(len);
    00407         unsigned char *ptr = (unsigned char *)ps;
    00408         unsigned int count = 0;
    00409         for (; count < len; ptr++) {
    00410                 str.d->str[count++] = hex[*ptr >> 4];
    00411                 str.d->str[count++] = hex[*ptr & 0xf];
    00412         }
    00413         str.d->str[count] = 0;
    00414         // free temp buf
    00415         free(ps);
    00416         return str;
    00417 }
    00418
    00419 SEString& SEString::operator+=(const SEString &str)
    00420 {
    00421         if (isNull())
    00422                 return (*this = str);
    00423         if (str.isNull())
    00424                 return (*this);
    00425
    00426         detach();
    00427
    00428         size_t l = length();
    00429
    00430         char* str_new  = se_realloc(l + str.length() + 1);
    00431
    00432         if (str_new) {
    00433                 strcpy(str_new + l, str.d->str);
    00434
    00435                 d->str = str_new;
    00436         }
    00437
    00438         return *this;
    00439 }
    00440
    00441 SEString& SEString::operator+=(const char* str)
    00442 {
    00443         if (isNull())
    00444                 return (*this = str);
    00445         if (str == NULL)
    00446                 return (*this);
    00447
    00448         detach();
    00449
    00450         size_t l = length();
    00451         size_t l2 = strlen(str);
    00452
    00453         char* str_new = se_realloc(l + l2 + 1);
    00454
    00455         if (str_new) {
    00456                 strcpy(str_new + l, str);
    00457
    00458                 d->str = str_new;
    00459         }
    00460
    00461         return *this;
    00462 }
    00463
    00464 SEString& SEString::operator=(const SEString& str)
    00465 {
    00466         Data* strd = const_cast<SEString&>(str).d_ref(); // shall be mutable
    00467         d_unref();
    00468         d = strd;
    00469
    00470         return *this;
    00471 }
    00472
    00473 SEString& SEString::operator=(const char* str)
    00474 {
    00475         d_unref();
    00476
    00477         if (str) {
    00478                 d = new Data();
    00479                 d->ref = 1;
    00480                 d->real_size = CALC_SIZE(strlen(str) + 1);
    00481                 d->str = (char*)malloc(d->real_size);
    00482                 strcpy(d->str, str);
    00483                 d->isBin = false;
    00484         } else {
    00485                 d = 0;
    00486         }
    00487
    00488         return *this;
    00489 }
    00490
    00491 /** \cond INTERNAL */
    00492 SEString::Data* SEString::d_ref()
    00493 {
    00494         SEMutexLock lock_string(mutex);
    00495         if (0 == d)
    00496                 return d;
    00497
    00498         d->lock.Acquire();
    00499
    00500         d->ref++;
    00501
    00502         d->lock.Release();
    00503         return d;
    00504 }
    00505
    00506 void SEString::d_unref()
    00507 {
    00508         SEMutexLock lock_string(mutex);
    00509         if (0 == d)
    00510                 return;
    00511
    00512         SEMutex* lock = &d->lock;
    00513
    00514         lock->Acquire();
    00515
    00516         if (d->ref > 1)
    00517                 d->ref--;
    00518         else {
    00519                 Data* tmp_d = d;
    00520                 d = 0;
    00521                 lock->Release();
    00522                 free(tmp_d->str);
    00523                 delete tmp_d;
    00524                 return;
    00525         }
    00526
    00527         lock->Release();
    00528 }
    00529
    00530 void SEString::detach()
    00531 {
    00532         SEMutexLock lock_string(mutex);
    00533         if (0 == d)
    00534                 return;
    00535
    00536         SEMutex* lock = &d->lock;
    00537         lock->Acquire();
    00538
    00539         if (1 != d->ref) {
    00540
    00541                 d->ref--;
    00542
    00543                 size_t sz = CALC_SIZE(strlen(d->str) + 1);
    00544                 char* buf = (char*)malloc(sz);
    00545                 strcpy(buf, d->str);
    00546                 lock->Release();
    00547
    00548                 Data* d_new = new Data();
    00549                 d_new->ref = 1;
    00550                 d_new->real_size = sz;
    00551                 d_new->str = buf;
    00552                 d_new->isBin = d->isBin;
    00553
    00554                 d = d_new;
    00555                 return;
    00556         }
    00557
    00558         lock->Release();
    00559 }
    00560 /** \endcond */
    00561
    00562 SEString SEString::deepCopy() const
    00563 {
    00564         SEString tmp = *this;
    00565
    00566         tmp.detach();
    00567
    00568         return tmp;
    00569 }
    00570
    00571 unsigned int SEString::hash(unsigned int hash_size) const
    00572 {
    00573         if (isNull())
    00574                 return 0;
    00575
    00576         const char *ptr;
    00577         unsigned int val;
    00578
    00579         val = 0;
    00580         ptr = d->str;
    00581
    00582         while (*ptr) {
    00583                 int tmp;
    00584                 val = (val << 4) + (*ptr);
    00585                 tmp = (val & 0xf0000000);
    00586                 if (tmp) {
    00587                         val = val ^ (tmp >> 24);
    00588                         val = val ^ tmp;
    00589                 }
    00590
    00591                 ptr++;
    00592         }
    00593
    00594         return val % hash_size;
    00595 }
    00596
    00597 bool SEString::equals(const SEString& str) const
    00598 {
    00599         if (isNull() && str.isNull())
    00600                 return true;
    00601
    00602         else if (isNull() || str.isNull())
    00603                 return false;
    00604
    00605         return (0 == strcmp(d->str, str.d->str));
    00606 }
    00607
    00608 bool SEString::equals(const char* str) const
    00609 {
    00610         if (isNull() && (0 == str))
    00611                 return true;
    00612
    00613         if (isNull() || (0 == str))
    00614                 return false;
    00615
    00616         return (0 == strcmp(str, d->str));
    00617 }
    00618
    00619 int SEString::find(char c) const
    00620 {
    00621         if (isNull())
    00622                 return -1;
    00623
    00624         char* found = strchr(d->str, c);
    00625
    00626         if (0 == found)
    00627                 return -1;
    00628
    00629         return int(found - d->str);
    00630 }
    00631
    00632 int SEString::find(int startpos, char c) const
    00633 {
    00634         if (isNull())
    00635                 return -1;
    00636
    00637         char* found = strchr(d->str+startpos, c);
    00638
    00639         if (0 == found)
    00640                 return -1;
    00641
    00642         return int(found - d->str);
    00643 }
    00644
    00645 /** \cond INTERNAL */
    00646 char* SEString::se_realloc(size_t new_size)
    00647 {
    00648         if (d->real_size >= new_size)
    00649                 return d->str;
    00650         else {
    00651                 d->real_size = CALC_SIZE(new_size);
    00652
    00653                 return (char*)::realloc(d->str, d->real_size);
    00654         }
    00655 }
    00656 /** \endcond */
    00657
    00658 void SEString::Format(const char *format, va_list arglist)
    00659 {
    00660         const unsigned int bufsize = 1024;
    00661         char buffer [bufsize], *buf = buffer;
    00662         unsigned int requested = vsnprintf (buf, bufsize, format, arglist);
    00663         if (requested >= bufsize) {
    00664                 buf = new char[requested + 1];
    00665                 requested = vsnprintf(buf, requested + 1, format, arglist);
    00666                 *this = buf; //copy
    00667                 delete [] buf;
    00668         } else {
    00669                 *this = buf; //copy
    00670         }
    00671 }
    00672
    00673 #ifdef SE_STRING_TEST_PROGRAM
    00674 int main(char **, int)
    00675 {
    00676         int i;
    00677         SEString strings[] = {
    00678                 "Hello World!",
    00679                 "Hel,lo\\ World!",
    00680                 "Hel\"lo Wo\\9rld!",
    00681                 "Hel,lo Wo\\0rld!",
    00682                 SEString()
    00683         };
    00684         for (i = 0; !strings[i].isNull(); i++) {
    00685                 SEString escaped = strings[i].escape();
    00686                 SEString unescaped = escaped.unescape();
    00687                 if (strcmp((const char*)strings[i], (const char*)unescaped))
    00688                         printf("String Failed:\n%s\n%s\n%s\n\n", (const char*)strings[i], (const char*)escaped, (const char*)unescaped);
    00689         }
    00690
    00691         // 0x5c = '\\', 0x30 = '0', 0x00 = 0, 0x22 = '"'
    00692         const char bins[] = {
    00693                 '1', '2', '3', '4', '5', '6', '7', '8' ,
    00694                 '1', '2', 0x5c, 0x30, '5', '6', '7', '8' ,
    00695                 '1', '2', 0x5c, 0x30, 0x5c, 0x5c, 0x5c, '8' ,
    00696                 '1', '2', 0x5c, 0x30, '5', '6', '7', '8' ,
    00697                 '1', '2', 0x00, '4', '5', '6', '7', '8' ,
    00698                 '1', 0x5c, 0x00, 0x5c, '5', '6', 0x5c, 0x5c ,
    00699                 '1', 0x5c, 0x00, 0x00, '5', 0x00, 0x5c, '8' ,
    00700                 0x00, '2', 0x5c, 0x30, '5', 0x22, 0x22, '8' ,
    00701                 0x5c, '2', 0x5c, 0x30, '5', 0x22, 0x22, 0x00 ,
    00702                 0x00, 0x00, 0x5c, 0x30, '5', 0x22, 0x22, 0x5c ,
    00703                 'E'
    00704         };
    00705         size_t bins_len = 8;
    00706         for (i = 0; bins[i] != 'E'; i += bins_len) {
    00707                 SEString escaped = SEString::from((char*)(bins + i), bins_len);
    00708                 char *unescaped = (char *)malloc(escaped.length());
    00709                 size_t unescaped_len = escaped.toBinary(unescaped);
    00710                 //printf("%d, escaped.length()=%d unescaped_len=%d\n", i/bins_len, escaped.length(), unescaped_len);
    00711                 if ( (memcmp((char*)(bins + i), unescaped, bins_len)) || (unescaped_len != bins_len) )
    00712                         printf("Binary Failed: index %d\n", i/bins_len);
    00713                 //printf("%s\n", (const char*)escaped.getHexRepresentation());
    00714                 free(unescaped);
    00715         }
    00716
    00717 }
    00718 #endif

All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

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

Last updated: Fri Mar 16 2012