2 * stream.c: svn_stream operations
4 * ====================================================================
5 * Copyright (c) 2000-2004, 2006 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 //#include "svn_private_config.h"
25 #include <apr_pools.h>
26 #include <apr_strings.h>
27 #include <apr_file_io.h>
28 #include <apr_errno.h>
33 #include "svn_pools.h"
35 #include "svn_error.h"
36 #include "svn_string.h"
38 #include "svn_checksum.h"
44 svn_read_fn_t read_fn
;
45 svn_write_fn_t write_fn
;
46 svn_close_fn_t close_fn
;
51 /*** Generic streams. ***/
54 svn_stream_create(void *baton
, apr_pool_t
*pool
)
58 stream
= apr_palloc(pool
, sizeof(*stream
));
59 stream
->baton
= baton
;
60 stream
->read_fn
= NULL
;
61 stream
->write_fn
= NULL
;
62 stream
->close_fn
= NULL
;
68 svn_stream_set_baton(svn_stream_t
*stream
, void *baton
)
70 stream
->baton
= baton
;
75 svn_stream_set_read(svn_stream_t
*stream
, svn_read_fn_t read_fn
)
77 stream
->read_fn
= read_fn
;
82 svn_stream_set_write(svn_stream_t
*stream
, svn_write_fn_t write_fn
)
84 stream
->write_fn
= write_fn
;
89 svn_stream_set_close(svn_stream_t
*stream
, svn_close_fn_t close_fn
)
91 stream
->close_fn
= close_fn
;
96 svn_stream_read(svn_stream_t
*stream
, char *buffer
, apr_size_t
*len
)
98 SVN_ERR_ASSERT(stream
->read_fn
!= NULL
);
99 return stream
->read_fn(stream
->baton
, buffer
, len
);
104 svn_stream_write(svn_stream_t
*stream
, const char *data
, apr_size_t
*len
)
106 SVN_ERR_ASSERT(stream
->write_fn
!= NULL
);
107 return stream
->write_fn(stream
->baton
, data
, len
);
112 svn_stream_close(svn_stream_t
*stream
)
114 if (stream
->close_fn
== NULL
)
116 return stream
->close_fn(stream
->baton
);
121 svn_stream_printf(svn_stream_t
*stream
,
131 message
= apr_pvsprintf(pool
, fmt
, ap
);
134 len
= strlen(message
);
135 return svn_stream_write(stream
, message
, &len
);
140 svn_stream_printf_from_utf8(svn_stream_t
*stream
,
141 const char *encoding
,
146 const char *message
, *translated
;
151 message
= apr_pvsprintf(pool
, fmt
, ap
);
154 SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated
, message
, encoding
,
157 len
= strlen(translated
);
159 return svn_stream_write(stream
, translated
, &len
);
164 svn_stream_readline(svn_stream_t
*stream
,
165 svn_stringbuf_t
**stringbuf
,
173 /* Since we're reading one character at a time, let's at least
174 optimize for the 90% case. 90% of the time, we can avoid the
175 stringbuf ever having to realloc() itself if we start it out at
177 svn_stringbuf_t
*str
= svn_stringbuf_create_ensure(80, pool
);
183 SVN_ERR(svn_stream_read(stream
, &c
, &numbytes
));
186 /* a 'short' read means the stream has run out. */
197 svn_stringbuf_appendbytes(str
, &c
, 1);
201 svn_stringbuf_chop(str
, match
- eol
);
207 svn_error_t
*svn_stream_copy3(svn_stream_t
*from
, svn_stream_t
*to
,
208 svn_cancel_func_t cancel_func
,
210 apr_pool_t
*scratch_pool
)
212 char *buf
= apr_palloc(scratch_pool
, SVN__STREAM_CHUNK_SIZE
);
216 /* Read and write chunks until we get a short read, indicating the
217 end of the stream. (We can't get a short write without an
218 associated error.) */
221 apr_size_t len
= SVN__STREAM_CHUNK_SIZE
;
224 SVN_ERR(cancel_func(cancel_baton
));
226 SVN_ERR(svn_stream_read(from
, buf
, &len
));
228 SVN_ERR(svn_stream_write(to
, buf
, &len
));
229 if (len
!= SVN__STREAM_CHUNK_SIZE
)
233 err
= svn_stream_close(from
);
234 err2
= svn_stream_close(to
);
237 /* ### it would be nice to compose the two errors in some way */
238 svn_error_clear(err2
); /* note: might be NULL */
244 svn_error_t
*svn_stream_copy2(svn_stream_t
*from
, svn_stream_t
*to
,
245 svn_cancel_func_t cancel_func
,
247 apr_pool_t
*scratch_pool
)
249 return svn_stream_copy3(svn_stream_disown(from
, scratch_pool
),
250 svn_stream_disown(to
, scratch_pool
),
251 cancel_func
, cancel_baton
, scratch_pool
);
254 svn_error_t
*svn_stream_copy(svn_stream_t
*from
, svn_stream_t
*to
,
255 apr_pool_t
*scratch_pool
)
257 return svn_stream_copy3(svn_stream_disown(from
, scratch_pool
),
258 svn_stream_disown(to
, scratch_pool
),
259 NULL
, NULL
, scratch_pool
);
264 svn_stream_contents_same(svn_boolean_t
*same
,
265 svn_stream_t
*stream1
,
266 svn_stream_t
*stream2
,
269 char *buf1
= apr_palloc(pool
, SVN__STREAM_CHUNK_SIZE
);
270 char *buf2
= apr_palloc(pool
, SVN__STREAM_CHUNK_SIZE
);
271 apr_size_t bytes_read1
= SVN__STREAM_CHUNK_SIZE
;
272 apr_size_t bytes_read2
= SVN__STREAM_CHUNK_SIZE
;
274 *same
= TRUE
; /* assume TRUE, until disproved below */
275 while (bytes_read1
== SVN__STREAM_CHUNK_SIZE
276 && bytes_read2
== SVN__STREAM_CHUNK_SIZE
)
278 SVN_ERR(svn_stream_read(stream1
, buf1
, &bytes_read1
));
279 SVN_ERR(svn_stream_read(stream2
, buf2
, &bytes_read2
));
281 if ((bytes_read1
!= bytes_read2
)
282 || (memcmp(buf1
, buf2
, bytes_read1
)))
294 /*** Generic readable empty stream ***/
297 read_handler_empty(void *baton
, char *buffer
, apr_size_t
*len
)
305 write_handler_empty(void *baton
, const char *data
, apr_size_t
*len
)
312 svn_stream_empty(apr_pool_t
*pool
)
314 svn_stream_t
*stream
;
316 stream
= svn_stream_create(NULL
, pool
);
317 svn_stream_set_read(stream
, read_handler_empty
);
318 svn_stream_set_write(stream
, write_handler_empty
);
325 /*** Ownership detaching stream ***/
328 read_handler_disown(void *baton
, char *buffer
, apr_size_t
*len
)
330 return svn_stream_read((svn_stream_t
*)baton
, buffer
, len
);
334 write_handler_disown(void *baton
, const char *buffer
, apr_size_t
*len
)
336 return svn_stream_write((svn_stream_t
*)baton
, buffer
, len
);
341 svn_stream_disown(svn_stream_t
*stream
, apr_pool_t
*pool
)
343 svn_stream_t
*s
= svn_stream_create(stream
, pool
);
345 svn_stream_set_read(s
, read_handler_disown
);
346 svn_stream_set_write(s
, write_handler_disown
);
353 /*** Generic stream for APR files ***/
361 read_handler_apr(void *baton
, char *buffer
, apr_size_t
*len
)
363 struct baton_apr
*btn
= baton
;
366 err
= svn_io_file_read_full(btn
->file
, buffer
, *len
, len
, btn
->pool
);
367 if (err
&& APR_STATUS_IS_EOF(err
->apr_err
))
369 svn_error_clear(err
);
378 write_handler_apr(void *baton
, const char *data
, apr_size_t
*len
)
380 struct baton_apr
*btn
= baton
;
382 return svn_io_file_write_full(btn
->file
, data
, *len
, len
, btn
->pool
);
386 close_handler_apr(void *baton
)
388 struct baton_apr
*btn
= baton
;
390 return svn_io_file_close(btn
->file
, btn
->pool
);
395 svn_stream_open_readonly(svn_stream_t
**stream
,
397 apr_pool_t
*result_pool
,
398 apr_pool_t
*scratch_pool
)
402 SVN_ERR(svn_io_file_open(&file
, path
, APR_READ
| APR_BUFFERED
| APR_BINARY
,
403 APR_OS_DEFAULT
, result_pool
));
404 *stream
= svn_stream_from_aprfile2(file
, FALSE
, result_pool
);
411 svn_stream_open_writable(svn_stream_t
**stream
,
413 apr_pool_t
*result_pool
,
414 apr_pool_t
*scratch_pool
)
418 SVN_ERR(svn_io_file_open(&file
, path
,
424 APR_OS_DEFAULT
, result_pool
));
425 *stream
= svn_stream_from_aprfile2(file
, FALSE
, result_pool
);
432 svn_stream_open_unique(svn_stream_t
**stream
,
433 const char **temp_path
,
435 svn_io_file_del_t delete_when
,
436 apr_pool_t
*result_pool
,
437 apr_pool_t
*scratch_pool
)
441 SVN_ERR(svn_io_open_unique_file3(&file
, temp_path
, dirpath
,
442 delete_when
, result_pool
, scratch_pool
));
443 *stream
= svn_stream_from_aprfile2(file
, FALSE
, result_pool
);
450 svn_stream_from_aprfile2(apr_file_t
*file
,
451 svn_boolean_t disown
,
454 struct baton_apr
*baton
;
455 svn_stream_t
*stream
;
458 return svn_stream_empty(pool
);
460 baton
= apr_palloc(pool
, sizeof(*baton
));
463 stream
= svn_stream_create(baton
, pool
);
464 svn_stream_set_read(stream
, read_handler_apr
);
465 svn_stream_set_write(stream
, write_handler_apr
);
468 svn_stream_set_close(stream
, close_handler_apr
);
474 svn_stream_from_aprfile(apr_file_t
*file
, apr_pool_t
*pool
)
476 return svn_stream_from_aprfile2(file
, TRUE
, pool
);
481 /* Compressed stream support */
483 #define ZBUFFER_SIZE 4096 /* The size of the buffer the
484 compressed stream uses to read from
485 the substream. Basically an
486 arbitrary value, picked to be about
490 z_stream
*in
; /* compressed stream for reading */
491 z_stream
*out
; /* compressed stream for writing */
492 svn_read_fn_t read
; /* substream's read function */
493 svn_write_fn_t write
; /* substream's write function */
494 svn_close_fn_t close
; /* substream's close function */
495 void *read_buffer
; /* buffer used for reading from
497 int read_flush
; /* what flush mode to use while
499 apr_pool_t
*pool
; /* The pool this baton is allocated
501 void *subbaton
; /* The substream's baton */
504 /* zlib alloc function. opaque is the pool we need. */
506 zalloc(voidpf opaque
, uInt items
, uInt size
)
508 apr_pool_t
*pool
= opaque
;
510 return apr_palloc(pool
, items
* size
);
513 /* zlib free function */
515 zfree(voidpf opaque
, voidpf address
)
517 /* Empty, since we allocate on the pool */
520 /* Converts a zlib error to an svn_error_t. zerr is the error code,
521 function is the function name, and stream is the z_stream we are
524 zerr_to_svn_error(int zerr
, const char *function
, z_stream
*stream
)
535 status
= SVN_ERR_STREAM_MALFORMED_DATA
;
536 message
= "stream error";
541 message
= "out of memory";
546 message
= "buffer error";
549 case Z_VERSION_ERROR
:
550 status
= SVN_ERR_STREAM_UNRECOGNIZED_DATA
;
551 message
= "version error";
555 status
= SVN_ERR_STREAM_MALFORMED_DATA
;
556 message
= "corrupted data";
560 status
= SVN_ERR_STREAM_UNRECOGNIZED_DATA
;
565 if (stream
->msg
!= NULL
)
566 return svn_error_createf(status
, NULL
, "zlib (%s): %s: %s", function
,
567 message
, stream
->msg
);
569 return svn_error_createf(status
, NULL
, "zlib (%s): %s", function
,
573 /* Helper function to figure out the sync mode */
575 read_helper_gz(svn_read_fn_t read_fn
,
578 uInt
*len
, int *zflush
)
580 uInt orig_len
= *len
;
582 /* There's no reason this value should grow bigger than the range of
583 uInt, but Subversion's API requires apr_size_t. */
584 apr_size_t apr_len
= (apr_size_t
) *len
;
586 SVN_ERR((*read_fn
)(baton
, buffer
, &apr_len
));
588 /* Type cast back to uInt type that zlib uses. On LP64 platforms
589 apr_size_t will be bigger than uInt. */
590 *len
= (uInt
) apr_len
;
592 /* I wanted to use Z_FINISH here, but we need to know our buffer is
594 *zflush
= (*len
) < orig_len
? Z_SYNC_FLUSH
: Z_SYNC_FLUSH
;
599 /* Handle reading from a compressed stream */
601 read_handler_gz(void *baton
, char *buffer
, apr_size_t
*len
)
603 struct zbaton
*btn
= baton
;
608 btn
->in
= apr_palloc(btn
->pool
, sizeof(z_stream
));
609 btn
->in
->zalloc
= zalloc
;
610 btn
->in
->zfree
= zfree
;
611 btn
->in
->opaque
= btn
->pool
;
612 btn
->read_buffer
= apr_palloc(btn
->pool
, ZBUFFER_SIZE
);
613 btn
->in
->next_in
= btn
->read_buffer
;
614 btn
->in
->avail_in
= ZBUFFER_SIZE
;
616 SVN_ERR(read_helper_gz(btn
->read
, btn
->subbaton
, btn
->read_buffer
,
617 &btn
->in
->avail_in
, &btn
->read_flush
));
619 zerr
= inflateInit(btn
->in
);
620 SVN_ERR(zerr_to_svn_error(zerr
, "inflateInit", btn
->in
));
623 btn
->in
->next_out
= (Bytef
*) buffer
;
624 btn
->in
->avail_out
= *len
;
626 while (btn
->in
->avail_out
> 0)
628 if (btn
->in
->avail_in
<= 0)
630 btn
->in
->avail_in
= ZBUFFER_SIZE
;
631 btn
->in
->next_in
= btn
->read_buffer
;
632 SVN_ERR(read_helper_gz(btn
->read
, btn
->subbaton
, btn
->read_buffer
,
633 &btn
->in
->avail_in
, &btn
->read_flush
));
636 zerr
= inflate(btn
->in
, btn
->read_flush
);
637 if (zerr
== Z_STREAM_END
)
639 else if (zerr
!= Z_OK
)
640 return zerr_to_svn_error(zerr
, "inflate", btn
->in
);
643 *len
-= btn
->in
->avail_out
;
647 /* Compress data and write it to the substream */
649 write_handler_gz(void *baton
, const char *buffer
, apr_size_t
*len
)
651 struct zbaton
*btn
= baton
;
654 apr_size_t buf_size
, write_len
;
657 if (btn
->out
== NULL
)
659 btn
->out
= apr_palloc(btn
->pool
, sizeof(z_stream
));
660 btn
->out
->zalloc
= zalloc
;
661 btn
->out
->zfree
= zfree
;
662 btn
->out
->opaque
= btn
->pool
;
664 zerr
= deflateInit(btn
->out
, Z_DEFAULT_COMPRESSION
);
665 SVN_ERR(zerr_to_svn_error(zerr
, "deflateInit", btn
->out
));
668 /* The largest buffer we should need is 0.1% larger than the
669 compressed data, + 12 bytes. This info comes from zlib.h. */
670 buf_size
= *len
+ (*len
/ 1000) + 13;
671 subpool
= svn_pool_create(btn
->pool
);
672 write_buf
= apr_palloc(subpool
, buf_size
);
674 btn
->out
->next_in
= (Bytef
*) buffer
; /* Casting away const! */
675 btn
->out
->avail_in
= *len
;
677 while (btn
->out
->avail_in
> 0)
679 btn
->out
->next_out
= write_buf
;
680 btn
->out
->avail_out
= buf_size
;
682 zerr
= deflate(btn
->out
, Z_NO_FLUSH
);
683 SVN_ERR(zerr_to_svn_error(zerr
, "deflate", btn
->out
));
684 write_len
= buf_size
- btn
->out
->avail_out
;
686 SVN_ERR(btn
->write(btn
->subbaton
, write_buf
, &write_len
));
689 svn_pool_destroy(subpool
);
694 /* Handle flushing and closing the stream */
696 close_handler_gz(void *baton
)
698 struct zbaton
*btn
= baton
;
703 zerr
= inflateEnd(btn
->in
);
704 SVN_ERR(zerr_to_svn_error(zerr
, "inflateEnd", btn
->in
));
707 if (btn
->out
!= NULL
)
710 apr_size_t write_len
;
712 buf
= apr_palloc(btn
->pool
, ZBUFFER_SIZE
);
716 btn
->out
->next_out
= buf
;
717 btn
->out
->avail_out
= ZBUFFER_SIZE
;
719 zerr
= deflate(btn
->out
, Z_FINISH
);
720 if (zerr
!= Z_STREAM_END
&& zerr
!= Z_OK
)
721 return zerr_to_svn_error(zerr
, "deflate", btn
->out
);
722 write_len
= ZBUFFER_SIZE
- btn
->out
->avail_out
;
724 SVN_ERR(btn
->write(btn
->subbaton
, buf
, &write_len
));
725 if (zerr
== Z_STREAM_END
)
729 zerr
= deflateEnd(btn
->out
);
730 SVN_ERR(zerr_to_svn_error(zerr
, "deflateEnd", btn
->out
));
733 if (btn
->close
!= NULL
)
734 return btn
->close(btn
->subbaton
);
741 svn_stream_compressed(svn_stream_t
*stream
, apr_pool_t
*pool
)
743 struct svn_stream_t
*zstream
;
744 struct zbaton
*baton
;
746 assert(stream
!= NULL
);
748 baton
= apr_palloc(pool
, sizeof(*baton
));
749 baton
->in
= baton
->out
= NULL
;
750 baton
->read
= stream
->read_fn
;
751 baton
->write
= stream
->write_fn
;
752 baton
->close
= stream
->close_fn
;
753 baton
->subbaton
= stream
->baton
;
755 baton
->read_buffer
= NULL
;
756 baton
->read_flush
= Z_SYNC_FLUSH
;
758 zstream
= svn_stream_create(baton
, pool
);
759 svn_stream_set_read(zstream
, read_handler_gz
);
760 svn_stream_set_write(zstream
, write_handler_gz
);
761 svn_stream_set_close(zstream
, close_handler_gz
);
767 /* Checksummed stream support */
769 struct checksum_stream_baton
771 svn_checksum_ctx_t
*read_ctx
, *write_ctx
;
772 svn_checksum_t
**read_checksum
; /* Output value. */
773 svn_checksum_t
**write_checksum
; /* Output value. */
776 /* True if more data should be read when closing the stream. */
777 svn_boolean_t read_more
;
779 /* Pool to allocate read buffer and output values from. */
784 read_handler_checksum(void *baton
, char *buffer
, apr_size_t
*len
)
786 struct checksum_stream_baton
*btn
= baton
;
787 apr_size_t saved_len
= *len
;
789 SVN_ERR(svn_stream_read(btn
->proxy
, buffer
, len
));
791 if (btn
->read_checksum
)
792 SVN_ERR(svn_checksum_update(btn
->read_ctx
, buffer
, *len
));
794 if (saved_len
!= *len
)
795 btn
->read_more
= FALSE
;
802 write_handler_checksum(void *baton
, const char *buffer
, apr_size_t
*len
)
804 struct checksum_stream_baton
*btn
= baton
;
806 if (btn
->write_checksum
&& *len
> 0)
807 SVN_ERR(svn_checksum_update(btn
->write_ctx
, buffer
, *len
));
809 return svn_stream_write(btn
->proxy
, buffer
, len
);
814 close_handler_checksum(void *baton
)
816 struct checksum_stream_baton
*btn
= baton
;
818 /* If we're supposed to drain the stream, do so before finalizing the
822 char *buf
= apr_palloc(btn
->pool
, SVN__STREAM_CHUNK_SIZE
);
823 apr_size_t len
= SVN__STREAM_CHUNK_SIZE
;
827 SVN_ERR(read_handler_checksum(baton
, buf
, &len
));
829 while (btn
->read_more
);
833 SVN_ERR(svn_checksum_final(btn
->read_checksum
, btn
->read_ctx
, btn
->pool
));
836 SVN_ERR(svn_checksum_final(btn
->write_checksum
, btn
->write_ctx
, btn
->pool
));
838 return svn_stream_close(btn
->proxy
);
843 svn_stream_checksummed2(svn_stream_t
*stream
,
844 svn_checksum_t
**read_checksum
,
845 svn_checksum_t
**write_checksum
,
846 svn_checksum_kind_t checksum_kind
,
847 svn_boolean_t read_all
,
851 struct checksum_stream_baton
*baton
;
853 if (read_checksum
== NULL
&& write_checksum
== NULL
)
856 baton
= apr_palloc(pool
, sizeof(*baton
));
858 baton
->read_ctx
= svn_checksum_ctx_create(checksum_kind
, pool
);
860 baton
->read_ctx
= NULL
;
863 baton
->write_ctx
= svn_checksum_ctx_create(checksum_kind
, pool
);
865 baton
->write_ctx
= NULL
;
867 baton
->read_checksum
= read_checksum
;
868 baton
->write_checksum
= write_checksum
;
869 baton
->proxy
= stream
;
870 baton
->read_more
= read_all
;
873 s
= svn_stream_create(baton
, pool
);
874 svn_stream_set_read(s
, read_handler_checksum
);
875 svn_stream_set_write(s
, write_handler_checksum
);
876 svn_stream_set_close(s
, close_handler_checksum
);
880 struct md5_stream_baton
882 const unsigned char **read_digest
;
883 const unsigned char **write_digest
;
884 svn_checksum_t
*read_checksum
;
885 svn_checksum_t
*write_checksum
;
891 read_handler_md5(void *baton
, char *buffer
, apr_size_t
*len
)
893 struct md5_stream_baton
*btn
= baton
;
894 return svn_stream_read(btn
->proxy
, buffer
, len
);
898 write_handler_md5(void *baton
, const char *buffer
, apr_size_t
*len
)
900 struct md5_stream_baton
*btn
= baton
;
901 return svn_stream_write(btn
->proxy
, buffer
, len
);
905 close_handler_md5(void *baton
)
907 struct md5_stream_baton
*btn
= baton
;
909 SVN_ERR(svn_stream_close(btn
->proxy
));
911 if (btn
->read_digest
)
913 = apr_pmemdup(btn
->pool
, btn
->read_checksum
->digest
,
916 if (btn
->write_digest
)
918 = apr_pmemdup(btn
->pool
, btn
->write_checksum
->digest
,
926 svn_stream_checksummed(svn_stream_t
*stream
,
927 const unsigned char **read_digest
,
928 const unsigned char **write_digest
,
929 svn_boolean_t read_all
,
933 struct md5_stream_baton
*baton
;
935 if (! read_digest
&& ! write_digest
)
938 baton
= apr_palloc(pool
, sizeof(*baton
));
939 baton
->read_digest
= read_digest
;
940 baton
->write_digest
= write_digest
;
943 /* Set BATON->proxy to a stream that will fill in BATON->read_checksum
944 * and BATON->write_checksum (if we want them) when it is closed. */
946 = svn_stream_checksummed2(stream
,
947 read_digest
? &baton
->read_checksum
: NULL
,
948 write_digest
? &baton
->write_checksum
: NULL
,
952 /* Create a stream that will forward its read/write/close operations to
953 * BATON->proxy and will fill in *READ_DIGEST and *WRITE_DIGEST (if we
954 * want them) after it closes BATON->proxy. */
955 s
= svn_stream_create(baton
, pool
);
956 svn_stream_set_read(s
, read_handler_md5
);
957 svn_stream_set_write(s
, write_handler_md5
);
958 svn_stream_set_close(s
, close_handler_md5
);
965 /* Miscellaneous stream functions. */
966 struct stringbuf_stream_baton
968 svn_stringbuf_t
*str
;
973 read_handler_stringbuf(void *baton
, char *buffer
, apr_size_t
*len
)
975 struct stringbuf_stream_baton
*btn
= baton
;
976 apr_size_t left_to_read
= btn
->str
->len
- btn
->amt_read
;
978 *len
= (*len
> left_to_read
) ? left_to_read
: *len
;
979 memcpy(buffer
, btn
->str
->data
+ btn
->amt_read
, *len
);
980 btn
->amt_read
+= *len
;
985 write_handler_stringbuf(void *baton
, const char *data
, apr_size_t
*len
)
987 struct stringbuf_stream_baton
*btn
= baton
;
989 svn_stringbuf_appendbytes(btn
->str
, data
, *len
);
994 svn_stream_from_stringbuf(svn_stringbuf_t
*str
,
997 svn_stream_t
*stream
;
998 struct stringbuf_stream_baton
*baton
;
1001 return svn_stream_empty(pool
);
1003 baton
= apr_palloc(pool
, sizeof(*baton
));
1005 baton
->amt_read
= 0;
1006 stream
= svn_stream_create(baton
, pool
);
1007 svn_stream_set_read(stream
, read_handler_stringbuf
);
1008 svn_stream_set_write(stream
, write_handler_stringbuf
);
1012 struct string_stream_baton
1014 const svn_string_t
*str
;
1015 apr_size_t amt_read
;
1018 static svn_error_t
*
1019 read_handler_string(void *baton
, char *buffer
, apr_size_t
*len
)
1021 struct string_stream_baton
*btn
= baton
;
1022 apr_size_t left_to_read
= btn
->str
->len
- btn
->amt_read
;
1024 *len
= (*len
> left_to_read
) ? left_to_read
: *len
;
1025 memcpy(buffer
, btn
->str
->data
+ btn
->amt_read
, *len
);
1026 btn
->amt_read
+= *len
;
1027 return SVN_NO_ERROR
;
1031 svn_stream_from_string(const svn_string_t
*str
,
1034 svn_stream_t
*stream
;
1035 struct string_stream_baton
*baton
;
1038 return svn_stream_empty(pool
);
1040 baton
= apr_palloc(pool
, sizeof(*baton
));
1042 baton
->amt_read
= 0;
1043 stream
= svn_stream_create(baton
, pool
);
1044 svn_stream_set_read(stream
, read_handler_string
);
1050 svn_stream_for_stdout(svn_stream_t
**out
, apr_pool_t
*pool
)
1052 apr_file_t
*stdout_file
;
1053 apr_status_t apr_err
;
1055 apr_err
= apr_file_open_stdout(&stdout_file
, pool
);
1057 return svn_error_wrap_apr(apr_err
, "Can't open stdout");
1059 *out
= svn_stream_from_aprfile2(stdout_file
, TRUE
, pool
);
1061 return SVN_NO_ERROR
;
1066 svn_string_from_stream(svn_string_t
**result
,
1067 svn_stream_t
*stream
,
1068 apr_pool_t
*result_pool
,
1069 apr_pool_t
*scratch_pool
)
1071 svn_stringbuf_t
*work
= svn_stringbuf_create_ensure(SVN__STREAM_CHUNK_SIZE
,
1073 char *buffer
= apr_palloc(scratch_pool
, SVN__STREAM_CHUNK_SIZE
);
1077 apr_size_t len
= SVN__STREAM_CHUNK_SIZE
;
1079 SVN_ERR(svn_stream_read(stream
, buffer
, &len
));
1080 svn_stringbuf_appendbytes(work
, buffer
, len
);
1082 if (len
< SVN__STREAM_CHUNK_SIZE
)
1086 SVN_ERR(svn_stream_close(stream
));
1088 *result
= apr_palloc(result_pool
, sizeof(**result
));
1089 (*result
)->data
= work
->data
;
1090 (*result
)->len
= work
->len
;
1092 return SVN_NO_ERROR
;