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 < array_length; i++) {
68 * if (i > 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