Sync libsvn_diff from subversion r876937
[TortoiseGit.git] / src / TortoiseMerge / libsvn_diff / stream.c
blob3c1967eb6716a05c2f0b71da76c19b510136dc8b
1 /*
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"
21 #include <assert.h>
22 #include <stdio.h>
24 #include <apr.h>
25 #include <apr_pools.h>
26 #include <apr_strings.h>
27 #include <apr_file_io.h>
28 #include <apr_errno.h>
29 #include <apr_md5.h>
31 #include <zlib.h>
33 #include "svn_pools.h"
34 #include "svn_io.h"
35 #include "svn_error.h"
36 #include "svn_string.h"
37 #include "svn_utf.h"
38 #include "svn_checksum.h"
39 #include "svn_path.h"
42 struct svn_stream_t {
43 void *baton;
44 svn_read_fn_t read_fn;
45 svn_write_fn_t write_fn;
46 svn_close_fn_t close_fn;
51 /*** Generic streams. ***/
53 svn_stream_t *
54 svn_stream_create(void *baton, apr_pool_t *pool)
56 svn_stream_t *stream;
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;
63 return stream;
67 void
68 svn_stream_set_baton(svn_stream_t *stream, void *baton)
70 stream->baton = baton;
74 void
75 svn_stream_set_read(svn_stream_t *stream, svn_read_fn_t read_fn)
77 stream->read_fn = read_fn;
81 void
82 svn_stream_set_write(svn_stream_t *stream, svn_write_fn_t write_fn)
84 stream->write_fn = write_fn;
88 void
89 svn_stream_set_close(svn_stream_t *stream, svn_close_fn_t close_fn)
91 stream->close_fn = close_fn;
95 svn_error_t *
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);
103 svn_error_t *
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);
111 svn_error_t *
112 svn_stream_close(svn_stream_t *stream)
114 if (stream->close_fn == NULL)
115 return SVN_NO_ERROR;
116 return stream->close_fn(stream->baton);
120 svn_error_t *
121 svn_stream_printf(svn_stream_t *stream,
122 apr_pool_t *pool,
123 const char *fmt,
124 ...)
126 const char *message;
127 va_list ap;
128 apr_size_t len;
130 va_start(ap, fmt);
131 message = apr_pvsprintf(pool, fmt, ap);
132 va_end(ap);
134 len = strlen(message);
135 return svn_stream_write(stream, message, &len);
139 svn_error_t *
140 svn_stream_printf_from_utf8(svn_stream_t *stream,
141 const char *encoding,
142 apr_pool_t *pool,
143 const char *fmt,
144 ...)
146 const char *message, *translated;
147 va_list ap;
148 apr_size_t len;
150 va_start(ap, fmt);
151 message = apr_pvsprintf(pool, fmt, ap);
152 va_end(ap);
154 SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding,
155 pool));
157 len = strlen(translated);
159 return svn_stream_write(stream, translated, &len);
163 svn_error_t *
164 svn_stream_readline(svn_stream_t *stream,
165 svn_stringbuf_t **stringbuf,
166 const char *eol,
167 svn_boolean_t *eof,
168 apr_pool_t *pool)
170 apr_size_t numbytes;
171 const char *match;
172 char c;
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
176 80 chars. */
177 svn_stringbuf_t *str = svn_stringbuf_create_ensure(80, pool);
179 match = eol;
180 while (*match)
182 numbytes = 1;
183 SVN_ERR(svn_stream_read(stream, &c, &numbytes));
184 if (numbytes != 1)
186 /* a 'short' read means the stream has run out. */
187 *eof = TRUE;
188 *stringbuf = str;
189 return SVN_NO_ERROR;
192 if (c == *match)
193 match++;
194 else
195 match = eol;
197 svn_stringbuf_appendbytes(str, &c, 1);
200 *eof = FALSE;
201 svn_stringbuf_chop(str, match - eol);
202 *stringbuf = str;
203 return SVN_NO_ERROR;
207 svn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to,
208 svn_cancel_func_t cancel_func,
209 void *cancel_baton,
210 apr_pool_t *scratch_pool)
212 char *buf = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE);
213 svn_error_t *err;
214 svn_error_t *err2;
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.) */
219 while (1)
221 apr_size_t len = SVN__STREAM_CHUNK_SIZE;
223 if (cancel_func)
224 SVN_ERR(cancel_func(cancel_baton));
226 SVN_ERR(svn_stream_read(from, buf, &len));
227 if (len > 0)
228 SVN_ERR(svn_stream_write(to, buf, &len));
229 if (len != SVN__STREAM_CHUNK_SIZE)
230 break;
233 err = svn_stream_close(from);
234 err2 = svn_stream_close(to);
235 if (err)
237 /* ### it would be nice to compose the two errors in some way */
238 svn_error_clear(err2); /* note: might be NULL */
239 return err;
241 return err2;
244 svn_error_t *svn_stream_copy2(svn_stream_t *from, svn_stream_t *to,
245 svn_cancel_func_t cancel_func,
246 void *cancel_baton,
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);
263 svn_error_t *
264 svn_stream_contents_same(svn_boolean_t *same,
265 svn_stream_t *stream1,
266 svn_stream_t *stream2,
267 apr_pool_t *pool)
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)))
284 *same = FALSE;
285 break;
289 return SVN_NO_ERROR;
294 /*** Generic readable empty stream ***/
296 static svn_error_t *
297 read_handler_empty(void *baton, char *buffer, apr_size_t *len)
299 *len = 0;
300 return SVN_NO_ERROR;
304 static svn_error_t *
305 write_handler_empty(void *baton, const char *data, apr_size_t *len)
307 return SVN_NO_ERROR;
311 svn_stream_t *
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);
319 return stream;
325 /*** Ownership detaching stream ***/
327 static svn_error_t *
328 read_handler_disown(void *baton, char *buffer, apr_size_t *len)
330 return svn_stream_read((svn_stream_t *)baton, buffer, len);
333 static svn_error_t *
334 write_handler_disown(void *baton, const char *buffer, apr_size_t *len)
336 return svn_stream_write((svn_stream_t *)baton, buffer, len);
340 svn_stream_t *
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);
348 return s;
353 /*** Generic stream for APR files ***/
354 struct baton_apr {
355 apr_file_t *file;
356 apr_pool_t *pool;
360 static svn_error_t *
361 read_handler_apr(void *baton, char *buffer, apr_size_t *len)
363 struct baton_apr *btn = baton;
364 svn_error_t *err;
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);
370 err = SVN_NO_ERROR;
373 return err;
377 static svn_error_t *
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);
385 static svn_error_t *
386 close_handler_apr(void *baton)
388 struct baton_apr *btn = baton;
390 return svn_io_file_close(btn->file, btn->pool);
394 svn_error_t *
395 svn_stream_open_readonly(svn_stream_t **stream,
396 const char *path,
397 apr_pool_t *result_pool,
398 apr_pool_t *scratch_pool)
400 apr_file_t *file;
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);
406 return SVN_NO_ERROR;
410 svn_error_t *
411 svn_stream_open_writable(svn_stream_t **stream,
412 const char *path,
413 apr_pool_t *result_pool,
414 apr_pool_t *scratch_pool)
416 apr_file_t *file;
418 SVN_ERR(svn_io_file_open(&file, path,
419 APR_WRITE
420 | APR_BUFFERED
421 | APR_BINARY
422 | APR_CREATE
423 | APR_EXCL,
424 APR_OS_DEFAULT, result_pool));
425 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
427 return SVN_NO_ERROR;
431 svn_error_t *
432 svn_stream_open_unique(svn_stream_t **stream,
433 const char **temp_path,
434 const char *dirpath,
435 svn_io_file_del_t delete_when,
436 apr_pool_t *result_pool,
437 apr_pool_t *scratch_pool)
439 apr_file_t *file;
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);
445 return SVN_NO_ERROR;
449 svn_stream_t *
450 svn_stream_from_aprfile2(apr_file_t *file,
451 svn_boolean_t disown,
452 apr_pool_t *pool)
454 struct baton_apr *baton;
455 svn_stream_t *stream;
457 if (file == NULL)
458 return svn_stream_empty(pool);
460 baton = apr_palloc(pool, sizeof(*baton));
461 baton->file = file;
462 baton->pool = pool;
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);
467 if (! disown)
468 svn_stream_set_close(stream, close_handler_apr);
470 return stream;
473 svn_stream_t *
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
487 page-sized. */
489 struct zbaton {
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
496 substream */
497 int read_flush; /* what flush mode to use while
498 reading */
499 apr_pool_t *pool; /* The pool this baton is allocated
500 on */
501 void *subbaton; /* The substream's baton */
504 /* zlib alloc function. opaque is the pool we need. */
505 static voidpf
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 */
514 static void
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
522 using. */
523 static svn_error_t *
524 zerr_to_svn_error(int zerr, const char *function, z_stream *stream)
526 apr_status_t status;
527 const char *message;
529 if (zerr == Z_OK)
530 return SVN_NO_ERROR;
532 switch (zerr)
534 case Z_STREAM_ERROR:
535 status = SVN_ERR_STREAM_MALFORMED_DATA;
536 message = "stream error";
537 break;
539 case Z_MEM_ERROR:
540 status = APR_ENOMEM;
541 message = "out of memory";
542 break;
544 case Z_BUF_ERROR:
545 status = APR_ENOMEM;
546 message = "buffer error";
547 break;
549 case Z_VERSION_ERROR:
550 status = SVN_ERR_STREAM_UNRECOGNIZED_DATA;
551 message = "version error";
552 break;
554 case Z_DATA_ERROR:
555 status = SVN_ERR_STREAM_MALFORMED_DATA;
556 message = "corrupted data";
557 break;
559 default:
560 status = SVN_ERR_STREAM_UNRECOGNIZED_DATA;
561 message = "error";
562 break;
565 if (stream->msg != NULL)
566 return svn_error_createf(status, NULL, "zlib (%s): %s: %s", function,
567 message, stream->msg);
568 else
569 return svn_error_createf(status, NULL, "zlib (%s): %s", function,
570 message);
573 /* Helper function to figure out the sync mode */
574 static svn_error_t *
575 read_helper_gz(svn_read_fn_t read_fn,
576 void *baton,
577 char *buffer,
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
593 big enough */
594 *zflush = (*len) < orig_len ? Z_SYNC_FLUSH : Z_SYNC_FLUSH;
596 return SVN_NO_ERROR;
599 /* Handle reading from a compressed stream */
600 static svn_error_t *
601 read_handler_gz(void *baton, char *buffer, apr_size_t *len)
603 struct zbaton *btn = baton;
604 int zerr;
606 if (btn->in == NULL)
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)
638 break;
639 else if (zerr != Z_OK)
640 return zerr_to_svn_error(zerr, "inflate", btn->in);
643 *len -= btn->in->avail_out;
644 return SVN_NO_ERROR;
647 /* Compress data and write it to the substream */
648 static svn_error_t *
649 write_handler_gz(void *baton, const char *buffer, apr_size_t *len)
651 struct zbaton *btn = baton;
652 apr_pool_t *subpool;
653 void *write_buf;
654 apr_size_t buf_size, write_len;
655 int zerr;
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;
685 if (write_len > 0)
686 SVN_ERR(btn->write(btn->subbaton, write_buf, &write_len));
689 svn_pool_destroy(subpool);
691 return SVN_NO_ERROR;
694 /* Handle flushing and closing the stream */
695 static svn_error_t *
696 close_handler_gz(void *baton)
698 struct zbaton *btn = baton;
699 int zerr;
701 if (btn->in != NULL)
703 zerr = inflateEnd(btn->in);
704 SVN_ERR(zerr_to_svn_error(zerr, "inflateEnd", btn->in));
707 if (btn->out != NULL)
709 void *buf;
710 apr_size_t write_len;
712 buf = apr_palloc(btn->pool, ZBUFFER_SIZE);
714 while (TRUE)
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;
723 if (write_len > 0)
724 SVN_ERR(btn->write(btn->subbaton, buf, &write_len));
725 if (zerr == Z_STREAM_END)
726 break;
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);
735 else
736 return SVN_NO_ERROR;
740 svn_stream_t *
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;
754 baton->pool = pool;
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);
763 return zstream;
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. */
774 svn_stream_t *proxy;
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. */
780 apr_pool_t *pool;
783 static svn_error_t *
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;
797 return SVN_NO_ERROR;
801 static svn_error_t *
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);
813 static svn_error_t *
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
819 checksum. */
820 if (btn->read_more)
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);
832 if (btn->read_ctx)
833 SVN_ERR(svn_checksum_final(btn->read_checksum, btn->read_ctx, btn->pool));
835 if (btn->write_ctx)
836 SVN_ERR(svn_checksum_final(btn->write_checksum, btn->write_ctx, btn->pool));
838 return svn_stream_close(btn->proxy);
842 svn_stream_t *
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,
848 apr_pool_t *pool)
850 svn_stream_t *s;
851 struct checksum_stream_baton *baton;
853 if (read_checksum == NULL && write_checksum == NULL)
854 return stream;
856 baton = apr_palloc(pool, sizeof(*baton));
857 if (read_checksum)
858 baton->read_ctx = svn_checksum_ctx_create(checksum_kind, pool);
859 else
860 baton->read_ctx = NULL;
862 if (write_checksum)
863 baton->write_ctx = svn_checksum_ctx_create(checksum_kind, pool);
864 else
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;
871 baton->pool = pool;
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);
877 return s;
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;
886 svn_stream_t *proxy;
887 apr_pool_t *pool;
890 static svn_error_t *
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);
897 static svn_error_t *
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);
904 static svn_error_t *
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)
912 *btn->read_digest
913 = apr_pmemdup(btn->pool, btn->read_checksum->digest,
914 APR_MD5_DIGESTSIZE);
916 if (btn->write_digest)
917 *btn->write_digest
918 = apr_pmemdup(btn->pool, btn->write_checksum->digest,
919 APR_MD5_DIGESTSIZE);
921 return SVN_NO_ERROR;
925 svn_stream_t *
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,
930 apr_pool_t *pool)
932 svn_stream_t *s;
933 struct md5_stream_baton *baton;
935 if (! read_digest && ! write_digest)
936 return stream;
938 baton = apr_palloc(pool, sizeof(*baton));
939 baton->read_digest = read_digest;
940 baton->write_digest = write_digest;
941 baton->pool = pool;
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. */
945 baton->proxy
946 = svn_stream_checksummed2(stream,
947 read_digest ? &baton->read_checksum : NULL,
948 write_digest ? &baton->write_checksum : NULL,
949 svn_checksum_md5,
950 read_all, pool);
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);
959 return s;
965 /* Miscellaneous stream functions. */
966 struct stringbuf_stream_baton
968 svn_stringbuf_t *str;
969 apr_size_t amt_read;
972 static svn_error_t *
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;
981 return SVN_NO_ERROR;
984 static svn_error_t *
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);
990 return SVN_NO_ERROR;
993 svn_stream_t *
994 svn_stream_from_stringbuf(svn_stringbuf_t *str,
995 apr_pool_t *pool)
997 svn_stream_t *stream;
998 struct stringbuf_stream_baton *baton;
1000 if (! str)
1001 return svn_stream_empty(pool);
1003 baton = apr_palloc(pool, sizeof(*baton));
1004 baton->str = str;
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);
1009 return stream;
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;
1030 svn_stream_t *
1031 svn_stream_from_string(const svn_string_t *str,
1032 apr_pool_t *pool)
1034 svn_stream_t *stream;
1035 struct string_stream_baton *baton;
1037 if (! str)
1038 return svn_stream_empty(pool);
1040 baton = apr_palloc(pool, sizeof(*baton));
1041 baton->str = str;
1042 baton->amt_read = 0;
1043 stream = svn_stream_create(baton, pool);
1044 svn_stream_set_read(stream, read_handler_string);
1045 return stream;
1049 svn_error_t *
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);
1056 if (apr_err)
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;
1065 svn_error_t *
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,
1072 result_pool);
1073 char *buffer = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE);
1075 while (1)
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)
1083 break;
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;