1 /* string buffers
2  */
3 
4 /*
5 
6     Copyright (C) 1991-2003 The National Gallery
7 
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation; either
11     version 2.1 of the License, or (at your option) any later version.
12 
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Lesser General Public License for more details.
17 
18     You should have received a copy of the GNU Lesser General Public
19     License along with this library; if not, write to the Free Software
20     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21     02110-1301  USA
22 
23  */
24 
25 /*
26 
27     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
28 
29  */
30 
31 /*
32 #define DEBUG
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif /*HAVE_CONFIG_H*/
38 #include <vips/intl.h>
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <ctype.h>
44 
45 #include <vips/vips.h>
46 #include <vips/buf.h>
47 
48 /**
49  * SECTION: buf
50  * @short_description: a string you can append to
51  * @stability: Stable
52  * @see_also: #vips
53  * @include: vips/vips.h
54  *
55  * A message buffer you can append stuff to safely and quickly. If the message
56  * gets too long, you get "..." and truncation. Message buffers can be on the
57  * stack or heap.
58  *
59  * For example:
60  *
61  * |[
62  * char txt[256];
63  * VipsBuf buf = VIPS_BUF_STATIC (txt);
64  * int i;
65  *
66  * vips_buf_appends (&buf, "Numbers are: ");
67  * for (i = 0; i &lt; array_length; i++) {
68  *   if (i &gt; 0)
69  *     vips_buf_appends (&buf, ", ");
70  *   vips_buf_appendg (&buf, array[i]);
71  * }
72  * printf ("%s", vips_buf_all (&buf));
73  * ]|
74  */
75 
76 /**
77  * VIPS_BUF_STATIC:
78  * @TEXT: the storage area to use
79  *
80  * Initialize a heap buffer. For example:
81  *
82  * |[
83  * char txt[256];
84  * VipsBuf buf = VIPS_BUF_STATIC (txt);
85  * ]|
86  */
87 
88 /**
89  * vips_buf_rewind:
90  * @buf: the buffer
91  *
92  * Reset the buffer to the empty string.
93  */
94 void
vips_buf_rewind(VipsBuf * buf)95 vips_buf_rewind( VipsBuf *buf )
96 {
97 	buf->i = 0;
98 	buf->lasti = 0;
99 	buf->full = FALSE;
100 
101 	if( buf->base )
102 		buf->base[0] = '\0';
103 }
104 
105 /**
106  * vips_buf_init:
107  * @buf: the buffer
108  *
109  * Initialize a buffer.
110  */
111 void
vips_buf_init(VipsBuf * buf)112 vips_buf_init( VipsBuf *buf )
113 {
114 	buf->base = NULL;
115 	buf->mx = 0;
116 	buf->dynamic = FALSE;
117 	vips_buf_rewind( buf );
118 }
119 
120 /**
121  * vips_buf_destroy:
122  * @buf: the buffer
123  *
124  * Destroy a buffer. Only needed for heap buffers. Leaves the buffer in the
125  * _init state.
126  */
127 void
vips_buf_destroy(VipsBuf * buf)128 vips_buf_destroy( VipsBuf *buf )
129 {
130 	if( buf->dynamic ) {
131 		VIPS_FREE( buf->base );
132 	}
133 
134 	vips_buf_init( buf );
135 }
136 
137 /**
138  * vips_buf_set_static:
139  * @buf: the buffer
140  * @base: the start of the memory area to use for storage
141  * @mx: the size of the storage area
142  *
143  * Attach the buffer to a static memory area. The buffer needs to have been
144  * initialised. The memory area needs to be at least 4 bytes long.
145  */
146 void
vips_buf_set_static(VipsBuf * buf,char * base,int mx)147 vips_buf_set_static( VipsBuf *buf, char *base, int mx )
148 {
149 	g_assert( mx >= 4 );
150 
151 	vips_buf_destroy( buf );
152 
153 	buf->base = base;
154 	buf->mx = mx;
155 	buf->dynamic = FALSE;
156 	vips_buf_rewind( buf );
157 }
158 
159 /**
160  * vips_buf_init_static:
161  * @buf: the buffer
162  * @base: the start of the memory area to use for storage
163  * @mx: the size of the storage area
164  *
165  * Initialise and attach to a static memory area. VIPS_BUF_STATIC() is usually
166  * more convenient.
167  *
168  * For example:
169  *
170  * |[
171  * char txt[256];
172  * VipsBuf buf;
173  *
174  * vips_buf_init_static (&buf, txt, 256);
175  * ]|
176  *
177  * Static buffers don't need to be freed when they go out of scope, but their
178  * size must be set at compile-time.
179  */
180 void
vips_buf_init_static(VipsBuf * buf,char * base,int mx)181 vips_buf_init_static( VipsBuf *buf, char *base, int mx )
182 {
183 	vips_buf_init( buf );
184 	vips_buf_set_static( buf, base, mx );
185 }
186 
187 /**
188  * vips_buf_set_dynamic:
189  * @buf: the buffer
190  * @mx: the size of the storage area
191  *
192  * Attach the buffer to a heap memory area. The buffer needs to have been
193  * initialised. The memory area needs to be at least 4 bytes long.
194  */
195 void
vips_buf_set_dynamic(VipsBuf * buf,int mx)196 vips_buf_set_dynamic( VipsBuf *buf, int mx )
197 {
198 	g_assert( mx >= 4 );
199 
200 	if( buf->mx == mx && buf->dynamic )
201 		/* No change?
202 		 */
203 		vips_buf_rewind( buf );
204 	else {
205 		vips_buf_destroy( buf );
206 
207 		if( !(buf->base = VIPS_ARRAY( NULL, mx, char )) )
208 			/* No error return, so just block writes.
209 			 */
210 			buf->full = TRUE;
211 		else {
212 			buf->mx = mx;
213 			buf->dynamic = TRUE;
214 			vips_buf_rewind( buf );
215 		}
216 	}
217 }
218 
219 /**
220  * vips_buf_init_dynamic:
221  * @buf: the buffer
222  * @mx: the size of the storage area
223  *
224  * Initialise and attach to a heap memory area.
225  * The memory area needs to be at least 4 bytes long.
226  *
227  * |[
228  * VipsBuf buf;
229  *
230  * vips_buf_init_synamic (&buf, 256);
231  * ]|
232  *
233  * Dynamic buffers must be freed with vips_buf_destroy(), but their size can
234  * be set at runtime.
235  */
236 void
vips_buf_init_dynamic(VipsBuf * buf,int mx)237 vips_buf_init_dynamic( VipsBuf *buf, int mx )
238 {
239 	vips_buf_init( buf );
240 	vips_buf_set_dynamic( buf, mx );
241 }
242 
243 /**
244  * vips_buf_appendns:
245  * @buf: the buffer
246  * @str: the string to append to the buffer
247  * @sz: the size of the string to append
248  *
249  * Append at most @sz chars from @str to @buf. @sz < 0 means unlimited. This
250  * is the low-level append operation: functions like vips_buf_appendf() build
251  * on top of this.
252  *
253  * Returns: %FALSE on overflow, %TRUE otherwise.
254  */
255 gboolean
vips_buf_appendns(VipsBuf * buf,const char * str,int sz)256 vips_buf_appendns( VipsBuf *buf, const char *str, int sz )
257 {
258 	int len;
259 	int n;
260 	int avail;
261 	int cpy;
262 
263 	if( buf->full )
264 		return( FALSE );
265 
266 	/* Amount we want to copy.
267 	 */
268 	len = strlen( str );
269 	if( sz >= 0 )
270 		n = VIPS_MIN( sz, len );
271 	else
272 		n = len;
273 
274 	/* Space available.
275 	 */
276 	avail = buf->mx - buf->i - 4;
277 
278 	cpy = VIPS_MIN( n, avail );
279 
280 	/* Can't use vips_strncpy() here, we don't want to drop the end of the
281 	 * string.
282 	 *
283 	 * gcc10.3 (I think?) issues a false-positive warning about this.
284 	 */
285 #pragma GCC diagnostic push
286 #pragma GCC diagnostic ignored "-Wstringop-overflow"
287 	strncpy( buf->base + buf->i, str, cpy );
288 #pragma GCC diagnostic pop
289 	buf->i += cpy;
290 
291 	if( buf->i >= buf->mx - 4 ) {
292 		buf->full = TRUE;
293 		strcpy( buf->base + buf->mx - 4, "..." );
294 		buf->i = buf->mx - 1;
295 		return( FALSE );
296 	}
297 
298 	return( TRUE );
299 }
300 
301 /**
302  * vips_buf_appends:
303  * @buf: the buffer
304  * @str: the string to append to the buffer
305  *
306  * Append the whole of @str to @buf.
307  *
308  * Returns: %FALSE on overflow, %TRUE otherwise.
309  */
310 gboolean
vips_buf_appends(VipsBuf * buf,const char * str)311 vips_buf_appends( VipsBuf *buf, const char *str )
312 {
313 	return( vips_buf_appendns( buf, str, -1 ) );
314 }
315 
316 /**
317  * vips_buf_appendc:
318  * @buf: the buffer
319  * @ch: the character to append to the buffer
320  *
321  * Append a single character @ch to @buf.
322  *
323  * Returns: %FALSE on overflow, %TRUE otherwise.
324  */
325 gboolean
vips_buf_appendc(VipsBuf * buf,char ch)326 vips_buf_appendc( VipsBuf *buf, char ch )
327 {
328 	char tiny[2];
329 
330 	tiny[0] = ch;
331 	tiny[1] = '\0';
332 
333 	return( vips_buf_appendns( buf, tiny, 1 ) );
334 }
335 
336 /**
337  * vips_buf_change:
338  * @buf: the buffer
339  * @o: the string to search for
340  * @n: the string to substitute
341  *
342  * Swap the rightmost occurence of @o for @n.
343  *
344  * Returns: %FALSE on overflow, %TRUE otherwise.
345  */
346 gboolean
vips_buf_change(VipsBuf * buf,const char * old,const char * new)347 vips_buf_change( VipsBuf *buf, const char *old, const char *new )
348 {
349 	int olen = strlen( old );
350 	int nlen = strlen( new );
351 	int i;
352 
353 	if( buf->full )
354 		return( FALSE );
355 	if( buf->i - olen + nlen > buf->mx - 4 ) {
356 		buf->full = TRUE;
357 		return( FALSE );
358 	}
359 
360 	/* Find pos of old.
361 	 */
362 	for( i = buf->i - olen; i > 0; i-- )
363 		if( vips_isprefix( old, buf->base + i ) )
364 			break;
365 	g_assert( i >= 0 );
366 
367 	/* Move tail of buffer to make right-size space for new.
368 	 */
369 	memmove( buf->base + i + nlen, buf->base + i + olen,
370 		buf->i - i - olen );
371 
372 	/* Copy new in.
373 	 */
374 	memcpy( buf->base + i, new, nlen );
375 	buf->i = i + nlen + (buf->i - i - olen);
376 
377 	return( TRUE );
378 }
379 
380 /**
381  * vips_buf_removec:
382  * @buf: the buffer
383  * @ch: the character to remove
384  *
385  * Remove the last character, if it's @ch.
386  *
387  * Returns: %FALSE on failure, %TRUE otherwise.
388  */
389 gboolean
vips_buf_removec(VipsBuf * buf,char ch)390 vips_buf_removec( VipsBuf *buf, char ch )
391 {
392 	if( buf->full )
393 		return( FALSE );
394 	if( buf->i <= 0 )
395 		return( FALSE );
396 	if( buf->base[buf->i - 1] == ch )
397 		buf->i -= 1;
398 
399 	return( TRUE );
400 }
401 
402 /**
403  * vips_buf_vappendf:
404  * @buf: the buffer
405  * @fmt: <function>printf()</function>-style format string
406  * @ap: arguments to format string
407  *
408  * Append to @buf, args as <function>vprintf()</function>.
409  *
410  * Returns: %FALSE on overflow, %TRUE otherwise.
411  */
412 gboolean
vips_buf_vappendf(VipsBuf * buf,const char * fmt,va_list ap)413 vips_buf_vappendf( VipsBuf *buf, const char *fmt, va_list ap )
414 {
415 	int avail;
416 	char *p;
417 
418 	if( buf->full )
419 		return( FALSE );
420 
421 	avail = buf->mx - buf->i - 4;
422 	p = buf->base + buf->i;
423 	(void) vips_vsnprintf( p, avail, fmt, ap );
424 	buf->i += strlen( p );
425 
426 	if( buf->i >= buf->mx - 4 ) {
427 		buf->full = TRUE;
428 		strcpy( buf->base + buf->mx - 4, "..." );
429 		buf->i = buf->mx - 1;
430 		return( FALSE );
431 	}
432 
433 	return( TRUE );
434 }
435 
436 /**
437  * vips_buf_appendf:
438  * @buf: the buffer
439  * @fmt: <function>printf()</function>-style format string
440  * @...: arguments to format string
441  *
442  * Format the string and append to @buf.
443  *
444  * Returns: %FALSE on overflow, %TRUE otherwise.
445  */
446 gboolean
vips_buf_appendf(VipsBuf * buf,const char * fmt,...)447 vips_buf_appendf( VipsBuf *buf, const char *fmt, ... )
448 {
449 	va_list ap;
450 	gboolean result;
451 
452         va_start( ap, fmt );
453         result = vips_buf_vappendf( buf, fmt, ap );
454         va_end( ap );
455 
456 	return( result );
457 }
458 
459 /**
460  * vips_buf_appendg:
461  * @buf: the buffer
462  * @g: value to format and append
463  *
464  * Append a double, non-localised. Useful for config files etc.
465  *
466  * Returns: %FALSE on overflow, %TRUE otherwise.
467  */
468 gboolean
vips_buf_appendg(VipsBuf * buf,double g)469 vips_buf_appendg( VipsBuf *buf, double g )
470 {
471 	char text[G_ASCII_DTOSTR_BUF_SIZE];
472 
473 	g_ascii_dtostr( text, sizeof( text ), g );
474 
475 	return( vips_buf_appends( buf, text ) );
476 }
477 
478 /**
479  * vips_buf_appendd:
480  * @buf: the buffer
481  * @d: value to format and append
482  *
483  * Append a number. If the number is -ve, add brackets. Needed for
484  * building function arguments.
485  *
486  * Returns: %FALSE on overflow, %TRUE otherwise.
487  */
488 gboolean
vips_buf_appendd(VipsBuf * buf,int d)489 vips_buf_appendd( VipsBuf *buf, int d )
490 {
491 	if( d < 0 )
492 		return( vips_buf_appendf( buf, " (%d)", d ) );
493 	else
494 		return( vips_buf_appendf( buf, " %d", d ) );
495 }
496 
497 /**
498  * vips_buf_appendgv:
499  * @buf: the buffer
500  * @value: #GValue to format and append
501  *
502  * Format and append a #GValue as a printable thing. We display text line "3144
503  * bytes of binary data" for BLOBs like icc-profile-data.
504  *
505  * Use vips_image_get_as_string() to make a text representation of a field.
506  * That will base64-encode blobs, for example.
507  *
508  * Returns: %FALSE on overflow, %TRUE otherwise.
509  */
510 gboolean
vips_buf_appendgv(VipsBuf * buf,GValue * value)511 vips_buf_appendgv( VipsBuf *buf, GValue *value )
512 {
513 	GType type = G_VALUE_TYPE( value );
514 	GType fundamental = g_type_fundamental( type );
515 
516 	gboolean handled;
517 	gboolean result;
518 
519 	result = FALSE;
520 	handled = FALSE;
521 
522 	switch( fundamental ) {
523 	case G_TYPE_STRING:
524 {
525 		const char *str;
526 
527 		/* These are GStrings (gchararray). vips refstrings are
528 		 * handled by boxed, see below.
529 		 */
530 		str = g_value_get_string( value );
531 		result = vips_buf_appends( buf, str );
532 		handled = TRUE;
533 }
534 		break;
535 
536 	case G_TYPE_OBJECT:
537 {
538 		GObject *object;
539 
540 		object = g_value_get_object( value );
541 		if( VIPS_IS_OBJECT( object ) ) {
542 			vips_object_summary( VIPS_OBJECT( object ), buf );
543 			result = TRUE;
544 			handled = TRUE;
545 		}
546 }
547 		break;
548 
549 	case G_TYPE_INT:
550 		result = vips_buf_appendf( buf,
551 			"%d", g_value_get_int( value ) );
552 		handled = TRUE;
553 		break;
554 
555 	case G_TYPE_UINT64:
556 		result = vips_buf_appendf( buf,
557 			"%" G_GINT64_FORMAT, g_value_get_uint64( value ) );
558 		handled = TRUE;
559 		break;
560 
561 	case G_TYPE_DOUBLE:
562 		result = vips_buf_appendf( buf,
563 			"%g", g_value_get_double( value ) );
564 		handled = TRUE;
565 		break;
566 
567 	case G_TYPE_BOOLEAN:
568 		result = vips_buf_appends( buf,
569 			g_value_get_boolean( value ) ? "true" : "false" );
570 		handled = TRUE;
571 		break;
572 
573 	case G_TYPE_ENUM:
574 		result = vips_buf_appends( buf,
575 			vips_enum_nick( type, g_value_get_enum( value ) ) );
576 		handled = TRUE;
577 		break;
578 
579 	case G_TYPE_FLAGS:
580 {
581 		GFlagsClass *flags_class = g_type_class_ref( type );
582 
583 		GFlagsValue *v;
584 		int flags;
585 
586 		flags = g_value_get_flags( value );
587 
588 		while( flags &&
589 			(v = g_flags_get_first_value( flags_class, flags )) ) {
590 			result = vips_buf_appendf( buf, "%s ", v->value_nick );
591 			flags &= ~v->value;
592 		}
593 
594 		handled = TRUE;
595 }
596 		break;
597 
598 	case G_TYPE_BOXED:
599 		if( type == VIPS_TYPE_REF_STRING ) {
600 			const char *str;
601 			size_t str_len;
602 
603 			/* These should be printable.
604 			 */
605 			str = vips_value_get_ref_string( value, &str_len );
606 			result = vips_buf_appends( buf, str );
607 			handled = TRUE;
608 		}
609 		else if( type == VIPS_TYPE_BLOB ) {
610 			size_t str_len;
611 
612 			/* Binary data and not printable.
613 			 */
614 			(void) vips_value_get_ref_string( value, &str_len );
615 			result = vips_buf_appendf( buf,
616 				_( "%zd bytes of binary data" ), str_len );
617 			handled = TRUE;
618 		}
619 		else if( type == VIPS_TYPE_ARRAY_DOUBLE ) {
620 			double *arr;
621 			int n;
622 			int i;
623 
624 			arr = vips_value_get_array_double( value, &n );
625 			for( i = 0; i < n; i++ )
626 				result = vips_buf_appendf( buf, "%g ", arr[i] );
627 			handled = TRUE;
628 		}
629 		else if( type == VIPS_TYPE_ARRAY_INT ) {
630 			int *arr;
631 			int n;
632 			int i;
633 
634 			arr = vips_value_get_array_int( value, &n );
635 			for( i = 0; i < n; i++ )
636 				result = vips_buf_appendf( buf, "%d ", arr[i] );
637 			handled = TRUE;
638 		}
639 		else if( type == VIPS_TYPE_ARRAY_IMAGE ) {
640 			VipsImage **arr;
641 			int n;
642 			int i;
643 
644 			arr = vips_value_get_array_image( value, &n );
645 			for( i = 0; i < n; i++ ) {
646 				vips_object_summary( VIPS_OBJECT( arr[i] ),
647 					buf );
648 				result = vips_buf_appends( buf, " " );
649 			}
650 			handled = TRUE;
651 		}
652 		break;
653 
654 	default:
655 		break;
656 	}
657 
658 	if( !handled ) {
659 		char *str_value;
660 
661 		str_value = g_strdup_value_contents( value );
662 		result = vips_buf_appends( buf, str_value );
663 		g_free( str_value );
664 	}
665 
666 	return( result );
667 }
668 
669 /**
670  * vips_buf_append_size:
671  * @buf: the buffer
672  * @n: the number of bytes
673  *
674  * Turn a number of bytes into a sensible string ... eg "12", "12KB", "12MB",
675  * "12GB" etc.
676  *
677  * Returns: %FALSE on overflow, %TRUE otherwise.
678  */
679 gboolean
vips_buf_append_size(VipsBuf * buf,size_t n)680 vips_buf_append_size( VipsBuf *buf, size_t n )
681 {
682 	const static char *names[] = {
683 		/* File length unit.
684 		 */
685 		N_( "bytes" ),
686 
687 		/* Kilobyte unit.
688 		 */
689 		N_( "KB" ),
690 
691 		/* Megabyte unit.
692 		 */
693 		N_( "MB" ),
694 
695 		/* Gigabyte unit.
696 		 */
697 		N_( "GB" ),
698 
699 		/* Terabyte unit.
700 		 */
701 		N_( "TB" )
702 	};
703 
704 	double sz = n;
705 	int i;
706 
707 	/* -1, since we want to stop at TB, not run off the end.
708 	 */
709 	for( i = 0; sz > 1024 && i < VIPS_NUMBER( names ) - 1; sz /= 1024, i++ )
710 		;
711 
712 	if( i == 0 )
713 		/* No decimal places for bytes.
714 		 */
715 		return( vips_buf_appendf( buf, "%g %s", sz, _( names[i] ) ) );
716 	else
717 		return( vips_buf_appendf( buf, "%.2f %s", sz, _( names[i] ) ) );
718 }
719 
720 /**
721  * vips_buf_all:
722  * @buf: the buffer
723  *
724  * Return the contents of the buffer as a C string.
725  *
726  * Returns: the %NULL-terminated contents of the buffer. This is a pointer to
727  * the memory managed by the buffer and must not be freed.
728  */
729 const char *
vips_buf_all(VipsBuf * buf)730 vips_buf_all( VipsBuf *buf )
731 {
732 	buf->base[buf->i] = '\0';
733 
734 	return( buf->base );
735 }
736 
737 /**
738  * vips_buf_firstline:
739  * @buf: the buffer
740  *
741  * Trim to just the first line (excluding "\n").
742  *
743  * Returns: the %NULL-terminated contents of the buffer. This is a pointer to
744  * the memory managed by the buffer and must not be freed.
745  */
746 const char *
vips_buf_firstline(VipsBuf * buf)747 vips_buf_firstline( VipsBuf *buf )
748 {
749 	char *p;
750 
751 	if( (p = strchr( vips_buf_all( buf ), '\n' )) )
752 		*p = '\0';
753 
754 	return( vips_buf_all( buf ) );
755 }
756 
757 /**
758  * vips_buf_is_empty:
759  * @buf: the buffer
760  *
761  * Returns: %TRUE if the buffer is empty.
762  */
763 gboolean
vips_buf_is_empty(VipsBuf * buf)764 vips_buf_is_empty( VipsBuf *buf )
765 {
766 	return( buf->i == 0 );
767 }
768 
769 /**
770  * vips_buf_is_full:
771  * @buf: the buffer
772  *
773  * Returns: %TRUE if the buffer is full.
774  */
775 gboolean
vips_buf_is_full(VipsBuf * buf)776 vips_buf_is_full( VipsBuf *buf )
777 {
778 	return( buf->full );
779 }
780 
781 /**
782  * vips_buf_len:
783  * @buf: the buffer
784  *
785  * Returns: the number of characters currently in the buffer.
786  */
787 int
vips_buf_len(VipsBuf * buf)788 vips_buf_len( VipsBuf *buf )
789 {
790 	return( buf->i );
791 }
792 
793