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 * Allocate a new buffer with default buffer size
49 * \returns the new stringbuffer
51 StrBuf* NewStrBuf(void)
55 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
56 NewBuf->buf = (char*) malloc(SIZ);
57 NewBuf->buf[0] = '\0';
58 NewBuf->BufSize = SIZ;
65 * \brief Copy Constructor; returns a duplicate of CopyMe
66 * \params CopyMe Buffer to faxmilate
67 * \returns the new stringbuffer
69 StrBuf* NewStrBufDup(const StrBuf *CopyMe)
76 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
77 NewBuf->buf = (char*) malloc(CopyMe->BufSize);
78 memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
79 NewBuf->BufUsed = CopyMe->BufUsed;
80 NewBuf->BufSize = CopyMe->BufSize;
86 * \brief create a new Buffer using an existing c-string
87 * this function should also be used if you want to pre-suggest
88 * the buffer size to allocate in conjunction with ptr == NULL
89 * \param ptr the c-string to copy; may be NULL to create a blank instance
90 * \param nChars How many chars should we copy; -1 if we should measure the length ourselves
91 * \returns the new stringbuffer
93 StrBuf* NewStrBufPlain(const char* ptr, int nChars)
99 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
101 CopySize = strlen((ptr != NULL)?ptr:"");
105 while (Siz <= CopySize)
108 NewBuf->buf = (char*) malloc(Siz);
109 NewBuf->BufSize = Siz;
111 memcpy(NewBuf->buf, ptr, CopySize);
112 NewBuf->buf[CopySize] = '\0';
113 NewBuf->BufUsed = CopySize;
116 NewBuf->buf[0] = '\0';
119 NewBuf->ConstBuf = 0;
124 * \brief Set an existing buffer from a c-string
125 * \param ptr c-string to put into
126 * \param nChars set to -1 if we should work 0-terminated
127 * \returns the new length of the string
129 int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
131 size_t Siz = Buf->BufSize;
135 CopySize = strlen(ptr);
139 while (Siz <= CopySize)
142 if (Siz != Buf->BufSize)
143 IncreaseBuf(Buf, 0, Siz);
144 memcpy(Buf->buf, ptr, CopySize);
145 Buf->buf[CopySize] = '\0';
146 Buf->BufUsed = CopySize;
153 * \brief use strbuf as wrapper for a string constant for easy handling
154 * \param StringConstant a string to wrap
155 * \param SizeOfConstant should be sizeof(StringConstant)-1
157 StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
161 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
162 NewBuf->buf = (char*) StringConstant;
163 NewBuf->BufSize = SizeOfStrConstant;
164 NewBuf->BufUsed = SizeOfStrConstant;
165 NewBuf->ConstBuf = 1;
170 * \brief local utility function to resize the buffer
171 * \param Buf the buffer whichs storage we should increase
172 * \param KeepOriginal should we copy the original buffer or just start over with a new one
173 * \param DestSize what should fit in after?
175 static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
178 size_t NewSize = Buf->BufSize * 2;
184 while (NewSize < DestSize)
187 NewBuf= (char*) malloc(NewSize);
188 if (KeepOriginal && (Buf->BufUsed > 0))
190 memcpy(NewBuf, Buf->buf, Buf->BufUsed);
204 * \brief flush the content of a Buf; keep its struct
205 * \param buf Buffer to flush
207 int FlushStrBuf(StrBuf *buf)
217 * \brief Release a Buffer
218 * Its a double pointer, so it can NULL your pointer
219 * so fancy SIG11 appear instead of random results
220 * \param FreeMe Pointer Pointer to the buffer to free
222 void FreeStrBuf (StrBuf **FreeMe)
226 if (!(*FreeMe)->ConstBuf)
227 free((*FreeMe)->buf);
233 * \brief Release the buffer
234 * If you want put your StrBuf into a Hash, use this as Destructor.
235 * \param VFreeMe untyped pointer to a StrBuf. be shure to do the right thing [TM]
237 void HFreeStrBuf (void *VFreeMe)
239 StrBuf *FreeMe = (StrBuf*)VFreeMe;
242 if (!FreeMe->ConstBuf)
248 * \brief Wrapper around atol
250 long StrTol(const StrBuf *Buf)
253 return atol(Buf->buf);
259 * \brief Wrapper around atoi
261 int StrToi(const StrBuf *Buf)
264 return atoi(Buf->buf);
270 * \brief modifies a Single char of the Buf
271 * You can point to it via char* or a zero-based integer
272 * \param ptr char* to zero; use NULL if unused
273 * \param nThChar zero based pointer into the string; use -1 if unused
274 * \param PeekValue The Character to place into the position
276 long StrBufPeek(StrBuf *Buf, const char* ptr, long nThChar, char PeekValue)
281 nThChar = ptr - Buf->buf;
282 if ((nThChar < 0) || (nThChar > Buf->BufUsed))
284 Buf->buf[nThChar] = PeekValue;
289 * \brief Append a StringBuffer to the buffer
290 * \param Buf Buffer to modify
291 * \param AppendBuf Buffer to copy at the end of our buffer
292 * \param Offset Should we start copying from an offset?
294 void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, size_t Offset)
296 if ((AppendBuf == NULL) || (Buf == NULL))
299 if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed)
302 AppendBuf->BufUsed + Buf->BufUsed);
304 memcpy(Buf->buf + Buf->BufUsed,
305 AppendBuf->buf + Offset,
306 AppendBuf->BufUsed - Offset);
307 Buf->BufUsed += AppendBuf->BufUsed - Offset;
308 Buf->buf[Buf->BufUsed] = '\0';
313 * \brief Append a C-String to the buffer
314 * \param Buf Buffer to modify
315 * \param AppendBuf Buffer to copy at the end of our buffer
316 * \param AppendSize number of bytes to copy; set to -1 if we should count it in advance
317 * \param Offset Should we start copying from an offset?
319 void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, size_t Offset)
323 if ((AppendBuf == NULL) || (Buf == NULL))
327 aps = strlen(AppendBuf + Offset);
329 aps = AppendSize - Offset;
331 if (Buf->BufSize < Buf->BufUsed + aps)
332 IncreaseBuf(Buf, (Buf->BufUsed > 0), Buf->BufUsed + aps);
334 memcpy(Buf->buf + Buf->BufUsed,
338 Buf->buf[Buf->BufUsed] = '\0';
343 * \brief Escape a string for feeding out as a URL while appending it to a Buffer
344 * \param outbuf the output buffer
345 * \param oblen the size of outbuf to sanitize
346 * \param strbuf the input buffer
348 void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
350 const char *pch, *pche;
353 const char ec[] = " +#&;`'|*?-~<>^()[]{}/$\"\\";
354 int eclen = sizeof(ec) -1;
356 if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
358 if (PlainIn != NULL) {
359 len = strlen(PlainIn);
365 pche = pch + In->BufUsed;
372 pt = OutBuf->buf + OutBuf->BufUsed;
373 pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
377 IncreaseBuf(OutBuf, 1, -1);
378 pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
379 pt = OutBuf->buf + OutBuf->BufUsed;
383 for (b = 0; b < eclen; ++b) {
390 sprintf(pt,"%%%02X", *pch);
392 OutBuf->BufUsed += 3;
404 * \brief Append a string, escaping characters which have meaning in HTML.
406 * \param Target target buffer
407 * \param Source source buffer; set to NULL if you just have a C-String
408 * \param PlainIn Plain-C string to append; set to NULL if unused
409 * \param nbsp If nonzero, spaces are converted to non-breaking spaces.
410 * \param nolinebreaks if set, linebreaks are removed from the string.
412 long StrEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
414 const char *aptr, *eiptr;
418 if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
421 if (PlainIn != NULL) {
423 len = strlen(PlainIn);
428 eiptr = aptr + Source->BufUsed;
429 len = Source->BufUsed;
435 bptr = Target->buf + Target->BufUsed;
436 eptr = Target->buf + Target->BufSize - 6; /* our biggest unit to put in... */
438 while (aptr < eiptr){
440 IncreaseBuf(Target, 1, -1);
441 eptr = Target->buf + Target->BufSize - 6;
442 bptr = Target->buf + Target->BufUsed;
445 memcpy(bptr, "<", 4);
447 Target->BufUsed += 4;
449 else if (*aptr == '>') {
450 memcpy(bptr, ">", 4);
452 Target->BufUsed += 4;
454 else if (*aptr == '&') {
455 memcpy(bptr, "&", 5);
457 Target->BufUsed += 5;
459 else if (*aptr == '\"') {
460 memcpy(bptr, """, 6);
462 Target->BufUsed += 6;
464 else if (*aptr == '\'') {
465 memcpy(bptr, "'", 5);
467 Target->BufUsed += 5;
469 else if (*aptr == LB) {
474 else if (*aptr == RB) {
479 else if (*aptr == QU) {
484 else if ((*aptr == 32) && (nbsp == 1)) {
485 memcpy(bptr, " ", 6);
487 Target->BufUsed += 6;
489 else if ((*aptr == '\n') && (nolinebreaks)) {
490 *bptr='\0'; /* nothing */
492 else if ((*aptr == '\r') && (nolinebreaks)) {
493 *bptr='\0'; /* nothing */
503 if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
505 return Target->BufUsed;
509 * \brief Append a string, escaping characters which have meaning in HTML.
510 * Converts linebreaks into blanks; escapes single quotes
511 * \param Target target buffer
512 * \param Source source buffer; set to NULL if you just have a C-String
513 * \param PlainIn Plain-C string to append; set to NULL if unused
515 void StrMsgEscAppend(StrBuf *Target, StrBuf *Source, const char *PlainIn)
517 const char *aptr, *eiptr;
521 if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
524 if (PlainIn != NULL) {
526 len = strlen(PlainIn);
531 eiptr = aptr + Source->BufUsed;
532 len = Source->BufUsed;
538 eptr = Target->buf + Target->BufSize - 6;
539 tptr = Target->buf + Target->BufUsed;
541 while (aptr < eiptr){
543 IncreaseBuf(Target, 1, -1);
544 eptr = Target->buf + Target->BufSize - 6;
545 tptr = Target->buf + Target->BufUsed;
552 else if (*aptr == '\r') {
556 else if (*aptr == '\'') {
562 Target->BufUsed += 5;
574 * \brief extracts a substring from Source into dest
575 * \param dest buffer to place substring into
576 * \param Source string to copy substring from
577 * \param Offset chars to skip from start
578 * \param nChars number of chars to copy
579 * \returns the number of chars copied; may be different from nChars due to the size of Source
581 int StrBufSub(StrBuf *dest, const StrBuf *Source, size_t Offset, size_t nChars)
584 if (Offset > Source->BufUsed)
589 if (Offset + nChars < Source->BufUsed)
591 if (nChars > dest->BufSize)
592 IncreaseBuf(dest, 0, nChars + 1);
593 memcpy(dest->buf, Source->buf + Offset, nChars);
594 dest->BufUsed = nChars;
595 dest->buf[dest->BufUsed] = '\0';
598 NCharsRemain = Source->BufUsed - Offset;
599 if (NCharsRemain > dest->BufSize)
600 IncreaseBuf(dest, 0, NCharsRemain + 1);
601 memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
602 dest->BufUsed = NCharsRemain;
603 dest->buf[dest->BufUsed] = '\0';
608 * \brief sprintf like function appending the formated string to the buffer
609 * vsnprintf version to wrap into own calls
610 * \param Buf Buffer to extend by format and params
611 * \param format printf alike format to add
612 * \param ap va_list containing the items for format
614 void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
617 size_t BufSize = Buf->BufSize;
618 size_t nWritten = Buf->BufSize + 1;
619 size_t Offset = Buf->BufUsed;
620 size_t newused = Offset + nWritten;
622 while (newused >= BufSize) {
624 nWritten = vsnprintf(Buf->buf + Offset,
625 Buf->BufSize - Offset,
628 newused = Offset + nWritten;
629 if (newused >= Buf->BufSize) {
630 IncreaseBuf(Buf, 1, newused);
633 Buf->BufUsed = Offset + nWritten;
634 BufSize = Buf->BufSize;
641 * \brief sprintf like function appending the formated string to the buffer
642 * \param Buf Buffer to extend by format and params
643 * \param format printf alike format to add
644 * \param ap va_list containing the items for format
646 void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
648 size_t BufSize = Buf->BufSize;
649 size_t nWritten = Buf->BufSize + 1;
650 size_t Offset = Buf->BufUsed;
651 size_t newused = Offset + nWritten;
654 while (newused >= BufSize) {
655 va_start(arg_ptr, format);
656 nWritten = vsnprintf(Buf->buf + Buf->BufUsed,
657 Buf->BufSize - Buf->BufUsed,
660 newused = Buf->BufUsed + nWritten;
661 if (newused >= Buf->BufSize) {
662 IncreaseBuf(Buf, 1, newused);
665 Buf->BufUsed += nWritten;
666 BufSize = Buf->BufSize;
673 * \brief sprintf like function putting the formated string into the buffer
674 * \param Buf Buffer to extend by format and params
675 * \param format printf alike format to add
676 * \param ap va_list containing the items for format
678 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
680 size_t nWritten = Buf->BufSize + 1;
683 while (nWritten >= Buf->BufSize) {
684 va_start(arg_ptr, format);
685 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
687 Buf->BufUsed = nWritten ;
688 if (nWritten >= Buf->BufSize)
689 IncreaseBuf(Buf, 0, 0);
695 * \brief Counts the numbmer of tokens in a buffer
696 * \param Source String to count tokens in
697 * \param tok Tokenizer char to count
698 * \returns numbers of tokenizer chars found
700 inline int StrBufNum_tokens(const StrBuf *source, char tok)
702 return num_tokens(source->buf, tok);
706 * \brief a string tokenizer
707 * \param dest Destination StringBuffer
708 * \param Source StringBuffer to read into
709 * \param parmnum n'th parameter to extract
710 * \param separator tokenizer param
711 * \returns -1 if not found, else length of token.
713 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
715 const char *s, *e; //* source * /
716 int len = 0; //* running total length of extracted string * /
717 int current_token = 0; //* token currently being processed * /
719 if ((Source == NULL) || (Source->BufUsed ==0)) {
723 e = s + Source->BufUsed;
729 //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
733 while ((s<e) && !IsEmptyStr(s)) {
734 if (*s == separator) {
737 if (len >= dest->BufSize)
738 if (!IncreaseBuf(dest, 1, -1))
740 if ( (current_token == parmnum) &&
745 else if (current_token > parmnum) {
751 dest->buf[len] = '\0';
754 if (current_token < parmnum) {
755 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
758 //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
764 * \brief a string tokenizer to fetch an integer
765 * \param dest Destination StringBuffer
766 * \param parmnum n'th parameter to extract
767 * \param separator tokenizer param
768 * \returns 0 if not found, else integer representation of the token
770 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
779 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
786 * \brief a string tokenizer to fetch a long integer
787 * \param dest Destination StringBuffer
788 * \param parmnum n'th parameter to extract
789 * \param separator tokenizer param
790 * \returns 0 if not found, else long integer representation of the token
792 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
801 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
809 * \brief a string tokenizer to fetch an unsigned long
810 * \param dest Destination StringBuffer
811 * \param parmnum n'th parameter to extract
812 * \param separator tokenizer param
813 * \returns 0 if not found, else unsigned long representation of the token
815 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
825 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0) {
829 return (unsigned long) atol(pnum);
838 * \brief Read a line from socket
839 * flushes and closes the FD on error
840 * \param buf the buffer to get the input to
841 * \param fd pointer to the filedescriptor to read
842 * \param append Append to an existing string or replace?
843 * \param Error strerror() on error
844 * \returns numbers of chars read
846 int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
853 slen = len = buf->BufUsed;
855 rlen = read(*fd, &buf->buf[len], 1);
857 *Error = strerror(errno);
864 if (buf->buf[len] == '\n')
866 if (buf->buf[len] != '\r')
868 if (!(len < buf->BufSize)) {
870 buf->buf[len+1] = '\0';
871 IncreaseBuf(buf, 1, -1);
875 buf->buf[len] = '\0';
880 * \brief Input binary data from socket
881 * flushes and closes the FD on error
882 * \param buf the buffer to get the input to
883 * \param fd pointer to the filedescriptor to read
884 * \param append Append to an existing string or replace?
885 * \param nBytes the maximal number of bytes to read
886 * \param Error strerror() on error
887 * \returns numbers of chars read
889 int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error)
897 if ((Buf == NULL) || (*fd == -1))
901 if (Buf->BufUsed + nBytes > Buf->BufSize)
902 IncreaseBuf(Buf, 1, Buf->BufUsed + nBytes);
904 ptr = Buf->buf + Buf->BufUsed;
906 slen = len = Buf->BufUsed;
908 fdflags = fcntl(*fd, F_GETFL);
910 while (nRead < nBytes) {
911 if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
914 if (select(*fd + 1, NULL, &wset, NULL, NULL) == -1) {
915 *Error = strerror(errno);
920 if ((rlen = read(*fd,
922 nBytes - nRead)) == -1) {
925 *Error = strerror(errno);
930 Buf->BufUsed += rlen;
932 Buf->buf[Buf->BufUsed] = '\0';
937 * \brief Cut nChars from the start of the string
938 * \param Buf Buffer to modify
939 * \param nChars how many chars should be skipped?
941 void StrBufCutLeft(StrBuf *Buf, int nChars)
943 if (nChars >= Buf->BufUsed) {
947 memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
948 Buf->BufUsed -= nChars;
949 Buf->buf[Buf->BufUsed] = '\0';
953 * \brief Cut the trailing n Chars from the string
954 * \param Buf Buffer to modify
955 * \param nChars how many chars should be trunkated?
957 void StrBufCutRight(StrBuf *Buf, int nChars)
959 if (nChars >= Buf->BufUsed) {
963 Buf->BufUsed -= nChars;
964 Buf->buf[Buf->BufUsed] = '\0';
969 * \brief unhide special chars hidden to the HTML escaper
970 * \param target buffer to put the unescaped string in
971 * \param source buffer to unescape
973 void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source)
981 if (source == NULL ||target == NULL)
986 len = source->BufUsed;
987 for (a = 0; a < len; ++a) {
988 if (target->BufUsed >= target->BufSize)
989 IncreaseBuf(target, 1, -1);
991 if (source->buf[a] == '=') {
992 hex[0] = source->buf[a + 1];
993 hex[1] = source->buf[a + 2];
996 sscanf(hex, "%02x", &b);
997 target->buf[target->BufUsed] = b;
998 target->buf[++target->BufUsed] = 0;
1002 target->buf[target->BufUsed] = source->buf[a];
1003 target->buf[++target->BufUsed] = 0;
1010 * \brief hide special chars from the HTML escapers and friends
1011 * \param target buffer to put the escaped string in
1012 * \param source buffer to escape
1014 void StrBufEUid_escapize(StrBuf *target, const StrBuf *source)
1019 FlushStrBuf(target);
1021 if (source == NULL ||target == NULL)
1026 len = source->BufUsed;
1027 for (i=0; i<len; ++i) {
1028 if (target->BufUsed + 4 >= target->BufSize)
1029 IncreaseBuf(target, 1, -1);
1030 if ( (isalnum(source->buf[i])) ||
1031 (source->buf[i]=='-') ||
1032 (source->buf[i]=='_') ) {
1033 target->buf[target->BufUsed++] = source->buf[i];
1036 sprintf(&target->buf[target->BufUsed],
1038 (0xFF &source->buf[i]));
1039 target->BufUsed += 3;
1042 target->buf[target->BufUsed + 1] = '\0';
1046 * \brief uses the same calling syntax as compress2(), but it
1047 * creates a stream compatible with HTTP "Content-encoding: gzip"
1050 #define DEF_MEM_LEVEL 8 /*< memlevel??? */
1051 #define OS_CODE 0x03 /*< unix */
1052 int ZEXPORT compress_gzip(Bytef * dest, /*< compressed buffer*/
1053 size_t * destLen, /*< length of the compresed data */
1054 const Bytef * source, /*< source to encode */
1055 uLong sourceLen, /*< length of source to encode */
1056 int level) /*< compression level */
1058 const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
1060 /* write gzip header */
1061 snprintf((char *) dest, *destLen,
1062 "%c%c%c%c%c%c%c%c%c%c",
1063 gz_magic[0], gz_magic[1], Z_DEFLATED,
1064 0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
1067 /* normal deflate */
1070 stream.next_in = (Bytef *) source;
1071 stream.avail_in = (uInt) sourceLen;
1072 stream.next_out = dest + 10L; // after header
1073 stream.avail_out = (uInt) * destLen;
1074 if ((uLong) stream.avail_out != *destLen)
1077 stream.zalloc = (alloc_func) 0;
1078 stream.zfree = (free_func) 0;
1079 stream.opaque = (voidpf) 0;
1081 err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS,
1082 DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
1086 err = deflate(&stream, Z_FINISH);
1087 if (err != Z_STREAM_END) {
1088 deflateEnd(&stream);
1089 return err == Z_OK ? Z_BUF_ERROR : err;
1091 *destLen = stream.total_out + 10L;
1093 /* write CRC and Length */
1094 uLong crc = crc32(0L, source, sourceLen);
1096 for (n = 0; n < 4; ++n, ++*destLen) {
1097 dest[*destLen] = (int) (crc & 0xff);
1100 uLong len = stream.total_in;
1101 for (n = 0; n < 4; ++n, ++*destLen) {
1102 dest[*destLen] = (int) (len & 0xff);
1105 err = deflateEnd(&stream);
1112 * Attention! If you feed this a Const String, you must maintain the uncompressed buffer yourself!
1114 int CompressBuffer(StrBuf *Buf)
1117 char *compressed_data = NULL;
1118 size_t compressed_len, bufsize;
1120 bufsize = compressed_len = ((Buf->BufUsed * 101) / 100) + 100;
1121 compressed_data = malloc(compressed_len);
1123 if (compress_gzip((Bytef *) compressed_data,
1126 (uLongf) Buf->BufUsed, Z_BEST_SPEED) == Z_OK) {
1129 Buf->buf = compressed_data;
1130 Buf->BufUsed = compressed_len;
1131 Buf->BufSize = bufsize;
1134 free(compressed_data);
1136 #endif /* HAVE_ZLIB */
1141 * \brief decode a buffer from base 64 encoding; destroys original
1142 * \param Buf Buffor to transform
1144 int StrBufDecodeBase64(StrBuf *Buf)
1148 if (Buf == NULL) return -1;
1150 xferbuf = (char*) malloc(Buf->BufSize);
1151 siz = CtdlDecodeBase64(xferbuf,
1162 * \brief remove escaped strings from i.e. the url string (like %20 for blanks)
1163 * \param Buf Buffer to translate
1164 * \param StripBlanks Reduce several blanks to one?
1166 long StrBufUnescape(StrBuf *Buf, int StripBlanks)
1172 while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
1173 Buf->buf[Buf->BufUsed - 1] = '\0';
1178 while (a < Buf->BufUsed) {
1179 if (Buf->buf[a] == '+')
1181 else if (Buf->buf[a] == '%') {
1182 /* don't let % chars through, rather truncate the input. */
1183 if (a + 2 > Buf->BufUsed) {
1188 hex[0] = Buf->buf[a + 1];
1189 hex[1] = Buf->buf[a + 2];
1192 sscanf(hex, "%02x", &b);
1193 Buf->buf[a] = (char) b;
1194 len = Buf->BufUsed - a - 2;
1196 memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
1208 * \brief RFC2047-encode a header field if necessary.
1209 * If no non-ASCII characters are found, the string
1210 * will be copied verbatim without encoding.
1212 * \param target Target buffer.
1213 * \param source Source string to be encoded.
1214 * \returns encoded length; -1 if non success.
1216 int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
1218 const char headerStr[] = "=?UTF-8?Q?";
1219 int need_to_encode = 0;
1223 if ((source == NULL) ||
1227 while ((i < source->BufUsed) &&
1228 (!IsEmptyStr (&source->buf[i])) &&
1229 (need_to_encode == 0)) {
1230 if (((unsigned char) source->buf[i] < 32) ||
1231 ((unsigned char) source->buf[i] > 126)) {
1237 if (!need_to_encode) {
1238 if (*target == NULL) {
1239 *target = NewStrBufPlain(source->buf, source->BufUsed);
1242 FlushStrBuf(*target);
1243 StrBufAppendBuf(*target, source, 0);
1245 return (*target)->BufUsed;
1247 if (*target == NULL)
1248 *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
1249 else if (sizeof(headerStr) + source->BufUsed > (*target)->BufSize)
1250 IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
1251 memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
1252 (*target)->BufUsed = sizeof(headerStr) - 1;
1253 for (i=0; (i < source->BufUsed); ++i) {
1254 if ((*target)->BufUsed + 4 > (*target)->BufSize)
1255 IncreaseBuf(*target, 1, 0);
1256 ch = (unsigned char) source->buf[i];
1257 if ((ch < 32) || (ch > 126) || (ch == 61)) {
1258 sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
1259 (*target)->BufUsed += 3;
1262 (*target)->buf[(*target)->BufUsed] = ch;
1263 (*target)->BufUsed++;
1267 if ((*target)->BufUsed + 4 > (*target)->BufSize)
1268 IncreaseBuf(*target, 1, 0);
1270 (*target)->buf[(*target)->BufUsed++] = '?';
1271 (*target)->buf[(*target)->BufUsed++] = '=';
1272 (*target)->buf[(*target)->BufUsed] = '\0';
1273 return (*target)->BufUsed;;
1277 * \brief replaces all occurances of 'search' by 'replace'
1278 * \param buf Buffer to modify
1279 * \param search character to search
1280 * \param relpace character to replace search by
1282 void StrBufReplaceChars(StrBuf *buf, char search, char replace)
1287 for (i=0; i<buf->BufUsed; i++)
1288 if (buf->buf[i] == search)
1289 buf->buf[i] = replace;