123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946 |
- /*##############################################################################
- 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.
- ############################################################################## */
- #ifdef _WIN32
- #pragma warning(disable: 4996)
- #include "winprocess.hpp"
- #include <conio.h>
- #endif
- #include "platform.h"
- #include "jmisc.hpp"
- #include "jutil.hpp"
- #include "jexcept.hpp"
- #include "jmutex.hpp"
- #include "jfile.hpp"
- #include "jprop.hpp"
- #include "jerror.hpp"
- #include "jencrypt.hpp"
- #include "jerror.hpp"
- #ifdef _WIN32
- #include <mmsystem.h> // for timeGetTime
- #include <float.h> //for _isnan and _fpclass
- #else
- #include <unistd.h> // read()
- #include <sys/wait.h>
- #include <pwd.h>
- #ifdef __linux__
- #include <crypt.h>
- #include <shadow.h>
- #endif
- #include <time.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <termios.h>
- #include <signal.h>
- #include <paths.h>
- #include <cmath>
- #endif
- #include "build-config.h"
- #include "portlist.h"
- static NonReentrantSpinLock * cvtLock;
- #ifdef _WIN32
- static IRandomNumberGenerator * protectedGenerator;
- static CriticalSection * protectedGeneratorCs;
- #endif
- #if defined (__APPLE__)
- #include <mach-o/dyld.h>
- #include <mach/mach_time.h> /* mach_absolute_time */
- mach_timebase_info_data_t timebase_info = { 1,1 };
- #endif
- MODULE_INIT(INIT_PRIORITY_SYSTEM)
- {
- cvtLock = new NonReentrantSpinLock;
- #ifdef _WIN32
- protectedGenerator = createRandomNumberGenerator();
- protectedGeneratorCs = new CriticalSection;
- #endif
- #if defined (__APPLE__)
- if (mach_timebase_info(&timebase_info) != KERN_SUCCESS)
- return false;
- #endif
- return true;
- }
- MODULE_EXIT()
- {
- delete cvtLock;
- #ifdef _WIN32
- protectedGenerator->Release();
- delete protectedGeneratorCs;
- #endif
- }
- //===========================================================================
- bool safe_ecvt(size_t len, char * buffer, double value, int numDigits, int * decimal, int * sign)
- {
- #ifdef _WIN32
- return _ecvt_s(buffer, len, value, numDigits, decimal, sign) == 0;
- #else
- NonReentrantSpinBlock block(*cvtLock);
- const char * result = ecvt(value, numDigits, decimal, sign);
- if (!result)
- return false;
- strncpy(buffer, result, len);
- return true;
- #endif
- }
- bool safe_fcvt(size_t len, char * buffer, double value, int numPlaces, int * decimal, int * sign)
- {
- #ifdef _WIN32
- return _fcvt_s(buffer, len, value, numPlaces, decimal, sign) == 0;
- #else
- NonReentrantSpinBlock block(*cvtLock);
- const char * result = fcvt(value, numPlaces, decimal, sign);
- if (!result)
- return false;
- strncpy(buffer, result, len);
- return true;
- #endif
- }
- //===========================================================================
- bool j_isnan(double x)
- {
- #ifdef _MSC_VER
- return _isnan(x)!=0;
- #else
- return std::isnan(x);
- #endif
- }
- bool j_isinf(double x)
- {
- #ifdef _MSC_VER
- int fpv = _fpclass(x);
- return (fpv==_FPCLASS_PINF || fpv==_FPCLASS_NINF);
- #else
- return std::isinf(x);
- #endif
- }
- #ifdef _WIN32
- void MilliSleep(unsigned milli)
- {
- Sleep(milli);
- }
- #else
- void MilliSleep(unsigned milli)
- {
- if (milli) {
- unsigned target = msTick()+milli;
- for (;;) {
- timespec sleepTime;
-
- if (milli>=1000)
- {
- sleepTime.tv_sec = milli/1000;
- milli %= 1000;
- }
- else
- sleepTime.tv_sec = 0;
- sleepTime.tv_nsec = milli * 1000000;
- if (nanosleep(&sleepTime, NULL)==0)
- break;
- if (errno!=EINTR) {
- PROGLOG("MilliSleep err %d",errno);
- break;
- }
- milli = target-msTick();
- if ((int)milli<=0)
- break;
- }
- }
- else
- ThreadYield(); // 0 means yield
- }
- #endif
- long atolong_l(const char * s,int l)
- {
- char t[32];
- memcpy(t,s,l);
- t[l]=0;
- return atol(t);
- }
- int atoi_l(const char * s,int l)
- {
- char t[32];
- memcpy(t,s,l);
- t[l]=0;
- return atoi(t);
- }
- __int64 atoi64_l(const char * s,int l)
- {
- __int64 result = 0;
- char sign = '+';
- while (l>0 && isspace(*s))
- {
- l--;
- s++;
- }
- if (l>0 && (*s == '-' || *s == '+'))
- {
- sign = *s;
- l--;
- s++;
- }
-
- while (l>0 && isdigit(*s))
- {
- result = 10 * result + ((*s) - '0');
- l--;
- s++;
- }
- if (sign == '-')
- return -result;
- else
- return result;
- }
- #ifndef _WIN32
- static char *_itoa(unsigned long n, char *str, int b, bool sign)
- {
- char *s = str;
-
- if (sign)
- n = -n;
-
- do
- {
- byte d = n % b;
- *(s++) = d+((d<10)?'0':('a'-10));
- }
- while ((n /= b) > 0);
- if (sign)
- *(s++) = '-';
- *s = '\0';
-
- // reverse
- char *s2 = str;
- s--;
- while (s2<s)
- {
- char tc = *s2;
- *(s2++) = *s;
- *(s--) = tc;
- }
-
- return str;
- }
- char *itoa(int n, char *str, int b)
- {
- return _itoa(n, str, b, (n<0));
- }
- char *ltoa(long n, char *str, int b)
- {
- return _itoa(n, str, b, (n<0));
- }
- char *ultoa(unsigned long n, char *str, int b)
- {
- return _itoa(n, str, b, false);
- }
- #endif
- void packNumber(char * target, const char * source, unsigned slen)
- {
- unsigned next = 0;
- while (slen)
- {
- unsigned c = *source++;
- if (c == ' ') c = '0';
- next = (next << 4) + (c - '0');
- slen--;
-
- if ((slen & 1) == 0)
- {
- *target++ = next;
- next = 0;
- }
- }
- }
- void unpackNumber(char * target, const char * source, unsigned tlen)
- {
- if (tlen & 1)
- {
- *target = '0' + *source++;
- tlen--;
- }
-
- while (tlen)
- {
- unsigned char next = *source++;
- *target++ = (next >> 4) + '0';
- *target++ = (next & 15) + '0';
- tlen -= 2;
- }
- }
- //-----------------------------------------------------------------------
- class jlib_thrown_decl CorruptDllException : public CInterfaceOf<ICorruptDllException>
- {
- public:
- CorruptDllException(int code, const char *_dllName, const char *_dlError)
- : errcode(code)
- {
- VStringBuffer s("Error loading %s: %s", _dllName, _dlError);
- msg.set(s.str());
- };
- int errorCode() const { return errcode; }
- StringBuffer & errorMessage(StringBuffer &str) const
- {
- return str.append(msg.get());
- }
- MessageAudience errorAudience() const
- {
- return MSGAUD_operator;
- }
- private:
- int errcode;
- StringAttr msg;
- };
- static bool isCorruptDll(const char *errorMessage)
- {
- // yuk.
- // Add other error strings for corrupt .so files as/when we encounter them
- if (strstr(errorMessage, "file too short") ||
- strstr(errorMessage, "ELF load command past end of file"))
- return true;
- return false;
- }
- //-----------------------------------------------------------------------
- #ifdef __APPLE__
- bool findLoadedModule(StringBuffer &ret, const char *match)
- {
- bool found = false;
- unsigned count = _dyld_image_count();
- for (unsigned i = 0; i<count; i++)
- {
- const char *ln = _dyld_get_image_name(i);
- if (ln)
- {
- if (strstr(ln, match))
- {
- ret.set(ln);
- found = true;
- break;
- }
- }
- }
- return found;
- }
- #elif !defined(WIN32)
- bool findLoadedModule(StringBuffer &ret, const char *match)
- {
- bool found = false;
- FILE *diskfp = fopen("/proc/self/maps", "r");
- if (diskfp)
- {
- char ln[_MAX_PATH];
- while (fgets(ln, sizeof(ln), diskfp))
- {
- if (strstr(ln, match))
- {
- const char *fullName = strchr(ln, '/');
- if (fullName)
- {
- char * lf = (char *) strchr(fullName, '\n');
- if (lf)
- {
- *lf = 0;
- ret.set(fullName);
- found = true;
- break;
- }
- }
- }
- }
- fclose(diskfp);
- }
- return found;
- }
- #endif
- HINSTANCE LoadSharedObject(const char *name, bool isGlobal, bool raiseOnError)
- {
- #if defined(_WIN32)
- UINT oldMode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
- #else
- // don't think anything to do here.
- #endif
- DynamicScopeCtx scope;
- StringBuffer tmp;
- if (name&&isPathSepChar(*name)&&isPathSepChar(name[1])) {
- RemoteFilename rfn;
- rfn.setRemotePath(name);
- SocketEndpoint ep;
- if (!rfn.isLocal()) {
- // I guess could copy to a temporary location but currently just fail
- throw MakeStringException(-1,"LoadSharedObject: %s is not a local file",name);
- }
- name = rfn.getLocalPath(tmp).str();
- }
- #if defined(_WIN32)
- HINSTANCE h = LoadLibrary(name);
- if (!LoadSucceeded(h))
- {
- int errcode = GetLastError();
- StringBuffer errmsg;
- formatSystemError(errmsg, errcode);
- //Strip trailing newlines - makes output/errors messages cleaner
- unsigned len = errmsg.length();
- while (len)
- {
- char c = errmsg.charAt(len-1);
- if ((c != '\r') && (c != '\n'))
- break;
- len--;
- }
- errmsg.setLength(len);
- DBGLOG("Error loading %s: %d - %s", name, errcode, errmsg.str());
- if (raiseOnError)
- throw MakeStringException(0, "Error loading %s: %d - %s", name, errcode, errmsg.str());
- }
- #else
- HINSTANCE h = dlopen((char *)name, isGlobal ? RTLD_NOW|RTLD_GLOBAL : RTLD_NOW);
- if(h == NULL)
- {
- // Try again, with .so extension if necessary
- StringBuffer path, tail, ext;
- splitFilename(name, &path, &path, &tail, &ext, false);
- if (!streq(ext.str(), SharedObjectExtension))
- {
- // Assume if there's no .so, there may also be no lib at the beginning
- if (strncmp(tail.str(), SharedObjectPrefix, strlen(SharedObjectPrefix)) != 0)
- path.append(SharedObjectPrefix);
- path.append(tail).append(ext).append(SharedObjectExtension);
- name = path.str();
- h = dlopen((char *)name, isGlobal ? RTLD_NOW|RTLD_GLOBAL : RTLD_NOW);
- }
- if (h == NULL)
- {
- StringBuffer dlErrorMsg(dlerror());
- DBGLOG("Warning: Could not load %s: %s", name, dlErrorMsg.str());
- if (raiseOnError)
- {
- if (isCorruptDll(dlErrorMsg.str()))
- throw new CorruptDllException(errno, name, dlErrorMsg.str());
- else
- throw MakeStringException(0, "Error loading %s: %s", name, dlErrorMsg.str());
- }
- }
- }
- #endif
- #if defined(_WIN32)
- SetErrorMode(oldMode);
- #else
- // don't think anything to do here.
- #endif
- scope.processInitialization(h);
- return h;
- }
- void FreeSharedObject(HINSTANCE h)
- {
- ExitModuleObjects(h);
- #if defined(_WIN32)
- FreeLibrary(h);
- #else
- dlclose(h);
- #endif
- }
- bool SharedObject::load(const char * dllName, bool isGlobal, bool raiseOnError)
- {
- unload();
- #ifdef _WIN32
- UINT oldMode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
- if (dllName)
- {
- h=LoadSharedObject(dllName, isGlobal, raiseOnError);
- bRefCounted = true;
- }
- else
- {
- h=GetModuleHandle(NULL);
- bRefCounted = false;
- }
- SetErrorMode(oldMode);
- #else
- h=LoadSharedObject(dllName, isGlobal, raiseOnError);
- bRefCounted = true;
- #endif
- if (!LoadSucceeded(h))
- {
- h = 0;
- return false;
- }
- return true;
- }
- bool SharedObject::loadCurrentExecutable()
- {
- unload();
- #ifdef _WIN32
- h=GetModuleHandle(NULL);
- bRefCounted = false;
- #else
- h=dlopen(NULL, RTLD_NOW);
- bRefCounted = true;
- #endif
- return true;
- }
- bool SharedObject::loadResources(const char * dllName)
- {
- #ifdef _WIN32
- UINT oldMode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
- h = LoadLibraryEx(dllName, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
- if (!LoadSucceeded(h))
- h = LoadLibraryEx(dllName, NULL, LOAD_LIBRARY_AS_DATAFILE); // the LOAD_LIBRARY_AS_IMAGE_RESOURCE flag is not supported on all versions of Windows
- SetErrorMode(oldMode);
- return LoadSucceeded(h);
- #else
- UNIMPLEMENTED;
- #endif
- }
- void *SharedObject::getEntry(const char * name) const
- {
- return GetSharedProcedure(getInstanceHandle(), name);
- }
- void SharedObject::unload()
- {
- if (h && bRefCounted) FreeSharedObject(h);
- h = 0;
- }
- //-----------------------------------------------------------------------
- IPluggableFactory *loadPlugin(const IPropertyTree *pluginInfo)
- {
- const char *pluginName = pluginInfo->queryProp("@pluginName");
- const char *entrypoint = pluginInfo->queryProp("@entrypoint");
- if (!pluginName || !entrypoint)
- throw makeStringException(0, "Plugin information missing plugin name or entrypoint");
- Owned<SharedObject> pluginDll = new SharedObject;
- if (!pluginDll->load(pluginName, false, true))
- throw makeStringExceptionV(0, "Failed to load plugin %s", pluginName);
- IPluggableFactoryFactory pf = (IPluggableFactoryFactory) pluginDll->getEntry(entrypoint);
- if (!pf)
- throw makeStringExceptionV(0, "Function %s not found in plugin %s", entrypoint, pluginName);
- IPluggableFactory *factory = pf(pluginDll, pluginInfo);
- if (!factory)
- throw makeStringExceptionV(0, "Factory function %s returned NULL in plugin %s", entrypoint, pluginName);
- return factory;
- }
- //-----------------------------------------------------------------------
- /*
- We use a 64 bit number for generating temporaries so that we are unlikely to get any
- clashes (being paranoid). This should mean if a temporary ID is allocated 1,000,000,000
- times a second, then we won't repeat until 400 years later - assuming the machine stays
- alive for that long.
-
- Using a 32 bit number we loop after about an hour if we allocated 1,000,000 a second -
- not an unreasonable estimate for the future.
- */
- static unique_id_t nextTemporaryId;
- StringBuffer & appendUniqueId(StringBuffer & target, unique_id_t value)
- {
- //Just generate a temporary name from the __int64 -
- //Don't care about the format, therfore use base 32 in reverse order.
- while (value)
- {
- unsigned next = ((unsigned)value) & 31;
- value = value >> 5;
- if (next < 10)
- target.append((char)(next+'0'));
- else
- target.append((char)(next+'A'-10));
- }
- return target;
- }
- unique_id_t getUniqueId()
- {
- return ++nextTemporaryId;
- }
- StringBuffer & getUniqueId(StringBuffer & target)
- {
- return appendUniqueId(target, ++nextTemporaryId);
- }
- void resetUniqueId()
- {
- nextTemporaryId = 0;
- }
- //-----------------------------------------------------------------------
- #define make_numtostr(VTYPE) \
- int numtostr(char *dst, signed VTYPE _value) \
- { \
- int c; \
- unsigned VTYPE value; \
- if (_value<0) \
- { \
- *(dst++) = '-'; \
- value = (unsigned VTYPE) -_value; \
- c = 1; \
- } \
- else \
- { \
- c = 0; \
- value = _value; \
- } \
- char temp[11], *end = temp+10; \
- char *tmp = end; \
- *tmp = '\0'; \
- \
- while (value>=10) \
- { \
- unsigned VTYPE next = value / 10; \
- *(--tmp) = ((char)(value-next*10))+'0'; \
- value = next; \
- } \
- *(--tmp) = ((char)value)+'0'; \
- \
- int diff = (int)(end-tmp); \
- int i=diff+1; \
- while (i--) *(dst++) = *(tmp++); \
- \
- return c+diff; \
- }
- #define make_unumtostr(VTYPE) \
- int numtostr(char *dst, unsigned VTYPE value) \
- { \
- char temp[11], *end = temp+10; \
- char *tmp = end; \
- *tmp = '\0'; \
- \
- while (value>=10) \
- { \
- unsigned VTYPE next = value / 10; \
- *(--tmp) = ((char)(value-next*10))+'0'; \
- value = next; \
- } \
- *(--tmp) = ((char)value)+'0'; \
- \
- int diff = (int)(end-tmp); \
- int i=diff+1; \
- while (i--) *(dst++) = *(tmp++); \
- \
- return diff; \
- }
- make_numtostr(char);
- make_numtostr(short);
- make_numtostr(int);
- make_numtostr(long);
- make_unumtostr(char);
- make_unumtostr(short);
- make_unumtostr(int);
- make_unumtostr(long);
- int numtostr(char *dst, __int64 _value)
- {
- int c;
- unsigned __int64 value;
- if (_value<0)
- {
- *(dst++) = '-';
- value = (unsigned __int64) -_value;
- c = 1;
- }
- else
- {
- value = _value;
- c = 0;
- }
- char temp[24], *end = temp+23, *tmp = end;
- *tmp = '\0';
- unsigned __int32 v3 = (unsigned __int32)(value / LLC(10000000000));
- unsigned __int64 vv = value - ((unsigned __int64)v3*LLC(10000000000));
- unsigned __int32 v2 = (unsigned __int32)(vv / 100000);
- unsigned __int32 v1 = (unsigned __int32) (vv - (v2 * 100000));
- unsigned __int32 next;
- while (v1>=10)
- {
- next = v1/10;
- *(--tmp) = ((char)(v1-next*10))+'0';
- v1 = next;
- }
- *(--tmp) = ((char)v1)+'0';
- if (v2)
- {
- char *d = end-5;
- while (d != tmp)
- *(--tmp) = '0';
- while (v2>=10)
- {
- next = v2/10;
- *(--tmp) = ((char)(v2-next*10))+'0';
- v2 = next;
- }
- *(--tmp) = ((char)v2)+'0';
- }
- if (v3)
- {
- char *d = end-10;
- while (d != tmp)
- *(--tmp) = '0';
- while (v3>=10)
- {
- next = v3/10;
- *(--tmp) = ((char)(v3-next*10))+'0';
- v3 = next;
- }
- *(--tmp) = ((char)v3)+'0';
- }
-
- int diff = (int)(end-tmp);
- #ifdef USEMEMCPY
- memcpy(dst, tmp, diff+1);
- #else
- int i=diff+1;
- while (i--)
- { *(dst++) = *(tmp++);
- }
- #endif
- return c+diff;
- }
- int numtostr(char *dst, unsigned __int64 value)
- {
- char temp[24], *end = temp+23, *tmp = end;
- *tmp = '\0';
- unsigned __int32 v3 = (unsigned __int32)(value / LLC(10000000000));
- unsigned __int64 vv = value - ((unsigned __int64)v3*LLC(10000000000));
- unsigned __int32 v2 = (unsigned __int32)(vv / 100000);
- unsigned __int32 v1 = (unsigned __int32) (vv - (v2 * 100000));
- unsigned __int32 next;
- while (v1>=10)
- {
- next = v1/10;
- *(--tmp) = ((char)(v1-next*10))+'0';
- v1 = next;
- }
- *(--tmp) = ((char)v1)+'0';
- if (v2)
- {
- char *d = end-5;
- while (d != tmp)
- *(--tmp) = '0';
- while (v2>=10)
- {
- next = v2/10;
- *(--tmp) = ((char)(v2-next*10))+'0';
- v2 = next;
- }
- *(--tmp) = ((char)v2)+'0';
- }
- if (v3)
- {
- char *d = end-10;
- while (d != tmp)
- *(--tmp) = '0';
- while (v3>=10)
- {
- next = v3/10;
- *(--tmp) = ((char)(v3-next*10))+'0';
- v3 = next;
- }
- *(--tmp) = ((char)v3)+'0';
- }
-
- int diff = (int)(end-tmp);
- #ifdef USEMEMCPY
- memcpy(dst, tmp, diff+1);
- #else
- int i=diff+1;
- while (i--)
- { *(dst++) = *(tmp++);
- }
- #endif
- return diff;
- }
- class CRandom: public IRandomNumberGenerator, public CInterface
- {
- // from Knuth if I remember correctly
- #define HISTORYSIZE 55
- #define HISTORYMAX (HISTORYSIZE-1)
- unsigned history[HISTORYSIZE];
- unsigned ptr;
- unsigned lower;
- public:
- IMPLEMENT_IINTERFACE;
- CRandom()
- {
- seed((unsigned)get_cycles_now());
- }
-
- void seed(unsigned su)
- {
- ptr = HISTORYMAX;
- lower = 23;
- double s = 91648253+su;
- double a = 1389796;
- double m = 2147483647;
- unsigned i;
- for (i=0;i<HISTORYSIZE;i++) { // just used for initialization
- s *= a;
- int q = (int)(s/m);
- s -= q*m;
- history[i] = (unsigned)s;
- }
- }
-
- unsigned next()
- {
- if (ptr==0) {
- ptr = HISTORYMAX;
- lower--;
- }
- else {
- ptr--;
- if (lower==0)
- lower = HISTORYMAX;
- else
- lower--;
- }
- unsigned ret = history[ptr]+history[lower];
- history[ptr] = ret;
- return ret;
- }
- } RandomMain;
- static CriticalSection gobalRandomSect;
- unsigned getRandom()
- {
- CriticalBlock block(gobalRandomSect); // this is a shame but it is not thread-safe without
- return RandomMain.next();
- }
- void seedRandom(unsigned seed)
- {
- CriticalBlock block(gobalRandomSect);
- RandomMain.seed(seed);
- }
- IRandomNumberGenerator *createRandomNumberGenerator()
- {
- return new CRandom();
- }
- void fillRandomData(size32_t writeSz, void *_writePtr)
- {
- static thread_local Owned<IRandomNumberGenerator> generator = createRandomNumberGenerator();
- unsigned *writePtr = (unsigned *)_writePtr;
- unsigned *bufEnd = (unsigned *)(((byte *)writePtr)+writeSz);
- while (true)
- {
- size32_t diff = (const byte *)bufEnd - (const byte *)writePtr;
- unsigned r = generator->next();
- if (diff<sizeof(unsigned))
- {
- // last few bytes
- byte *p = (byte *)writePtr;
- while (diff--)
- {
- *p++ = r & 0xff;
- r >>= 8;
- }
- break;
- }
- *writePtr++ = r;
- }
- }
- void fillRandomData(size32_t writeSz, MemoryBuffer &mb)
- {
- void *writePtr = mb.reserveTruncate(writeSz);
- fillRandomData(writeSz, writePtr);
- }
- #ifdef WIN32
- // This function has the same prototype for rand_r, but seed is ignored.
- jlib_decl int rand_r(unsigned int *seed)
- {
- CriticalBlock procedure(*protectedGeneratorCs);
- return (protectedGenerator->next() & RAND_R_MAX);
- }
- #if ((RAND_R_MAX & (RAND_R_MAX+1)) != 0)
- #error RAND_R_MAX expected to be 2^n-1
- #endif
- #endif
- class CShuffledIterator: implements IShuffledIterator, public CInterface
- {
- CRandom rand;
- unsigned *seq;
- unsigned idx;
- unsigned num;
- public:
- IMPLEMENT_IINTERFACE;
- CShuffledIterator(unsigned _num)
- {
- num = _num;
- idx = 0;
- seq = NULL;
- }
- ~CShuffledIterator()
- {
- delete [] seq;
- }
- bool first()
- {
- if (!seq)
- seq = new unsigned[num];
- idx = 0;
- if (!num)
- return false;
- unsigned i;
- for (i=0;i<num;i++)
- seq[i] = i;
- while (i>1) {
- unsigned j = rand.next()%i; // NB i is correct here
- i--;
- unsigned t = seq[j];
- seq[j] = seq[i];
- seq[i] = t;
- }
- return true;
- }
- bool isValid()
- {
- return idx<num;
- }
- bool next()
- {
- if (idx<num)
- idx++;
- return isValid();
- }
- unsigned get()
- {
- return lookup(idx);
- }
- unsigned lookup(unsigned i)
- {
- if (!seq)
- first();
- return seq[i%num];
- }
- void seed(unsigned su)
- {
- rand.seed(su);
- }
- };
- extern jlib_decl IShuffledIterator *createShuffledIterator(unsigned n)
- {
- return new CShuffledIterator(n);
- }
- /* Check whether a string is a valid C identifier. */
- bool isCIdentifier(const char* id)
- {
- if (id==NULL || *id==0)
- return false;
-
- if (!isalpha(*id) && *id!='_')
- return false;
- for (++id; *id != 0; id++)
- if (!isalnum(*id) && *id!='_')
- return false;
- return true;
- }
- //-------------------------------------------------------------------
- static const char BASE64_enc[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
- static const unsigned char BASE64_dec[256] =
- {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f,
- 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
- 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- static const char pad = '=';
- //
- // Encode the input in a base64 format
- //
- // const void * data -> data to be encoded
- // long length -> length in bytes of this data
- // IIOStream &out -> Write the result into this stream
- //
- void JBASE64_Encode(const void *data, long length, IIOStream &out, bool addLineBreaks/*=true*/)
- {
- const unsigned char *in = static_cast<const unsigned char *>(data);
- unsigned char one;
- unsigned char two;
- unsigned char three;
- long i;
- for(i = 0; i < length && length - i >= 3;)
- {
- one = *(in + i++);
- two = *(in + i++);
- three = *(in + i++);
- // 0x30 -> 0011 0000 b
- // 0x3c -> 0011 1100 b
- // 0x3f -> 0011 1111 b
- //
- writeCharToStream(out, BASE64_enc[one >> 2]);
- writeCharToStream(out, BASE64_enc[((one << 4) & 0x30) | (two >> 4)]);
- writeCharToStream(out, BASE64_enc[((two << 2) & 0x3c) | (three >> 6)]);
- writeCharToStream(out, BASE64_enc[three & 0x3f]);
- if(addLineBreaks && (i % 54 == 0))
- {
- writeCharToStream(out, '\n');
- }
- }
- switch(length - i)
- {
- case 2:
- one = *(in + i++);
- two = *(in + i++);
- writeCharToStream(out, BASE64_enc[one >> 2]);
- writeCharToStream(out, BASE64_enc[((one << 4) & 0x30) | (two >> 4)]);
- writeCharToStream(out, BASE64_enc[(two << 2) & 0x3c]);
- writeCharToStream(out, pad);
- break;
- case 1:
- one = *(in + i++);
- writeCharToStream(out, BASE64_enc[one >> 2]);
- writeCharToStream(out, BASE64_enc[(one << 4) & 0x30]);
- writeCharToStream(out, pad);
- writeCharToStream(out, pad);
- break;
- }
- }
- // JCSMORE could have IIOStream StringBuffer adapter inplace of below.
- void JBASE64_Encode(const void *data, long length, StringBuffer &out, bool addLineBreaks/*=true*/)
- {
- const unsigned char *in = static_cast<const unsigned char *>(data);
- unsigned char one;
- unsigned char two;
- unsigned char three;
- long i;
- for(i = 0; i < length && length - i >= 3;)
- {
- one = *(in + i++);
- two = *(in + i++);
- three = *(in + i++);
- // 0x30 -> 0011 0000 b
- // 0x3c -> 0011 1100 b
- // 0x3f -> 0011 1111 b
- //
- out.append(BASE64_enc[one >> 2]);
- out.append(BASE64_enc[((one << 4) & 0x30) | (two >> 4)]);
- out.append(BASE64_enc[((two << 2) & 0x3c) | (three >> 6)]);
- out.append(BASE64_enc[three & 0x3f]);
- if(addLineBreaks && (i % 54 == 0))
- {
- out.append('\n');
- }
- }
- switch(length - i)
- {
- case 2:
- one = *(in + i++);
- two = *(in + i++);
- out.append(BASE64_enc[one >> 2]);
- out.append(BASE64_enc[((one << 4) & 0x30) | (two >> 4)]);
- out.append(BASE64_enc[(two << 2) & 0x3c]);
- out.append(pad);
- break;
- case 1:
- one = *(in + i++);
- out.append(BASE64_enc[one >> 2]);
- out.append(BASE64_enc[(one << 4) & 0x30]);
- out.append(pad);
- out.append(pad);
- break;
- }
- }
- //
- // Decode the input in a base64 format
- //
- // const char *in -> The string to be decoded
- // StringBuffer & out -> Decoded string here
- //
- StringBuffer &JBASE64_Decode(ISimpleReadStream &in, StringBuffer &out)
- {
- unsigned char c1, cs[3];
- unsigned char &c2 = *cs;
- unsigned char &c3 = *(cs+1);
- unsigned char &c4 = *(cs+2);
- unsigned char d1, d2, d3, d4;
- for(;;)
- {
- if (in.read(1, &c1))
- break;
- if (!c1)
- break;
- else if (!isspace(c1))
- {
- in.read(3, cs);
- d1 = BASE64_dec[c1];
- d2 = BASE64_dec[c2];
- d3 = BASE64_dec[c3];
- d4 = BASE64_dec[c4];
- out.append((char)((d1 << 2) | (d2 >> 4)));
- if(c3 == pad)
- break;
- out.append((char)((d2 << 4) | (d3 >> 2)));
- if(c4 == pad)
- break;
- out.append((char)((d3 << 6) | d4));
- }
- }
- return out;
- }
- MemoryBuffer &JBASE64_Decode(ISimpleReadStream &in, MemoryBuffer &out)
- {
- unsigned char c1, cs[3];
- unsigned char &c2 = *cs;
- unsigned char &c3 = *(cs+1);
- unsigned char &c4 = *(cs+2);
- unsigned char d1, d2, d3, d4;
- for(;;)
- {
- if (in.read(1, &c1) != 1)
- break;
- if (!c1)
- break;
- else if (!isspace(c1))
- {
- in.read(3, cs);
- d1 = BASE64_dec[c1];
- d2 = BASE64_dec[c2];
- d3 = BASE64_dec[c3];
- d4 = BASE64_dec[c4];
- out.append((char)((d1 << 2) | (d2 >> 4)));
- if(c3 == pad)
- break;
- out.append((char)((d2 << 4) | (d3 >> 2)));
- if(c4 == pad)
- break;
- out.append((char)((d3 << 6) | d4));
- }
- }
- return out;
- }
- StringBuffer &JBASE64_Decode(const char *incs, StringBuffer &out)
- {
- unsigned char c1, c2, c3, c4;
- unsigned char d1, d2, d3, d4;
- for(;;)
- {
- c1 = *incs++;
- if (!c1)
- break;
- else if (!isspace(c1))
- {
- c2 = *incs++;
- c3 = *incs++;
- c4 = *incs++;
- d1 = BASE64_dec[c1];
- d2 = BASE64_dec[c2];
- d3 = BASE64_dec[c3];
- d4 = BASE64_dec[c4];
- out.append((char)((d1 << 2) | (d2 >> 4)));
- if(c3 == pad)
- break;
- out.append((char)((d2 << 4) | (d3 >> 2)));
- if(c4 == pad)
- break;
- out.append((char)((d3 << 6) | d4));
- }
- }
- return out;
- }
- MemoryBuffer &JBASE64_Decode(const char *incs, MemoryBuffer &out)
- {
- unsigned char c1, c2, c3, c4;
- unsigned char d1, d2, d3, d4;
- for(;;)
- {
- c1 = *incs++;
- if (!c1)
- break;
- else if (!isspace(c1))
- {
- c2 = *incs++;
- c3 = *incs++;
- c4 = *incs++;
- d1 = BASE64_dec[c1];
- d2 = BASE64_dec[c2];
- d3 = BASE64_dec[c3];
- d4 = BASE64_dec[c4];
- out.append((char)((d1 << 2) | (d2 >> 4)));
- if(c3 == pad)
- break;
- out.append((char)((d2 << 4) | (d3 >> 2)));
- if(c4 == pad)
- break;
- out.append((char)((d3 << 6) | d4));
- }
- }
- return out;
- }
- bool JBASE64_Decode(size32_t length, const char *incs, StringBuffer &out)
- {
- out.ensureCapacity(((length / 4) + 1) * 3);
- const char * end = incs + length;
- unsigned char c1;
- unsigned char c[4];
- unsigned cIndex = 0;
- unsigned char d1, d2, d3, d4;
- bool fullQuartetDecoded = false;
- while (incs < end)
- {
- c1 = *incs++;
- if (isspace(c1))
- continue;
- if (!BASE64_dec[c1] && ('A' != c1) && (pad != c1))
- {
- // Forbidden char
- fullQuartetDecoded = false;
- break;
- }
- c[cIndex++] = c1;
- fullQuartetDecoded = false;
- if (4 == cIndex)
- {
- d1 = BASE64_dec[c[0]];
- d2 = BASE64_dec[c[1]];
- d3 = BASE64_dec[c[2]];
- d4 = BASE64_dec[c[3]];
- out.append((char)((d1 << 2) | (d2 >> 4)));
- fullQuartetDecoded = true;
- if (pad == c[2])
- break;
- out.append((char)((d2 << 4) | (d3 >> 2)));
- if( pad == c[3])
- break;
- out.append((char)((d3 << 6) | d4));
- cIndex = 0;
- }
- }
- return fullQuartetDecoded;
- }
- static const char enc32[33] =
- "abcdefghijklmnopqrstuvwxyz"
- "234567";
- static inline void encode5_32(const byte *in,StringBuffer &out)
- {
- // 5 bytes in 8 out
- out.append(enc32[(in[0] >> 3)]);
- out.append(enc32[((in[0] & 0x07) << 2) | (in[1] >> 6)]);
- out.append(enc32[(in[1] >> 1) & 0x1f]);
- out.append(enc32[((in[1] & 0x01) << 4) | (in[2] >> 4)]);
- out.append(enc32[((in[2] & 0x0f) << 1) | (in[3] >> 7)]);
- out.append(enc32[(in[3] >> 2) & 0x1f]);
- out.append(enc32[((in[3] & 0x03) << 3) | (in[4] >> 5)]);
- out.append(enc32[in[4] & 0x1f]);
- }
- void JBASE32_Encode(const char *in,StringBuffer &out)
- {
- size32_t len = (size32_t)strlen(in);
- while (len>=5) {
- encode5_32((const byte *)in,out);
- in += 5;
- len -= 5;
- }
- byte rest[5];
- memcpy(rest,in,len);
- memset(rest+len,0,5-len);
- encode5_32(rest,out);
- }
- static inline byte decode_32c(char c)
- {
- byte b = (byte)c;
- if (b>=97) {
- if (b<=122)
- return b-97;
- }
- else if ((b>=50)&&(b<=55))
- return b-24;
- return 0;
- }
- void JBASE32_Decode(const char *bi,StringBuffer &out)
- {
- for (;;) {
- byte b[8];
- for (unsigned i=0;i<8;i++)
- b[i] = decode_32c(*(bi++));
- byte o;
- o = ((b[0] & 0x1f) << 3) | ((b[1] & 0x1c) >> 2);
- if (!o) return;
- out.append(o);
- o = ((b[1] & 0x03) << 6) | ((b[2] & 0x1f) << 1) | ((b[3] & 0x10) >> 4);
- if (!o) return;
- out.append(o);
- o = ((b[3] & 0x0f) << 4) | ((b[4] & 0x1e) >> 1);
- if (!o) return;
- out.append(o);
- o = ((b[4] & 0x01) << 7) | ((b[5] & 0x1f) << 2) | ((b[6] & 0x18) >> 3);
- if (!o) return;
- out.append(o);
- o = ((b[6] & 0x07) << 5) | (b[7] & 0x1f);
- if (!o) return;
- out.append(o);
- }
- }
- static void DelimToStringArray(const char *csl, StringArray &dst, const char *delim, bool deldup, bool trimSpaces)
- {
- if (!csl)
- return;
- const char *s = csl;
- char c;
- if (!delim)
- c = ',';
- else if (*delim&&!delim[1])
- c = *delim;
- else
- c = 0;
- StringBuffer str;
- unsigned dstlen=dst.ordinality();
- for (;;)
- {
- if (trimSpaces)
- while (isspace(*s))
- s++;
- if (!*s&&(dst.ordinality()==dstlen)) // this check is to allow trailing separators (e.g. ",," is 3 (NULL) entries) but not generate an entry for ""
- break;
- const char *e = s;
- while (*e) {
- if (c) {
- if (*e==c)
- break;
- }
- else if (strchr(delim,*e))
- break;
- e++;
- }
- str.clear().append((size32_t)(e-s),s);
- if (trimSpaces)
- str.clip();
- if (deldup) {
- const char *s1 = str.str();
- unsigned i;
- for (i=0;i<dst.ordinality();i++)
- if (strcmp(s1,dst.item(i))==0)
- break;
- if (i>=dst.ordinality())
- dst.append(s1);
- }
- else
- dst.append(str.str());
- if (!*e)
- break;
- s = e+1;
- }
- }
- void StringArray::appendList(const char *list, const char *delim, bool trimSpaces)
- {
- DelimToStringArray(list, *this, delim, false, trimSpaces);
- }
- void StringArray::appendListUniq(const char *list, const char *delim, bool trimSpaces)
- {
- DelimToStringArray(list, *this, delim, true, trimSpaces);
- }
- StringBuffer &StringArray::getString(StringBuffer &ret, const char *delim)
- {
- ForEachItemIn(i, *this)
- {
- const char *v = item(i);
- ret.append(v);
- if (i+1 != ordinality())
- ret.append(delim);
- }
- return ret;
- }
- void StringArray::sortAscii(bool nocase)
- {
- PARENT::sort(nocase ? CCmp::compareNC : CCmp::compare);
- }
- void StringArray::sortAsciiReverse(bool nocase)
- {
- PARENT::sort(nocase ? CCmp::revCompareNC : CCmp::revCompare);
- }
- void StringArray::sortCompare(int (*compare)(const char * const * l, const char * const * r))
- {
- PARENT::sort(compare);
- }
- #ifdef _WIN32
- unsigned msTick() { return timeGetTime(); }
- unsigned usTick()
- {
- static __int64 freq=0;
- LARGE_INTEGER v;
- if (!freq) {
- if (QueryPerformanceFrequency(&v))
- freq=v.QuadPart;
- if (!freq)
- return 0;
- }
- if (!QueryPerformanceCounter(&v))
- return 0;
- return (unsigned) ((v.QuadPart*1000000)/freq); // hope dividend doesn't overflow though it might
- }
- #else
- #ifdef CLOCK_MONOTONIC
- static bool use_gettimeofday=false;
- unsigned msTick()
- {
- if (!use_gettimeofday) {
- timespec tm;
- if (clock_gettime(CLOCK_MONOTONIC, &tm)>=0)
- return tm.tv_sec*1000+(tm.tv_nsec/1000000);
- use_gettimeofday = true;
- fprintf(stderr,"clock_gettime CLOCK_MONOTONIC returns %d",errno); // don't use PROGLOG
- }
- struct timeval tm;
- gettimeofday(&tm,NULL);
- return tm.tv_sec*1000+(tm.tv_usec/1000);
- }
- unsigned usTick()
- {
- if (!use_gettimeofday) {
- timespec tm;
- if (clock_gettime(CLOCK_MONOTONIC, &tm)>=0)
- return tm.tv_sec*1000000+(tm.tv_nsec/1000);
- use_gettimeofday = true;
- fprintf(stderr,"clock_gettime CLOCK_MONOTONIC returns %d",errno); // don't use PROGLOG
- }
- struct timeval tm;
- gettimeofday(&tm,NULL);
- return tm.tv_sec*1000000+tm.tv_usec;
- }
- #elif __APPLE__
- unsigned usTick()
- {
- __uint64 nano = mach_absolute_time() * (uint64_t)timebase_info.numer / (uint64_t)timebase_info.denom;
- return nano / 1000;
- }
- unsigned msTick()
- {
- __uint64 nano = mach_absolute_time() * (uint64_t)timebase_info.numer / (uint64_t)timebase_info.denom;
- return nano / 1000000;
- }
- #else
- #warning "clock_gettime(CLOCK_MONOTONIC) not supported"
- unsigned msTick()
- {
- struct timeval tm;
- gettimeofday(&tm,NULL);
- return tm.tv_sec*1000+(tm.tv_usec/1000);
- }
- unsigned usTick()
- {
- struct timeval tm;
- gettimeofday(&tm,NULL);
- return tm.tv_sec*1000000+tm.tv_usec;
- }
- #endif
- #endif
- int write_pidfile(const char * instance)
- {
- #ifndef _WIN32
- StringBuffer path;
- path.append(PID_DIR).append(PATHSEPCHAR).append(instance).append(".pid");
- FILE * fd = fopen(path.str(),"w");
- if (fd==NULL) {
- perror("Unable to open pidfile for writing");
- return(EXIT_FAILURE);
- }
- fprintf(fd,"%d",getpid());
- fclose(fd);
- return(EXIT_SUCCESS);
- #endif
- return 0;
- }
- //Calculate the greatest common divisor using Euclid's method
- unsigned __int64 greatestCommonDivisor(unsigned __int64 left, unsigned __int64 right)
- {
- for (;;)
- {
- if (left > right)
- {
- if (right == 0)
- return left;
- left = left % right;
- }
- else
- {
- if (left == 0)
- return right;
- right = right % left;
- }
- }
- }
- //The whole point of this function is to force memory to be accessed on the stack to avoid page faults.
- //Therefore disable the gcc warning.
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wuninitialized"
- #endif
- //In a separate module to stop optimizer removing the surrounding catch.
- void doStackProbe()
- {
- byte local;
- const volatile byte * x = (const byte *)&local;
- byte forceload __attribute__((unused)) = x[-4096];
- }
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
- #ifdef _WIN32
- DWORD dwTlsIndex = -1;
- CriticalSection tlscrit;
- void initThreadLocal(int len, void* val)
- {
- {
- CriticalBlock b(tlscrit);
- if(dwTlsIndex == -1)
- {
- if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
- throw MakeStringException(-1, "TlsAlloc failed");
- }
- }
- LPVOID lpvData;
-
- lpvData = TlsGetValue(dwTlsIndex);
- if (lpvData != 0)
- LocalFree((HLOCAL) lpvData);
-
- // Initialize the TLS index for this thread.
- lpvData = (LPVOID) LocalAlloc(LPTR, len);
- memcpy((char*)lpvData, val, len);
- if (! TlsSetValue(dwTlsIndex, lpvData))
- throw MakeStringException(-1, "TlsSetValue error");
- }
- void* getThreadLocalVal()
- {
- if(dwTlsIndex == -1)
- return NULL;
- return TlsGetValue(dwTlsIndex);
- }
- void clearThreadLocal()
- {
- if(dwTlsIndex == -1)
- return;
- LPVOID lpvData = TlsGetValue(dwTlsIndex);
- if (lpvData != 0)
- {
- LocalFree((HLOCAL) lpvData);
- if (! TlsSetValue(dwTlsIndex, NULL))
- throw MakeStringException(-1, "TlsSetValue error");
- }
- }
- #else
- // Key for the thread-specific buffer
- static pthread_key_t buffer_key;
- // Once-only initialisation of the key
- static pthread_once_t buffer_key_once = PTHREAD_ONCE_INIT;
- // Free the thread-specific buffer
- static void buffer_destroy(void * buf)
- {
- if(buf)
- free(buf);
- }
- // Allocate the key
- static void buffer_key_alloc()
- {
- pthread_key_create(&buffer_key, buffer_destroy);
- }
- // Allocate the thread-specific buffer
- void initThreadLocal(int len, void* val)
- {
- pthread_once(&buffer_key_once, buffer_key_alloc);
- void* valbuf = malloc(len);
- memcpy(valbuf, val, len);
- pthread_setspecific(buffer_key, valbuf);
- }
- // Return the thread-specific buffer
- void* getThreadLocalVal()
- {
- return (char *) pthread_getspecific(buffer_key);
- }
- void clearThreadLocal()
- {
- }
- #endif
- StringBuffer &expandMask(StringBuffer &buf, const char *mask, unsigned p, unsigned n)
- {
- const char *s=mask;
- if (s)
- while (*s) {
- char next = *(s++);
- if (next=='$') {
- char pc = toupper(s[0]);
- if (pc&&(s[1]=='$')) {
- if (pc=='P') {
- buf.append(p+1);
- next = 0;
- s+=2;
- }
- else if (pc=='N') {
- buf.append(n);
- next = 0;
- s+=2;
- }
- }
- }
- if (next)
- buf.append(next);
- }
- return buf;
- }
- static const char *findExtension(const char *fn)
- {
- if (!fn)
- return NULL;
- const char *ret = strchr(fn,'.');
- if (ret) {
- for (;;) {
- ret++;
- const char *s = strchr(ret,'.');
- if (!s)
- break;
- ret = s;
- }
- }
- return ret;
- }
- unsigned runExternalCommand(StringBuffer &output, StringBuffer &error, const char *cmd, const char *input)
- {
- try
- {
- Owned<IPipeProcess> pipe = createPipeProcess();
- int ret = START_FAILURE;
- if (pipe->run(cmd, cmd, ".", input != NULL, true, true, 1024*1024))
- {
- if (input)
- {
- pipe->write(strlen(input), input);
- pipe->closeInput();
- }
- char buf[1024];
- while (true)
- {
- size32_t read = pipe->read(sizeof(buf), buf);
- if (!read)
- break;
- output.append(read, buf);
- }
- ret = pipe->wait();
- while (true)
- {
- size32_t read = pipe->readError(sizeof(buf), buf);
- if (!read)
- break;
- error.append(read, buf);
- }
- }
- return ret;
- }
- catch (IException *E)
- {
- E->Release();
- output.clear();
- return START_FAILURE;
- }
- }
- bool matchesMask(const char *fn, const char *mask, unsigned p, unsigned n)
- {
- StringBuffer match;
- expandMask(match,mask,p,n);
- return (stricmp(fn,match.str())==0);
- }
- bool constructMask(StringAttr &attr, const char *fn, unsigned p, unsigned n)
- {
- StringBuffer buf;
- const char *ext = findExtension(fn);
- if (!ext)
- return false;
- buf.append((size32_t)(ext-fn),fn).append("_$P$_of_$N$");
- if (matchesMask(fn,buf.str(),p,n)) {
- attr.set(buf.str());
- return true;
- }
- return false;
- }
- bool deduceMask(const char *fn, bool expandN, StringAttr &mask, unsigned &pret, unsigned &nret)
- {
- const char *e = findExtension(fn);
- if (!e)
- return false;
- for (;;) {
- const char *s=e;
- if (*s=='_') {
- s++;
- unsigned p = 0;
- while (isdigit(*s))
- p = p*10+*(s++)-'0';
- if (p&&(memcmp(s,"_of_",4)==0)) {
- s += 4;
- pret = p-1;
- p = 0;
- while (isdigit(*s))
- p = p*10+*(s++)-'0';
- nret = p;
- if (((*s==0)||(*s=='.'))&&(p>pret)) {
- StringBuffer buf;
- if (expandN)
- buf.append((size32_t)(e-fn),fn).append("_$P$_of_").append(p);
- else
- buf.append((size32_t)(e-fn),fn).append("_$P$_of_$N$");
- if (*s=='.')
- buf.append(s);
- mask.set(buf);
- return true;
- }
- }
- }
- e--;
- for (;;) {
- if (e==fn)
- return false;
- if (*(e-1)=='.')
- break;
- e--;
- }
- }
- return false;
- }
- //==============================================================
- #ifdef _WIN32
- class CWindowsAuthenticatedUser: implements IAuthenticatedUser, public CInterface
- {
- StringAttr name;
- HANDLE usertoken;
- public:
- IMPLEMENT_IINTERFACE;
- CWindowsAuthenticatedUser()
- {
- usertoken = (HANDLE)-1;
- }
- ~CWindowsAuthenticatedUser()
- {
- if (usertoken != (HANDLE)-1)
- CloseHandle(usertoken);
- }
- bool login(const char *user, const char *passwd)
- {
- name.clear();
- if (usertoken != (HANDLE)-1)
- CloseHandle(usertoken);
- StringBuffer domain("");
- const char *ut = strchr(user,'\\');
- if (ut) {
- domain.clear().append((size32_t)(ut-user),user);
- user = ut+1;
- }
- BOOL res = LogonUser((LPTSTR)user,(LPTSTR)(domain.length()==0?NULL:domain.str()),(LPTSTR)passwd,LOGON32_LOGON_NETWORK,LOGON32_PROVIDER_DEFAULT,&usertoken);
- if (res==0)
- return false;
- name.set(user);
- return true;
- }
- void impersonate()
- {
- if (!ImpersonateLoggedOnUser(usertoken))
- throw makeOsException(GetLastError());
- }
- void revert()
- {
- RevertToSelf();
- }
- const char *username()
- {
- return name.get();
- }
- };
- IAuthenticatedUser *createAuthenticatedUser() { return new CWindowsAuthenticatedUser; }
- #elif defined(__linux__)
- class CLinuxAuthenticatedUser: implements IAuthenticatedUser, public CInterface
- {
- StringAttr name;
- uid_t uid;
- gid_t gid;
- uid_t saveuid;
- gid_t savegid;
- public:
- IMPLEMENT_IINTERFACE;
- bool login(const char *user, const char *passwd)
- {
- name.clear();
- const char *ut = strchr(user,'\\');
- if (ut)
- user = ut+1; // remove windows domain
- struct passwd *pw;
- char *epasswd;
- if ((pw = getpwnam(user)) == NULL)
- return false;
- struct spwd *spwd = getspnam(user);
- if (spwd)
- epasswd = spwd->sp_pwdp;
- else
- epasswd = pw->pw_passwd;
- if (!epasswd||!*epasswd)
- return false;
- if (strcmp(crypt(passwd,epasswd),epasswd)!=0)
- return false;
- uid = pw->pw_uid;
- gid = pw->pw_gid;
- name.set(pw->pw_name);
- return true;
- }
- void impersonate()
- {
- saveuid = geteuid();
- savegid = getegid();
- if (setegid(gid) == -1)
- throw makeOsException(errno, "Failed to set effective group id");
- if (seteuid(uid) == -1)
- throw makeOsException(errno, "Failed to set effective user id");
- }
- void revert()
- {
- if (seteuid(saveuid) == -1)
- throw makeOsException(errno, "Failed to restore effective group id");
- if (setegid(savegid) == -1)
- throw makeOsException(errno, "Failed to restore effective user id");
- }
- const char *username()
- {
- return name.get();
- }
- };
- IAuthenticatedUser *createAuthenticatedUser() { return new CLinuxAuthenticatedUser; }
- #elif defined(__FreeBSD__) || defined (__APPLE__)
- IAuthenticatedUser *createAuthenticatedUser() { UNIMPLEMENTED; }
- #endif
- extern jlib_decl void serializeAtom(MemoryBuffer & target, IAtom * name)
- {
- StringBuffer lower(str(name));
- lower.toLowerCase();
- serialize(target, lower.str());
- }
- extern jlib_decl IAtom * deserializeAtom(MemoryBuffer & source)
- {
- StringAttr text;
- deserialize(source, text);
- if (text)
- return createAtom(text);
- return NULL;
- }
- //==============================================================
- static const char enc64[65] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789-_";
- static inline void encode3_64(byte *in,StringBuffer &out)
- {
- // 3 bytes in 4 out
- out.append(enc64[in[0]>>2]);
- out.append(enc64[((in[0] << 4) & 0x30) | (in[1] >> 4)]);
- out.append(enc64[((in[1] << 2) & 0x3c) | (in[2] >> 6)]);
- out.append(enc64[in[2] & 0x3f]);
- }
- static NonReentrantSpinLock lock;
- static unsigned uuidbin[5] = {0,0,0,0,0};
- StringBuffer &genUUID(StringBuffer &out, bool nocase)
- { // returns a 24 char UUID for nocase=false or 32 char for nocase=true
- lock.enter();
- // could be quicker using statics
- if (uuidbin[0]==0) {
- queryHostIP().getNetAddress(sizeof(uuidbin[0]),uuidbin);
- uuidbin[1] = (unsigned)GetCurrentProcessId();
- }
- time_t t;
- time(&t);
- uuidbin[2] = (unsigned)t;
- uuidbin[3] = msTick();
- uuidbin[4]++;
- byte *in = (byte *)uuidbin;
- if (nocase) {
- encode5_32(in,out);
- encode5_32(in+5,out);
- encode5_32(in+10,out);
- encode5_32(in+15,out);
- }
- else {
- encode3_64(in,out);
- encode3_64(in+3,out);
- encode3_64(in+6,out);
- encode3_64(in+9,out);
- byte tmp[3]; // drop two msb bytes from msec time
- tmp[0] = in[12];
- tmp[1] = in[13];
- tmp[2] = in[16];
- encode3_64(tmp,out);
- encode3_64(in+17,out);
- }
- lock.leave();
- return out;
- }
- //==============================================================
- class jlib_decl CNameCountTable : public AtomRefTable
- {
- public:
- CNameCountTable(bool _nocase=false) : AtomRefTable(_nocase) { }
- StringBuffer &dump(StringBuffer &str)
- {
- SuperHashIteratorOf<HashKeyElement> iter(*this);
- CriticalBlock b(crit);
- ForEach (iter)
- {
- HashKeyElement &elem = iter.query();
- str.append(elem.get()).append(", count = ").append(elem.queryReferences()).newline();
- }
- return str;
- }
- };
- static CNameCountTable *namedCountHT;
- MODULE_INIT(INIT_PRIORITY_SYSTEM)
- {
- namedCountHT = new CNameCountTable;
- return true;
- }
- MODULE_EXIT()
- {
- delete namedCountHT;
- }
- NamedCount::NamedCount()
- {
- ht = NULL;
- }
- NamedCount::~NamedCount()
- {
- if (ht) namedCountHT->releaseKey(ht);
- }
- void NamedCount::set(const char *name)
- {
- ht = namedCountHT->queryCreate(name);
- }
- StringBuffer &dumpNamedCounts(StringBuffer &str)
- {
- return namedCountHT->dump(str);
- }
- //==============================================================
- // class OffsetToString
- OffsetToString::OffsetToString(offset_t offset)
- {
- #if defined(_MSC_VER) && !defined (_POSIX_) && (__STDC__ || _INTEGRAL_MAX_BITS < 64)
- // fpos_t is defined as struct (see <stdio.h> in VC)
- __int64 v = offset.lopart + (offset.hipart<<32);
- m_buffer.append(v);
- #else
- m_buffer.append(offset);
- #endif
- }
- /* Gentoo libc version omits these symbols which are directly */
- /* referenced by some 3rd party libraries (sybase, Hasp). Until these */
- /* libs get updated, provide linkable symbols within jlib for these... */
- #if defined(__linux__) && (__GNUC__ >= 3)
- const jlib_decl unsigned short int *__ctype_b = *__ctype_b_loc ();
- const jlib_decl __int32_t *__ctype_tolower = *__ctype_tolower_loc();
- const jlib_decl __int32_t *__ctype_toupper = *__ctype_toupper_loc();
- // There seems to be some debate about whether these are needed
- //#elif (__GNUC__ >= 3)
- //const unsigned short int *__ctype_b = *__ctype_b_loc ();
- //const unsigned int *__ctype_tolower = *__ctype_tolower_loc();
- //const unsigned int *__ctype_toupper = *__ctype_toupper_loc();
- #endif
- //==============================================================
- // URL Password, username handling
- /*
- From ftp://ftp.isi.edu/in-notes/rfc1738.txt:
- http://<user>:<password>@<host>:<port>/<url-path>
- Some or all of the parts "<user>:<password>@", ":<password>",
- ":<port>", and "/<url-path>" may be excluded.
- The user name (and password), if present, are followed by a
- commercial at-sign "@". Within the user and password field, any ":",
- "@", or "/" must be encoded.
- */
- jlib_decl StringBuffer& encodeUrlUseridPassword(StringBuffer& out, const char* in)
- {
- for (const char* p = in; *p; p++)
- {
- switch(*p)
- {
- // mentioned in rfc1738
- case ':': out.append("%3A"); break;
- case '@': out.append("%40"); break;
- case '/': out.append("%2F"); break;
-
- // these are not in the spec, but IE/Firefox has trouble if left un-encoded
- case '%': out.append("%25"); break;
- // these are not necessary: both IE and firefox handle them correctly
- /*
- case '&': out.append("%26"); break;
- case ' ': out.append("%20"); break;
- */
- default: out.append(*p); break;
- }
- }
- return out;
- }
- inline bool isHexChar(char c)
- {
- return (c>='0' && c<='9')
- || (c>='A' && c<='F')
- || (c>='a' && c<='f');
- }
- int hexValue(char c)
- {
- return (c>='0' && c<='9') ? c-'0' :
- ((c>='A' && (c<='F') ? c-'A'+10 : c-'a'+10));
- }
- jlib_decl StringBuffer& decodeUrlUseridPassword(StringBuffer& out, const char* in)
- {
- for (const char* p = in; *p; p++)
- {
- if (*p=='%' && isHexChar(*(p+1)) && isHexChar(*(p+2)) )
- {
- char c1 = *(p+1), c2 = *(p+2);
- int x = (hexValue(c1)<<4) + hexValue(c2);
- out.appendf("%c",x);
- p += 2;
- }
- else
- out.appendf("%c",*p);
- }
- return out;
- }
- StringBuffer jlib_decl passwordInput(const char* prompt, StringBuffer& passwd)
- {
- #ifdef _WIN32
- printf("%s", prompt);
- size32_t entrylen = passwd.length();
- for (;;) {
- char c = getch();
- if (c == '\r')
- break;
- if (c == '\b') {
- if (passwd.length()>entrylen) {
- printf("\b \b");
- passwd.setLength(passwd.length()-1);
- }
- }
- else {
- passwd.append(c);
- printf("*");
- }
- }
- printf("\n");
- #else
- // unfortuantely linux tty can't easily support using '*' hiding
- sigset_t saved_signals;
- sigset_t set_signals;
- struct termios saved_term;
- struct termios set_term;
- FILE *term = fopen(_PATH_TTY, "w+");
- if (!term)
- term = stdin;
- int termfd = fileno(term);
- fprintf(stdout, "%s", prompt);
- fflush(stdout);
- sigemptyset(&set_signals);
- sigaddset(&set_signals, SIGINT);
- sigaddset(&set_signals, SIGTSTP);
- sigprocmask(SIG_BLOCK, &set_signals, &saved_signals);
- tcgetattr(termfd, &saved_term);
- set_term = saved_term;
- set_term.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL);
- tcsetattr(termfd, TCSAFLUSH, &set_term);
- char c = EOF;
- int rd = ::read(termfd,&c,1);
- while ((rd==1)&&(c!='\r')&&(c!='\n')) {
- passwd.append(c);
- rd = ::read(termfd,&c,1);
- }
- int err = (rd<0)?errno:0;
- tcsetattr(termfd, TCSAFLUSH, &saved_term);
- sigprocmask(SIG_SETMASK, &saved_signals, 0);
- if (term!=stdin)
- fclose(term);
- if (err)
- throw makeOsException(err);
- #endif
- return passwd;
- }
- StringBuffer & fillConfigurationDirectoryEntry(const char *dir,const char *name, const char *component, const char *instance, StringBuffer &dirout)
- {
- while (*dir) {
- if (*dir=='[') {
- if (memicmp(dir+1,"NAME]",5)==0) {
- dirout.append(name);
- dir += 5;
- }
- else if (memicmp(dir+1,"COMPONENT]",10)==0) {
- dirout.append(component);
- dir += 10;
- }
- else if (memicmp(dir+1,"INST]",5)==0){
- dirout.append(instance);
- dir += 5;
- }
- else
- dirout.append('[');
- }
- else
- dirout.append(*dir);
- dir++;
- }
- return dirout;
- }
- IPropertyTree *getHPCCEnvironment()
- {
- StringBuffer envfile;
- if (queryEnvironmentConf().getProp("environment",envfile) && envfile.length())
- {
- if (!isAbsolutePath(envfile.str()))
- {
- envfile.insert(0, CONFIG_DIR PATHSEPSTR);
- }
- Owned<IFile> file = createIFile(envfile.str());
- if (file)
- {
- Owned<IFileIO> fileio = file->open(IFOread);
- if (fileio)
- return createPTree(*fileio, ipt_lowmem);
- }
- }
- return NULL;
- }
- static Owned<IProperties> envConfFile;
- static CriticalSection envConfCrit;
- jlib_decl const IProperties &queryEnvironmentConf()
- {
- CriticalBlock b(envConfCrit);
- if (!envConfFile)
- envConfFile.setown(createProperties(CONFIG_DIR PATHSEPSTR ENV_CONF_FILE, true));
- return *envConfFile;
- }
- static StringBuffer DAFSpassPhraseDec;//deprecated
- static CriticalSection DAFSpassPhraseCrit;
- //Deprecated, please use queryHPCCPKIKeyFiles() instead
- jlib_decl bool querySecuritySettings(DAFSConnectCfg *_connectMethod,
- unsigned short *_port,
- const char * * _certificate,
- const char * * _privateKey,
- const char * * _passPhrase)//decrypted passphrase
- {
- if (_connectMethod)
- *_connectMethod = SSLNone;//default
- if (_port)
- *_port = DAFILESRV_PORT;//default
- const IProperties & conf = queryEnvironmentConf();
- StringAttr sslMethod;
- sslMethod.set(conf.queryProp("dfsUseSSL"));
- if (!sslMethod.isEmpty())
- {
- DAFSConnectCfg tmpMethod;
- // checking for true | false for backward compatibility
- if ( strieq(sslMethod.str(), "SSLOnly") || strieq(sslMethod.str(), "true") )
- tmpMethod = SSLOnly;
- else if ( strieq(sslMethod.str(), "SSLFirst") )
- tmpMethod = SSLFirst;
- else if ( strieq(sslMethod.str(), "UnsecureFirst") )
- tmpMethod = UnsecureFirst;
- else // SSLNone or false or ...
- tmpMethod = SSLNone;
- if (_connectMethod)
- *_connectMethod = tmpMethod;
- if (_port)
- {
- if (tmpMethod == SSLOnly || tmpMethod == SSLFirst)
- *_port = SECURE_DAFILESRV_PORT;
- }
- //Begin of deprecated code
- bool dfsKeywords = false;
- if (_certificate)
- {
- *_certificate = conf.queryProp("dfsSSLCertFile");
- if (*_certificate)
- dfsKeywords = true;
- }
- if (_privateKey)
- {
- *_privateKey = conf.queryProp("dfsSSLPrivateKeyFile");
- if (*_privateKey)
- dfsKeywords = true;
- }
- StringBuffer DAFSpassPhraseEnc;
- if (_passPhrase)
- {
- CriticalBlock b(DAFSpassPhraseCrit);
- if (DAFSpassPhraseDec.isEmpty())//previously retrieved/decrypted it?
- {
- const char *passPhrasePtr = conf.queryProp("dfsSSLPassPhrase");
- if (!isEmptyString(passPhrasePtr))
- {
- DAFSpassPhraseEnc.append(passPhrasePtr);//got encrypted pwd
- dfsKeywords = true;
- }
- }
- }
- if (!dfsKeywords && (_certificate || _privateKey || _passPhrase))
- {
- //end of deprecated code
- const char *passPhrasePtr = nullptr;
- queryHPCCPKIKeyFiles(_certificate, nullptr, _privateKey, _passPhrase ? &passPhrasePtr : nullptr);//use new keywords
- if (!isEmptyString(passPhrasePtr))
- {
- CriticalBlock b(DAFSpassPhraseCrit);
- if (DAFSpassPhraseEnc.isEmpty())
- DAFSpassPhraseEnc.append(passPhrasePtr);//got encrypted pwd
- }
- }
- if (_passPhrase)
- {
- CriticalBlock b(DAFSpassPhraseCrit);
- if (DAFSpassPhraseDec.isEmpty() && !DAFSpassPhraseEnc.isEmpty())
- decrypt(DAFSpassPhraseDec, DAFSpassPhraseEnc.str());
- *_passPhrase = DAFSpassPhraseDec.str();//return decrypted password. Note the preferred queryHPCCPKIKeyFiles() method returns it encrypted
- }
- }
- return true;
- }
- jlib_decl bool queryDafsSecSettings(DAFSConnectCfg *_connectMethod,
- unsigned short *_port,
- unsigned short *_sslport,
- const char * * _certificate,
- const char * * _privateKey,
- const char * * _passPhrase)
- {
- bool ret = querySecuritySettings(_connectMethod, nullptr, _certificate, _privateKey, _passPhrase);
- if (ret)
- {
- if (_port)
- *_port = DAFILESRV_PORT;
- if (_sslport)
- *_sslport = SECURE_DAFILESRV_PORT;
- }
- return ret;
- }
- //query PKI values from environment.conf
- jlib_decl bool queryHPCCPKIKeyFiles(const char * * _certificate,//HPCCCertificateFile
- const char * * _publicKey, //HPCCPublicKeyFile
- const char * * _privateKey, //HPCCPrivateKeyFile
- const char * * _passPhrase) //HPCCPassPhrase
- {
- const IProperties & conf = queryEnvironmentConf();
- if (_certificate)
- *_certificate = conf.queryProp("HPCCCertificateFile");
- if (_publicKey)
- *_publicKey = conf.queryProp("HPCCPublicKeyFile");
- if (_privateKey)
- *_privateKey = conf.queryProp("HPCCPrivateKeyFile");
- if (_passPhrase)
- *_passPhrase = conf.queryProp("HPCCPassPhrase"); //return encrypted
- return true;
- }
- static IPropertyTree *getOSSdirTree()
- {
- Owned<IPropertyTree> envtree = getHPCCEnvironment();
- if (envtree) {
- IPropertyTree *ret = envtree->queryPropTree("Software/Directories");
- if (ret)
- return createPTreeFromIPT(ret);
- }
- return NULL;
- }
- bool getConfigurationDirectory(const IPropertyTree *useTree, const char *category, const char *component, const char *instance, StringBuffer &dirout)
- {
- Linked<const IPropertyTree> dirtree = useTree;
- if (!dirtree)
- dirtree.setown(getOSSdirTree());
- if (dirtree && category && *category)
- {
- const char *name = dirtree->queryProp("@name");
- if (name&&*name) {
- StringBuffer q("Category[@name=\"");
- q.append(category).append("\"]");
- IPropertyTree *cat = dirtree->queryPropTree(q.str()); // assume only 1
- if (cat) {
- IPropertyTree *over = NULL;
- if (instance&&*instance) {
- q.clear().append("Override[@instance=\"").append(instance).append("\"]");
- Owned<IPropertyTreeIterator> it1 = cat->getElements(q.str());
- ForEach(*it1) {
- IPropertyTree &o1 = it1->query();
- if ((!component||!*component)) {
- if (!over)
- over = &o1;
- }
- else {
- const char *comp = o1.queryProp("@component");
- if (!comp||!*comp) {
- if (!over)
- over = &o1;
- }
- else if (strcmp(comp,component)==0) {
- over = &o1;
- break;
- }
- }
- }
- }
- if (!over&&component&&*component) {
- q.clear().append("Override[@component=\"").append(component).append("\"]");
- Owned<IPropertyTreeIterator> it2 = cat->getElements(q.str());
- ForEach(*it2) {
- IPropertyTree &o2 = it2->query();
- if ((!instance||!*instance)) {
- over = &o2;
- break;
- }
- else {
- const char *inst = o2.queryProp("@instance");
- if (!inst||!*inst) {
- over = &o2;
- break;
- }
- }
- }
- }
- const char *dir = over?over->queryProp("@dir"):cat->queryProp("@dir");
- if (dir&&*dir) {
- fillConfigurationDirectoryEntry(dir,name,component,instance,dirout);
- return true;
- }
- }
- }
- }
- return false;
- }
- const char * matchConfigurationDirectoryEntry(const char *path,const char *mask,StringBuffer &name, StringBuffer &component, StringBuffer &instance)
- {
- // first check matches from (and set any values)
- // only handles simple masks currently
- StringBuffer var;
- PointerArray val;
- const char *m = mask;
- const char *p = path;
- for (;;) {
- char c = *m;
- if (!c)
- break;
- m++;
- StringBuffer *out=NULL;
- if (c=='[') {
- if (memicmp(m,"NAME]",5)==0) {
- out = &name;
- m += 5;
- }
- else if (memicmp(m,"COMPONENT]",10)==0) {
- out = &component;
- m += 10;
- }
- else if (memicmp(m,"INST]",5)==0) {
- out = &instance;
- m += 5;
- }
- }
- if (out) {
- StringBuffer mtail;
- while (*m&&!isPathSepChar(*m)&&(*m!='['))
- mtail.append(*(m++));
- StringBuffer ptail;
- while (*p&&!isPathSepChar(*p))
- ptail.append(*(p++));
- if (ptail.length()<mtail.length())
- return NULL;
- size32_t l = ptail.length()-mtail.length();
- if (l&&(memcmp(ptail.str()+l,mtail.str(),mtail.length())!=0))
- return NULL;
- out->clear().append(l,ptail.str());
- }
- else if (c!=*(p++))
- return NULL;
- }
- if (!*p)
- return p;
- if (isPathSepChar(*p))
- return p+1;
- return NULL;
- }
- bool replaceConfigurationDirectoryEntry(const char *path,const char *frommask,const char *tomask,StringBuffer &out)
- {
- StringBuffer name;
- StringBuffer comp;
- StringBuffer inst;
- const char *tail = matchConfigurationDirectoryEntry(path,frommask,name,comp,inst);
- if (!tail)
- return false;
- fillConfigurationDirectoryEntry(tomask,name,comp,inst,out);
- if (*tail)
- addPathSepChar(out).append(tail);
- return true;
- }
- static CriticalSection sect;
- static StringAttr processPath;
- const char * queryCurrentProcessPath()
- {
- CriticalBlock block(sect);
- if (processPath.isEmpty())
- {
- #if _WIN32
- HMODULE hModule = GetModuleHandle(NULL);
- char path[MAX_PATH];
- if (GetModuleFileName(hModule, path, MAX_PATH) != 0)
- processPath.set(path);
- #elif defined (__APPLE__)
- char path[PATH_MAX];
- uint32_t size = sizeof(path);
- ssize_t len = _NSGetExecutablePath(path, &size);
- switch(len)
- {
- case -1:
- {
- char * biggerPath = new char[size];
- if (_NSGetExecutablePath(biggerPath, &size) == 0)
- processPath.set(biggerPath);
- delete [] biggerPath;
- }
- break;
- case 0:
- processPath.set(path);
- break;
- default:
- break;
- }
- #else
- char path[PATH_MAX + 1];
- ssize_t len = readlink("/proc/self/exe", path, PATH_MAX);
- if (len != -1)
- {
- path[len] = 0;
- processPath.set(path);
- }
- #endif
- }
- if (processPath.isEmpty())
- return NULL;
- return processPath.str();
- }
- bool getPackageFolder(StringBuffer & path)
- {
- StringBuffer folder;
- splitDirTail(queryCurrentProcessPath(), folder);
- removeTrailingPathSepChar(folder);
- if (folder.length())
- {
- StringBuffer foldersFolder;
- splitDirTail(folder.str(), foldersFolder);
- if (foldersFolder.length())
- {
- path = foldersFolder;
- return true;
- }
- }
- return false;
- }
- inline bool isOctChar(char c)
- {
- return (c>='0' && c<'8');
- }
- inline int octValue(char c)
- {
- return c-'0';
- }
- int parseCommandLine(const char * cmdline, MemoryBuffer &mb, const char** &argvout)
- {
- mb.append((char)0);
- size32_t arg[256];
- int argc = 0;
- arg[0] = 0;
- char quotechar = 0;
- for (;;) {
- char c = *(cmdline++);
- switch(c) {
- case ' ':
- case '\t':
- if (quotechar)
- break;
- // fall through
- case 0: {
- if (arg[argc]) {
- while (mb.length()>arg[argc]) {
- size32_t l = mb.length()-1;
- const byte * b = ((const byte *)mb.bufferBase())+l;
- if ((*b!=' ')&&(*b!='\t'))
- break;
- mb.setLength(l);
- }
- if (mb.length()>arg[argc]) {
- mb.append((char)0);
- argc++;
- }
- if (c) {
- if (argc==256)
- throw makeStringException(-1, "parseCommandLine: too many arguments");
- arg[argc] = 0;
- }
- }
- if (c)
- continue;
- argvout = (const char **)mb.reserve(argc*sizeof(const char *));
- for (int i=0;i<argc;i++)
- argvout[i] = arg[i]+(const char *)mb.bufferBase();
- return argc;
- }
- break;
- case '\'':
- case '"':
- if (c==quotechar) {
- quotechar = 0;
- continue;
- }
- if (quotechar)
- break;
- quotechar = c;
- continue;
- case '\\': {
- if (*cmdline&&!quotechar) {
- c = *(cmdline++);
- switch (c) {
- 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 'x': case 'X': {
- c = 0;
- if (isHexChar(*cmdline)) {
- c = hexValue(*(cmdline++));
- if (isHexChar(*cmdline))
- c = ((byte)c*16)+hexValue(*(cmdline++));
- }
- }
- break;
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7': {
- c = octValue(c);
- if (isOctChar(*cmdline)) {
- c = ((byte)c*8)+octValue(*(cmdline++));
- if (isOctChar(*cmdline))
- c = ((byte)c*8)+octValue(*(cmdline++));
- }
- }
- break;
- }
- }
- }
- break;
- }
- if (!arg[argc])
- arg[argc] = mb.length();
- mb.append(c);
- }
- return 0;
- }
- jlib_decl StringBuffer &getTempFilePath(StringBuffer & target, const char * component, IPropertyTree * pTree)
- {
- StringBuffer dir;
- if (pTree)
- getConfigurationDirectory(pTree->queryPropTree("Directories"),"temp",component,pTree->queryProp("@name"),dir);
- if (!dir.length())
- {
- #ifdef _WIN32
- char path[_MAX_PATH+1];
- if(GetTempPath(sizeof(path),path))
- dir.append(path).append("HPCCSystems\\hpcc-data");
- else
- dir.append("c:\\HPCCSystems\\hpcc-data\\temp");
- #else
- dir.append(getenv("TMPDIR"));
- if (!dir.length())
- dir.append("/var/lib");
- dir.append("/HPCCSystems/hpcc-data/temp");
- #endif
- }
- dir.append(PATHSEPCHAR).append(component);
- recursiveCreateDirectory(dir.str());
- return target.set(dir);
- }
- const char *getEnumText(int value, const EnumMapping *map)
- {
- while (map->str)
- {
- if (value==map->val)
- return map->str;
- map++;
- }
- throwUnexpectedX("Unexpected value in getEnumText");
- }
- int getEnum(const char *v, const EnumMapping *map)
- {
- if (v && *v)
- {
- while (map->str)
- {
- if (stricmp(v, map->str)==0)
- return map->val;
- map++;
- }
- throwUnexpectedX("Unexpected value in getEnum");
- }
- return 0;
- }
- const char *getEnumText(int value, const EnumMapping *map, const char * defval)
- {
- while (map->str)
- {
- if (value==map->val)
- return map->str;
- map++;
- }
- return defval;
- }
- int getEnum(const char *v, const EnumMapping *map, int defval)
- {
- if (v && *v)
- {
- while (map->str)
- {
- if (stricmp(v, map->str)==0)
- return map->val;
- map++;
- }
- }
- return defval;
- }
- //#define TESTURL
- #ifdef TESTURL
- static int doTests()
- {
- const char* ps[] = {
- "ABCD", "@BCD", "%BCD","&BCD","A CD","A/CD", "A@@%%A","A&%/@"
- };
-
- const int N = sizeof(ps)/sizeof(char*);
- for (int i=0; i<N; i++)
- {
- StringBuffer raw, encoded;
- encodeUrlUseridPassword(encoded,ps[i]);
- printf("Encoded: %s\n", encoded.str());
- decodeUrlUseridPassword(raw,encoded);
- if (strcmp(raw.str(),ps[i])!=0)
- assert(!"decoding error");
- }
- return 0;
- }
- int gDummy = doTests();
- #endif
|