7 #include <sys/select.h>
9 #define SHOW_ME_VAPPEND_PRINTF
11 #include "libcitadel.h"
22 inline const char *ChrPtr(const StrBuf *Str)
29 inline int StrLength(const StrBuf *Str)
31 return (Str != NULL) ? Str->BufUsed : 0;
34 StrBuf* NewStrBuf(void)
38 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
39 NewBuf->buf = (char*) malloc(SIZ);
40 NewBuf->buf[0] = '\0';
41 NewBuf->BufSize = SIZ;
47 StrBuf* NewStrBufDup(const StrBuf *CopyMe)
54 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
55 NewBuf->buf = (char*) malloc(CopyMe->BufSize);
56 memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
57 NewBuf->BufUsed = CopyMe->BufUsed;
58 NewBuf->BufSize = CopyMe->BufSize;
62 StrBuf* NewStrBufPlain(const char* ptr, int nChars)
68 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
70 CopySize = strlen((ptr != NULL)?ptr:"");
74 while (Siz <= CopySize)
77 NewBuf->buf = (char*) malloc(Siz);
78 NewBuf->BufSize = Siz;
80 memcpy(NewBuf->buf, ptr, CopySize);
81 NewBuf->buf[CopySize] = '\0';
82 NewBuf->BufUsed = CopySize;
85 NewBuf->buf[0] = '\0';
93 StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
97 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
98 NewBuf->buf = (char*) StringConstant;
99 NewBuf->BufSize = SizeOfStrConstant;
100 NewBuf->BufUsed = SizeOfStrConstant;
101 NewBuf->ConstBuf = 1;
106 static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
109 size_t NewSize = Buf->BufSize * 2;
115 while (NewSize < DestSize)
118 NewBuf= (char*) malloc(NewSize);
121 memcpy(NewBuf, Buf->buf, Buf->BufUsed);
134 int FlushStrBuf(StrBuf *buf)
143 void FreeStrBuf (StrBuf **FreeMe)
147 if (!(*FreeMe)->ConstBuf)
148 free((*FreeMe)->buf);
153 void HFreeStrBuf (void *VFreeMe)
155 StrBuf *FreeMe = (StrBuf*)VFreeMe;
158 if (!FreeMe->ConstBuf)
163 long StrTol(const StrBuf *Buf)
166 return atol(Buf->buf);
171 int StrToi(const StrBuf *Buf)
174 return atoi(Buf->buf);
179 int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
181 size_t Siz = Buf->BufSize;
185 CopySize = strlen(ptr);
189 while (Siz <= CopySize)
192 if (Siz != Buf->BufSize)
193 IncreaseBuf(Buf, 0, Siz);
194 memcpy(Buf->buf, ptr, CopySize);
195 Buf->buf[CopySize] = '\0';
196 Buf->BufUsed = CopySize;
201 void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, size_t Offset)
203 if ((AppendBuf == NULL) || (Buf == NULL))
206 if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed)
209 AppendBuf->BufUsed + Buf->BufUsed);
211 memcpy(Buf->buf + Buf->BufUsed,
212 AppendBuf->buf + Offset,
213 AppendBuf->BufUsed - Offset);
214 Buf->BufUsed += AppendBuf->BufUsed - Offset;
215 Buf->buf[Buf->BufUsed] = '\0';
219 void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, size_t Offset)
223 if ((AppendBuf == NULL) || (Buf == NULL))
227 aps = strlen(AppendBuf + Offset);
229 aps = AppendSize - Offset;
231 if (Buf->BufSize < Buf->BufUsed + aps)
232 IncreaseBuf(Buf, (Buf->BufUsed > 0), Buf->BufUsed + aps);
234 memcpy(Buf->buf + Buf->BufUsed,
238 Buf->buf[Buf->BufUsed] = '\0';
242 inline int StrBufNum_tokens(const StrBuf *source, char tok)
244 return num_tokens(source->buf, tok);
248 int StrBufSub(StrBuf *dest, const StrBuf *Source, size_t Offset, size_t nChars)
251 if (Offset > Source->BufUsed)
256 if (Offset + nChars < Source->BufUsed)
258 if (nChars > dest->BufSize)
259 IncreaseBuf(dest, 0, nChars + 1);
260 memcpy(dest->buf, Source->buf + Offset, nChars);
261 dest->BufUsed = nChars;
262 dest->buf[dest->BufUsed] = '\0';
265 NCharsRemain = Source->BufUsed - Offset;
266 if (NCharsRemain > dest->BufSize)
267 IncreaseBuf(dest, 0, NCharsRemain + 1);
268 memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
269 dest->BufUsed = NCharsRemain;
270 dest->buf[dest->BufUsed] = '\0';
275 void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
277 size_t nWritten = Buf->BufSize + 1;
278 size_t Offset = Buf->BufUsed;
279 size_t newused = Offset + nWritten;
281 while (newused >= Buf->BufSize) {
282 nWritten = vsnprintf(Buf->buf + Offset,
283 Buf->BufSize - Offset,
285 newused = Offset + nWritten;
286 if (newused >= Buf->BufSize)
287 IncreaseBuf(Buf, 1, 0);
289 Buf->BufUsed = Offset + nWritten ;
294 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
296 size_t nWritten = Buf->BufSize + 1;
299 while (nWritten >= Buf->BufSize) {
300 va_start(arg_ptr, format);
301 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
303 Buf->BufUsed = nWritten ;
304 if (nWritten >= Buf->BufSize)
305 IncreaseBuf(Buf, 0, 0);
311 * \brief a string tokenizer
312 * \param dest Destination StringBuffer
313 * \param Source StringBuffer to read into
314 * \param separator tokenizer param
315 * \returns -1 if not found, else length of token.
317 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
319 const char *s, *e; //* source * /
320 int len = 0; //* running total length of extracted string * /
321 int current_token = 0; //* token currently being processed * /
323 if ((Source == NULL) || (Source->BufUsed ==0)) {
327 e = s + Source->BufUsed;
333 //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
337 while ((s<e) && !IsEmptyStr(s)) {
338 if (*s == separator) {
341 if (len >= dest->BufSize)
342 if (!IncreaseBuf(dest, 1, -1))
344 if ( (current_token == parmnum) &&
349 else if (current_token > parmnum) {
355 dest->buf[len] = '\0';
358 if (current_token < parmnum) {
359 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
362 //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
368 * extract_int() - extract an int parm w/o supplying a buffer
370 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
379 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
386 * extract_long() - extract an long parm w/o supplying a buffer
388 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
397 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
405 * extract_unsigned_long() - extract an unsigned long parm
407 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
416 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
425 * \brief Input binary data from socket
426 * \param buf the buffer to get the input to
427 * \param bytes the maximal number of bytes to read
429 int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
436 slen = len = buf->BufUsed;
438 rlen = read(*fd, &buf->buf[len], 1);
440 *Error = strerror(errno);
447 if (buf->buf[len] == '\n')
449 if (buf->buf[len] != '\r')
451 if (!(len < buf->BufSize)) {
453 buf->buf[len+1] = '\0';
454 IncreaseBuf(buf, 1, -1);
458 buf->buf[len] = '\0';
463 * \brief Input binary data from socket
464 * \param buf the buffer to get the input to
465 * \param bytes the maximal number of bytes to read
467 int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error)
475 if ((Buf == NULL) || (*fd == -1))
479 if (Buf->BufUsed + nBytes > Buf->BufSize)
480 IncreaseBuf(Buf, 1, Buf->BufUsed + nBytes);
482 ptr = Buf->buf + Buf->BufUsed;
484 slen = len = Buf->BufUsed;
486 fdflags = fcntl(*fd, F_GETFL);
488 while (nRead < nBytes) {
489 if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
492 if (select(*fd + 1, NULL, &wset, NULL, NULL) == -1) {
493 *Error = strerror(errno);
498 if ((rlen = read(*fd,
500 nBytes - nRead)) == -1) {
503 *Error = strerror(errno);
507 Buf->BufUsed += rlen;
509 Buf->buf[Buf->BufUsed] = '\0';
513 void StrBufCutLeft(StrBuf *Buf, int nChars)
515 if (nChars >= Buf->BufUsed) {
519 memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
520 Buf->BufUsed -= nChars;
521 Buf->buf[Buf->BufUsed] = '\0';
524 void StrBufCutRight(StrBuf *Buf, int nChars)
526 if (nChars >= Buf->BufUsed) {
530 Buf->BufUsed -= nChars;
531 Buf->buf[Buf->BufUsed] = '\0';
536 * string conversion function
538 void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source)
546 if (source == NULL ||target == NULL)
551 len = source->BufUsed;
552 for (a = 0; a < len; ++a) {
553 if (target->BufUsed >= target->BufSize)
554 IncreaseBuf(target, 1, -1);
556 if (source->buf[a] == '=') {
557 hex[0] = source->buf[a + 1];
558 hex[1] = source->buf[a + 2];
561 sscanf(hex, "%02x", &b);
562 target->buf[target->BufUsed] = b;
563 target->buf[++target->BufUsed] = 0;
567 target->buf[target->BufUsed] = source->buf[a];
568 target->buf[++target->BufUsed] = 0;
575 * string conversion function
577 void StrBufEUid_escapize(StrBuf *target, const StrBuf *source)
584 if (source == NULL ||target == NULL)
589 len = source->BufUsed;
590 for (i=0; i<len; ++i) {
591 if (target->BufUsed + 4 >= target->BufSize)
592 IncreaseBuf(target, 1, -1);
593 if ( (isalnum(source->buf[i])) ||
594 (source->buf[i]=='-') ||
595 (source->buf[i]=='_') ) {
596 target->buf[target->BufUsed++] = source->buf[i];
599 sprintf(&target->buf[target->BufUsed],
601 (0xFF &source->buf[i]));
602 target->BufUsed += 3;
605 target->buf[target->BufUsed + 1] = '\0';
609 * \brief uses the same calling syntax as compress2(), but it
610 * creates a stream compatible with HTTP "Content-encoding: gzip"
613 #define DEF_MEM_LEVEL 8 /*< memlevel??? */
614 #define OS_CODE 0x03 /*< unix */
615 int ZEXPORT compress_gzip(Bytef * dest, /*< compressed buffer*/
616 size_t * destLen, /*< length of the compresed data */
617 const Bytef * source, /*< source to encode */
618 uLong sourceLen, /*< length of source to encode */
619 int level) /*< compression level */
621 const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
623 /* write gzip header */
624 snprintf((char *) dest, *destLen,
625 "%c%c%c%c%c%c%c%c%c%c",
626 gz_magic[0], gz_magic[1], Z_DEFLATED,
627 0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
633 stream.next_in = (Bytef *) source;
634 stream.avail_in = (uInt) sourceLen;
635 stream.next_out = dest + 10L; // after header
636 stream.avail_out = (uInt) * destLen;
637 if ((uLong) stream.avail_out != *destLen)
640 stream.zalloc = (alloc_func) 0;
641 stream.zfree = (free_func) 0;
642 stream.opaque = (voidpf) 0;
644 err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS,
645 DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
649 err = deflate(&stream, Z_FINISH);
650 if (err != Z_STREAM_END) {
652 return err == Z_OK ? Z_BUF_ERROR : err;
654 *destLen = stream.total_out + 10L;
656 /* write CRC and Length */
657 uLong crc = crc32(0L, source, sourceLen);
659 for (n = 0; n < 4; ++n, ++*destLen) {
660 dest[*destLen] = (int) (crc & 0xff);
663 uLong len = stream.total_in;
664 for (n = 0; n < 4; ++n, ++*destLen) {
665 dest[*destLen] = (int) (len & 0xff);
668 err = deflateEnd(&stream);
675 * Attention! If you feed this a Const String, you must maintain the uncompressed buffer yourself!
677 int CompressBuffer(StrBuf *Buf)
680 char *compressed_data = NULL;
681 size_t compressed_len, bufsize;
683 bufsize = compressed_len = ((Buf->BufUsed * 101) / 100) + 100;
684 compressed_data = malloc(compressed_len);
686 if (compress_gzip((Bytef *) compressed_data,
689 (uLongf) Buf->BufUsed, Z_BEST_SPEED) == Z_OK) {
692 Buf->buf = compressed_data;
693 Buf->BufUsed = compressed_len;
694 Buf->BufSize = bufsize;
697 free(compressed_data);
699 #endif /* HAVE_ZLIB */
703 int StrBufDecodeBase64(StrBuf *Buf)
707 if (Buf == NULL) return -1;
709 xferbuf = (char*) malloc(Buf->BufSize);
710 siz = CtdlDecodeBase64(xferbuf,
721 * remove escaped strings from i.e. the url string (like %20 for blanks)
723 long StrBufUnescape(StrBuf *Buf, int StripBlanks)
729 while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
730 Buf->buf[Buf->BufUsed - 1] = '\0';
735 while (a < Buf->BufUsed) {
736 if (Buf->buf[a] == '+')
738 else if (Buf->buf[a] == '%') {
739 /* don't let % chars through, rather truncate the input. */
740 if (a + 2 > Buf->BufUsed) {
745 hex[0] = Buf->buf[a + 1];
746 hex[1] = Buf->buf[a + 2];
749 sscanf(hex, "%02x", &b);
750 Buf->buf[a] = (char) b;
751 len = Buf->BufUsed - a - 2;
753 memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
765 * \brief RFC2047-encode a header field if necessary.
766 * If no non-ASCII characters are found, the string
767 * will be copied verbatim without encoding.
769 * \param target Target buffer.
770 * \param source Source string to be encoded.
771 * \returns encoded length; -1 if non success.
773 int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
775 const char headerStr[] = "=?UTF-8?Q?";
776 int need_to_encode = 0;
780 if ((source == NULL) ||
784 while ((i < source->BufUsed) &&
785 (!IsEmptyStr (&source->buf[i])) &&
786 (need_to_encode == 0)) {
787 if (((unsigned char) source->buf[i] < 32) ||
788 ((unsigned char) source->buf[i] > 126)) {
794 if (!need_to_encode) {
795 if (*target == NULL) {
796 *target = NewStrBufPlain(source->buf, source->BufUsed);
799 FlushStrBuf(*target);
800 StrBufAppendBuf(*target, source, 0);
802 return (*target)->BufUsed;
805 *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
806 else if (sizeof(headerStr) + source->BufUsed > (*target)->BufSize)
807 IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
808 memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
809 (*target)->BufUsed = sizeof(headerStr) - 1;
810 for (i=0; (i < source->BufUsed); ++i) {
811 if ((*target)->BufUsed + 4 > (*target)->BufSize)
812 IncreaseBuf(*target, 1, 0);
813 ch = (unsigned char) source->buf[i];
814 if ((ch < 32) || (ch > 126) || (ch == 61)) {
815 sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
816 (*target)->BufUsed += 3;
819 (*target)->buf[(*target)->BufUsed] = ch;
820 (*target)->BufUsed++;
824 if ((*target)->BufUsed + 4 > (*target)->BufSize)
825 IncreaseBuf(*target, 1, 0);
827 (*target)->buf[(*target)->BufUsed++] = '?';
828 (*target)->buf[(*target)->BufUsed++] = '=';
829 (*target)->buf[(*target)->BufUsed] = '\0';
830 return (*target)->BufUsed;;
833 void StrBufReplaceChars(StrBuf *buf, char search, char replace)
838 for (i=0; i<buf->BufUsed; i++)
839 if (buf->buf[i] == search)
840 buf->buf[i] = replace;