1 /* GSK - a library to write servers
2 Copyright (C) 1999-2000 Dave Benson
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18 Contact:
19 daveb@ffem.org <Dave Benson>
20 */
21
22 /* Free blocks to hold around to avoid repeated mallocs... */
23 #define MAX_RECYCLED 16
24
25 /* Size of allocations to make. */
26 #define BUF_CHUNK_SIZE 32768
27
28 /* Max fragments in the iovector to writev. */
29 #define MAX_FRAGMENTS_TO_WRITE 16
30
31 /* This causes fragments not to be transferred from buffer to buffer,
32 * and not to be allocated in pools. The result is that stack-trace
33 * based debug-allocators work much better with this on.
34 *
35 * On the other hand, this can mask over some abuses (eg stack-based
36 * foreign buffer fragment bugs) so we disable it by default.
37 */
38 #define GSK_DEBUG_BUFFER_ALLOCATIONS 0
39
40 #include "config.h"
41 #include "gskmacros.h"
42 #include <sys/types.h>
43 #if HAVE_WRITEV
44 #include <sys/uio.h>
45 #endif
46 #include <unistd.h>
47 #include <string.h>
48 #include <errno.h>
49 #include "gskbuffer.h"
50 #include "gskerrno.h"
51
52 /* --- GskBufferFragment implementation --- */
53 static inline int
gsk_buffer_fragment_avail(GskBufferFragment * frag)54 gsk_buffer_fragment_avail (GskBufferFragment *frag)
55 {
56 return frag->buf_max_size - frag->buf_start - frag->buf_length;
57 }
58 static inline char *
gsk_buffer_fragment_start(GskBufferFragment * frag)59 gsk_buffer_fragment_start (GskBufferFragment *frag)
60 {
61 return frag->buf + frag->buf_start;
62 }
63 static inline char *
gsk_buffer_fragment_end(GskBufferFragment * frag)64 gsk_buffer_fragment_end (GskBufferFragment *frag)
65 {
66 return frag->buf + frag->buf_start + frag->buf_length;
67 }
68
69 /* --- GskBufferFragment recycling --- */
70 #if !GSK_DEBUG_BUFFER_ALLOCATIONS
71 static int num_recycled = 0;
72 static GskBufferFragment* recycling_stack = 0;
73 G_LOCK_DEFINE_STATIC (recycling_stack);
74
75 #endif
76
77 static GskBufferFragment *
new_native_fragment()78 new_native_fragment()
79 {
80 GskBufferFragment *frag;
81 #if GSK_DEBUG_BUFFER_ALLOCATIONS
82 frag = (GskBufferFragment *) g_malloc (BUF_CHUNK_SIZE);
83 frag->buf_max_size = BUF_CHUNK_SIZE - sizeof (GskBufferFragment);
84 #else /* optimized (?) */
85 G_LOCK (recycling_stack);
86 if (recycling_stack)
87 {
88 frag = recycling_stack;
89 recycling_stack = recycling_stack->next;
90 num_recycled--;
91 G_UNLOCK (recycling_stack);
92 }
93 else
94 {
95 G_UNLOCK (recycling_stack);
96 frag = (GskBufferFragment *) g_malloc (BUF_CHUNK_SIZE);
97 frag->buf_max_size = BUF_CHUNK_SIZE - sizeof (GskBufferFragment);
98 }
99 #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
100 frag->buf_start = frag->buf_length = 0;
101 frag->next = 0;
102 frag->buf = (char *) (frag + 1);
103 frag->is_foreign = 0;
104 return frag;
105 }
106
107 static GskBufferFragment *
new_foreign_fragment(gconstpointer ptr,int length,GDestroyNotify destroy,gpointer ddata)108 new_foreign_fragment (gconstpointer ptr,
109 int length,
110 GDestroyNotify destroy,
111 gpointer ddata)
112 {
113 GskBufferFragment *fragment;
114 fragment = g_slice_new (GskBufferFragment);
115 fragment->is_foreign = 1;
116 fragment->buf_start = 0;
117 fragment->buf_length = length;
118 fragment->buf_max_size = length;
119 fragment->next = NULL;
120 fragment->buf = (char *) ptr;
121 fragment->destroy = destroy;
122 fragment->destroy_data = ddata;
123 return fragment;
124 }
125
126 #if GSK_DEBUG_BUFFER_ALLOCATIONS
127 #define recycle(frag) G_STMT_START{ \
128 if (frag->is_foreign) { \
129 { if (frag->destroy) frag->destroy (frag->destroy_data); \
130 g_slice_free(GskBufferFragment, frag); } \
131 else g_free (frag); \
132 }G_STMT_END
133 #else /* optimized (?) */
134 static void
recycle(GskBufferFragment * frag)135 recycle(GskBufferFragment* frag)
136 {
137 if (frag->is_foreign)
138 {
139 if (frag->destroy)
140 frag->destroy (frag->destroy_data);
141 g_slice_free (GskBufferFragment, frag);
142 return;
143 }
144 G_LOCK (recycling_stack);
145 #if defined(MAX_RECYCLED)
146 if (num_recycled >= MAX_RECYCLED)
147 {
148 g_free (frag);
149 G_UNLOCK (recycling_stack);
150 return;
151 }
152 #endif
153 frag->next = recycling_stack;
154 recycling_stack = frag;
155 num_recycled++;
156 G_UNLOCK (recycling_stack);
157 }
158 #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
159
160 /* --- Global public methods --- */
161 /**
162 * gsk_buffer_cleanup_recycling_bin:
163 *
164 * Free unused buffer fragments. (Normally some are
165 * kept around to reduce strain on the global allocator.)
166 */
167 void
gsk_buffer_cleanup_recycling_bin()168 gsk_buffer_cleanup_recycling_bin ()
169 {
170 #if !GSK_DEBUG_BUFFER_ALLOCATIONS
171 G_LOCK (recycling_stack);
172 while (recycling_stack != NULL)
173 {
174 GskBufferFragment *next;
175 next = recycling_stack->next;
176 g_free (recycling_stack);
177 recycling_stack = next;
178 }
179 num_recycled = 0;
180 G_UNLOCK (recycling_stack);
181 #endif
182 }
183
184 /* --- Public methods --- */
185 /**
186 * gsk_buffer_construct:
187 * @buffer: buffer to initialize (as empty).
188 *
189 * Construct an empty buffer out of raw memory.
190 * (This is equivalent to filling the buffer with 0s)
191 */
192 void
gsk_buffer_construct(GskBuffer * buffer)193 gsk_buffer_construct(GskBuffer *buffer)
194 {
195 buffer->first_frag = buffer->last_frag = NULL;
196 buffer->size = 0;
197 }
198
199 #if defined(GSK_DEBUG) || GSK_DEBUG_BUFFER_ALLOCATIONS
200 static inline gboolean
verify_buffer(const GskBuffer * buffer)201 verify_buffer (const GskBuffer *buffer)
202 {
203 const GskBufferFragment *frag;
204 guint total = 0;
205 for (frag = buffer->first_frag; frag != NULL; frag = frag->next)
206 total += frag->buf_length;
207 return total == buffer->size;
208 }
209 #define CHECK_INTEGRITY(buffer) g_assert (verify_buffer (buffer))
210 #else
211 #define CHECK_INTEGRITY(buffer)
212 #endif
213
214 /**
215 * gsk_buffer_append:
216 * @buffer: the buffer to add data to. Data is put at the end of the buffer.
217 * @data: binary data to add to the buffer.
218 * @length: length of @data to add to the buffer.
219 *
220 * Append data into the buffer.
221 */
222 void
gsk_buffer_append(GskBuffer * buffer,gconstpointer data,guint length)223 gsk_buffer_append(GskBuffer *buffer,
224 gconstpointer data,
225 guint length)
226 {
227 CHECK_INTEGRITY (buffer);
228 buffer->size += length;
229 while (length > 0)
230 {
231 guint avail;
232 if (!buffer->last_frag)
233 {
234 buffer->last_frag = buffer->first_frag = new_native_fragment ();
235 avail = gsk_buffer_fragment_avail (buffer->last_frag);
236 }
237 else
238 {
239 avail = gsk_buffer_fragment_avail (buffer->last_frag);
240 if (avail <= 0)
241 {
242 buffer->last_frag->next = new_native_fragment ();
243 avail = gsk_buffer_fragment_avail (buffer->last_frag);
244 buffer->last_frag = buffer->last_frag->next;
245 }
246 }
247 if (avail > length)
248 avail = length;
249 memcpy (gsk_buffer_fragment_end (buffer->last_frag), data, avail);
250 data = (const char *) data + avail;
251 length -= avail;
252 buffer->last_frag->buf_length += avail;
253 }
254 CHECK_INTEGRITY (buffer);
255 }
256
257 void
gsk_buffer_append_repeated_char(GskBuffer * buffer,char character,gsize count)258 gsk_buffer_append_repeated_char (GskBuffer *buffer,
259 char character,
260 gsize count)
261 {
262 CHECK_INTEGRITY (buffer);
263 buffer->size += count;
264 while (count > 0)
265 {
266 guint avail;
267 if (!buffer->last_frag)
268 {
269 buffer->last_frag = buffer->first_frag = new_native_fragment ();
270 avail = gsk_buffer_fragment_avail (buffer->last_frag);
271 }
272 else
273 {
274 avail = gsk_buffer_fragment_avail (buffer->last_frag);
275 if (avail <= 0)
276 {
277 buffer->last_frag->next = new_native_fragment ();
278 avail = gsk_buffer_fragment_avail (buffer->last_frag);
279 buffer->last_frag = buffer->last_frag->next;
280 }
281 }
282 if (avail > count)
283 avail = count;
284 memset (gsk_buffer_fragment_end (buffer->last_frag), character, avail);
285 count -= avail;
286 buffer->last_frag->buf_length += avail;
287 }
288 CHECK_INTEGRITY (buffer);
289 }
290
291 #if 0
292 void
293 gsk_buffer_append_repeated_data (GskBuffer *buffer,
294 gconstpointer data_to_repeat,
295 gsize data_length,
296 gsize count)
297 {
298 ...
299 }
300 #endif
301
302 /**
303 * gsk_buffer_append_string:
304 * @buffer: the buffer to add data to. Data is put at the end of the buffer.
305 * @string: NUL-terminated string to append to the buffer.
306 * The NUL is not appended.
307 *
308 * Append a string to the buffer.
309 */
310 void
gsk_buffer_append_string(GskBuffer * buffer,const char * string)311 gsk_buffer_append_string(GskBuffer *buffer,
312 const char *string)
313 {
314 g_return_if_fail (string != NULL);
315 gsk_buffer_append (buffer, string, strlen (string));
316 }
317
318 /**
319 * gsk_buffer_append_char:
320 * @buffer: the buffer to add the byte to.
321 * @character: the byte to add to the buffer.
322 *
323 * Append a byte to a buffer.
324 */
325 void
gsk_buffer_append_char(GskBuffer * buffer,char character)326 gsk_buffer_append_char(GskBuffer *buffer,
327 char character)
328 {
329 gsk_buffer_append (buffer, &character, 1);
330 }
331
332 /**
333 * gsk_buffer_append_string0:
334 * @buffer: the buffer to add data to. Data is put at the end of the buffer.
335 * @string: NUL-terminated string to append to the buffer;
336 * NUL is appended.
337 *
338 * Append a NUL-terminated string to the buffer. The NUL is appended.
339 */
340 void
gsk_buffer_append_string0(GskBuffer * buffer,const char * string)341 gsk_buffer_append_string0 (GskBuffer *buffer,
342 const char *string)
343 {
344 gsk_buffer_append (buffer, string, strlen (string) + 1);
345 }
346
347 /**
348 * gsk_buffer_read:
349 * @buffer: the buffer to read data from.
350 * @data: buffer to fill with up to @max_length bytes of data.
351 * @max_length: maximum number of bytes to read.
352 *
353 * Removes up to @max_length data from the beginning of the buffer,
354 * and writes it to @data. The number of bytes actually read
355 * is returned.
356 *
357 * returns: number of bytes transferred.
358 */
359 guint
gsk_buffer_read(GskBuffer * buffer,gpointer data,guint max_length)360 gsk_buffer_read(GskBuffer *buffer,
361 gpointer data,
362 guint max_length)
363 {
364 guint rv = 0;
365 guint orig_max_length = max_length;
366 CHECK_INTEGRITY (buffer);
367 while (max_length > 0 && buffer->first_frag)
368 {
369 GskBufferFragment *first = buffer->first_frag;
370 if (first->buf_length <= max_length)
371 {
372 memcpy (data, gsk_buffer_fragment_start (first), first->buf_length);
373 rv += first->buf_length;
374 data = (char *) data + first->buf_length;
375 max_length -= first->buf_length;
376 buffer->first_frag = first->next;
377 if (!buffer->first_frag)
378 buffer->last_frag = NULL;
379 recycle (first);
380 }
381 else
382 {
383 memcpy (data, gsk_buffer_fragment_start (first), max_length);
384 rv += max_length;
385 first->buf_length -= max_length;
386 first->buf_start += max_length;
387 data = (char *) data + max_length;
388 max_length = 0;
389 }
390 }
391 buffer->size -= rv;
392 g_assert (rv == orig_max_length || buffer->size == 0);
393 CHECK_INTEGRITY (buffer);
394 return rv;
395 }
396
397 /**
398 * gsk_buffer_peek:
399 * @buffer: the buffer to peek data from the front of.
400 * This buffer is unchanged by the operation.
401 * @data: buffer to fill with up to @max_length bytes of data.
402 * @max_length: maximum number of bytes to peek.
403 *
404 * Copies up to @max_length data from the beginning of the buffer,
405 * and writes it to @data. The number of bytes actually copied
406 * is returned.
407 *
408 * This function is just like gsk_buffer_read() except that the
409 * data is not removed from the buffer.
410 *
411 * returns: number of bytes copied into data.
412 */
413 guint
gsk_buffer_peek(const GskBuffer * buffer,gpointer data,guint max_length)414 gsk_buffer_peek (const GskBuffer *buffer,
415 gpointer data,
416 guint max_length)
417 {
418 int rv = 0;
419 GskBufferFragment *frag = (GskBufferFragment *) buffer->first_frag;
420 CHECK_INTEGRITY (buffer);
421 while (max_length > 0 && frag)
422 {
423 if (frag->buf_length <= max_length)
424 {
425 memcpy (data, gsk_buffer_fragment_start (frag), frag->buf_length);
426 rv += frag->buf_length;
427 data = (char *) data + frag->buf_length;
428 max_length -= frag->buf_length;
429 frag = frag->next;
430 }
431 else
432 {
433 memcpy (data, gsk_buffer_fragment_start (frag), max_length);
434 rv += max_length;
435 data = (char *) data + max_length;
436 max_length = 0;
437 }
438 }
439 return rv;
440 }
441
442 /**
443 * gsk_buffer_read_line:
444 * @buffer: buffer to read a line from.
445 *
446 * Parse a newline (\n) terminated line from
447 * buffer and return it as a newly allocated string.
448 * The newline is changed to a NUL character.
449 *
450 * If the buffer does not contain a newline, then NULL is returned.
451 *
452 * returns: a newly allocated NUL-terminated string, or NULL.
453 */
454 char *
gsk_buffer_read_line(GskBuffer * buffer)455 gsk_buffer_read_line(GskBuffer *buffer)
456 {
457 int len = 0;
458 char *rv;
459 GskBufferFragment *at;
460 int newline_length;
461 CHECK_INTEGRITY (buffer);
462 for (at = buffer->first_frag; at; at = at->next)
463 {
464 char *start = gsk_buffer_fragment_start (at);
465 char *got;
466 got = memchr (start, '\n', at->buf_length);
467 if (got)
468 {
469 len += got - start;
470 break;
471 }
472 len += at->buf_length;
473 }
474 if (at == NULL)
475 return NULL;
476 rv = g_new (char, len + 1);
477 /* If we found a newline, read it out, truncating
478 * it with NUL before we return from the function... */
479 if (at)
480 newline_length = 1;
481 else
482 newline_length = 0;
483 gsk_buffer_read (buffer, rv, len + newline_length);
484 rv[len] = 0;
485 CHECK_INTEGRITY (buffer);
486 return rv;
487 }
488
489 /**
490 * gsk_buffer_parse_string0:
491 * @buffer: buffer to read a line from.
492 *
493 * Parse a NUL-terminated line from
494 * buffer and return it as a newly allocated string.
495 *
496 * If the buffer does not contain a newline, then NULL is returned.
497 *
498 * returns: a newly allocated NUL-terminated string, or NULL.
499 */
500 char *
gsk_buffer_parse_string0(GskBuffer * buffer)501 gsk_buffer_parse_string0(GskBuffer *buffer)
502 {
503 int index0 = gsk_buffer_index_of (buffer, '\0');
504 char *rv;
505 if (index0 < 0)
506 return NULL;
507 rv = g_new (char, index0 + 1);
508 gsk_buffer_read (buffer, rv, index0 + 1);
509 return rv;
510 }
511
512 /**
513 * gsk_buffer_peek_char:
514 * @buffer: buffer to peek a single byte from.
515 *
516 * Get the first byte in the buffer as a positive or 0 number.
517 * If the buffer is empty, -1 is returned.
518 * The buffer is unchanged.
519 *
520 * returns: an unsigned character or -1.
521 */
522 int
gsk_buffer_peek_char(const GskBuffer * buffer)523 gsk_buffer_peek_char(const GskBuffer *buffer)
524 {
525 const GskBufferFragment *frag;
526
527 if (buffer->size == 0)
528 return -1;
529
530 for (frag = buffer->first_frag; frag; frag = frag->next)
531 if (frag->buf_length > 0)
532 break;
533 return * (const unsigned char *) (gsk_buffer_fragment_start ((GskBufferFragment*)frag));
534 }
535
536 /**
537 * gsk_buffer_read_char:
538 * @buffer: buffer to read a single byte from.
539 *
540 * Get the first byte in the buffer as a positive or 0 number,
541 * and remove the character from the buffer.
542 * If the buffer is empty, -1 is returned.
543 *
544 * returns: an unsigned character or -1.
545 */
546 int
gsk_buffer_read_char(GskBuffer * buffer)547 gsk_buffer_read_char (GskBuffer *buffer)
548 {
549 char c;
550 if (gsk_buffer_read (buffer, &c, 1) == 0)
551 return -1;
552 return (int) (guint8) c;
553 }
554
555 /**
556 * gsk_buffer_discard:
557 * @buffer: the buffer to discard data from.
558 * @max_discard: maximum number of bytes to discard.
559 *
560 * Removes up to @max_discard data from the beginning of the buffer,
561 * and returns the number of bytes actually discarded.
562 *
563 * returns: number of bytes discarded.
564 */
565 int
gsk_buffer_discard(GskBuffer * buffer,guint max_discard)566 gsk_buffer_discard(GskBuffer *buffer,
567 guint max_discard)
568 {
569 int rv = 0;
570 CHECK_INTEGRITY (buffer);
571 while (max_discard > 0 && buffer->first_frag)
572 {
573 GskBufferFragment *first = buffer->first_frag;
574 if (first->buf_length <= max_discard)
575 {
576 rv += first->buf_length;
577 max_discard -= first->buf_length;
578 buffer->first_frag = first->next;
579 if (!buffer->first_frag)
580 buffer->last_frag = NULL;
581 recycle (first);
582 }
583 else
584 {
585 rv += max_discard;
586 first->buf_length -= max_discard;
587 first->buf_start += max_discard;
588 max_discard = 0;
589 }
590 }
591 buffer->size -= rv;
592 CHECK_INTEGRITY (buffer);
593 return rv;
594 }
595
596 /**
597 * gsk_buffer_writev:
598 * @read_from: buffer to take data from.
599 * @fd: file-descriptor to write data to.
600 *
601 * Writes as much data as possible to the
602 * given file-descriptor using the writev(2)
603 * function to deal with multiple fragments
604 * efficiently, where available.
605 *
606 * returns: the number of bytes transferred,
607 * or -1 on a write error (consult errno).
608 */
609 int
gsk_buffer_writev(GskBuffer * read_from,int fd)610 gsk_buffer_writev (GskBuffer *read_from,
611 int fd)
612 {
613 int rv;
614 struct iovec *iov;
615 int nfrag, i;
616 GskBufferFragment *frag_at = read_from->first_frag;
617 CHECK_INTEGRITY (read_from);
618 for (nfrag = 0; frag_at != NULL
619 #ifdef MAX_FRAGMENTS_TO_WRITE
620 && nfrag < MAX_FRAGMENTS_TO_WRITE
621 #endif
622 ; nfrag++)
623 frag_at = frag_at->next;
624 iov = (struct iovec *) alloca (sizeof (struct iovec) * nfrag);
625 frag_at = read_from->first_frag;
626 for (i = 0; i < nfrag; i++)
627 {
628 iov[i].iov_len = frag_at->buf_length;
629 iov[i].iov_base = gsk_buffer_fragment_start (frag_at);
630 frag_at = frag_at->next;
631 }
632 rv = writev (fd, iov, nfrag);
633 if (rv < 0 && gsk_errno_is_ignorable (errno))
634 return 0;
635 if (rv <= 0)
636 return rv;
637 gsk_buffer_discard (read_from, rv);
638 return rv;
639 }
640
641 /**
642 * gsk_buffer_writev_len:
643 * @read_from: buffer to take data from.
644 * @fd: file-descriptor to write data to.
645 * @max_bytes: maximum number of bytes to write.
646 *
647 * Writes up to max_bytes bytes to the
648 * given file-descriptor using the writev(2)
649 * function to deal with multiple fragments
650 * efficiently, where available.
651 *
652 * returns: the number of bytes transferred,
653 * or -1 on a write error (consult errno).
654 */
655 int
gsk_buffer_writev_len(GskBuffer * read_from,int fd,guint max_bytes)656 gsk_buffer_writev_len (GskBuffer *read_from,
657 int fd,
658 guint max_bytes)
659 {
660 int rv;
661 struct iovec *iov;
662 int nfrag, i;
663 guint bytes;
664 GskBufferFragment *frag_at = read_from->first_frag;
665 CHECK_INTEGRITY (read_from);
666 for (nfrag = 0, bytes = 0; frag_at != NULL && bytes < max_bytes
667 #ifdef MAX_FRAGMENTS_TO_WRITE
668 && nfrag < MAX_FRAGMENTS_TO_WRITE
669 #endif
670 ; nfrag++)
671 {
672 bytes += frag_at->buf_length;
673 frag_at = frag_at->next;
674 }
675 iov = (struct iovec *) alloca (sizeof (struct iovec) * nfrag);
676 frag_at = read_from->first_frag;
677 for (bytes = max_bytes, i = 0; i < nfrag && bytes > 0; i++)
678 {
679 guint frag_bytes = MIN (frag_at->buf_length, bytes);
680 iov[i].iov_len = frag_bytes;
681 iov[i].iov_base = gsk_buffer_fragment_start (frag_at);
682 frag_at = frag_at->next;
683 bytes -= frag_bytes;
684 }
685 rv = writev (fd, iov, i);
686 if (rv < 0 && gsk_errno_is_ignorable (errno))
687 return 0;
688 if (rv <= 0)
689 return rv;
690 gsk_buffer_discard (read_from, rv);
691 return rv;
692 }
693
694 /**
695 * gsk_buffer_read_in_fd:
696 * @write_to: buffer to append data to.
697 * @read_from: file-descriptor to read data from.
698 *
699 * Append data into the buffer directly from the
700 * given file-descriptor.
701 *
702 * returns: the number of bytes transferred,
703 * or -1 on a read error (consult errno).
704 */
705 /* TODO: zero-copy! */
706 int
gsk_buffer_read_in_fd(GskBuffer * write_to,int read_from)707 gsk_buffer_read_in_fd(GskBuffer *write_to,
708 int read_from)
709 {
710 char buf[8192];
711 int rv = read (read_from, buf, sizeof (buf));
712 if (rv < 0)
713 return rv;
714 gsk_buffer_append (write_to, buf, rv);
715 return rv;
716 }
717
718 /**
719 * gsk_buffer_destruct:
720 * @to_destroy: the buffer to empty.
721 *
722 * Remove all fragments from a buffer, leaving it empty.
723 * The buffer is guaranteed to not to be consuming any resources,
724 * but it also is allowed to start using it again.
725 */
726 void
gsk_buffer_destruct(GskBuffer * to_destroy)727 gsk_buffer_destruct(GskBuffer *to_destroy)
728 {
729 GskBufferFragment *at = to_destroy->first_frag;
730 CHECK_INTEGRITY (to_destroy);
731 while (at)
732 {
733 GskBufferFragment *next = at->next;
734 recycle (at);
735 at = next;
736 }
737 to_destroy->first_frag = to_destroy->last_frag = NULL;
738 to_destroy->size = 0;
739 }
740
741 /**
742 * gsk_buffer_index_of:
743 * @buffer: buffer to scan.
744 * @char_to_find: a byte to look for.
745 *
746 * Scans for the first instance of the given character.
747 * returns: its index in the buffer, or -1 if the character
748 * is not in the buffer.
749 */
750 int
gsk_buffer_index_of(GskBuffer * buffer,char char_to_find)751 gsk_buffer_index_of(GskBuffer *buffer,
752 char char_to_find)
753 {
754 GskBufferFragment *at = buffer->first_frag;
755 int rv = 0;
756 while (at)
757 {
758 char *start = gsk_buffer_fragment_start (at);
759 char *saught = memchr (start, char_to_find, at->buf_length);
760 if (saught)
761 return (saught - start) + rv;
762 else
763 rv += at->buf_length;
764 at = at->next;
765 }
766 return -1;
767 }
768
769 /**
770 * gsk_buffer_str_index_of:
771 * @buffer: buffer to scan.
772 * @str_to_find: a string to look for.
773 *
774 * Scans for the first instance of the given string.
775 * returns: its index in the buffer, or -1 if the string
776 * is not in the buffer.
777 */
778 int
gsk_buffer_str_index_of(GskBuffer * buffer,const char * str_to_find)779 gsk_buffer_str_index_of (GskBuffer *buffer,
780 const char *str_to_find)
781 {
782 GskBufferFragment *frag = buffer->first_frag;
783 guint rv = 0;
784 for (frag = buffer->first_frag; frag; frag = frag->next)
785 {
786 const char *frag_at = frag->buf + frag->buf_start;
787 guint frag_rem = frag->buf_length;
788 while (frag_rem > 0)
789 {
790 GskBufferFragment *subfrag;
791 const char *subfrag_at;
792 guint subfrag_rem;
793 const char *str_at;
794 if (G_LIKELY (*frag_at != str_to_find[0]))
795 {
796 frag_at++;
797 frag_rem--;
798 rv++;
799 continue;
800 }
801 subfrag = frag;
802 subfrag_at = frag_at + 1;
803 subfrag_rem = frag_rem - 1;
804 str_at = str_to_find + 1;
805 if (*str_at == '\0')
806 return rv;
807 while (subfrag != NULL)
808 {
809 while (subfrag_rem == 0)
810 {
811 subfrag = subfrag->next;
812 if (subfrag == NULL)
813 goto bad_guess;
814 subfrag_at = subfrag->buf + subfrag->buf_start;
815 subfrag_rem = subfrag->buf_length;
816 }
817 while (*str_at != '\0' && subfrag_rem != 0)
818 {
819 if (*str_at++ != *subfrag_at++)
820 goto bad_guess;
821 subfrag_rem--;
822 }
823 if (*str_at == '\0')
824 return rv;
825 }
826 bad_guess:
827 frag_at++;
828 frag_rem--;
829 rv++;
830 }
831 }
832 return -1;
833 }
834
835 /**
836 * gsk_buffer_drain:
837 * @dst: buffer to add to.
838 * @src: buffer to remove from.
839 *
840 * Transfer all data from @src to @dst,
841 * leaving @src empty.
842 *
843 * returns: the number of bytes transferred.
844 */
845 #if GSK_DEBUG_BUFFER_ALLOCATIONS
846 guint
gsk_buffer_drain(GskBuffer * dst,GskBuffer * src)847 gsk_buffer_drain (GskBuffer *dst,
848 GskBuffer *src)
849 {
850 guint rv = src->size;
851 GskBufferFragment *frag;
852 CHECK_INTEGRITY (dst);
853 CHECK_INTEGRITY (src);
854 for (frag = src->first_frag; frag; frag = frag->next)
855 gsk_buffer_append (dst,
856 gsk_buffer_fragment_start (frag),
857 frag->buf_length);
858 gsk_buffer_discard (src, src->size);
859 CHECK_INTEGRITY (dst);
860 CHECK_INTEGRITY (src);
861 return rv;
862 }
863 #else /* optimized */
864 guint
gsk_buffer_drain(GskBuffer * dst,GskBuffer * src)865 gsk_buffer_drain (GskBuffer *dst,
866 GskBuffer *src)
867 {
868 guint rv = src->size;
869
870 CHECK_INTEGRITY (dst);
871 CHECK_INTEGRITY (src);
872 if (src->first_frag == NULL)
873 return rv;
874
875 dst->size += src->size;
876
877 if (dst->last_frag != NULL)
878 {
879 dst->last_frag->next = src->first_frag;
880 dst->last_frag = src->last_frag;
881 }
882 else
883 {
884 dst->first_frag = src->first_frag;
885 dst->last_frag = src->last_frag;
886 }
887 src->size = 0;
888 src->first_frag = src->last_frag = NULL;
889 CHECK_INTEGRITY (dst);
890 return rv;
891 }
892 #endif
893
894 /**
895 * gsk_buffer_transfer:
896 * @dst: place to copy data into.
897 * @src: place to read data from.
898 * @max_transfer: maximum number of bytes to transfer.
899 *
900 * Transfer data out of @src and into @dst.
901 * Data is removed from @src. The number of bytes
902 * transferred is returned.
903 *
904 * returns: the number of bytes transferred.
905 */
906 #if GSK_DEBUG_BUFFER_ALLOCATIONS
907 guint
gsk_buffer_transfer(GskBuffer * dst,GskBuffer * src,guint max_transfer)908 gsk_buffer_transfer(GskBuffer *dst,
909 GskBuffer *src,
910 guint max_transfer)
911 {
912 guint rv = 0;
913 GskBufferFragment *frag;
914 CHECK_INTEGRITY (dst);
915 CHECK_INTEGRITY (src);
916 for (frag = src->first_frag; frag && max_transfer > 0; frag = frag->next)
917 {
918 guint len = frag->buf_length;
919 if (len >= max_transfer)
920 {
921 gsk_buffer_append (dst, gsk_buffer_fragment_start (frag), max_transfer);
922 rv += max_transfer;
923 break;
924 }
925 else
926 {
927 gsk_buffer_append (dst, gsk_buffer_fragment_start (frag), len);
928 rv += len;
929 max_transfer -= len;
930 }
931 }
932 gsk_buffer_discard (src, rv);
933 CHECK_INTEGRITY (dst);
934 CHECK_INTEGRITY (src);
935 return rv;
936 }
937 #else /* optimized */
938 guint
gsk_buffer_transfer(GskBuffer * dst,GskBuffer * src,guint max_transfer)939 gsk_buffer_transfer(GskBuffer *dst,
940 GskBuffer *src,
941 guint max_transfer)
942 {
943 guint rv = 0;
944 CHECK_INTEGRITY (dst);
945 CHECK_INTEGRITY (src);
946 while (src->first_frag && max_transfer >= src->first_frag->buf_length)
947 {
948 GskBufferFragment *frag = src->first_frag;
949 src->first_frag = frag->next;
950 frag->next = NULL;
951 if (src->first_frag == NULL)
952 src->last_frag = NULL;
953
954 if (dst->last_frag)
955 dst->last_frag->next = frag;
956 else
957 dst->first_frag = frag;
958 dst->last_frag = frag;
959
960 rv += frag->buf_length;
961 max_transfer -= frag->buf_length;
962 }
963 dst->size += rv;
964 if (src->first_frag && max_transfer)
965 {
966 GskBufferFragment *frag = src->first_frag;
967 gsk_buffer_append (dst, gsk_buffer_fragment_start (frag), max_transfer);
968 frag->buf_start += max_transfer;
969 frag->buf_length -= max_transfer;
970 rv += max_transfer;
971 }
972 src->size -= rv;
973 CHECK_INTEGRITY (dst);
974 CHECK_INTEGRITY (src);
975 return rv;
976 }
977 #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
978
979 /* --- foreign data --- */
980 /**
981 * gsk_buffer_append_foreign:
982 * @buffer: the buffer to append into.
983 * @data: the data to append.
984 * @length: length of @data.
985 * @destroy: optional method to call when the data is no longer needed.
986 * @destroy_data: the argument to the destroy method.
987 *
988 * This function allows data to be placed in a buffer without
989 * copying. It is the callers' responsibility to ensure that
990 * @data will remain valid until the destroy method is called.
991 * @destroy may be omitted if @data is permanent, for example,
992 * if appended a static string into a buffer.
993 */
gsk_buffer_append_foreign(GskBuffer * buffer,gconstpointer data,int length,GDestroyNotify destroy,gpointer destroy_data)994 void gsk_buffer_append_foreign (GskBuffer *buffer,
995 gconstpointer data,
996 int length,
997 GDestroyNotify destroy,
998 gpointer destroy_data)
999 {
1000 GskBufferFragment *fragment;
1001
1002 CHECK_INTEGRITY (buffer);
1003
1004 fragment = new_foreign_fragment (data, length, destroy, destroy_data);
1005 fragment->next = NULL;
1006
1007 if (buffer->last_frag == NULL)
1008 buffer->first_frag = fragment;
1009 else
1010 buffer->last_frag->next = fragment;
1011
1012 buffer->last_frag = fragment;
1013 buffer->size += length;
1014
1015 CHECK_INTEGRITY (buffer);
1016 }
1017
1018 /**
1019 * gsk_buffer_printf:
1020 * @buffer: the buffer to append to.
1021 * @format: printf-style format string describing what to append to buffer.
1022 * @Varargs: values referenced by @format string.
1023 *
1024 * Append printf-style content to a buffer.
1025 */
gsk_buffer_printf(GskBuffer * buffer,const char * format,...)1026 void gsk_buffer_printf (GskBuffer *buffer,
1027 const char *format,
1028 ...)
1029 {
1030 va_list args;
1031 va_start (args, format);
1032 gsk_buffer_vprintf (buffer, format, args);
1033 va_end (args);
1034 }
1035
1036 /**
1037 * gsk_buffer_vprintf:
1038 * @buffer: the buffer to append to.
1039 * @format: printf-style format string describing what to append to buffer.
1040 * @args: values referenced by @format string.
1041 *
1042 * Append printf-style content to a buffer, given a va_list.
1043 */
gsk_buffer_vprintf(GskBuffer * buffer,const char * format,va_list args)1044 void gsk_buffer_vprintf (GskBuffer *buffer,
1045 const char *format,
1046 va_list args)
1047 {
1048 gsize size = g_printf_string_upper_bound (format, args);
1049 if (size < 1024)
1050 {
1051 char buf[1024];
1052 g_vsnprintf (buf, sizeof (buf), format, args);
1053 gsk_buffer_append_string (buffer, buf);
1054 }
1055 else
1056 {
1057 char *buf = g_strdup_vprintf (format, args);
1058 gsk_buffer_append_foreign (buffer, buf, strlen (buf), g_free, buf);
1059 }
1060 }
1061
1062 /* --- gsk_buffer_polystr_index_of implementation --- */
1063 /* Test to see if a sequence of buffer fragments
1064 * starts with a particular NUL-terminated string.
1065 */
1066 static gboolean
fragment_n_str(GskBufferFragment * frag,guint frag_index,const char * string)1067 fragment_n_str(GskBufferFragment *frag,
1068 guint frag_index,
1069 const char *string)
1070 {
1071 guint len = strlen (string);
1072 for (;;)
1073 {
1074 guint test_len = frag->buf_length - frag_index;
1075 if (test_len > len)
1076 test_len = len;
1077
1078 if (memcmp (string,
1079 gsk_buffer_fragment_start (frag) + frag_index,
1080 test_len) != 0)
1081 return FALSE;
1082
1083 len -= test_len;
1084 string += test_len;
1085
1086 if (len <= 0)
1087 return TRUE;
1088 frag_index += test_len;
1089 if (frag_index >= frag->buf_length)
1090 {
1091 frag = frag->next;
1092 if (frag == NULL)
1093 return FALSE;
1094 }
1095 }
1096 }
1097
1098 /**
1099 * gsk_buffer_polystr_index_of:
1100 * @buffer: buffer to scan.
1101 * @strings: NULL-terminated set of string.
1102 *
1103 * Scans for the first instance of any of the strings
1104 * in the buffer.
1105 *
1106 * returns: the index of that instance, or -1 if not found.
1107 */
1108 int
gsk_buffer_polystr_index_of(GskBuffer * buffer,char ** strings)1109 gsk_buffer_polystr_index_of (GskBuffer *buffer,
1110 char **strings)
1111 {
1112 guint8 init_char_map[16];
1113 int num_strings;
1114 int num_bits = 0;
1115 int total_index = 0;
1116 GskBufferFragment *frag;
1117 memset (init_char_map, 0, sizeof (init_char_map));
1118 for (num_strings = 0; strings[num_strings] != NULL; num_strings++)
1119 {
1120 guint8 c = strings[num_strings][0];
1121 guint8 mask = (1 << (c % 8));
1122 guint8 *rack = init_char_map + (c / 8);
1123 if ((*rack & mask) == 0)
1124 {
1125 *rack |= mask;
1126 num_bits++;
1127 }
1128 }
1129 if (num_bits == 0)
1130 return 0;
1131 for (frag = buffer->first_frag; frag != NULL; frag = frag->next)
1132 {
1133 const char *frag_start;
1134 const char *at;
1135 int remaining = frag->buf_length;
1136 frag_start = gsk_buffer_fragment_start (frag);
1137 at = frag_start;
1138 while (at != NULL)
1139 {
1140 const char *start = at;
1141 if (num_bits == 1)
1142 {
1143 at = memchr (start, strings[0][0], remaining);
1144 if (at == NULL)
1145 remaining = 0;
1146 else
1147 remaining -= (at - start);
1148 }
1149 else
1150 {
1151 while (remaining > 0)
1152 {
1153 guint8 i = (guint8) (*at);
1154 if (init_char_map[i / 8] & (1 << (i % 8)))
1155 break;
1156 remaining--;
1157 at++;
1158 }
1159 if (remaining == 0)
1160 at = NULL;
1161 }
1162
1163 if (at == NULL)
1164 break;
1165
1166 /* Now test each of the strings manually. */
1167 {
1168 char **test;
1169 for (test = strings; *test != NULL; test++)
1170 {
1171 if (fragment_n_str(frag, at - frag_start, *test))
1172 return total_index + (at - frag_start);
1173 }
1174 at++;
1175 }
1176 }
1177 total_index += frag->buf_length;
1178 }
1179 return -1;
1180 }
1181
1182 /* --- GskBufferIterator --- */
1183
1184 /**
1185 * gsk_buffer_iterator_construct:
1186 * @iterator: to initialize.
1187 * @to_iterate: the buffer to walk through.
1188 *
1189 * Initialize a new #GskBufferIterator.
1190 */
1191 void
gsk_buffer_iterator_construct(GskBufferIterator * iterator,GskBuffer * to_iterate)1192 gsk_buffer_iterator_construct (GskBufferIterator *iterator,
1193 GskBuffer *to_iterate)
1194 {
1195 iterator->fragment = to_iterate->first_frag;
1196 if (iterator->fragment != NULL)
1197 {
1198 iterator->in_cur = 0;
1199 iterator->cur_data = (guint8*)gsk_buffer_fragment_start (iterator->fragment);
1200 iterator->cur_length = iterator->fragment->buf_length;
1201 }
1202 else
1203 {
1204 iterator->in_cur = 0;
1205 iterator->cur_data = NULL;
1206 iterator->cur_length = 0;
1207 }
1208 iterator->offset = 0;
1209 }
1210
1211 /**
1212 * gsk_buffer_iterator_peek:
1213 * @iterator: to peek data from.
1214 * @out: to copy data into.
1215 * @max_length: maximum number of bytes to write to @out.
1216 *
1217 * Peek data from the current position of an iterator.
1218 * The iterator's position is not changed.
1219 *
1220 * returns: number of bytes peeked into @out.
1221 */
1222 guint
gsk_buffer_iterator_peek(GskBufferIterator * iterator,gpointer out,guint max_length)1223 gsk_buffer_iterator_peek (GskBufferIterator *iterator,
1224 gpointer out,
1225 guint max_length)
1226 {
1227 GskBufferFragment *fragment = iterator->fragment;
1228
1229 guint frag_length = iterator->cur_length;
1230 const guint8 *frag_data = iterator->cur_data;
1231 guint in_frag = iterator->in_cur;
1232
1233 guint out_remaining = max_length;
1234 guint8 *out_at = out;
1235
1236 while (fragment != NULL)
1237 {
1238 guint frag_remaining = frag_length - in_frag;
1239 if (out_remaining <= frag_remaining)
1240 {
1241 memcpy (out_at, frag_data + in_frag, out_remaining);
1242 out_remaining = 0;
1243 break;
1244 }
1245
1246 memcpy (out_at, frag_data + in_frag, frag_remaining);
1247 out_remaining -= frag_remaining;
1248 out_at += frag_remaining;
1249
1250 fragment = fragment->next;
1251 if (fragment != NULL)
1252 {
1253 frag_data = (guint8 *) gsk_buffer_fragment_start (fragment);
1254 frag_length = fragment->buf_length;
1255 }
1256 in_frag = 0;
1257 }
1258 return max_length - out_remaining;
1259 }
1260
1261 /**
1262 * gsk_buffer_iterator_read:
1263 * @iterator: to read data from.
1264 * @out: to copy data into.
1265 * @max_length: maximum number of bytes to write to @out.
1266 *
1267 * Peek data from the current position of an iterator.
1268 * The iterator's position is updated to be at the end of
1269 * the data read.
1270 *
1271 * returns: number of bytes read into @out.
1272 */
1273 guint
gsk_buffer_iterator_read(GskBufferIterator * iterator,gpointer out,guint max_length)1274 gsk_buffer_iterator_read (GskBufferIterator *iterator,
1275 gpointer out,
1276 guint max_length)
1277 {
1278 GskBufferFragment *fragment = iterator->fragment;
1279
1280 guint frag_length = iterator->cur_length;
1281 const guint8 *frag_data = iterator->cur_data;
1282 guint in_frag = iterator->in_cur;
1283
1284 guint out_remaining = max_length;
1285 guint8 *out_at = out;
1286
1287 while (fragment != NULL)
1288 {
1289 guint frag_remaining = frag_length - in_frag;
1290 if (out_remaining <= frag_remaining)
1291 {
1292 memcpy (out_at, frag_data + in_frag, out_remaining);
1293 in_frag += out_remaining;
1294 out_remaining = 0;
1295 break;
1296 }
1297
1298 memcpy (out_at, frag_data + in_frag, frag_remaining);
1299 out_remaining -= frag_remaining;
1300 out_at += frag_remaining;
1301
1302 fragment = fragment->next;
1303 if (fragment != NULL)
1304 {
1305 frag_data = (guint8 *) gsk_buffer_fragment_start (fragment);
1306 frag_length = fragment->buf_length;
1307 }
1308 in_frag = 0;
1309 }
1310 iterator->in_cur = in_frag;
1311 iterator->fragment = fragment;
1312 iterator->cur_length = frag_length;
1313 iterator->cur_data = frag_data;
1314 iterator->offset += max_length - out_remaining;
1315 return max_length - out_remaining;
1316 }
1317
1318 /**
1319 * gsk_buffer_iterator_find_char:
1320 * @iterator: to advance.
1321 * @c: the character to look for.
1322 *
1323 * If it exists,
1324 * skip forward to the next instance of @c and return TRUE.
1325 * Otherwise, do nothing and return FALSE.
1326 *
1327 * returns: whether the character was found.
1328 */
1329
1330 gboolean
gsk_buffer_iterator_find_char(GskBufferIterator * iterator,char c)1331 gsk_buffer_iterator_find_char (GskBufferIterator *iterator,
1332 char c)
1333 {
1334 GskBufferFragment *fragment = iterator->fragment;
1335
1336 guint frag_length = iterator->cur_length;
1337 const guint8 *frag_data = iterator->cur_data;
1338 guint in_frag = iterator->in_cur;
1339 guint new_offset = iterator->offset;
1340
1341 if (fragment == NULL)
1342 return -1;
1343
1344 for (;;)
1345 {
1346 guint frag_remaining = frag_length - in_frag;
1347 const guint8 * ptr = memchr (frag_data + in_frag, c, frag_remaining);
1348 if (ptr != NULL)
1349 {
1350 iterator->offset = (ptr - frag_data) - in_frag + new_offset;
1351 iterator->fragment = fragment;
1352 iterator->in_cur = ptr - frag_data;
1353 iterator->cur_length = frag_length;
1354 iterator->cur_data = frag_data;
1355 return TRUE;
1356 }
1357 fragment = fragment->next;
1358 if (fragment == NULL)
1359 return FALSE;
1360 new_offset += frag_length - in_frag;
1361 in_frag = 0;
1362 frag_length = fragment->buf_length;
1363 frag_data = (guint8 *) fragment->buf + fragment->buf_start;
1364 }
1365 }
1366
1367 /**
1368 * gsk_buffer_iterator_skip:
1369 * @iterator: to advance.
1370 * @max_length: maximum number of bytes to skip forward.
1371 *
1372 * Advance an iterator forward in the buffer,
1373 * returning the number of bytes skipped.
1374 *
1375 * returns: number of bytes skipped forward.
1376 */
1377 guint
gsk_buffer_iterator_skip(GskBufferIterator * iterator,guint max_length)1378 gsk_buffer_iterator_skip (GskBufferIterator *iterator,
1379 guint max_length)
1380 {
1381 GskBufferFragment *fragment = iterator->fragment;
1382
1383 guint frag_length = iterator->cur_length;
1384 const guint8 *frag_data = iterator->cur_data;
1385 guint in_frag = iterator->in_cur;
1386
1387 guint out_remaining = max_length;
1388
1389 while (fragment != NULL)
1390 {
1391 guint frag_remaining = frag_length - in_frag;
1392 if (out_remaining <= frag_remaining)
1393 {
1394 in_frag += out_remaining;
1395 out_remaining = 0;
1396 break;
1397 }
1398
1399 out_remaining -= frag_remaining;
1400
1401 fragment = fragment->next;
1402 if (fragment != NULL)
1403 {
1404 frag_data = (guint8 *) gsk_buffer_fragment_start (fragment);
1405 frag_length = fragment->buf_length;
1406 }
1407 else
1408 {
1409 frag_data = NULL;
1410 frag_length = 0;
1411 }
1412 in_frag = 0;
1413 }
1414 iterator->in_cur = in_frag;
1415 iterator->fragment = fragment;
1416 iterator->cur_length = frag_length;
1417 iterator->cur_data = frag_data;
1418 iterator->offset += max_length - out_remaining;
1419 return max_length - out_remaining;
1420 }
1421