7 #include <sys/select.h>
9 #define SHOW_ME_VAPPEND_PRINTF
11 #include "libcitadel.h"
15 * Private Structure for the Stringbuffer
18 char *buf; /**< the pointer to the dynamic buffer */
19 long BufSize; /**< how many spcae do we optain */
20 long BufUsed; /**< Number of Chars used excluding the trailing \0 */
21 int ConstBuf; /**< are we just a wrapper arround a static buffer and musn't we be changed? */
26 * \Brief Cast operator to Plain String
27 * \param Str the string we want to get the c-string representation for
28 * \returns the Pointer to the Content. Don't mess with it!
30 inline const char *ChrPtr(const StrBuf *Str)
38 * \brief since we know strlen()'s result, provide it here.
39 * \param Str the string to return the length to
40 * \returns contentlength of the buffer
42 inline int StrLength(const StrBuf *Str)
44 return (Str != NULL) ? Str->BufUsed : 0;
48 * \brief local utility function to resize the buffer
49 * \param Buf the buffer whichs storage we should increase
50 * \param KeepOriginal should we copy the original buffer or just start over with a new one
51 * \param DestSize what should fit in after?
53 static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
56 size_t NewSize = Buf->BufSize * 2;
62 while (NewSize < DestSize)
65 NewBuf= (char*) malloc(NewSize);
66 if (KeepOriginal && (Buf->BufUsed > 0))
68 memcpy(NewBuf, Buf->buf, Buf->BufUsed);
82 * Allocate a new buffer with default buffer size
83 * \returns the new stringbuffer
85 StrBuf* NewStrBuf(void)
89 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
90 NewBuf->buf = (char*) malloc(SIZ);
91 NewBuf->buf[0] = '\0';
92 NewBuf->BufSize = SIZ;
99 * \brief Copy Constructor; returns a duplicate of CopyMe
100 * \params CopyMe Buffer to faxmilate
101 * \returns the new stringbuffer
103 StrBuf* NewStrBufDup(const StrBuf *CopyMe)
110 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
111 NewBuf->buf = (char*) malloc(CopyMe->BufSize);
112 memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
113 NewBuf->BufUsed = CopyMe->BufUsed;
114 NewBuf->BufSize = CopyMe->BufSize;
115 NewBuf->ConstBuf = 0;
120 * \brief create a new Buffer using an existing c-string
121 * this function should also be used if you want to pre-suggest
122 * the buffer size to allocate in conjunction with ptr == NULL
123 * \param ptr the c-string to copy; may be NULL to create a blank instance
124 * \param nChars How many chars should we copy; -1 if we should measure the length ourselves
125 * \returns the new stringbuffer
127 StrBuf* NewStrBufPlain(const char* ptr, int nChars)
133 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
135 CopySize = strlen((ptr != NULL)?ptr:"");
139 while (Siz <= CopySize)
142 NewBuf->buf = (char*) malloc(Siz);
143 NewBuf->BufSize = Siz;
145 memcpy(NewBuf->buf, ptr, CopySize);
146 NewBuf->buf[CopySize] = '\0';
147 NewBuf->BufUsed = CopySize;
150 NewBuf->buf[0] = '\0';
153 NewBuf->ConstBuf = 0;
158 * \brief Set an existing buffer from a c-string
159 * \param ptr c-string to put into
160 * \param nChars set to -1 if we should work 0-terminated
161 * \returns the new length of the string
163 int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
165 size_t Siz = Buf->BufSize;
169 CopySize = strlen(ptr);
173 while (Siz <= CopySize)
176 if (Siz != Buf->BufSize)
177 IncreaseBuf(Buf, 0, Siz);
178 memcpy(Buf->buf, ptr, CopySize);
179 Buf->buf[CopySize] = '\0';
180 Buf->BufUsed = CopySize;
187 * \brief use strbuf as wrapper for a string constant for easy handling
188 * \param StringConstant a string to wrap
189 * \param SizeOfConstant should be sizeof(StringConstant)-1
191 StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
195 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
196 NewBuf->buf = (char*) StringConstant;
197 NewBuf->BufSize = SizeOfStrConstant;
198 NewBuf->BufUsed = SizeOfStrConstant;
199 NewBuf->ConstBuf = 1;
205 * \brief flush the content of a Buf; keep its struct
206 * \param buf Buffer to flush
208 int FlushStrBuf(StrBuf *buf)
218 * \brief Release a Buffer
219 * Its a double pointer, so it can NULL your pointer
220 * so fancy SIG11 appear instead of random results
221 * \param FreeMe Pointer Pointer to the buffer to free
223 void FreeStrBuf (StrBuf **FreeMe)
227 if (!(*FreeMe)->ConstBuf)
228 free((*FreeMe)->buf);
234 * \brief Release the buffer
235 * If you want put your StrBuf into a Hash, use this as Destructor.
236 * \param VFreeMe untyped pointer to a StrBuf. be shure to do the right thing [TM]
238 void HFreeStrBuf (void *VFreeMe)
240 StrBuf *FreeMe = (StrBuf*)VFreeMe;
243 if (!FreeMe->ConstBuf)
249 * \brief Wrapper around atol
251 long StrTol(const StrBuf *Buf)
254 return atol(Buf->buf);
260 * \brief Wrapper around atoi
262 int StrToi(const StrBuf *Buf)
265 return atoi(Buf->buf);
271 * \brief modifies a Single char of the Buf
272 * You can point to it via char* or a zero-based integer
273 * \param ptr char* to zero; use NULL if unused
274 * \param nThChar zero based pointer into the string; use -1 if unused
275 * \param PeekValue The Character to place into the position
277 long StrBufPeek(StrBuf *Buf, const char* ptr, long nThChar, char PeekValue)
282 nThChar = ptr - Buf->buf;
283 if ((nThChar < 0) || (nThChar > Buf->BufUsed))
285 Buf->buf[nThChar] = PeekValue;
290 * \brief Append a StringBuffer to the buffer
291 * \param Buf Buffer to modify
292 * \param AppendBuf Buffer to copy at the end of our buffer
293 * \param Offset Should we start copying from an offset?
295 void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, size_t Offset)
297 if ((AppendBuf == NULL) || (Buf == NULL))
300 if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed)
303 AppendBuf->BufUsed + Buf->BufUsed);
305 memcpy(Buf->buf + Buf->BufUsed,
306 AppendBuf->buf + Offset,
307 AppendBuf->BufUsed - Offset);
308 Buf->BufUsed += AppendBuf->BufUsed - Offset;
309 Buf->buf[Buf->BufUsed] = '\0';
314 * \brief Append a C-String to the buffer
315 * \param Buf Buffer to modify
316 * \param AppendBuf Buffer to copy at the end of our buffer
317 * \param AppendSize number of bytes to copy; set to -1 if we should count it in advance
318 * \param Offset Should we start copying from an offset?
320 void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, size_t Offset)
324 if ((AppendBuf == NULL) || (Buf == NULL))
328 aps = strlen(AppendBuf + Offset);
330 aps = AppendSize - Offset;
332 if (Buf->BufSize < Buf->BufUsed + aps)
333 IncreaseBuf(Buf, (Buf->BufUsed > 0), Buf->BufUsed + aps);
335 memcpy(Buf->buf + Buf->BufUsed,
339 Buf->buf[Buf->BufUsed] = '\0';
344 * \brief Escape a string for feeding out as a URL while appending it to a Buffer
345 * \param outbuf the output buffer
346 * \param oblen the size of outbuf to sanitize
347 * \param strbuf the input buffer
349 void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
351 const char *pch, *pche;
354 const char ec[] = " +#&;`'|*?-~<>^()[]{}/$\"\\";
355 int eclen = sizeof(ec) -1;
357 if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
359 if (PlainIn != NULL) {
360 len = strlen(PlainIn);
366 pche = pch + In->BufUsed;
373 pt = OutBuf->buf + OutBuf->BufUsed;
374 pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
378 IncreaseBuf(OutBuf, 1, -1);
379 pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
380 pt = OutBuf->buf + OutBuf->BufUsed;
384 for (b = 0; b < eclen; ++b) {
391 sprintf(pt,"%%%02X", *pch);
393 OutBuf->BufUsed += 3;
405 * \brief Append a string, escaping characters which have meaning in HTML.
407 * \param Target target buffer
408 * \param Source source buffer; set to NULL if you just have a C-String
409 * \param PlainIn Plain-C string to append; set to NULL if unused
410 * \param nbsp If nonzero, spaces are converted to non-breaking spaces.
411 * \param nolinebreaks if set, linebreaks are removed from the string.
413 long StrEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
415 const char *aptr, *eiptr;
419 if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
422 if (PlainIn != NULL) {
424 len = strlen(PlainIn);
429 eiptr = aptr + Source->BufUsed;
430 len = Source->BufUsed;
436 bptr = Target->buf + Target->BufUsed;
437 eptr = Target->buf + Target->BufSize - 6; /* our biggest unit to put in... */
439 while (aptr < eiptr){
441 IncreaseBuf(Target, 1, -1);
442 eptr = Target->buf + Target->BufSize - 6;
443 bptr = Target->buf + Target->BufUsed;
446 memcpy(bptr, "<", 4);
448 Target->BufUsed += 4;
450 else if (*aptr == '>') {
451 memcpy(bptr, ">", 4);
453 Target->BufUsed += 4;
455 else if (*aptr == '&') {
456 memcpy(bptr, "&", 5);
458 Target->BufUsed += 5;
460 else if (*aptr == '\"') {
461 memcpy(bptr, """, 6);
463 Target->BufUsed += 6;
465 else if (*aptr == '\'') {
466 memcpy(bptr, "'", 5);
468 Target->BufUsed += 5;
470 else if (*aptr == LB) {
475 else if (*aptr == RB) {
480 else if (*aptr == QU) {
485 else if ((*aptr == 32) && (nbsp == 1)) {
486 memcpy(bptr, " ", 6);
488 Target->BufUsed += 6;
490 else if ((*aptr == '\n') && (nolinebreaks)) {
491 *bptr='\0'; /* nothing */
493 else if ((*aptr == '\r') && (nolinebreaks)) {
494 *bptr='\0'; /* nothing */
504 if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
506 return Target->BufUsed;
510 * \brief Append a string, escaping characters which have meaning in HTML.
511 * Converts linebreaks into blanks; escapes single quotes
512 * \param Target target buffer
513 * \param Source source buffer; set to NULL if you just have a C-String
514 * \param PlainIn Plain-C string to append; set to NULL if unused
516 void StrMsgEscAppend(StrBuf *Target, StrBuf *Source, const char *PlainIn)
518 const char *aptr, *eiptr;
522 if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
525 if (PlainIn != NULL) {
527 len = strlen(PlainIn);
532 eiptr = aptr + Source->BufUsed;
533 len = Source->BufUsed;
539 eptr = Target->buf + Target->BufSize - 6;
540 tptr = Target->buf + Target->BufUsed;
542 while (aptr < eiptr){
544 IncreaseBuf(Target, 1, -1);
545 eptr = Target->buf + Target->BufSize - 6;
546 tptr = Target->buf + Target->BufUsed;
553 else if (*aptr == '\r') {
557 else if (*aptr == '\'') {
563 Target->BufUsed += 5;
575 * \brief extracts a substring from Source into dest
576 * \param dest buffer to place substring into
577 * \param Source string to copy substring from
578 * \param Offset chars to skip from start
579 * \param nChars number of chars to copy
580 * \returns the number of chars copied; may be different from nChars due to the size of Source
582 int StrBufSub(StrBuf *dest, const StrBuf *Source, size_t Offset, size_t nChars)
585 if (Offset > Source->BufUsed)
590 if (Offset + nChars < Source->BufUsed)
592 if (nChars > dest->BufSize)
593 IncreaseBuf(dest, 0, nChars + 1);
594 memcpy(dest->buf, Source->buf + Offset, nChars);
595 dest->BufUsed = nChars;
596 dest->buf[dest->BufUsed] = '\0';
599 NCharsRemain = Source->BufUsed - Offset;
600 if (NCharsRemain > dest->BufSize)
601 IncreaseBuf(dest, 0, NCharsRemain + 1);
602 memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
603 dest->BufUsed = NCharsRemain;
604 dest->buf[dest->BufUsed] = '\0';
609 * \brief sprintf like function appending the formated string to the buffer
610 * vsnprintf version to wrap into own calls
611 * \param Buf Buffer to extend by format and params
612 * \param format printf alike format to add
613 * \param ap va_list containing the items for format
615 void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
618 size_t BufSize = Buf->BufSize;
619 size_t nWritten = Buf->BufSize + 1;
620 size_t Offset = Buf->BufUsed;
621 size_t newused = Offset + nWritten;
623 while (newused >= BufSize) {
625 nWritten = vsnprintf(Buf->buf + Offset,
626 Buf->BufSize - Offset,
629 newused = Offset + nWritten;
630 if (newused >= Buf->BufSize) {
631 IncreaseBuf(Buf, 1, newused);
634 Buf->BufUsed = Offset + nWritten;
635 BufSize = Buf->BufSize;
642 * \brief sprintf like function appending the formated string to the buffer
643 * \param Buf Buffer to extend by format and params
644 * \param format printf alike format to add
645 * \param ap va_list containing the items for format
647 void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
649 size_t BufSize = Buf->BufSize;
650 size_t nWritten = Buf->BufSize + 1;
651 size_t Offset = Buf->BufUsed;
652 size_t newused = Offset + nWritten;
655 while (newused >= BufSize) {
656 va_start(arg_ptr, format);
657 nWritten = vsnprintf(Buf->buf + Buf->BufUsed,
658 Buf->BufSize - Buf->BufUsed,
661 newused = Buf->BufUsed + nWritten;
662 if (newused >= Buf->BufSize) {
663 IncreaseBuf(Buf, 1, newused);
666 Buf->BufUsed += nWritten;
667 BufSize = Buf->BufSize;
674 * \brief sprintf like function putting the formated string into the buffer
675 * \param Buf Buffer to extend by format and params
676 * \param format printf alike format to add
677 * \param ap va_list containing the items for format
679 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
681 size_t nWritten = Buf->BufSize + 1;
684 while (nWritten >= Buf->BufSize) {
685 va_start(arg_ptr, format);
686 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
688 Buf->BufUsed = nWritten ;
689 if (nWritten >= Buf->BufSize)
690 IncreaseBuf(Buf, 0, 0);
696 * \brief Counts the numbmer of tokens in a buffer
697 * \param Source String to count tokens in
698 * \param tok Tokenizer char to count
699 * \returns numbers of tokenizer chars found
701 inline int StrBufNum_tokens(const StrBuf *source, char tok)
703 return num_tokens(source->buf, tok);
707 * \brief a string tokenizer
708 * \param dest Destination StringBuffer
709 * \param Source StringBuffer to read into
710 * \param parmnum n'th parameter to extract
711 * \param separator tokenizer param
712 * \returns -1 if not found, else length of token.
714 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
716 const char *s, *e; //* source * /
717 int len = 0; //* running total length of extracted string * /
718 int current_token = 0; //* token currently being processed * /
720 if ((Source == NULL) || (Source->BufUsed ==0)) {
724 e = s + Source->BufUsed;
730 //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
734 while ((s<e) && !IsEmptyStr(s)) {
735 if (*s == separator) {
738 if (len >= dest->BufSize)
739 if (!IncreaseBuf(dest, 1, -1))
741 if ( (current_token == parmnum) &&
746 else if (current_token > parmnum) {
752 dest->buf[len] = '\0';
755 if (current_token < parmnum) {
756 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
759 //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
765 * \brief a string tokenizer to fetch an integer
766 * \param dest Destination StringBuffer
767 * \param parmnum n'th parameter to extract
768 * \param separator tokenizer param
769 * \returns 0 if not found, else integer representation of the token
771 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
780 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
787 * \brief a string tokenizer to fetch a long integer
788 * \param dest Destination StringBuffer
789 * \param parmnum n'th parameter to extract
790 * \param separator tokenizer param
791 * \returns 0 if not found, else long integer representation of the token
793 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
802 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
810 * \brief a string tokenizer to fetch an unsigned long
811 * \param dest Destination StringBuffer
812 * \param parmnum n'th parameter to extract
813 * \param separator tokenizer param
814 * \returns 0 if not found, else unsigned long representation of the token
816 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
826 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0) {
830 return (unsigned long) atol(pnum);
839 * \brief Read a line from socket
840 * flushes and closes the FD on error
841 * \param buf the buffer to get the input to
842 * \param fd pointer to the filedescriptor to read
843 * \param append Append to an existing string or replace?
844 * \param Error strerror() on error
845 * \returns numbers of chars read
847 int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
854 slen = len = buf->BufUsed;
856 rlen = read(*fd, &buf->buf[len], 1);
858 *Error = strerror(errno);
865 if (buf->buf[len] == '\n')
867 if (buf->buf[len] != '\r')
869 if (!(len < buf->BufSize)) {
871 buf->buf[len+1] = '\0';
872 IncreaseBuf(buf, 1, -1);
876 buf->buf[len] = '\0';
881 * \brief Read a line from socket
882 * flushes and closes the FD on error
883 * \param buf the buffer to get the input to
884 * \param fd pointer to the filedescriptor to read
885 * \param append Append to an existing string or replace?
886 * \param Error strerror() on error
887 * \returns numbers of chars read
889 int StrBufTCP_read_buffered_line(StrBuf *Line,
893 int selectresolution,
897 int nSuccessLess = 0;
903 if (buf->BufUsed > 0) {
904 pch = strchr(buf->buf, '\n');
907 len = pch - buf->buf;
908 if (len > 0 && (*(pch - 1) == '\r') )
910 StrBufSub(Line, buf, 0, len - rlen);
911 StrBufCutLeft(buf, len + 1);
916 if (buf->BufSize - buf->BufUsed < 10)
917 IncreaseBuf(buf, 1, -1);
919 fdflags = fcntl(*fd, F_GETFL);
920 if ((fdflags & O_NONBLOCK) == O_NONBLOCK)
923 while ((nSuccessLess < timeout) && (pch == NULL)) {
924 tv.tv_sec = selectresolution;
929 if (select(*fd + 1, NULL, &rfds, NULL, &tv) == -1) {
930 *Error = strerror(errno);
935 if (FD_ISSET(*fd, &rfds)) {
937 &buf->buf[buf->BufUsed],
938 buf->BufSize - buf->BufUsed - 1);
940 *Error = strerror(errno);
947 buf->BufUsed += rlen;
948 buf->buf[buf->BufUsed] = '\0';
949 if (buf->BufUsed + 10 > buf->BufSize) {
950 IncreaseBuf(buf, 1, -1);
952 pch = strchr(buf->buf, '\n');
960 len = pch - buf->buf;
961 if (len > 0 && (*(pch - 1) == '\r') )
963 StrBufSub(Line, buf, 0, len - rlen);
964 StrBufCutLeft(buf, len + 1);
972 * \brief Input binary data from socket
973 * flushes and closes the FD on error
974 * \param buf the buffer to get the input to
975 * \param fd pointer to the filedescriptor to read
976 * \param append Append to an existing string or replace?
977 * \param nBytes the maximal number of bytes to read
978 * \param Error strerror() on error
979 * \returns numbers of chars read
981 int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error)
989 if ((Buf == NULL) || (*fd == -1))
993 if (Buf->BufUsed + nBytes > Buf->BufSize)
994 IncreaseBuf(Buf, 1, Buf->BufUsed + nBytes);
996 ptr = Buf->buf + Buf->BufUsed;
998 slen = len = Buf->BufUsed;
1000 fdflags = fcntl(*fd, F_GETFL);
1002 while (nRead < nBytes) {
1003 if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
1006 if (select(*fd + 1, NULL, &wset, NULL, NULL) == -1) {
1007 *Error = strerror(errno);
1012 if ((rlen = read(*fd,
1014 nBytes - nRead)) == -1) {
1017 *Error = strerror(errno);
1022 Buf->BufUsed += rlen;
1024 Buf->buf[Buf->BufUsed] = '\0';
1029 * \brief Cut nChars from the start of the string
1030 * \param Buf Buffer to modify
1031 * \param nChars how many chars should be skipped?
1033 void StrBufCutLeft(StrBuf *Buf, int nChars)
1035 if (nChars >= Buf->BufUsed) {
1039 memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
1040 Buf->BufUsed -= nChars;
1041 Buf->buf[Buf->BufUsed] = '\0';
1045 * \brief Cut the trailing n Chars from the string
1046 * \param Buf Buffer to modify
1047 * \param nChars how many chars should be trunkated?
1049 void StrBufCutRight(StrBuf *Buf, int nChars)
1051 if (nChars >= Buf->BufUsed) {
1055 Buf->BufUsed -= nChars;
1056 Buf->buf[Buf->BufUsed] = '\0';
1061 * \brief unhide special chars hidden to the HTML escaper
1062 * \param target buffer to put the unescaped string in
1063 * \param source buffer to unescape
1065 void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source)
1071 FlushStrBuf(target);
1073 if (source == NULL ||target == NULL)
1078 len = source->BufUsed;
1079 for (a = 0; a < len; ++a) {
1080 if (target->BufUsed >= target->BufSize)
1081 IncreaseBuf(target, 1, -1);
1083 if (source->buf[a] == '=') {
1084 hex[0] = source->buf[a + 1];
1085 hex[1] = source->buf[a + 2];
1088 sscanf(hex, "%02x", &b);
1089 target->buf[target->BufUsed] = b;
1090 target->buf[++target->BufUsed] = 0;
1094 target->buf[target->BufUsed] = source->buf[a];
1095 target->buf[++target->BufUsed] = 0;
1102 * \brief hide special chars from the HTML escapers and friends
1103 * \param target buffer to put the escaped string in
1104 * \param source buffer to escape
1106 void StrBufEUid_escapize(StrBuf *target, const StrBuf *source)
1111 FlushStrBuf(target);
1113 if (source == NULL ||target == NULL)
1118 len = source->BufUsed;
1119 for (i=0; i<len; ++i) {
1120 if (target->BufUsed + 4 >= target->BufSize)
1121 IncreaseBuf(target, 1, -1);
1122 if ( (isalnum(source->buf[i])) ||
1123 (source->buf[i]=='-') ||
1124 (source->buf[i]=='_') ) {
1125 target->buf[target->BufUsed++] = source->buf[i];
1128 sprintf(&target->buf[target->BufUsed],
1130 (0xFF &source->buf[i]));
1131 target->BufUsed += 3;
1134 target->buf[target->BufUsed + 1] = '\0';
1138 * \brief uses the same calling syntax as compress2(), but it
1139 * creates a stream compatible with HTTP "Content-encoding: gzip"
1142 #define DEF_MEM_LEVEL 8 /*< memlevel??? */
1143 #define OS_CODE 0x03 /*< unix */
1144 int ZEXPORT compress_gzip(Bytef * dest, /*< compressed buffer*/
1145 size_t * destLen, /*< length of the compresed data */
1146 const Bytef * source, /*< source to encode */
1147 uLong sourceLen, /*< length of source to encode */
1148 int level) /*< compression level */
1150 const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
1152 /* write gzip header */
1153 snprintf((char *) dest, *destLen,
1154 "%c%c%c%c%c%c%c%c%c%c",
1155 gz_magic[0], gz_magic[1], Z_DEFLATED,
1156 0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
1159 /* normal deflate */
1162 stream.next_in = (Bytef *) source;
1163 stream.avail_in = (uInt) sourceLen;
1164 stream.next_out = dest + 10L; // after header
1165 stream.avail_out = (uInt) * destLen;
1166 if ((uLong) stream.avail_out != *destLen)
1169 stream.zalloc = (alloc_func) 0;
1170 stream.zfree = (free_func) 0;
1171 stream.opaque = (voidpf) 0;
1173 err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS,
1174 DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
1178 err = deflate(&stream, Z_FINISH);
1179 if (err != Z_STREAM_END) {
1180 deflateEnd(&stream);
1181 return err == Z_OK ? Z_BUF_ERROR : err;
1183 *destLen = stream.total_out + 10L;
1185 /* write CRC and Length */
1186 uLong crc = crc32(0L, source, sourceLen);
1188 for (n = 0; n < 4; ++n, ++*destLen) {
1189 dest[*destLen] = (int) (crc & 0xff);
1192 uLong len = stream.total_in;
1193 for (n = 0; n < 4; ++n, ++*destLen) {
1194 dest[*destLen] = (int) (len & 0xff);
1197 err = deflateEnd(&stream);
1204 * Attention! If you feed this a Const String, you must maintain the uncompressed buffer yourself!
1206 int CompressBuffer(StrBuf *Buf)
1209 char *compressed_data = NULL;
1210 size_t compressed_len, bufsize;
1212 bufsize = compressed_len = ((Buf->BufUsed * 101) / 100) + 100;
1213 compressed_data = malloc(compressed_len);
1215 if (compress_gzip((Bytef *) compressed_data,
1218 (uLongf) Buf->BufUsed, Z_BEST_SPEED) == Z_OK) {
1221 Buf->buf = compressed_data;
1222 Buf->BufUsed = compressed_len;
1223 Buf->BufSize = bufsize;
1226 free(compressed_data);
1228 #endif /* HAVE_ZLIB */
1233 * \brief decode a buffer from base 64 encoding; destroys original
1234 * \param Buf Buffor to transform
1236 int StrBufDecodeBase64(StrBuf *Buf)
1240 if (Buf == NULL) return -1;
1242 xferbuf = (char*) malloc(Buf->BufSize);
1243 siz = CtdlDecodeBase64(xferbuf,
1254 * \brief remove escaped strings from i.e. the url string (like %20 for blanks)
1255 * \param Buf Buffer to translate
1256 * \param StripBlanks Reduce several blanks to one?
1258 long StrBufUnescape(StrBuf *Buf, int StripBlanks)
1264 while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
1265 Buf->buf[Buf->BufUsed - 1] = '\0';
1270 while (a < Buf->BufUsed) {
1271 if (Buf->buf[a] == '+')
1273 else if (Buf->buf[a] == '%') {
1274 /* don't let % chars through, rather truncate the input. */
1275 if (a + 2 > Buf->BufUsed) {
1280 hex[0] = Buf->buf[a + 1];
1281 hex[1] = Buf->buf[a + 2];
1284 sscanf(hex, "%02x", &b);
1285 Buf->buf[a] = (char) b;
1286 len = Buf->BufUsed - a - 2;
1288 memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
1300 * \brief RFC2047-encode a header field if necessary.
1301 * If no non-ASCII characters are found, the string
1302 * will be copied verbatim without encoding.
1304 * \param target Target buffer.
1305 * \param source Source string to be encoded.
1306 * \returns encoded length; -1 if non success.
1308 int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
1310 const char headerStr[] = "=?UTF-8?Q?";
1311 int need_to_encode = 0;
1315 if ((source == NULL) ||
1319 while ((i < source->BufUsed) &&
1320 (!IsEmptyStr (&source->buf[i])) &&
1321 (need_to_encode == 0)) {
1322 if (((unsigned char) source->buf[i] < 32) ||
1323 ((unsigned char) source->buf[i] > 126)) {
1329 if (!need_to_encode) {
1330 if (*target == NULL) {
1331 *target = NewStrBufPlain(source->buf, source->BufUsed);
1334 FlushStrBuf(*target);
1335 StrBufAppendBuf(*target, source, 0);
1337 return (*target)->BufUsed;
1339 if (*target == NULL)
1340 *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
1341 else if (sizeof(headerStr) + source->BufUsed > (*target)->BufSize)
1342 IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
1343 memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
1344 (*target)->BufUsed = sizeof(headerStr) - 1;
1345 for (i=0; (i < source->BufUsed); ++i) {
1346 if ((*target)->BufUsed + 4 > (*target)->BufSize)
1347 IncreaseBuf(*target, 1, 0);
1348 ch = (unsigned char) source->buf[i];
1349 if ((ch < 32) || (ch > 126) || (ch == 61)) {
1350 sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
1351 (*target)->BufUsed += 3;
1354 (*target)->buf[(*target)->BufUsed] = ch;
1355 (*target)->BufUsed++;
1359 if ((*target)->BufUsed + 4 > (*target)->BufSize)
1360 IncreaseBuf(*target, 1, 0);
1362 (*target)->buf[(*target)->BufUsed++] = '?';
1363 (*target)->buf[(*target)->BufUsed++] = '=';
1364 (*target)->buf[(*target)->BufUsed] = '\0';
1365 return (*target)->BufUsed;;
1369 * \brief replaces all occurances of 'search' by 'replace'
1370 * \param buf Buffer to modify
1371 * \param search character to search
1372 * \param relpace character to replace search by
1374 void StrBufReplaceChars(StrBuf *buf, char search, char replace)
1379 for (i=0; i<buf->BufUsed; i++)
1380 if (buf->buf[i] == search)
1381 buf->buf[i] = replace;