1 /* abstract base class for all vips objects
2  *
3  * Edited from nip's base class, 15/10/08
4  *
5  * 29/5/18
6  * 	- added vips_argument_get_id()
7  */
8 
9 /*
10 
11     Copyright (C) 1991-2003 The National Gallery
12 
13     This library is free software; you can redistribute it and/or
14     modify it under the terms of the GNU Lesser General Public
15     License as published by the Free Software Foundation; either
16     version 2.1 of the License, or (at your option) any later version.
17 
18     This library is distributed in the hope that it will be useful,
19     but WITHOUT ANY WARRANTY; without even the implied warranty of
20     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21     Lesser General Public License for more details.
22 
23     You should have received a copy of the GNU Lesser General Public
24     License along with this library; if not, write to the Free Software
25     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26     02110-1301  USA
27 
28  */
29 
30 /*
31 
32     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
33 
34  */
35 
36 /*
37 #define DEBUG
38 #define VIPS_DEBUG
39 #define DEBUG_REF
40  */
41 
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif /*HAVE_CONFIG_H*/
45 #include <vips/intl.h>
46 
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <stdarg.h>
51 
52 #include <vips/vips.h>
53 #include <vips/internal.h>
54 #include <vips/debug.h>
55 
56 #include <gobject/gvaluecollector.h>
57 
58 #include "vipsmarshal.h"
59 
60 /**
61  * SECTION: object
62  * @short_description: the VIPS base object class
63  * @stability: Stable
64  * @see_also: <link linkend="VipsOperation">operation</link>
65  * @include: vips/vips.h
66  *
67  * The #VipsObject class and associated types and macros.
68  *
69  * #VipsObject is the base class for all objects in libvips. It has the
70  * following major features:
71  *
72  * <emphasis>Functional class creation</emphasis> Vips objects have a very
73  * regular lifecycle: initialise, build, use, destroy. They behave rather like
74  * function calls and are free of side-effects.
75  *
76  * <emphasis>Run-time introspection</emphasis> Vips objects can be fully
77  * introspected at run-time. There is no need for separate source-code
78  * analysis.
79  *
80  * <emphasis>Command-line interface</emphasis> Any vips object can be run from
81  * the command-line with the `vips` driver program.
82  *
83  * ## The #VipsObject lifecycle
84  *
85  * #VipsObject s have a strictly defined lifecycle, split broadly as construct
86  * and then use. In detail, the stages are:
87  *
88  * 1. g_object_new(). The #VipsObject is created with g_object_new(). Objects
89  * in this state are blank slates and need to have their various parameters
90  * set.
91  *
92  * 2. g_object_set(). You loop over the #VipsArgument that the object has
93  * defined with vips_argument_map(). Arguments have a set of flags attached to
94  * them for required, optional, input, output, type, and so on. You must set
95  * all required arguments.
96  *
97  * 3. vips_object_build(). Call this to construct the object and get it ready
98  * for use. Building an object happens in four stages, see below.
99  *
100  * 4. g_object_get(). The object has now been built. You can read out any
101  * computed values.
102  *
103  * 5. g_object_unref(). When you are done with an object, you can unref it.
104  * See the section on reference counting for an explanation of the convention
105  * that #VipsObject uses. When the last ref to an object is released, the
106  * object is closed. Objects close in three stages, see below.
107  *
108  * The stages inside vips_object_build() are:
109  *
110  * 1. Chain up through the object's @build class methods. At each stage,
111  * each class does any initial setup and checking, then chains up to its
112  * superclass.
113  *
114  * 2. The innermost @build method inside #VipsObject itself checks that all
115  * input arguments have been set and then returns.
116  *
117  * 3. All object @build methods now finish executing, from innermost to
118  * outermost. They know all input arguments have been checked and supplied, so
119  * now they set all output arguments.
120  *
121  * 4. vips_object_build() finishes the process by checking that all output
122  * objects have been set, and then triggering the #VipsObject::postbuild
123  * signal. #VipsObject::postbuild only runs if the object has constructed
124  * successfuly.
125  *
126  * #VipsOperation has a cache of recent operation objects, see that class for
127  * an explanation of vips_cache_operation_build().
128  *
129  * Finally the stages inside close are:
130  *
131  * 1. #VipsObject::preclose. This is emitted at the start of
132  * the #VipsObject dispose. The object is still functioning.
133  *
134  * 2. #VipsObject::close. This runs just after all #VipsArgument held by
135  * the object have been released.
136  *
137  * 3. #VipsObject::postclose. This runs right at the end. The object
138  * pointer is still valid, but nothing else is.
139  *
140  * ## #VipsArgument
141  *
142  * libvips has a simple mechanism for automating at least some aspects of
143  * %GObject properties. You add a set of macros to your _class_init() which
144  * describe the arguments, and set the get and set functions to the vips ones.
145  *
146  * See <link linkend="extending">extending</link> for a complete example.
147  *
148  * ## The #VipsObject reference counting convention
149  *
150  * #VipsObject has a set of conventions to simplify reference counting.
151  *
152  * 1. All input %GObject have a ref added to them, owned by the object. When a
153  * #VipsObject is unreffed, all of these refs to input objects are
154  * automatically dropped.
155  *
156  * 2. All output %GObject hold a ref to the object. When a %GObject which is an
157  * output of a #VipsObject is disposed, it must drop this reference.
158  * #VipsObject which are outputs of other #VipsObject will do this
159  * automatically.
160  *
161  * See #VipsOperation for an example of #VipsObject reference counting.
162  *
163  */
164 
165 /**
166  * VipsArgumentFlags:
167  * @VIPS_ARGUMENT_NONE: no flags
168  * @VIPS_ARGUMENT_REQUIRED: must be set in the constructor
169  * @VIPS_ARGUMENT_CONSTRUCT: can only be set in the constructor
170  * @VIPS_ARGUMENT_SET_ONCE: can only be set once
171  * @VIPS_ARGUMENT_SET_ALWAYS: don't do use-before-set checks
172  * @VIPS_ARGUMENT_INPUT: is an input argument (one we depend on)
173  * @VIPS_ARGUMENT_OUTPUT: is an output argument (depends on us)
174  * @VIPS_ARGUMENT_DEPRECATED: just there for back-compat, hide
175  * @VIPS_ARGUMENT_MODIFY: the input argument will be modified
176  *
177  * Flags we associate with each object argument.
178  *
179  * Have separate input & output flags. Both set is an error; neither set is OK.
180  *
181  * Input gobjects are automatically reffed, output gobjects automatically ref
182  * us. We also automatically watch for "destroy" and unlink.
183  *
184  * @VIPS_ARGUMENT_SET_ALWAYS is handy for arguments which are set from C. For
185  * example, VipsImage::width is a property that gives access to the Xsize
186  * member of struct _VipsImage. We default its 'assigned' to TRUE
187  * since the field is always set directly by C.
188  *
189  * @VIPS_ARGUMENT_DEPRECATED arguments are not shown in help text, are not
190  * looked for if required, are not checked for "have-been-set". You can
191  * deprecate a required argument, but you must obviously add a new required
192  * argument if you do.
193  *
194  * Input args with @VIPS_ARGUMENT_MODIFY will be modified by the operation.
195  * This is used for things like the in-place drawing operations.
196  */
197 
198 /* Our signals.
199  */
200 enum {
201 	SIG_POSTBUILD,
202 	SIG_PRECLOSE,
203 	SIG_CLOSE,
204 	SIG_POSTCLOSE,
205 	SIG_LAST
206 };
207 
208 /* Table of all objects, handy for debugging.
209  */
210 static GHashTable *vips__object_all = NULL;
211 static GMutex *vips__object_all_lock = NULL;
212 
213 static guint vips_object_signals[SIG_LAST] = { 0 };
214 
215 /* This has to be externally visible for compatibility with older libvipses.
216  */
217 int _vips__argument_id = 1;
218 
219 /* Keep a cache of nickname -> GType lookups.
220  */
221 static GHashTable *vips__object_nickname_table = NULL;
222 
223 G_DEFINE_ABSTRACT_TYPE( VipsObject, vips_object, G_TYPE_OBJECT );
224 
225 /**
226  * vips_argument_get_id: (skip)
227  *
228  * Allocate a new property id. See g_object_class_install_property().
229  *
230  * Returns: a new property id > 0
231  */
232 int
vips_argument_get_id(void)233 vips_argument_get_id( void )
234 {
235 	int id;
236 
237 	/* We probably don't need to lock: glib seems to single-thread class
238 	 * creation.
239 	 */
240 	id = _vips__argument_id++;
241 
242 	return( id );
243 }
244 
245 /* Don't call this directly, see vips_object_build().
246  */
247 static int
vips_object_postbuild(VipsObject * object)248 vips_object_postbuild( VipsObject *object )
249 {
250 	int result;
251 
252 #ifdef DEBUG
253 	printf( "vips_object_postbuild: " );
254 	vips_object_print_name( object );
255 	printf( "\n" );
256 #endif /*DEBUG*/
257 
258 	g_signal_emit( object, vips_object_signals[SIG_POSTBUILD], 0, &result );
259 
260 	return( result );
261 }
262 
263 void
vips_object_preclose(VipsObject * object)264 vips_object_preclose( VipsObject *object )
265 {
266 	if( !object->preclose ) {
267 		object->preclose = TRUE;
268 
269 #ifdef DEBUG
270 		printf( "vips_object_preclose: " );
271 		vips_object_print_name( object );
272 		printf( "\n" );
273 #endif /*DEBUG*/
274 
275 		g_signal_emit( object, vips_object_signals[SIG_PRECLOSE], 0 );
276 	}
277 }
278 
279 static void
vips_object_close(VipsObject * object)280 vips_object_close( VipsObject *object )
281 {
282 	if( !object->close ) {
283 		object->close = TRUE;
284 
285 #ifdef DEBUG
286 		printf( "vips_object_close: " );
287 		vips_object_print_name( object );
288 		printf( "\n" );
289 #endif /*DEBUG*/
290 
291 		g_signal_emit( object, vips_object_signals[SIG_CLOSE], 0 );
292 	}
293 }
294 
295 static void
vips_object_postclose(VipsObject * object)296 vips_object_postclose( VipsObject *object )
297 {
298 	if( !object->postclose ) {
299 		object->postclose = TRUE;
300 
301 #ifdef DEBUG
302 		printf( "vips_object_postclose: " );
303 		vips_object_print_name( object );
304 		printf( "\n" );
305 #endif /*DEBUG*/
306 
307 		g_signal_emit( object, vips_object_signals[SIG_POSTCLOSE], 0 );
308 	}
309 }
310 
311 static void *
vips_object_check_required(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)312 vips_object_check_required( VipsObject *object, GParamSpec *pspec,
313 	VipsArgumentClass *argument_class,
314 	VipsArgumentInstance *argument_instance,
315 	void *a, void *b )
316 {
317 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
318 
319 	int *result = (int *) a;
320 	VipsArgumentFlags *iomask = (VipsArgumentFlags *) b;
321 
322 	VIPS_DEBUG_MSG( "vips_object_check_required: %s\n",
323 		g_param_spec_get_name( pspec ) );
324 	VIPS_DEBUG_MSG( "\trequired: %d\n",
325 		argument_class->flags & VIPS_ARGUMENT_REQUIRED );
326 	VIPS_DEBUG_MSG( "\tconstruct: %d\n",
327 		argument_class->flags & VIPS_ARGUMENT_CONSTRUCT );
328 	VIPS_DEBUG_MSG( "\tinput: %d\n",
329 		argument_class->flags & VIPS_ARGUMENT_INPUT );
330 	VIPS_DEBUG_MSG( "\toutput: %d\n",
331 		argument_class->flags & VIPS_ARGUMENT_OUTPUT );
332 	VIPS_DEBUG_MSG( "\tassigned: %d\n",
333 		argument_instance->assigned );
334 
335 	if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
336 		(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
337 		!(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) &&
338 		(argument_class->flags & *iomask) &&
339 		!argument_instance->assigned ) {
340 		vips_error( class->nickname,
341 			_( "parameter %s not set" ),
342 			g_param_spec_get_name( pspec ) );
343 		*result = -1;
344 	}
345 
346 	return( NULL );
347 }
348 
349 int
vips_object_build(VipsObject * object)350 vips_object_build( VipsObject *object )
351 {
352 	VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
353 
354 	/* Input and output args must both be set.
355 	 */
356 	VipsArgumentFlags iomask =
357 		VIPS_ARGUMENT_INPUT | VIPS_ARGUMENT_OUTPUT;
358 
359 	int result;
360 
361 #ifdef DEBUG
362 	printf( "vips_object_build: " );
363 	vips_object_print_name( object );
364 	printf( "\n" );
365 #endif /*DEBUG*/
366 
367 	if( object_class->build( object ) )
368 		return( -1 );
369 
370 	/* Check all required arguments have been supplied, don't stop on 1st
371 	 * error.
372 	 */
373 	result = 0;
374 	(void) vips_argument_map( object,
375 		vips_object_check_required, &result, &iomask );
376 
377 	/* ... more checks go here.
378 	 */
379 	object->constructed = TRUE;
380 
381 	/* Only postbuild on success.
382 	 */
383 	if( !result )
384 		result = vips_object_postbuild( object );
385 
386 	return( result );
387 }
388 
389 /**
390  * vips_object_summary_class: (skip)
391  * @klass: class to summarise
392  * @buf: write summary here
393  *
394  * Generate a human-readable summary for a class.
395  */
396 void
vips_object_summary_class(VipsObjectClass * klass,VipsBuf * buf)397 vips_object_summary_class( VipsObjectClass *klass, VipsBuf *buf )
398 {
399 	klass->summary_class( klass, buf );
400 }
401 
402 /**
403  * vips_object_summary: (skip)
404  * @object: object to summarise
405  * @buf: write summary here
406  *
407  * Generate a human-readable summary for an object.
408  */
409 void
vips_object_summary(VipsObject * object,VipsBuf * buf)410 vips_object_summary( VipsObject *object, VipsBuf *buf )
411 {
412 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
413 
414 	class->summary( object, buf );
415 }
416 
417 /**
418  * vips_object_dump: (skip)
419  * @object: object to dump
420  * @buf: write dump here
421  *
422  * Dump everything that vips knows about an object to a string.
423  */
424 void
vips_object_dump(VipsObject * object,VipsBuf * buf)425 vips_object_dump( VipsObject *object, VipsBuf *buf )
426 {
427 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
428 
429 	class->dump( object, buf );
430 }
431 
432 void
vips_object_print_summary_class(VipsObjectClass * class)433 vips_object_print_summary_class( VipsObjectClass *class )
434 {
435 	char str[2048];
436 	VipsBuf buf = VIPS_BUF_STATIC( str );
437 
438 	vips_object_summary_class( class, &buf );
439 	printf( "%s\n", vips_buf_all( &buf ) );
440 }
441 
442 void
vips_object_print_summary(VipsObject * object)443 vips_object_print_summary( VipsObject *object )
444 {
445 	char str[2048];
446 	VipsBuf buf = VIPS_BUF_STATIC( str );
447 
448 	vips_object_summary( object, &buf );
449 	printf( "%s\n", vips_buf_all( &buf ) );
450 }
451 
452 void
vips_object_print_dump(VipsObject * object)453 vips_object_print_dump( VipsObject *object )
454 {
455 	char str[32768];
456 	VipsBuf buf = VIPS_BUF_STATIC( str );
457 
458 	vips_object_dump( object, &buf );
459 	printf( "%s\n", vips_buf_all( &buf ) );
460 }
461 
462 void
vips_object_print_name(VipsObject * object)463 vips_object_print_name( VipsObject *object )
464 {
465 	printf( "%s (%p)", G_OBJECT_TYPE_NAME( object ), object );
466 }
467 
468 gboolean
vips_object_sanity(VipsObject * object)469 vips_object_sanity( VipsObject *object )
470 {
471 	VipsObjectClass *class;
472 	char str[1000];
473 	VipsBuf buf = VIPS_BUF_STATIC( str );
474 
475 	if( !object ) {
476 		printf( "vips_object_sanity: null object\n" );
477 
478 		return( FALSE );
479 	}
480 
481 	class = VIPS_OBJECT_GET_CLASS( object );
482 	class->sanity( object, &buf );
483 	if( !vips_buf_is_empty( &buf ) ) {
484 		printf( "sanity failure: " );
485 		vips_object_print_name( object );
486 		printf( " %s\n", vips_buf_all( &buf ) );
487 
488 		return( FALSE );
489 	}
490 
491 	return( TRUE );
492 }
493 
494 /* On a rewind, we dispose the old contents of the object and
495  * reconstruct. This is used in things like im_pincheck() where a "w"
496  * image has to be rewound and become a "p" image.
497  *
498  * Override in subclasses if you want to preserve some fields, see image.c.
499  */
500 void
vips_object_rewind(VipsObject * object)501 vips_object_rewind( VipsObject *object )
502 {
503 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
504 
505 	class->rewind( object );
506 }
507 
508 /* Extra stuff we track for properties to do our argument handling.
509  */
510 
511 static void
vips_argument_instance_detach(VipsArgumentInstance * argument_instance)512 vips_argument_instance_detach( VipsArgumentInstance *argument_instance )
513 {
514 	VipsObject *object = argument_instance->object;
515 	VipsArgumentClass *argument_class = argument_instance->argument_class;
516 
517 	if( argument_instance->close_id ) {
518 		/* If close_id is set, the argument must be a gobject of some
519 		 * sort, so we can fetch it.
520 		 */
521 		GObject *member = G_STRUCT_MEMBER( GObject *, object,
522 			argument_class->offset );
523 
524 		if( g_signal_handler_is_connected( member,
525 			argument_instance->close_id ) )
526 			g_signal_handler_disconnect( member,
527 				argument_instance->close_id );
528 		argument_instance->close_id = 0;
529 	}
530 
531 	if( argument_instance->invalidate_id ) {
532 		GObject *member = G_STRUCT_MEMBER( GObject *, object,
533 			argument_class->offset );
534 
535 		if( g_signal_handler_is_connected( member,
536 			argument_instance->invalidate_id ) )
537 			g_signal_handler_disconnect( member,
538 				argument_instance->invalidate_id );
539 		argument_instance->invalidate_id = 0;
540 	}
541 }
542 
543 /* Free a VipsArgumentInstance ... VipsArgumentClass can just be g_free()d.
544  */
545 static void
vips_argument_instance_free(VipsArgumentInstance * argument_instance)546 vips_argument_instance_free( VipsArgumentInstance *argument_instance )
547 {
548 	vips_argument_instance_detach( argument_instance );
549 	g_free( argument_instance );
550 }
551 
552 VipsArgument *
vips__argument_table_lookup(VipsArgumentTable * table,GParamSpec * pspec)553 vips__argument_table_lookup( VipsArgumentTable *table, GParamSpec *pspec )
554 {
555 	VipsArgument *argument;
556 
557 	g_mutex_lock( vips__global_lock );
558 	argument = (VipsArgument *) g_hash_table_lookup( table, pspec );
559 	g_mutex_unlock( vips__global_lock );
560 
561 	return( argument );
562 }
563 
564 static void
vips_argument_table_replace(VipsArgumentTable * table,VipsArgument * argument)565 vips_argument_table_replace( VipsArgumentTable *table, VipsArgument *argument )
566 {
567 	g_hash_table_replace( table, argument->pspec, argument );
568 }
569 
570 static void
vips_argument_table_destroy(VipsArgumentTable * table)571 vips_argument_table_destroy( VipsArgumentTable *table )
572 {
573 	g_hash_table_destroy( table );
574 }
575 
576 /**
577  * vips_argument_map: (skip)
578  * @object: object whose args should be enumerated
579  * @fn: call this function for every argument
580  * @a: client data
581  * @b: client data
582  *
583  * Loop over the vips_arguments to an object. Stop when @fn returns non-%NULL
584  * and return that value.
585  *
586  * Returns: %NULL if @fn returns %NULL for all arguments, otherwise the first
587  * non-%NULL value from @fn.
588  */
589 void *
vips_argument_map(VipsObject * object,VipsArgumentMapFn fn,void * a,void * b)590 vips_argument_map( VipsObject *object,
591 	VipsArgumentMapFn fn, void *a, void *b )
592 {
593 	/* Make sure we can't go during the loop. This can happen if eg. we
594 	 * flush an arg that refs us.
595 	 */
596 	g_object_ref( object );
597 
598 	VIPS_ARGUMENT_FOR_ALL( object,
599 		pspec, argument_class, argument_instance ) {
600 		void *result;
601 
602 		/* argument_instance should not be NULL.
603 		 */
604 		g_assert( argument_instance );
605 
606 		if( (result = fn( object, pspec,
607 			argument_class, argument_instance, a, b )) ) {
608 			g_object_unref( object );
609 			return( result );
610 		}
611 	} VIPS_ARGUMENT_FOR_ALL_END
612 
613 	g_object_unref( object );
614 
615 	return( NULL );
616 }
617 
618 /**
619  * vips_argument_class_map: (skip)
620  *
621  * And loop over a class. Same as ^^, but with no VipsArgumentInstance.
622  */
623 void *
vips_argument_class_map(VipsObjectClass * object_class,VipsArgumentClassMapFn fn,void * a,void * b)624 vips_argument_class_map( VipsObjectClass *object_class,
625 	VipsArgumentClassMapFn fn, void *a, void *b )
626 {
627 	GSList *p;
628 
629 	for( p = object_class->argument_table_traverse; p; p = p->next ) {
630 		VipsArgumentClass *arg_class =
631 			(VipsArgumentClass *) p->data;
632 		VipsArgument *argument = (VipsArgument *) arg_class;
633 		GParamSpec *pspec = argument->pspec;
634 
635 		void *result;
636 
637 		if( (result =
638 			fn( object_class, pspec, arg_class, a, b )) )
639 			return( result );
640 	}
641 
642 	return( NULL );
643 }
644 
645 /* Does an vipsargument need an argument to write to? For example, an image
646  * output needs a filename, a double output just prints.
647  */
648 gboolean
vips_argument_class_needsstring(VipsArgumentClass * argument_class)649 vips_argument_class_needsstring( VipsArgumentClass *argument_class )
650 {
651 	GParamSpec *pspec = ((VipsArgument *) argument_class)->pspec;
652 
653 	GType otype;
654 	VipsObjectClass *oclass;
655 
656 	if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) )
657 		/* Bools, input or output, don't need args.
658 		 */
659 		return( FALSE );
660 
661 	if( argument_class->flags & VIPS_ARGUMENT_INPUT )
662 		/* All other inputs need something.
663 		 */
664 		return( TRUE );
665 
666 	/* Just output objects.
667 	 */
668 
669 	if( (otype = G_PARAM_SPEC_VALUE_TYPE( pspec )) &&
670 		g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
671 		(oclass = g_type_class_ref( otype )) )
672 		/* For now, only vipsobject subclasses can ask for args.
673 		 */
674 		return( oclass->output_needs_arg );
675 	else
676 		return( FALSE );
677 }
678 
679 /* Create a VipsArgumentInstance for each installed argument property. Ideally
680  * we'd do this during _init() but g_object_class_find_property() does not seem
681  * to work then :-( so we have to delay it until first access. See
682  * vips__argument_get_instance().
683  */
684 static void
vips_argument_init(VipsObject * object)685 vips_argument_init( VipsObject *object )
686 {
687 	if( !object->argument_table ) {
688 #ifdef DEBUG
689 		printf( "vips_argument_init: " );
690 		vips_object_print_name( object );
691 		printf( "\n" );
692 #endif /*DEBUG*/
693 
694 		object->argument_table = g_hash_table_new_full( g_direct_hash,
695 			g_direct_equal, NULL,
696 			(GDestroyNotify) vips_argument_instance_free );
697 
698 		/* Make a VipsArgumentInstance for each installed argument
699 		 * property. We can't use vips_argument_map() since that does
700 		 * some sanity checks that won't pass until all arg instance
701 		 * are built.
702 		 */
703 		VIPS_ARGUMENT_FOR_ALL( object,
704 			pspec, argument_class, argument_instance ) {
705 #ifdef DEBUG
706 			printf( "vips_argument_init: "
707 				"adding instance argument for %s\n",
708 				g_param_spec_get_name( pspec ) );
709 #endif /*DEBUG*/
710 
711 			/* argument_instance should be NULL since we've not
712 			 * set it yet.
713 			 */
714 			g_assert( argument_instance == NULL );
715 
716 			argument_instance = g_new( VipsArgumentInstance, 1 );
717 
718 			((VipsArgument *) argument_instance)->pspec = pspec;
719 			argument_instance->argument_class = argument_class;
720 			argument_instance->object = object;
721 			/* SET_ALWAYS args default to assigned.
722 			 */
723 			argument_instance->assigned =
724 				argument_class->flags &
725 					VIPS_ARGUMENT_SET_ALWAYS;
726 			argument_instance->close_id = 0;
727 			argument_instance->invalidate_id = 0;
728 
729 			vips_argument_table_replace( object->argument_table,
730 				(VipsArgument *) argument_instance );
731 		} VIPS_ARGUMENT_FOR_ALL_END
732 	}
733 }
734 
735 /**
736  * vips__argument_get_instance: (skip)
737  *
738  * Convenience ... given the VipsArgumentClass, get the VipsArgumentInstance.
739  */
740 VipsArgumentInstance *
vips__argument_get_instance(VipsArgumentClass * argument_class,VipsObject * object)741 vips__argument_get_instance( VipsArgumentClass *argument_class,
742 	VipsObject *object )
743 {
744 	/* Make sure the instance args are built.
745 	 */
746 	vips_argument_init( object );
747 
748 	return( (VipsArgumentInstance *)
749 		vips__argument_table_lookup( object->argument_table,
750 			((VipsArgument *) argument_class)->pspec ) );
751 }
752 
753 /**
754  * vips_object_get_argument: (skip)
755  * @object: the object to fetch the args from
756  * @name: arg to fetch
757  * @pspec: (transfer none): the pspec for this arg
758  * @argument_class: (transfer none): the argument_class for this arg
759  * @argument_instance: (transfer none): the argument_instance for this arg
760  *
761  * Look up the three things you need to work with a vips argument.
762  *
763  * Returns: 0 on success, or -1 on error.
764  */
765 int
vips_object_get_argument(VipsObject * object,const char * name,GParamSpec ** pspec,VipsArgumentClass ** argument_class,VipsArgumentInstance ** argument_instance)766 vips_object_get_argument( VipsObject *object, const char *name,
767 	GParamSpec **pspec,
768 	VipsArgumentClass **argument_class,
769 	VipsArgumentInstance **argument_instance )
770 {
771 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
772 
773 	if( !(*pspec = g_object_class_find_property(
774 		G_OBJECT_CLASS( class ), name )) ) {
775 		vips_error( class->nickname,
776 			_( "no property named `%s'" ), name );
777 		return( -1 );
778 	}
779 
780 	if( !(*argument_class = (VipsArgumentClass *)
781 		vips__argument_table_lookup( class->argument_table,
782 		*pspec )) ) {
783 		vips_error( class->nickname,
784 			_( "no vips argument named `%s'" ), name );
785 		return( -1 );
786 	}
787 	if( !(*argument_instance = vips__argument_get_instance(
788 		*argument_class, object )) ) {
789 		vips_error( class->nickname,
790 			_( "argument `%s' has no instance" ), name );
791 		return( -1 );
792 	}
793 
794 	return( 0 );
795 }
796 
797 /**
798  * vips_object_argument_isset:
799  * @object: the object to fetch the args from
800  * @name: arg to fetch
801  *
802  * Convenience: has an argument been assigned. Useful for bindings.
803  *
804  * Returns: %TRUE if the argument has been assigned.
805  */
806 gboolean
vips_object_argument_isset(VipsObject * object,const char * name)807 vips_object_argument_isset( VipsObject *object, const char *name )
808 {
809 	GParamSpec *pspec;
810 	VipsArgumentClass *argument_class;
811 	VipsArgumentInstance *argument_instance;
812 
813 	if( vips_object_get_argument( object, name,
814 		&pspec, &argument_class, &argument_instance ) )
815 		return( FALSE );
816 
817 	return( argument_instance->assigned );
818 }
819 
820 /**
821  * vips_object_get_argument_flags:
822  * @object: the object to fetch the args from
823  * @name: arg to fetch
824  *
825  * Convenience: get the flags for an argument. Useful for bindings.
826  *
827  * Returns: The #VipsArgumentFlags for this argument.
828  */
829 VipsArgumentFlags
vips_object_get_argument_flags(VipsObject * object,const char * name)830 vips_object_get_argument_flags( VipsObject *object, const char *name )
831 {
832 	GParamSpec *pspec;
833 	VipsArgumentClass *argument_class;
834 	VipsArgumentInstance *argument_instance;
835 
836 	if( vips_object_get_argument( object, name,
837 		&pspec, &argument_class, &argument_instance ) )
838 		return( 0 );
839 
840 	return( argument_class->flags );
841 }
842 
843 /**
844  * vips_object_get_argument_priority:
845  * @object: the object to fetch the args from
846  * @name: arg to fetch
847  *
848  * Convenience: get the priority for an argument. Useful for bindings.
849  *
850  * Returns: The priority of this argument.
851  */
852 int
vips_object_get_argument_priority(VipsObject * object,const char * name)853 vips_object_get_argument_priority( VipsObject *object, const char *name )
854 {
855 	GParamSpec *pspec;
856 	VipsArgumentClass *argument_class;
857 	VipsArgumentInstance *argument_instance;
858 
859 	if( vips_object_get_argument( object, name,
860 		&pspec, &argument_class, &argument_instance ) )
861 		return( 0 );
862 
863 	return( argument_class->priority );
864 }
865 
866 static void
vips_object_clear_member(VipsArgumentInstance * argument_instance)867 vips_object_clear_member( VipsArgumentInstance *argument_instance )
868 {
869 	VipsObject *object = argument_instance->object;
870 	VipsArgumentClass *argument_class = argument_instance->argument_class;
871 	GObject **member = &G_STRUCT_MEMBER( GObject *, object,
872 		argument_class->offset );
873 
874 	vips_argument_instance_detach( argument_instance );
875 
876 	if( *member ) {
877 		if( argument_class->flags & VIPS_ARGUMENT_INPUT ) {
878 #ifdef DEBUG_REF
879 			printf( "vips_object_clear_member: vips object: " );
880 			vips_object_print_name( object );
881 			printf( "  no longer refers to gobject %s (%p)\n",
882 				G_OBJECT_TYPE_NAME( *member ), *member );
883 			printf( "  count down to %d\n",
884 				G_OBJECT( *member )->ref_count - 1 );
885 #endif /*DEBUG_REF*/
886 
887 			/* We reffed the object.
888 			 */
889 			g_object_unref( *member );
890 		}
891 		else if( argument_class->flags & VIPS_ARGUMENT_OUTPUT ) {
892 #ifdef DEBUG_REF
893 			printf( "vips_object_clear_member: gobject %s (%p)\n",
894 				G_OBJECT_TYPE_NAME( *member ), *member );
895 			printf( "  no longer refers to vips object: " );
896 			vips_object_print_name( object );
897 			printf( "  count down to %d\n",
898 				G_OBJECT( object )->ref_count - 1 );
899 #endif /*DEBUG_REF*/
900 
901 			g_object_unref( object );
902 		}
903 
904 		*member = NULL;
905 	}
906 }
907 
908 /* Free any args which are holding resources.
909  */
910 static void *
vips_object_dispose_argument(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)911 vips_object_dispose_argument( VipsObject *object, GParamSpec *pspec,
912 	VipsArgumentClass *argument_class,
913 	VipsArgumentInstance *argument_instance,
914 	void *a, void *b )
915 {
916 	g_assert( ((VipsArgument *) argument_class)->pspec == pspec );
917 	g_assert( ((VipsArgument *) argument_instance)->pspec == pspec );
918 
919 	if( G_IS_PARAM_SPEC_OBJECT( pspec ) ||
920 		G_IS_PARAM_SPEC_BOXED( pspec ) ) {
921 #ifdef DEBUG
922 		printf( "vips_object_dispose_argument: " );
923 		vips_object_print_name( object );
924 		printf( ".%s\n", g_param_spec_get_name( pspec ) );
925 #endif /*DEBUG*/
926 
927 		g_object_set( object,
928 			g_param_spec_get_name( pspec ), NULL,
929 			NULL );
930 	}
931 
932 	return( NULL );
933 }
934 
935 /* Free all args on this object which may be holding resources.
936  *
937  * Note that this is not the same as vips_object_unref_outputs(). That
938  * looks for output objects which may have been created during _build() which
939  * hold refs to this object and unrefs them.
940  *
941  * This function looks for objects which this object holds refs to and which
942  * may be holding sub-resources and zaps them.
943  */
944 static void
vips_argument_dispose_all(VipsObject * object)945 vips_argument_dispose_all( VipsObject *object )
946 {
947 #ifdef DEBUG
948 	printf( "vips_argument_dispose_all: " );
949 	vips_object_print_name( object );
950 	printf( "\n" );
951 #endif /*DEBUG*/
952 
953 	vips_argument_map( object, vips_object_dispose_argument, NULL, NULL );
954 }
955 
956 /* Free any args which are holding memory.
957  */
958 static void *
vips_object_free_argument(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)959 vips_object_free_argument( VipsObject *object, GParamSpec *pspec,
960 	VipsArgumentClass *argument_class,
961 	VipsArgumentInstance *argument_instance,
962 	void *a, void *b )
963 {
964 	g_assert( ((VipsArgument *) argument_class)->pspec == pspec );
965 	g_assert( ((VipsArgument *) argument_instance)->pspec == pspec );
966 
967 	if( G_IS_PARAM_SPEC_STRING( pspec ) ) {
968 #ifdef DEBUG
969 		printf( "vips_object_free_argument: " );
970 		vips_object_print_name( object );
971 		printf( ".%s\n", g_param_spec_get_name( pspec ) );
972 #endif /*DEBUG*/
973 
974 		g_object_set( object,
975 			g_param_spec_get_name( pspec ), NULL,
976 			NULL );
977 	}
978 
979 	return( NULL );
980 }
981 
982 /* Free args which hold memory. Things like strings need to be freed right at
983  * the end in case anyone is still using them.
984  */
985 static void
vips_argument_free_all(VipsObject * object)986 vips_argument_free_all( VipsObject *object )
987 {
988 #ifdef DEBUG
989 	printf( "vips_argument_free_all: " );
990 	vips_object_print_name( object );
991 	printf( "\n" );
992 #endif /*DEBUG*/
993 
994 	vips_argument_map( object, vips_object_free_argument, NULL, NULL );
995 }
996 
997 static void
vips_object_dispose(GObject * gobject)998 vips_object_dispose( GObject *gobject )
999 {
1000 	VipsObject *object = VIPS_OBJECT( gobject );
1001 
1002 #ifdef DEBUG
1003 	printf( "vips_object_dispose: " );
1004 	vips_object_print_name( object );
1005 	printf( "\n" );
1006 #endif /*DEBUG*/
1007 
1008 	/* Our subclasses should have already called this. Run it again, just
1009 	 * in case.
1010 	 */
1011 #ifdef DEBUG
1012 	if( !object->preclose )
1013 		printf( "vips_object_dispose: pre-close missing!\n" );
1014 #endif /*DEBUG*/
1015 	vips_object_preclose( object );
1016 
1017 	/* Clear all our arguments: they may be holding resources we should
1018 	 * drop.
1019 	 */
1020 	vips_argument_dispose_all( object );
1021 
1022 	vips_object_close( object );
1023 
1024 	vips_object_postclose( object );
1025 
1026 	vips_argument_free_all( object );
1027 
1028 	VIPS_FREEF( vips_argument_table_destroy, object->argument_table );
1029 
1030 	G_OBJECT_CLASS( vips_object_parent_class )->dispose( gobject );
1031 }
1032 
1033 static void
vips_object_finalize(GObject * gobject)1034 vips_object_finalize( GObject *gobject )
1035 {
1036 	VipsObject *object = VIPS_OBJECT( gobject );
1037 
1038 #ifdef DEBUG
1039 	printf( "vips_object_finalize: " );
1040 	vips_object_print_name( object );
1041 	printf( "\n" );
1042 #endif /*DEBUG*/
1043 
1044 	/* I'd like to have post-close in here, but you can't emit signals
1045 	 * from finalize, sadly.
1046 	 */
1047 
1048 	g_mutex_lock( vips__object_all_lock );
1049 	g_hash_table_remove( vips__object_all, object );
1050 	g_mutex_unlock( vips__object_all_lock );
1051 
1052 	G_OBJECT_CLASS( vips_object_parent_class )->finalize( gobject );
1053 }
1054 
1055 static void
vips_object_arg_invalidate(GObject * argument,VipsArgumentInstance * argument_instance)1056 vips_object_arg_invalidate( GObject *argument,
1057 	VipsArgumentInstance *argument_instance )
1058 {
1059 	/* Image @argument has signalled "invalidate" ... resignal on our
1060 	 * operation.
1061 	 */
1062 	if( VIPS_IS_OPERATION( argument_instance->object ) )
1063 		vips_operation_invalidate(
1064 			VIPS_OPERATION( argument_instance->object ) );
1065 }
1066 
1067 static void
vips_object_arg_close(GObject * argument,VipsArgumentInstance * argument_instance)1068 vips_object_arg_close( GObject *argument,
1069 	VipsArgumentInstance *argument_instance )
1070 {
1071 	VipsObject *object = argument_instance->object;
1072 	GParamSpec *pspec = ((VipsArgument *) argument_instance)->pspec;
1073 
1074 	/* Argument had reffed us ... now it's being closed, so we NULL out
1075 	 * the pointer to unref.
1076 	 */
1077 	g_object_set( object,
1078 		g_param_spec_get_name( pspec ), NULL,
1079 		NULL );
1080 }
1081 
1082 /* Set a member to an object. Handle the ref counts and signal
1083  * connect/disconnect.
1084  */
1085 void
vips__object_set_member(VipsObject * object,GParamSpec * pspec,GObject ** member,GObject * argument)1086 vips__object_set_member( VipsObject *object, GParamSpec *pspec,
1087 	GObject **member, GObject *argument )
1088 {
1089 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
1090 	VipsArgumentClass *argument_class = (VipsArgumentClass *)
1091 		vips__argument_table_lookup( class->argument_table, pspec );
1092 	VipsArgumentInstance *argument_instance =
1093 		vips__argument_get_instance( argument_class, object );
1094 	GType otype = G_PARAM_SPEC_VALUE_TYPE( pspec );
1095 
1096 	g_assert( argument_instance );
1097 
1098 	vips_object_clear_member( argument_instance );
1099 
1100 	g_assert( !*member );
1101 	*member = argument;
1102 
1103 	if( *member ) {
1104 		if( argument_class->flags & VIPS_ARGUMENT_INPUT ) {
1105 #ifdef DEBUG_REF
1106 			printf( "vips__object_set_member: vips object: " );
1107 			vips_object_print_name( object );
1108 			printf( "  refers to gobject %s (%p)\n",
1109 				G_OBJECT_TYPE_NAME( *member ), *member );
1110 			printf( "  count up to %d\n",
1111 				G_OBJECT( *member )->ref_count );
1112 #endif /*DEBUG_REF*/
1113 
1114 			/* Ref the argument.
1115 			 */
1116 			g_object_ref( *member );
1117 		}
1118 		else if( argument_class->flags & VIPS_ARGUMENT_OUTPUT ) {
1119 #ifdef DEBUG_REF
1120 			printf( "vips__object_set_member: gobject %s (%p)\n",
1121 				G_OBJECT_TYPE_NAME( *member ), *member );
1122 			printf( "  refers to vips object: " );
1123 			vips_object_print_name( object );
1124 			printf( "  count up to %d\n",
1125 				G_OBJECT (object)->ref_count );
1126 #endif /*DEBUG_REF*/
1127 
1128 			/* The argument reffs us.
1129 			 */
1130 			g_object_ref( object );
1131 		}
1132 	}
1133 
1134 	if( *member &&
1135 		g_type_is_a( otype, VIPS_TYPE_IMAGE ) ) {
1136 		if( argument_class->flags & VIPS_ARGUMENT_INPUT ) {
1137 			g_assert( !argument_instance->invalidate_id );
1138 
1139 			argument_instance->invalidate_id =
1140 				g_signal_connect( *member, "invalidate",
1141 					G_CALLBACK(
1142 						vips_object_arg_invalidate ),
1143 					argument_instance );
1144 		}
1145 		else if( argument_class->flags & VIPS_ARGUMENT_OUTPUT ) {
1146 			g_assert( !argument_instance->close_id );
1147 
1148 			argument_instance->close_id =
1149 				g_signal_connect( *member, "close",
1150 					G_CALLBACK( vips_object_arg_close ),
1151 					argument_instance );
1152 		}
1153 	}
1154 }
1155 
1156 /* Is a value NULL? We allow multiple sets of NULL so props can be cleared.
1157  * The pspec gives the value type, for consistency with the way value types
1158  * are detected in set and get.
1159  */
1160 gboolean
vips_value_is_null(GParamSpec * pspec,const GValue * value)1161 vips_value_is_null( GParamSpec *pspec, const GValue *value )
1162 {
1163 	if( G_IS_PARAM_SPEC_STRING( pspec ) &&
1164 		!g_value_get_string( value ) )
1165 		return( TRUE );
1166 	if( G_IS_PARAM_SPEC_OBJECT( pspec ) &&
1167 		!g_value_get_object( value ) )
1168 		return( TRUE );
1169 	if( G_IS_PARAM_SPEC_POINTER( pspec ) &&
1170 		!g_value_get_pointer( value ) )
1171 		return( TRUE );
1172 	if( G_IS_PARAM_SPEC_BOXED( pspec ) &&
1173 		!g_value_get_boxed( value ) )
1174 		return( TRUE );
1175 
1176 	return( FALSE );
1177 }
1178 
1179 /* Also used by subclasses, so not static.
1180  */
1181 void
vips_object_set_property(GObject * gobject,guint property_id,const GValue * value,GParamSpec * pspec)1182 vips_object_set_property( GObject *gobject,
1183 	guint property_id, const GValue *value, GParamSpec *pspec )
1184 {
1185 	VipsObject *object = VIPS_OBJECT( gobject );
1186 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( gobject );
1187 	VipsArgumentClass *argument_class = (VipsArgumentClass *)
1188 		vips__argument_table_lookup( class->argument_table, pspec );
1189 	VipsArgumentInstance *argument_instance =
1190 		vips__argument_get_instance( argument_class, object );
1191 
1192 	g_assert( argument_instance );
1193 
1194 #ifdef DEBUG
1195 	printf( "vips_object_set_property: " );
1196 	vips_object_print_name( object );
1197 	printf( ".%s\n", g_param_spec_get_name( pspec ) );
1198 
1199 	/* This can crash horribly with some values, have it as a separate
1200 	 * chunk so we can easily comment it out.
1201 	 */
1202 {
1203 	char *str_value;
1204 
1205 	str_value = g_strdup_value_contents( value );
1206 	printf( "\t%s\n", str_value );
1207 	g_free( str_value );
1208 }
1209 #endif /*DEBUG*/
1210 
1211 	g_assert( ((VipsArgument *) argument_class)->pspec == pspec );
1212 	g_assert( ((VipsArgument *) argument_instance)->pspec == pspec );
1213 
1214 	/* If this is a construct-only argument, we can only set before we've
1215 	 * built.
1216 	 */
1217 	if( argument_class->flags & VIPS_ARGUMENT_CONSTRUCT &&
1218 		object->constructed &&
1219 		!vips_value_is_null( pspec, value ) ) {
1220 		g_warning( "%s: %s can't assign '%s' after construct",
1221 			G_STRLOC,
1222 			G_OBJECT_TYPE_NAME( gobject ),
1223 			g_param_spec_get_name( pspec ) );
1224 		return;
1225 	}
1226 
1227 	/* If this is a set-once argument, check we've not set it before.
1228 	 */
1229 	if( argument_class->flags & VIPS_ARGUMENT_SET_ONCE &&
1230 		argument_instance->assigned &&
1231 		!vips_value_is_null( pspec, value ) ) {
1232 		g_warning( "%s: %s can only assign '%s' once",
1233 			G_STRLOC,
1234 			G_OBJECT_TYPE_NAME( gobject ),
1235 			g_param_spec_get_name( pspec ) );
1236 		return;
1237 	}
1238 
1239 	/* We can't use a switch since some param specs don't have fundamental
1240 	 * types and are hence not compile-time constants, argh.
1241 	 */
1242 	if( G_IS_PARAM_SPEC_STRING( pspec ) ) {
1243 		char **member = &G_STRUCT_MEMBER( char *, object,
1244 			argument_class->offset );
1245 
1246 		if( *member )
1247 			g_free( *member );
1248 		*member = g_value_dup_string( value );
1249 	}
1250 	else if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
1251 		GObject **member = &G_STRUCT_MEMBER( GObject *, object,
1252 			argument_class->offset );
1253 
1254 		vips__object_set_member( object, pspec, member,
1255 			g_value_get_object( value ) );
1256 	}
1257 	else if( G_IS_PARAM_SPEC_INT( pspec ) ) {
1258 		int *member = &G_STRUCT_MEMBER( int, object,
1259 			argument_class->offset );
1260 
1261 		*member = g_value_get_int( value );
1262 	}
1263 	else if( G_IS_PARAM_SPEC_UINT64( pspec ) ) {
1264 		guint64 *member = &G_STRUCT_MEMBER( guint64, object,
1265 			argument_class->offset );
1266 
1267 		*member = g_value_get_uint64( value );
1268 	}
1269 	else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
1270 		gboolean *member = &G_STRUCT_MEMBER( gboolean, object,
1271 			argument_class->offset );
1272 
1273 		*member = g_value_get_boolean( value );
1274 	}
1275 	else if( G_IS_PARAM_SPEC_ENUM( pspec ) ) {
1276 		int *member = &G_STRUCT_MEMBER( int, object,
1277 			argument_class->offset );
1278 
1279 		*member = g_value_get_enum( value );
1280 	}
1281 	else if( G_IS_PARAM_SPEC_FLAGS( pspec ) ) {
1282 		int *member = &G_STRUCT_MEMBER( int, object,
1283 			argument_class->offset );
1284 
1285 		*member = g_value_get_flags( value );
1286 	}
1287 	else if( G_IS_PARAM_SPEC_POINTER( pspec ) ) {
1288 		gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
1289 			argument_class->offset );
1290 
1291 		*member = g_value_get_pointer( value );
1292 	}
1293 	else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) {
1294 		double *member = &G_STRUCT_MEMBER( double, object,
1295 			argument_class->offset );
1296 
1297 		*member = g_value_get_double( value );
1298 	}
1299 	else if( G_IS_PARAM_SPEC_BOXED( pspec ) ) {
1300 		gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
1301 			argument_class->offset );
1302 
1303 		if( *member ) {
1304 			g_boxed_free( G_PARAM_SPEC_VALUE_TYPE( pspec ),
1305 				*member );
1306 			*member = NULL;
1307 		}
1308 
1309 		/* Copy the boxed into our pointer (will use eg.
1310 		 * vips__object_vector_dup()).
1311 		 */
1312 		*member = g_value_dup_boxed( value );
1313 	}
1314 	else {
1315 		g_warning( "%s: %s.%s unimplemented property type %s",
1316 			G_STRLOC,
1317 			G_OBJECT_TYPE_NAME( gobject ),
1318 			g_param_spec_get_name( pspec ),
1319 			g_type_name( G_PARAM_SPEC_VALUE_TYPE( pspec ) ) );
1320 	}
1321 
1322 	/* Note that it's now been set.
1323 	 */
1324 	argument_instance->assigned = TRUE;
1325 }
1326 
1327 /* Also used by subclasses, so not static.
1328  */
1329 void
vips_object_get_property(GObject * gobject,guint property_id,GValue * value,GParamSpec * pspec)1330 vips_object_get_property( GObject *gobject,
1331 	guint property_id, GValue *value, GParamSpec *pspec )
1332 {
1333 	VipsObject *object = VIPS_OBJECT( gobject );
1334 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( gobject );
1335 	VipsArgumentClass *argument_class = (VipsArgumentClass *)
1336 		vips__argument_table_lookup( class->argument_table, pspec );
1337 	VipsArgumentInstance *argument_instance =
1338 		vips__argument_get_instance( argument_class, object );
1339 
1340 	g_assert( ((VipsArgument *) argument_class)->pspec == pspec );
1341 
1342 	if( !argument_instance->assigned ) {
1343 		/* Set the value to the default. Things like Ruby
1344 		 * gobject-introspection will walk objects during GC, and we
1345 		 * can find ourselves fetching object values between init and
1346 		 * build.
1347 		 */
1348 		g_param_value_set_default( pspec, value );
1349 		return;
1350 	}
1351 
1352 	if( G_IS_PARAM_SPEC_STRING( pspec ) ) {
1353 		char *member = G_STRUCT_MEMBER( char *, object,
1354 			argument_class->offset );
1355 
1356 		g_value_set_string( value, member );
1357 	}
1358 	else if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
1359 		GObject **member = &G_STRUCT_MEMBER( GObject *, object,
1360 			argument_class->offset );
1361 
1362 		g_value_set_object( value, *member );
1363 	}
1364 	else if( G_IS_PARAM_SPEC_INT( pspec ) ) {
1365 		int *member = &G_STRUCT_MEMBER( int, object,
1366 			argument_class->offset );
1367 
1368 		g_value_set_int( value, *member );
1369 	}
1370 	else if( G_IS_PARAM_SPEC_UINT64( pspec ) ) {
1371 		guint64 *member = &G_STRUCT_MEMBER( guint64, object,
1372 			argument_class->offset );
1373 
1374 		g_value_set_uint64( value, *member );
1375 	}
1376 	else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
1377 		gboolean *member = &G_STRUCT_MEMBER( gboolean, object,
1378 			argument_class->offset );
1379 
1380 		g_value_set_boolean( value, *member );
1381 	}
1382 	else if( G_IS_PARAM_SPEC_ENUM( pspec ) ) {
1383 		int *member = &G_STRUCT_MEMBER( int, object,
1384 			argument_class->offset );
1385 
1386 		g_value_set_enum( value, *member );
1387 	}
1388 	else if( G_IS_PARAM_SPEC_FLAGS( pspec ) ) {
1389 		int *member = &G_STRUCT_MEMBER( int, object,
1390 			argument_class->offset );
1391 
1392 		g_value_set_flags( value, *member );
1393 	}
1394 	else if( G_IS_PARAM_SPEC_POINTER( pspec ) ) {
1395 		gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
1396 			argument_class->offset );
1397 
1398 		g_value_set_pointer( value, *member );
1399 	}
1400 	else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) {
1401 		double *member = &G_STRUCT_MEMBER( double, object,
1402 			argument_class->offset );
1403 
1404 		g_value_set_double( value, *member );
1405 	}
1406 	else if( G_IS_PARAM_SPEC_BOXED( pspec ) ) {
1407 		gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
1408 			argument_class->offset );
1409 
1410 		/* Copy the boxed into our pointer (will use eg.
1411 		 * vips__object_vector_dup ()).
1412 		 */
1413 		g_value_set_boxed( value, *member );
1414 	}
1415 	else {
1416 		g_warning( "%s: %s.%s unimplemented property type %s",
1417 			G_STRLOC,
1418 			G_OBJECT_TYPE_NAME( gobject ),
1419 			g_param_spec_get_name( pspec ),
1420 			g_type_name( G_PARAM_SPEC_VALUE_TYPE( pspec ) ) );
1421 	}
1422 }
1423 
1424 static int
vips_object_real_build(VipsObject * object)1425 vips_object_real_build( VipsObject *object )
1426 {
1427 	VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
1428 
1429 	/* Only test input args, output ones can be set by our subclasses as
1430 	 * they build. See vips_object_build() above.
1431 	 */
1432 	VipsArgumentFlags iomask = VIPS_ARGUMENT_INPUT;
1433 
1434 	int result;
1435 
1436 #ifdef DEBUG
1437 	printf( "vips_object_real_build: " );
1438 	vips_object_print_name( object );
1439 	printf( "\n" );
1440 #endif /*DEBUG*/
1441 
1442 	g_assert( !object->constructed );
1443 
1444 	/* It'd be nice if this just copied a pointer rather than did a
1445 	 * strdup(). Set these here rather than in object_init, so that the
1446 	 * class gets a chance to set them.
1447 	 */
1448 	g_object_set( object,
1449 		"nickname", object_class->nickname,
1450 		"description", object_class->description, NULL );
1451 
1452 	/* Check all required input arguments have been supplied, don't stop
1453 	 * on 1st error.
1454 	 */
1455 	result = 0;
1456 	(void) vips_argument_map( object,
1457 		vips_object_check_required, &result, &iomask );
1458 
1459 	return( result );
1460 }
1461 
1462 static int
vips_object_real_postbuild(VipsObject * object,void * data)1463 vips_object_real_postbuild( VipsObject *object, void *data )
1464 {
1465 #ifdef DEBUG
1466 	printf( "vips_object_real_postbuild: " );
1467 	vips_object_print_name( object );
1468 	printf( "\n" );
1469 #endif /*DEBUG*/
1470 
1471 	g_assert( object->constructed );
1472 
1473 	return( 0 );
1474 }
1475 
1476 static void
vips_object_real_summary_class(VipsObjectClass * class,VipsBuf * buf)1477 vips_object_real_summary_class( VipsObjectClass *class, VipsBuf *buf )
1478 {
1479 	vips_buf_appendf( buf, "%s", G_OBJECT_CLASS_NAME( class ) );
1480 	if( class->nickname )
1481 		vips_buf_appendf( buf, " (%s)", class->nickname );
1482 	if( class->description )
1483 		vips_buf_appendf( buf, ", %s", class->description );
1484 }
1485 
1486 static void
vips_object_real_summary(VipsObject * object,VipsBuf * buf)1487 vips_object_real_summary( VipsObject *object, VipsBuf *buf )
1488 {
1489 }
1490 
1491 static void
vips_object_real_dump(VipsObject * object,VipsBuf * buf)1492 vips_object_real_dump( VipsObject *object, VipsBuf *buf )
1493 {
1494 	vips_buf_appendf( buf, " %s (%p) count=%d",
1495 		G_OBJECT_TYPE_NAME( object ),
1496 		object,
1497 		G_OBJECT( object )->ref_count );
1498 
1499 	if( object->local_memory )
1500 		vips_buf_appendf( buf, " %zd bytes", object->local_memory );
1501 }
1502 
1503 static void
vips_object_real_sanity(VipsObject * object,VipsBuf * buf)1504 vips_object_real_sanity( VipsObject *object, VipsBuf *buf )
1505 {
1506 }
1507 
1508 static void
vips_object_real_rewind(VipsObject * object)1509 vips_object_real_rewind( VipsObject *object )
1510 {
1511 #ifdef DEBUG
1512 	printf( "vips_object_real_rewind\n" );
1513 	vips_object_print_name( object );
1514 	printf( "\n" );
1515 #endif /*DEBUG*/
1516 
1517 	g_object_run_dispose( G_OBJECT( object ) );
1518 
1519 	object->constructed = FALSE;
1520 	object->preclose = FALSE;
1521 	object->close = FALSE;
1522 	object->postclose = FALSE;
1523 }
1524 
1525 static VipsObject *
vips_object_real_new_from_string(const char * string)1526 vips_object_real_new_from_string( const char *string )
1527 {
1528 	GType type;
1529 
1530 	vips_check_init();
1531 
1532 	/* The main arg selects the subclass.
1533 	 */
1534 	if( !(type = vips_type_find( NULL, string )) ) {
1535 		vips_error( "VipsObject",
1536 			_( "class \"%s\" not found" ), string );
1537 		return( NULL );
1538 	}
1539 
1540 	return( VIPS_OBJECT( g_object_new( type, NULL ) ) );
1541 }
1542 
1543 static void
vips_object_real_to_string(VipsObject * object,VipsBuf * buf)1544 vips_object_real_to_string( VipsObject *object, VipsBuf *buf )
1545 {
1546 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
1547 
1548 	/* Just "bicubic" or whatever.
1549 	 */
1550 	vips_buf_appends( buf, class->nickname );
1551 }
1552 
1553 static void
transform_string_double(const GValue * src_value,GValue * dest_value)1554 transform_string_double( const GValue *src_value, GValue *dest_value )
1555 {
1556 	g_value_set_double( dest_value,
1557 		g_ascii_strtod( g_value_get_string( src_value ), NULL ) );
1558 }
1559 
1560 static void
vips_object_class_init(VipsObjectClass * class)1561 vips_object_class_init( VipsObjectClass *class )
1562 {
1563 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
1564 
1565 	if( !vips__object_all ) {
1566 		vips__object_all = g_hash_table_new(
1567 			g_direct_hash, g_direct_equal );
1568 		vips__object_all_lock = vips_g_mutex_new();
1569 	}
1570 
1571 	gobject_class->dispose = vips_object_dispose;
1572 	gobject_class->finalize = vips_object_finalize;
1573 	gobject_class->set_property = vips_object_set_property;
1574 	gobject_class->get_property = vips_object_get_property;
1575 
1576 	class->build = vips_object_real_build;
1577 	class->postbuild = vips_object_real_postbuild;
1578 	class->summary_class = vips_object_real_summary_class;
1579 	class->summary = vips_object_real_summary;
1580 	class->dump = vips_object_real_dump;
1581 	class->sanity = vips_object_real_sanity;
1582 	class->rewind = vips_object_real_rewind;
1583 	class->new_from_string = vips_object_real_new_from_string;
1584 	class->to_string = vips_object_real_to_string;
1585 	class->nickname = "object";
1586 	class->description = _( "base class" );
1587 
1588 	/* Table of VipsArgumentClass ... we can just g_free() them.
1589 	 */
1590 	class->argument_table = g_hash_table_new_full(
1591 		g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_free );
1592 	class->argument_table_traverse = NULL;
1593 
1594 	/* For setting double arguments from the command-line.
1595 	 */
1596 	g_value_register_transform_func( G_TYPE_STRING, G_TYPE_DOUBLE,
1597 		transform_string_double );
1598 
1599 	VIPS_ARG_STRING( class, "nickname", 1,
1600 		_( "Nickname" ),
1601 		_( "Class nickname" ),
1602 		VIPS_ARGUMENT_SET_ONCE,
1603 		G_STRUCT_OFFSET( VipsObject, nickname ),
1604 		"" );
1605 
1606 	VIPS_ARG_STRING( class, "description", 2,
1607 		_( "Description" ),
1608 		_( "Class description" ),
1609 		VIPS_ARGUMENT_SET_ONCE,
1610 		G_STRUCT_OFFSET( VipsObject, description ),
1611 		"" );
1612 
1613 	/**
1614 	 * VipsObject::postbuild:
1615 	 * @object: the object that has been built
1616 	 *
1617 	 * The ::postbuild signal is emitted once just after successful object
1618 	 * construction. Return non-zero to cause object construction to fail.
1619 	 */
1620 	vips_object_signals[SIG_POSTBUILD] = g_signal_new( "postbuild",
1621 		G_TYPE_FROM_CLASS( class ),
1622 		G_SIGNAL_RUN_LAST,
1623 		G_STRUCT_OFFSET( VipsObjectClass, postbuild ),
1624 		NULL, NULL,
1625 		vips_INT__VOID,
1626 		G_TYPE_INT, 0 );
1627 
1628 	/**
1629 	 * VipsObject::preclose:
1630 	 * @object: the object that is to close
1631 	 *
1632 	 * The ::preclose signal is emitted once just before object close
1633 	 * starts. The oject is still alive.
1634 	 */
1635 	vips_object_signals[SIG_PRECLOSE] = g_signal_new( "preclose",
1636 		G_TYPE_FROM_CLASS( class ),
1637 		G_SIGNAL_RUN_LAST,
1638 		G_STRUCT_OFFSET( VipsObjectClass, preclose ),
1639 		NULL, NULL,
1640 		g_cclosure_marshal_VOID__VOID,
1641 		G_TYPE_NONE, 0 );
1642 
1643 	/**
1644 	 * VipsObject::close:
1645 	 * @object: the object that is closing
1646 	 *
1647 	 * The ::close signal is emitted once during object close. The object
1648 	 * is dying and may not work.
1649 	 */
1650 	vips_object_signals[SIG_CLOSE] = g_signal_new( "close",
1651 		G_TYPE_FROM_CLASS( class ),
1652 		G_SIGNAL_RUN_LAST,
1653 		G_STRUCT_OFFSET( VipsObjectClass, close ),
1654 		NULL, NULL,
1655 		g_cclosure_marshal_VOID__VOID,
1656 		G_TYPE_NONE, 0 );
1657 
1658 	/**
1659 	 * VipsObject::postclose:
1660 	 * @object: the object that has closed
1661 	 *
1662 	 * The ::postclose signal is emitted once after object close. The
1663 	 * object pointer is still valid, but nothing else.
1664 	 */
1665 	vips_object_signals[SIG_POSTCLOSE] = g_signal_new( "postclose",
1666 		G_TYPE_FROM_CLASS( class ),
1667 		G_SIGNAL_RUN_LAST,
1668 		G_STRUCT_OFFSET( VipsObjectClass, postclose ),
1669 		NULL, NULL,
1670 		g_cclosure_marshal_VOID__VOID,
1671 		G_TYPE_NONE, 0 );
1672 
1673 }
1674 
1675 static void
vips_object_init(VipsObject * object)1676 vips_object_init( VipsObject *object )
1677 {
1678 #ifdef DEBUG
1679 	printf( "vips_object_init: " );
1680 	vips_object_print_name( object );
1681 	printf( "\n" );
1682 #endif /*DEBUG*/
1683 
1684 	g_mutex_lock( vips__object_all_lock );
1685 	g_hash_table_insert( vips__object_all, object, object );
1686 	g_mutex_unlock( vips__object_all_lock );
1687 }
1688 
1689 static void *
traverse_find_required_priority(void * data,void * a,void * b)1690 traverse_find_required_priority( void *data, void *a, void *b )
1691 {
1692 	VipsArgumentClass *argument_class = (VipsArgumentClass *) data;
1693 	int priority = GPOINTER_TO_INT( a );
1694 
1695 	if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
1696 		!(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) &&
1697 		argument_class->priority == priority )
1698 		return( argument_class );
1699 
1700 	return( NULL );
1701 }
1702 
1703 static gint
traverse_sort(gconstpointer a,gconstpointer b,void * user_data)1704 traverse_sort( gconstpointer a, gconstpointer b, void *user_data )
1705 {
1706 	VipsArgumentClass *class1 = (VipsArgumentClass *) a;
1707 	VipsArgumentClass *class2 = (VipsArgumentClass *) b;
1708 
1709 	return( class1->priority - class2->priority );
1710 }
1711 
1712 /* Add a vipsargument ... automate some stuff with this.
1713  */
1714 void
vips_object_class_install_argument(VipsObjectClass * object_class,GParamSpec * pspec,VipsArgumentFlags flags,int priority,guint offset)1715 vips_object_class_install_argument( VipsObjectClass *object_class,
1716 	GParamSpec *pspec, VipsArgumentFlags flags, int priority, guint offset )
1717 {
1718 	VipsArgumentClass *argument_class = g_new( VipsArgumentClass, 1 );
1719 
1720 	GSList *argument_table_traverse;
1721 	VipsArgumentClass *ac;
1722 
1723 #ifdef DEBUG
1724 	printf( "vips_object_class_install_argument: %p %s %s\n",
1725 		object_class,
1726 		g_type_name( G_TYPE_FROM_CLASS( object_class ) ),
1727 		g_param_spec_get_name( pspec ) );
1728 #endif /*DEBUG*/
1729 
1730 	/* object_class->argument* is shared, so we must lock.
1731 	 */
1732 	g_mutex_lock( vips__global_lock );
1733 
1734 	/* Must be a new one.
1735 	 */
1736 	g_assert( !g_hash_table_lookup( object_class->argument_table, pspec ) );
1737 
1738 	/* Mustn't have INPUT and OUTPUT both set.
1739 	 */
1740 	g_assert( !(
1741 		(flags & VIPS_ARGUMENT_INPUT) &&
1742 		(flags & VIPS_ARGUMENT_OUTPUT)) );
1743 
1744 	((VipsArgument *) argument_class)->pspec = pspec;
1745 	argument_class->object_class = object_class;
1746 	argument_class->flags = flags;
1747 	argument_class->priority = priority;
1748 	argument_class->offset = offset;
1749 
1750 	vips_argument_table_replace( object_class->argument_table,
1751 		(VipsArgument *) argument_class );
1752 
1753 	/* If this is the first argument for a new subclass, we need to clone
1754 	 * the traverse list we inherit.
1755 	 */
1756 	if( object_class->argument_table_traverse_gtype !=
1757 		G_TYPE_FROM_CLASS( object_class ) ) {
1758 #ifdef DEBUG
1759 		printf( "vips_object_class_install_argument: "
1760 			"cloning traverse\n" );
1761 #endif /*DEBUG*/
1762 
1763 		object_class->argument_table_traverse =
1764 			g_slist_copy( object_class->argument_table_traverse );
1765 		object_class->argument_table_traverse_gtype =
1766 			G_TYPE_FROM_CLASS( object_class );
1767 	}
1768 
1769 	/* We read argument_table_traverse without a lock (eg. see
1770 	 * vips_argument_map()), so we must be very careful updating it.
1771 	 */
1772 	argument_table_traverse =
1773 		g_slist_copy( object_class->argument_table_traverse );
1774 
1775 	/* We keep traverse sorted by priority, so we musn't have duplicate
1776 	 * priority values in required args.
1777 	 */
1778 	if( (flags & VIPS_ARGUMENT_REQUIRED) &&
1779 		!(flags & VIPS_ARGUMENT_DEPRECATED) &&
1780 		(ac = vips_slist_map2( argument_table_traverse,
1781 			traverse_find_required_priority,
1782 			GINT_TO_POINTER( priority ), NULL )) )
1783 		g_warning( "vips_object_class_install_argument: "
1784 			"%s.%s, %s.%s duplicate priority",
1785 			g_type_name( G_TYPE_FROM_CLASS( object_class ) ),
1786 			g_param_spec_get_name( pspec ),
1787 			g_type_name( G_TYPE_FROM_CLASS( ac->object_class ) ),
1788 			g_param_spec_get_name( ((VipsArgument *) ac)->pspec ) );
1789 
1790 	/* Warn about optional boolean args which default TRUE. These won't
1791 	 * work from the CLI, since simple GOption switches don't allow
1792 	 * `=false`.
1793 	 */
1794 	if( !(flags & VIPS_ARGUMENT_REQUIRED) &&
1795 		!(flags & VIPS_ARGUMENT_DEPRECATED) &&
1796 		G_IS_PARAM_SPEC_BOOLEAN( pspec ) &&
1797 		G_PARAM_SPEC_BOOLEAN( pspec )->default_value )
1798 		g_warning( "vips_object_class_install_argument: "
1799 			"default TRUE BOOL arg %s.%s",
1800 			g_type_name( G_TYPE_FROM_CLASS( object_class ) ),
1801 			g_param_spec_get_name( pspec ) );
1802 
1803 	argument_table_traverse = g_slist_prepend(
1804 		argument_table_traverse, argument_class );
1805 	argument_table_traverse = g_slist_sort(
1806 		argument_table_traverse, (GCompareFunc) traverse_sort );
1807 	VIPS_SWAP( GSList *,
1808 		argument_table_traverse,
1809 		object_class->argument_table_traverse );
1810 
1811 	g_slist_free( argument_table_traverse );
1812 
1813 #ifdef DEBUG
1814 {
1815 	GSList *p;
1816 
1817 	printf( "%d items on traverse %p\n",
1818 		g_slist_length( object_class->argument_table_traverse ),
1819 		&object_class->argument_table_traverse );
1820 	for( p = object_class->argument_table_traverse; p; p = p->next ) {
1821 		VipsArgumentClass *argument_class =
1822 			(VipsArgumentClass *) p->data;
1823 
1824 		printf( "\t%p %s\n",
1825 			argument_class,
1826 			g_param_spec_get_name(
1827 				((VipsArgument *) argument_class)->pspec ) );
1828 	}
1829 }
1830 #endif /*DEBUG*/
1831 
1832 	g_mutex_unlock( vips__global_lock );
1833 }
1834 
1835 static void
vips_object_no_value(VipsObject * object,const char * name)1836 vips_object_no_value( VipsObject *object, const char *name )
1837 {
1838 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
1839 
1840 	GParamSpec *pspec;
1841 	VipsArgumentClass *argument_class;
1842 	VipsArgumentInstance *argument_instance;
1843 
1844 	if( vips_object_get_argument( object, name,
1845 		&pspec, &argument_class, &argument_instance ) )
1846 		g_assert_not_reached();
1847 
1848 	if( strcmp( name, g_param_spec_get_name( pspec ) ) == 0 )
1849 		vips_error( class->nickname,
1850 			_( "no value supplied for argument '%s'" ), name );
1851 	else
1852 		vips_error( class->nickname,
1853 			_( "no value supplied for argument '%s' ('%s')" ),
1854 			name,
1855 			g_param_spec_get_name( pspec ) );
1856 }
1857 
1858 /* Set a named arg from a string.
1859  */
1860 int
vips_object_set_argument_from_string(VipsObject * object,const char * name,const char * value)1861 vips_object_set_argument_from_string( VipsObject *object,
1862 	const char *name, const char *value )
1863 {
1864 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
1865 
1866 	GParamSpec *pspec;
1867 	VipsArgumentClass *argument_class;
1868 	VipsArgumentInstance *argument_instance;
1869 	VipsObjectClass *oclass;
1870 	GType otype;
1871 
1872 	GValue gvalue = { 0 };
1873 
1874 	VIPS_DEBUG_MSG( "vips_object_set_argument_from_string: %s = %s\n",
1875 		name, value );
1876 
1877 	if( vips_object_get_argument( object, name,
1878 		&pspec, &argument_class, &argument_instance ) )
1879 		return( -1 );
1880 
1881 	otype = G_PARAM_SPEC_VALUE_TYPE( pspec );
1882 
1883 	g_assert( argument_class->flags & VIPS_ARGUMENT_INPUT );
1884 
1885 	if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) ) {
1886 		VipsImage *out;
1887 		VipsOperationFlags flags;
1888 		VipsAccess access;
1889 		char filename[VIPS_PATH_MAX];
1890 		char option_string[VIPS_PATH_MAX];
1891 
1892 		flags = 0;
1893 		if( VIPS_IS_OPERATION( object ) )
1894 			flags = vips_operation_get_flags(
1895 				VIPS_OPERATION( object ) );
1896 
1897 		if( flags &
1898 			(VIPS_OPERATION_SEQUENTIAL_UNBUFFERED |
1899 			 VIPS_OPERATION_SEQUENTIAL) )
1900 			access = VIPS_ACCESS_SEQUENTIAL;
1901 		else
1902 			access = VIPS_ACCESS_RANDOM;
1903 
1904 		if( !value ) {
1905 			vips_object_no_value( object, name );
1906 			return( -1 );
1907 		}
1908 		vips__filename_split8( value, filename, option_string );
1909 
1910 		if( strcmp( "stdin", filename ) == 0 ) {
1911 			VipsSource *source;
1912 
1913 			if( !(source =
1914 				vips_source_new_from_descriptor( 0 )) )
1915 				return( -1 );
1916 			if( !(out = vips_image_new_from_source( source,
1917 				option_string,
1918 				"access", access,
1919 				NULL )) ) {
1920 				VIPS_UNREF( source );
1921 				return( -1 );
1922 			}
1923 			VIPS_UNREF( source );
1924 		}
1925 		else {
1926 			if( !(out = vips_image_new_from_file( value,
1927 				"access", access,
1928 				NULL )) )
1929 				return( -1 );
1930 		}
1931 
1932 		g_value_init( &gvalue, VIPS_TYPE_IMAGE );
1933 		g_value_set_object( &gvalue, out );
1934 
1935 		/* Setting gvalue will have upped @out's count again,
1936 		 * go back to 1 so that gvalue has the only ref.
1937 		 */
1938 		g_object_unref( out );
1939 	}
1940 	else if( g_type_is_a( otype, VIPS_TYPE_SOURCE ) ) {
1941 		VipsSource *source;
1942 
1943 		if( !value ) {
1944 			vips_object_no_value( object, name );
1945 			return( -1 );
1946 		}
1947 
1948 		if( !(source = vips_source_new_from_options( value )) )
1949 			return( -1 );
1950 
1951 		g_value_init( &gvalue, VIPS_TYPE_SOURCE );
1952 		g_value_set_object( &gvalue, source );
1953 
1954 		/* Setting gvalue will have upped @out's count again,
1955 		 * go back to 1 so that gvalue has the only ref.
1956 		 */
1957 		g_object_unref( source );
1958 	}
1959 	else if( g_type_is_a( otype, VIPS_TYPE_ARRAY_IMAGE ) ) {
1960 		/* We have to have a special case for this, we can't just rely
1961 		 * on transform_g_string_array_image(), since we need to be
1962 		 * able to set the access hint on the image.
1963 		 */
1964 		VipsArrayImage *array_image;
1965 		VipsOperationFlags flags;
1966 		VipsAccess access;
1967 
1968 		if( !value ) {
1969 			vips_object_no_value( object, name );
1970 			return( -1 );
1971 		}
1972 
1973 		flags = 0;
1974 		if( VIPS_IS_OPERATION( object ) )
1975 			flags = vips_operation_get_flags(
1976 				VIPS_OPERATION( object ) );
1977 
1978 		if( flags & (VIPS_OPERATION_SEQUENTIAL_UNBUFFERED |
1979 			     VIPS_OPERATION_SEQUENTIAL) )
1980 			access = VIPS_ACCESS_SEQUENTIAL;
1981 		else
1982 			access = VIPS_ACCESS_RANDOM;
1983 
1984 		if( !(array_image =
1985 			vips_array_image_new_from_string( value, access )) )
1986 			return( -1 );
1987 
1988 		g_value_init( &gvalue, VIPS_TYPE_ARRAY_IMAGE );
1989 		g_value_set_boxed( &gvalue, array_image );
1990 
1991 		/* Setting gvalue will have upped @array_image's count again,
1992 		 * go back to 1 so that gvalue has the only ref.
1993 		 */
1994 		vips_area_unref( VIPS_AREA( array_image ) );
1995 	}
1996 	else if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
1997 		(oclass = g_type_class_ref( otype )) ) {
1998 		VipsObject *new_object;
1999 
2000 		if( !value ) {
2001 			vips_object_no_value( object, name );
2002 			return( -1 );
2003 		}
2004 
2005 		if( !(new_object =
2006 			vips_object_new_from_string( oclass, value )) )
2007 			return( -1 );
2008 
2009 		/* Not necessarily a VipsOperation subclass so we don't use
2010 		 * the cache. We could have a separate case for this.
2011 		 */
2012 		if( vips_object_build( new_object ) ) {
2013 			g_object_unref( new_object );
2014 			return( -1 );
2015 		}
2016 
2017 		g_value_init( &gvalue, G_TYPE_OBJECT );
2018 		g_value_set_object( &gvalue, new_object );
2019 
2020 		/* The GValue now has a ref, we can drop ours.
2021 		 */
2022 		g_object_unref( new_object );
2023 	}
2024 	else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
2025 		gboolean b;
2026 
2027 		b = TRUE;
2028 		if( value &&
2029 			(g_ascii_strcasecmp( value, "false" ) == 0 ||
2030 			g_ascii_strcasecmp( value, "no" ) == 0 ||
2031 			strcmp( value, "0" ) == 0) )
2032 			b = FALSE;
2033 
2034 		g_value_init( &gvalue, G_TYPE_BOOLEAN );
2035 		g_value_set_boolean( &gvalue, b );
2036 	}
2037 	else if( G_IS_PARAM_SPEC_INT( pspec ) ) {
2038 		int i;
2039 
2040 		if( !value ) {
2041 			vips_object_no_value( object, name );
2042 			return( -1 );
2043 		}
2044 
2045 		if( sscanf( value, "%d", &i ) != 1 ) {
2046 			vips_error( class->nickname,
2047 				_( "'%s' is not an integer" ), value );
2048 			return( -1 );
2049 		}
2050 
2051 		g_value_init( &gvalue, G_TYPE_INT );
2052 		g_value_set_int( &gvalue, i );
2053 	}
2054 	else if( G_IS_PARAM_SPEC_UINT64( pspec ) ) {
2055 		/* Not allways the same as guint64 :-( argh.
2056 		 */
2057 		long long l;
2058 
2059 		if( !value ) {
2060 			vips_object_no_value( object, name );
2061 			return( -1 );
2062 		}
2063 
2064 		if( sscanf( value, "%lld", &l ) != 1 ) {
2065 			vips_error( class->nickname,
2066 				_( "'%s' is not an integer" ), value );
2067 			return( -1 );
2068 		}
2069 
2070 		g_value_init( &gvalue, G_TYPE_UINT64 );
2071 		g_value_set_uint64( &gvalue, l );
2072 	}
2073 	else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) {
2074 		double d;
2075 
2076 		if( !value ) {
2077 			vips_object_no_value( object, name );
2078 			return( -1 );
2079 		}
2080 
2081 		if( sscanf( value, "%lg", &d ) != 1 ) {
2082 			vips_error( class->nickname,
2083 				_( "'%s' is not a double" ), value );
2084 			return( -1 );
2085 		}
2086 
2087 		g_value_init( &gvalue, G_TYPE_DOUBLE );
2088 		g_value_set_double( &gvalue, d );
2089 	}
2090 	else if( G_IS_PARAM_SPEC_ENUM( pspec ) ) {
2091 		int i;
2092 
2093 		if( !value ) {
2094 			vips_object_no_value( object, name );
2095 			return( -1 );
2096 		}
2097 
2098 		if( (i = vips_enum_from_nick( class->nickname,
2099 			otype, value )) < 0 )
2100 			return( -1 );
2101 
2102 		g_value_init( &gvalue, otype );
2103 		g_value_set_enum( &gvalue, i );
2104 	}
2105 	else if( G_IS_PARAM_SPEC_FLAGS( pspec ) ) {
2106 		/* Allow a symbolic name, or an int.
2107 		 */
2108 		int i;
2109 
2110 		if( !value ) {
2111 			vips_object_no_value( object, name );
2112 			return( -1 );
2113 		}
2114 
2115 		if( sscanf( value, "%d", &i ) != 1 &&
2116 			(i = vips_flags_from_nick( class->nickname,
2117 			otype, value )) < 0 ) {
2118 			vips_error( class->nickname,
2119 				_( "'%s' is not an integer" ), value );
2120 			return( -1 );
2121 		}
2122 
2123 		g_value_init( &gvalue, otype );
2124 		g_value_set_flags( &gvalue, i );
2125 	}
2126 	else {
2127 		if( !value ) {
2128 			vips_object_no_value( object, name );
2129 			return( -1 );
2130 		}
2131 
2132 		g_value_init( &gvalue, G_TYPE_STRING );
2133 		g_value_set_string( &gvalue, value );
2134 	}
2135 
2136 	g_object_set_property( G_OBJECT( object ), name, &gvalue );
2137 	g_value_unset( &gvalue );
2138 
2139 	return( 0 );
2140 }
2141 
2142 /* Does an vipsargument need an argument to write to? For example, an image
2143  * output needs a filename, a double output just prints.
2144  */
2145 gboolean
vips_object_argument_needsstring(VipsObject * object,const char * name)2146 vips_object_argument_needsstring( VipsObject *object, const char *name )
2147 {
2148 	GParamSpec *pspec;
2149 	VipsArgumentClass *argument_class;
2150 	VipsArgumentInstance *argument_instance;
2151 
2152 #ifdef DEBUG
2153 	printf( "vips_object_argument_needsstring: %s\n", name );
2154 #endif /*DEBUG*/
2155 
2156 	if( vips_object_get_argument( object, name,
2157 		&pspec, &argument_class, &argument_instance ) )
2158 		return( -1 );
2159 
2160 	return( vips_argument_class_needsstring( argument_class ) );
2161 }
2162 
2163 static void
vips_object_print_arg(VipsObject * object,GParamSpec * pspec,VipsBuf * buf)2164 vips_object_print_arg( VipsObject *object, GParamSpec *pspec, VipsBuf *buf )
2165 {
2166 	GType type = G_PARAM_SPEC_VALUE_TYPE( pspec );
2167 	const char *name = g_param_spec_get_name( pspec );
2168 	GValue value = { 0, };
2169 	char *str_value;
2170 
2171 	g_value_init( &value, type );
2172 	g_object_get_property( G_OBJECT( object ), name, &value );
2173 	str_value = g_strdup_value_contents( &value );
2174 	vips_buf_appends( buf, str_value );
2175 	g_free( str_value );
2176 	g_value_unset( &value );
2177 }
2178 
2179 /* Is a filename a target, ie. it is of the form ".jpg". Any trailing options
2180  * have already been stripped. Watch out for cases like "./x.jpg".
2181  */
2182 static gboolean
vips_filename_istarget(const char * filename)2183 vips_filename_istarget( const char *filename )
2184 {
2185 	const char *p;
2186 
2187 	return( (p = strrchr( filename, '.' )) && p == filename );
2188 }
2189 
2190 /* Write a named arg to the string. If the arg does not need a string (see
2191  * above), arg will be NULL.
2192  */
2193 int
vips_object_get_argument_to_string(VipsObject * object,const char * name,const char * arg)2194 vips_object_get_argument_to_string( VipsObject *object,
2195 	const char *name, const char *arg )
2196 {
2197 	GParamSpec *pspec;
2198 	GType otype;
2199 	VipsArgumentClass *argument_class;
2200 	VipsArgumentInstance *argument_instance;
2201 	VipsObjectClass *oclass;
2202 
2203 #ifdef DEBUG
2204 	printf( "vips_object_get_argument_to_string: %s -> %s\n",
2205 		name, arg );
2206 #endif /*DEBUG*/
2207 
2208 	if( vips_object_get_argument( object, name,
2209 		&pspec, &argument_class, &argument_instance ) )
2210 		return( -1 );
2211 
2212 	otype = G_PARAM_SPEC_VALUE_TYPE( pspec );
2213 
2214 	g_assert( argument_class->flags & VIPS_ARGUMENT_OUTPUT );
2215 
2216 	if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) ) {
2217 		VipsImage *in;
2218 		char filename[VIPS_PATH_MAX];
2219 		char option_string[VIPS_PATH_MAX];
2220 
2221 		vips__filename_split8( arg, filename, option_string );
2222 
2223 		if( vips_filename_istarget( filename ) ) {
2224 			VipsTarget *target;
2225 
2226 			if( !(target = vips_target_new_to_descriptor( 1 )) )
2227 				return( -1 );
2228 			g_object_get( object, name, &in, NULL );
2229 			if( vips_image_write_to_target( in,
2230 				arg, target, NULL ) ) {
2231 				VIPS_UNREF( in );
2232 				VIPS_UNREF( target );
2233 				return( -1 );
2234 			}
2235 			VIPS_UNREF( in );
2236 			VIPS_UNREF( target );
2237 		}
2238 		else {
2239 			/* Pull out the image and write it.
2240 			 */
2241 			g_object_get( object, name, &in, NULL );
2242 			if( vips_image_write_to_file( in, arg, NULL ) ) {
2243 				VIPS_UNREF( in );
2244 				return( -1 );
2245 			}
2246 			VIPS_UNREF( in );
2247 		}
2248 	}
2249 	else if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
2250 		(oclass = g_type_class_ref( otype )) &&
2251 		oclass->output_to_arg ) {
2252 		VipsObject *value;
2253 
2254 		g_object_get( object, name, &value, NULL );
2255 		if( oclass->output_to_arg( value, arg ) ) {
2256 			g_object_unref( value );
2257 			return( -1 );
2258 		}
2259 		g_object_unref( value );
2260 	}
2261 	else {
2262 		char str[1000];
2263 		VipsBuf buf = VIPS_BUF_STATIC( str );
2264 
2265 		vips_object_print_arg( object, pspec, &buf );
2266 		printf( "%s\n", vips_buf_all( &buf ) );
2267 	}
2268 
2269 	return( 0 );
2270 }
2271 
2272 static void *
vips_argument_is_required(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)2273 vips_argument_is_required( VipsObject *object,
2274 	GParamSpec *pspec,
2275 	VipsArgumentClass *argument_class,
2276 	VipsArgumentInstance *argument_instance,
2277 	void *a, void *b )
2278 {
2279 	if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
2280 		(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
2281 		(argument_class->flags & VIPS_ARGUMENT_INPUT) &&
2282 		!argument_instance->assigned )
2283 		return( pspec );
2284 
2285 	return( NULL );
2286 }
2287 
2288 /* Find the first unassigned required input arg.
2289  */
2290 static GParamSpec *
vips_object_find_required(VipsObject * object)2291 vips_object_find_required( VipsObject *object )
2292 {
2293 	return( (GParamSpec *) vips_argument_map( object,
2294 		vips_argument_is_required, NULL, NULL ) );
2295 }
2296 
2297 typedef struct _VipsNameFlagsPair {
2298 	const char **names;
2299 	int *flags;
2300 } VipsNameFlagsPair;
2301 
2302 static void *
vips_object_find_args(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)2303 vips_object_find_args( VipsObject *object,
2304 	GParamSpec *pspec,
2305 	VipsArgumentClass *argument_class,
2306 	VipsArgumentInstance *argument_instance,
2307 	void *a, void *b )
2308 {
2309 	VipsNameFlagsPair *pair = (VipsNameFlagsPair *) a;
2310 	int *i = (int *) b;
2311 
2312 	pair->names[*i] = g_param_spec_get_name( pspec );
2313 	pair->flags[*i] = (int) argument_class->flags;
2314 
2315 	*i += 1;
2316 
2317 	return( NULL );
2318 }
2319 
2320 /**
2321  * vips_object_get_args: (skip)
2322  * @object: object whose args should be retrieved
2323  * @names: (transfer none) (array length=n_args) (allow-none): output array of %GParamSpec names
2324  * @flags: (transfer none) (array length=n_args) (allow-none): output array of #VipsArgumentFlags
2325  * @n_args: (allow-none): length of output arrays
2326  *
2327  * Get all %GParamSpec names and #VipsArgumentFlags for an object.
2328  *
2329  * This is handy for language bindings. From C, it's usually more convenient to
2330  * use vips_argument_map().
2331  *
2332  * Returns: 0 on success, -1 on error
2333  */
2334 int
vips_object_get_args(VipsObject * object,const char *** names,int ** flags,int * n_args)2335 vips_object_get_args( VipsObject *object,
2336 	const char ***names, int **flags, int *n_args )
2337 {
2338 	VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
2339 	int n = g_slist_length( object_class->argument_table_traverse );
2340 
2341 	VipsNameFlagsPair pair;
2342 	int i;
2343 
2344 	pair.names = VIPS_ARRAY( object, n, const char * );
2345 	pair.flags = VIPS_ARRAY( object, n, int );
2346 	if( !pair.names ||
2347 		!pair.flags )
2348 		return( -1 );
2349 
2350 	i = 0;
2351 	(void) vips_argument_map( object,
2352 		vips_object_find_args, &pair, &i );
2353 
2354 	if( names )
2355 		*names = pair.names;
2356 	if( flags )
2357 		*flags = pair.flags;
2358 	if( n_args )
2359 		*n_args = n;
2360 
2361 	return( 0 );
2362 }
2363 
2364 /**
2365  * vips_object_new: (skip)
2366  * @type: object to create
2367  * @set: set arguments with this
2368  * @a: client data
2369  * @b: client data
2370  *
2371  * g_object_new() the object, set any arguments with @set, call
2372  * vips_object_build() and return the complete object.
2373  *
2374  * Returns: the new object
2375  */
2376 VipsObject *
vips_object_new(GType type,VipsObjectSetArguments set,void * a,void * b)2377 vips_object_new( GType type, VipsObjectSetArguments set, void *a, void *b )
2378 {
2379 	VipsObject *object;
2380 
2381 	vips_check_init();
2382 
2383 	object = VIPS_OBJECT( g_object_new( type, NULL ) );
2384 
2385 	if( set && set( object, a, b ) ) {
2386 		g_object_unref( object );
2387 		return( NULL );
2388 	}
2389 
2390 	if( vips_object_build( object ) ) {
2391 		g_object_unref( object );
2392 		return( NULL );
2393 	}
2394 
2395 	return( object );
2396 }
2397 
2398 /**
2399  * vips_object_set_valist:
2400  * @object: object to set arguments on
2401  * @ap: %NULL-terminated list of argument/value pairs
2402  *
2403  * See vips_object_set().
2404  *
2405  * Returns: 0 on success, -1 on error
2406  */
2407 int
vips_object_set_valist(VipsObject * object,va_list ap)2408 vips_object_set_valist( VipsObject *object, va_list ap )
2409 {
2410 	char *name;
2411 
2412 	VIPS_DEBUG_MSG( "vips_object_set_valist:\n" );
2413 
2414 	for( name = va_arg( ap, char * ); name; name = va_arg( ap, char * ) ) {
2415 		GParamSpec *pspec;
2416 		VipsArgumentClass *argument_class;
2417 		VipsArgumentInstance *argument_instance;
2418 
2419 		VIPS_DEBUG_MSG( "\tname = '%s' (%p)\n", name, name );
2420 
2421 		if( vips_object_get_argument( VIPS_OBJECT( object ), name,
2422 			&pspec, &argument_class, &argument_instance ) )
2423 			return( -1 );
2424 
2425 		VIPS_ARGUMENT_COLLECT_SET( pspec, argument_class, ap );
2426 
2427 		g_object_set_property( G_OBJECT( object ), name, &value );
2428 
2429 		VIPS_ARGUMENT_COLLECT_GET( pspec, argument_class, ap );
2430 
2431 		VIPS_ARGUMENT_COLLECT_END
2432 	}
2433 
2434 	return( 0 );
2435 }
2436 
2437 /**
2438  * vips_object_set:
2439  * @object: object to set arguments on
2440  * @...: %NULL-terminated list of argument/value pairs
2441  *
2442  * Set a list of vips object arguments. For example:
2443  *
2444  * |[
2445  * vips_object_set (operation,
2446  *   "input", in,
2447  *   "output", &out,
2448  *   NULL);
2449  * ]|
2450  *
2451  * Input arguments are given in-line, output arguments are given as pointers
2452  * to where the output value should be written.
2453  *
2454  * See also: vips_object_set_valist(), vips_object_set_from_string().
2455  *
2456  * Returns: 0 on success, -1 on error
2457  */
2458 int
vips_object_set(VipsObject * object,...)2459 vips_object_set( VipsObject *object, ... )
2460 {
2461 	va_list ap;
2462 	int result;
2463 
2464 	va_start( ap, object );
2465 	result = vips_object_set_valist( object, ap );
2466 	va_end( ap );
2467 
2468 	return( result );
2469 }
2470 
2471 /* Set object args from a string. @p should be the initial left bracket and
2472  * there should be no tokens after the matching right bracket. @p is modified.
2473  */
2474 static int
vips_object_set_args(VipsObject * object,const char * p)2475 vips_object_set_args( VipsObject *object, const char *p )
2476 {
2477 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
2478 
2479 	VipsToken token;
2480 	char string[VIPS_PATH_MAX];
2481 	char string2[VIPS_PATH_MAX];
2482 	GParamSpec *pspec;
2483 	VipsArgumentClass *argument_class;
2484 	VipsArgumentInstance *argument_instance;
2485 
2486 	if( !(p = vips__token_need( p, VIPS_TOKEN_LEFT,
2487 		string, VIPS_PATH_MAX )) )
2488 		return( -1 );
2489 
2490 	if( !(p = vips__token_segment( p, &token, string, VIPS_PATH_MAX )) )
2491 		return( -1 );
2492 
2493 	for(;;) {
2494 		if( token == VIPS_TOKEN_RIGHT )
2495 			break;
2496 		if( token != VIPS_TOKEN_STRING ) {
2497 			vips_error( class->nickname,
2498 				_( "expected string or ), saw %s" ),
2499 				vips_enum_nick( VIPS_TYPE_TOKEN, token ) );
2500 			return( -1 );
2501 		}
2502 
2503 		/* We have to look for a '=', ']' or a ',' to see if string is
2504 		 * a param name or a value.
2505 		 */
2506 		if( !(p = vips__token_segment( p, &token,
2507 			string2, VIPS_PATH_MAX )) )
2508 			return( -1 );
2509 		if( token == VIPS_TOKEN_EQUALS ) {
2510 			if( !(p = vips__token_segment_need( p, VIPS_TOKEN_STRING,
2511 				string2, VIPS_PATH_MAX )) )
2512 				return( -1 );
2513 			if( vips_object_set_argument_from_string( object,
2514 				string, string2 ) )
2515 				return( -1 );
2516 
2517 			if( !(p = vips__token_must( p, &token,
2518 				string2, VIPS_PATH_MAX )) )
2519 				return( -1 );
2520 		}
2521 		else if( g_object_class_find_property(
2522 			G_OBJECT_GET_CLASS( object ), string ) &&
2523 			!vips_object_get_argument( object, string,
2524 				&pspec, &argument_class, &argument_instance ) &&
2525 			(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
2526 			(argument_class->flags & VIPS_ARGUMENT_INPUT) &&
2527 			G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
2528 			/* The string is the name of an optional
2529 			 * input boolean ... set it!
2530 			 */
2531 			if( !argument_instance->assigned )
2532 				g_object_set( object, string, TRUE, NULL );
2533 		}
2534 		else if( (pspec = vips_object_find_required( object )) ) {
2535 			if( vips_object_set_argument_from_string( object,
2536 				g_param_spec_get_name( pspec ), string ) )
2537 				return( -1 );
2538 		}
2539 		else {
2540 			vips_error( class->nickname,
2541 				_( "unable to set '%s'" ), string );
2542 			return( -1 );
2543 		}
2544 
2545 		/* Now must be a , or a ).
2546 		 */
2547 		if( token == VIPS_TOKEN_COMMA ) {
2548 			if( !(p = vips__token_must( p, &token,
2549 				string, VIPS_PATH_MAX )) )
2550 				return( -1 );
2551 		}
2552 		else if( token != VIPS_TOKEN_RIGHT ) {
2553 			vips_error( class->nickname,
2554 				"%s", _( "not , or ) after parameter" ) );
2555 			return( -1 );
2556 		}
2557 	}
2558 
2559 	if( (p = vips__token_get( p, &token, string, VIPS_PATH_MAX )) ) {
2560 		vips_error( class->nickname,
2561 			"%s", _( "extra tokens after ')'" ) );
2562 		return( -1 );
2563 	}
2564 
2565 	return( 0 );
2566 }
2567 
2568 /**
2569  * vips_object_set_from_string:
2570  * @object: object to set arguments on
2571  * @string: arguments as a string
2572  *
2573  * Set object arguments from a string. The string can be something like
2574  * "a=12", or "a = 12, b = 13", or "fred". The string can optionally be
2575  * enclosed in brackets.
2576  *
2577  * You'd typically use this between creating the object and building it.
2578  *
2579  * See also: vips_object_set(), vips_object_build(),
2580  * vips_cache_operation_buildp().
2581  *
2582  * Returns: 0 on success, -1 on error
2583  */
2584 int
vips_object_set_from_string(VipsObject * object,const char * string)2585 vips_object_set_from_string( VipsObject *object, const char *string )
2586 {
2587 	const char *q;
2588 	VipsToken token;
2589 	char buffer[VIPS_PATH_MAX];
2590 	char str[VIPS_PATH_MAX];
2591 
2592 	vips_strncpy( buffer, string, VIPS_PATH_MAX );
2593 
2594 	/* Does string start with a bracket? If it doesn't, enclose the whole
2595 	 * thing in [].
2596 	 */
2597 	if( !(q = vips__token_get( buffer, &token, str, VIPS_PATH_MAX )) ||
2598 		token != VIPS_TOKEN_LEFT )
2599 		vips_snprintf( buffer, VIPS_PATH_MAX, "[%s]", string );
2600 	else
2601 		vips_strncpy( buffer, string, VIPS_PATH_MAX );
2602 
2603 	return( vips_object_set_args( object, buffer ) );
2604 }
2605 
2606 VipsObject *
vips_object_new_from_string(VipsObjectClass * object_class,const char * p)2607 vips_object_new_from_string( VipsObjectClass *object_class, const char *p )
2608 {
2609 	const char *q;
2610 	char str[VIPS_PATH_MAX];
2611 	VipsObject *object;
2612 
2613 	g_assert( object_class );
2614 	g_assert( object_class->new_from_string );
2615 
2616 	/* Find the start of the optional args on the end of the string, take
2617 	 * everything before that as the principal arg for the constructor.
2618 	 */
2619 	if( (q = vips__find_rightmost_brackets( p )) )
2620 		vips_strncpy( str, p, VIPS_MIN( VIPS_PATH_MAX, q - p + 1 ) );
2621 	else
2622 		vips_strncpy( str, p, VIPS_PATH_MAX );
2623 	if( !(object = object_class->new_from_string( str )) )
2624 		return( NULL );
2625 
2626 	/* More tokens there? Set any other args.
2627 	 */
2628 	if( q &&
2629 		vips_object_set_from_string( object, q ) ) {
2630 		g_object_unref( object );
2631 		return( NULL );
2632 	}
2633 
2634 	return( object );
2635 }
2636 
2637 static void *
vips_object_to_string_required(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)2638 vips_object_to_string_required( VipsObject *object,
2639 	GParamSpec *pspec,
2640 	VipsArgumentClass *argument_class,
2641 	VipsArgumentInstance *argument_instance,
2642 	void *a, void *b )
2643 {
2644 	VipsBuf *buf = (VipsBuf *) a;
2645 	gboolean *first = (gboolean *) b;
2646 
2647 	if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) ) {
2648 		if( *first ) {
2649 			vips_buf_appends( buf, "(" );
2650 			*first = FALSE;
2651 		}
2652 		else {
2653 			vips_buf_appends( buf, "," );
2654 		}
2655 
2656 		vips_object_print_arg( object, pspec, buf );
2657 	}
2658 
2659 	return( NULL );
2660 }
2661 
2662 static void *
vips_object_to_string_optional(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)2663 vips_object_to_string_optional( VipsObject *object,
2664 	GParamSpec *pspec,
2665 	VipsArgumentClass *argument_class,
2666 	VipsArgumentInstance *argument_instance,
2667 	void *a, void *b )
2668 {
2669 	VipsBuf *buf = (VipsBuf *) a;
2670 	gboolean *first = (gboolean *) b;
2671 
2672 	if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
2673 		argument_instance->assigned ) {
2674 		if( *first ) {
2675 			vips_buf_appends( buf, "(" );
2676 			*first = FALSE;
2677 		}
2678 		else {
2679 			vips_buf_appends( buf, "," );
2680 		}
2681 
2682 		vips_buf_appends( buf, g_param_spec_get_name( pspec ) );
2683 		vips_buf_appends( buf, "=" );
2684 		vips_object_print_arg( object, pspec, buf );
2685 	}
2686 
2687 	return( NULL );
2688 }
2689 
2690 /**
2691  * vips_object_to_string:
2692  * @object: object to stringify
2693  * @buf: write string here
2694  *
2695  * The inverse of vips_object_new_from_string(): turn @object into eg.
2696  * "VipsInterpolateSnohalo1(blur=.333333)".
2697  */
2698 void
vips_object_to_string(VipsObject * object,VipsBuf * buf)2699 vips_object_to_string( VipsObject *object, VipsBuf *buf )
2700 {
2701 	VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
2702 
2703 	gboolean first;
2704 
2705 	g_assert( object_class->to_string );
2706 
2707 	/* Nicknames are not guaranteed to be unique, so use the full type
2708 	 * name.
2709 	 */
2710 	object_class->to_string( object, buf );
2711 	first = TRUE;
2712 	(void) vips_argument_map( object,
2713 		vips_object_to_string_required, buf, &first );
2714 	(void) vips_argument_map( object,
2715 		vips_object_to_string_optional, buf, &first );
2716 	if( !first )
2717 		vips_buf_appends( buf, ")" );
2718 }
2719 
2720 typedef struct {
2721 	VipsSListMap2Fn fn;
2722 	void *a;
2723 	void *b;
2724 	void *result;
2725 } VipsObjectMapArgs;
2726 
2727 static void
vips_object_map_sub(VipsObject * key,VipsObject * value,VipsObjectMapArgs * args)2728 vips_object_map_sub( VipsObject *key, VipsObject *value,
2729 	VipsObjectMapArgs *args )
2730 {
2731 	if( !args->result )
2732 		args->result = args->fn( key, args->a, args->b );
2733 }
2734 
2735 /**
2736  * vips_object_map: (skip)
2737  * @fn: function to call for all objects
2738  * @a: client data
2739  * @b: client data
2740  *
2741  * Call a function for all alive objects.
2742  * Stop when @fn returns non-%NULL and return that value.
2743  *
2744  * Returns: %NULL if @fn returns %NULL for all arguments, otherwise the first
2745  * non-%NULL value from @fn.
2746  */
2747 void *
vips_object_map(VipsSListMap2Fn fn,void * a,void * b)2748 vips_object_map( VipsSListMap2Fn fn, void *a, void *b )
2749 {
2750 	VipsObjectMapArgs args;
2751 
2752 	args.fn = fn;
2753 	args.a = a;
2754 	args.b = b;
2755 	args.result = NULL;
2756 
2757 	/* We must test vips__object_all before we lock because the lock is
2758 	 * only created when the first object is created.
2759 	 */
2760 	if( vips__object_all ) {
2761 		g_mutex_lock( vips__object_all_lock );
2762 		g_hash_table_foreach( vips__object_all,
2763 			(GHFunc) vips_object_map_sub, &args );
2764 		g_mutex_unlock( vips__object_all_lock );
2765 	}
2766 
2767 	return( args.result );
2768 }
2769 
2770 /**
2771  * vips_type_map: (skip)
2772  * @base: base type
2773  * @fn: call this function for every type
2774  * @a: client data
2775  * @b: client data
2776  *
2777  * Map over a type's children. Stop when @fn returns non-%NULL
2778  * and return that value.
2779  *
2780  * Returns: %NULL if @fn returns %NULL for all arguments, otherwise the first
2781  * non-%NULL value from @fn.
2782  */
2783 void *
vips_type_map(GType base,VipsTypeMap2Fn fn,void * a,void * b)2784 vips_type_map( GType base, VipsTypeMap2Fn fn, void *a, void *b )
2785 {
2786 	GType *child;
2787 	guint n_children;
2788 	unsigned int i;
2789 	void *result;
2790 
2791 	child = g_type_children( base, &n_children );
2792 	result = NULL;
2793 	for( i = 0; i < n_children && !result; i++ )
2794 		result = fn( child[i], a, b );
2795 	g_free( child );
2796 
2797 	return( result );
2798 }
2799 
2800 /**
2801  * vips_type_map_all: (skip)
2802  * @base: base type
2803  * @fn: call this function for every type
2804  * @a: client data
2805  *
2806  * Map over a type's children, direct and indirect. Stop when @fn returns
2807  * non-%NULL and return that value.
2808  *
2809  * Returns: %NULL if @fn returns %NULL for all arguments, otherwise the first
2810  * non-%NULL value from @fn.
2811  */
2812 void *
vips_type_map_all(GType base,VipsTypeMapFn fn,void * a)2813 vips_type_map_all( GType base, VipsTypeMapFn fn, void *a )
2814 {
2815 	void *result;
2816 
2817 	if( !(result = fn( base, a )) )
2818 		result = vips_type_map( base,
2819 			(VipsTypeMap2Fn) vips_type_map_all, fn, a );
2820 
2821 	return( result );
2822 }
2823 
2824 /**
2825  * vips_class_map_all: (skip)
2826  * @type: base type
2827  * @fn: call this function for every type
2828  * @a: client data
2829  *
2830  * Loop over all the subclasses of @type. Non-abstract classes only.
2831  * Stop when @fn returns
2832  * non-%NULL and return that value.
2833  *
2834  * Returns: %NULL if @fn returns %NULL for all arguments, otherwise the first
2835  * non-%NULL value from @fn.
2836  */
2837 void *
vips_class_map_all(GType type,VipsClassMapFn fn,void * a)2838 vips_class_map_all( GType type, VipsClassMapFn fn, void *a )
2839 {
2840 	void *result;
2841 
2842 	/* Avoid abstract classes. Use type_map_all for them.
2843 	 */
2844 	if( !G_TYPE_IS_ABSTRACT( type ) ) {
2845 		/* We never unref this ref, but we never unload classes
2846 		 * anyway, so so what.
2847 		 */
2848 		if( (result = fn(
2849 			VIPS_OBJECT_CLASS( g_type_class_ref( type ) ), a )) )
2850 			return( result );
2851 	}
2852 
2853 	if( (result = vips_type_map( type,
2854 		(VipsTypeMap2Fn) vips_class_map_all, fn, a )) )
2855 		return( result );
2856 
2857 	return( NULL );
2858 }
2859 
2860 /* How deeply nested is a class ... used to indent class lists.
2861  */
2862 int
vips_type_depth(GType type)2863 vips_type_depth( GType type )
2864 {
2865 	int depth;
2866 
2867 	depth = 0;
2868 	while( type != VIPS_TYPE_OBJECT &&
2869 		(type = g_type_parent( type )) )
2870 		depth += 1;
2871 
2872 	return( depth );
2873 }
2874 
2875 static void *
test_name(VipsObjectClass * class,const char * nickname)2876 test_name( VipsObjectClass *class, const char *nickname )
2877 {
2878 	if( g_ascii_strcasecmp( class->nickname, nickname ) == 0 )
2879 		return( class );
2880 
2881 	/* Check the class name too, why not.
2882 	 */
2883 	if( g_ascii_strcasecmp( G_OBJECT_CLASS_NAME( class ), nickname ) == 0 )
2884 		return( class );
2885 
2886 	return( NULL );
2887 }
2888 
2889 /**
2890  * vips_class_find:
2891  * @basename: name of base class
2892  * @nickname: search for a class with this nickname
2893  *
2894  * Search below @basename, return the first class whose name or @nickname
2895  * matches.
2896  *
2897  * See also: vips_type_find()
2898  *
2899  * Returns: (transfer none): the found class.
2900  */
2901 const VipsObjectClass *
vips_class_find(const char * basename,const char * nickname)2902 vips_class_find( const char *basename, const char *nickname )
2903 {
2904 	const char *classname = basename ? basename : "VipsObject";
2905 
2906 	VipsObjectClass *class;
2907 	GType base;
2908 
2909 	if( !(base = g_type_from_name( classname )) )
2910 		return( NULL );
2911 	class = vips_class_map_all( base,
2912 		(VipsClassMapFn) test_name, (void *) nickname );
2913 
2914 	return( class );
2915 }
2916 
2917 /* What we store for each nickname. We can't just store the type with
2918  * GINT_TO_POINTER() since GType is 64 bits on some platforms.
2919  */
2920 typedef struct _NicknameGType {
2921 	const char *nickname;
2922 	GType type;
2923 	gboolean duplicate;
2924 } NicknameGType;
2925 
2926 static void *
vips_class_add_hash(VipsObjectClass * class,GHashTable * table)2927 vips_class_add_hash( VipsObjectClass *class, GHashTable *table )
2928 {
2929 	GType type = G_OBJECT_CLASS_TYPE( class );
2930 	NicknameGType *hit;
2931 
2932 	hit = (NicknameGType *)
2933 		g_hash_table_lookup( table, (void *) class->nickname );
2934 
2935 	/* If this is not a unique name, mark as a duplicate. In this case
2936 	 * we'll need to fall back to a search.
2937 	 */
2938 	if( hit )
2939 		hit->duplicate = TRUE;
2940 	else {
2941 		hit = g_new( NicknameGType, 1 );
2942 		hit->nickname = class->nickname;
2943 		hit->type = type;
2944 		hit->duplicate = FALSE;
2945 		g_hash_table_insert( table, (void *) hit->nickname, hit );
2946 	}
2947 
2948 	return( NULL );
2949 }
2950 
2951 static void *
vips_class_build_hash_cb(void * dummy)2952 vips_class_build_hash_cb( void *dummy )
2953 {
2954 	GType base;
2955 
2956 	vips__object_nickname_table =
2957 		g_hash_table_new( g_str_hash, g_str_equal );
2958 
2959 	base = g_type_from_name( "VipsObject" );
2960 	g_assert( base );
2961 
2962 	vips_class_map_all( base,
2963 		(VipsClassMapFn) vips_class_add_hash,
2964 		(void *) vips__object_nickname_table );
2965 
2966 	return( NULL );
2967 }
2968 
2969 /**
2970  * vips_type_find:
2971  * @basename: name of base class
2972  * @nickname: search for a class with this nickname
2973  *
2974  * Search below @basename, return the %GType of the class whose name or
2975  * @nickname matches, or 0 for not found.
2976  * If @basename is NULL, the whole of #VipsObject is searched.
2977  *
2978  * This function uses a cache, so it should be quick.
2979  *
2980  * See also: vips_class_find()
2981  *
2982  * Returns: the %GType of the class, or 0 if the class is not found.
2983  */
2984 GType
vips_type_find(const char * basename,const char * nickname)2985 vips_type_find( const char *basename, const char *nickname )
2986 {
2987 	static GOnce once = G_ONCE_INIT;
2988 
2989 	const char *classname = basename ? basename : "VipsObject";
2990 
2991 	NicknameGType *hit;
2992 	GType base;
2993 	GType type;
2994 
2995 	VIPS_ONCE( &once, vips_class_build_hash_cb, NULL );
2996 
2997 	hit = (NicknameGType *)
2998 		g_hash_table_lookup( vips__object_nickname_table,
2999 			(void *) nickname );
3000 
3001 	/* We must only search below basename ... check that the cache hit is
3002 	 * in the right part of the tree.
3003 	 */
3004 	if( !(base = g_type_from_name( classname )) )
3005 		return( 0 );
3006 	if( hit &&
3007 		!hit->duplicate &&
3008 		g_type_is_a( hit->type, base ) )
3009 		type = hit->type;
3010 	else {
3011 		const VipsObjectClass *class;
3012 
3013 		if( !(class = vips_class_find( basename, nickname )) )
3014 			return( 0 );
3015 
3016 		type = G_OBJECT_CLASS_TYPE( class );
3017 	}
3018 
3019 	return( type );
3020 }
3021 
3022 /**
3023  * vips_nickname_find:
3024  * @type: #GType to search for
3025  *
3026  * Return the VIPS nickname for a %GType. Handy for language bindings.
3027  *
3028  * Returns: (transfer none): the class nickname.
3029  */
3030 const char *
vips_nickname_find(GType type)3031 vips_nickname_find( GType type )
3032 {
3033 	gpointer p;
3034 	VipsObjectClass *class;
3035 
3036 	if( type &&
3037 		(p = g_type_class_ref( type )) &&
3038 		VIPS_IS_OBJECT_CLASS( p ) &&
3039 		(class = VIPS_OBJECT_CLASS( p )) )
3040 		return( class->nickname );
3041 
3042 	return( NULL );
3043 }
3044 
3045 /* The vips_object_local() macro uses this as its callback.
3046  */
3047 void
vips_object_local_cb(VipsObject * vobject,GObject * gobject)3048 vips_object_local_cb( VipsObject *vobject, GObject *gobject )
3049 {
3050 	VIPS_FREEF( g_object_unref, gobject );
3051 }
3052 
3053 typedef struct {
3054 	VipsObject **array;
3055 	int n;
3056 } VipsObjectLocal;
3057 
3058 static void
vips_object_local_array_cb(VipsObject * parent,VipsObjectLocal * local)3059 vips_object_local_array_cb( VipsObject *parent, VipsObjectLocal *local )
3060 {
3061 	int i;
3062 
3063 	for( i = 0; i < local->n; i++ )
3064 		VIPS_FREEF( g_object_unref, local->array[i] );
3065 
3066 	VIPS_FREEF( g_free, local->array );
3067 	VIPS_FREEF( g_free, local );
3068 }
3069 
3070 /**
3071  * vips_object_local_array: (skip)
3072  * @parent: objects unref when this object unrefs
3073  * @n: array size
3074  *
3075  * Make an array of NULL VipsObject pointers. When @parent closes, every
3076  * non-NULL pointer in the array will be unreffed and the array will be
3077  * freed. Handy for creating a set of temporary images for a function.
3078  *
3079  * The array is NULL-terminated, ie. contains an extra NULL element at the
3080  * end.
3081  *
3082  * Example:
3083  *
3084  * |[
3085  * VipsObject **t;
3086  *
3087  * t = vips_object_local_array( parent, 5 );
3088  * if(
3089  *   vips_add( a, b, &t[0], NULL ) ||
3090  *   vips_invert( t[0], &t[1], NULL ) ||
3091  *   vips_add( t[1], t[0], &t[2], NULL ) ||
3092  *   vips_costra( t[2], out, NULL ) )
3093  *   return( -1 );
3094  * ]|
3095  *
3096  * See also: vips_object_local().
3097  *
3098  * Returns: an array of NULL pointers of length @n
3099  */
3100 VipsObject **
vips_object_local_array(VipsObject * parent,int n)3101 vips_object_local_array( VipsObject *parent, int n )
3102 {
3103 	VipsObjectLocal *local;
3104 
3105 	local = g_new( VipsObjectLocal, 1 );
3106 	local->n = n;
3107 	/* Make the array 1 too long so we can be sure there's a NULL
3108 	 * terminator.
3109 	 */
3110 	local->array = g_new0( VipsObject *, n + 1 );
3111 
3112 	g_signal_connect( parent, "close",
3113 		G_CALLBACK( vips_object_local_array_cb ), local );
3114 
3115 	return( local->array );
3116 }
3117 
3118 void
vips_object_set_static(VipsObject * object,gboolean static_object)3119 vips_object_set_static( VipsObject *object, gboolean static_object )
3120 {
3121 	object->static_object = static_object;
3122 }
3123 
3124 static void *
vips_object_n_static_cb(VipsObject * object,int * n,void * b)3125 vips_object_n_static_cb( VipsObject *object, int *n, void *b )
3126 {
3127 	if( object->static_object )
3128 		*n += 1;
3129 
3130 	return( NULL );
3131 }
3132 
3133 static int
vips_object_n_static(void)3134 vips_object_n_static( void )
3135 {
3136 	int n;
3137 
3138 	n = 0;
3139 	vips_object_map(
3140 		(VipsSListMap2Fn) vips_object_n_static_cb, &n, NULL );
3141 
3142 	return( n );
3143 }
3144 
3145 static void *
vips_object_print_all_cb(VipsObject * object,int * n,void * b)3146 vips_object_print_all_cb( VipsObject *object, int *n, void *b )
3147 {
3148 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
3149 
3150 	char str[32768];
3151 	VipsBuf buf = VIPS_BUF_STATIC( str );
3152 
3153 	fprintf( stderr, "%d) %s (%p)",
3154 		*n, G_OBJECT_TYPE_NAME( object ), object );
3155 	if( object->local_memory )
3156 		fprintf( stderr, " %zd bytes", object->local_memory );
3157 	fprintf( stderr, ", count=%d", G_OBJECT( object )->ref_count );
3158 	fprintf( stderr, "\n" );
3159 
3160 	vips_object_summary_class( class, &buf );
3161 	vips_buf_appends( &buf, ", " );
3162 	vips_object_summary( object, &buf );
3163 	fprintf( stderr, "%s\n", vips_buf_all( &buf ) );
3164 
3165 	*n += 1;
3166 
3167 	return( NULL );
3168 }
3169 
3170 int
vips__object_leak(void)3171 vips__object_leak( void )
3172 {
3173 	int n_leaks;
3174 
3175 	n_leaks = 0;
3176 
3177 	/* Don't count static objects.
3178 	 */
3179 	if( vips__object_all &&
3180 		g_hash_table_size( vips__object_all ) >
3181 			vips_object_n_static() ) {
3182 		fprintf( stderr, "%d objects alive:\n",
3183 			g_hash_table_size( vips__object_all ) );
3184 
3185 		vips_object_map(
3186 			(VipsSListMap2Fn) vips_object_print_all_cb,
3187 			&n_leaks, NULL );
3188 	}
3189 
3190 	return( n_leaks );
3191 }
3192 
3193 void
vips_object_print_all(void)3194 vips_object_print_all( void )
3195 {
3196 	(void) vips__object_leak();
3197 	(void) vips__type_leak();
3198 }
3199 
3200 static void *
vips_object_sanity_all_cb(VipsObject * object,void * a,void * b)3201 vips_object_sanity_all_cb( VipsObject *object, void *a, void *b )
3202 {
3203 	(void) vips_object_sanity( object );
3204 
3205 	return( NULL );
3206 }
3207 
3208 void
vips_object_sanity_all(void)3209 vips_object_sanity_all( void )
3210 {
3211 	vips_object_map(
3212 		(VipsSListMap2Fn) vips_object_sanity_all_cb, NULL, NULL );
3213 }
3214 
3215 static void *
vips_object_unref_outputs_sub(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)3216 vips_object_unref_outputs_sub( VipsObject *object,
3217 	GParamSpec *pspec,
3218 	VipsArgumentClass *argument_class,
3219 	VipsArgumentInstance *argument_instance,
3220 	void *a, void *b )
3221 {
3222 	if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) &&
3223 		G_IS_PARAM_SPEC_OBJECT( pspec ) &&
3224 		argument_instance->assigned ) {
3225 		GObject *value;
3226 
3227 		g_object_get( object,
3228 			g_param_spec_get_name( pspec ), &value, NULL );
3229 
3230 		/* Doing the get refs the object, so unref the get, then unref
3231 		 * again since this an an output object of the operation.
3232 		 */
3233 		g_object_unref( value );
3234 		g_object_unref( value );
3235 	}
3236 
3237 	return( NULL );
3238 }
3239 
3240 /**
3241  * vips_object_unref_outputs:
3242  * @object: object to drop output refs from
3243  *
3244  * Unref all assigned output objects. Useful for language bindings.
3245  *
3246  * After an object is built, all output args are owned by the caller. If
3247  * something goes wrong before then, we have to unref the outputs that have
3248  * been made so far. This function can also be useful for callers when
3249  * they've finished processing outputs themselves.
3250  *
3251  * See also: vips_cache_operation_build().
3252  */
3253 void
vips_object_unref_outputs(VipsObject * object)3254 vips_object_unref_outputs( VipsObject *object )
3255 {
3256 	(void) vips_argument_map( object,
3257 		vips_object_unref_outputs_sub, NULL, NULL );
3258 }
3259 
3260 /**
3261  * vips_object_get_description:
3262  * @object: object to fetch description from
3263  *
3264  * Fetch the object description. Useful for language bindings.
3265  *
3266  * @object.description is only avaliable after _build(), which can be too
3267  * late. This function fetches from the instance, if possible, but falls back
3268  * to the class description if we are too early.
3269  *
3270  * Returns: the object description
3271  */
3272 const char *
vips_object_get_description(VipsObject * object)3273 vips_object_get_description( VipsObject *object )
3274 {
3275 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
3276 
3277 	if( object->description )
3278 		return( object->description ) ;
3279 	else
3280 		return( class->description ) ;
3281 }
3282