Branch data Line data Source code
1 : : #include "sysdep.h"
2 : : #include <ctype.h>
3 : : #include <errno.h>
4 : : #include <string.h>
5 : : #include <unistd.h>
6 : : #include <string.h>
7 : : #include <stdio.h>
8 : : #include <sys/select.h>
9 : : #include <fcntl.h>
10 : : #include <sys/types.h>
11 : : #define SHOW_ME_VAPPEND_PRINTF
12 : : #include <stdarg.h>
13 : : #include "libcitadel.h"
14 : :
15 : : #ifdef HAVE_ICONV
16 : : #include <iconv.h>
17 : : #endif
18 : :
19 : : #ifdef HAVE_BACKTRACE
20 : : #include <execinfo.h>
21 : : #endif
22 : :
23 : : #ifdef HAVE_ZLIB
24 : : #include <zlib.h>
25 : : int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen,
26 : : const Bytef * source, uLong sourceLen, int level);
27 : : #endif
28 : : int BaseStrBufSize = 64;
29 : :
30 : : const char *StrBufNOTNULL = ((char*) NULL) - 1;
31 : :
32 : : const char HexList[256][3] = {
33 : : "00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F",
34 : : "10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F",
35 : : "20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F",
36 : : "30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F",
37 : : "40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F",
38 : : "50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F",
39 : : "60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F",
40 : : "70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F",
41 : : "80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F",
42 : : "90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F",
43 : : "A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF",
44 : : "B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF",
45 : : "C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF",
46 : : "D0","D1","D2","D3","D4","D5","D6","D7","D8","D9","DA","DB","DC","DD","DE","DF",
47 : : "E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF",
48 : : "F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF"};
49 : :
50 : : /**
51 : : * @defgroup StrBuf Stringbuffer, A class for manipulating strings with dynamic buffers
52 : : * StrBuf is a versatile class, aiding the handling of dynamic strings
53 : : * * reduce de/reallocations
54 : : * * reduce the need to remeasure it
55 : : * * reduce scanning over the string (in @ref StrBuf_NextTokenizer "Tokenizers")
56 : : * * allow asyncroneous IO for line and Blob based operations
57 : : * * reduce the use of memove in those
58 : : * * Quick filling in several operations with append functions
59 : : */
60 : :
61 : : /**
62 : : * @defgroup StrBuf_DeConstructors Create/Destroy StrBufs
63 : : * @ingroup StrBuf
64 : : */
65 : :
66 : : /**
67 : : * @defgroup StrBuf_Cast Cast operators to interact with char* based code
68 : : * @ingroup StrBuf
69 : : * use these operators to interfere with code demanding char*;
70 : : * if you need to own the content, smash me. Avoid, since we loose the length information.
71 : : */
72 : :
73 : : /**
74 : : * @defgroup StrBuf_Filler Create/Replace/Append Content into a StrBuf
75 : : * @ingroup StrBuf
76 : : * operations to get your Strings into a StrBuf, manipulating them, or appending
77 : : */
78 : : /**
79 : : * @defgroup StrBuf_NextTokenizer Fast tokenizer to pull tokens in sequence
80 : : * @ingroup StrBuf
81 : : * Quick tokenizer; demands of the user to pull its tokens in sequence
82 : : */
83 : :
84 : : /**
85 : : * @defgroup StrBuf_Tokenizer tokenizer Functions; Slow ones.
86 : : * @ingroup StrBuf
87 : : * versatile tokenizer; random access to tokens, but slower; Prefer the @ref StrBuf_NextTokenizer "Next Tokenizer"
88 : : */
89 : :
90 : : /**
91 : : * @defgroup StrBuf_BufferedIO Buffered IO with Asynchroneous reads and no unneeded memmoves (the fast ones)
92 : : * @ingroup StrBuf
93 : : * File IO to fill StrBufs; Works with work-buffer shared across several calls;
94 : : * External Cursor to maintain the current read position inside of the buffer
95 : : * the non-fast ones will use memove to keep the start of the buffer the read buffer (which is slower)
96 : : */
97 : :
98 : : /**
99 : : * @defgroup StrBuf_IO FileIO; Prefer @ref StrBuf_BufferedIO
100 : : * @ingroup StrBuf
101 : : * Slow I/O; avoid.
102 : : */
103 : :
104 : : /**
105 : : * @defgroup StrBuf_DeEnCoder functions to translate the contents of a buffer
106 : : * @ingroup StrBuf
107 : : * these functions translate the content of a buffer into another representation;
108 : : * some are combined Fillers and encoders
109 : : */
110 : :
111 : : /**
112 : : * Private Structure for the Stringbuffer
113 : : */
114 : : struct StrBuf {
115 : : char *buf; /**< the pointer to the dynamic buffer */
116 : : long BufSize; /**< how many spcae do we optain */
117 : : long BufUsed; /**< StNumber of Chars used excluding the trailing \\0 */
118 : : int ConstBuf; /**< are we just a wrapper arround a static buffer and musn't we be changed? */
119 : : #ifdef SIZE_DEBUG
120 : : long nIncreases; /**< for profiling; cound how many times we needed more */
121 : : char bt [SIZ]; /**< Stacktrace of last increase */
122 : : char bt_lastinc [SIZ]; /**< How much did we increase last time? */
123 : : #endif
124 : : };
125 : :
126 : :
127 : : static inline int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *CharE);
128 : : static inline int Ctdl_IsUtf8SequenceStart(const char Char);
129 : :
130 : : #ifdef SIZE_DEBUG
131 : : #ifdef HAVE_BACKTRACE
132 : : static void StrBufBacktrace(StrBuf *Buf, int which)
133 : : {
134 : : int n;
135 : : char *pstart, *pch;
136 : : void *stack_frames[50];
137 : : size_t size, i;
138 : : char **strings;
139 : :
140 : : if (which)
141 : : pstart = pch = Buf->bt;
142 : : else
143 : : pstart = pch = Buf->bt_lastinc;
144 : : size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
145 : : strings = backtrace_symbols(stack_frames, size);
146 : : for (i = 0; i < size; i++) {
147 : : if (strings != NULL)
148 : : n = snprintf(pch, SIZ - (pch - pstart), "%s\\n", strings[i]);
149 : : else
150 : : n = snprintf(pch, SIZ - (pch - pstart), "%p\\n", stack_frames[i]);
151 : : pch += n;
152 : : }
153 : : free(strings);
154 : :
155 : :
156 : : }
157 : : #endif
158 : :
159 : : void dbg_FreeStrBuf(StrBuf *FreeMe, char *FromWhere)
160 : : {
161 : : if (hFreeDbglog == -1){
162 : : pid_t pid = getpid();
163 : : char path [SIZ];
164 : : snprintf(path, SIZ, "/tmp/libcitadel_strbuf_realloc.log.%d", pid);
165 : : hFreeDbglog = open(path, O_APPEND|O_CREAT|O_WRONLY);
166 : : }
167 : : if ((*FreeMe)->nIncreases > 0)
168 : : {
169 : : char buf[SIZ * 3];
170 : : long n;
171 : : n = snprintf(buf, SIZ * 3, "%c+|%ld|%ld|%ld|%s|%s|\n",
172 : : FromWhere,
173 : : (*FreeMe)->nIncreases,
174 : : (*FreeMe)->BufUsed,
175 : : (*FreeMe)->BufSize,
176 : : (*FreeMe)->bt,
177 : : (*FreeMe)->bt_lastinc);
178 : : n = write(hFreeDbglog, buf, n);
179 : : }
180 : : else
181 : : {
182 : : char buf[128];
183 : : long n;
184 : : n = snprintf(buf, 128, "%c_|0|%ld%ld|\n",
185 : : FromWhere,
186 : : (*FreeMe)->BufUsed,
187 : : (*FreeMe)->BufSize);
188 : : n = write(hFreeDbglog, buf, n);
189 : : }
190 : : }
191 : :
192 : : void dbg_IncreaseBuf(StrBuf *IncMe)
193 : : {
194 : : Buf->nIncreases++;
195 : : #ifdef HAVE_BACKTRACE
196 : : StrBufBacktrace(Buf, 1);
197 : : #endif
198 : : }
199 : :
200 : : void dbg_Init(StrBuf *Buf)
201 : : {
202 : : Buf->nIncreases = 0;
203 : : Buf->bt[0] = '\0';
204 : : Buf->bt_lastinc[0] = '\0';
205 : : #ifdef HAVE_BACKTRACE
206 : : StrBufBacktrace(Buf, 0);
207 : : #endif
208 : : }
209 : :
210 : : #else
211 : : /* void it... */
212 : : #define dbg_FreeStrBuf(a, b)
213 : : #define dbg_IncreaseBuf(a)
214 : : #define dbg_Init(a)
215 : :
216 : : #endif
217 : :
218 : : /**
219 : : * @ingroup StrBuf
220 : : * @brief swaps the contents of two StrBufs
221 : : * this is to be used to have cheap switched between a work-buffer and a target buffer
222 : : * @param A First one
223 : : * @param B second one
224 : : */
225 : 25 : static inline void SwapBuffers(StrBuf *A, StrBuf *B)
226 : : {
227 : : StrBuf C;
228 : :
229 : 25 : memcpy(&C, A, sizeof(*A));
230 : 25 : memcpy(A, B, sizeof(*B));
231 : 25 : memcpy(B, &C, sizeof(C));
232 : :
233 : 25 : }
234 : :
235 : : /**
236 : : * @ingroup StrBuf_Cast
237 : : * @brief Cast operator to Plain String
238 : : * @note if the buffer is altered by StrBuf operations, this pointer may become
239 : : * invalid. So don't lean on it after altering the buffer!
240 : : * Since this operation is considered cheap, rather call it often than risking
241 : : * your pointer to become invalid!
242 : : * @param Str the string we want to get the c-string representation for
243 : : * @returns the Pointer to the Content. Don't mess with it!
244 : : */
245 : 298 : inline const char *ChrPtr(const StrBuf *Str)
246 : : {
247 [ - + ]: 298 : if (Str == NULL)
248 : 0 : return "";
249 : 298 : return Str->buf;
250 : : }
251 : :
252 : : /**
253 : : * @ingroup StrBuf_Cast
254 : : * @brief since we know strlen()'s result, provide it here.
255 : : * @param Str the string to return the length to
256 : : * @returns contentlength of the buffer
257 : : */
258 : 484 : inline int StrLength(const StrBuf *Str)
259 : : {
260 [ + - ]: 484 : return (Str != NULL) ? Str->BufUsed : 0;
261 : : }
262 : :
263 : : /**
264 : : * @ingroup StrBuf_DeConstructors
265 : : * @brief local utility function to resize the buffer
266 : : * @param Buf the buffer whichs storage we should increase
267 : : * @param KeepOriginal should we copy the original buffer or just start over with a new one
268 : : * @param DestSize what should fit in after?
269 : : */
270 : 92 : static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
271 : : {
272 : : char *NewBuf;
273 : 92 : size_t NewSize = Buf->BufSize * 2;
274 : :
275 [ - + ]: 92 : if (Buf->ConstBuf)
276 : 0 : return -1;
277 : :
278 [ + + ]: 92 : if (DestSize > 0)
279 [ + + ]: 126 : while (NewSize <= DestSize)
280 : 65 : NewSize *= 2;
281 : :
282 : 92 : NewBuf= (char*) malloc(NewSize);
283 [ - + ]: 92 : if (NewBuf == NULL)
284 : 0 : return -1;
285 : :
286 [ + + ][ + + ]: 92 : if (KeepOriginal && (Buf->BufUsed > 0))
287 : : {
288 : 27 : memcpy(NewBuf, Buf->buf, Buf->BufUsed);
289 : : }
290 : : else
291 : : {
292 : 65 : NewBuf[0] = '\0';
293 : 65 : Buf->BufUsed = 0;
294 : : }
295 : 92 : free (Buf->buf);
296 : 92 : Buf->buf = NewBuf;
297 : 92 : Buf->BufSize = NewSize;
298 : :
299 : : dbg_IncreaseBuf(Buf);
300 : :
301 : 92 : return Buf->BufSize;
302 : : }
303 : :
304 : : /**
305 : : * @ingroup StrBuf_DeConstructors
306 : : * @brief shrink / increase an _EMPTY_ buffer to NewSize. Buffercontent is thoroughly ignored and flushed.
307 : : * @param Buf Buffer to shrink (has to be empty)
308 : : * @param ThreshHold if the buffer is bigger then this, its readjusted
309 : : * @param NewSize if we Shrink it, how big are we going to be afterwards?
310 : : */
311 : 0 : void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize)
312 : : {
313 [ # # ][ # # ]: 0 : if ((Buf != NULL) &&
[ # # ]
314 : 0 : (Buf->BufUsed == 0) &&
315 : 0 : (Buf->BufSize < ThreshHold)) {
316 : 0 : free(Buf->buf);
317 : 0 : Buf->buf = (char*) malloc(NewSize);
318 : 0 : Buf->BufUsed = 0;
319 : 0 : Buf->BufSize = NewSize;
320 : : }
321 : 0 : }
322 : :
323 : : /**
324 : : * @ingroup StrBuf_DeConstructors
325 : : * @brief shrink long term buffers to their real size so they don't waste memory
326 : : * @param Buf buffer to shrink
327 : : * @param Force if not set, will just executed if the buffer is much to big; set for lifetime strings
328 : : * @returns physical size of the buffer
329 : : */
330 : 0 : long StrBufShrinkToFit(StrBuf *Buf, int Force)
331 : : {
332 [ # # ]: 0 : if (Buf == NULL)
333 : 0 : return -1;
334 [ # # ][ # # ]: 0 : if (Force ||
335 : 0 : (Buf->BufUsed + (Buf->BufUsed / 3) > Buf->BufSize))
336 : : {
337 : 0 : char *TmpBuf = (char*) malloc(Buf->BufUsed + 1);
338 : 0 : memcpy (TmpBuf, Buf->buf, Buf->BufUsed + 1);
339 : 0 : Buf->BufSize = Buf->BufUsed + 1;
340 : 0 : free(Buf->buf);
341 : 0 : Buf->buf = TmpBuf;
342 : : }
343 : 0 : return Buf->BufUsed;
344 : : }
345 : :
346 : : /**
347 : : * @ingroup StrBuf_DeConstructors
348 : : * @brief Allocate a new buffer with default buffer size
349 : : * @returns the new stringbuffer
350 : : */
351 : 79 : StrBuf* NewStrBuf(void)
352 : : {
353 : : StrBuf *NewBuf;
354 : :
355 : 79 : NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
356 : 79 : NewBuf->buf = (char*) malloc(BaseStrBufSize);
357 : 79 : NewBuf->buf[0] = '\0';
358 : 79 : NewBuf->BufSize = BaseStrBufSize;
359 : 79 : NewBuf->BufUsed = 0;
360 : 79 : NewBuf->ConstBuf = 0;
361 : :
362 : : dbg_Init (NewBuf);
363 : :
364 : 79 : return NewBuf;
365 : : }
366 : :
367 : : /**
368 : : * @ingroup StrBuf_DeConstructors
369 : : * @brief Copy Constructor; returns a duplicate of CopyMe
370 : : * @param CopyMe Buffer to faxmilate
371 : : * @returns the new stringbuffer
372 : : */
373 : 48 : StrBuf* NewStrBufDup(const StrBuf *CopyMe)
374 : : {
375 : : StrBuf *NewBuf;
376 : :
377 [ - + ]: 48 : if (CopyMe == NULL)
378 : 0 : return NewStrBuf();
379 : :
380 : 48 : NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
381 : 48 : NewBuf->buf = (char*) malloc(CopyMe->BufSize);
382 : 48 : memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
383 : 48 : NewBuf->BufUsed = CopyMe->BufUsed;
384 : 48 : NewBuf->BufSize = CopyMe->BufSize;
385 : 48 : NewBuf->ConstBuf = 0;
386 : :
387 : : dbg_Init(NewBuf);
388 : :
389 : 48 : return NewBuf;
390 : : }
391 : :
392 : : /**
393 : : * @ingroup StrBuf_DeConstructors
394 : : * @brief Copy Constructor; CreateRelpaceMe will contain CopyFlushMe afterwards.
395 : : * @param NoMe if non-NULL, we will use that buffer as value; KeepOriginal will abused as len.
396 : : * @param CopyFlushMe Buffer to faxmilate if KeepOriginal, or to move into CreateRelpaceMe if !KeepOriginal.
397 : : * @param CreateRelpaceMe If NULL, will be created, else Flushed and filled CopyFlushMe
398 : : * @param KeepOriginal should CopyFlushMe remain intact? or may we Steal its buffer?
399 : : * @returns the new stringbuffer
400 : : */
401 : 0 : void NewStrBufDupAppendFlush(StrBuf **CreateRelpaceMe, StrBuf *CopyFlushMe, const char *NoMe, int KeepOriginal)
402 : : {
403 : : StrBuf *NewBuf;
404 : :
405 [ # # ]: 0 : if (CreateRelpaceMe == NULL)
406 : 0 : return;
407 : :
408 [ # # ]: 0 : if (NoMe != NULL)
409 : : {
410 [ # # ]: 0 : if (*CreateRelpaceMe != NULL)
411 : 0 : StrBufPlain(*CreateRelpaceMe, NoMe, KeepOriginal);
412 : : else
413 : 0 : *CreateRelpaceMe = NewStrBufPlain(NoMe, KeepOriginal);
414 : 0 : return;
415 : : }
416 : :
417 [ # # ]: 0 : if (CopyFlushMe == NULL)
418 : : {
419 [ # # ]: 0 : if (*CreateRelpaceMe != NULL)
420 : 0 : FlushStrBuf(*CreateRelpaceMe);
421 : : else
422 : 0 : *CreateRelpaceMe = NewStrBuf();
423 : 0 : return;
424 : : }
425 : :
426 : : /*
427 : : * Randomly Chosen: bigger than 64 chars is cheaper to swap the buffers instead of copying.
428 : : * else *CreateRelpaceMe may use more memory than needed in a longer term, CopyFlushMe might
429 : : * be a big IO-Buffer...
430 : : */
431 [ # # ][ # # ]: 0 : if (KeepOriginal || (StrLength(CopyFlushMe) < 256))
432 : : {
433 [ # # ]: 0 : if (*CreateRelpaceMe == NULL)
434 : : {
435 : 0 : *CreateRelpaceMe = NewBuf = NewStrBufPlain(NULL, CopyFlushMe->BufUsed);
436 : : dbg_Init(NewBuf);
437 : : }
438 : : else
439 : : {
440 : 0 : NewBuf = *CreateRelpaceMe;
441 : 0 : FlushStrBuf(NewBuf);
442 : : }
443 : 0 : StrBufAppendBuf(NewBuf, CopyFlushMe, 0);
444 : : }
445 : : else
446 : : {
447 [ # # ]: 0 : if (*CreateRelpaceMe == NULL)
448 : : {
449 : 0 : *CreateRelpaceMe = NewBuf = NewStrBufPlain(NULL, CopyFlushMe->BufUsed);
450 : : dbg_Init(NewBuf);
451 : : }
452 : : else
453 : 0 : NewBuf = *CreateRelpaceMe;
454 : 0 : SwapBuffers (NewBuf, CopyFlushMe);
455 : : }
456 [ # # ]: 0 : if (!KeepOriginal)
457 : 0 : FlushStrBuf(CopyFlushMe);
458 : 0 : return;
459 : : }
460 : :
461 : : /**
462 : : * @ingroup StrBuf_DeConstructors
463 : : * @brief create a new Buffer using an existing c-string
464 : : * this function should also be used if you want to pre-suggest
465 : : * the buffer size to allocate in conjunction with ptr == NULL
466 : : * @param ptr the c-string to copy; may be NULL to create a blank instance
467 : : * @param nChars How many chars should we copy; -1 if we should measure the length ourselves
468 : : * @returns the new stringbuffer
469 : : */
470 : 502 : StrBuf* NewStrBufPlain(const char* ptr, int nChars)
471 : : {
472 : : StrBuf *NewBuf;
473 : 502 : size_t Siz = BaseStrBufSize;
474 : : size_t CopySize;
475 : :
476 : 502 : NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
477 [ - + ]: 502 : if (nChars < 0)
478 [ # # ]: 0 : CopySize = strlen((ptr != NULL)?ptr:"");
479 : : else
480 : 502 : CopySize = nChars;
481 : :
482 [ + + ]: 3532 : while (Siz <= CopySize)
483 : 3030 : Siz *= 2;
484 : :
485 : 502 : NewBuf->buf = (char*) malloc(Siz);
486 [ - + ]: 502 : if (NewBuf->buf == NULL)
487 : : {
488 : 0 : free(NewBuf);
489 : 0 : return NULL;
490 : : }
491 : 502 : NewBuf->BufSize = Siz;
492 [ + + ]: 502 : if (ptr != NULL) {
493 : 221 : memcpy(NewBuf->buf, ptr, CopySize);
494 : 221 : NewBuf->buf[CopySize] = '\0';
495 : 221 : NewBuf->BufUsed = CopySize;
496 : : }
497 : : else {
498 : 281 : NewBuf->buf[0] = '\0';
499 : 281 : NewBuf->BufUsed = 0;
500 : : }
501 : 502 : NewBuf->ConstBuf = 0;
502 : :
503 : : dbg_Init(NewBuf);
504 : :
505 : 502 : return NewBuf;
506 : : }
507 : :
508 : : /**
509 : : * @ingroup StrBuf_DeConstructors
510 : : * @brief Set an existing buffer from a c-string
511 : : * @param Buf buffer to load
512 : : * @param ptr c-string to put into
513 : : * @param nChars set to -1 if we should work 0-terminated
514 : : * @returns the new length of the string
515 : : */
516 : 4 : int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
517 : : {
518 : : size_t Siz;
519 : : size_t CopySize;
520 : :
521 [ - + ]: 4 : if (Buf == NULL)
522 : 0 : return -1;
523 [ - + ]: 4 : if (ptr == NULL) {
524 : 0 : FlushStrBuf(Buf);
525 : 0 : return -1;
526 : : }
527 : :
528 : 4 : Siz = Buf->BufSize;
529 : :
530 [ + - ]: 4 : if (nChars < 0)
531 : 4 : CopySize = strlen(ptr);
532 : : else
533 : 0 : CopySize = nChars;
534 : :
535 [ + + ]: 5 : while (Siz <= CopySize)
536 : 1 : Siz *= 2;
537 : :
538 [ + + ]: 4 : if (Siz != Buf->BufSize)
539 : 1 : IncreaseBuf(Buf, 0, Siz);
540 : 4 : memcpy(Buf->buf, ptr, CopySize);
541 : 4 : Buf->buf[CopySize] = '\0';
542 : 4 : Buf->BufUsed = CopySize;
543 : 4 : Buf->ConstBuf = 0;
544 : 4 : return CopySize;
545 : : }
546 : :
547 : :
548 : : /**
549 : : * @ingroup StrBuf_DeConstructors
550 : : * @brief use strbuf as wrapper for a string constant for easy handling
551 : : * @param StringConstant a string to wrap
552 : : * @param SizeOfStrConstant should be sizeof(StringConstant)-1
553 : : */
554 : 0 : StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
555 : : {
556 : : StrBuf *NewBuf;
557 : :
558 : 0 : NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
559 : 0 : NewBuf->buf = (char*) StringConstant;
560 : 0 : NewBuf->BufSize = SizeOfStrConstant;
561 : 0 : NewBuf->BufUsed = SizeOfStrConstant;
562 : 0 : NewBuf->ConstBuf = 1;
563 : :
564 : : dbg_Init(NewBuf);
565 : :
566 : 0 : return NewBuf;
567 : : }
568 : :
569 : :
570 : : /**
571 : : * @ingroup StrBuf_DeConstructors
572 : : * @brief flush the content of a Buf; keep its struct
573 : : * @param buf Buffer to flush
574 : : */
575 : 176 : int FlushStrBuf(StrBuf *buf)
576 : : {
577 [ - + ]: 176 : if (buf == NULL)
578 : 0 : return -1;
579 [ - + ]: 176 : if (buf->ConstBuf)
580 : 0 : return -1;
581 : 176 : buf->buf[0] ='\0';
582 : 176 : buf->BufUsed = 0;
583 : 176 : return 0;
584 : : }
585 : :
586 : : /**
587 : : * @ingroup StrBuf_DeConstructors
588 : : * @brief wipe the content of a Buf thoroughly (overwrite it -> expensive); keep its struct
589 : : * @param buf Buffer to wipe
590 : : */
591 : 0 : int FLUSHStrBuf(StrBuf *buf)
592 : : {
593 [ # # ]: 0 : if (buf == NULL)
594 : 0 : return -1;
595 [ # # ]: 0 : if (buf->ConstBuf)
596 : 0 : return -1;
597 [ # # ]: 0 : if (buf->BufUsed > 0) {
598 : 0 : memset(buf->buf, 0, buf->BufUsed);
599 : 0 : buf->BufUsed = 0;
600 : : }
601 : 0 : return 0;
602 : : }
603 : :
604 : : #ifdef SIZE_DEBUG
605 : : int hFreeDbglog = -1;
606 : : #endif
607 : : /**
608 : : * @ingroup StrBuf_DeConstructors
609 : : * @brief Release a Buffer
610 : : * Its a double pointer, so it can NULL your pointer
611 : : * so fancy SIG11 appear instead of random results
612 : : * @param FreeMe Pointer Pointer to the buffer to free
613 : : */
614 : 593 : void FreeStrBuf (StrBuf **FreeMe)
615 : : {
616 [ + + ]: 593 : if (*FreeMe == NULL)
617 : 161 : return;
618 : :
619 : : dbg_FreeStrBuf(FreeMe, 'F');
620 : :
621 [ + - ]: 432 : if (!(*FreeMe)->ConstBuf)
622 : 432 : free((*FreeMe)->buf);
623 : 432 : free(*FreeMe);
624 : 593 : *FreeMe = NULL;
625 : : }
626 : :
627 : : /**
628 : : * @ingroup StrBuf_DeConstructors
629 : : * @brief flatten a Buffer to the Char * we return
630 : : * Its a double pointer, so it can NULL your pointer
631 : : * so fancy SIG11 appear instead of random results
632 : : * The Callee then owns the buffer and is responsible for freeing it.
633 : : * @param SmashMe Pointer Pointer to the buffer to release Buf from and free
634 : : * @returns the pointer of the buffer; Callee owns the memory thereafter.
635 : : */
636 : 194 : char *SmashStrBuf (StrBuf **SmashMe)
637 : : {
638 : : char *Ret;
639 : :
640 [ + - ][ - + ]: 194 : if ((SmashMe == NULL) || (*SmashMe == NULL))
641 : 0 : return NULL;
642 : :
643 : : dbg_FreeStrBuf(SmashMe, 'S');
644 : :
645 : 194 : Ret = (*SmashMe)->buf;
646 : 194 : free(*SmashMe);
647 : 194 : *SmashMe = NULL;
648 : 194 : return Ret;
649 : : }
650 : :
651 : : /**
652 : : * @ingroup StrBuf_DeConstructors
653 : : * @brief Release the buffer
654 : : * If you want put your StrBuf into a Hash, use this as Destructor.
655 : : * @param VFreeMe untyped pointer to a StrBuf. be shure to do the right thing [TM]
656 : : */
657 : 0 : void HFreeStrBuf (void *VFreeMe)
658 : : {
659 : 0 : StrBuf *FreeMe = (StrBuf*)VFreeMe;
660 [ # # ]: 0 : if (FreeMe == NULL)
661 : 0 : return;
662 : :
663 : : dbg_FreeStrBuf(SmashMe, 'H');
664 : :
665 [ # # ]: 0 : if (!FreeMe->ConstBuf)
666 : 0 : free(FreeMe->buf);
667 : 0 : free(FreeMe);
668 : : }
669 : :
670 : :
671 : : /*******************************************************************************
672 : : * Simple string transformations *
673 : : *******************************************************************************/
674 : :
675 : : /**
676 : : * @ingroup StrBuf
677 : : * @brief Wrapper around atol
678 : : */
679 : 0 : long StrTol(const StrBuf *Buf)
680 : : {
681 [ # # ]: 0 : if (Buf == NULL)
682 : 0 : return 0;
683 [ # # ]: 0 : if(Buf->BufUsed > 0)
684 : 0 : return atol(Buf->buf);
685 : : else
686 : 0 : return 0;
687 : : }
688 : :
689 : : /**
690 : : * @ingroup StrBuf
691 : : * @brief Wrapper around atoi
692 : : */
693 : 0 : int StrToi(const StrBuf *Buf)
694 : : {
695 [ # # ]: 0 : if (Buf == NULL)
696 : 0 : return 0;
697 [ # # ]: 0 : if (Buf->BufUsed > 0)
698 : 0 : return atoi(Buf->buf);
699 : : else
700 : 0 : return 0;
701 : : }
702 : :
703 : : /**
704 : : * @ingroup StrBuf
705 : : * @brief Checks to see if the string is a pure number
706 : : * @param Buf The buffer to inspect
707 : : * @returns 1 if its a pure number, 0, if not.
708 : : */
709 : 0 : int StrBufIsNumber(const StrBuf *Buf) {
710 : : char * pEnd;
711 [ # # ][ # # ]: 0 : if ((Buf == NULL) || (Buf->BufUsed == 0)) {
712 : 0 : return 0;
713 : : }
714 : 0 : strtoll(Buf->buf, &pEnd, 10);
715 [ # # ]: 0 : if (pEnd == Buf->buf)
716 : 0 : return 0;
717 [ # # ][ # # ]: 0 : if ((pEnd != NULL) && (pEnd == Buf->buf + Buf->BufUsed))
718 : 0 : return 1;
719 [ # # ]: 0 : if (Buf->buf == pEnd)
720 : 0 : return 0;
721 : 0 : return 0;
722 : : }
723 : :
724 : : /**
725 : : * @ingroup StrBuf_Filler
726 : : * @brief modifies a Single char of the Buf
727 : : * You can point to it via char* or a zero-based integer
728 : : * @param Buf The buffer to manipulate
729 : : * @param ptr char* to zero; use NULL if unused
730 : : * @param nThChar zero based pointer into the string; use -1 if unused
731 : : * @param PeekValue The Character to place into the position
732 : : */
733 : 0 : long StrBufPeek(StrBuf *Buf, const char* ptr, long nThChar, char PeekValue)
734 : : {
735 [ # # ]: 0 : if (Buf == NULL)
736 : 0 : return -1;
737 [ # # ]: 0 : if (ptr != NULL)
738 : 0 : nThChar = ptr - Buf->buf;
739 [ # # ][ # # ]: 0 : if ((nThChar < 0) || (nThChar > Buf->BufUsed))
740 : 0 : return -1;
741 : 0 : Buf->buf[nThChar] = PeekValue;
742 : 0 : return nThChar;
743 : : }
744 : :
745 : : /**
746 : : * @ingroup StrBuf_Filler
747 : : * @brief modifies a range of chars of the Buf
748 : : * You can point to it via char* or a zero-based integer
749 : : * @param Buf The buffer to manipulate
750 : : * @param ptr char* to zero; use NULL if unused
751 : : * @param nThChar zero based pointer into the string; use -1 if unused
752 : : * @param nChars how many chars are to be flushed?
753 : : * @param PookValue The Character to place into that area
754 : : */
755 : 0 : long StrBufPook(StrBuf *Buf, const char* ptr, long nThChar, long nChars, char PookValue)
756 : : {
757 [ # # ]: 0 : if (Buf == NULL)
758 : 0 : return -1;
759 [ # # ]: 0 : if (ptr != NULL)
760 : 0 : nThChar = ptr - Buf->buf;
761 [ # # ][ # # ]: 0 : if ((nThChar < 0) || (nThChar > Buf->BufUsed))
762 : 0 : return -1;
763 [ # # ]: 0 : if (nThChar + nChars > Buf->BufUsed)
764 : 0 : nChars = Buf->BufUsed - nThChar;
765 : :
766 : 0 : memset(Buf->buf + nThChar, PookValue, nChars);
767 : : /* just to be shure... */
768 : 0 : Buf->buf[Buf->BufUsed] = 0;
769 : 0 : return nChars;
770 : : }
771 : :
772 : : /**
773 : : * @ingroup StrBuf_Filler
774 : : * @brief Append a StringBuffer to the buffer
775 : : * @param Buf Buffer to modify
776 : : * @param AppendBuf Buffer to copy at the end of our buffer
777 : : * @param Offset Should we start copying from an offset?
778 : : */
779 : 227 : void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, unsigned long Offset)
780 : : {
781 [ + - ][ + - ]: 227 : if ((AppendBuf == NULL) || (Buf == NULL) || (AppendBuf->buf == NULL))
[ - + ]
782 : 0 : return;
783 : :
784 [ + + ]: 227 : if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed + 1)
785 : 14 : IncreaseBuf(Buf,
786 : : (Buf->BufUsed > 0),
787 : 14 : AppendBuf->BufUsed + Buf->BufUsed);
788 : :
789 : 454 : memcpy(Buf->buf + Buf->BufUsed,
790 : : AppendBuf->buf + Offset,
791 : 227 : AppendBuf->BufUsed - Offset);
792 : 227 : Buf->BufUsed += AppendBuf->BufUsed - Offset;
793 : 227 : Buf->buf[Buf->BufUsed] = '\0';
794 : : }
795 : :
796 : :
797 : : /**
798 : : * @ingroup StrBuf_Filler
799 : : * @brief Append a C-String to the buffer
800 : : * @param Buf Buffer to modify
801 : : * @param AppendBuf Buffer to copy at the end of our buffer
802 : : * @param AppendSize number of bytes to copy; set to -1 if we should count it in advance
803 : : * @param Offset Should we start copying from an offset?
804 : : */
805 : 844 : void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, unsigned long Offset)
806 : : {
807 : : long aps;
808 : : long BufSizeRequired;
809 : :
810 [ + - ][ - + ]: 844 : if ((AppendBuf == NULL) || (Buf == NULL))
811 : 0 : return;
812 : :
813 [ + + ]: 844 : if (AppendSize < 0 )
814 : 30 : aps = strlen(AppendBuf + Offset);
815 : : else
816 : 814 : aps = AppendSize - Offset;
817 : :
818 : 844 : BufSizeRequired = Buf->BufUsed + aps + 1;
819 [ + + ]: 844 : if (Buf->BufSize <= BufSizeRequired)
820 : 32 : IncreaseBuf(Buf, (Buf->BufUsed > 0), BufSizeRequired);
821 : :
822 : 844 : memcpy(Buf->buf + Buf->BufUsed,
823 : : AppendBuf + Offset,
824 : : aps);
825 : 844 : Buf->BufUsed += aps;
826 : 844 : Buf->buf[Buf->BufUsed] = '\0';
827 : : }
828 : :
829 : : /**
830 : : * @ingroup StrBuf_Filler
831 : : * @brief sprintf like function appending the formated string to the buffer
832 : : * vsnprintf version to wrap into own calls
833 : : * @param Buf Buffer to extend by format and Params
834 : : * @param format printf alike format to add
835 : : * @param ap va_list containing the items for format
836 : : */
837 : 0 : void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
838 : : {
839 : : va_list apl;
840 : : size_t BufSize;
841 : : size_t nWritten;
842 : : size_t Offset;
843 : : size_t newused;
844 : :
845 [ # # ][ # # ]: 0 : if ((Buf == NULL) || (format == NULL))
846 : 0 : return;
847 : :
848 : 0 : BufSize = Buf->BufSize;
849 : 0 : nWritten = Buf->BufSize + 1;
850 : 0 : Offset = Buf->BufUsed;
851 : 0 : newused = Offset + nWritten;
852 : :
853 [ # # ]: 0 : while (newused >= BufSize) {
854 : 0 : va_copy(apl, ap);
855 : 0 : nWritten = vsnprintf(Buf->buf + Offset,
856 : 0 : Buf->BufSize - Offset,
857 : : format, apl);
858 : 0 : va_end(apl);
859 : 0 : newused = Offset + nWritten;
860 [ # # ]: 0 : if (newused >= Buf->BufSize) {
861 : 0 : IncreaseBuf(Buf, 1, newused);
862 : 0 : newused = Buf->BufSize + 1;
863 : : }
864 : : else {
865 : 0 : Buf->BufUsed = Offset + nWritten;
866 : 0 : BufSize = Buf->BufSize;
867 : : }
868 : :
869 : : }
870 : : }
871 : :
872 : : /**
873 : : * @ingroup StrBuf_Filler
874 : : * @brief sprintf like function appending the formated string to the buffer
875 : : * @param Buf Buffer to extend by format and Params
876 : : * @param format printf alike format to add
877 : : */
878 : 9 : void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
879 : : {
880 : : size_t BufSize;
881 : : size_t nWritten;
882 : : size_t Offset;
883 : : size_t newused;
884 : : va_list arg_ptr;
885 : :
886 [ + - ][ - + ]: 9 : if ((Buf == NULL) || (format == NULL))
887 : 0 : return;
888 : :
889 : 9 : BufSize = Buf->BufSize;
890 : 9 : nWritten = Buf->BufSize + 1;
891 : 9 : Offset = Buf->BufUsed;
892 : 9 : newused = Offset + nWritten;
893 : :
894 [ + + ]: 23 : while (newused >= BufSize) {
895 : 14 : va_start(arg_ptr, format);
896 : 28 : nWritten = vsnprintf(Buf->buf + Buf->BufUsed,
897 : 14 : Buf->BufSize - Buf->BufUsed,
898 : : format, arg_ptr);
899 : 14 : va_end(arg_ptr);
900 : 14 : newused = Buf->BufUsed + nWritten;
901 [ + + ]: 14 : if (newused >= Buf->BufSize) {
902 : 5 : IncreaseBuf(Buf, 1, newused);
903 : 5 : newused = Buf->BufSize + 1;
904 : : }
905 : : else {
906 : 9 : Buf->BufUsed += nWritten;
907 : 9 : BufSize = Buf->BufSize;
908 : : }
909 : :
910 : : }
911 : : }
912 : :
913 : : /**
914 : : * @ingroup StrBuf_Filler
915 : : * @brief sprintf like function putting the formated string into the buffer
916 : : * @param Buf Buffer to extend by format and Parameters
917 : : * @param format printf alike format to add
918 : : */
919 : 103 : void StrBufPrintf(StrBuf *Buf, const char *format, ...)
920 : : {
921 : : size_t nWritten;
922 : : va_list arg_ptr;
923 : :
924 [ + - ][ - + ]: 103 : if ((Buf == NULL) || (format == NULL))
925 : 0 : return;
926 : :
927 : 103 : nWritten = Buf->BufSize + 1;
928 [ + + ]: 225 : while (nWritten >= Buf->BufSize) {
929 : 122 : va_start(arg_ptr, format);
930 : 122 : nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
931 : 122 : va_end(arg_ptr);
932 [ + + ]: 122 : if (nWritten >= Buf->BufSize) {
933 : 19 : IncreaseBuf(Buf, 0, 0);
934 : 19 : nWritten = Buf->BufSize + 1;
935 : 19 : continue;
936 : : }
937 : 103 : Buf->BufUsed = nWritten ;
938 : : }
939 : : }
940 : :
941 : : /**
942 : : * @ingroup StrBuf_Filler
943 : : * @brief Callback for cURL to append the webserver reply to a buffer
944 : : * @param ptr pre-defined by the cURL API; see man 3 curl for mre info
945 : : * @param size pre-defined by the cURL API; see man 3 curl for mre info
946 : : * @param nmemb pre-defined by the cURL API; see man 3 curl for mre info
947 : : * @param stream pre-defined by the cURL API; see man 3 curl for mre info
948 : : */
949 : 0 : size_t CurlFillStrBuf_callback(void *ptr, size_t size, size_t nmemb, void *stream)
950 : : {
951 : :
952 : : StrBuf *Target;
953 : :
954 : 0 : Target = stream;
955 [ # # ]: 0 : if (ptr == NULL)
956 : 0 : return 0;
957 : :
958 : 0 : StrBufAppendBufPlain(Target, ptr, size * nmemb, 0);
959 : 0 : return size * nmemb;
960 : : }
961 : :
962 : :
963 : : /**
964 : : * @ingroup StrBuf
965 : : * @brief extracts a substring from Source into dest
966 : : * @param dest buffer to place substring into
967 : : * @param Source string to copy substring from
968 : : * @param Offset chars to skip from start
969 : : * @param nChars number of chars to copy
970 : : * @returns the number of chars copied; may be different from nChars due to the size of Source
971 : : */
972 : 0 : int StrBufSub(StrBuf *dest, const StrBuf *Source, unsigned long Offset, size_t nChars)
973 : : {
974 : : size_t NCharsRemain;
975 [ # # ]: 0 : if (Offset > Source->BufUsed)
976 : : {
977 [ # # ]: 0 : if (dest != NULL)
978 : 0 : FlushStrBuf(dest);
979 : 0 : return 0;
980 : : }
981 [ # # ]: 0 : if (Offset + nChars < Source->BufUsed)
982 : : {
983 [ # # ]: 0 : if (nChars >= dest->BufSize)
984 : 0 : IncreaseBuf(dest, 0, nChars + 1);
985 : 0 : memcpy(dest->buf, Source->buf + Offset, nChars);
986 : 0 : dest->BufUsed = nChars;
987 : 0 : dest->buf[dest->BufUsed] = '\0';
988 : 0 : return nChars;
989 : : }
990 : 0 : NCharsRemain = Source->BufUsed - Offset;
991 [ # # ]: 0 : if (NCharsRemain >= dest->BufSize)
992 : 0 : IncreaseBuf(dest, 0, NCharsRemain + 1);
993 : 0 : memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
994 : 0 : dest->BufUsed = NCharsRemain;
995 : 0 : dest->buf[dest->BufUsed] = '\0';
996 : 0 : return NCharsRemain;
997 : : }
998 : :
999 : : /**
1000 : : * @ingroup StrBuf
1001 : : * @brief Cut nChars from the start of the string
1002 : : * @param Buf Buffer to modify
1003 : : * @param nChars how many chars should be skipped?
1004 : : */
1005 : 2 : void StrBufCutLeft(StrBuf *Buf, int nChars)
1006 : : {
1007 [ + - ][ - + ]: 2 : if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1008 [ - + ]: 2 : if (nChars >= Buf->BufUsed) {
1009 : 0 : FlushStrBuf(Buf);
1010 : 0 : return;
1011 : : }
1012 : 2 : memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
1013 : 2 : Buf->BufUsed -= nChars;
1014 : 2 : Buf->buf[Buf->BufUsed] = '\0';
1015 : : }
1016 : :
1017 : : /**
1018 : : * @ingroup StrBuf
1019 : : * @brief Cut the trailing n Chars from the string
1020 : : * @param Buf Buffer to modify
1021 : : * @param nChars how many chars should be trunkated?
1022 : : */
1023 : 0 : void StrBufCutRight(StrBuf *Buf, int nChars)
1024 : : {
1025 [ # # ][ # # ]: 0 : if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1026 [ # # ]: 0 : if (nChars >= Buf->BufUsed) {
1027 : 0 : FlushStrBuf(Buf);
1028 : 0 : return;
1029 : : }
1030 : 0 : Buf->BufUsed -= nChars;
1031 : 0 : Buf->buf[Buf->BufUsed] = '\0';
1032 : : }
1033 : :
1034 : : /**
1035 : : * @ingroup StrBuf
1036 : : * @brief Cut the string after n Chars
1037 : : * @param Buf Buffer to modify
1038 : : * @param AfternChars after how many chars should we trunkate the string?
1039 : : * @param At if non-null and points inside of our string, cut it there.
1040 : : */
1041 : 0 : void StrBufCutAt(StrBuf *Buf, int AfternChars, const char *At)
1042 : : {
1043 [ # # ][ # # ]: 0 : if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1044 [ # # ]: 0 : if (At != NULL){
1045 : 0 : AfternChars = At - Buf->buf;
1046 : : }
1047 : :
1048 [ # # ][ # # ]: 0 : if ((AfternChars < 0) || (AfternChars >= Buf->BufUsed))
1049 : 0 : return;
1050 : 0 : Buf->BufUsed = AfternChars;
1051 : 0 : Buf->buf[Buf->BufUsed] = '\0';
1052 : : }
1053 : :
1054 : :
1055 : : /**
1056 : : * @ingroup StrBuf
1057 : : * @brief Strip leading and trailing spaces from a string; with premeasured and adjusted length.
1058 : : * @param Buf the string to modify
1059 : : */
1060 : 0 : void StrBufTrim(StrBuf *Buf)
1061 : : {
1062 : 0 : int delta = 0;
1063 [ # # ][ # # ]: 0 : if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1064 : :
1065 [ # # # # ]: 0 : while ((Buf->BufUsed > 0) &&
1066 : 0 : isspace(Buf->buf[Buf->BufUsed - 1]))
1067 : : {
1068 : 0 : Buf->BufUsed --;
1069 : : }
1070 : 0 : Buf->buf[Buf->BufUsed] = '\0';
1071 : :
1072 [ # # ]: 0 : if (Buf->BufUsed == 0) return;
1073 : :
1074 [ # # ][ # # ]: 0 : while ((Buf->BufUsed > delta) && (isspace(Buf->buf[delta]))){
1075 : 0 : delta ++;
1076 : : }
1077 [ # # ]: 0 : if (delta > 0) StrBufCutLeft(Buf, delta);
1078 : : }
1079 : : /**
1080 : : * @ingroup StrBuf
1081 : : * @brief changes all spaces in the string (tab, linefeed...) to Blank (0x20)
1082 : : * @param Buf the string to modify
1083 : : */
1084 : 0 : void StrBufSpaceToBlank(StrBuf *Buf)
1085 : : {
1086 : : char *pche, *pch;
1087 : :
1088 [ # # ][ # # ]: 0 : if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1089 : :
1090 : 0 : pch = Buf->buf;
1091 : 0 : pche = pch + Buf->BufUsed;
1092 [ # # ]: 0 : while (pch < pche)
1093 : : {
1094 [ # # ]: 0 : if (isspace(*pch))
1095 : 0 : *pch = ' ';
1096 : 0 : pch ++;
1097 : : }
1098 : : }
1099 : :
1100 : 0 : void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary)
1101 : : {
1102 : : const char *pBuff;
1103 : : const char *pLeft;
1104 : : const char *pRight;
1105 : :
1106 [ # # ]: 0 : if (Buf == NULL)
1107 : 0 : return;
1108 : 0 : pLeft = pBuff = Buf->buf;
1109 [ # # ]: 0 : while (pBuff != NULL) {
1110 : 0 : pLeft = pBuff;
1111 : 0 : pBuff = strchr(pBuff, leftboundary);
1112 [ # # ]: 0 : if (pBuff != NULL)
1113 : 0 : pBuff++;
1114 : : }
1115 : :
1116 [ # # ]: 0 : if (pLeft != NULL)
1117 : 0 : pBuff = pLeft;
1118 : : else
1119 : 0 : pBuff = Buf->buf;
1120 : 0 : pRight = strchr(pBuff, rightboundary);
1121 [ # # ]: 0 : if (pRight != NULL)
1122 : 0 : StrBufCutAt(Buf, 0, pRight);
1123 [ # # ]: 0 : if (pLeft != NULL)
1124 : 0 : StrBufCutLeft(Buf, pLeft - Buf->buf);
1125 : : }
1126 : :
1127 : :
1128 : : /**
1129 : : * @ingroup StrBuf_Filler
1130 : : * @brief uppercase the contents of a buffer
1131 : : * @param Buf the buffer to translate
1132 : : */
1133 : 0 : void StrBufUpCase(StrBuf *Buf)
1134 : : {
1135 : : char *pch, *pche;
1136 : :
1137 [ # # ][ # # ]: 0 : if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1138 : :
1139 : 0 : pch = Buf->buf;
1140 : 0 : pche = pch + Buf->BufUsed;
1141 [ # # ]: 0 : while (pch < pche) {
1142 : 0 : *pch = toupper(*pch);
1143 : 0 : pch ++;
1144 : : }
1145 : : }
1146 : :
1147 : :
1148 : : /**
1149 : : * @ingroup StrBuf_Filler
1150 : : * @brief lowercase the contents of a buffer
1151 : : * @param Buf the buffer to translate
1152 : : */
1153 : 0 : void StrBufLowerCase(StrBuf *Buf)
1154 : : {
1155 : : char *pch, *pche;
1156 : :
1157 [ # # ][ # # ]: 0 : if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1158 : :
1159 : 0 : pch = Buf->buf;
1160 : 0 : pche = pch + Buf->BufUsed;
1161 [ # # ]: 0 : while (pch < pche) {
1162 : 0 : *pch = tolower(*pch);
1163 : 0 : pch ++;
1164 : : }
1165 : : }
1166 : :
1167 : :
1168 : : /*******************************************************************************
1169 : : * a tokenizer that kills, maims, and destroys *
1170 : : *******************************************************************************/
1171 : :
1172 : : /**
1173 : : * @ingroup StrBuf_Tokenizer
1174 : : * @brief Replace a token at a given place with a given length by another token with given length
1175 : : * @param Buf String where to work on
1176 : : * @param where where inside of the Buf is the search-token
1177 : : * @param HowLong How long is the token to be replaced
1178 : : * @param Repl Token to insert at 'where'
1179 : : * @param ReplLen Length of repl
1180 : : * @returns -1 if fail else length of resulting Buf
1181 : : */
1182 : 0 : int StrBufReplaceToken(StrBuf *Buf, long where, long HowLong,
1183 : : const char *Repl, long ReplLen)
1184 : : {
1185 : :
1186 [ # # ][ # # ]: 0 : if ((Buf == NULL) ||
[ # # ]
1187 : 0 : (where > Buf->BufUsed) ||
1188 : 0 : (where + HowLong > Buf->BufUsed))
1189 : 0 : return -1;
1190 : :
1191 [ # # ]: 0 : if (where + ReplLen - HowLong > Buf->BufSize)
1192 [ # # ]: 0 : if (IncreaseBuf(Buf, 1, Buf->BufUsed + ReplLen) < 0)
1193 : 0 : return -1;
1194 : :
1195 : 0 : memmove(Buf->buf + where + ReplLen,
1196 : 0 : Buf->buf + where + HowLong,
1197 : 0 : Buf->BufUsed - where - HowLong);
1198 : :
1199 : 0 : memcpy(Buf->buf + where,
1200 : : Repl, ReplLen);
1201 : :
1202 : 0 : Buf->BufUsed += ReplLen - HowLong;
1203 : :
1204 : 0 : return Buf->BufUsed;
1205 : : }
1206 : :
1207 : : /**
1208 : : * @ingroup StrBuf_Tokenizer
1209 : : * @brief Counts the numbmer of tokens in a buffer
1210 : : * @param source String to count tokens in
1211 : : * @param tok Tokenizer char to count
1212 : : * @returns numbers of tokenizer chars found
1213 : : */
1214 : 0 : int StrBufNum_tokens(const StrBuf *source, char tok)
1215 : : {
1216 : : char *pch, *pche;
1217 : : long NTokens;
1218 [ # # ][ # # ]: 0 : if ((source == NULL) || (source->BufUsed == 0))
1219 : 0 : return 0;
1220 [ # # ][ # # ]: 0 : if ((source->BufUsed == 1) && (*source->buf == tok))
1221 : 0 : return 2;
1222 : 0 : NTokens = 1;
1223 : 0 : pch = source->buf;
1224 : 0 : pche = pch + source->BufUsed;
1225 [ # # ]: 0 : while (pch < pche)
1226 : : {
1227 [ # # ]: 0 : if (*pch == tok)
1228 : 0 : NTokens ++;
1229 : 0 : pch ++;
1230 : : }
1231 : 0 : return NTokens;
1232 : : }
1233 : :
1234 : : /**
1235 : : * @ingroup StrBuf_Tokenizer
1236 : : * @brief a string tokenizer
1237 : : * @param Source StringBuffer to read into
1238 : : * @param parmnum n'th Parameter to remove
1239 : : * @param separator tokenizer character
1240 : : * @returns -1 if not found, else length of token.
1241 : : */
1242 : 0 : int StrBufRemove_token(StrBuf *Source, int parmnum, char separator)
1243 : : {
1244 : : int ReducedBy;
1245 : : char *d, *s, *end; /* dest, source */
1246 : 0 : int count = 0;
1247 : :
1248 : : /* Find desired @parameter */
1249 : 0 : end = Source->buf + Source->BufUsed;
1250 : 0 : d = Source->buf;
1251 [ # # ][ # # ]: 0 : while ((d <= end) &&
1252 : : (count < parmnum))
1253 : : {
1254 : : /* End of string, bail! */
1255 [ # # ]: 0 : if (!*d) {
1256 : 0 : d = NULL;
1257 : 0 : break;
1258 : : }
1259 [ # # ]: 0 : if (*d == separator) {
1260 : 0 : count++;
1261 : : }
1262 : 0 : d++;
1263 : : }
1264 [ # # ][ # # ]: 0 : if ((d == NULL) || (d >= end))
1265 : 0 : return 0; /* @Parameter not found */
1266 : :
1267 : : /* Find next @parameter */
1268 : 0 : s = d;
1269 [ # # ][ # # ]: 0 : while ((s <= end) &&
[ # # ]
1270 : 0 : (*s && *s != separator))
1271 : : {
1272 : 0 : s++;
1273 : : }
1274 [ # # ]: 0 : if (*s == separator)
1275 : 0 : s++;
1276 : 0 : ReducedBy = d - s;
1277 : :
1278 : : /* Hack and slash */
1279 [ # # ]: 0 : if (s >= end) {
1280 : 0 : return 0;
1281 : : }
1282 [ # # ]: 0 : else if (*s) {
1283 : 0 : memmove(d, s, Source->BufUsed - (s - Source->buf));
1284 : 0 : Source->BufUsed += ReducedBy;
1285 : 0 : Source->buf[Source->BufUsed] = '\0';
1286 : : }
1287 [ # # ]: 0 : else if (d == Source->buf) {
1288 : 0 : *d = 0;
1289 : 0 : Source->BufUsed = 0;
1290 : : }
1291 : : else {
1292 : 0 : *--d = '\0';
1293 : 0 : Source->BufUsed += ReducedBy;
1294 : : }
1295 : : /*
1296 : : while (*s) {
1297 : : *d++ = *s++;
1298 : : }
1299 : : *d = 0;
1300 : : */
1301 : 0 : return ReducedBy;
1302 : : }
1303 : :
1304 : :
1305 : : /**
1306 : : * @ingroup StrBuf_Tokenizer
1307 : : * @brief a string tokenizer
1308 : : * @param dest Destination StringBuffer
1309 : : * @param Source StringBuffer to read into
1310 : : * @param parmnum n'th Parameter to extract
1311 : : * @param separator tokenizer character
1312 : : * @returns -1 if not found, else length of token.
1313 : : */
1314 : 20 : int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
1315 : : {
1316 : : const char *s, *e; //* source * /
1317 : 20 : int len = 0; //* running total length of extracted string * /
1318 : 20 : int current_token = 0; //* token currently being processed * /
1319 : :
1320 [ + - ]: 20 : if (dest != NULL) {
1321 : 20 : dest->buf[0] = '\0';
1322 : 20 : dest->BufUsed = 0;
1323 : : }
1324 : : else
1325 : 0 : return(-1);
1326 : :
1327 [ + - ][ - + ]: 20 : if ((Source == NULL) || (Source->BufUsed ==0)) {
1328 : 0 : return(-1);
1329 : : }
1330 : 20 : s = Source->buf;
1331 : 20 : e = s + Source->BufUsed;
1332 : :
1333 : : //cit_backtrace();
1334 : : //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
1335 : :
1336 [ + + ][ + - ]: 620 : while ((s<e) && !IsEmptyStr(s)) {
1337 [ + + ]: 600 : if (*s == separator) {
1338 : 60 : ++current_token;
1339 : : }
1340 [ - + ]: 600 : if (len >= dest->BufSize) {
1341 : 0 : dest->BufUsed = len;
1342 [ # # ]: 0 : if (IncreaseBuf(dest, 1, -1) < 0) {
1343 : 0 : dest->BufUsed --;
1344 : 0 : break;
1345 : : }
1346 : : }
1347 [ + + ][ + + ]: 600 : if ( (current_token == parmnum) &&
1348 : 320 : (*s != separator)) {
1349 : 300 : dest->buf[len] = *s;
1350 : 300 : ++len;
1351 : : }
1352 [ - + ]: 300 : else if (current_token > parmnum) {
1353 : 0 : break;
1354 : : }
1355 : 600 : ++s;
1356 : : }
1357 : :
1358 : 20 : dest->buf[len] = '\0';
1359 : 20 : dest->BufUsed = len;
1360 : :
1361 [ - + ]: 20 : if (current_token < parmnum) {
1362 : : //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
1363 : 0 : return(-1);
1364 : : }
1365 : : //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
1366 : 20 : return(len);
1367 : : }
1368 : :
1369 : :
1370 : :
1371 : :
1372 : :
1373 : : /**
1374 : : * @ingroup StrBuf_Tokenizer
1375 : : * @brief a string tokenizer to fetch an integer
1376 : : * @param Source String containing tokens
1377 : : * @param parmnum n'th Parameter to extract
1378 : : * @param separator tokenizer character
1379 : : * @returns 0 if not found, else integer representation of the token
1380 : : */
1381 : 0 : int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
1382 : : {
1383 : : StrBuf tmp;
1384 : : char buf[64];
1385 : :
1386 : 0 : tmp.buf = buf;
1387 : 0 : buf[0] = '\0';
1388 : 0 : tmp.BufSize = 64;
1389 : 0 : tmp.BufUsed = 0;
1390 : 0 : tmp.ConstBuf = 1;
1391 [ # # ]: 0 : if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
1392 : 0 : return(atoi(buf));
1393 : : else
1394 : 0 : return 0;
1395 : : }
1396 : :
1397 : : /**
1398 : : * @ingroup StrBuf_Tokenizer
1399 : : * @brief a string tokenizer to fetch a long integer
1400 : : * @param Source String containing tokens
1401 : : * @param parmnum n'th Parameter to extract
1402 : : * @param separator tokenizer character
1403 : : * @returns 0 if not found, else long integer representation of the token
1404 : : */
1405 : 0 : long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
1406 : : {
1407 : : StrBuf tmp;
1408 : : char buf[64];
1409 : :
1410 : 0 : tmp.buf = buf;
1411 : 0 : buf[0] = '\0';
1412 : 0 : tmp.BufSize = 64;
1413 : 0 : tmp.BufUsed = 0;
1414 : 0 : tmp.ConstBuf = 1;
1415 [ # # ]: 0 : if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
1416 : 0 : return(atoi(buf));
1417 : : else
1418 : 0 : return 0;
1419 : : }
1420 : :
1421 : :
1422 : : /**
1423 : : * @ingroup StrBuf_Tokenizer
1424 : : * @brief a string tokenizer to fetch an unsigned long
1425 : : * @param Source String containing tokens
1426 : : * @param parmnum n'th Parameter to extract
1427 : : * @param separator tokenizer character
1428 : : * @returns 0 if not found, else unsigned long representation of the token
1429 : : */
1430 : 0 : unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
1431 : : {
1432 : : StrBuf tmp;
1433 : : char buf[64];
1434 : : char *pnum;
1435 : :
1436 : 0 : tmp.buf = buf;
1437 : 0 : buf[0] = '\0';
1438 : 0 : tmp.BufSize = 64;
1439 : 0 : tmp.BufUsed = 0;
1440 : 0 : tmp.ConstBuf = 1;
1441 [ # # ]: 0 : if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0) {
1442 : 0 : pnum = &buf[0];
1443 [ # # ]: 0 : if (*pnum == '-')
1444 : 0 : pnum ++;
1445 : 0 : return (unsigned long) atol(pnum);
1446 : : }
1447 : : else
1448 : 0 : return 0;
1449 : : }
1450 : :
1451 : :
1452 : :
1453 : : /**
1454 : : * @ingroup StrBuf_NextTokenizer
1455 : : * @brief a string tokenizer; Bounds checker
1456 : : * function to make shure whether StrBufExtract_NextToken and friends have reached the end of the string.
1457 : : * @param Source our tokenbuffer
1458 : : * @param pStart the token iterator pointer to inspect
1459 : : * @returns whether the revolving pointer is inside of the search range
1460 : : */
1461 : 0 : int StrBufHaveNextToken(const StrBuf *Source, const char **pStart)
1462 : : {
1463 [ # # ][ # # ]: 0 : if ((Source == NULL) ||
[ # # ]
1464 : 0 : (*pStart == StrBufNOTNULL) ||
1465 : 0 : (Source->BufUsed == 0))
1466 : : {
1467 : 0 : return 0;
1468 : : }
1469 [ # # ]: 0 : if (*pStart == NULL)
1470 : : {
1471 : 0 : return 1;
1472 : : }
1473 [ # # ]: 0 : else if (*pStart > Source->buf + Source->BufUsed)
1474 : : {
1475 : 0 : return 0;
1476 : : }
1477 [ # # ]: 0 : else if (*pStart <= Source->buf)
1478 : : {
1479 : 0 : return 0;
1480 : : }
1481 : :
1482 : 0 : return 1;
1483 : : }
1484 : :
1485 : : /**
1486 : : * @ingroup StrBuf_NextTokenizer
1487 : : * @brief a string tokenizer
1488 : : * @param dest Destination StringBuffer
1489 : : * @param Source StringBuffer to read into
1490 : : * @param pStart pointer to the end of the last token. Feed with NULL on start.
1491 : : * @param separator tokenizer
1492 : : * @returns -1 if not found, else length of token.
1493 : : */
1494 : 18 : int StrBufExtract_NextToken(StrBuf *dest, const StrBuf *Source, const char **pStart, char separator)
1495 : : {
1496 : : const char *s; /* source */
1497 : : const char *EndBuffer; /* end stop of source buffer */
1498 : 18 : int current_token = 0; /* token currently being processed */
1499 : 18 : int len = 0; /* running total length of extracted string */
1500 : :
1501 [ + - ][ - + ]: 18 : if ((Source == NULL) ||
1502 : 18 : (Source->BufUsed == 0) )
1503 : : {
1504 : 0 : *pStart = StrBufNOTNULL;
1505 : 0 : return -1;
1506 : : }
1507 : :
1508 : 18 : EndBuffer = Source->buf + Source->BufUsed;
1509 : :
1510 [ + - ]: 18 : if (dest != NULL)
1511 : : {
1512 : 18 : dest->buf[0] = '\0';
1513 : 18 : dest->BufUsed = 0;
1514 : : }
1515 : : else
1516 : : {
1517 : 0 : *pStart = EndBuffer + 1;
1518 : 0 : return -1;
1519 : : }
1520 : :
1521 [ + + ]: 18 : if (*pStart == NULL)
1522 : : {
1523 : 12 : *pStart = Source->buf; /* we're starting to examine this buffer. */
1524 : : }
1525 [ + - ][ - + ]: 6 : else if ((*pStart < Source->buf) ||
1526 : 6 : (*pStart > EndBuffer ) )
1527 : : {
1528 : 0 : return -1; /* no more tokens to find. */
1529 : : }
1530 : :
1531 : 18 : s = *pStart;
1532 : : /* start to find the next token */
1533 [ + + ][ + + ]: 76 : while ((s <= EndBuffer) &&
1534 : : (current_token == 0) )
1535 : : {
1536 [ + + ]: 58 : if (*s == separator)
1537 : : {
1538 : : /* we found the next token */
1539 : 7 : ++current_token;
1540 : : }
1541 : :
1542 [ - + ]: 58 : if (len >= dest->BufSize)
1543 : : {
1544 : : /* our Dest-buffer isn't big enough, increase it. */
1545 : 0 : dest->BufUsed = len;
1546 : :
1547 [ # # ]: 0 : if (IncreaseBuf(dest, 1, -1) < 0) {
1548 : : /* WHUT? no more mem? bail out. */
1549 : 0 : s = EndBuffer;
1550 : 0 : dest->BufUsed --;
1551 : 0 : break;
1552 : : }
1553 : : }
1554 : :
1555 [ + + ][ + + ]: 58 : if ( (current_token == 0 ) && /* are we in our target token? */
[ + - ]
1556 : 51 : (!IsEmptyStr(s) ) &&
1557 : 40 : (separator != *s) ) /* don't copy the token itself */
1558 : : {
1559 : 40 : dest->buf[len] = *s; /* Copy the payload */
1560 : 40 : ++len; /* remember the bigger size. */
1561 : : }
1562 : :
1563 : 58 : ++s;
1564 : : }
1565 : :
1566 : : /* did we reach the end? */
1567 [ + + ]: 18 : if ((s > EndBuffer)) {
1568 : 11 : EndBuffer = StrBufNOTNULL;
1569 : 11 : *pStart = EndBuffer;
1570 : : }
1571 : : else {
1572 : 7 : *pStart = s; /* remember the position for the next run */
1573 : : }
1574 : :
1575 : : /* sanitize our extracted token */
1576 : 18 : dest->buf[len] = '\0';
1577 : 18 : dest->BufUsed = len;
1578 : :
1579 : 18 : return (len);
1580 : : }
1581 : :
1582 : :
1583 : : /**
1584 : : * @ingroup StrBuf_NextTokenizer
1585 : : * @brief a string tokenizer
1586 : : * @param Source StringBuffer to read from
1587 : : * @param pStart pointer to the end of the last token. Feed with NULL.
1588 : : * @param separator tokenizer character
1589 : : * @param nTokens number of tokens to fastforward over
1590 : : * @returns -1 if not found, else length of token.
1591 : : */
1592 : 0 : int StrBufSkip_NTokenS(const StrBuf *Source, const char **pStart, char separator, int nTokens)
1593 : : {
1594 : : const char *s, *EndBuffer; //* source * /
1595 : 0 : int len = 0; //* running total length of extracted string * /
1596 : 0 : int current_token = 0; //* token currently being processed * /
1597 : :
1598 [ # # ][ # # ]: 0 : if ((Source == NULL) ||
1599 : 0 : (Source->BufUsed ==0)) {
1600 : 0 : return(-1);
1601 : : }
1602 [ # # ]: 0 : if (nTokens == 0)
1603 : 0 : return Source->BufUsed;
1604 : :
1605 [ # # ]: 0 : if (*pStart == NULL)
1606 : 0 : *pStart = Source->buf;
1607 : :
1608 : 0 : EndBuffer = Source->buf + Source->BufUsed;
1609 : :
1610 [ # # ][ # # ]: 0 : if ((*pStart < Source->buf) ||
1611 : 0 : (*pStart > EndBuffer)) {
1612 : 0 : return (-1);
1613 : : }
1614 : :
1615 : :
1616 : 0 : s = *pStart;
1617 : :
1618 : : //cit_backtrace();
1619 : : //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
1620 : :
1621 [ # # ][ # # ]: 0 : while ((s<EndBuffer) && !IsEmptyStr(s)) {
1622 [ # # ]: 0 : if (*s == separator) {
1623 : 0 : ++current_token;
1624 : : }
1625 [ # # ]: 0 : if (current_token >= nTokens) {
1626 : 0 : break;
1627 : : }
1628 : 0 : ++s;
1629 : : }
1630 : 0 : *pStart = s;
1631 : 0 : (*pStart) ++;
1632 : :
1633 : 0 : return(len);
1634 : : }
1635 : :
1636 : : /**
1637 : : * @ingroup StrBuf_NextTokenizer
1638 : : * @brief a string tokenizer to fetch an integer
1639 : : * @param Source StringBuffer to read from
1640 : : * @param pStart Cursor on the tokenstring
1641 : : * @param separator tokenizer character
1642 : : * @returns 0 if not found, else integer representation of the token
1643 : : */
1644 : 0 : int StrBufExtractNext_int(const StrBuf* Source, const char **pStart, char separator)
1645 : : {
1646 : : StrBuf tmp;
1647 : : char buf[64];
1648 : :
1649 : 0 : tmp.buf = buf;
1650 : 0 : buf[0] = '\0';
1651 : 0 : tmp.BufSize = 64;
1652 : 0 : tmp.BufUsed = 0;
1653 : 0 : tmp.ConstBuf = 1;
1654 [ # # ]: 0 : if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0)
1655 : 0 : return(atoi(buf));
1656 : : else
1657 : 0 : return 0;
1658 : : }
1659 : :
1660 : : /**
1661 : : * @ingroup StrBuf_NextTokenizer
1662 : : * @brief a string tokenizer to fetch a long integer
1663 : : * @param Source StringBuffer to read from
1664 : : * @param pStart Cursor on the tokenstring
1665 : : * @param separator tokenizer character
1666 : : * @returns 0 if not found, else long integer representation of the token
1667 : : */
1668 : 10 : long StrBufExtractNext_long(const StrBuf* Source, const char **pStart, char separator)
1669 : : {
1670 : : StrBuf tmp;
1671 : : char buf[64];
1672 : :
1673 : 10 : tmp.buf = buf;
1674 : 10 : buf[0] = '\0';
1675 : 10 : tmp.BufSize = 64;
1676 : 10 : tmp.BufUsed = 0;
1677 : 10 : tmp.ConstBuf = 1;
1678 [ + - ]: 10 : if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0)
1679 : 10 : return(atoi(buf));
1680 : : else
1681 : 10 : return 0;
1682 : : }
1683 : :
1684 : :
1685 : : /**
1686 : : * @ingroup StrBuf_NextTokenizer
1687 : : * @brief a string tokenizer to fetch an unsigned long
1688 : : * @param Source StringBuffer to read from
1689 : : * @param pStart Cursor on the tokenstring
1690 : : * @param separator tokenizer character
1691 : : * @returns 0 if not found, else unsigned long representation of the token
1692 : : */
1693 : 0 : unsigned long StrBufExtractNext_unsigned_long(const StrBuf* Source, const char **pStart, char separator)
1694 : : {
1695 : : StrBuf tmp;
1696 : : char buf[64];
1697 : : char *pnum;
1698 : :
1699 : 0 : tmp.buf = buf;
1700 : 0 : buf[0] = '\0';
1701 : 0 : tmp.BufSize = 64;
1702 : 0 : tmp.BufUsed = 0;
1703 : 0 : tmp.ConstBuf = 1;
1704 [ # # ]: 0 : if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0) {
1705 : 0 : pnum = &buf[0];
1706 [ # # ]: 0 : if (*pnum == '-')
1707 : 0 : pnum ++;
1708 : 0 : return (unsigned long) atol(pnum);
1709 : : }
1710 : : else
1711 : 0 : return 0;
1712 : : }
1713 : :
1714 : :
1715 : :
1716 : :
1717 : :
1718 : : /*******************************************************************************
1719 : : * Escape Appending *
1720 : : *******************************************************************************/
1721 : :
1722 : : /**
1723 : : * @ingroup StrBuf_DeEnCoder
1724 : : * @brief Escape a string for feeding out as a URL while appending it to a Buffer
1725 : : * @param OutBuf the output buffer
1726 : : * @param In Buffer to encode
1727 : : * @param PlainIn way in from plain old c strings
1728 : : */
1729 : 0 : void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
1730 : : {
1731 : : const char *pch, *pche;
1732 : : char *pt, *pte;
1733 : : int len;
1734 : :
1735 [ # # ][ # # ]: 0 : if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
[ # # ]
1736 : 0 : return;
1737 [ # # ]: 0 : if (PlainIn != NULL) {
1738 : 0 : len = strlen(PlainIn);
1739 : 0 : pch = PlainIn;
1740 : 0 : pche = pch + len;
1741 : : }
1742 : : else {
1743 : 0 : pch = In->buf;
1744 : 0 : pche = pch + In->BufUsed;
1745 : 0 : len = In->BufUsed;
1746 : : }
1747 : :
1748 [ # # ]: 0 : if (len == 0)
1749 : 0 : return;
1750 : :
1751 : 0 : pt = OutBuf->buf + OutBuf->BufUsed;
1752 : 0 : pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
1753 : :
1754 [ # # ]: 0 : while (pch < pche) {
1755 [ # # ]: 0 : if (pt >= pte) {
1756 : 0 : IncreaseBuf(OutBuf, 1, -1);
1757 : 0 : pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
1758 : 0 : pt = OutBuf->buf + OutBuf->BufUsed;
1759 : : }
1760 : :
1761 [ # # ][ # # ]: 0 : if((*pch >= 'a' && *pch <= 'z') ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1762 : 0 : (*pch >= '@' && *pch <= 'Z') || /* @ A-Z */
1763 : 0 : (*pch >= '0' && *pch <= ':') || /* 0-9 : */
1764 : 0 : (*pch == '!') || (*pch == '_') ||
1765 : 0 : (*pch == ',') || (*pch == '.'))
1766 : : {
1767 : 0 : *(pt++) = *(pch++);
1768 : 0 : OutBuf->BufUsed++;
1769 : : }
1770 : : else {
1771 : 0 : *pt = '%';
1772 : 0 : *(pt + 1) = HexList[(unsigned char)*pch][0];
1773 : 0 : *(pt + 2) = HexList[(unsigned char)*pch][1];
1774 : 0 : pt += 3;
1775 : 0 : OutBuf->BufUsed += 3;
1776 : 0 : pch ++;
1777 : : }
1778 : : }
1779 : 0 : *pt = '\0';
1780 : : }
1781 : :
1782 : : /**
1783 : : * @ingroup StrBuf_DeEnCoder
1784 : : * @brief append a string in hex encoding to the buffer
1785 : : * @param OutBuf the output buffer
1786 : : * @param In Buffer to encode
1787 : : * @param PlainIn way in from plain old c strings
1788 : : */
1789 : 0 : void StrBufHexescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
1790 : : {
1791 : : const char *pch, *pche;
1792 : : char *pt, *pte;
1793 : : int len;
1794 : :
1795 [ # # ][ # # ]: 0 : if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
[ # # ]
1796 : 0 : return;
1797 [ # # ]: 0 : if (PlainIn != NULL) {
1798 : 0 : len = strlen(PlainIn);
1799 : 0 : pch = PlainIn;
1800 : 0 : pche = pch + len;
1801 : : }
1802 : : else {
1803 : 0 : pch = In->buf;
1804 : 0 : pche = pch + In->BufUsed;
1805 : 0 : len = In->BufUsed;
1806 : : }
1807 : :
1808 [ # # ]: 0 : if (len == 0)
1809 : 0 : return;
1810 : :
1811 : 0 : pt = OutBuf->buf + OutBuf->BufUsed;
1812 : 0 : pte = OutBuf->buf + OutBuf->BufSize - 3; /**< we max append 3 chars at once plus the \0 */
1813 : :
1814 [ # # ]: 0 : while (pch < pche) {
1815 [ # # ]: 0 : if (pt >= pte) {
1816 : 0 : IncreaseBuf(OutBuf, 1, -1);
1817 : 0 : pte = OutBuf->buf + OutBuf->BufSize - 3; /**< we max append 3 chars at once plus the \0 */
1818 : 0 : pt = OutBuf->buf + OutBuf->BufUsed;
1819 : : }
1820 : :
1821 : 0 : *pt = HexList[(unsigned char)*pch][0];
1822 : 0 : pt ++;
1823 : 0 : *pt = HexList[(unsigned char)*pch][1];
1824 : 0 : pt ++; pch ++; OutBuf->BufUsed += 2;
1825 : : }
1826 : 0 : *pt = '\0';
1827 : : }
1828 : :
1829 : : /**
1830 : : * @ingroup StrBuf_DeEnCoder
1831 : : * @brief Append a string, escaping characters which have meaning in HTML.
1832 : : *
1833 : : * @param Target target buffer
1834 : : * @param Source source buffer; set to NULL if you just have a C-String
1835 : : * @param PlainIn Plain-C string to append; set to NULL if unused
1836 : : * @param nbsp If nonzero, spaces are converted to non-breaking spaces.
1837 : : * @param nolinebreaks if set to 1, linebreaks are removed from the string.
1838 : : * if set to 2, linebreaks are replaced by <br/>
1839 : : */
1840 : 0 : long StrEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
1841 : : {
1842 : : const char *aptr, *eiptr;
1843 : : char *bptr, *eptr;
1844 : : long len;
1845 : :
1846 [ # # ][ # # ]: 0 : if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
[ # # ]
1847 : 0 : return -1;
1848 : :
1849 [ # # ]: 0 : if (PlainIn != NULL) {
1850 : 0 : aptr = PlainIn;
1851 : 0 : len = strlen(PlainIn);
1852 : 0 : eiptr = aptr + len;
1853 : : }
1854 : : else {
1855 : 0 : aptr = Source->buf;
1856 : 0 : eiptr = aptr + Source->BufUsed;
1857 : 0 : len = Source->BufUsed;
1858 : : }
1859 : :
1860 [ # # ]: 0 : if (len == 0)
1861 : 0 : return -1;
1862 : :
1863 : 0 : bptr = Target->buf + Target->BufUsed;
1864 : 0 : eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
1865 : :
1866 [ # # ]: 0 : while (aptr < eiptr){
1867 [ # # ]: 0 : if(bptr >= eptr) {
1868 : 0 : IncreaseBuf(Target, 1, -1);
1869 : 0 : eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
1870 : 0 : bptr = Target->buf + Target->BufUsed;
1871 : : }
1872 [ # # ]: 0 : if (*aptr == '<') {
1873 : 0 : memcpy(bptr, "<", 4);
1874 : 0 : bptr += 4;
1875 : 0 : Target->BufUsed += 4;
1876 : : }
1877 [ # # ]: 0 : else if (*aptr == '>') {
1878 : 0 : memcpy(bptr, ">", 4);
1879 : 0 : bptr += 4;
1880 : 0 : Target->BufUsed += 4;
1881 : : }
1882 [ # # ]: 0 : else if (*aptr == '&') {
1883 : 0 : memcpy(bptr, "&", 5);
1884 : 0 : bptr += 5;
1885 : 0 : Target->BufUsed += 5;
1886 : : }
1887 [ # # ]: 0 : else if (*aptr == '"') {
1888 : 0 : memcpy(bptr, """, 6);
1889 : 0 : bptr += 6;
1890 : 0 : Target->BufUsed += 6;
1891 : : }
1892 [ # # ]: 0 : else if (*aptr == '\'') {
1893 : 0 : memcpy(bptr, "'", 5);
1894 : 0 : bptr += 5;
1895 : 0 : Target->BufUsed += 5;
1896 : : }
1897 [ # # ]: 0 : else if (*aptr == LB) {
1898 : 0 : *bptr = '<';
1899 : 0 : bptr ++;
1900 : 0 : Target->BufUsed ++;
1901 : : }
1902 [ # # ]: 0 : else if (*aptr == RB) {
1903 : 0 : *bptr = '>';
1904 : 0 : bptr ++;
1905 : 0 : Target->BufUsed ++;
1906 : : }
1907 [ # # ]: 0 : else if (*aptr == QU) {
1908 : 0 : *bptr ='"';
1909 : 0 : bptr ++;
1910 : 0 : Target->BufUsed ++;
1911 : : }
1912 [ # # ][ # # ]: 0 : else if ((*aptr == 32) && (nbsp == 1)) {
1913 : 0 : memcpy(bptr, " ", 6);
1914 : 0 : bptr += 6;
1915 : 0 : Target->BufUsed += 6;
1916 : : }
1917 [ # # ][ # # ]: 0 : else if ((*aptr == '\n') && (nolinebreaks == 1)) {
1918 : 0 : *bptr='\0'; /* nothing */
1919 : : }
1920 [ # # ][ # # ]: 0 : else if ((*aptr == '\n') && (nolinebreaks == 2)) {
1921 : 0 : memcpy(bptr, "<br/>", 11);
1922 : 0 : bptr += 11;
1923 : 0 : Target->BufUsed += 11;
1924 : : }
1925 : :
1926 : :
1927 [ # # ][ # # ]: 0 : else if ((*aptr == '\r') && (nolinebreaks != 0)) {
1928 : 0 : *bptr='\0'; /* nothing */
1929 : : }
1930 : : else{
1931 : 0 : *bptr = *aptr;
1932 : 0 : bptr++;
1933 : 0 : Target->BufUsed ++;
1934 : : }
1935 : 0 : aptr ++;
1936 : : }
1937 : 0 : *bptr = '\0';
1938 [ # # ][ # # ]: 0 : if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
1939 : 0 : return -1;
1940 : 0 : return Target->BufUsed;
1941 : : }
1942 : :
1943 : : /**
1944 : : * @ingroup StrBuf_DeEnCoder
1945 : : * @brief Append a string, escaping characters which have meaning in HTML.
1946 : : * Converts linebreaks into blanks; escapes single quotes
1947 : : * @param Target target buffer
1948 : : * @param Source source buffer; set to NULL if you just have a C-String
1949 : : * @param PlainIn Plain-C string to append; set to NULL if unused
1950 : : */
1951 : 0 : void StrMsgEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
1952 : : {
1953 : : const char *aptr, *eiptr;
1954 : : char *tptr, *eptr;
1955 : : long len;
1956 : :
1957 [ # # ][ # # ]: 0 : if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
[ # # ]
1958 : 0 : return ;
1959 : :
1960 [ # # ]: 0 : if (PlainIn != NULL) {
1961 : 0 : aptr = PlainIn;
1962 : 0 : len = strlen(PlainIn);
1963 : 0 : eiptr = aptr + len;
1964 : : }
1965 : : else {
1966 : 0 : aptr = Source->buf;
1967 : 0 : eiptr = aptr + Source->BufUsed;
1968 : 0 : len = Source->BufUsed;
1969 : : }
1970 : :
1971 [ # # ]: 0 : if (len == 0)
1972 : 0 : return;
1973 : :
1974 : 0 : eptr = Target->buf + Target->BufSize - 8;
1975 : 0 : tptr = Target->buf + Target->BufUsed;
1976 : :
1977 [ # # ]: 0 : while (aptr < eiptr){
1978 [ # # ]: 0 : if(tptr >= eptr) {
1979 : 0 : IncreaseBuf(Target, 1, -1);
1980 : 0 : eptr = Target->buf + Target->BufSize - 8;
1981 : 0 : tptr = Target->buf + Target->BufUsed;
1982 : : }
1983 : :
1984 [ # # ]: 0 : if (*aptr == '\n') {
1985 : 0 : *tptr = ' ';
1986 : 0 : Target->BufUsed++;
1987 : : }
1988 [ # # ]: 0 : else if (*aptr == '\r') {
1989 : 0 : *tptr = ' ';
1990 : 0 : Target->BufUsed++;
1991 : : }
1992 [ # # ]: 0 : else if (*aptr == '\'') {
1993 : 0 : *(tptr++) = '&';
1994 : 0 : *(tptr++) = '#';
1995 : 0 : *(tptr++) = '3';
1996 : 0 : *(tptr++) = '9';
1997 : 0 : *tptr = ';';
1998 : 0 : Target->BufUsed += 5;
1999 : : } else {
2000 : 0 : *tptr = *aptr;
2001 : 0 : Target->BufUsed++;
2002 : : }
2003 : 0 : tptr++; aptr++;
2004 : : }
2005 : 0 : *tptr = '\0';
2006 : : }
2007 : :
2008 : :
2009 : :
2010 : : /**
2011 : : * @ingroup StrBuf_DeEnCoder
2012 : : * @brief Append a string, escaping characters which have meaning in ICAL.
2013 : : * [\n,]
2014 : : * @param Target target buffer
2015 : : * @param Source source buffer; set to NULL if you just have a C-String
2016 : : * @param PlainIn Plain-C string to append; set to NULL if unused
2017 : : */
2018 : 0 : void StrIcalEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
2019 : : {
2020 : : const char *aptr, *eiptr;
2021 : : char *tptr, *eptr;
2022 : : long len;
2023 : :
2024 [ # # ][ # # ]: 0 : if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
[ # # ]
2025 : 0 : return ;
2026 : :
2027 [ # # ]: 0 : if (PlainIn != NULL) {
2028 : 0 : aptr = PlainIn;
2029 : 0 : len = strlen(PlainIn);
2030 : 0 : eiptr = aptr + len;
2031 : : }
2032 : : else {
2033 : 0 : aptr = Source->buf;
2034 : 0 : eiptr = aptr + Source->BufUsed;
2035 : 0 : len = Source->BufUsed;
2036 : : }
2037 : :
2038 [ # # ]: 0 : if (len == 0)
2039 : 0 : return;
2040 : :
2041 : 0 : eptr = Target->buf + Target->BufSize - 8;
2042 : 0 : tptr = Target->buf + Target->BufUsed;
2043 : :
2044 [ # # ]: 0 : while (aptr < eiptr){
2045 [ # # ]: 0 : if(tptr + 3 >= eptr) {
2046 : 0 : IncreaseBuf(Target, 1, -1);
2047 : 0 : eptr = Target->buf + Target->BufSize - 8;
2048 : 0 : tptr = Target->buf + Target->BufUsed;
2049 : : }
2050 : :
2051 [ # # ]: 0 : if (*aptr == '\n') {
2052 : 0 : *tptr = '\\';
2053 : 0 : Target->BufUsed++;
2054 : 0 : tptr++;
2055 : 0 : *tptr = 'n';
2056 : 0 : Target->BufUsed++;
2057 : : }
2058 [ # # ]: 0 : else if (*aptr == '\r') {
2059 : 0 : *tptr = '\\';
2060 : 0 : Target->BufUsed++;
2061 : 0 : tptr++;
2062 : 0 : *tptr = 'r';
2063 : 0 : Target->BufUsed++;
2064 : : }
2065 [ # # ]: 0 : else if (*aptr == ',') {
2066 : 0 : *tptr = '\\';
2067 : 0 : Target->BufUsed++;
2068 : 0 : tptr++;
2069 : 0 : *tptr = ',';
2070 : 0 : Target->BufUsed++;
2071 : : } else {
2072 : 0 : *tptr = *aptr;
2073 : 0 : Target->BufUsed++;
2074 : : }
2075 : 0 : tptr++; aptr++;
2076 : : }
2077 : 0 : *tptr = '\0';
2078 : : }
2079 : :
2080 : : /**
2081 : : * @ingroup StrBuf_DeEnCoder
2082 : : * @brief Append a string, escaping characters which have meaning in JavaScript strings .
2083 : : *
2084 : : * @param Target target buffer
2085 : : * @param Source source buffer; set to NULL if you just have a C-String
2086 : : * @param PlainIn Plain-C string to append; set to NULL if unused
2087 : : * @returns size of result or -1
2088 : : */
2089 : 89 : long StrECMAEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
2090 : : {
2091 : : const char *aptr, *eiptr;
2092 : : char *bptr, *eptr;
2093 : : long len;
2094 : :
2095 [ - + ][ # # ]: 89 : if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
[ - + ]
2096 : 0 : return -1;
2097 : :
2098 [ - + ]: 89 : if (PlainIn != NULL) {
2099 : 0 : aptr = PlainIn;
2100 : 0 : len = strlen(PlainIn);
2101 : 0 : eiptr = aptr + len;
2102 : : }
2103 : : else {
2104 : 89 : aptr = Source->buf;
2105 : 89 : eiptr = aptr + Source->BufUsed;
2106 : 89 : len = Source->BufUsed;
2107 : : }
2108 : :
2109 [ + + ]: 89 : if (len == 0)
2110 : 8 : return -1;
2111 : :
2112 : 81 : bptr = Target->buf + Target->BufUsed;
2113 : 81 : eptr = Target->buf + Target->BufSize - 3; /* our biggest unit to put in... */
2114 : :
2115 [ + + ]: 1179 : while (aptr < eiptr){
2116 [ + + ]: 1098 : if(bptr >= eptr) {
2117 : 3 : IncreaseBuf(Target, 1, -1);
2118 : 3 : eptr = Target->buf + Target->BufSize - 3;
2119 : 3 : bptr = Target->buf + Target->BufUsed;
2120 : : }
2121 [ - + ]: 1098 : if (*aptr == '"') {
2122 : 0 : *bptr = '\\';
2123 : 0 : bptr ++;
2124 : 0 : *bptr = '"';
2125 : 0 : bptr ++;
2126 : 0 : Target->BufUsed += 2;
2127 [ - + ]: 1098 : } else if (*aptr == '\\') {
2128 : 0 : *bptr = '\\';
2129 : 0 : bptr ++;
2130 : 0 : *bptr = '\\';
2131 : 0 : bptr ++;
2132 : 0 : Target->BufUsed += 2;
2133 : : }
2134 : : else{
2135 : 1098 : *bptr = *aptr;
2136 : 1098 : bptr++;
2137 : 1098 : Target->BufUsed ++;
2138 : : }
2139 : 1098 : aptr ++;
2140 : : }
2141 : 81 : *bptr = '\0';
2142 [ - + ][ # # ]: 81 : if ((bptr == eptr - 1 ) && !IsEmptyStr(aptr) )
2143 : 0 : return -1;
2144 : 89 : return Target->BufUsed;
2145 : : }
2146 : :
2147 : : /**
2148 : : * @ingroup StrBuf_DeEnCoder
2149 : : * @brief Append a string, escaping characters which have meaning in HTML + json.
2150 : : *
2151 : : * @param Target target buffer
2152 : : * @param Source source buffer; set to NULL if you just have a C-String
2153 : : * @param PlainIn Plain-C string to append; set to NULL if unused
2154 : : * @param nbsp If nonzero, spaces are converted to non-breaking spaces.
2155 : : * @param nolinebreaks if set to 1, linebreaks are removed from the string.
2156 : : * if set to 2, linebreaks are replaced by <br/>
2157 : : */
2158 : 0 : long StrHtmlEcmaEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
2159 : : {
2160 : : const char *aptr, *eiptr;
2161 : : char *bptr, *eptr;
2162 : : long len;
2163 : 0 : int IsUtf8Sequence = 0;
2164 : :
2165 [ # # ][ # # ]: 0 : if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
[ # # ]
2166 : 0 : return -1;
2167 : :
2168 [ # # ]: 0 : if (PlainIn != NULL) {
2169 : 0 : aptr = PlainIn;
2170 : 0 : len = strlen(PlainIn);
2171 : 0 : eiptr = aptr + len;
2172 : : }
2173 : : else {
2174 : 0 : aptr = Source->buf;
2175 : 0 : eiptr = aptr + Source->BufUsed;
2176 : 0 : len = Source->BufUsed;
2177 : : }
2178 : :
2179 [ # # ]: 0 : if (len == 0)
2180 : 0 : return -1;
2181 : :
2182 : 0 : bptr = Target->buf + Target->BufUsed;
2183 : 0 : eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
2184 : :
2185 [ # # ]: 0 : while (aptr < eiptr){
2186 [ # # ]: 0 : if(bptr >= eptr) {
2187 : 0 : IncreaseBuf(Target, 1, -1);
2188 : 0 : eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
2189 : 0 : bptr = Target->buf + Target->BufUsed;
2190 : : }
2191 [ # # ]: 0 : if (*aptr == '<') {
2192 : 0 : memcpy(bptr, "<", 4);
2193 : 0 : bptr += 4;
2194 : 0 : Target->BufUsed += 4;
2195 : : }
2196 [ # # ]: 0 : else if (*aptr == '>') {
2197 : 0 : memcpy(bptr, ">", 4);
2198 : 0 : bptr += 4;
2199 : 0 : Target->BufUsed += 4;
2200 : : }
2201 [ # # ]: 0 : else if (*aptr == '&') {
2202 : 0 : memcpy(bptr, "&", 5);
2203 : 0 : bptr += 5;
2204 : 0 : Target->BufUsed += 5;
2205 : : }
2206 [ # # ]: 0 : else if (*aptr == LB) {
2207 : 0 : *bptr = '<';
2208 : 0 : bptr ++;
2209 : 0 : Target->BufUsed ++;
2210 : : }
2211 [ # # ]: 0 : else if (*aptr == RB) {
2212 : 0 : *bptr = '>';
2213 : 0 : bptr ++;
2214 : 0 : Target->BufUsed ++;
2215 : : }
2216 [ # # ][ # # ]: 0 : else if ((*aptr == 32) && (nbsp == 1)) {
2217 : 0 : memcpy(bptr, " ", 6);
2218 : 0 : bptr += 6;
2219 : 0 : Target->BufUsed += 6;
2220 : : }
2221 [ # # ][ # # ]: 0 : else if ((*aptr == '\n') && (nolinebreaks == 1)) {
2222 : 0 : *bptr='\0'; /* nothing */
2223 : : }
2224 [ # # ][ # # ]: 0 : else if ((*aptr == '\n') && (nolinebreaks == 2)) {
2225 : 0 : memcpy(bptr, "<br/>", 11);
2226 : 0 : bptr += 11;
2227 : 0 : Target->BufUsed += 11;
2228 : : }
2229 : :
2230 [ # # ][ # # ]: 0 : else if ((*aptr == '\r') && (nolinebreaks != 0)) {
2231 : 0 : *bptr='\0'; /* nothing */
2232 : : }
2233 : :
2234 [ # # ][ # # ]: 0 : else if ((*aptr == '"') || (*aptr == QU)) {
2235 : 0 : *bptr = '\\';
2236 : 0 : bptr ++;
2237 : 0 : *bptr = '"';
2238 : 0 : bptr ++;
2239 : 0 : Target->BufUsed += 2;
2240 [ # # ]: 0 : } else if (*aptr == '\\') {
2241 : 0 : *bptr = '\\';
2242 : 0 : bptr ++;
2243 : 0 : *bptr = '\\';
2244 : 0 : bptr ++;
2245 : 0 : Target->BufUsed += 2;
2246 : : }
2247 : : else {
2248 [ # # ]: 0 : if (((unsigned char)*aptr) >= 0x20)
2249 : : {
2250 : 0 : IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(aptr, eiptr);
2251 : :
2252 : 0 : *bptr = *aptr;
2253 : 0 : Target->BufUsed ++;
2254 [ # # ]: 0 : while (IsUtf8Sequence > 1){
2255 [ # # ]: 0 : if(bptr + IsUtf8Sequence >= eptr) {
2256 : 0 : IncreaseBuf(Target, 1, -1);
2257 : 0 : eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
2258 : 0 : bptr = Target->buf + Target->BufUsed - 1;
2259 : : }
2260 : 0 : bptr++; aptr++;
2261 : 0 : IsUtf8Sequence --;
2262 : 0 : *bptr = *aptr;
2263 : 0 : Target->BufUsed ++;
2264 : : }
2265 : 0 : bptr++;
2266 : : }
2267 : :
2268 : : }
2269 : 0 : aptr ++;
2270 : : }
2271 : 0 : *bptr = '\0';
2272 [ # # ][ # # ]: 0 : if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
2273 : 0 : return -1;
2274 : 0 : return Target->BufUsed;
2275 : : }
2276 : :
2277 : : /**
2278 : : * @ingroup StrBuf_DeEnCoder
2279 : : * @brief unhide special chars hidden to the HTML escaper
2280 : : * @param target buffer to put the unescaped string in
2281 : : * @param source buffer to unescape
2282 : : */
2283 : 0 : void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source)
2284 : : {
2285 : : int a, b, len;
2286 : : char hex[3];
2287 : :
2288 [ # # ]: 0 : if (target != NULL)
2289 : 0 : FlushStrBuf(target);
2290 : :
2291 [ # # ][ # # ]: 0 : if (source == NULL ||target == NULL)
2292 : : {
2293 : 0 : return;
2294 : : }
2295 : :
2296 : 0 : len = source->BufUsed;
2297 [ # # ]: 0 : for (a = 0; a < len; ++a) {
2298 [ # # ]: 0 : if (target->BufUsed >= target->BufSize)
2299 : 0 : IncreaseBuf(target, 1, -1);
2300 : :
2301 [ # # ]: 0 : if (source->buf[a] == '=') {
2302 : 0 : hex[0] = source->buf[a + 1];
2303 : 0 : hex[1] = source->buf[a + 2];
2304 : 0 : hex[2] = 0;
2305 : 0 : b = 0;
2306 : 0 : sscanf(hex, "%02x", &b);
2307 : 0 : target->buf[target->BufUsed] = b;
2308 : 0 : target->buf[++target->BufUsed] = 0;
2309 : 0 : a += 2;
2310 : : }
2311 : : else {
2312 : 0 : target->buf[target->BufUsed] = source->buf[a];
2313 : 0 : target->buf[++target->BufUsed] = 0;
2314 : : }
2315 : : }
2316 : : }
2317 : :
2318 : :
2319 : : /**
2320 : : * @ingroup StrBuf_DeEnCoder
2321 : : * @brief hide special chars from the HTML escapers and friends
2322 : : * @param target buffer to put the escaped string in
2323 : : * @param source buffer to escape
2324 : : */
2325 : 0 : void StrBufEUid_escapize(StrBuf *target, const StrBuf *source)
2326 : : {
2327 : : int i, len;
2328 : :
2329 [ # # ]: 0 : if (target != NULL)
2330 : 0 : FlushStrBuf(target);
2331 : :
2332 [ # # ][ # # ]: 0 : if (source == NULL ||target == NULL)
2333 : : {
2334 : 0 : return;
2335 : : }
2336 : :
2337 : 0 : len = source->BufUsed;
2338 [ # # ]: 0 : for (i=0; i<len; ++i) {
2339 [ # # ]: 0 : if (target->BufUsed + 4 >= target->BufSize)
2340 : 0 : IncreaseBuf(target, 1, -1);
2341 [ # # ][ # # ]: 0 : if ( (isalnum(source->buf[i])) ||
[ # # ]
2342 : 0 : (source->buf[i]=='-') ||
2343 : 0 : (source->buf[i]=='_') ) {
2344 : 0 : target->buf[target->BufUsed++] = source->buf[i];
2345 : : }
2346 : : else {
2347 : 0 : sprintf(&target->buf[target->BufUsed],
2348 : : "=%02X",
2349 : 0 : (0xFF &source->buf[i]));
2350 : 0 : target->BufUsed += 3;
2351 : : }
2352 : : }
2353 : 0 : target->buf[target->BufUsed + 1] = '\0';
2354 : : }
2355 : :
2356 : :
2357 : : /*******************************************************************************
2358 : : * Quoted Printable de/encoding *
2359 : : *******************************************************************************/
2360 : :
2361 : : /**
2362 : : * @ingroup StrBuf_DeEnCoder
2363 : : * @brief decode a buffer from base 64 encoding; destroys original
2364 : : * @param Buf Buffor to transform
2365 : : */
2366 : 0 : int StrBufDecodeBase64(StrBuf *Buf)
2367 : : {
2368 : : char *xferbuf;
2369 : : size_t siz;
2370 [ # # ]: 0 : if (Buf == NULL) return -1;
2371 : :
2372 : 0 : xferbuf = (char*) malloc(Buf->BufSize);
2373 : 0 : *xferbuf = '\0';
2374 : 0 : siz = CtdlDecodeBase64(xferbuf,
2375 : 0 : Buf->buf,
2376 : 0 : Buf->BufUsed);
2377 : 0 : free(Buf->buf);
2378 : 0 : Buf->buf = xferbuf;
2379 : 0 : Buf->BufUsed = siz;
2380 : 0 : return siz;
2381 : : }
2382 : :
2383 : : /**
2384 : : * @ingroup StrBuf_DeEnCoder
2385 : : * @brief decode a buffer from base 64 encoding; destroys original
2386 : : * @param Buf Buffor to transform
2387 : : */
2388 : 0 : int StrBufDecodeHex(StrBuf *Buf)
2389 : : {
2390 : : unsigned int ch;
2391 : : char *pch, *pche, *pchi;
2392 : :
2393 [ # # ]: 0 : if (Buf == NULL) return -1;
2394 : :
2395 : 0 : pch = pchi = Buf->buf;
2396 : 0 : pche = pch + Buf->BufUsed;
2397 : :
2398 [ # # ]: 0 : while (pchi < pche){
2399 : 0 : ch = decode_hex(pchi);
2400 : 0 : *pch = ch;
2401 : 0 : pch ++;
2402 : 0 : pchi += 2;
2403 : : }
2404 : :
2405 : 0 : *pch = '\0';
2406 : 0 : Buf->BufUsed = pch - Buf->buf;
2407 : 0 : return Buf->BufUsed;
2408 : : }
2409 : :
2410 : : /**
2411 : : * @ingroup StrBuf_DeEnCoder
2412 : : * @brief replace all chars >0x20 && < 0x7F with Mute
2413 : : * @param Mute char to put over invalid chars
2414 : : * @param Buf Buffor to transform
2415 : : */
2416 : 0 : int StrBufSanitizeAscii(StrBuf *Buf, const char Mute)
2417 : : {
2418 : : unsigned char *pch;
2419 : :
2420 [ # # ]: 0 : if (Buf == NULL) return -1;
2421 : 0 : pch = (unsigned char *)Buf->buf;
2422 [ # # ]: 0 : while (pch < (unsigned char *)Buf->buf + Buf->BufUsed) {
2423 [ # # ][ # # ]: 0 : if ((*pch < 0x20) || (*pch > 0x7F))
2424 : 0 : *pch = Mute;
2425 : 0 : pch ++;
2426 : : }
2427 : 0 : return Buf->BufUsed;
2428 : : }
2429 : :
2430 : :
2431 : : /**
2432 : : * @ingroup StrBuf_DeEnCoder
2433 : : * @brief remove escaped strings from i.e. the url string (like %20 for blanks)
2434 : : * @param Buf Buffer to translate
2435 : : * @param StripBlanks Reduce several blanks to one?
2436 : : */
2437 : 0 : long StrBufUnescape(StrBuf *Buf, int StripBlanks)
2438 : : {
2439 : : int a, b;
2440 : : char hex[3];
2441 : : long len;
2442 : :
2443 [ # # ]: 0 : if (Buf == NULL)
2444 : 0 : return -1;
2445 : :
2446 [ # # ][ # # ]: 0 : while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
2447 : 0 : Buf->buf[Buf->BufUsed - 1] = '\0';
2448 : 0 : Buf->BufUsed --;
2449 : : }
2450 : :
2451 : 0 : a = 0;
2452 [ # # ]: 0 : while (a < Buf->BufUsed) {
2453 [ # # ]: 0 : if (Buf->buf[a] == '+')
2454 : 0 : Buf->buf[a] = ' ';
2455 [ # # ]: 0 : else if (Buf->buf[a] == '%') {
2456 : : /* don't let % chars through, rather truncate the input. */
2457 [ # # ]: 0 : if (a + 2 > Buf->BufUsed) {
2458 : 0 : Buf->buf[a] = '\0';
2459 : 0 : Buf->BufUsed = a;
2460 : : }
2461 : : else {
2462 : 0 : hex[0] = Buf->buf[a + 1];
2463 : 0 : hex[1] = Buf->buf[a + 2];
2464 : 0 : hex[2] = 0;
2465 : 0 : b = 0;
2466 : 0 : sscanf(hex, "%02x", &b);
2467 : 0 : Buf->buf[a] = (char) b;
2468 : 0 : len = Buf->BufUsed - a - 2;
2469 [ # # ]: 0 : if (len > 0)
2470 : 0 : memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
2471 : :
2472 : 0 : Buf->BufUsed -=2;
2473 : : }
2474 : : }
2475 : 0 : a++;
2476 : : }
2477 : 0 : return a;
2478 : : }
2479 : :
2480 : :
2481 : : /**
2482 : : * @ingroup StrBuf_DeEnCoder
2483 : : * @brief RFC2047-encode a header field if necessary.
2484 : : * If no non-ASCII characters are found, the string
2485 : : * will be copied verbatim without encoding.
2486 : : *
2487 : : * @param target Target buffer.
2488 : : * @param source Source string to be encoded.
2489 : : * @returns encoded length; -1 if non success.
2490 : : */
2491 : 0 : int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
2492 : : {
2493 : 0 : const char headerStr[] = "=?UTF-8?Q?";
2494 : 0 : int need_to_encode = 0;
2495 : 0 : int i = 0;
2496 : : unsigned char ch;
2497 : :
2498 [ # # ][ # # ]: 0 : if ((source == NULL) ||
2499 : : (target == NULL))
2500 : 0 : return -1;
2501 : :
2502 [ # # ][ # # ]: 0 : while ((i < source->BufUsed) &&
[ # # ]
2503 : 0 : (!IsEmptyStr (&source->buf[i])) &&
2504 : : (need_to_encode == 0)) {
2505 [ # # ][ # # ]: 0 : if (((unsigned char) source->buf[i] < 32) ||
2506 : 0 : ((unsigned char) source->buf[i] > 126)) {
2507 : 0 : need_to_encode = 1;
2508 : : }
2509 : 0 : i++;
2510 : : }
2511 : :
2512 [ # # ]: 0 : if (!need_to_encode) {
2513 [ # # ]: 0 : if (*target == NULL) {
2514 : 0 : *target = NewStrBufPlain(source->buf, source->BufUsed);
2515 : : }
2516 : : else {
2517 : 0 : FlushStrBuf(*target);
2518 : 0 : StrBufAppendBuf(*target, source, 0);
2519 : : }
2520 : 0 : return (*target)->BufUsed;
2521 : : }
2522 [ # # ]: 0 : if (*target == NULL)
2523 : 0 : *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
2524 [ # # ]: 0 : else if (sizeof(headerStr) + source->BufUsed >= (*target)->BufSize)
2525 : 0 : IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
2526 : 0 : memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
2527 : 0 : (*target)->BufUsed = sizeof(headerStr) - 1;
2528 [ # # ]: 0 : for (i=0; (i < source->BufUsed); ++i) {
2529 [ # # ]: 0 : if ((*target)->BufUsed + 4 >= (*target)->BufSize)
2530 : 0 : IncreaseBuf(*target, 1, 0);
2531 : 0 : ch = (unsigned char) source->buf[i];
2532 [ # # ][ # # ]: 0 : if ((ch < 32) || (ch > 126) || (ch == 61)) {
[ # # ]
2533 : 0 : sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
2534 : 0 : (*target)->BufUsed += 3;
2535 : : }
2536 : : else {
2537 : 0 : (*target)->buf[(*target)->BufUsed] = ch;
2538 : 0 : (*target)->BufUsed++;
2539 : : }
2540 : : }
2541 : :
2542 [ # # ]: 0 : if ((*target)->BufUsed + 4 >= (*target)->BufSize)
2543 : 0 : IncreaseBuf(*target, 1, 0);
2544 : :
2545 : 0 : (*target)->buf[(*target)->BufUsed++] = '?';
2546 : 0 : (*target)->buf[(*target)->BufUsed++] = '=';
2547 : 0 : (*target)->buf[(*target)->BufUsed] = '\0';
2548 : 0 : return (*target)->BufUsed;;
2549 : : }
2550 : :
2551 : :
2552 : :
2553 : 0 : static void AddRecipient(StrBuf *Target,
2554 : : StrBuf *UserName,
2555 : : StrBuf *EmailAddress,
2556 : : StrBuf *EncBuf)
2557 : : {
2558 : 0 : int QuoteMe = 0;
2559 : :
2560 [ # # ]: 0 : if (StrLength(Target) > 0) StrBufAppendBufPlain(Target, HKEY(", "), 0);
2561 [ # # ]: 0 : if (strchr(ChrPtr(UserName), ',') != NULL) QuoteMe = 1;
2562 : :
2563 [ # # ]: 0 : if (QuoteMe) StrBufAppendBufPlain(Target, HKEY("\""), 0);
2564 : 0 : StrBufRFC2047encode(&EncBuf, UserName);
2565 : 0 : StrBufAppendBuf(Target, EncBuf, 0);
2566 [ # # ]: 0 : if (QuoteMe) StrBufAppendBufPlain(Target, HKEY("\" "), 0);
2567 : 0 : else StrBufAppendBufPlain(Target, HKEY(" "), 0);
2568 : :
2569 [ # # ]: 0 : if (StrLength(EmailAddress) > 0){
2570 : 0 : StrBufAppendBufPlain(Target, HKEY("<"), 0);
2571 : 0 : StrBufAppendBuf(Target, EmailAddress, 0); /* TODO: what about IDN???? */
2572 : 0 : StrBufAppendBufPlain(Target, HKEY(">"), 0);
2573 : : }
2574 : 0 : }
2575 : :
2576 : :
2577 : : /**
2578 : : * \brief QP encode parts of an email TO/CC/BCC vector, and strip/filter invalid parts
2579 : : * \param Recp Source list of email recipients
2580 : : * \param UserName Temporary buffer for internal use; Please provide valid buffer.
2581 : : * \param EmailAddress Temporary buffer for internal use; Please provide valid buffer.
2582 : : * \param EncBuf Temporary buffer for internal use; Please provide valid buffer.
2583 : : * \returns encoded & sanitized buffer with the contents of Recp; Caller owns this memory.
2584 : : */
2585 : 0 : StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
2586 : : StrBuf *UserName,
2587 : : StrBuf *EmailAddress,
2588 : : StrBuf *EncBuf)
2589 : : {
2590 : : StrBuf *Target;
2591 : : int need_to_encode;
2592 : :
2593 : : const char *pch, *pche;
2594 : : const char *UserStart, *UserEnd, *EmailStart, *EmailEnd, *At;
2595 : :
2596 [ # # ][ # # ]: 0 : if ((Recp == NULL) || (StrLength(Recp) == 0))
2597 : 0 : return NULL;
2598 : :
2599 : 0 : need_to_encode = 0;
2600 : 0 : pch = ChrPtr(Recp);
2601 : 0 : pche = pch + StrLength(Recp);
2602 : :
2603 [ # # ]: 0 : if (!CheckEncode(pch, -1, pche))
2604 : 0 : return NewStrBufDup(Recp);
2605 : :
2606 : 0 : Target = NewStrBufPlain(NULL, StrLength(Recp));
2607 : :
2608 [ # # ][ # # ]: 0 : while ((pch != NULL) && (pch < pche))
2609 : : {
2610 : 0 : int ColonOk = 0;
2611 : :
2612 [ # # ]: 0 : while (isspace(*pch)) pch++;
2613 : 0 : UserStart = UserEnd = EmailStart = EmailEnd = NULL;
2614 : :
2615 [ # # ][ # # ]: 0 : if ((*pch == '"') || (*pch == '\'')) {
2616 : 0 : UserStart = pch + 1;
2617 : :
2618 : 0 : UserEnd = strchr(UserStart, *pch);
2619 [ # # ]: 0 : if (UserEnd == NULL)
2620 : 0 : break; ///TODO: Userfeedback??
2621 : 0 : EmailStart = UserEnd + 1;
2622 [ # # ]: 0 : while (isspace(*EmailStart))
2623 : 0 : EmailStart++;
2624 [ # # ]: 0 : if (UserEnd == UserStart) {
2625 : 0 : UserStart = UserEnd = NULL;
2626 : : }
2627 : :
2628 [ # # ]: 0 : if (*EmailStart == '<') {
2629 : 0 : EmailStart++;
2630 : 0 : EmailEnd = strchr(EmailStart, '>');
2631 [ # # ]: 0 : if (EmailEnd == NULL)
2632 : 0 : EmailEnd = strchr(EmailStart, ',');
2633 : :
2634 : : }
2635 : : else {
2636 : 0 : EmailEnd = strchr(EmailStart, ',');
2637 : : }
2638 [ # # ]: 0 : if (EmailEnd == NULL)
2639 : 0 : EmailEnd = pche;
2640 : 0 : pch = EmailEnd + 1;
2641 : 0 : ColonOk = 1;
2642 : : }
2643 : : else {
2644 : 0 : int gt = 0;
2645 : 0 : UserStart = pch;
2646 : 0 : EmailEnd = strchr(UserStart, ',');
2647 [ # # ]: 0 : if (EmailEnd == NULL) {
2648 : 0 : EmailEnd = strchr(pch, '>');
2649 : 0 : pch = NULL;
2650 [ # # ]: 0 : if (EmailEnd != NULL) {
2651 : 0 : gt = 1;
2652 : : }
2653 : : else {
2654 : 0 : EmailEnd = pche;
2655 : : }
2656 : : }
2657 : : else {
2658 : :
2659 : 0 : pch = EmailEnd + 1;
2660 [ # # ][ # # ]: 0 : while ((EmailEnd > UserStart) && !gt &&
[ # # ]
[ # # # # ]
2661 : 0 : ((*EmailEnd == ',') ||
2662 : 0 : (*EmailEnd == '>') ||
2663 : 0 : (isspace(*EmailEnd))))
2664 : : {
2665 [ # # ]: 0 : if (*EmailEnd == '>')
2666 : 0 : gt = 1;
2667 : : else
2668 : 0 : EmailEnd--;
2669 : : }
2670 [ # # ]: 0 : if (EmailEnd == UserStart)
2671 : 0 : break;
2672 : : }
2673 [ # # ]: 0 : if (gt) {
2674 : 0 : EmailStart = strchr(UserStart, '<');
2675 [ # # ][ # # ]: 0 : if ((EmailStart == NULL) || (EmailStart > EmailEnd))
2676 : : break;
2677 : 0 : UserEnd = EmailStart;
2678 : :
2679 [ # # # # ]: 0 : while ((UserEnd > UserStart) &&
2680 : 0 : isspace (*(UserEnd - 1)))
2681 : 0 : UserEnd --;
2682 : 0 : EmailStart ++;
2683 [ # # ]: 0 : if (UserStart >= UserEnd)
2684 : 0 : UserStart = UserEnd = NULL;
2685 : 0 : At = strchr(EmailStart, '@');
2686 : : }
2687 : : else { /* this is a local recipient... no domain, just a realname */
2688 : 0 : EmailStart = UserStart;
2689 : 0 : At = strchr(EmailStart, '@');
2690 [ # # ]: 0 : if (At == NULL) {
2691 : 0 : UserEnd = EmailEnd;
2692 : 0 : EmailEnd = NULL;
2693 : : }
2694 : : else {
2695 : 0 : EmailStart = UserStart;
2696 : 0 : UserStart = NULL;
2697 : : }
2698 : : }
2699 : : }
2700 : :
2701 [ # # ][ # # ]: 0 : if ((UserStart != NULL) && (UserEnd != NULL))
2702 : 0 : StrBufPlain(UserName, UserStart, UserEnd - UserStart);
2703 [ # # ][ # # ]: 0 : else if ((UserStart != NULL) && (UserEnd == NULL))
2704 : 0 : StrBufPlain(UserName, UserStart, UserEnd - UserStart);
2705 : : else
2706 : 0 : FlushStrBuf(UserName);
2707 : :
2708 [ # # ][ # # ]: 0 : if ((EmailStart != NULL) && (EmailEnd != NULL))
2709 : 0 : StrBufPlain(EmailAddress, EmailStart, EmailEnd - EmailStart);
2710 [ # # ][ # # ]: 0 : else if ((EmailStart != NULL) && (EmailEnd == NULL))
2711 : 0 : StrBufPlain(EmailAddress, EmailStart, EmailEnd - pche);
2712 : : else
2713 : 0 : FlushStrBuf(EmailAddress);
2714 : :
2715 : 0 : AddRecipient(Target, UserName, EmailAddress, EncBuf);
2716 : :
2717 [ # # ]: 0 : if (pch == NULL)
2718 : 0 : break;
2719 : :
2720 [ # # ][ # # ]: 0 : if ((pch != NULL) && (*pch == ','))
2721 : 0 : pch ++;
2722 [ # # ][ # # ]: 0 : if (pch != NULL) while (isspace(*pch))
2723 : 0 : pch ++;
2724 : : }
2725 : 0 : return Target;
2726 : : }
2727 : :
2728 : :
2729 : : /**
2730 : : * @ingroup StrBuf
2731 : : * @brief replaces all occurances of 'search' by 'replace'
2732 : : * @param buf Buffer to modify
2733 : : * @param search character to search
2734 : : * @param replace character to replace search by
2735 : : */
2736 : 0 : void StrBufReplaceChars(StrBuf *buf, char search, char replace)
2737 : : {
2738 : : long i;
2739 [ # # ]: 0 : if (buf == NULL)
2740 : 0 : return;
2741 [ # # ]: 0 : for (i=0; i<buf->BufUsed; i++)
2742 [ # # ]: 0 : if (buf->buf[i] == search)
2743 : 0 : buf->buf[i] = replace;
2744 : :
2745 : : }
2746 : :
2747 : : /**
2748 : : * @ingroup StrBuf
2749 : : * @brief removes all \r s from the string, or replaces them with \n if its not a combination of both.
2750 : : * @param buf Buffer to modify
2751 : : */
2752 : 0 : void StrBufToUnixLF(StrBuf *buf)
2753 : : {
2754 : : char *pche, *pchS, *pchT;
2755 [ # # ]: 0 : if (buf == NULL)
2756 : 0 : return;
2757 : :
2758 : 0 : pche = buf->buf + buf->BufUsed;
2759 : 0 : pchS = pchT = buf->buf;
2760 [ # # ]: 0 : while (pchS < pche)
2761 : : {
2762 [ # # ]: 0 : if (*pchS == '\r')
2763 : : {
2764 : 0 : pchS ++;
2765 [ # # ]: 0 : if (*pchS != '\n') {
2766 : 0 : *pchT = '\n';
2767 : 0 : pchT++;
2768 : : }
2769 : : }
2770 : 0 : *pchT = *pchS;
2771 : 0 : pchT++; pchS++;
2772 : : }
2773 : 0 : *pchT = '\0';
2774 : 0 : buf->BufUsed = pchT - buf->buf;
2775 : : }
2776 : :
2777 : :
2778 : : /*******************************************************************************
2779 : : * Iconv Wrapper; RFC822 de/encoding *
2780 : : *******************************************************************************/
2781 : :
2782 : : /**
2783 : : * @ingroup StrBuf_DeEnCoder
2784 : : * @brief Wrapper around iconv_open()
2785 : : * Our version adds aliases for non-standard Microsoft charsets
2786 : : * such as 'MS950', aliasing them to names like 'CP950'
2787 : : *
2788 : : * @param tocode Target encoding
2789 : : * @param fromcode Source encoding
2790 : : * @param pic anonimized pointer to iconv struct
2791 : : */
2792 : 25 : void ctdl_iconv_open(const char *tocode, const char *fromcode, void *pic)
2793 : : {
2794 : : #ifdef HAVE_ICONV
2795 : 25 : iconv_t ic = (iconv_t)(-1) ;
2796 : 25 : ic = iconv_open(tocode, fromcode);
2797 [ - + ]: 25 : if (ic == (iconv_t)(-1) ) {
2798 : : char alias_fromcode[64];
2799 [ # # ][ # # ]: 0 : if ( (strlen(fromcode) == 5) && (!strncasecmp(fromcode, "MS", 2)) ) {
2800 : 0 : safestrncpy(alias_fromcode, fromcode, sizeof alias_fromcode);
2801 : 0 : alias_fromcode[0] = 'C';
2802 : 0 : alias_fromcode[1] = 'P';
2803 : 0 : ic = iconv_open(tocode, alias_fromcode);
2804 : : }
2805 : : }
2806 : 25 : *(iconv_t *)pic = ic;
2807 : : #endif
2808 : 25 : }
2809 : :
2810 : :
2811 : : /**
2812 : : * @ingroup StrBuf_DeEnCoder
2813 : : * @brief find one chunk of a RFC822 encoded string
2814 : : * @param Buffer where to search
2815 : : * @param bptr where to start searching
2816 : : * @returns found position, NULL if none.
2817 : : */
2818 : 20 : static inline const char *FindNextEnd (const StrBuf *Buf, const char *bptr)
2819 : : {
2820 : : const char * end;
2821 : : /* Find the next ?Q? */
2822 [ - + ]: 20 : if (Buf->BufUsed - (bptr - Buf->buf) < 6)
2823 : 0 : return NULL;
2824 : :
2825 : 20 : end = strchr(bptr + 2, '?');
2826 : :
2827 [ - + ]: 20 : if (end == NULL)
2828 : 0 : return NULL;
2829 : :
2830 [ + - ][ + + ]: 20 : if ((Buf->BufUsed - (end - Buf->buf) > 3) &&
[ + - ][ + - ]
2831 : 36 : ((*(end + 1) == 'B') || (*(end + 1) == 'Q')) &&
2832 : 20 : (*(end + 2) == '?')) {
2833 : : /* skip on to the end of the cluster, the next ?= */
2834 : 20 : end = strstr(end + 3, "?=");
2835 : : }
2836 : : else
2837 : : /* sort of half valid encoding, try to find an end. */
2838 : 0 : end = strstr(bptr, "?=");
2839 : 20 : return end;
2840 : : }
2841 : :
2842 : :
2843 : :
2844 : : /**
2845 : : * @ingroup StrBuf_DeEnCoder
2846 : : * @brief convert one buffer according to the preselected iconv pointer PIC
2847 : : * @param ConvertBuf buffer we need to translate
2848 : : * @param TmpBuf To share a workbuffer over several iterations. prepare to have it filled with useless stuff afterwards.
2849 : : * @param pic Pointer to the iconv-session Object
2850 : : */
2851 : 25 : void StrBufConvert(StrBuf *ConvertBuf, StrBuf *TmpBuf, void *pic)
2852 : : {
2853 : : #ifdef HAVE_ICONV
2854 : 25 : long trycount = 0;
2855 : : size_t siz;
2856 : : iconv_t ic;
2857 : : char *ibuf; /**< Buffer of characters to be converted */
2858 : : char *obuf; /**< Buffer for converted characters */
2859 : : size_t ibuflen; /**< Length of input buffer */
2860 : : size_t obuflen; /**< Length of output buffer */
2861 : :
2862 : :
2863 : : /* since we're converting to utf-8, one glyph may take up to 6 bytes */
2864 [ + + ]: 25 : if (ConvertBuf->BufUsed * 6 >= TmpBuf->BufSize)
2865 : 9 : IncreaseBuf(TmpBuf, 0, ConvertBuf->BufUsed * 6);
2866 : : TRYAGAIN:
2867 : 25 : ic = *(iconv_t*)pic;
2868 : 25 : ibuf = ConvertBuf->buf;
2869 : 25 : ibuflen = ConvertBuf->BufUsed;
2870 : 25 : obuf = TmpBuf->buf;
2871 : 25 : obuflen = TmpBuf->BufSize;
2872 : :
2873 : 25 : siz = iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
2874 : :
2875 : : if (siz < 0) {
2876 : : if (errno == E2BIG) {
2877 : : trycount ++;
2878 : : IncreaseBuf(TmpBuf, 0, 0);
2879 : : if (trycount < 5)
2880 : : goto TRYAGAIN;
2881 : :
2882 : : }
2883 : : else if (errno == EILSEQ){
2884 : : /* hm, invalid utf8 sequence... what to do now? */
2885 : : /* An invalid multibyte sequence has been encountered in the input */
2886 : : }
2887 : : else if (errno == EINVAL) {
2888 : : /* An incomplete multibyte sequence has been encountered in the input. */
2889 : : }
2890 : :
2891 : : FlushStrBuf(TmpBuf);
2892 : : }
2893 : : else {
2894 : 25 : TmpBuf->BufUsed = TmpBuf->BufSize - obuflen;
2895 : 25 : TmpBuf->buf[TmpBuf->BufUsed] = '\0';
2896 : :
2897 : : /* little card game: wheres the red lady? */
2898 : 25 : SwapBuffers(ConvertBuf, TmpBuf);
2899 : 25 : FlushStrBuf(TmpBuf);
2900 : : }
2901 : : #endif
2902 : 25 : }
2903 : :
2904 : :
2905 : : /**
2906 : : * @ingroup StrBuf_DeEnCoder
2907 : : * @brief catches one RFC822 encoded segment, and decodes it.
2908 : : * @param Target buffer to fill with result
2909 : : * @param DecodeMe buffer with stuff to process
2910 : : * @param SegmentStart points to our current segment in DecodeMe
2911 : : * @param SegmentEnd Points to the end of our current segment in DecodeMe
2912 : : * @param ConvertBuf Workbuffer shared between several iterations. Random content; needs to be valid
2913 : : * @param ConvertBuf2 Workbuffer shared between several iterations. Random content; needs to be valid
2914 : : * @param FoundCharset Characterset to default decoding to; if we find another we will overwrite it.
2915 : : */
2916 : 20 : inline static void DecodeSegment(StrBuf *Target,
2917 : : const StrBuf *DecodeMe,
2918 : : const char *SegmentStart,
2919 : : const char *SegmentEnd,
2920 : : StrBuf *ConvertBuf,
2921 : : StrBuf *ConvertBuf2,
2922 : : StrBuf *FoundCharset)
2923 : : {
2924 : : StrBuf StaticBuf;
2925 : : char charset[128];
2926 : : char encoding[16];
2927 : : #ifdef HAVE_ICONV
2928 : 20 : iconv_t ic = (iconv_t)(-1);
2929 : : #else
2930 : : void *ic = NULL;
2931 : : #endif
2932 : : /* Now we handle foreign character sets properly encoded
2933 : : * in RFC2047 format.
2934 : : */
2935 : 20 : StaticBuf.buf = (char*) SegmentStart; /*< it will just be read there... */
2936 : 20 : StaticBuf.BufUsed = SegmentEnd - SegmentStart;
2937 : 20 : StaticBuf.BufSize = DecodeMe->BufSize - (SegmentStart - DecodeMe->buf);
2938 : 20 : extract_token(charset, SegmentStart, 1, '?', sizeof charset);
2939 [ + - ]: 20 : if (FoundCharset != NULL) {
2940 : 20 : FlushStrBuf(FoundCharset);
2941 : 20 : StrBufAppendBufPlain(FoundCharset, charset, -1, 0);
2942 : : }
2943 : 20 : extract_token(encoding, SegmentStart, 2, '?', sizeof encoding);
2944 : 20 : StrBufExtract_token(ConvertBuf, &StaticBuf, 3, '?');
2945 : :
2946 : 20 : *encoding = toupper(*encoding);
2947 [ + + ]: 20 : if (*encoding == 'B') { /**< base64 */
2948 [ - + ]: 4 : if (ConvertBuf2->BufSize < ConvertBuf->BufUsed)
2949 : 0 : IncreaseBuf(ConvertBuf2, 0, ConvertBuf->BufUsed);
2950 : 4 : ConvertBuf2->BufUsed = CtdlDecodeBase64(ConvertBuf2->buf,
2951 : 4 : ConvertBuf->buf,
2952 : 4 : ConvertBuf->BufUsed);
2953 : : }
2954 [ + - ]: 16 : else if (*encoding == 'Q') { /**< quoted-printable */
2955 : : long pos;
2956 : :
2957 : 16 : pos = 0;
2958 [ + + ]: 156 : while (pos < ConvertBuf->BufUsed)
2959 : : {
2960 [ + + ]: 140 : if (ConvertBuf->buf[pos] == '_')
2961 : 8 : ConvertBuf->buf[pos] = ' ';
2962 : 140 : pos++;
2963 : : }
2964 : :
2965 [ - + ]: 16 : if (ConvertBuf2->BufSize < ConvertBuf->BufUsed)
2966 : 0 : IncreaseBuf(ConvertBuf2, 0, ConvertBuf->BufUsed);
2967 : :
2968 : 16 : ConvertBuf2->BufUsed = CtdlDecodeQuotedPrintable(
2969 : : ConvertBuf2->buf,
2970 : : ConvertBuf->buf,
2971 : 16 : ConvertBuf->BufUsed);
2972 : : }
2973 : : else {
2974 : 0 : StrBufAppendBuf(ConvertBuf2, ConvertBuf, 0);
2975 : : }
2976 : : #ifdef HAVE_ICONV
2977 : 20 : ctdl_iconv_open("UTF-8", charset, &ic);
2978 [ + - ]: 20 : if (ic != (iconv_t)(-1) ) {
2979 : : #endif
2980 : 20 : StrBufConvert(ConvertBuf2, ConvertBuf, &ic);
2981 : 20 : StrBufAppendBuf(Target, ConvertBuf2, 0);
2982 : : #ifdef HAVE_ICONV
2983 : 20 : iconv_close(ic);
2984 : : }
2985 : : else {
2986 : 0 : StrBufAppendBufPlain(Target, HKEY("(unreadable)"), 0);
2987 : : }
2988 : : #endif
2989 : 20 : }
2990 : :
2991 : : /**
2992 : : * @ingroup StrBuf_DeEnCoder
2993 : : * @brief Handle subjects with RFC2047 encoding such as: [deprecated old syntax!]
2994 : : * =?koi8-r?B?78bP0s3Mxc7JxSDXz9rE1dvO2c3JINvB0sHNySDP?=
2995 : : * @param Target where to put the decoded string to
2996 : : * @param DecodeMe buffer with encoded string
2997 : : * @param DefaultCharset if we don't find one, which should we use?
2998 : : * @param FoundCharset overrides DefaultCharset if non-empty; If we find a charset inside of the string,
2999 : : * put it here for later use where no string might be known.
3000 : : */
3001 : 17 : void StrBuf_RFC822_to_Utf8(StrBuf *Target, const StrBuf *DecodeMe, const StrBuf* DefaultCharset, StrBuf *FoundCharset)
3002 : : {
3003 : : StrBuf *ConvertBuf;
3004 : : StrBuf *ConvertBuf2;
3005 : 17 : ConvertBuf = NewStrBufPlain(NULL, StrLength(DecodeMe));
3006 : 17 : ConvertBuf2 = NewStrBufPlain(NULL, StrLength(DecodeMe));
3007 : :
3008 : 17 : StrBuf_RFC822_2_Utf8(Target,
3009 : : DecodeMe,
3010 : : DefaultCharset,
3011 : : FoundCharset,
3012 : : ConvertBuf,
3013 : : ConvertBuf2);
3014 : 17 : FreeStrBuf(&ConvertBuf);
3015 : 17 : FreeStrBuf(&ConvertBuf2);
3016 : 17 : }
3017 : :
3018 : : /**
3019 : : * @ingroup StrBuf_DeEnCoder
3020 : : * @brief Handle subjects with RFC2047 encoding such as:
3021 : : * =?koi8-r?B?78bP0s3Mxc7JxSDXz9rE1dvO2c3JINvB0sHNySDP?=
3022 : : * @param Target where to put the decoded string to
3023 : : * @param DecodeMe buffer with encoded string
3024 : : * @param DefaultCharset if we don't find one, which should we use?
3025 : : * @param FoundCharset overrides DefaultCharset if non-empty; If we find a charset inside of the string,
3026 : : * put it here for later use where no string might be known.
3027 : : * @param ConvertBuf workbuffer. feed in, you shouldn't care about its content.
3028 : : * @param ConvertBuf2 workbuffer. feed in, you shouldn't care about its content.
3029 : : */
3030 : 17 : void StrBuf_RFC822_2_Utf8(StrBuf *Target,
3031 : : const StrBuf *DecodeMe,
3032 : : const StrBuf* DefaultCharset,
3033 : : StrBuf *FoundCharset,
3034 : : StrBuf *ConvertBuf,
3035 : : StrBuf *ConvertBuf2)
3036 : : {
3037 : 17 : StrBuf *DecodedInvalidBuf = NULL;
3038 : 17 : const StrBuf *DecodeMee = DecodeMe;
3039 : 17 : const char *start, *end, *next, *nextend, *ptr = NULL;
3040 : : #ifdef HAVE_ICONV
3041 : 17 : iconv_t ic = (iconv_t)(-1) ;
3042 : : #endif
3043 : : const char *eptr;
3044 : 17 : int passes = 0;
3045 : : int i, len;
3046 : 17 : int illegal_non_rfc2047_encoding = 0;
3047 : :
3048 : : /* Sometimes, badly formed messages contain strings which were simply
3049 : : * written out directly in some foreign character set instead of
3050 : : * using RFC2047 encoding. This is illegal but we will attempt to
3051 : : * handle it anyway by converting from a user-specified default
3052 : : * charset to UTF-8 if we see any nonprintable characters.
3053 : : */
3054 : :
3055 : 17 : len = StrLength(DecodeMe);
3056 [ + + ]: 1398 : for (i=0; i<DecodeMe->BufUsed; ++i) {
3057 [ + + ][ - + ]: 1386 : if ((DecodeMe->buf[i] < 32) || (DecodeMe->buf[i] > 126)) {
3058 : 5 : illegal_non_rfc2047_encoding = 1;
3059 : 5 : break;
3060 : : }
3061 : : }
3062 : :
3063 [ + + + - + : 27 : if ((illegal_non_rfc2047_encoding) &&
- ]
3064 : 5 : (strcasecmp(ChrPtr(DefaultCharset), "UTF-8")) &&
3065 : 5 : (strcasecmp(ChrPtr(DefaultCharset), "us-ascii")) )
3066 : : {
3067 : : #ifdef HAVE_ICONV
3068 : 5 : ctdl_iconv_open("UTF-8", ChrPtr(DefaultCharset), &ic);
3069 [ + - ]: 5 : if (ic != (iconv_t)(-1) ) {
3070 : 5 : DecodedInvalidBuf = NewStrBufDup(DecodeMe);
3071 : 5 : StrBufConvert(DecodedInvalidBuf, ConvertBuf, &ic);///TODO: don't void const?
3072 : 5 : DecodeMee = DecodedInvalidBuf;
3073 : 5 : iconv_close(ic);
3074 : : }
3075 : : #endif
3076 : : }
3077 : :
3078 : : /* pre evaluate the first pair */
3079 : 17 : nextend = end = NULL;
3080 : 17 : len = StrLength(DecodeMee);
3081 : 17 : start = strstr(DecodeMee->buf, "=?");
3082 : 17 : eptr = DecodeMee->buf + DecodeMee->BufUsed;
3083 [ + + ]: 17 : if (start != NULL)
3084 : 8 : end = FindNextEnd (DecodeMee, start);
3085 : : else {
3086 : 9 : StrBufAppendBuf(Target, DecodeMee, 0);
3087 : 9 : FreeStrBuf(&DecodedInvalidBuf);
3088 : 9 : return;
3089 : : }
3090 : :
3091 : :
3092 [ + + ]: 8 : if (start != DecodeMee->buf) {
3093 : : long nFront;
3094 : :
3095 : 4 : nFront = start - DecodeMee->buf;
3096 : 4 : StrBufAppendBufPlain(Target, DecodeMee->buf, nFront, 0);
3097 : 4 : len -= nFront;
3098 : : }
3099 : : /*
3100 : : * Since spammers will go to all sorts of absurd lengths to get their
3101 : : * messages through, there are LOTS of corrupt headers out there.
3102 : : * So, prevent a really badly formed RFC2047 header from throwing
3103 : : * this function into an infinite loop.
3104 : : */
3105 [ + + ][ + - ]: 28 : while ((start != NULL) &&
[ + - ][ + - ]
[ + - ]
3106 : : (end != NULL) &&
3107 : : (start < eptr) &&
3108 : : (end < eptr) &&
3109 : : (passes < 20))
3110 : : {
3111 : 20 : passes++;
3112 : 20 : DecodeSegment(Target,
3113 : : DecodeMee,
3114 : : start,
3115 : : end,
3116 : : ConvertBuf,
3117 : : ConvertBuf2,
3118 : : FoundCharset);
3119 : :
3120 : 20 : next = strstr(end, "=?");
3121 : 20 : nextend = NULL;
3122 [ + + + - ]: 20 : if ((next != NULL) &&
3123 : : (next < eptr))
3124 : 12 : nextend = FindNextEnd(DecodeMee, next);
3125 [ + + ]: 20 : if (nextend == NULL)
3126 : 8 : next = NULL;
3127 : :
3128 : : /* did we find two partitions */
3129 [ + + ][ + - ]: 20 : if ((next != NULL) &&
3130 : 12 : ((next - end) > 2))
3131 : : {
3132 : 12 : ptr = end + 2;
3133 [ + + + + ]: 40 : while ((ptr < next) &&
[ - + ][ - + ]
[ - + ]
3134 : 16 : (isspace(*ptr) ||
3135 : 4 : (*ptr == '\r') ||
3136 : 4 : (*ptr == '\n') ||
3137 : 4 : (*ptr == '\t')))
3138 : 12 : ptr ++;
3139 : : /*
3140 : : * did we find a gab just filled with blanks?
3141 : : * if not, copy its stuff over.
3142 : : */
3143 [ + + ]: 12 : if (ptr != next)
3144 : : {
3145 : 4 : StrBufAppendBufPlain(Target,
3146 : : end + 2,
3147 : 4 : next - end - 2,
3148 : : 0);
3149 : : }
3150 : : }
3151 : : /* our next-pair is our new first pair now. */
3152 : 20 : ptr = end + 2;
3153 : 20 : start = next;
3154 : 20 : end = nextend;
3155 : : }
3156 : 8 : end = ptr;
3157 : 8 : nextend = DecodeMee->buf + DecodeMee->BufUsed;
3158 [ + - ][ + + ]: 8 : if ((end != NULL) && (end < nextend)) {
3159 : 4 : ptr = end;
3160 [ + - + + ]: 16 : while ( (ptr < nextend) &&
[ - + ][ - + ]
[ - + ]
3161 : 8 : (isspace(*ptr) ||
3162 : 4 : (*ptr == '\r') ||
3163 : 4 : (*ptr == '\n') ||
3164 : 4 : (*ptr == '\t')))
3165 : 4 : ptr ++;
3166 [ + - ]: 4 : if (ptr < nextend)
3167 : 4 : StrBufAppendBufPlain(Target, end, nextend - end, 0);
3168 : : }
3169 : 17 : FreeStrBuf(&DecodedInvalidBuf);
3170 : : }
3171 : :
3172 : : /*******************************************************************************
3173 : : * Manipulating UTF-8 Strings *
3174 : : *******************************************************************************/
3175 : :
3176 : : /**
3177 : : * @ingroup StrBuf
3178 : : * @brief evaluate the length of an utf8 special character sequence
3179 : : * @param Char the character to examine
3180 : : * @returns width of utf8 chars in bytes
3181 : : */
3182 : 0 : static inline int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *CharE)
3183 : : {
3184 : 0 : int n = 1;
3185 : 0 : char test = (1<<7);
3186 : :
3187 [ # # ][ # # ]: 0 : while ((n < 8) && ((test & *CharS) != 0)) {
3188 : 0 : test = test << 1;
3189 : 0 : n ++;
3190 : : }
3191 [ # # ][ # # ]: 0 : if ((n > 6) || ((CharE - CharS) < n))
3192 : 0 : n = 1;
3193 : 0 : return n;
3194 : : }
3195 : :
3196 : : /**
3197 : : * @ingroup StrBuf
3198 : : * @brief detect whether this char starts an utf-8 encoded char
3199 : : * @param Char character to inspect
3200 : : * @returns yes or no
3201 : : */
3202 : 0 : static inline int Ctdl_IsUtf8SequenceStart(const char Char)
3203 : : {
3204 : : /** 11??.???? indicates an UTF8 Sequence. */
3205 : 0 : return ((Char & 0xC0) != 0);
3206 : : }
3207 : :
3208 : : /**
3209 : : * @ingroup StrBuf
3210 : : * @brief measure the number of glyphs in an UTF8 string...
3211 : : * @param Buf string to measure
3212 : : * @returns the number of glyphs in Buf
3213 : : */
3214 : 0 : long StrBuf_Utf8StrLen(StrBuf *Buf)
3215 : : {
3216 : 0 : int n = 0;
3217 : 0 : int m = 0;
3218 : : char *aptr, *eptr;
3219 : :
3220 [ # # ][ # # ]: 0 : if ((Buf == NULL) || (Buf->BufUsed == 0))
3221 : 0 : return 0;
3222 : 0 : aptr = Buf->buf;
3223 : 0 : eptr = Buf->buf + Buf->BufUsed;
3224 [ # # ][ # # ]: 0 : while ((aptr < eptr) && (*aptr != '\0')) {
3225 [ # # ]: 0 : if (Ctdl_IsUtf8SequenceStart(*aptr)){
3226 : 0 : m = Ctdl_GetUtf8SequenceLength(aptr, eptr);
3227 [ # # ][ # # ]: 0 : while ((aptr < eptr) && (*aptr++ != '\0')&& (m-- > 0) );
[ # # ]
3228 : 0 : n ++;
3229 : : }
3230 : : else {
3231 : 0 : n++;
3232 : 0 : aptr++;
3233 : : }
3234 : : }
3235 : 0 : return n;
3236 : : }
3237 : :
3238 : : /**
3239 : : * @ingroup StrBuf
3240 : : * @brief cuts a string after maxlen glyphs
3241 : : * @param Buf string to cut to maxlen glyphs
3242 : : * @param maxlen how long may the string become?
3243 : : * @returns current length of the string
3244 : : */
3245 : 0 : long StrBuf_Utf8StrCut(StrBuf *Buf, int maxlen)
3246 : : {
3247 : : char *aptr, *eptr;
3248 : 0 : int n = 0, m = 0;
3249 : :
3250 : 0 : aptr = Buf->buf;
3251 : 0 : eptr = Buf->buf + Buf->BufUsed;
3252 [ # # ][ # # ]: 0 : while ((aptr < eptr) && (*aptr != '\0')) {
3253 [ # # ]: 0 : if (Ctdl_IsUtf8SequenceStart(*aptr)){
3254 : 0 : m = Ctdl_GetUtf8SequenceLength(aptr, eptr);
3255 [ # # ][ # # ]: 0 : while ((*aptr++ != '\0') && (m-- > 0));
3256 : 0 : n ++;
3257 : : }
3258 : : else {
3259 : 0 : n++;
3260 : 0 : aptr++;
3261 : : }
3262 [ # # ]: 0 : if (n > maxlen) {
3263 : 0 : *aptr = '\0';
3264 : 0 : Buf->BufUsed = aptr - Buf->buf;
3265 : 0 : return Buf->BufUsed;
3266 : : }
3267 : : }
3268 : 0 : return Buf->BufUsed;
3269 : :
3270 : : }
3271 : :
3272 : :
3273 : :
3274 : :
3275 : :
3276 : : /*******************************************************************************
3277 : : * wrapping ZLib *
3278 : : *******************************************************************************/
3279 : :
3280 : : #ifdef HAVE_ZLIB
3281 : : #define DEF_MEM_LEVEL 8 /*< memlevel??? */
3282 : : #define OS_CODE 0x03 /*< unix */
3283 : :
3284 : : /**
3285 : : * @ingroup StrBuf_DeEnCoder
3286 : : * @brief uses the same calling syntax as compress2(), but it
3287 : : * creates a stream compatible with HTTP "Content-encoding: gzip"
3288 : : * @param dest compressed buffer
3289 : : * @param destLen length of the compresed data
3290 : : * @param source source to encode
3291 : : * @param sourceLen length of source to encode
3292 : : * @param level compression level
3293 : : */
3294 : 0 : int ZEXPORT compress_gzip(Bytef * dest,
3295 : : size_t * destLen,
3296 : : const Bytef * source,
3297 : : uLong sourceLen,
3298 : : int level)
3299 : : {
3300 : : const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
3301 : :
3302 : : /* write gzip header */
3303 : 0 : snprintf((char *) dest, *destLen,
3304 : : "%c%c%c%c%c%c%c%c%c%c",
3305 : : gz_magic[0], gz_magic[1], Z_DEFLATED,
3306 : : 0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
3307 : : OS_CODE);
3308 : :
3309 : : /* normal deflate */
3310 : : z_stream stream;
3311 : : int err;
3312 : 0 : stream.next_in = (Bytef *) source;
3313 : 0 : stream.avail_in = (uInt) sourceLen;
3314 : 0 : stream.next_out = dest + 10L; // after header
3315 : 0 : stream.avail_out = (uInt) * destLen;
3316 [ # # ]: 0 : if ((uLong) stream.avail_out != *destLen)
3317 : 0 : return Z_BUF_ERROR;
3318 : :
3319 : 0 : stream.zalloc = (alloc_func) 0;
3320 : 0 : stream.zfree = (free_func) 0;
3321 : 0 : stream.opaque = (voidpf) 0;
3322 : :
3323 : 0 : err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS,
3324 : : DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
3325 [ # # ]: 0 : if (err != Z_OK)
3326 : 0 : return err;
3327 : :
3328 : 0 : err = deflate(&stream, Z_FINISH);
3329 [ # # ]: 0 : if (err != Z_STREAM_END) {
3330 : 0 : deflateEnd(&stream);
3331 [ # # ]: 0 : return err == Z_OK ? Z_BUF_ERROR : err;
3332 : : }
3333 : 0 : *destLen = stream.total_out + 10L;
3334 : :
3335 : : /* write CRC and Length */
3336 : 0 : uLong crc = crc32(0L, source, sourceLen);
3337 : : int n;
3338 [ # # ]: 0 : for (n = 0; n < 4; ++n, ++*destLen) {
3339 : 0 : dest[*destLen] = (int) (crc & 0xff);
3340 : 0 : crc >>= 8;
3341 : : }
3342 : 0 : uLong len = stream.total_in;
3343 [ # # ]: 0 : for (n = 0; n < 4; ++n, ++*destLen) {
3344 : 0 : dest[*destLen] = (int) (len & 0xff);
3345 : 0 : len >>= 8;
3346 : : }
3347 : 0 : err = deflateEnd(&stream);
3348 : 0 : return err;
3349 : : }
3350 : : #endif
3351 : :
3352 : :
3353 : : /**
3354 : : * @ingroup StrBuf_DeEnCoder
3355 : : * @brief compress the buffer with gzip
3356 : : * Attention! If you feed this a Const String, you must maintain the uncompressed buffer yourself!
3357 : : * @param Buf buffer whose content is to be gzipped
3358 : : */
3359 : 0 : int CompressBuffer(StrBuf *Buf)
3360 : : {
3361 : : #ifdef HAVE_ZLIB
3362 : 0 : char *compressed_data = NULL;
3363 : : size_t compressed_len, bufsize;
3364 : 0 : int i = 0;
3365 : :
3366 : 0 : bufsize = compressed_len = Buf->BufUsed + (Buf->BufUsed / 100) + 100;
3367 : 0 : compressed_data = malloc(compressed_len);
3368 : :
3369 [ # # ]: 0 : if (compressed_data == NULL)
3370 : 0 : return -1;
3371 : : /* Flush some space after the used payload so valgrind shuts up... */
3372 [ # # ][ # # ]: 0 : while ((i < 10) && (Buf->BufUsed + i < Buf->BufSize))
3373 : 0 : Buf->buf[Buf->BufUsed + i++] = '\0';
3374 [ # # ]: 0 : if (compress_gzip((Bytef *) compressed_data,
3375 : : &compressed_len,
3376 : : (Bytef *) Buf->buf,
3377 : : (uLongf) Buf->BufUsed, Z_BEST_SPEED) == Z_OK) {
3378 [ # # ]: 0 : if (!Buf->ConstBuf)
3379 : 0 : free(Buf->buf);
3380 : 0 : Buf->buf = compressed_data;
3381 : 0 : Buf->BufUsed = compressed_len;
3382 : 0 : Buf->BufSize = bufsize;
3383 : : /* Flush some space after the used payload so valgrind shuts up... */
3384 : 0 : i = 0;
3385 [ # # ][ # # ]: 0 : while ((i < 10) && (Buf->BufUsed + i < Buf->BufSize))
3386 : 0 : Buf->buf[Buf->BufUsed + i++] = '\0';
3387 : 0 : return 1;
3388 : : } else {
3389 : 0 : free(compressed_data);
3390 : : }
3391 : : #endif /* HAVE_ZLIB */
3392 : 0 : return 0;
3393 : : }
3394 : :
3395 : :
3396 : :
3397 : : /*******************************************************************************
3398 : : * File I/O; Prefer buffered read since its faster! *
3399 : : *******************************************************************************/
3400 : :
3401 : : /**
3402 : : * @ingroup StrBuf_IO
3403 : : * @brief Read a line from socket
3404 : : * flushes and closes the FD on error
3405 : : * @param buf the buffer to get the input to
3406 : : * @param fd pointer to the filedescriptor to read
3407 : : * @param append Append to an existing string or replace?
3408 : : * @param Error strerror() on error
3409 : : * @returns numbers of chars read
3410 : : */
3411 : 26 : int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
3412 : : {
3413 : : int len, rlen, slen;
3414 : :
3415 [ + - ]: 26 : if (!append)
3416 : 26 : FlushStrBuf(buf);
3417 : :
3418 : 26 : slen = len = buf->BufUsed;
3419 : : while (1) {
3420 : 691 : rlen = read(*fd, &buf->buf[len], 1);
3421 [ + + ]: 691 : if (rlen < 1) {
3422 : 1 : *Error = strerror(errno);
3423 : :
3424 : 1 : close(*fd);
3425 : 1 : *fd = -1;
3426 : :
3427 : 1 : return -1;
3428 : : }
3429 [ + + ]: 690 : if (buf->buf[len] == '\n')
3430 : : break;
3431 [ + - ]: 665 : if (buf->buf[len] != '\r')
3432 : 665 : len ++;
3433 [ + + ]: 665 : if (len + 2 >= buf->BufSize) {
3434 : 9 : buf->BufUsed = len;
3435 : 9 : buf->buf[len+1] = '\0';
3436 : 9 : IncreaseBuf(buf, 1, -1);
3437 : : }
3438 : 691 : }
3439 : 25 : buf->BufUsed = len;
3440 : 25 : buf->buf[len] = '\0';
3441 : 25 : return len - slen;
3442 : : }
3443 : :
3444 : : /**
3445 : : * @ingroup StrBuf_BufferedIO
3446 : : * @brief Read a line from socket
3447 : : * flushes and closes the FD on error
3448 : : * @param Line the line to read from the fd / I/O Buffer
3449 : : * @param buf the buffer to get the input to
3450 : : * @param fd pointer to the filedescriptor to read
3451 : : * @param timeout number of successless selects until we bail out
3452 : : * @param selectresolution how long to wait on each select
3453 : : * @param Error strerror() on error
3454 : : * @returns numbers of chars read
3455 : : */
3456 : 0 : int StrBufTCP_read_buffered_line(StrBuf *Line,
3457 : : StrBuf *buf,
3458 : : int *fd,
3459 : : int timeout,
3460 : : int selectresolution,
3461 : : const char **Error)
3462 : : {
3463 : : int len, rlen;
3464 : 0 : int nSuccessLess = 0;
3465 : : fd_set rfds;
3466 : 0 : char *pch = NULL;
3467 : : int fdflags;
3468 : : int IsNonBlock;
3469 : : struct timeval tv;
3470 : :
3471 [ # # ]: 0 : if (buf->BufUsed > 0) {
3472 : 0 : pch = strchr(buf->buf, '\n');
3473 [ # # ]: 0 : if (pch != NULL) {
3474 : 0 : rlen = 0;
3475 : 0 : len = pch - buf->buf;
3476 [ # # ][ # # ]: 0 : if (len > 0 && (*(pch - 1) == '\r') )
3477 : 0 : rlen ++;
3478 : 0 : StrBufSub(Line, buf, 0, len - rlen);
3479 : 0 : StrBufCutLeft(buf, len + 1);
3480 : 0 : return len - rlen;
3481 : : }
3482 : : }
3483 : :
3484 [ # # ]: 0 : if (buf->BufSize - buf->BufUsed < 10)
3485 : 0 : IncreaseBuf(buf, 1, -1);
3486 : :
3487 : 0 : fdflags = fcntl(*fd, F_GETFL);
3488 : 0 : IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
3489 : :
3490 [ # # ][ # # ]: 0 : while ((nSuccessLess < timeout) && (pch == NULL)) {
3491 [ # # ]: 0 : if (IsNonBlock){
3492 : 0 : tv.tv_sec = selectresolution;
3493 : 0 : tv.tv_usec = 0;
3494 : :
3495 : 0 : FD_ZERO(&rfds);
3496 : 0 : FD_SET(*fd, &rfds);
3497 [ # # ]: 0 : if (select(*fd + 1, NULL, &rfds, NULL, &tv) == -1) {
3498 : 0 : *Error = strerror(errno);
3499 : 0 : close (*fd);
3500 : 0 : *fd = -1;
3501 : 0 : return -1;
3502 : : }
3503 : : }
3504 [ # # ][ # # ]: 0 : if (IsNonBlock && ! FD_ISSET(*fd, &rfds)) {
3505 : 0 : nSuccessLess ++;
3506 : 0 : continue;
3507 : : }
3508 : 0 : rlen = read(*fd,
3509 : 0 : &buf->buf[buf->BufUsed],
3510 : 0 : buf->BufSize - buf->BufUsed - 1);
3511 [ # # ]: 0 : if (rlen < 1) {
3512 : 0 : *Error = strerror(errno);
3513 : 0 : close(*fd);
3514 : 0 : *fd = -1;
3515 : 0 : return -1;
3516 : : }
3517 [ # # ]: 0 : else if (rlen > 0) {
3518 : 0 : nSuccessLess = 0;
3519 : 0 : buf->BufUsed += rlen;
3520 : 0 : buf->buf[buf->BufUsed] = '\0';
3521 [ # # ]: 0 : if (buf->BufUsed + 10 > buf->BufSize) {
3522 : 0 : IncreaseBuf(buf, 1, -1);
3523 : : }
3524 : 0 : pch = strchr(buf->buf, '\n');
3525 : 0 : continue;
3526 : : }
3527 : :
3528 : : }
3529 [ # # ]: 0 : if (pch != NULL) {
3530 : 0 : rlen = 0;
3531 : 0 : len = pch - buf->buf;
3532 [ # # ][ # # ]: 0 : if (len > 0 && (*(pch - 1) == '\r') )
3533 : 0 : rlen ++;
3534 : 0 : StrBufSub(Line, buf, 0, len - rlen);
3535 : 0 : StrBufCutLeft(buf, len + 1);
3536 : 0 : return len - rlen;
3537 : : }
3538 : 0 : return -1;
3539 : :
3540 : : }
3541 : :
3542 : : static const char *ErrRBLF_PreConditionFailed="StrBufTCP_read_buffered_line_fast: Wrong arguments or invalid Filedescriptor";
3543 : : static const char *ErrRBLF_SelectFailed="StrBufTCP_read_buffered_line_fast: Select failed without reason";
3544 : : static const char *ErrRBLF_NotEnoughSentFromServer="StrBufTCP_read_buffered_line_fast: No complete line was sent from peer";
3545 : : /**
3546 : : * @ingroup StrBuf_BufferedIO
3547 : : * @brief Read a line from socket
3548 : : * flushes and closes the FD on error
3549 : : * @param Line where to append our Line read from the fd / I/O Buffer;
3550 : : * @param IOBuf the buffer to get the input to; lifetime pair to FD
3551 : : * @param Pos pointer to the current read position, should be NULL initialized on opening the FD it belongs to.!
3552 : : * @param fd pointer to the filedescriptor to read
3553 : : * @param timeout number of successless selects until we bail out
3554 : : * @param selectresolution how long to wait on each select
3555 : : * @param Error strerror() on error
3556 : : * @returns numbers of chars read or -1 in case of error. "\n" will become 0
3557 : : */
3558 : 0 : int StrBufTCP_read_buffered_line_fast(StrBuf *Line,
3559 : : StrBuf *IOBuf,
3560 : : const char **Pos,
3561 : : int *fd,
3562 : : int timeout,
3563 : : int selectresolution,
3564 : : const char **Error)
3565 : : {
3566 : 0 : const char *pche = NULL;
3567 : 0 : const char *pos = NULL;
3568 : : const char *pLF;
3569 : : int len, rlen, retlen;
3570 : 0 : int nSuccessLess = 0;
3571 : : fd_set rfds;
3572 : 0 : const char *pch = NULL;
3573 : : int fdflags;
3574 : : int IsNonBlock;
3575 : : struct timeval tv;
3576 : :
3577 : 0 : retlen = 0;
3578 [ # # ][ # # ]: 0 : if ((Line == NULL) ||
[ # # ][ # # ]
3579 : : (Pos == NULL) ||
3580 : : (IOBuf == NULL) ||
3581 : 0 : (*fd == -1))
3582 : : {
3583 [ # # ]: 0 : if (Pos != NULL)
3584 : 0 : *Pos = NULL;
3585 : 0 : *Error = ErrRBLF_PreConditionFailed;
3586 : 0 : return -1;
3587 : : }
3588 : :
3589 : 0 : pos = *Pos;
3590 [ # # ][ # # ]: 0 : if ((IOBuf->BufUsed > 0) &&
[ # # ]
3591 : : (pos != NULL) &&
3592 : 0 : (pos < IOBuf->buf + IOBuf->BufUsed))
3593 : : {
3594 : : char *pcht;
3595 : :
3596 : 0 : pche = IOBuf->buf + IOBuf->BufUsed;
3597 : 0 : pch = pos;
3598 : 0 : pcht = Line->buf;
3599 : :
3600 [ # # ][ # # ]: 0 : while ((pch < pche) && (*pch != '\n'))
3601 : : {
3602 [ # # ]: 0 : if (Line->BufUsed + 10 > Line->BufSize)
3603 : : {
3604 : : long apos;
3605 : 0 : apos = pcht - Line->buf;
3606 : 0 : *pcht = '\0';
3607 : 0 : IncreaseBuf(Line, 1, -1);
3608 : 0 : pcht = Line->buf + apos;
3609 : : }
3610 : 0 : *pcht++ = *pch++;
3611 : 0 : Line->BufUsed++;
3612 : 0 : retlen++;
3613 : : }
3614 : :
3615 : 0 : len = pch - pos;
3616 [ # # ][ # # ]: 0 : if (len > 0 && (*(pch - 1) == '\r') )
3617 : : {
3618 : 0 : retlen--;
3619 : 0 : len --;
3620 : 0 : pcht --;
3621 : 0 : Line->BufUsed --;
3622 : : }
3623 : 0 : *pcht = '\0';
3624 : :
3625 [ # # ][ # # ]: 0 : if ((pch >= pche) || (*pch == '\0'))
3626 : : {
3627 : 0 : FlushStrBuf(IOBuf);
3628 : 0 : *Pos = NULL;
3629 : 0 : pch = NULL;
3630 : 0 : pos = 0;
3631 : : }
3632 : :
3633 [ # # ][ # # ]: 0 : if ((pch != NULL) &&
3634 : : (pch <= pche))
3635 : : {
3636 [ # # ]: 0 : if (pch + 1 >= pche) {
3637 : 0 : *Pos = NULL;
3638 : 0 : FlushStrBuf(IOBuf);
3639 : : }
3640 : : else
3641 : 0 : *Pos = pch + 1;
3642 : :
3643 : 0 : return retlen;
3644 : : }
3645 : : else
3646 : 0 : FlushStrBuf(IOBuf);
3647 : : }
3648 : :
3649 : : /* If we come here, Pos is Unset since we read everything into Line, and now go for more. */
3650 : :
3651 [ # # ]: 0 : if (IOBuf->BufSize - IOBuf->BufUsed < 10)
3652 : 0 : IncreaseBuf(IOBuf, 1, -1);
3653 : :
3654 : 0 : fdflags = fcntl(*fd, F_GETFL);
3655 : 0 : IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
3656 : :
3657 : 0 : pLF = NULL;
3658 [ # # ][ # # ]: 0 : while ((nSuccessLess < timeout) &&
[ # # ]
3659 : : (pLF == NULL) &&
3660 : 0 : (*fd != -1)) {
3661 [ # # ]: 0 : if (IsNonBlock)
3662 : : {
3663 : 0 : tv.tv_sec = 1;
3664 : 0 : tv.tv_usec = 0;
3665 : :
3666 : 0 : FD_ZERO(&rfds);
3667 : 0 : FD_SET(*fd, &rfds);
3668 [ # # ]: 0 : if (select((*fd) + 1, &rfds, NULL, NULL, &tv) == -1) {
3669 : 0 : *Error = strerror(errno);
3670 : 0 : close (*fd);
3671 : 0 : *fd = -1;
3672 [ # # ]: 0 : if (*Error == NULL)
3673 : 0 : *Error = ErrRBLF_SelectFailed;
3674 : 0 : return -1;
3675 : : }
3676 [ # # ]: 0 : if (! FD_ISSET(*fd, &rfds) != 0) {
3677 : 0 : nSuccessLess ++;
3678 : 0 : continue;
3679 : : }
3680 : : }
3681 : 0 : rlen = read(*fd,
3682 : 0 : &IOBuf->buf[IOBuf->BufUsed],
3683 : 0 : IOBuf->BufSize - IOBuf->BufUsed - 1);
3684 [ # # ]: 0 : if (rlen < 1) {
3685 : 0 : *Error = strerror(errno);
3686 : 0 : close(*fd);
3687 : 0 : *fd = -1;
3688 : 0 : return -1;
3689 : : }
3690 [ # # ]: 0 : else if (rlen > 0) {
3691 : 0 : nSuccessLess = 0;
3692 : 0 : pLF = IOBuf->buf + IOBuf->BufUsed;
3693 : 0 : IOBuf->BufUsed += rlen;
3694 : 0 : IOBuf->buf[IOBuf->BufUsed] = '\0';
3695 : :
3696 : 0 : pche = IOBuf->buf + IOBuf->BufUsed;
3697 : :
3698 [ # # ][ # # ]: 0 : while ((pLF < pche) && (*pLF != '\n'))
3699 : 0 : pLF ++;
3700 [ # # ][ # # ]: 0 : if ((pLF >= pche) || (*pLF == '\0'))
3701 : 0 : pLF = NULL;
3702 : :
3703 [ # # ]: 0 : if (IOBuf->BufUsed + 10 > IOBuf->BufSize)
3704 : : {
3705 : 0 : long apos = 0;
3706 : :
3707 [ # # ]: 0 : if (pLF != NULL) apos = pLF - IOBuf->buf;
3708 : 0 : IncreaseBuf(IOBuf, 1, -1);
3709 [ # # ]: 0 : if (pLF != NULL) pLF = IOBuf->buf + apos;
3710 : : }
3711 : :
3712 : 0 : continue;
3713 : : }
3714 : : }
3715 : 0 : *Pos = NULL;
3716 [ # # ]: 0 : if (pLF != NULL) {
3717 : 0 : pos = IOBuf->buf;
3718 : 0 : len = pLF - pos;
3719 [ # # ][ # # ]: 0 : if (len > 0 && (*(pLF - 1) == '\r') )
3720 : 0 : len --;
3721 : 0 : StrBufAppendBufPlain(Line, ChrPtr(IOBuf), len, 0);
3722 [ # # ]: 0 : if (pLF + 1 >= IOBuf->buf + IOBuf->BufUsed)
3723 : : {
3724 : 0 : FlushStrBuf(IOBuf);
3725 : : }
3726 : : else
3727 : 0 : *Pos = pLF + 1;
3728 : 0 : return retlen + len;
3729 : : }
3730 : 0 : *Error = ErrRBLF_NotEnoughSentFromServer;
3731 : 0 : return -1;
3732 : :
3733 : : }
3734 : :
3735 : : static const char *ErrRBLF_BLOBPreConditionFailed="StrBufReadBLOB: Wrong arguments or invalid Filedescriptor";
3736 : : /**
3737 : : * @ingroup StrBuf_IO
3738 : : * @brief Input binary data from socket
3739 : : * flushes and closes the FD on error
3740 : : * @param Buf the buffer to get the input to
3741 : : * @param fd pointer to the filedescriptor to read
3742 : : * @param append Append to an existing string or replace?
3743 : : * @param nBytes the maximal number of bytes to read
3744 : : * @param Error strerror() on error
3745 : : * @returns numbers of chars read
3746 : : */
3747 : 194 : int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error)
3748 : : {
3749 : : int fdflags;
3750 : : int len, rlen, slen;
3751 : : int nSuccessLess;
3752 : 194 : int nRead = 0;
3753 : : char *ptr;
3754 : : int IsNonBlock;
3755 : : struct timeval tv;
3756 : : fd_set rfds;
3757 : :
3758 [ + - ][ - + ]: 194 : if ((Buf == NULL) || (*fd == -1))
3759 : : {
3760 : 0 : *Error = ErrRBLF_BLOBPreConditionFailed;
3761 : 0 : return -1;
3762 : : }
3763 [ - + ]: 194 : if (!append)
3764 : 0 : FlushStrBuf(Buf);
3765 [ - + ]: 194 : if (Buf->BufUsed + nBytes >= Buf->BufSize)
3766 : 0 : IncreaseBuf(Buf, 1, Buf->BufUsed + nBytes);
3767 : :
3768 : 194 : ptr = Buf->buf + Buf->BufUsed;
3769 : :
3770 : 194 : slen = len = Buf->BufUsed;
3771 : :
3772 : 194 : fdflags = fcntl(*fd, F_GETFL);
3773 : 194 : IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
3774 : 194 : nSuccessLess = 0;
3775 [ + + ][ + - ]: 388 : while ((nRead < nBytes) &&
3776 : 194 : (*fd != -1))
3777 : : {
3778 [ - + ]: 194 : if (IsNonBlock)
3779 : : {
3780 : 0 : tv.tv_sec = 1;
3781 : 0 : tv.tv_usec = 0;
3782 : :
3783 : 0 : FD_ZERO(&rfds);
3784 : 0 : FD_SET(*fd, &rfds);
3785 [ # # ]: 0 : if (select(*fd + 1, &rfds, NULL, NULL, &tv) == -1) {
3786 : 0 : *Error = strerror(errno);
3787 : 0 : close (*fd);
3788 : 0 : *fd = -1;
3789 [ # # ]: 0 : if (*Error == NULL)
3790 : 0 : *Error = ErrRBLF_SelectFailed;
3791 : 0 : return -1;
3792 : : }
3793 [ # # ]: 0 : if (! FD_ISSET(*fd, &rfds) != 0) {
3794 : 0 : nSuccessLess ++;
3795 : 0 : continue;
3796 : : }
3797 : : }
3798 : :
3799 [ - + ]: 194 : if ((rlen = read(*fd,
3800 : : ptr,
3801 : 194 : nBytes - nRead)) == -1) {
3802 : 0 : close(*fd);
3803 : 0 : *fd = -1;
3804 : 0 : *Error = strerror(errno);
3805 : 0 : return rlen;
3806 : : }
3807 : 194 : nRead += rlen;
3808 : 194 : ptr += rlen;
3809 : 194 : Buf->BufUsed += rlen;
3810 : : }
3811 : 194 : Buf->buf[Buf->BufUsed] = '\0';
3812 : 194 : return nRead;
3813 : : }
3814 : :
3815 : : const char *ErrRBB_BLOBFPreConditionFailed = "StrBufReadBLOBBuffered: to many selects; aborting.";
3816 : : const char *ErrRBB_too_many_selects = "StrBufReadBLOBBuffered: to many selects; aborting.";
3817 : : /**
3818 : : * @ingroup StrBuf_BufferedIO
3819 : : * @brief Input binary data from socket
3820 : : * flushes and closes the FD on error
3821 : : * @param Blob put binary thing here
3822 : : * @param IOBuf the buffer to get the input to
3823 : : * @param Pos offset inside of IOBuf
3824 : : * @param fd pointer to the filedescriptor to read
3825 : : * @param append Append to an existing string or replace?
3826 : : * @param nBytes the maximal number of bytes to read
3827 : : * @param check whether we should search for '000\n' terminators in case of timeouts
3828 : : * @param Error strerror() on error
3829 : : * @returns numbers of chars read
3830 : : */
3831 : 0 : int StrBufReadBLOBBuffered(StrBuf *Blob,
3832 : : StrBuf *IOBuf,
3833 : : const char **Pos,
3834 : : int *fd,
3835 : : int append,
3836 : : long nBytes,
3837 : : int check,
3838 : : const char **Error)
3839 : : {
3840 : : const char *pche;
3841 : : const char *pos;
3842 : : int fdflags;
3843 : 0 : int len = 0;
3844 : : int rlen, slen;
3845 : 0 : int nRead = 0;
3846 : 0 : int nAlreadyRead = 0;
3847 : : int IsNonBlock;
3848 : : char *ptr;
3849 : : fd_set rfds;
3850 : : const char *pch;
3851 : : struct timeval tv;
3852 : 0 : int nSuccessLess = 0;
3853 : : int MaxTries;
3854 : :
3855 [ # # ][ # # ]: 0 : if ((Blob == NULL) || (*fd == -1) || (IOBuf == NULL) || (Pos == NULL))
[ # # ][ # # ]
3856 : : {
3857 [ # # ]: 0 : if (*Pos != NULL)
3858 : 0 : *Pos = NULL;
3859 : 0 : *Error = ErrRBB_BLOBFPreConditionFailed;
3860 : 0 : return -1;
3861 : : }
3862 : :
3863 [ # # ]: 0 : if (!append)
3864 : 0 : FlushStrBuf(Blob);
3865 [ # # ]: 0 : if (Blob->BufUsed + nBytes >= Blob->BufSize)
3866 : 0 : IncreaseBuf(Blob, append, Blob->BufUsed + nBytes);
3867 : :
3868 : 0 : pos = *Pos;
3869 : :
3870 [ # # ]: 0 : if (pos != NULL)
3871 : 0 : len = pos - IOBuf->buf;
3872 : 0 : rlen = IOBuf->BufUsed - len;
3873 : :
3874 : :
3875 [ # # ][ # # ]: 0 : if ((IOBuf->BufUsed > 0) &&
[ # # ]
3876 : : (pos != NULL) &&
3877 : 0 : (pos < IOBuf->buf + IOBuf->BufUsed))
3878 : : {
3879 : 0 : pche = IOBuf->buf + IOBuf->BufUsed;
3880 : 0 : pch = pos;
3881 : :
3882 [ # # ]: 0 : if (rlen < nBytes) {
3883 : 0 : memcpy(Blob->buf + Blob->BufUsed, pos, rlen);
3884 : 0 : Blob->BufUsed += rlen;
3885 : 0 : Blob->buf[Blob->BufUsed] = '\0';
3886 : 0 : nAlreadyRead = nRead = rlen;
3887 : 0 : *Pos = NULL;
3888 : : }
3889 [ # # ]: 0 : if (rlen >= nBytes) {
3890 : 0 : memcpy(Blob->buf + Blob->BufUsed, pos, nBytes);
3891 : 0 : Blob->BufUsed += nBytes;
3892 : 0 : Blob->buf[Blob->BufUsed] = '\0';
3893 [ # # ]: 0 : if (rlen == nBytes) {
3894 : 0 : *Pos = NULL;
3895 : 0 : FlushStrBuf(IOBuf);
3896 : : }
3897 : : else
3898 : 0 : *Pos += nBytes;
3899 : 0 : return nBytes;
3900 : : }
3901 : : }
3902 : :
3903 : 0 : FlushStrBuf(IOBuf);
3904 : 0 : *Pos = NULL;
3905 [ # # ]: 0 : if (IOBuf->BufSize < nBytes - nRead)
3906 : 0 : IncreaseBuf(IOBuf, 0, nBytes - nRead);
3907 : 0 : ptr = IOBuf->buf;
3908 : :
3909 : 0 : slen = len = Blob->BufUsed;
3910 : :
3911 : 0 : fdflags = fcntl(*fd, F_GETFL);
3912 : 0 : IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
3913 [ # # ]: 0 : if (IsNonBlock)
3914 : 0 : MaxTries = 1000;
3915 : : else
3916 : 0 : MaxTries = 100000;
3917 : :
3918 : 0 : nBytes -= nRead;
3919 : 0 : nRead = 0;
3920 [ # # ][ # # ]: 0 : while ((nSuccessLess < MaxTries) &&
[ # # ]
3921 : : (nRead < nBytes) &&
3922 : 0 : (*fd != -1)) {
3923 [ # # ]: 0 : if (IsNonBlock)
3924 : : {
3925 : 0 : tv.tv_sec = 1;
3926 : 0 : tv.tv_usec = 0;
3927 : :
3928 : 0 : FD_ZERO(&rfds);
3929 : 0 : FD_SET(*fd, &rfds);
3930 [ # # ]: 0 : if (select(*fd + 1, &rfds, NULL, NULL, &tv) == -1) {
3931 : 0 : *Error = strerror(errno);
3932 : 0 : close (*fd);
3933 : 0 : *fd = -1;
3934 [ # # ]: 0 : if (*Error == NULL)
3935 : 0 : *Error = ErrRBLF_SelectFailed;
3936 : 0 : return -1;
3937 : : }
3938 [ # # ]: 0 : if (! FD_ISSET(*fd, &rfds) != 0) {
3939 : 0 : nSuccessLess ++;
3940 : 0 : continue;
3941 : : }
3942 : : }
3943 : 0 : rlen = read(*fd,
3944 : : ptr,
3945 : 0 : IOBuf->BufSize - (ptr - IOBuf->buf));
3946 [ # # ]: 0 : if (rlen == -1) {
3947 : 0 : close(*fd);
3948 : 0 : *fd = -1;
3949 : 0 : *Error = strerror(errno);
3950 : 0 : return rlen;
3951 : : }
3952 [ # # ]: 0 : else if (rlen == 0){
3953 [ # # ][ # # ]: 0 : if ((check == NNN_TERM) &&
[ # # ]
3954 : : (nRead > 5) &&
3955 : 0 : (strncmp(IOBuf->buf + IOBuf->BufUsed - 5, "\n000\n", 5) == 0))
3956 : : {
3957 : 0 : StrBufPlain(Blob, HKEY("\n000\n"));
3958 : 0 : StrBufCutRight(Blob, 5);
3959 : 0 : return Blob->BufUsed;
3960 : : }
3961 [ # # ]: 0 : else if (!IsNonBlock)
3962 : 0 : nSuccessLess ++;
3963 [ # # ]: 0 : else if (nSuccessLess > MaxTries) {
3964 : 0 : FlushStrBuf(IOBuf);
3965 : 0 : *Error = ErrRBB_too_many_selects;
3966 : 0 : return -1;
3967 : : }
3968 : : }
3969 [ # # ]: 0 : else if (rlen > 0) {
3970 : 0 : nSuccessLess = 0;
3971 : 0 : nRead += rlen;
3972 : 0 : ptr += rlen;
3973 : 0 : IOBuf->BufUsed += rlen;
3974 : : }
3975 : : }
3976 [ # # ]: 0 : if (nSuccessLess >= MaxTries) {
3977 : 0 : FlushStrBuf(IOBuf);
3978 : 0 : *Error = ErrRBB_too_many_selects;
3979 : 0 : return -1;
3980 : : }
3981 : :
3982 [ # # ]: 0 : if (nRead > nBytes) {
3983 : 0 : *Pos = IOBuf->buf + nBytes;
3984 : : }
3985 : 0 : Blob->buf[Blob->BufUsed] = '\0';
3986 : 0 : StrBufAppendBufPlain(Blob, IOBuf->buf, nBytes, 0);
3987 [ # # ]: 0 : if (*Pos == NULL) {
3988 : 0 : FlushStrBuf(IOBuf);
3989 : : }
3990 : 0 : return nRead + nAlreadyRead;
3991 : : }
3992 : :
3993 : : /**
3994 : : * @ingroup StrBuf_IO
3995 : : * @brief extract a "next line" from Buf; Ptr to persist across several iterations
3996 : : * @param LineBuf your line will be copied here.
3997 : : * @param Buf BLOB with lines of text...
3998 : : * @param Ptr moved arround to keep the next-line across several iterations
3999 : : * has to be &NULL on start; will be &NotNULL on end of buffer
4000 : : * @returns size of copied buffer
4001 : : */
4002 : 0 : int StrBufSipLine(StrBuf *LineBuf, StrBuf *Buf, const char **Ptr)
4003 : : {
4004 : : const char *aptr, *ptr, *eptr;
4005 : : char *optr, *xptr;
4006 : :
4007 [ # # ][ # # ]: 0 : if ((Buf == NULL) || (*Ptr == StrBufNOTNULL)) {
4008 : 0 : *Ptr = StrBufNOTNULL;
4009 : 0 : return 0;
4010 : : }
4011 : :
4012 : 0 : FlushStrBuf(LineBuf);
4013 [ # # ]: 0 : if (*Ptr==NULL)
4014 : 0 : ptr = aptr = Buf->buf;
4015 : : else
4016 : 0 : ptr = aptr = *Ptr;
4017 : :
4018 : 0 : optr = LineBuf->buf;
4019 : 0 : eptr = Buf->buf + Buf->BufUsed;
4020 : 0 : xptr = LineBuf->buf + LineBuf->BufSize - 1;
4021 : :
4022 [ # # ][ # # ]: 0 : while ((ptr <= eptr) &&
[ # # ]
4023 : 0 : (*ptr != '\n') &&
4024 : 0 : (*ptr != '\r') )
4025 : : {
4026 : 0 : *optr = *ptr;
4027 : 0 : optr++; ptr++;
4028 [ # # ]: 0 : if (optr == xptr) {
4029 : 0 : LineBuf->BufUsed = optr - LineBuf->buf;
4030 : 0 : IncreaseBuf(LineBuf, 1, LineBuf->BufUsed + 1);
4031 : 0 : optr = LineBuf->buf + LineBuf->BufUsed;
4032 : 0 : xptr = LineBuf->buf + LineBuf->BufSize - 1;
4033 : : }
4034 : : }
4035 : :
4036 [ # # ][ # # ]: 0 : if ((ptr >= eptr) && (optr > LineBuf->buf))
4037 : 0 : optr --;
4038 : 0 : LineBuf->BufUsed = optr - LineBuf->buf;
4039 : 0 : *optr = '\0';
4040 [ # # ][ # # ]: 0 : if ((ptr <= eptr) && (*ptr == '\r'))
4041 : 0 : ptr ++;
4042 [ # # ][ # # ]: 0 : if ((ptr <= eptr) && (*ptr == '\n'))
4043 : 0 : ptr ++;
4044 : :
4045 [ # # ]: 0 : if (ptr < eptr) {
4046 : 0 : *Ptr = ptr;
4047 : : }
4048 : : else {
4049 : 0 : *Ptr = StrBufNOTNULL;
4050 : : }
4051 : :
4052 : 0 : return Buf->BufUsed - (ptr - Buf->buf);
4053 : : }
4054 : :
4055 : :
4056 : : /**
4057 : : * @ingroup StrBuf_IO
4058 : : * @brief removes double slashes from pathnames
4059 : : * @param Dir directory string to filter
4060 : : * @param RemoveTrailingSlash allows / disallows trailing slashes
4061 : : */
4062 : 0 : void StrBufStripSlashes(StrBuf *Dir, int RemoveTrailingSlash)
4063 : : {
4064 : : char *a, *b;
4065 : :
4066 : 0 : a = b = Dir->buf;
4067 : :
4068 [ # # ]: 0 : while (!IsEmptyStr(a)) {
4069 [ # # ]: 0 : if (*a == '/') {
4070 [ # # ]: 0 : while (*a == '/')
4071 : 0 : a++;
4072 : 0 : *b = '/';
4073 : 0 : b++;
4074 : : }
4075 : : else {
4076 : 0 : *b = *a;
4077 : 0 : b++; a++;
4078 : : }
4079 : : }
4080 [ # # ][ # # ]: 0 : if ((RemoveTrailingSlash) && (*(b - 1) != '/')){
4081 : 0 : *b = '/';
4082 : 0 : b++;
4083 : : }
4084 : 0 : *b = '\0';
4085 : 0 : Dir->BufUsed = b - Dir->buf;
4086 : 0 : }
4087 : :
4088 : :
|