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 "%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, "<" ) )
588 return( -1 );
589 }
590 else if( *p == '>' ) {
591 if( vips_target_writes( target, ">" ) )
592 return( -1 );
593 }
594 else if( *p == '&' ) {
595 if( vips_target_writes( target, "&" ) )
596 return( -1 );
597 }
598 else {
599 if( VIPS_TARGET_PUTC( target, *p ) )
600 return( -1 );
601 }
602
603 return( 0 );
604 }
605
606