1 /* A byte source/sink .. it can be a pipe, file descriptor, memory area,
2  * socket, node.js stream, etc.
3  *
4  * J.Cupitt, 19/6/14
5  *
6  * 26/11/20
7  * 	- use _setmode() on win to force binary write for previously opened
8  * 	  descriptors
9  */
10 
11 /*
12 
13     This file is part of VIPS.
14 
15     VIPS is free software; you can redistribute it and/or modify
16     it under the terms of the GNU Lesser General Public License as published by
17     the Free Software Foundation; either version 2 of the License, or
18     (at your option) any later version.
19 
20     This program is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     GNU Lesser General Public License for more details.
24 
25     You should have received a copy of the GNU Lesser General Public License
26     along with this program; if not, write to the Free Software
27     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28     02110-1301  USA
29 
30  */
31 
32 /*
33 
34     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
35 
36  */
37 
38 /*
39 #define VIPS_DEBUG
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 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif /*HAVE_UNISTD_H*/
52 #include <string.h>
53 #include <errno.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <fcntl.h>
57 #include <unistd.h>
58 
59 #include <vips/vips.h>
60 
61 #ifdef G_OS_WIN32
62 #include <io.h>
63 #endif /*G_OS_WIN32*/
64 
65 #include <vips/debug.h>
66 #include <vips/internal.h>
67 
68 #define MODE_WRITE CLOEXEC (BINARYIZE (O_WRONLY | O_CREAT | O_TRUNC))
69 
70 G_DEFINE_TYPE( VipsTarget, vips_target, VIPS_TYPE_CONNECTION );
71 
72 static void
vips_target_finalize(GObject * gobject)73 vips_target_finalize( GObject *gobject )
74 {
75 	VipsTarget *target = VIPS_TARGET( gobject );
76 
77 	VIPS_DEBUG_MSG( "vips_target_finalize:\n" );
78 
79 	VIPS_FREEF( g_byte_array_unref, target->memory_buffer );
80 	if( target->blob ) {
81 		vips_area_unref( VIPS_AREA( target->blob ) );
82 		target->blob = NULL;
83 	}
84 
85 	G_OBJECT_CLASS( vips_target_parent_class )->finalize( gobject );
86 }
87 
88 static int
vips_target_build(VipsObject * object)89 vips_target_build( VipsObject *object )
90 {
91 	VipsConnection *connection = VIPS_CONNECTION( object );
92 	VipsTarget *target = VIPS_TARGET( object );
93 
94 	VIPS_DEBUG_MSG( "vips_target_build: %p\n", connection );
95 
96 	if( VIPS_OBJECT_CLASS( vips_target_parent_class )->build( object ) )
97 		return( -1 );
98 
99 	if( vips_object_argument_isset( object, "filename" ) &&
100 		vips_object_argument_isset( object, "descriptor" ) ) {
101 		vips_error( vips_connection_nick( connection ),
102 			"%s", _( "don't set 'filename' and 'descriptor'" ) );
103 		return( -1 );
104 	}
105 
106 	if( connection->filename ) {
107 		const char *filename = connection->filename;
108 
109 		int fd;
110 
111 		/* 0644 is rw user, r group and other.
112 		 */
113 		if( (fd = vips_tracked_open( filename,
114 			MODE_WRITE, 0644 )) == -1 ) {
115 			vips_error_system( errno,
116 				vips_connection_nick( connection ),
117 				"%s", _( "unable to open for write" ) );
118 			return( -1 );
119 		}
120 
121 		connection->tracked_descriptor = fd;
122 		connection->descriptor = fd;
123 	}
124 	else if( vips_object_argument_isset( object, "descriptor" ) ) {
125 		connection->descriptor = dup( connection->descriptor );
126 		connection->close_descriptor = connection->descriptor;
127 
128 #ifdef G_OS_WIN32
129 		/* Windows will create eg. stdin and stdout in text mode.
130 		 * We always write in binary mode.
131 		 */
132 		_setmode( connection->descriptor, _O_BINARY );
133 #endif /*G_OS_WIN32*/
134 	}
135 	else if( target->memory )
136 		target->memory_buffer = g_byte_array_new();
137 
138 	return( 0 );
139 }
140 
141 static gint64
vips_target_write_real(VipsTarget * target,const void * data,size_t length)142 vips_target_write_real( VipsTarget *target, const void *data, size_t length )
143 {
144 	VipsConnection *connection = VIPS_CONNECTION( target );
145 
146 	VIPS_DEBUG_MSG( "vips_target_write_real: %zd bytes\n", length );
147 
148 	return( write( connection->descriptor, data, length ) );
149 }
150 
151 static void
vips_target_finish_real(VipsTarget * target)152 vips_target_finish_real( VipsTarget *target )
153 {
154 	VIPS_DEBUG_MSG( "vips_target_finish_real:\n" );
155 }
156 
157 static void
vips_target_class_init(VipsTargetClass * class)158 vips_target_class_init( VipsTargetClass *class )
159 {
160 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
161 	VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
162 
163 	gobject_class->finalize = vips_target_finalize;
164 	gobject_class->set_property = vips_object_set_property;
165 	gobject_class->get_property = vips_object_get_property;
166 
167 	object_class->nickname = "target";
168 	object_class->description = _( "Target" );
169 
170 	object_class->build = vips_target_build;
171 
172 	class->write = vips_target_write_real;
173 	class->finish = vips_target_finish_real;
174 
175 	VIPS_ARG_BOOL( class, "memory", 3,
176 		_( "Memory" ),
177 		_( "File descriptor should output to memory" ),
178 		VIPS_ARGUMENT_OPTIONAL_INPUT,
179 		G_STRUCT_OFFSET( VipsTarget, memory ),
180 		FALSE );
181 
182 	/* SET_ALWAYS means that blob is set by C and the obj system is not
183 	 * involved in creation or destruction. It can be read at any time.
184 	 */
185 	VIPS_ARG_BOXED( class, "blob", 4,
186 		_( "Blob" ),
187 		_( "Blob to save to" ),
188 		VIPS_ARGUMENT_SET_ALWAYS,
189 		G_STRUCT_OFFSET( VipsTarget, blob ),
190 		VIPS_TYPE_BLOB );
191 
192 }
193 
194 static void
vips_target_init(VipsTarget * target)195 vips_target_init( VipsTarget *target )
196 {
197 	target->blob = vips_blob_new( NULL, NULL, 0 );
198 	target->write_point = 0;
199 }
200 
201 /**
202  * vips_target_new_to_descriptor:
203  * @descriptor: write to this file descriptor
204  *
205  * Create a target attached to a file descriptor.
206  * @descriptor is kept open until the target is finalized.
207  *
208  * See also: vips_target_new_to_file().
209  *
210  * Returns: a new target.
211  */
212 VipsTarget *
vips_target_new_to_descriptor(int descriptor)213 vips_target_new_to_descriptor( int descriptor )
214 {
215 	VipsTarget *target;
216 
217 	VIPS_DEBUG_MSG( "vips_target_new_to_descriptor: %d\n",
218 		descriptor );
219 
220 	target = VIPS_TARGET( g_object_new( VIPS_TYPE_TARGET,
221 		"descriptor", descriptor,
222 		NULL ) );
223 
224 	if( vips_object_build( VIPS_OBJECT( target ) ) ) {
225 		VIPS_UNREF( target );
226 		return( NULL );
227 	}
228 
229 	return( target );
230 }
231 
232 /**
233  * vips_target_new_to_file:
234  * @filename: write to this file
235  *
236  * Create a target attached to a file.
237  *
238  * Returns: a new target.
239  */
240 VipsTarget *
vips_target_new_to_file(const char * filename)241 vips_target_new_to_file( const char *filename )
242 {
243 	VipsTarget *target;
244 
245 	VIPS_DEBUG_MSG( "vips_target_new_to_file: %s\n",
246 		filename );
247 
248 	target = VIPS_TARGET( g_object_new( VIPS_TYPE_TARGET,
249 		"filename", filename,
250 		NULL ) );
251 
252 	if( vips_object_build( VIPS_OBJECT( target ) ) ) {
253 		VIPS_UNREF( target );
254 		return( NULL );
255 	}
256 
257 	return( target );
258 }
259 
260 /**
261  * vips_target_new_to_memory:
262  *
263  * Create a target which will write to a memory area. Read from @blob to get
264  * memory.
265  *
266  * See also: vips_target_new_to_file().
267  *
268  * Returns: a new #VipsConnection
269  */
270 VipsTarget *
vips_target_new_to_memory(void)271 vips_target_new_to_memory( void )
272 {
273 	VipsTarget *target;
274 
275 	VIPS_DEBUG_MSG( "vips_target_new_to_memory:\n" );
276 
277 	target = VIPS_TARGET( g_object_new( VIPS_TYPE_TARGET,
278 		"memory", TRUE,
279 		NULL ) );
280 
281 	if( vips_object_build( VIPS_OBJECT( target ) ) ) {
282 		VIPS_UNREF( target );
283 		return( NULL );
284 	}
285 
286 	return( target );
287 }
288 
289 static int
vips_target_write_unbuffered(VipsTarget * target,const void * data,size_t length)290 vips_target_write_unbuffered( VipsTarget *target,
291 	const void *data, size_t length )
292 {
293 	VipsTargetClass *class = VIPS_TARGET_GET_CLASS( target );
294 
295 	VIPS_DEBUG_MSG( "vips_target_write_unbuffered:\n" );
296 
297 	if( target->finished )
298 		return( 0 );
299 
300 	if( target->memory_buffer )
301 		g_byte_array_append( target->memory_buffer, data, length );
302 	else
303 		while( length > 0 ) {
304 			gint64 bytes_written;
305 
306 			bytes_written = class->write( target, data, length );
307 
308 			/* n == 0 isn't strictly an error, but we treat it as
309 			 * one to make sure we don't get stuck in this loop.
310 			 */
311 			if( bytes_written <= 0 ) {
312 				vips_error_system( errno,
313 					vips_connection_nick(
314 						VIPS_CONNECTION( target ) ),
315 					"%s", _( "write error" ) );
316 				return( -1 );
317 			}
318 
319 			length -= bytes_written;
320 			data += bytes_written;
321 		}
322 
323 	return( 0 );
324 }
325 
326 static int
vips_target_flush(VipsTarget * target)327 vips_target_flush( VipsTarget *target )
328 {
329 	g_assert( target->write_point >= 0 );
330 	g_assert( target->write_point <= VIPS_TARGET_BUFFER_SIZE );
331 
332 	VIPS_DEBUG_MSG( "vips_target_flush:\n" );
333 
334 	if( target->write_point > 0 ) {
335 		if( vips_target_write_unbuffered( target,
336 			target->output_buffer, target->write_point ) )
337 			return( -1 );
338 		target->write_point = 0;
339 	}
340 
341 	return( 0 );
342 }
343 
344 /**
345  * vips_target_write:
346  * @target: target to operate on
347  * @buffer: bytes to write
348  * @length: length of @buffer in bytes
349  *
350  * Write @length bytes from @buffer to the output.
351  *
352  * Returns: 0 on success, -1 on error.
353  */
354 int
vips_target_write(VipsTarget * target,const void * buffer,size_t length)355 vips_target_write( VipsTarget *target, const void *buffer, size_t length )
356 {
357 	VIPS_DEBUG_MSG( "vips_target_write: %zd bytes\n", length );
358 
359 	if( length > VIPS_TARGET_BUFFER_SIZE - target->write_point &&
360 		vips_target_flush( target ) )
361 		return( -1 );
362 
363 	if( length > VIPS_TARGET_BUFFER_SIZE - target->write_point ) {
364 		/* Still too large? Do an unbuffered write.
365 		 */
366 		if( vips_target_write_unbuffered( target, buffer, length ) )
367 			return( -1 );
368 	}
369 	else {
370 		memcpy( target->output_buffer + target->write_point,
371 			buffer, length );
372 		target->write_point += length;
373 	}
374 
375 	return( 0 );
376 }
377 
378 /**
379  * vips_target_finish:
380  * @target: target to operate on
381  * @buffer: bytes to write
382  * @length: length of @buffer in bytes
383  *
384  * Call this at the end of write to make the target do any cleaning up. You
385  * can call it many times.
386  *
387  * After a target has been finished, further writes will do nothing.
388  */
389 void
vips_target_finish(VipsTarget * target)390 vips_target_finish( VipsTarget *target )
391 {
392 	VipsTargetClass *class = VIPS_TARGET_GET_CLASS( target );
393 
394 	VIPS_DEBUG_MSG( "vips_target_finish:\n" );
395 
396 	if( target->finished )
397 		return;
398 
399 	(void) vips_target_flush( target );
400 
401 	/* Move the target buffer into the blob so it can be read out.
402 	 */
403 	if( target->memory_buffer ) {
404 		unsigned char *data;
405 		size_t length;
406 
407 		length = target->memory_buffer->len;
408 		data = g_byte_array_free( target->memory_buffer, FALSE );
409 		target->memory_buffer = NULL;
410 		vips_blob_set( target->blob,
411 			(VipsCallbackFn) vips_area_free_cb, data, length );
412 	}
413 	else
414 		class->finish( target );
415 
416 	target->finished = TRUE;
417 }
418 
419 /**
420  * vips_target_steal:
421  * @target: target to operate on
422  * @length: return number of bytes of data
423  *
424  * Memory targets only (see vips_target_new_to_memory()). Steal all data
425  * written to the target so far, and finish it.
426  *
427  * You must free the returned pointer with g_free().
428  *
429  * The data is NOT automatically null-terminated. vips_target_putc() a '\0'
430  * before calling this to get a null-terminated string.
431  *
432  * Returns: (array length=length) (element-type guint8) (transfer full): the
433  * data
434  */
435 unsigned char *
vips_target_steal(VipsTarget * target,size_t * length)436 vips_target_steal( VipsTarget *target, size_t *length )
437 {
438 	unsigned char *data;
439 
440 	(void) vips_target_flush( target );
441 
442 	if( !target->memory_buffer ||
443 		target->finished ) {
444 		if( length )
445 			*length = target->memory_buffer->len;
446 
447 		return( NULL );
448 	}
449 
450 	if( length )
451 		*length = target->memory_buffer->len;
452 	data = g_byte_array_free( target->memory_buffer, FALSE );
453 	target->memory_buffer = NULL;
454 
455 	/* We must have a valid byte array or finish will fail.
456 	 */
457 	target->memory_buffer = g_byte_array_new();
458 
459 	vips_target_finish( target );
460 
461 	return( data );
462 }
463 
464 /**
465  * vips_target_steal_text:
466  * @target: target to operate on
467  *
468  * As vips_target_steal_text(), but return a null-terminated string.
469  *
470  * Returns: (transfer full): target contents as a null-terminated string.
471  */
472 char *
vips_target_steal_text(VipsTarget * target)473 vips_target_steal_text( VipsTarget *target )
474 {
475 	vips_target_putc( target, '\0' );
476 
477 	return( (char *) vips_target_steal( target, NULL ) );
478 }
479 
480 /**
481  * vips_target_putc:
482  * @target: target to operate on
483  * @ch: character to write
484  *
485  * Write a single character @ch to @target. See the macro VIPS_TARGET_PUTC()
486  * for a faster way to do this.
487  *
488  * Returns: 0 on success, -1 on error.
489  */
490 int
vips_target_putc(VipsTarget * target,int ch)491 vips_target_putc( VipsTarget *target, int ch )
492 {
493 	VIPS_DEBUG_MSG( "vips_target_putc: %d\n", ch );
494 
495 	if( target->write_point >= VIPS_TARGET_BUFFER_SIZE &&
496 		vips_target_flush( target ) )
497 		return( -1 );
498 
499 	target->output_buffer[target->write_point++] = ch;
500 
501 	return( 0 );
502 }
503 
504 /**
505  * vips_target_writes:
506  * @target: target to operate on
507  * @str: string to write
508  *
509  * Write a null-terminated string to @target.
510  *
511  * Returns: 0 on success, and -1 on error.
512  */
513 int
vips_target_writes(VipsTarget * target,const char * str)514 vips_target_writes( VipsTarget *target, const char *str )
515 {
516 	return( vips_target_write( target,
517 		(unsigned char *) str, strlen( str ) ) );
518 }
519 
520 /**
521  * vips_target_writef:
522  * @target: target to operate on
523  * @fmt: <function>printf()</function>-style format string
524  * @...: arguments to format string
525  *
526  * Format the string and write to @target.
527  *
528  * Returns: 0 on success, and -1 on error.
529  */
530 int
vips_target_writef(VipsTarget * target,const char * fmt,...)531 vips_target_writef( VipsTarget *target, const char *fmt, ... )
532 {
533 	va_list ap;
534 	char *line;
535 	int result;
536 
537         va_start( ap, fmt );
538 	line = g_strdup_vprintf( fmt, ap );
539         va_end( ap );
540 
541 	result = vips_target_writes( target, line );
542 
543 	g_free( line );
544 
545 	return( result );
546 }
547 
548 /**
549  * vips_target_write_amp:
550  * @target: target to operate on
551  * @str: string to write
552  *
553  * Write @str to @target, but escape stuff that xml hates in text. Our
554  * argument string is utf-8.
555  *
556  * XML rules:
557  *
558  * - We must escape &<>
559  * - Don't escape \n, \t, \r
560  * - Do escape the other ASCII codes.
561  *
562  * Returns: 0 on success, -1 on error.
563  */
564 int
vips_target_write_amp(VipsTarget * target,const char * str)565 vips_target_write_amp( VipsTarget *target, const char *str )
566 {
567 	const char *p;
568 
569 	for( p = str; *p; p++ )
570 		if( *p < 32 &&
571 			*p != '\n' &&
572 			*p != '\t' &&
573 			*p != '\r' ) {
574 			/* You'd think we could output "&#x02%x;", but xml
575 			 * 1.0 parsers barf on that. xml 1.1 allows this, but
576 			 * there are almost no parsers.
577 			 *
578 			 * U+2400 onwards are unicode glyphs for the ASCII
579 			 * control characters, so we can use them -- thanks
580 			 * electroly.
581 			 */
582 			if( vips_target_writef( target,
583 				"&#x%04x;", 0x2400 + *p ) )
584 				return( -1 );
585 		}
586 		else if( *p == '<' ) {
587 			if( vips_target_writes( target, "&lt;" ) )
588 				return( -1 );
589 		}
590 		else if( *p == '>' ) {
591 			if( vips_target_writes( target, "&gt;" ) )
592 				return( -1 );
593 		}
594 		else if( *p == '&' ) {
595 			if( vips_target_writes( target, "&amp;" ) )
596 				return( -1 );
597 		}
598 		else  {
599 			if( VIPS_TARGET_PUTC( target, *p ) )
600 				return( -1 );
601 		}
602 
603 	return( 0 );
604 }
605 
606