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 * Note: if the buffer is altered by StrBuf operations, this pointer may become
28 * invalid. So don't lean on it after altering the buffer!
29 * Since this operation is considered cheap, rather call it often than risking
30 * your pointer to become invalid!
31 * \param Str the string we want to get the c-string representation for
32 * \returns the Pointer to the Content. Don't mess with it!
34 inline const char *ChrPtr(const StrBuf *Str)
42 * \brief since we know strlen()'s result, provide it here.
43 * \param Str the string to return the length to
44 * \returns contentlength of the buffer
46 inline int StrLength(const StrBuf *Str)
48 return (Str != NULL) ? Str->BufUsed : 0;
52 * \brief local utility function to resize the buffer
53 * \param Buf the buffer whichs storage we should increase
54 * \param KeepOriginal should we copy the original buffer or just start over with a new one
55 * \param DestSize what should fit in after?
57 static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
60 size_t NewSize = Buf->BufSize * 2;
66 while (NewSize < DestSize)
69 NewBuf= (char*) malloc(NewSize);
70 if (KeepOriginal && (Buf->BufUsed > 0))
72 memcpy(NewBuf, Buf->buf, Buf->BufUsed);
86 * Allocate a new buffer with default buffer size
87 * \returns the new stringbuffer
89 StrBuf* NewStrBuf(void)
93 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
94 NewBuf->buf = (char*) malloc(SIZ);
95 NewBuf->buf[0] = '\0';
96 NewBuf->BufSize = SIZ;
103 * \brief Copy Constructor; returns a duplicate of CopyMe
104 * \params CopyMe Buffer to faxmilate
105 * \returns the new stringbuffer
107 StrBuf* NewStrBufDup(const StrBuf *CopyMe)
114 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
115 NewBuf->buf = (char*) malloc(CopyMe->BufSize);
116 memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
117 NewBuf->BufUsed = CopyMe->BufUsed;
118 NewBuf->BufSize = CopyMe->BufSize;
119 NewBuf->ConstBuf = 0;
124 * \brief create a new Buffer using an existing c-string
125 * this function should also be used if you want to pre-suggest
126 * the buffer size to allocate in conjunction with ptr == NULL
127 * \param ptr the c-string to copy; may be NULL to create a blank instance
128 * \param nChars How many chars should we copy; -1 if we should measure the length ourselves
129 * \returns the new stringbuffer
131 StrBuf* NewStrBufPlain(const char* ptr, int nChars)
137 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
139 CopySize = strlen((ptr != NULL)?ptr:"");
143 while (Siz <= CopySize)
146 NewBuf->buf = (char*) malloc(Siz);
147 NewBuf->BufSize = Siz;
149 memcpy(NewBuf->buf, ptr, CopySize);
150 NewBuf->buf[CopySize] = '\0';
151 NewBuf->BufUsed = CopySize;
154 NewBuf->buf[0] = '\0';
157 NewBuf->ConstBuf = 0;
162 * \brief Set an existing buffer from a c-string
163 * \param ptr c-string to put into
164 * \param nChars set to -1 if we should work 0-terminated
165 * \returns the new length of the string
167 int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
169 size_t Siz = Buf->BufSize;
173 CopySize = strlen(ptr);
177 while (Siz <= CopySize)
180 if (Siz != Buf->BufSize)
181 IncreaseBuf(Buf, 0, Siz);
182 memcpy(Buf->buf, ptr, CopySize);
183 Buf->buf[CopySize] = '\0';
184 Buf->BufUsed = CopySize;
191 * \brief use strbuf as wrapper for a string constant for easy handling
192 * \param StringConstant a string to wrap
193 * \param SizeOfConstant should be sizeof(StringConstant)-1
195 StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
199 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
200 NewBuf->buf = (char*) StringConstant;
201 NewBuf->BufSize = SizeOfStrConstant;
202 NewBuf->BufUsed = SizeOfStrConstant;
203 NewBuf->ConstBuf = 1;
209 * \brief flush the content of a Buf; keep its struct
210 * \param buf Buffer to flush
212 int FlushStrBuf(StrBuf *buf)
222 * \brief Release a Buffer
223 * Its a double pointer, so it can NULL your pointer
224 * so fancy SIG11 appear instead of random results
225 * \param FreeMe Pointer Pointer to the buffer to free
227 void FreeStrBuf (StrBuf **FreeMe)
231 if (!(*FreeMe)->ConstBuf)
232 free((*FreeMe)->buf);
238 * \brief Release the buffer
239 * If you want put your StrBuf into a Hash, use this as Destructor.
240 * \param VFreeMe untyped pointer to a StrBuf. be shure to do the right thing [TM]
242 void HFreeStrBuf (void *VFreeMe)
244 StrBuf *FreeMe = (StrBuf*)VFreeMe;
247 if (!FreeMe->ConstBuf)
253 * \brief Wrapper around atol
255 long StrTol(const StrBuf *Buf)
258 return atol(Buf->buf);
264 * \brief Wrapper around atoi
266 int StrToi(const StrBuf *Buf)
269 return atoi(Buf->buf);
275 * \brief modifies a Single char of the Buf
276 * You can point to it via char* or a zero-based integer
277 * \param ptr char* to zero; use NULL if unused
278 * \param nThChar zero based pointer into the string; use -1 if unused
279 * \param PeekValue The Character to place into the position
281 long StrBufPeek(StrBuf *Buf, const char* ptr, long nThChar, char PeekValue)
286 nThChar = ptr - Buf->buf;
287 if ((nThChar < 0) || (nThChar > Buf->BufUsed))
289 Buf->buf[nThChar] = PeekValue;
294 * \brief Append a StringBuffer to the buffer
295 * \param Buf Buffer to modify
296 * \param AppendBuf Buffer to copy at the end of our buffer
297 * \param Offset Should we start copying from an offset?
299 void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, size_t Offset)
301 if ((AppendBuf == NULL) || (Buf == NULL))
304 if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed)
307 AppendBuf->BufUsed + Buf->BufUsed);
309 memcpy(Buf->buf + Buf->BufUsed,
310 AppendBuf->buf + Offset,
311 AppendBuf->BufUsed - Offset);
312 Buf->BufUsed += AppendBuf->BufUsed - Offset;
313 Buf->buf[Buf->BufUsed] = '\0';
318 * \brief Append a C-String to the buffer
319 * \param Buf Buffer to modify
320 * \param AppendBuf Buffer to copy at the end of our buffer
321 * \param AppendSize number of bytes to copy; set to -1 if we should count it in advance
322 * \param Offset Should we start copying from an offset?
324 void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, size_t Offset)
328 if ((AppendBuf == NULL) || (Buf == NULL))
332 aps = strlen(AppendBuf + Offset);
334 aps = AppendSize - Offset;
336 if (Buf->BufSize < Buf->BufUsed + aps)
337 IncreaseBuf(Buf, (Buf->BufUsed > 0), Buf->BufUsed + aps);
339 memcpy(Buf->buf + Buf->BufUsed,
343 Buf->buf[Buf->BufUsed] = '\0';
348 * \brief Escape a string for feeding out as a URL while appending it to a Buffer
349 * \param outbuf the output buffer
350 * \param oblen the size of outbuf to sanitize
351 * \param strbuf the input buffer
353 void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
355 const char *pch, *pche;
358 const char ec[] = " +#&;`'|*?-~<>^()[]{}/$\"\\";
359 int eclen = sizeof(ec) -1;
361 if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
363 if (PlainIn != NULL) {
364 len = strlen(PlainIn);
370 pche = pch + In->BufUsed;
377 pt = OutBuf->buf + OutBuf->BufUsed;
378 pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
382 IncreaseBuf(OutBuf, 1, -1);
383 pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
384 pt = OutBuf->buf + OutBuf->BufUsed;
388 for (b = 0; b < eclen; ++b) {
395 sprintf(pt,"%%%02X", *pch);
397 OutBuf->BufUsed += 3;
409 * \brief Append a string, escaping characters which have meaning in HTML.
411 * \param Target target buffer
412 * \param Source source buffer; set to NULL if you just have a C-String
413 * \param PlainIn Plain-C string to append; set to NULL if unused
414 * \param nbsp If nonzero, spaces are converted to non-breaking spaces.
415 * \param nolinebreaks if set, linebreaks are removed from the string.
417 long StrEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
419 const char *aptr, *eiptr;
423 if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
426 if (PlainIn != NULL) {
428 len = strlen(PlainIn);
433 eiptr = aptr + Source->BufUsed;
434 len = Source->BufUsed;
440 bptr = Target->buf + Target->BufUsed;
441 eptr = Target->buf + Target->BufSize - 6; /* our biggest unit to put in... */
443 while (aptr < eiptr){
445 IncreaseBuf(Target, 1, -1);
446 eptr = Target->buf + Target->BufSize - 6;
447 bptr = Target->buf + Target->BufUsed;
450 memcpy(bptr, "<", 4);
452 Target->BufUsed += 4;
454 else if (*aptr == '>') {
455 memcpy(bptr, ">", 4);
457 Target->BufUsed += 4;
459 else if (*aptr == '&') {
460 memcpy(bptr, "&", 5);
462 Target->BufUsed += 5;
464 else if (*aptr == '\"') {
465 memcpy(bptr, """, 6);
467 Target->BufUsed += 6;
469 else if (*aptr == '\'') {
470 memcpy(bptr, "'", 5);
472 Target->BufUsed += 5;
474 else if (*aptr == LB) {
479 else if (*aptr == RB) {
484 else if (*aptr == QU) {
489 else if ((*aptr == 32) && (nbsp == 1)) {
490 memcpy(bptr, " ", 6);
492 Target->BufUsed += 6;
494 else if ((*aptr == '\n') && (nolinebreaks)) {
495 *bptr='\0'; /* nothing */
497 else if ((*aptr == '\r') && (nolinebreaks)) {
498 *bptr='\0'; /* nothing */
508 if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
510 return Target->BufUsed;
514 * \brief Append a string, escaping characters which have meaning in HTML.
515 * Converts linebreaks into blanks; escapes single quotes
516 * \param Target target buffer
517 * \param Source source buffer; set to NULL if you just have a C-String
518 * \param PlainIn Plain-C string to append; set to NULL if unused
520 void StrMsgEscAppend(StrBuf *Target, StrBuf *Source, const char *PlainIn)
522 const char *aptr, *eiptr;
526 if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
529 if (PlainIn != NULL) {
531 len = strlen(PlainIn);
536 eiptr = aptr + Source->BufUsed;
537 len = Source->BufUsed;
543 eptr = Target->buf + Target->BufSize - 6;
544 tptr = Target->buf + Target->BufUsed;
546 while (aptr < eiptr){
548 IncreaseBuf(Target, 1, -1);
549 eptr = Target->buf + Target->BufSize - 6;
550 tptr = Target->buf + Target->BufUsed;
557 else if (*aptr == '\r') {
561 else if (*aptr == '\'') {
567 Target->BufUsed += 5;
579 * \brief extracts a substring from Source into dest
580 * \param dest buffer to place substring into
581 * \param Source string to copy substring from
582 * \param Offset chars to skip from start
583 * \param nChars number of chars to copy
584 * \returns the number of chars copied; may be different from nChars due to the size of Source
586 int StrBufSub(StrBuf *dest, const StrBuf *Source, size_t Offset, size_t nChars)
589 if (Offset > Source->BufUsed)
594 if (Offset + nChars < Source->BufUsed)
596 if (nChars > dest->BufSize)
597 IncreaseBuf(dest, 0, nChars + 1);
598 memcpy(dest->buf, Source->buf + Offset, nChars);
599 dest->BufUsed = nChars;
600 dest->buf[dest->BufUsed] = '\0';
603 NCharsRemain = Source->BufUsed - Offset;
604 if (NCharsRemain > dest->BufSize)
605 IncreaseBuf(dest, 0, NCharsRemain + 1);
606 memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
607 dest->BufUsed = NCharsRemain;
608 dest->buf[dest->BufUsed] = '\0';
613 * \brief sprintf like function appending the formated string to the buffer
614 * vsnprintf version to wrap into own calls
615 * \param Buf Buffer to extend by format and params
616 * \param format printf alike format to add
617 * \param ap va_list containing the items for format
619 void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
622 size_t BufSize = Buf->BufSize;
623 size_t nWritten = Buf->BufSize + 1;
624 size_t Offset = Buf->BufUsed;
625 size_t newused = Offset + nWritten;
627 while (newused >= BufSize) {
629 nWritten = vsnprintf(Buf->buf + Offset,
630 Buf->BufSize - Offset,
633 newused = Offset + nWritten;
634 if (newused >= Buf->BufSize) {
635 IncreaseBuf(Buf, 1, newused);
638 Buf->BufUsed = Offset + nWritten;
639 BufSize = Buf->BufSize;
646 * \brief sprintf like function appending the formated string to the buffer
647 * \param Buf Buffer to extend by format and params
648 * \param format printf alike format to add
649 * \param ap va_list containing the items for format
651 void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
653 size_t BufSize = Buf->BufSize;
654 size_t nWritten = Buf->BufSize + 1;
655 size_t Offset = Buf->BufUsed;
656 size_t newused = Offset + nWritten;
659 while (newused >= BufSize) {
660 va_start(arg_ptr, format);
661 nWritten = vsnprintf(Buf->buf + Buf->BufUsed,
662 Buf->BufSize - Buf->BufUsed,
665 newused = Buf->BufUsed + nWritten;
666 if (newused >= Buf->BufSize) {
667 IncreaseBuf(Buf, 1, newused);
670 Buf->BufUsed += nWritten;
671 BufSize = Buf->BufSize;
678 * \brief sprintf like function putting the formated string into the buffer
679 * \param Buf Buffer to extend by format and params
680 * \param format printf alike format to add
681 * \param ap va_list containing the items for format
683 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
685 size_t nWritten = Buf->BufSize + 1;
688 while (nWritten >= Buf->BufSize) {
689 va_start(arg_ptr, format);
690 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
692 Buf->BufUsed = nWritten ;
693 if (nWritten >= Buf->BufSize)
694 IncreaseBuf(Buf, 0, 0);
700 * \brief Counts the numbmer of tokens in a buffer
701 * \param Source String to count tokens in
702 * \param tok Tokenizer char to count
703 * \returns numbers of tokenizer chars found
705 inline int StrBufNum_tokens(const StrBuf *source, char tok)
709 return num_tokens(source->buf, tok);
713 * remove_token() - a tokenizer that kills, maims, and destroys
716 * \brief a string tokenizer
717 * \param Source StringBuffer to read into
718 * \param parmnum n'th parameter to remove
719 * \param separator tokenizer param
720 * \returns -1 if not found, else length of token.
722 int StrBufRemove_token(StrBuf *Source, int parmnum, char separator)
725 char *d, *s; /* dest, source */
728 /* Find desired parameter */
730 while (count < parmnum) {
731 /* End of string, bail! */
736 if (*d == separator) {
741 if (!d) return 0; /* Parameter not found */
743 /* Find next parameter */
745 while (*s && *s != separator) {
753 memmove(d, s, Source->BufUsed - (s - Source->buf));
754 Source->BufUsed -= (ReducedBy + 1);
756 else if (d == Source->buf) {
762 Source->BufUsed -= (ReducedBy + 1);
775 * \brief a string tokenizer
776 * \param dest Destination StringBuffer
777 * \param Source StringBuffer to read into
778 * \param parmnum n'th parameter to extract
779 * \param separator tokenizer param
780 * \returns -1 if not found, else length of token.
782 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
784 const char *s, *e; //* source * /
785 int len = 0; //* running total length of extracted string * /
786 int current_token = 0; //* token currently being processed * /
788 if ((Source == NULL) || (Source->BufUsed ==0)) {
792 e = s + Source->BufUsed;
798 //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
802 while ((s<e) && !IsEmptyStr(s)) {
803 if (*s == separator) {
806 if (len >= dest->BufSize)
807 if (!IncreaseBuf(dest, 1, -1))
809 if ( (current_token == parmnum) &&
814 else if (current_token > parmnum) {
820 dest->buf[len] = '\0';
823 if (current_token < parmnum) {
824 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
827 //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
833 * \brief a string tokenizer to fetch an integer
834 * \param dest Destination StringBuffer
835 * \param parmnum n'th parameter to extract
836 * \param separator tokenizer param
837 * \returns 0 if not found, else integer representation of the token
839 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
848 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
855 * \brief a string tokenizer to fetch a long integer
856 * \param dest Destination StringBuffer
857 * \param parmnum n'th parameter to extract
858 * \param separator tokenizer param
859 * \returns 0 if not found, else long integer representation of the token
861 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
870 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
878 * \brief a string tokenizer to fetch an unsigned long
879 * \param dest Destination StringBuffer
880 * \param parmnum n'th parameter to extract
881 * \param separator tokenizer param
882 * \returns 0 if not found, else unsigned long representation of the token
884 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
894 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0) {
898 return (unsigned long) atol(pnum);
907 * \brief Read a line from socket
908 * flushes and closes the FD on error
909 * \param buf the buffer to get the input to
910 * \param fd pointer to the filedescriptor to read
911 * \param append Append to an existing string or replace?
912 * \param Error strerror() on error
913 * \returns numbers of chars read
915 int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
922 slen = len = buf->BufUsed;
924 rlen = read(*fd, &buf->buf[len], 1);
926 *Error = strerror(errno);
933 if (buf->buf[len] == '\n')
935 if (buf->buf[len] != '\r')
937 if (!(len < buf->BufSize)) {
939 buf->buf[len+1] = '\0';
940 IncreaseBuf(buf, 1, -1);
944 buf->buf[len] = '\0';
949 * \brief Read a line from socket
950 * flushes and closes the FD on error
951 * \param buf the buffer to get the input to
952 * \param fd pointer to the filedescriptor to read
953 * \param append Append to an existing string or replace?
954 * \param Error strerror() on error
955 * \returns numbers of chars read
957 int StrBufTCP_read_buffered_line(StrBuf *Line,
961 int selectresolution,
965 int nSuccessLess = 0;
971 if (buf->BufUsed > 0) {
972 pch = strchr(buf->buf, '\n');
975 len = pch - buf->buf;
976 if (len > 0 && (*(pch - 1) == '\r') )
978 StrBufSub(Line, buf, 0, len - rlen);
979 StrBufCutLeft(buf, len + 1);
984 if (buf->BufSize - buf->BufUsed < 10)
985 IncreaseBuf(buf, 1, -1);
987 fdflags = fcntl(*fd, F_GETFL);
988 if ((fdflags & O_NONBLOCK) == O_NONBLOCK)
991 while ((nSuccessLess < timeout) && (pch == NULL)) {
992 tv.tv_sec = selectresolution;
997 if (select(*fd + 1, NULL, &rfds, NULL, &tv) == -1) {
998 *Error = strerror(errno);
1003 if (FD_ISSET(*fd, &rfds)) {
1005 &buf->buf[buf->BufUsed],
1006 buf->BufSize - buf->BufUsed - 1);
1008 *Error = strerror(errno);
1013 else if (rlen > 0) {
1015 buf->BufUsed += rlen;
1016 buf->buf[buf->BufUsed] = '\0';
1017 if (buf->BufUsed + 10 > buf->BufSize) {
1018 IncreaseBuf(buf, 1, -1);
1020 pch = strchr(buf->buf, '\n');
1028 len = pch - buf->buf;
1029 if (len > 0 && (*(pch - 1) == '\r') )
1031 StrBufSub(Line, buf, 0, len - rlen);
1032 StrBufCutLeft(buf, len + 1);
1040 * \brief Input binary data from socket
1041 * flushes and closes the FD on error
1042 * \param buf the buffer to get the input to
1043 * \param fd pointer to the filedescriptor to read
1044 * \param append Append to an existing string or replace?
1045 * \param nBytes the maximal number of bytes to read
1046 * \param Error strerror() on error
1047 * \returns numbers of chars read
1049 int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error)
1053 int len, rlen, slen;
1057 if ((Buf == NULL) || (*fd == -1))
1061 if (Buf->BufUsed + nBytes > Buf->BufSize)
1062 IncreaseBuf(Buf, 1, Buf->BufUsed + nBytes);
1064 ptr = Buf->buf + Buf->BufUsed;
1066 slen = len = Buf->BufUsed;
1068 fdflags = fcntl(*fd, F_GETFL);
1070 while (nRead < nBytes) {
1071 if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
1074 if (select(*fd + 1, NULL, &wset, NULL, NULL) == -1) {
1075 *Error = strerror(errno);
1080 if ((rlen = read(*fd,
1082 nBytes - nRead)) == -1) {
1085 *Error = strerror(errno);
1090 Buf->BufUsed += rlen;
1092 Buf->buf[Buf->BufUsed] = '\0';
1097 * \brief Cut nChars from the start of the string
1098 * \param Buf Buffer to modify
1099 * \param nChars how many chars should be skipped?
1101 void StrBufCutLeft(StrBuf *Buf, int nChars)
1103 if (nChars >= Buf->BufUsed) {
1107 memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
1108 Buf->BufUsed -= nChars;
1109 Buf->buf[Buf->BufUsed] = '\0';
1113 * \brief Cut the trailing n Chars from the string
1114 * \param Buf Buffer to modify
1115 * \param nChars how many chars should be trunkated?
1117 void StrBufCutRight(StrBuf *Buf, int nChars)
1119 if (nChars >= Buf->BufUsed) {
1123 Buf->BufUsed -= nChars;
1124 Buf->buf[Buf->BufUsed] = '\0';
1128 void StrBufUpCase(StrBuf *Buf)
1133 pche = pch + Buf->BufUsed;
1134 while (pch < pche) {
1135 *pch = toupper(*pch);
1142 * \brief unhide special chars hidden to the HTML escaper
1143 * \param target buffer to put the unescaped string in
1144 * \param source buffer to unescape
1146 void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source)
1152 FlushStrBuf(target);
1154 if (source == NULL ||target == NULL)
1159 len = source->BufUsed;
1160 for (a = 0; a < len; ++a) {
1161 if (target->BufUsed >= target->BufSize)
1162 IncreaseBuf(target, 1, -1);
1164 if (source->buf[a] == '=') {
1165 hex[0] = source->buf[a + 1];
1166 hex[1] = source->buf[a + 2];
1169 sscanf(hex, "%02x", &b);
1170 target->buf[target->BufUsed] = b;
1171 target->buf[++target->BufUsed] = 0;
1175 target->buf[target->BufUsed] = source->buf[a];
1176 target->buf[++target->BufUsed] = 0;
1183 * \brief hide special chars from the HTML escapers and friends
1184 * \param target buffer to put the escaped string in
1185 * \param source buffer to escape
1187 void StrBufEUid_escapize(StrBuf *target, const StrBuf *source)
1192 FlushStrBuf(target);
1194 if (source == NULL ||target == NULL)
1199 len = source->BufUsed;
1200 for (i=0; i<len; ++i) {
1201 if (target->BufUsed + 4 >= target->BufSize)
1202 IncreaseBuf(target, 1, -1);
1203 if ( (isalnum(source->buf[i])) ||
1204 (source->buf[i]=='-') ||
1205 (source->buf[i]=='_') ) {
1206 target->buf[target->BufUsed++] = source->buf[i];
1209 sprintf(&target->buf[target->BufUsed],
1211 (0xFF &source->buf[i]));
1212 target->BufUsed += 3;
1215 target->buf[target->BufUsed + 1] = '\0';
1219 * \brief uses the same calling syntax as compress2(), but it
1220 * creates a stream compatible with HTTP "Content-encoding: gzip"
1223 #define DEF_MEM_LEVEL 8 /*< memlevel??? */
1224 #define OS_CODE 0x03 /*< unix */
1225 int ZEXPORT compress_gzip(Bytef * dest, /*< compressed buffer*/
1226 size_t * destLen, /*< length of the compresed data */
1227 const Bytef * source, /*< source to encode */
1228 uLong sourceLen, /*< length of source to encode */
1229 int level) /*< compression level */
1231 const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
1233 /* write gzip header */
1234 snprintf((char *) dest, *destLen,
1235 "%c%c%c%c%c%c%c%c%c%c",
1236 gz_magic[0], gz_magic[1], Z_DEFLATED,
1237 0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
1240 /* normal deflate */
1243 stream.next_in = (Bytef *) source;
1244 stream.avail_in = (uInt) sourceLen;
1245 stream.next_out = dest + 10L; // after header
1246 stream.avail_out = (uInt) * destLen;
1247 if ((uLong) stream.avail_out != *destLen)
1250 stream.zalloc = (alloc_func) 0;
1251 stream.zfree = (free_func) 0;
1252 stream.opaque = (voidpf) 0;
1254 err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS,
1255 DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
1259 err = deflate(&stream, Z_FINISH);
1260 if (err != Z_STREAM_END) {
1261 deflateEnd(&stream);
1262 return err == Z_OK ? Z_BUF_ERROR : err;
1264 *destLen = stream.total_out + 10L;
1266 /* write CRC and Length */
1267 uLong crc = crc32(0L, source, sourceLen);
1269 for (n = 0; n < 4; ++n, ++*destLen) {
1270 dest[*destLen] = (int) (crc & 0xff);
1273 uLong len = stream.total_in;
1274 for (n = 0; n < 4; ++n, ++*destLen) {
1275 dest[*destLen] = (int) (len & 0xff);
1278 err = deflateEnd(&stream);
1285 * Attention! If you feed this a Const String, you must maintain the uncompressed buffer yourself!
1287 int CompressBuffer(StrBuf *Buf)
1290 char *compressed_data = NULL;
1291 size_t compressed_len, bufsize;
1293 bufsize = compressed_len = ((Buf->BufUsed * 101) / 100) + 100;
1294 compressed_data = malloc(compressed_len);
1296 if (compress_gzip((Bytef *) compressed_data,
1299 (uLongf) Buf->BufUsed, Z_BEST_SPEED) == Z_OK) {
1302 Buf->buf = compressed_data;
1303 Buf->BufUsed = compressed_len;
1304 Buf->BufSize = bufsize;
1307 free(compressed_data);
1309 #endif /* HAVE_ZLIB */
1314 * \brief decode a buffer from base 64 encoding; destroys original
1315 * \param Buf Buffor to transform
1317 int StrBufDecodeBase64(StrBuf *Buf)
1321 if (Buf == NULL) return -1;
1323 xferbuf = (char*) malloc(Buf->BufSize);
1324 siz = CtdlDecodeBase64(xferbuf,
1335 * \brief remove escaped strings from i.e. the url string (like %20 for blanks)
1336 * \param Buf Buffer to translate
1337 * \param StripBlanks Reduce several blanks to one?
1339 long StrBufUnescape(StrBuf *Buf, int StripBlanks)
1345 while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
1346 Buf->buf[Buf->BufUsed - 1] = '\0';
1351 while (a < Buf->BufUsed) {
1352 if (Buf->buf[a] == '+')
1354 else if (Buf->buf[a] == '%') {
1355 /* don't let % chars through, rather truncate the input. */
1356 if (a + 2 > Buf->BufUsed) {
1361 hex[0] = Buf->buf[a + 1];
1362 hex[1] = Buf->buf[a + 2];
1365 sscanf(hex, "%02x", &b);
1366 Buf->buf[a] = (char) b;
1367 len = Buf->BufUsed - a - 2;
1369 memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
1381 * \brief RFC2047-encode a header field if necessary.
1382 * If no non-ASCII characters are found, the string
1383 * will be copied verbatim without encoding.
1385 * \param target Target buffer.
1386 * \param source Source string to be encoded.
1387 * \returns encoded length; -1 if non success.
1389 int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
1391 const char headerStr[] = "=?UTF-8?Q?";
1392 int need_to_encode = 0;
1396 if ((source == NULL) ||
1400 while ((i < source->BufUsed) &&
1401 (!IsEmptyStr (&source->buf[i])) &&
1402 (need_to_encode == 0)) {
1403 if (((unsigned char) source->buf[i] < 32) ||
1404 ((unsigned char) source->buf[i] > 126)) {
1410 if (!need_to_encode) {
1411 if (*target == NULL) {
1412 *target = NewStrBufPlain(source->buf, source->BufUsed);
1415 FlushStrBuf(*target);
1416 StrBufAppendBuf(*target, source, 0);
1418 return (*target)->BufUsed;
1420 if (*target == NULL)
1421 *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
1422 else if (sizeof(headerStr) + source->BufUsed > (*target)->BufSize)
1423 IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
1424 memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
1425 (*target)->BufUsed = sizeof(headerStr) - 1;
1426 for (i=0; (i < source->BufUsed); ++i) {
1427 if ((*target)->BufUsed + 4 > (*target)->BufSize)
1428 IncreaseBuf(*target, 1, 0);
1429 ch = (unsigned char) source->buf[i];
1430 if ((ch < 32) || (ch > 126) || (ch == 61)) {
1431 sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
1432 (*target)->BufUsed += 3;
1435 (*target)->buf[(*target)->BufUsed] = ch;
1436 (*target)->BufUsed++;
1440 if ((*target)->BufUsed + 4 > (*target)->BufSize)
1441 IncreaseBuf(*target, 1, 0);
1443 (*target)->buf[(*target)->BufUsed++] = '?';
1444 (*target)->buf[(*target)->BufUsed++] = '=';
1445 (*target)->buf[(*target)->BufUsed] = '\0';
1446 return (*target)->BufUsed;;
1450 * \brief replaces all occurances of 'search' by 'replace'
1451 * \param buf Buffer to modify
1452 * \param search character to search
1453 * \param relpace character to replace search by
1455 void StrBufReplaceChars(StrBuf *buf, char search, char replace)
1460 for (i=0; i<buf->BufUsed; i++)
1461 if (buf->buf[i] == search)
1462 buf->buf[i] = replace;