#ifndef GB_SAFEBUF_H #define GB_SAFEBUF_H #include "utf8.h" #include <inttypes.h> #include <string.h> /** * Safe Char Buffer, or mutable Strings. * (for java programmers, very similar to the StringBuffer class, with all the speed that c++ allows). * Most of strings in Gigablast are handled by those. */ #include "iana_charset.h" #include "Sanity.h" template<int n=1024> class StackBuf; template<int n=1024> class SmallBuf; class SafeBuf { public: //*TRUCTORS SafeBuf(); SafeBuf(int32_t initSize, const char *label); void constructor(); private: //be careful with passing in a stackBuf! it could go out //of scope independently of the safebuf. SafeBuf(char* stackBuf, int32_t cap); template<int n> friend class StackBuf; template<int n> friend class SmallBuf; public: SafeBuf(char *heapBuf, int32_t bufMax, int32_t bytesInUse, bool ownData); ~SafeBuf(); void setLabel ( const char *label ); // CAUTION: BE CAREFUL WHEN USING THE FOLLOWING TWO FUNCTIONS!! // setBuf() allows you reset the contents of the SafeBuf to either // a stack buffer or a dynamic buffer. Only pass in true for // ownData if this is not a stack buffer and you are sure you // want SafeBuf to free the data for you. Keep in mind, all // previous content in SafeBuf will be cleared when you pass it // a new buffer. bool setBuf(char *newBuf, int32_t bufMax, int32_t bytesInUse, bool ownData); // set buffer from another safebuf, stealing it bool stealBuf ( SafeBuf *sb ); //ACCESSORS char *getBufPtr() { return m_buf + m_length; } const char *getBufPtr() const { return m_buf + m_length; } char *getBufStart() { return m_buf; } const char *getBufStart() const { return m_buf; } char *getBufEnd() { return m_buf + m_capacity; } const char *getBufEnd() const { return m_buf + m_capacity; } int32_t getCapacity() const { return m_capacity; } int32_t getAvail() const { return m_capacity - m_length; } int32_t length() const { return m_length; } // . returns bytes written to file, 0 is acceptable if m_length == 0 // . returns -1 on error and sets g_errno int32_t saveToFile(const char *dir, const char *filename) const; int32_t dumpToFile(const char *filename) const; int32_t save(const char *dir, const char *fname) const { return saveToFile(dir,fname); } int32_t save(const char *fullFilename) const; // saves to tmp file and if that succeeds then renames to orig filename int32_t safeSave(const char *filename) const; int32_t fillFromFile(const char *filename); int32_t fillFromFile(const char *dir, const char *filename, const char *label=NULL); int32_t load(const char *dir, const char *fname, const char *label = NULL) { return fillFromFile(dir,fname,label); } int32_t load(const char *fname) { return fillFromFile(fname); } bool safeTruncateEllipsis ( const char *src , int32_t maxLen ); bool safeTruncateEllipsis ( const char *src , int32_t srcLen, int32_t maxLen ); bool safeDecodeJSONToUtf8 ( const char *json, int32_t jsonLen); bool set ( const char *str ) { purge(); if ( ! str ) return true; // puts a \0 at the end, but does not include it in m_length: return safeStrcpy ( str ); } void removeLastChar ( char lastChar ) { if ( m_length <= 0 ) return; if ( m_buf[m_length-1] != lastChar ) return; m_length--; m_buf[m_length] = '\0'; } //MUTATORS bool safePrintf(const char *formatString, ...) __attribute__ ((format(printf, 2, 3))); bool safeMemcpy(const void *s, int32_t len){return safeMemcpy((const char*)s,len);} bool safeMemcpy(const char *s, int32_t len); bool safeMemcpy_nospaces(const char *s, int32_t len); bool safeMemcpy(const SafeBuf *c) { return safeMemcpy(c->m_buf,c->m_length); } bool safeStrcpy ( const char *s ) ; //bool safeStrcpyPrettyJSON ( char *decodedJson ) ; bool jsonEncode(const char *utf8); bool jsonEncode(const char *utf8, int32_t utf8Len); bool base64Encode ( const char *s , int32_t len ); bool base64Decode ( const char *src , int32_t srcLen ) ; bool base64Encode( const char *s ) ; //bool pushLong ( int32_t val ) { return safeMemcpy((char *)&val,4); } bool cat(const SafeBuf& c); void reset() { m_length = 0; } void purge(); // Clear all data and free all allocated memory // . if clearIt is true we init the new buffer space to zeroes // . used by Collectiondb.cpp bool reserve(int32_t i, const char *label=NULL , bool clearIt = false ); bool reserve2x(int32_t i, const char *label = NULL ); void incrementLength(int32_t i) { m_length += i; // watch out for negative i's if ( m_length < 0 ) m_length = 0; } void setLength(int32_t i) { m_length = i; } char *getNextLine ( char *p ) ; int32_t catFile(const char *filename) ; void detachBuf(); bool insert ( const char *s , int32_t insertPos ) ; bool insert2 ( const char *s , int32_t slen, int32_t insertPos ) ; bool replace ( const char *src, const char *dst ) ; // must be same lengths! bool removeChunk1 ( const char *p , int32_t len ) ; bool removeChunk2 ( int32_t pos , int32_t len ) ; bool safeReplace(const char *s, int32_t len, int32_t pos, int32_t replaceLen); bool safeReplace2 ( const char *s, int32_t slen, const char *t, int32_t tlen, int32_t startOff = 0 ); void replaceChar ( char src , char dst ); void zeroOut() { memset ( m_buf , 0 , m_capacity ); } // insert <br>'s to make 's' no more than 'cols' chars per line bool brify2 ( const char *s, int32_t cols, const char *sep = "<br>" , bool isHtml = true ) ; bool brify( const char *s, int32_t slen, int32_t cols, const char *sep = "<br>", bool isHtml = true ); bool hasDigits() const; bool utf8Encode2(const char *s, int32_t len, bool htmlEncode = false); bool utf32Encode(UChar32* codePoints, int32_t cpLen); bool htmlEncode( const char *s, int32_t len, bool encodePoundSign, int32_t truncateLen = -1 ); bool htmlEncode(const char *s) ; // html-encode any of the last "len" bytes that need it bool htmlEncode(int32_t len); bool htmlDecode(const char *s, int32_t len); bool dequote ( const char *t , int32_t tlen ); // . append a \0 but do not inc m_length // . for null terminating strings bool nullTerm ( ) { if(m_length >= m_capacity && !reserve(m_capacity + 1) ) return false; m_buf[m_length] = '\0'; return true; } //utf8 hack. make sure the buffer has 4 NULs beyond the end so we can use the fast approach to decoding utf8 characters bool nullTerm4() { if(m_length+3 >= m_capacity && !reserve(m_capacity + 4) ) return false; m_buf[m_length+0] = '\0'; m_buf[m_length+1] = '\0'; m_buf[m_length+2] = '\0'; m_buf[m_length+3] = '\0'; return true; } int32_t indexOf(char c) const; bool pushChar (char i) { if(m_length >= m_capacity) if(!reserve(2*m_capacity + 1)) return false; m_buf[m_length++] = i; // let's do this because we kinda expect it when making strings // and i've been burned by not having this before. // no, cause if we reserve just the right length, we end up // doing a realloc!! sux... //m_buf[m_length] = '\0'; return true; } bool pushLong (int32_t i); bool pushLongLong (int64_t i); bool pushFloat (float i); int32_t popLong(); float popFloat(); int32_t pad(const char ch, const int32_t len); //OPERATORS //copy numbers into the buffer, *in binary* //useful for making lists. bool operator += (uint64_t i); bool operator += (int64_t i); bool operator += (char i); bool operator += (uint32_t i); bool operator += (uint16_t i); bool operator += (uint8_t i); bool operator += (int32_t i) { return *this += (uint32_t)i; } bool operator += (int16_t i) { return *this += (uint16_t)i; } bool operator += (int8_t i) { return *this += (uint8_t)i; } const char& operator[](int32_t i) const; public: int32_t m_length; private: int32_t m_capacity; char *m_buf; bool m_usingStack; const char *m_label; }; template<int n> class StackBuf : public SafeBuf { char buf[n]; public: StackBuf() : SafeBuf(buf,sizeof(buf)) {} }; template<int n> class SmallBuf : public SafeBuf { char buf[n]; public: SmallBuf(const char *label) : SafeBuf(buf,sizeof(buf)) { setLabel(label); } }; #endif // GB_SAFEBUF_H