123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253 |
- /*##############################################################################
- HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ############################################################################## */
- #include "platform.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <assert.h>
- #include <string.h>
- #include <ctype.h>
- #include <time.h>
- #include <math.h>
- #include "jstring.hpp"
- #include "jexcept.hpp"
- #include "jhash.hpp"
- #include "jlog.hpp"
- #include "jfile.hpp"
- #include "jdebug.hpp"
- #include "jutil.hpp"
- #define DOUBLE_FORMAT "%.16g"
- #define FLOAT_FORMAT "%.7g"
- #ifndef va_copy
- /* WARNING - DANGER - ASSUMES TYPICAL STACK MACHINE */
- #define va_copy(dst, src) ((void)((dst) = (src)))
- #endif
- static const char * TheNullStr = "";
- #define FIRST_CHUNK_SIZE 8
- #define DOUBLE_LIMIT 0x100000 // must be a power of 2
- #define DETACH_GRANULARITY 16
- //===========================================================================
- StringBuffer::StringBuffer()
- {
- init();
- }
- #if 0
- StringBuffer::StringBuffer(int initial)
- {
- init();
- ensureCapacity(initial);
- }
- #endif
- StringBuffer::StringBuffer(String & value)
- {
- init();
- append(value);
- }
- StringBuffer::StringBuffer(const char *value)
- {
- init();
- append(value);
- }
- StringBuffer::StringBuffer(unsigned len, const char *value)
- {
- init();
- append(len, value);
- }
- StringBuffer::StringBuffer(const StringBuffer & value)
- {
- init();
- append(value);
- }
- void StringBuffer::setBuffer(size32_t buffLen, char * newBuff, size32_t strLen)
- {
- assertex(buffLen>0 && newBuff!=NULL && strLen<buffLen);
- if (buffer)
- free(buffer);
- buffer = newBuff;
- maxLen=buffLen;
- curLen=strLen;
- }
- void StringBuffer::_realloc(size32_t newLen)
- {
- if (newLen >= maxLen)
- {
- size32_t newMax = maxLen;
- if (newMax == 0)
- newMax = FIRST_CHUNK_SIZE;
- if (newLen > DOUBLE_LIMIT)
- {
- newMax = (newLen + DOUBLE_LIMIT) & ~(DOUBLE_LIMIT-1);
- if (newLen >= newMax)
- throw MakeStringException(MSGAUD_operator, -1, "StringBuffer::_realloc: Request for %d bytes oldMax = %d", newLen, maxLen);
- }
- else
- {
- while (newLen >= newMax)
- newMax += newMax;
- }
- char * newStr;
- if(!newMax || !(newStr=(char *)realloc(buffer, newMax)))
- {
- DBGLOG("StringBuffer::_realloc: Failed to realloc = %d, oldMax = %d", newMax, maxLen);
- PrintStackReport();
- PrintMemoryReport();
- throw MakeStringException(MSGAUD_operator, -1, "StringBuffer::_realloc: Failed to realloc = %d, oldMax = %d", newMax, maxLen);
- }
- buffer = newStr;
- maxLen = newMax;
- }
- }
- char * StringBuffer::detach()
- {
- if (buffer)
- {
- if (maxLen>curLen+1+DETACH_GRANULARITY)
- buffer = (char *)realloc(buffer,curLen+1); // shrink
- buffer[curLen] = '\0'; // There is always room for this null
- char *ret = buffer;
- init();
- return ret;
- }
- return strdup(TheNullStr);
- }
- StringBuffer & StringBuffer::append(char value)
- {
- ensureCapacity(1);
- buffer[curLen] = value;
- ++curLen;
- return *this;
- }
- StringBuffer & StringBuffer::append(unsigned char value)
- {
- ensureCapacity(1);
- buffer[curLen] = value;
- ++curLen;
- return *this;
- }
- StringBuffer & StringBuffer::append(const char * value)
- {
- if (value)
- {
- size32_t SourceLen = (size32_t)::strlen(value);
-
- ensureCapacity(SourceLen);
- memcpy(buffer + curLen, value, SourceLen);
- curLen += SourceLen;
- }
- return *this;
- }
- StringBuffer & StringBuffer::append(unsigned len, const char * value)
- {
- if (len)
- {
- ensureCapacity(len);
- memcpy(buffer + curLen, value, len);
- curLen += len;
- }
- return *this;
- }
- StringBuffer & StringBuffer::append(const unsigned char * value)
- {
- return append((const char *) value);
- }
- StringBuffer & StringBuffer::append(const char * value, int offset, int len)
- {
- ensureCapacity(len);
- memcpy(buffer + curLen, value+offset, len);
- curLen += len;
- return *this;
- }
- StringBuffer & StringBuffer::append(const IAtom * value)
- {
- if (value)
- append(value->getAtomNamePtr());
- return *this;
- }
- StringBuffer & StringBuffer::append(double value)
- {
- int len = length();
- int newlen = appendf(DOUBLE_FORMAT, value).length();
- while (len < newlen)
- {
- switch (charAt(len))
- {
- case '.':
- case 'E':
- case 'e':
- case 'N': // Not a number/infinity
- case 'n':
- return *this;
- }
- len++;
- }
- return append(".0");
- }
- StringBuffer & StringBuffer::append(float value)
- {
- int len = length();
- int newlen = appendf(FLOAT_FORMAT, value).length();
- while (len < newlen)
- {
- switch (charAt(len))
- {
- case '.':
- case 'E':
- case 'e':
- case 'N': // Not a number/infinity
- case 'n':
- return *this;
- }
- len++;
- }
- return append(".0");
- }
- StringBuffer & StringBuffer::append(int value)
- {
- char temp[12];
-
- unsigned written = numtostr(temp, value);
- return append(written, temp);
- }
- StringBuffer & StringBuffer::append(unsigned value)
- {
- char temp[12];
-
- unsigned written = numtostr(temp, value);
- return append(written, temp);
- }
- StringBuffer & StringBuffer::appendlong(long value)
- {
- char temp[24];
-
- unsigned written = numtostr(temp, value);
- return append(written, temp);
- }
- StringBuffer & StringBuffer::appendulong(unsigned long value)
- {
- char temp[24];
-
- unsigned written = numtostr(temp, value);
- return append(written, temp);
- }
- StringBuffer & StringBuffer::append(__int64 value)
- {
- char temp[24];
-
- unsigned written = numtostr(temp, value);
- return append(written, temp);
- }
- StringBuffer & StringBuffer::append(unsigned __int64 value)
- {
- char temp[24];
-
- unsigned written = numtostr(temp, value);
- return append(written, temp);
- }
- StringBuffer & StringBuffer::append(const String & value)
- {
- size32_t SourceLen = value.length();
-
- ensureCapacity(SourceLen);
- value.getChars(0, SourceLen, buffer, curLen);
- curLen += SourceLen;
- return *this;
- }
- StringBuffer & StringBuffer::append(const IStringVal & value)
- {
- return append(value.str());
- }
- StringBuffer & StringBuffer::append(const IStringVal * value)
- {
- if (value)
- return append(value->str());
- else
- return *this;
- }
- StringBuffer & StringBuffer::append(const StringBuffer & value)
- {
- size32_t SourceLen = value.length();
-
- ensureCapacity(SourceLen);
- value.getChars(0, SourceLen, buffer + curLen);
- curLen += SourceLen;
- return *this;
- }
- StringBuffer & StringBuffer::appendf(const char *format, ...)
- {
- va_list args;
- va_start(args, format);
- valist_appendf(format, args);
- va_end(args);
- return *this;
- }
- StringBuffer & StringBuffer::appendLower(unsigned len, const char * value)
- {
- if (len)
- {
- ensureCapacity(len);
- const byte * from = reinterpret_cast<const byte *>(value);
- for (unsigned i = 0; i < len; i++)
- buffer[curLen + i] = tolower(from[i]);
- curLen += len;
- }
- return *this;
- }
- StringBuffer & StringBuffer::setf(const char *format, ...)
- {
- clear();
- va_list args;
- va_start(args, format);
- valist_appendf(format, args);
- va_end(args);
- return *this;
- }
- StringBuffer & StringBuffer::limited_valist_appendf(unsigned szLimit, const char *format, va_list args)
- {
- #define BUF_SIZE 1024
- #define MAX_BUF_SIZE (1024*1024) // limit buffer size to 1MB when doubling
-
- // handle string that is bigger that BUF_SIZE bytes
- unsigned size = (0 == szLimit||szLimit>BUF_SIZE)?BUF_SIZE:szLimit;
- int len;
- va_list args2;
- va_copy(args2, args);
- try { ensureCapacity(size); }
- catch (IException *e)
- {
- StringBuffer eMsg;
- IException *e2 = MakeStringException(-1, "StringBuffer::valist_appendf(\"%s\"): vsnprintf failed or result exceeds limit (%d): %s", format, size, e->errorMessage(eMsg).str());
- e->Release();
- throw e2;
- }
- len = _vsnprintf(buffer+curLen,size,format,args);
- if (len >= 0)
- {
- if ((unsigned)len >= size)
- {
- if (szLimit && (unsigned)len >= szLimit)
- {
- if ((unsigned)len>szLimit)
- {
- len = size;
- if (len>3) memcpy(buffer+len-3, "...", 3);
- }
- }
- else
- {
- ensureCapacity(len);
- // no need for _vsnprintf since the buffer is already made big enough
- vsprintf(buffer+curLen,format,args2);
- }
- }
- }
- else if (size == szLimit)
- {
- len = size;
- if (len>3) memcpy(buffer+len-3, "...", 3);
- }
- else
- {
- size = BUF_SIZE * 2;
- loop
- {
- if (0 != szLimit && size>szLimit) size = szLimit; // if so, will be last attempt
- if (size>MAX_BUF_SIZE)
- {
- WARNLOG("StringBuffer::valist_appendf(\"%s\"): vsnprintf exceeds limit (%d)", format, size);
- size = szLimit = MAX_BUF_SIZE;
- }
- try { ensureCapacity(size); }
- catch (IException *e)
- {
- StringBuffer eMsg;
- IException *e2 = MakeStringException(-1, "StringBuffer::valist_appendf(\"%s\"): vsnprintf failed (%d): %s", format, size, e->errorMessage(eMsg).str());
- e->Release();
- throw e2;
- }
- va_list args3;
- va_copy(args3, args2);
- len = _vsnprintf(buffer+curLen,size,format,args3);
- va_end(args3);
- if (len>=0) // NB: len>size not possible, 1st _vsnprintf would have handled.
- break;
- if (size == szLimit)
- {
- len = size;
- if (len>3) memcpy(buffer+len-3, "...", 3);
- break;
- }
- size <<= 1;
- }
- }
- va_end(args2);
- curLen += len;
- return *this;
- }
- StringBuffer & StringBuffer::appendN(size32_t count, char fill)
- {
- ensureCapacity(count);
- memset(buffer+curLen, fill, count);
- curLen += count;
- return *this;
- }
- void StringBuffer::setLength(unsigned len)
- {
- if (len > curLen)
- {
- ensureCapacity(len-curLen);
- }
- curLen = len;
- }
- char * StringBuffer::reserve(size32_t size)
- {
- ensureCapacity(size);
- char *ret = buffer+curLen;
- curLen += size;
- return ret;
- }
- char * StringBuffer::reserveTruncate(size32_t size)
- {
- size32_t newMax = curLen+size+1;
- if (newMax != maxLen) {
- char * newStr = (char *) realloc(buffer, newMax);
- if (!newStr)
- throw MakeStringException(-1, "StringBuffer::_realloc: Failed to realloc newMax = %d, oldMax = %d", newMax, maxLen);
- buffer = newStr;
- maxLen = newMax;
- }
- char *ret = buffer+curLen;
- curLen += size;
- return ret;
- }
- void StringBuffer::swapWith(StringBuffer &other)
- {
- size32_t tmpsz = curLen;
- curLen = other.curLen;
- other.curLen = tmpsz;
- tmpsz = maxLen;
- maxLen = other.maxLen;
- other.maxLen = tmpsz;
- char *tmpbuf = buffer;
- buffer = other.buffer;
- other.buffer = tmpbuf;
- }
- void StringBuffer::kill()
- {
- if (buffer)
- free(buffer);
- init();
- }
- void StringBuffer::getChars(int srcBegin, int srcEnd, char * target) const
- {
- const int len = srcEnd - srcBegin;
- if (target && buffer && len > 0)
- memcpy(target, buffer + srcBegin, len);
- }
- void StringBuffer::_insert(unsigned offset, size32_t insertLen)
- {
- ensureCapacity(insertLen);
- memmove(buffer + offset + insertLen, buffer + offset, curLen - offset);
- curLen += insertLen;
- }
- StringBuffer & StringBuffer::insert(int offset, char value)
- {
- _insert(offset, 1);
- buffer[offset] = value;
- return *this;
- }
- StringBuffer & StringBuffer::insert(int offset, const char * value)
- {
- if (!value) return *this;
-
- unsigned len = (size32_t)strlen(value);
- _insert(offset, len);
- memcpy(buffer + offset, value, len);
- return *this;
- }
- StringBuffer & StringBuffer::insert(int offset, double value)
- {
- char temp[36];
- sprintf(temp, "%f", value);
- insert(offset, temp);
- return *this;
- }
- StringBuffer & StringBuffer::insert(int offset, float value)
- {
- return insert(offset, (double)value);
- }
- StringBuffer & StringBuffer::insert(int offset, int value)
- {
- char temp[12];
- numtostr(temp, value);
- return insert(offset, temp);
- }
- StringBuffer & StringBuffer::insert(int offset, unsigned value)
- {
- char temp[12];
-
- numtostr(temp, value);
- return insert(offset, temp);
- }
- #if 0
- StringBuffer & StringBuffer::insert(int offset, long value)
- {
- char temp[24];
- numtostr(temp, value);
- return insert(offset, temp);
- }
- #endif
- StringBuffer & StringBuffer::insert(int offset, __int64 value)
- {
- char temp[24];
-
- numtostr(temp, value);
- return insert(offset, temp);
- }
- StringBuffer & StringBuffer::insert(int offset, const String & value)
- {
- size32_t len = value.length();
-
- _insert(offset, len);
- value.getChars(0, len, buffer, offset);
- return *this;
- }
- StringBuffer & StringBuffer::insert(int offset, const StringBuffer & value)
- {
- size32_t len = value.length();
-
- _insert(offset, len);
- value.getChars(0, len, buffer+offset);
- return *this;
- }
- StringBuffer & StringBuffer::insert(int offset, const IStringVal & value)
- {
- return insert(offset, value.str());
- }
- StringBuffer & StringBuffer::insert(int offset, const IStringVal * value)
- {
- if (value)
- return insert(offset, value->str());
- else
- return *this;
- }
- StringBuffer & StringBuffer::newline()
- {
- return append("\n");
- }
- StringBuffer & StringBuffer::pad(unsigned count)
- {
- ensureCapacity(count);
- memset(buffer + curLen, ' ', count);
- curLen += count;
- return *this;
- }
- StringBuffer & StringBuffer::padTo(unsigned count)
- {
- if (curLen<count)
- pad(count-curLen);
- return *this;
- }
- StringBuffer & StringBuffer::clip()
- {
- while (curLen && isspace(buffer[curLen-1]))
- curLen--;
- return *this;
- }
- StringBuffer & StringBuffer::trim()
- {
- return clip().trimLeft();
- }
- StringBuffer & StringBuffer::trimLeft()
- {
- char *p;
- if (curLen==0)
- return *this;
- buffer[curLen] = 0;
- for(p = buffer;isspace(*p);p++)
- ;
- if (p!=buffer)
- {
- curLen -= p-buffer;
- memmove(buffer,p,curLen);
- }
-
- return *this;
- }
- StringBuffer & StringBuffer::remove(unsigned start, unsigned len)
- {
- if (start > curLen) start = curLen;
- if (start + len > curLen) len = curLen - start;
- unsigned start2 = start + len;
- memmove(buffer + start, buffer + start2, curLen - start2);
- setLength(curLen - len);
- return *this;
- }
- StringBuffer &StringBuffer::reverse()
- {
- unsigned max = curLen/2;
- char * end = buffer + curLen;
-
- unsigned idx;
- for (idx = 0; idx < max; idx++)
- {
- char temp = buffer[idx];
- end--;
- buffer[idx] = *end;
- *end = temp;
- }
-
- return *this;
- }
- MemoryBuffer & StringBuffer::deserialize(MemoryBuffer & in)
- {
- unsigned len;
- in.read(len);
- append(len, (const char *)in.readDirect(len));
- return in;
- }
- MemoryBuffer & StringBuffer::serialize(MemoryBuffer & out) const
- {
- return out.append(curLen).append(curLen, buffer);
- }
- StringBuffer &StringBuffer::loadFile(const char *filename, bool binaryMode)
- {
- FILE *in = fopen(filename, binaryMode?"rb":"rt");
- if (in)
- {
- char buffer[1024];
- int bytes;
- for (;;)
- {
- bytes = (size32_t)fread(buffer, 1, sizeof(buffer), in);
- if (!bytes)
- break;
- append(buffer, 0, bytes);
- }
- fclose(in);
- return *this;
- }
- else
- throw MakeStringException(errno, "File %s could not be opened", filename);
- }
- StringBuffer & StringBuffer::loadFile(IFile* f)
- {
- if(!f)
- return *this;
- Owned<IFileIO> io = f->open(IFOread);
- if(!io)
- throw MakeStringException(errno, "file %s could not be opened for reading", f->queryFilename());
- char buf[2048];
- const unsigned requestedSize = sizeof(buf);
- offset_t pos = 0;
- loop
- {
- size32_t len = io->read(pos, requestedSize, buf);
- if (len == 0)
- break;
- append(len, buf);
- pos += len;
- if (len != requestedSize)
- break;
- }
- return *this;
- }
- void StringBuffer::setCharAt(unsigned offset, char value)
- {
- if (offset < curLen)
- buffer[offset] = value;
- }
- StringBuffer & StringBuffer::toLowerCase()
- {
- if (buffer)
- {
- int l = curLen;
- for (int i = 0; i < l; i++)
- if (isupper(buffer[i]))
- buffer[i] = tolower(buffer[i]);
- }
- return *this;
- }
- StringBuffer & StringBuffer::toUpperCase()
- {
- if (buffer)
- {
- int l = curLen;
- for (int i = 0; i < l; i++)
- if (islower(buffer[i]))
- buffer[i] = toupper(buffer[i]);
- }
- return *this;
- }
- StringBuffer & StringBuffer::replace(char oldChar, char newChar)
- {
- if (buffer)
- {
- int l = curLen;
- for (int i = 0; i < l; i++)
- if (buffer[i] == oldChar)
- {
- buffer[i] = newChar;
- if (newChar == '\0')
- {
- curLen = i;
- break;
- }
- }
- }
- return *this;
- }
- // this method will replace all occurrances of "oldStr" with "newStr"
- StringBuffer & StringBuffer::replaceString(const char* oldStr, const char* newStr)
- {
- if (buffer)
- {
- const char* s = str(); // get null terminated version of the string
- int left = length();
- int oldStr_len = (size32_t)strlen(oldStr);
- StringBuffer tempbuff;
- while (left >= oldStr_len)
- {
- if ( memcmp(s, oldStr, oldStr_len) == 0)
- {
- tempbuff.append(newStr);
- s += oldStr_len;
- left -= oldStr_len;
- }
- else
- {
- tempbuff.append(*s);
- s++;
- left--;
- }
- }
- // there are no more possible replacements, make sure we keep the end of the original buffer
- tempbuff.append(s);
-
- //*this = tempbuff;
- swapWith(tempbuff);
-
- }
- return *this;
- }
- const char * StringBuffer::toCharArray() const
- {
- if (buffer)
- {
- buffer[curLen] = '\0'; // There is always room for this null
- return buffer;
- }
- return TheNullStr;
- }
- //===========================================================================
- VStringBuffer::VStringBuffer(const char* format, ...)
- {
- va_list args;
- va_start(args,format);
- valist_appendf(format,args);
- va_end(args);
- }
- //===========================================================================
- String::String()
- {
- text = (char *)TheNullStr;
- }
- String::String(const char * value)
- {
- text = (value ? strdup(value) : (char *)TheNullStr);
- }
- String::String(const char * value, int offset, int _count)
- {
- text = (char *)malloc(_count+1);
- memcpy(text, value+offset, _count);
- text[_count]=0;
- }
- String::String(String & value)
- {
- text = strdup(value.toCharArray());
- }
- String::String(StringBuffer & value)
- {
- unsigned len = value.length();
- text = (char *)malloc(len+1);
- value.getChars(0,len,text);
- text[len] = 0;
- }
- String::~String()
- {
- if (text != TheNullStr) free(text);
- }
- char String::charAt(size32_t index) const
- {
- return text[index];
- }
- int String::compareTo(const String & value) const
- {
- return strcmp(text, value.toCharArray());
- }
- int String::compareTo(const char* value) const
- {
- return strcmp(text,value);
- }
- String * String::concat(const String & value) const
- {
- StringBuffer temp(toCharArray());
- temp.append(value);
- return new String(temp.str());
- }
- bool String::endsWith(const String & value) const
- {
- unsigned lenValue = value.length();
- unsigned len = (size32_t)strlen(text);
- if (len >= lenValue)
- return (memcmp(text+(len-lenValue),value.toCharArray(),lenValue) == 0);
- return false;
- }
- bool String::endsWith(const char* value) const
- {
- return ::endsWith(this->text, value);
- }
- bool String::equals(String & value) const
- {
- return strcmp(text, value.toCharArray())==0;
- }
- bool String::equalsIgnoreCase(const String & value) const
- {
- return stricmp(text, value.toCharArray())==0;
- }
- void String::getBytes(int srcBegin, int srcEnd, void * dest, int dstBegin) const
- {
- memcpy((char *)dest+dstBegin, text+srcBegin, srcEnd-srcBegin);
- }
- void String::getChars(int srcBegin, int srcEnd, void * dest, int dstBegin) const
- {
- memcpy((char *)dest+dstBegin, text+srcBegin, srcEnd-srcBegin);
- }
- int String::hashCode() const
- {
- return (int)hashc((const byte *)text,length(),0);
- }
- int String::indexOf(int ch) const
- {
- char * match = strchr(text, ch);
- return match ? (int)(match - text) : -1;
- }
- int String::indexOf(int ch, int from) const
- {
- char * match = strchr(text + from, ch);
- return match ? (int)(match - text) : -1;
- }
- int String::indexOf(const String & search) const
- {
- const char * str = search.toCharArray();
- const char * match = strstr(text, str);
- return match ? (int)(match - text) : -1;
- }
- int String::indexOf(const String & search, int from) const
- {
- const char * str = search.toCharArray();
- const char * match = strstr(text + from, str);
- return match ? (int)(match - text) : -1;
- }
- int String::lastIndexOf(int ch) const
- {
- char * match = strrchr(text, ch);
- return match ? (int)(match - text) : -1;
- }
- int String::lastIndexOf(int ch, int from) const
- {
- for (;(from > 0);--from)
- if (text[from] == ch)
- return from;
- return -1;
- }
- int String::lastIndexOf(const String & search) const
- {
- assertex(!"TBD");
- return -1;
- }
- int String::lastIndexOf(const String & search, int from) const
- {
- assertex(!"TBD");
- return -1;
- }
- size32_t String::length() const
- {
- return (size32_t)strlen(text);
- }
- bool String::startsWith(String & value) const
- {
- unsigned lenValue = value.length();
- const char * search = value.toCharArray();
- return (memcmp(text, search, lenValue) == 0);
- }
- bool String::startsWith(String & value, int offset) const
- {
- unsigned lenValue = value.length();
- const char * search = value.toCharArray();
- return (memcmp(text + offset, search, lenValue) == 0);
- }
- bool String::startsWith(const char* value) const
- {
- return ::startsWith(this->text,value);
- }
- String * String::substring(int beginIndex) const
- {
- return new String(text+beginIndex);
- }
- String * String::substring(int beginIndex, int endIndex) const
- {
- return new String(text, beginIndex, endIndex - beginIndex);
- }
- const char *String::toCharArray() const
- {
- return text;
- }
- String * String::toLowerCase() const
- {
- String *ret = new String();
- size32_t l = length();
- if (l)
- {
- ret->text = (char *)malloc(l+1);
- for (unsigned i = 0; i < l; i++)
- ret->text[i] = tolower(text[i]);
- ret->text[l]=0;
- }
- return ret;
- }
- String * String::toString()
- {
- Link();
- return this;
- }
- String * String::toUpperCase() const
- {
- String *ret = new String();
- size32_t l = length();
- if (l)
- {
- ret->text = (char *)malloc(l+1);
- for (unsigned i = 0; i < l; i++)
- ret->text[i] = toupper(text[i]);
- ret->text[l]=0;
- }
- return ret;
- }
- String * String::trim() const
- {
- size32_t l = length();
- while (l && isspace(text[l-1]))
- l--;
- return new String(text, 0, l);
- }
- //------------------------------------------------
- #if 0
- String & String::valueOf(char value)
- {
- return * new String(&value, 0, 1);
- }
- String & String::valueOf(const char * value)
- {
- return * new String(value);
- }
- String & String::valueOf(const char * value, int offset, int count)
- {
- return * new String(value, offset, count);
- }
- String & String::valueOf(double value)
- {
- StringBuffer temp;
- return temp.append(value).toString();
- }
- String & String::valueOf(float value)
- {
- StringBuffer temp;
- return temp.append(value).toString();
- }
- String & String::valueOf(int value)
- {
- StringBuffer temp;
- return temp.append(value).toString();
- }
- String & String::valueOf(long value)
- {
- StringBuffer temp;
- return temp.append(value).toString();
- }
- #endif
- //------------------------------------------------
- StringAttr::StringAttr(const char * _text)
- {
- text = _text ? strdup(_text) : NULL;
- }
- StringAttr::StringAttr(const char * _text, unsigned _len)
- {
- text = NULL;
- set(_text, _len);
- }
- StringAttr::StringAttr(const StringAttr & src)
- {
- text = NULL;
- set(src.get());
- }
- void StringAttr::set(const char * _text)
- {
- free(text);
- text = _text ? strdup(_text) : NULL;
- }
- void StringAttr::set(const char * _text, unsigned _len)
- {
- if (text)
- free(text);
- text = (char *)malloc(_len+1);
- memcpy(text, _text, _len);
- text[_len] = 0;
- }
- void StringAttr::setown(const char * _text)
- {
- if (text)
- free(text);
- text = (char *)_text;
- }
- void StringAttr::toLowerCase()
- {
- if (text)
- {
- char * cur = text;
- char next;
- while ((next = *cur) != 0)
- {
- if (isupper(next))
- *cur = tolower(next);
- cur++;
- }
- }
- }
- void StringAttr::toUpperCase()
- {
- if (text)
- {
- char * cur = text;
- char next;
- while ((next = *cur) != 0)
- {
- if (islower(next))
- *cur = toupper(next);
- cur++;
- }
- }
- }
- StringAttrItem::StringAttrItem(const char *_text, unsigned _len)
- {
- text.set(_text, _len);
- }
- inline char hex(char c, char lower)
- {
- if (c < 10)
- return '0' + c;
- else if (lower)
- return 'a' + c - 10;
- else
- return 'A' + c - 10;
- }
- StringBuffer & StringBuffer::appendhex(unsigned char c, char lower)
- {
- append(hex(c>>4, lower));
- append(hex(c&0xF, lower));
- return *this;
- }
- void appendURL(StringBuffer *dest, const char *src, size32_t len, char lower)
- {
- if (len == (size32_t)-1)
- len = (size32_t)strlen(src);
- while (len)
- {
- // isalnum seems to give weird results for chars > 127....
- unsigned char c = (unsigned char) *src;
- if (c == ' ')
- dest->append('+');
- else if ((c & 0x80) || !isalnum(*src))
- {
- dest->append('%');
- dest->appendhex(c, lower);
- }
- else
- dest->append(c);
- src++;
- len--;
- }
- }
- static StringBuffer & appendStringExpandControl(StringBuffer &out, unsigned len, const char * src, bool addBreak, bool isCpp)
- {
- const int minBreakPos = 0;
- const int commaBreakPos = 70;
- const int maxBreakPos = 120;
- const char * startLine = src;
- out.ensureCapacity(len+2);
- for (; len > 0; --len)
- {
- unsigned char c = *src++;
- bool insertBreak = false;
- bool allowBreak = true;
- switch (c)
- {
- case '\n':
- {
- out.append("\\n");
- if (src-startLine > minBreakPos)
- insertBreak = true;
- break;
- }
- case ',':
- {
- out.append(c);
- if (src-startLine > commaBreakPos)
- insertBreak = true;
- break;
- }
- case '\r': out.append("\\r"); break;
- case '\t': out.append("\\t"); break;
- case '"':
- if (isCpp)
- out.append("\\");
- out.append(c);
- break;
- case '\'':
- if (!isCpp)
- out.append("\\");
- out.append(c);
- break;
- case '\\': out.append("\\\\"); break;
- case '?':
- if (isCpp)
- {
- //stop trigraphs being generated.... quote the second ?
- out.append(c);
- if ((len!=1) && (*src == '?'))
- {
- out.append('\\');
- allowBreak = false;
- }
- }
- else
- out.append(c);
- break;
- default:
- if ((c >= ' ') && (c <= 126))
- out.append(c);
- else
- out.appendf("\\%03o", c);
- break;
- }
- if (addBreak && (insertBreak || (allowBreak && src-startLine >= maxBreakPos)))
- {
- out.append("\"").newline().append("\t\t\"");
- startLine = src;
- }
- }
- return out;
- }
- StringBuffer & appendStringAsCPP(StringBuffer &out, unsigned len, const char * src, bool addBreak)
- {
- return appendStringExpandControl(out, len, src, addBreak, true);
- }
- StringBuffer & appendStringAsECL(StringBuffer &out, unsigned len, const char * src)
- {
- return appendStringExpandControl(out, len, src, false, false);
- }
- StringBuffer & appendStringAsQuotedCPP(StringBuffer &out, unsigned len, const char * src, bool addBreak)
- {
- out.ensureCapacity(len+2);
- out.append('\"');
- appendStringAsCPP(out, len, src, addBreak);
- return out.append('\"');
- }
- StringBuffer & appendStringAsQuotedECL(StringBuffer &out, unsigned len, const char * src)
- {
- out.ensureCapacity(len+2);
- out.append('\'');
- appendStringAsECL(out, len, src);
- return out.append('\'');
- }
- void extractItem(StringBuffer & res, const char * src, const char * sep, int whichItem, bool caps)
- {
- bool isSeparator[256];
-
- memset(isSeparator,0,sizeof(isSeparator));
- unsigned char * finger = (unsigned char *)sep;
- while (*finger !=0)
- isSeparator[*finger++] = true;
- isSeparator[0]=true;
-
- finger = (unsigned char *)src;
- unsigned char next;
- loop
- {
- while (isSeparator[(next = *finger)])
- {
- if (next == 0) return;
- finger++;
- }
-
- if (whichItem == 0)
- {
- while (!isSeparator[(next = *finger)])
- {
- if (caps)
- next = toupper(next);
- res.append(next);
- finger++;
- }
- return;
- }
- while (!isSeparator[*finger])
- finger++;
-
- whichItem--;
- }
- }
- int utf8CharLen(const unsigned char *ch)
- {
- //return 1 if this is an ascii character,
- //or 0 if its not a valid utf-8 character
- if (*ch < 128)
- return 1;
- if (*ch < 192)
- return 0;
-
- unsigned char len = 1;
- for (unsigned char lead = *ch << 1; (lead & 0x80); lead <<=1)
- len++;
-
- for (unsigned pos = 1; pos < len; pos++)
- if ((ch[pos] < 128) || (ch[pos] >= 192))
- return 0; //its not a valid utf-8 character after all
- return len;
- }
- const char *encodeXML(const char *x, StringBuffer &ret, unsigned flags, unsigned len, bool utf8)
- {
- while (len)
- {
- switch(*x)
- {
- case '&':
- ret.append("&");
- break;
- case '<':
- ret.append("<");
- break;
- case '>':
- ret.append(">");
- break;
- case '\"':
- ret.append(""");
- break;
- case '\'':
- ret.append("'");
- break;
- case ' ':
- ret.append(flags & ENCODE_SPACES?" ":" ");
- break;
- case '\n':
- ret.append(flags & ENCODE_NEWLINES?" ":"\n");
- break;
- case '\r':
- ret.append(flags & ENCODE_NEWLINES?" ":"\r");
- break;
- case '\t':
- ret.append(flags & ENCODE_SPACES?"	":"\t");
- break;
- case '\0':
- if (len == (unsigned) -1)
- return x;
- ret.append(""); // hack!!! Characters below 0x20 are not legal in strict xml, even encoded.
- break;
- default:
- if (*x >= ' ' && ((byte)*x) < 128)
- ret.append(*x);
- else if (*x < ' ' && *x > 0)
- ret.append("à").appendhex(*x, true).append(';'); // HACK
- else if (utf8)
- {
- unsigned chlen = utf8CharLen((const unsigned char *)x);
- if (chlen==0)
- ret.append("&#").append((unsigned int)*(unsigned char *) x).append(';');
- else
- {
- ret.append(*x);
- while(--chlen)
- {
- if (len != (unsigned) -1)
- len--;
- ret.append(*(++x));
- }
- }
- }
- else
- ret.append("&#").append((unsigned int)*(unsigned char *) x).append(';');
- break;
- }
- if (len != (unsigned) -1)
- len--;
- ++x;
- }
- return x;
- }
- const char *encodeXML(const char *x, IIOStream &out, unsigned flags, unsigned len, bool utf8)
- {
- while (len)
- {
- switch(*x)
- {
- case '&':
- writeStringToStream(out, "&");
- break;
- case '<':
- writeStringToStream(out, "<");
- break;
- case '>':
- writeStringToStream(out, ">");
- break;
- case '\"':
- writeStringToStream(out, """);
- break;
- case '\'':
- writeStringToStream(out, "'");
- break;
- case ' ':
- writeStringToStream(out, flags & ENCODE_SPACES?" ":" ");
- break;
- case '\n':
- writeStringToStream(out, flags & ENCODE_NEWLINES?" ":"\n");
- break;
- case '\r':
- writeStringToStream(out, flags & ENCODE_NEWLINES?" ":"\r");
- break;
- case '\t':
- writeStringToStream(out, flags & ENCODE_SPACES?"	":"\t");
- break;
- case '\0':
- if (len == (unsigned) -1)
- return x;
- writeStringToStream(out, ""); // hack!!! Characters below 0x20 are not legal in strict xml, even encoded.
- break;
- default:
- if (*x >= ' ' && ((byte)*x) < 128)
- writeCharToStream(out, *x);
- else if (*x < ' ' && *x > 0)
- {
- writeStringToStream(out, "à");
- unsigned char c = *(unsigned char *)x;
- writeCharToStream(out, hex(c>>4, true));
- writeCharToStream(out, hex(c&0xF, true));
- writeCharToStream(out, ';'); // HACK
- }
- else if (utf8)
- {
- int chlen = utf8CharLen((const unsigned char *)x);
- if (chlen==0)
- {
- writeStringToStream(out, "&#");
- char tmp[12];
- unsigned written = numtostr(tmp, *(unsigned char *)x);
- out.write(written, tmp);
- writeCharToStream(out, ';');
- }
- else
- {
- writeCharToStream(out, *x);
- while(--chlen)
- {
- if (len != (unsigned) -1)
- len--;
- writeCharToStream(out, *(++x));
- }
- }
- }
- else
- {
- writeStringToStream(out, "&#");
- char tmp[12];
- unsigned written = numtostr(tmp, *(unsigned char *)x);
- out.write(written, tmp);
- writeCharToStream(out, ';');
- }
- break;
- }
- if (len != (unsigned) -1)
- len--;
- ++x;
- }
- return x;
- }
- static void writeUtf8(unsigned c, StringBuffer &out)
- {
- if (c < 0x80)
- out.append((char)c);
- else if (c < 0x800)
- {
- out.append((char)(0xC0 | (c>>6)));
- out.append((char)(0x80 | (c & 0x3F)));
- }
- else if (c < 0x10000)
- {
- out.append((char) (0xE0 | (c>>12)));
- out.append((char) (0x80 | (c>>6 & 0x3F)));
- out.append((char) (0x80 | (c & 0x3F)));
- }
- else if (c < 0x200000)
- {
- out.append((char) (0xF0 | (c>>18)));
- out.append((char) (0x80 | (c>>12 & 0x3F)));
- out.append((char) (0x80 | (c>>6 & 0x3F)));
- out.append((char) (0x80 | (c & 0x3F)));
- }
- else if (c < 0x4000000)
- {
- out.append((char) (0xF8 | (c>>24)));
- out.append((char) (0x80 | (c>>18 & 0x3F)));
- out.append((char) (0x80 | (c>>12 & 0x3F)));
- out.append((char) (0x80 | (c>>6 & 0x3F)));
- out.append((char) (0x80 | (c & 0x3F)));
- }
- else if (c < 0x80000000)
- {
- out.append((char) (0xFC | (c>>30)));
- out.append((char) (0x80 | (c>>24 & 0x3F)));
- out.append((char) (0x80 | (c>>18 & 0x3F)));
- out.append((char) (0x80 | (c>>12 & 0x3F)));
- out.append((char) (0x80 | (c>>6 & 0x3F)));
- out.append((char) (0x80 | (c & 0x3F)));
- }
- else
- assertex(false);
- }
- #define JSONSTRICT
- const char *decodeJSON(const char *j, StringBuffer &ret, unsigned len, const char **errMark)
- {
- if (!j)
- return j;
- if ((unsigned)-1 == len)
- len = (unsigned)strlen(j);
- try
- {
- for (const char *end = j+len; j<end && *j; j++)
- {
- if (*j!='\\')
- ret.append(*j);
- else
- {
- switch (*++j)
- {
- case 'u':
- {
- j++;
- if (end-j>=4)
- {
- char *endptr;
- StringAttr s(j, 4);
- unsigned val = strtoul(s.get(), &endptr, 16);
- if (endptr && !*endptr)
- {
- writeUtf8(val, ret);
- j+=3;
- break;
- }
- }
- #ifdef JSONSTRICT
- throw MakeStringException(-1, "invalid json \\u escaped sequence");
- #endif
- ret.append(*j);
- break;
- }
- case '\"':
- case '\\':
- case '/':
- ret.append(*j);
- break;
- case 'b':
- ret.append('\b');
- break;
- case 'f':
- ret.append('\f');
- break;
- case 'n':
- ret.append('\n');
- continue;
- case 'r':
- ret.append('\r');
- break;
- case 't':
- ret.append('\t');
- break;
- default:
- {
- #ifdef JSONSTRICT
- throw MakeStringException(-1, "invalid json escaped sequence");
- #endif
- ret.append('\\');
- ret.append(*j);
- break;
- }
- }
- }
- }
- }
- catch (IException *)
- {
- if (errMark) *errMark = j;
- throw;
- }
- return j;
- }
- void decodeXML(ISimpleReadStream &in, StringBuffer &out, unsigned len)
- {
- // TODO
- UNIMPLEMENTED;
- }
- const char *decodeXML(const char *x, StringBuffer &ret, const char **errMark, IEntityHelper *entityHelper, bool strict)
- {
- if (!x)
- return x;
- try
- {
- while (*x)
- {
- if ('&' == *x)
- {
- switch (x[1])
- {
- case 'a':
- switch (x[2])
- {
- case 'm':
- {
- if ('p' == x[3] && ';' == x[4])
- {
- x += 5;
- ret.append('&');
- continue;
- }
- break;
- }
- case 'p':
- {
- if ('o' == x[3] && 's' == x[4] && ';' == x[5])
- {
- x += 6;
- ret.append('\'');
- continue;
- }
- break;
- }
- }
- break;
- case 'l':
- if ('t' == x[2] && ';' == x[3])
- {
- x += 4;
- ret.append('<');
- continue;
- }
- break;
- case 'g':
- if ('t' == x[2] && ';' == x[3])
- {
- x += 4;
- ret.append('>');
- continue;
- }
- break;
- case 'q':
- if ('u' == x[2] && 'o' == x[3] && 't' == x[4] && ';' == x[5])
- {
- x += 6;
- ret.append('"');
- continue;
- }
- break;
- case 'n':
- if ('b' == x[2] && 's' == x[3] && 'p' == x[4] && ';' == x[5])
- {
- x += 6;
- writeUtf8(0xa0, ret);
- continue;
- }
- break;
- case '#':
- {
- const char *numstart = x+2;
- int base = 10;
- if (*numstart == 'x')
- {
- base = 16;
- numstart++;
- }
- char *numend;
- unsigned val = strtoul(numstart, &numend, base);
- if (numstart==numend || *numend != ';')
- {
- if (strict)
- throw MakeStringException(-1, "invalid escaped sequence");
- }
- else // always convert to utf-8. Should potentially throw error if not marked as utf-8 encoded doc and out of ascii range.
- {
- writeUtf8(val, ret);
- x = numend+1;
- continue;
- }
- break;
- }
- case ';':
- case '\0':
- if (strict)
- throw MakeStringException(-1, "invalid escaped sequence");
- break;
- default:
- if (entityHelper)
- {
- bool error = false;
- const char *start=x+1;
- const char *finger=start;
- while (*finger && *finger != ';')
- ++finger;
- if (*finger == ';')
- {
- StringBuffer entity(finger-start, start);
- if (entityHelper->find(entity, ret))
- {
- x = finger + 1;
- continue;
- }
- }
- }
- if (strict)
- throw MakeStringException(-1, "invalid escaped sequence");
- break;
- }
- }
- ret.append(*x);
- ++x;
- }
- }
- catch (IException *)
- {
- if (errMark) *errMark = x;
- throw;
- }
- return x;
- }
- StringBuffer & appendXMLOpenTag(StringBuffer &xml, const char *tag, const char *prefix, bool complete, bool close, const char *uri)
- {
- if (!tag || !*tag)
- return xml;
- xml.append('<');
- appendXMLTagName(xml, tag, prefix);
- if (uri && *uri)
- {
- xml.append(" xmlns");
- if (prefix && *prefix)
- xml.append(':').append(prefix);
- xml.append("=\"").append(uri).append('\"');
- }
- if (complete)
- {
- if (close)
- xml.append('/');
- xml.append('>');
- }
- return xml;
- }
- jlib_decl StringBuffer &appendJSONName(StringBuffer &s, const char *name)
- {
- if (!name || !*name)
- return s;
- delimitJSON(s);
- return encodeJSON(s.append('"'), name).append("\": ");
- }
- jlib_decl StringBuffer &appendfJSONName(StringBuffer &s, const char *format, ...)
- {
- va_list args;
- va_start(args, format);
- StringBuffer vs;
- vs.valist_appendf(format, args);
- va_end(args);
- return appendJSONName(s, vs);
- }
- static char hexchar[] = "0123456789ABCDEF";
- jlib_decl StringBuffer &appendJSONValue(StringBuffer& s, const char *name, unsigned len, const void *_value)
- {
- appendJSONNameOrDelimit(s, name);
- s.append('"');
- const unsigned char *value = (const unsigned char *) _value;
- for (unsigned int i = 0; i < len; i++)
- s.append(hexchar[value[i] >> 4]).append(hexchar[value[i] & 0x0f]);
- return s.append('"');
- }
- inline StringBuffer &encodeJSON(StringBuffer &s, const char ch)
- {
- switch (ch)
- {
- case '\b':
- s.append("\\b");
- break;
- case '\f':
- s.append("\\f");
- break;
- case '\n':
- s.append("\\n");
- break;
- case '\r':
- s.append("\\r");
- break;
- case '\t':
- s.append("\\t");
- break;
- case '\"':
- case '\\':
- case '/':
- s.append('\\'); //fall through
- default:
- s.append(ch);
- }
- return s;
- }
- StringBuffer &encodeJSON(StringBuffer &s, unsigned len, const char *value)
- {
- if (!value)
- return s;
- unsigned pos=0;
- while(pos<len && value[pos]!=0)
- encodeJSON(s, value[pos++]);
- return s;
- }
- StringBuffer &encodeJSON(StringBuffer &s, const char *value)
- {
- if (!value)
- return s;
- while (*value)
- encodeJSON(s, *value++);
- return s;
- }
- void decodeCppEscapeSequence(StringBuffer & out, const char * in, bool errorIfInvalid)
- {
- out.ensureCapacity((size32_t)strlen(in));
- while (*in)
- {
- char c = *in++;
- if (c == '\\')
- {
- char next = *in;
- if (next)
- {
- in++;
- switch (next)
- {
- case 'a': c = '\a'; break;
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case 'v': c = '\v'; break;
- case '\\':
- case '\'':
- case '?':
- case '\"': break;
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
- {
- c = next - '0';
- if (*in >= '0' && *in <= '7')
- {
- c = c << 3 | (*in++-'0');
- if (*in >= '0' && *in <= '7')
- c = c << 3 | (*in++-'0');
- }
- break;
- }
- case 'x':
- c = 0;
- while (isxdigit(*in))
- {
- next = *in++;
- c = c << 4;
- if (next >= '0' && next <= '9') c |= (next - '0');
- else if (next >= 'A' && next <= 'F') c |= (next - 'A' + 10);
- else if (next >= 'a' && next <= 'f') c |= (next - 'a' + 10);
- }
- break;
- default:
- if (errorIfInvalid)
- throw MakeStringException(1, "unrecognised character escape sequence '\\%c'", next);
- in--; // keep it as is.
- break;
- }
- }
- }
- out.append(c);
- }
- }
- bool isPrintable(unsigned len, const char * src)
- {
- while (len--)
- {
- if (!isprint(*((unsigned char *)src)))
- return false;
- src++;
- }
- return true;
- }
- //make this as fast as possible...
- StringBuffer & appendStringAsSQL(StringBuffer & out, unsigned len, const char * src)
- {
- if (!isPrintable(len, src))
- {
- out.append("X'");
- appendDataAsHex(out, len, src);
- return out.append('\'');
- }
- out.ensureCapacity(2 + len);
- out.append('\'');
- loop
- {
- char * next = (char *)memchr(src, '\'', len);
- if (!next)
- break;
- unsigned chunk=(size32_t)(next-src)+1;
- out.append(chunk, src).append('\'');
- len -= chunk;
- src += chunk;
- }
- return out.append(len, src).append('\'');
- }
- static const char * hexText = "0123456789ABCDEF";
- StringBuffer & appendDataAsHex(StringBuffer &out, unsigned len, const void * data)
- {
- char * target = (char *)out.reserve(len*2);
- unsigned char * start = (unsigned char *)data;
- for (unsigned count=len; count> 0; --count)
- {
- unsigned next = *start++;
- *target++ = hexText[next >>4];
- *target++ = hexText[next & 15];
- }
- return out;
- }
- bool strToBool(size_t len, const char * text)
- {
- switch (len)
- {
- case 4:
- if (memicmp(text, "true", 4) == 0)
- return true;
- break;
- case 3:
- if (memicmp(text, "yes", 3) == 0)
- return true;
- break;
- case 2:
- if (memicmp(text, "on", 2) == 0)
- return true;
- break;
- case 1:
- if ((memicmp(text, "t", 1) == 0) || (memicmp(text, "y", 1) == 0))
- return true;
- break;
- }
- while (len && isspace(*text))
- {
- len--;
- text++;
- }
- while (len-- && isdigit(*text))
- {
- if (*text++ != '0') return true;
- }
- return false;
- }
- bool strToBool(const char * text)
- {
- return strToBool(strlen(text), text);
- }
- bool clipStrToBool(size_t len, const char * text)
- {
- while (len && *text==' ')
- {
- len--;
- text++;
- }
- while (len && text[len-1]== ' ')
- len--;
- return strToBool(len, text);
- }
- bool clipStrToBool(const char * text)
- {
- return clipStrToBool(strlen(text), text);
- }
- StringBuffer & ncnameEscape(char const * in, StringBuffer & out)
- {
- if(!isalpha(*in))
- {
- out.appendf("_%02X", static_cast<unsigned char>(*in));
- in++;
- }
- char const * finger = in;
- while(*finger)
- {
- if(!isalnum(*finger))
- {
- if(finger>in)
- out.append((size32_t)(finger-in), in);
- out.appendf("_%02X", static_cast<unsigned char>(*finger));
- in = ++finger;
- }
- else
- {
- finger++;
- }
- }
- if(finger>in)
- out.append((size32_t)(finger-in), in);
- return out;
- }
- StringBuffer & ncnameUnescape(char const * in, StringBuffer & out)
- {
- char const * finger = in;
- while(*finger)
- {
- if(*finger == '_')
- {
- if(finger>in)
- out.append((size32_t)(finger-in), in);
- unsigned char chr = 16 * hex2num(finger[1]) + hex2num(finger[2]);
- out.append(static_cast<char>(chr));
- in = (finger+=3);
- }
- else
- {
- finger++;
- }
- }
- if(finger>in)
- out.append((size32_t)(finger-in), in);
- return out;
- }
- bool startsWith(const char* src, const char* dst)
- {
- while (*dst && *dst == *src) { src++; dst++; }
- return *dst==0;
- }
- bool startsWithIgnoreCase(const char* src, const char* dst)
- {
- while (*dst && tolower(*dst) == tolower(*src)) { src++; dst++; }
- return *dst==0;
- }
- bool endsWith(const char* src, const char* dst)
- {
- size_t srcLen = strlen(src);
- size_t dstLen = strlen(dst);
- if (dstLen<=srcLen)
- return memcmp(dst, src+srcLen-dstLen, dstLen)==0;
- return false;
- }
- bool endsWithIgnoreCase(const char* src, const char* dst)
- {
- size_t srcLen = strlen(src);
- size_t dstLen = strlen(dst);
- if (dstLen<=srcLen)
- return memicmp(dst, src+srcLen-dstLen, dstLen)==0;
- return false;
- }
- char *j_strtok_r(char *str, const char *delim, char **saveptr)
- {
- if (!str)
- str = *saveptr;
- char c;
- loop {
- c = *str;
- if (!c) {
- *saveptr = str;
- return NULL;
- }
- if (!strchr(delim,c))
- break;
- str++;
- }
- char *ret=str;
- do {
- c = *(++str);
- } while (c&&!strchr(delim,c));
- if (c)
- *(str++) = 0;
- *saveptr = str;
- return ret;
- }
- int j_memicmp (const void *s1, const void *s2, size32_t len)
- {
- const byte *b1 = (const byte *)s1;
- const byte *b2 = (const byte *)s2;
- int ret = 0;
- while (len&&((ret = tolower(*b1)-tolower(*b2)) == 0)) {
- b1++;
- b2++;
- len--;
- }
- return ret;
- }
- size32_t memcount(size32_t len, const char * str, char search)
- {
- size32_t count = 0;
- for (size32_t i=0; i < len; i++)
- {
- if (str[i] == search)
- count++;
- }
- return count;
- }
- StringBuffer & elideString(StringBuffer & s, unsigned maxLength)
- {
- if (s.length() > maxLength)
- {
- s.setLength(maxLength);
- s.append("...");
- }
- return s;
- }
|