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