|
|
| version 1.144.2.28.2.9, 2003/03/20 13:09:54 | version 1.144.2.28.2.22, 2003/03/24 09:39:55 |
|---|---|
| Line 27 class SQL_Connection; | Line 27 class SQL_Connection; |
| class Dictionary; | class Dictionary; |
| class Request_charsets; | class Request_charsets; |
| class String; | class String; |
| typedef Array<const String* > ArrayString; | typedef Array<const String*> ArrayString; |
| // helpers | // helpers |
| /* | |
| /// appends clean piece to String @see String::append | /// appends clean piece to String @see String::append |
| #define APPEND_CLEAN(src, size) append(src, size, String::UL_CLEAN) | #define APPEND_CLEAN(src, length) append(src, length, String::L_CLEAN) |
| /// appends piece to String as-is @see String::append | /// appends piece to String as-is @see String::append |
| #define APPEND_AS_IS(src, size) append(src, size, String::UL_AS_IS) | #define APPEND_AS_IS(src, length) append(src, length, String::L_AS_IS) |
| /// appends tainted piece to String @see String::append | /// appends tainted piece to String @see String::append |
| #define APPEND_TAINTED(src, size) append(src, size, String::UL_TAINTED) | #define APPEND_TAINTED(src, length) append(src, length, String::L_TAINTED) |
| /// handy: appends const char* piece to String @see String::append | /// handy: appends const char* piece to String @see String::append |
| #define APPEND_CONST(src) APPEND_AS_IS(src, 0) | #define APPEND_CONST(src) APPEND_AS_IS(src, 0) |
| */ | |
| /// this is result of pos functions which mean that substr were not found | /// this is result of pos functions which mean that substr were not found |
| #define STRING_NOT_FOUND ((size_t)-1) | #define STRING_NOT_FOUND ((size_t)-1) |
| class StringBody { | |
| CORD body; | |
| public: | |
| StringBody(): body(CORD_EMPTY) {} | |
| StringBody(CORD abody): body(abody) {} | |
| explicit StringBody(const char* str, size_t length): body(CORD_EMPTY) { | |
| append(str, length); | |
| } | |
| void clear() { body=CORD_EMPTY; } | |
| uint hash_code() const; | |
| const char* cstr() const { return CORD_to_const_char_star(body); } | |
| char* cstrm() const { return CORD_to_char_star(body); } | |
| size_t length() const { return CORD_len(body); } | |
| bool is_empty() const { return body==CORD_EMPTY; } | |
| void append(const char *str, size_t length) { | |
| body=CORD_cat_char_star(body, str, length); | |
| } | |
| void append(char c) { body=CORD_cat_char(body, c); } | |
| void append(StringBody src) { body=CORD_cat(body, src.body); } | |
| // could not figure out why this operator is needed [should do this chain: string->simple->==] | |
| bool operator < (const StringBody& src) const { return CORD_cmp(body, src.body)<0; } | |
| bool operator > (const StringBody& src) const { return CORD_cmp(body, src.body)>0; } | |
| bool operator <= (const StringBody& src) const { return CORD_cmp(body, src.body)<=0; } | |
| bool operator >= (const StringBody& src) const { return CORD_cmp(body, src.body)>=0; } | |
| bool operator != (const StringBody& src) const { return CORD_cmp(body, src.body)!=0; } | |
| bool operator == (const StringBody& src) const { return CORD_cmp(body, src.body)==0; } | |
| int ncmp(size_t x_begin, const StringBody y, size_t y_begin, size_t size) const { | |
| return CORD_ncmp(body, x_begin, y.body, y_begin, size); | |
| } | |
| char fetch(size_t index) const { return CORD_fetch(body, index); } | |
| StringBody mid(size_t index, size_t length) const { return CORD_substr(body, index, length); } | |
| size_t pos(size_t offset, const char* substr) const { return CORD_str(body, offset, substr); } | |
| size_t pos(size_t offset, const StringBody substr) const { return CORD_str(body, offset, substr.body); } | |
| template<typename I> void for_each(int (*callback)(const char* s, I), I info) const { | |
| CORD_iter5(body, 0, 0, (CORD_batched_iter_fn)callback, info); | |
| } | |
| void set_pos(CORD_pos& pos, size_t index) const { CORD_set_pos(pos, body, index); } | |
| }; | |
| /** | /** |
| String which knows the language of all it's fragments. | String which knows the language of all it's fragments. |
| Line 53 typedef Array<const String* > ArrayStrin | Line 106 typedef Array<const String* > ArrayStrin |
| */ | */ |
| class String: public PA_Object { | class String: public PA_Object { |
| // friend class StringBody; | |
| public: | public: |
| /** piece is tainted or not. the language to use when detaint | /** piece is tainted or not. the language to use when detaint |
| remember to change String_Untaint_lang_name @ untaint.C along | remember to change String_Untaint_lang_name @ untaint.C along |
| */ | */ |
| enum Untaint_lang { | enum Language { |
| UL_UNSPECIFIED=0, ///< zero value handy for hash lookup @see untaint_lang_name2enum | L_UNSPECIFIED=0, ///< zero value handy for hash lookup @see untaint_lang_name2enum |
| // these two must go before others, there are checks for >UL_AS_IS | // these two must go before others, there are checks for >L_AS_IS |
| UL_CLEAN, ///< clean | L_CLEAN, ///< clean |
| UL_AS_IS, ///< leave all characters intact | L_AS_IS, ///< leave all characters intact |
| UL_PASS_APPENDED, | L_PASS_APPENDED, |
| /**< | /**< |
| leave language built into string being appended. | leave language built into string being appended. |
| just a flag, that value not stored | just a flag, that value not stored |
| */ | */ |
| UL_TAINTED, ///< tainted, untaint language as assigned later | L_TAINTED, ///< tainted, untaint language as assigned later |
| // untaint languages. assigned by ^untaint[lang]{...} | // untaint languages. assigned by ^untaint[lang]{...} |
| UL_FILE_SPEC, ///< file specification | L_FILE_SPEC, ///< file specification |
| UL_HTTP_HEADER, ///< text in HTTP response header | L_HTTP_HEADER, ///< text in HTTP response header |
| UL_MAIL_HEADER, ///< text in mail header | L_MAIL_HEADER, ///< text in mail header |
| UL_URI, ///< text in uri | L_URI, ///< text in uri |
| UL_TABLE, ///< ^table:set body | L_TABLE, ///< ^table:set body |
| UL_SQL, ///< ^table:sql body | L_SQL, ///< ^table:sql body |
| UL_JS, ///< JavaScript code | L_JS, ///< JavaScript code |
| UL_XML, ///< ^dom:set xml | L_XML, ///< ^dom:set xml |
| UL_HTML, ///< HTML code (for editing) | L_HTML, ///< HTML code (for editing) |
| UL_OPTIMIZE_BIT = 0x8000 ///< flag, requiring cstr whitespace optimization | L_OPTIMIZE_BIT = 0x8000 ///< flag, requiring cstr whitespace optimization |
| }; | }; |
| struct Fragment { | struct Fragment { |
| Untaint_lang lang; ///< untaint flag, later untaint language | Language lang; ///< untaint flag, later untaint language |
| size_t size; ///< size | size_t length; ///< length |
| Fragment(Untaint_lang alang, size_t asize): lang(alang), size(asize) {} | Fragment(Language alang, size_t asize): lang(alang), length(asize) {} |
| }; | }; |
| class ArrayFragment: public Array<Fragment> { | class ArrayFragment: public Array<Fragment> { |
| void simple_append(element_type src) { | void append(element_type src) { |
| *static_cast<Array<Fragment> *>(this)+=src; | *static_cast<Array<Fragment> *>(this)+=src; |
| } | } |
| /// hiding from accidental USE, use append_positions | |
| void append(const ArrayFragment& src, int offset, int limit) { | |
| static_cast<Array<Fragment> *>(this)->append(src, offset, limit); | |
| } | |
| public: | public: |
| ArrayFragment& operator += (element_type src) { | ArrayFragment& operator += (element_type src) { |
| if(count()) { // not empty? | if(count()) { // not empty? |
| // try to join with last | // try to join with last |
| Fragment& last=get(count()-1); | Fragment& last=get(count()-1); |
| if(last.lang==src.lang) { | if(last.lang==src.lang) { |
| last.size+=src.size; | last.length+=src.length; |
| return *this; | return *this; |
| } | } |
| } | } |
| simple_append(src); | append(src); |
| return *this; | return *this; |
| } | } |
| ArrayFragment& append(const ArrayFragment& src, size_t substr_start, size_t substr_end); | void append(const ArrayFragment& src) { append(src, 0, 0); } |
| void append_positions(const ArrayFragment& src, size_t substr_begin, size_t substr_end); | |
| }; | }; |
| struct C { | struct C { |
| char *str; | char *str; |
| size_t size; | size_t length; |
| operator char *() { return str; } | operator char *() { return str; } |
| C(char *astr, size_t asize): str(astr), size(asize) {} | C(char *astr, size_t asize): str(astr), length(asize) {} |
| }; | }; |
| private: | private: |
| CORD body; ///< all characters of string | StringBody body; ///< all characters of string |
| ArrayFragment fragments; ///< fragment language+size info | ArrayFragment fragments; ///< fragment language+length info |
| public: | public: |
| explicit String(const char* src=0, size_t src_size=0, bool tainted=false); | /// @todo check all places for length to be only HELPER length, and never be !=strlen(cstr) |
| explicit String(const char* cstr=0, size_t helper_length=0, bool tainted=false); | |
| String(const String& src); | String(const String& src); |
| operator bool() const { return body!=CORD_EMPTY; } | String(StringBody abody, Language alang): body(abody) { |
| size_t size() const { return CORD_len(body); } | fragments+=Fragment(alang, abody.length()); |
| } | |
| /// convert to C string. if 'lang' known, forcing 'lang' to it | /// for convinient hash lookup |
| CORD cstr_to_cord(Untaint_lang lang=UL_AS_IS, | operator const StringBody() const { return body; } |
| SQL_Connection *connection=0, | |
| bool is_empty() const { return body.is_empty(); } | |
| size_t length() const { return body.length(); } | |
| /// convert to CORD. if 'lang' known, forcing 'lang' to it | |
| StringBody cstr_to_string_body(Language lang=L_AS_IS, | |
| SQL_Connection* connection=0, | |
| const Request_charsets *charsets=0) const; | const Request_charsets *charsets=0) const; |
| /// convert to C string. if 'lang' known, forcing 'lang' to it | /// convert to constant C string. if 'lang' known, forcing 'lang' to it |
| const char* cstr(Untaint_lang lang=UL_AS_IS, | const char* cstr(Language lang=L_AS_IS, |
| SQL_Connection *connection=0, | SQL_Connection* connection=0, |
| const Request_charsets *charsets=0) const { | const Request_charsets *charsets=0) const { |
| return CORD_to_const_char_star(cstr_to_cord(lang, connection, charsets)); | return cstr_to_string_body(lang, connection, charsets).cstr(); |
| } | } |
| /// convert to C string. if 'lang' known, forcing 'lang' to it | /// convert to Modifiable C string. if 'lang' known, forcing 'lang' to it |
| char *cstrm(Untaint_lang lang=UL_AS_IS, | char *cstrm(Language lang=L_AS_IS, |
| SQL_Connection *connection=0, | SQL_Connection* connection=0, |
| const Request_charsets *charsets=0) const { | const Request_charsets *charsets=0) const { |
| return CORD_to_char_star(cstr_to_cord(lang, connection, charsets)); | return cstr_to_string_body(lang, connection, charsets).cstrm(); |
| } | } |
| /// puts pieces to buf | /// puts pieces to buf |
| C serialize(size_t prolog_size) const; | C serialize(size_t prolog_size) const; |
| /// appends pieces from buf to self | /// appends pieces from buf to self |
| bool deserialize(size_t prolog_size, void *buf, size_t buf_size, const char* file); | bool deserialize(size_t prolog_size, void *buf, size_t buf_size, const char* file); |
| /** append fragment | /** append fragment, |
| @see APPEND_AS_IS, APPEND_CLEAN, APPEND_TAINTED, APPEND_CONST | @c length can be zero, it will be autocalced |
| when length<strlen(str) makes heap copy of @c str piece | |
| */ | */ |
| String& append(const char* src, size_t size, Untaint_lang lang); | String& append(const char* str, size_t length, Language lang); |
| /** | |
| @param partial | bool operator == (const char* y) const { return body==StringBody(y); } |
| returns partial match status. | bool operator != (const char* y) const { return body!=StringBody(y); } |
| - -1: strings too different | |
| - 0: full match | |
| - 1: means @c this starts @c src | |
| - 2: means @src starts @this | |
| */ | |
| //int cmp(CORD substr, size_t this_offset=0) const; | |
| /// String version of @see cmp(CORD, size_t) | |
| //int cmp(const String& src, size_t this_offset=0) const; | |
| bool operator < (const String& src) const { return CORD_cmp(body, src.body)<0; } | |
| bool operator > (const String& src) const { return CORD_cmp(body, src.body)>0; } | |
| bool operator <= (const String& src) const { return CORD_cmp(body, src.body)<=0; } | |
| bool operator >= (const String& src) const { return CORD_cmp(body, src.body)>=0; } | |
| bool operator == (const String& src) const { return CORD_cmp(body, src.body)==0; } | |
| bool operator != (const String& src) const { return CORD_cmp(body, src.body)!=0; } | |
| /// this starts with y | /// this starts with y |
| bool starts_with(CORD y) const { | bool starts_with(const char* y) const { |
| return CORD_ncmp(body, 0/*x_start*/, y, 0/*y_start*/, CORD_len(y))==0; | return body.ncmp(0/*x_begin*/, StringBody(y), 0/*y_begin*/, strlen(y))==0; |
| } | } |
| /// y starts with this | /// y starts with this |
| bool this_starts(CORD y) const { | bool this_starts(const char* y) const { |
| return CORD_ncmp(body, 0/*x_start*/, y, 0/*y_start*/, CORD_len(y))==0; | return body.ncmp(0/*x_begin*/, StringBody(y), 0/*y_begin*/, strlen(y))==0; |
| } | } |
| bool operator == (CORD y) const { return CORD_cmp(body, y)==0; } | |
| bool operator != (CORD y) const { return CORD_cmp(body, y)!=0; } | |
| String& append_to(String& dest, Untaint_lang lang, bool forced) const; | String& append_to(String& dest, Language lang, bool forced) const; |
| String& append(const String& src, Untaint_lang lang, bool forced=false) { | String& append(const String& src, Language lang, bool forced=false) { |
| return src.append_to(*this, lang, forced); | return src.append_to(*this, lang, forced); |
| } | } |
| String& operator << (const String& src) { return append(src, UL_PASS_APPENDED); } | String& operator << (const String& src) { return append(src, L_PASS_APPENDED); } |
| //String& operator << (const String* src) { return append(*src, UL_PASS_APPENDED); } | String& operator << (const char* src) { return append(src, 0, L_AS_IS); } |
| String& operator << (const char* src) { return APPEND_CONST(src); } | String& operator << (const StringBody& src) { |
| body.append(src); | |
| /// simple hash code of string | fragments+=Fragment(L_AS_IS, src.length()); |
| uint hash_code() const; | return *this; |
| } | |
| /// extracts first char of a string, if any | /// extracts first char of a string, if any |
| char first_char() const { | char first_char() const { |
| return operator bool()?CORD_fetch(body, 0):0; | return is_empty()?0:body.fetch(0); |
| } | } |
| bool operator < (const String& src) const { return body<src.body; } | |
| bool operator > (const String& src) const { return body>src.body; } | |
| bool operator <= (const String& src) const { return body<=src.body; } | |
| bool operator >= (const String& src) const { return body>=src.body; } | |
| bool operator != (const String& src) const { return body!=src.body; } | |
| bool operator == (const String& src) const { return body==src.body; } | |
| /// extracts [start, finish) piece of string | /// extracts [start, finish) piece of string |
| const String& mid(size_t substr_start, size_t substr_end) const; | String& mid(size_t substr_begin, size_t substr_end) const; |
| /** | /** |
| ignore lang if it's UL_UNSPECIFIED | ignore lang if it's L_UNSPECIFIED |
| but when specified: look for substring that lies in ONE fragment in THAT lang | but when specified: look for substring that lies in ONE fragment in THAT lang |
| @return position of substr in string, -1 means "not found" [const char* version] | @return position of substr in string, -1 means "not found" [const char* version] |
| */ | */ |
| size_t pos(CORD substr, | size_t pos(const StringBody substr, |
| size_t this_offset=0, Untaint_lang lang=UL_UNSPECIFIED) const; | size_t this_offset=0, Language lang=L_UNSPECIFIED) const; |
| /// String version of @see pos(const char*, int, Untaint_lang) | /// String version of @see pos(const char*, int, Language) |
| size_t pos(const String& substr, | size_t pos(const String& substr, |
| size_t this_offset=0, Untaint_lang lang=UL_UNSPECIFIED) const; | size_t this_offset=0, Language lang=L_UNSPECIFIED) const; |
| void split(ArrayString& result, | void split(ArrayString& result, |
| size_t& pos_after_ref, | size_t& pos_after, |
| const char* delim, | const char* delim, |
| Untaint_lang lang=UL_UNSPECIFIED, int limit=-1); | Language lang=L_UNSPECIFIED, int limit=-1) const; |
| void split(ArrayString& result, | void split(ArrayString& result, |
| size_t& pos_after_ref, | size_t& pos_after, |
| const String& delim, | const String& delim, |
| Untaint_lang lang=UL_UNSPECIFIED, int limit=-1) const; | Language lang=L_UNSPECIFIED, int limit=-1) const; |
| typedef void (*Row_action)(Table* table, ArrayString* row, | typedef void (*Row_action)(Table* table, ArrayString* row, |
| int prestart, int prefinish, | int prestart, int prefinish, |
| Line 255 private: //disabled | Line 315 private: //disabled |
| }; | }; |
| /// simple hash code of string. used by Hash | /// simple hash code of string. used by Hash |
| inline uint hash_code(const String& self) { | inline uint hash_code(const StringBody& self) { |
| return self.hash_code(); | return self.hash_code(); |
| } | } |