Sync translations with Transifex
[TortoiseGit.git] / src / TortoiseMerge / libsvn_diff / stream.c
blob70e9e4894138173545050e14c29f2f36293ddf9a
1 /*
2 * stream.c: svn_stream operations
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 * ====================================================================
24 #include <assert.h>
25 #include <stdio.h>
27 #include <apr.h>
28 #include <apr_pools.h>
29 #include <apr_strings.h>
30 #include <apr_file_io.h>
31 #include <apr_errno.h>
32 #include <apr_md5.h>
34 #include <zlib.h>
36 #include "svn_pools.h"
37 #include "svn_io.h"
38 #include "svn_error.h"
39 #include "svn_string.h"
40 #include "svn_utf.h"
41 #include "svn_checksum.h"
42 #include "svn_path.h"
43 #include "svn_private_config.h"
44 #include "private/svn_error_private.h"
45 #include "private/svn_eol_private.h"
46 #include "private/svn_io_private.h"
47 #include "private/svn_subr_private.h"
50 struct svn_stream_t {
51 void *baton;
52 svn_read_fn_t read_fn;
53 svn_stream_skip_fn_t skip_fn;
54 svn_write_fn_t write_fn;
55 svn_close_fn_t close_fn;
56 svn_stream_mark_fn_t mark_fn;
57 svn_stream_seek_fn_t seek_fn;
58 svn_stream__is_buffered_fn_t is_buffered_fn;
62 /*** Forward declarations. ***/
64 static svn_error_t *
65 skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_fn);
68 /*** Generic streams. ***/
70 svn_stream_t *
71 svn_stream_create(void *baton, apr_pool_t *pool)
73 svn_stream_t *stream;
75 stream = apr_palloc(pool, sizeof(*stream));
76 stream->baton = baton;
77 stream->read_fn = NULL;
78 stream->skip_fn = NULL;
79 stream->write_fn = NULL;
80 stream->close_fn = NULL;
81 stream->mark_fn = NULL;
82 stream->seek_fn = NULL;
83 stream->is_buffered_fn = NULL;
84 return stream;
88 void
89 svn_stream_set_baton(svn_stream_t *stream, void *baton)
91 stream->baton = baton;
95 void
96 svn_stream_set_read(svn_stream_t *stream, svn_read_fn_t read_fn)
98 stream->read_fn = read_fn;
101 void
102 svn_stream_set_skip(svn_stream_t *stream, svn_stream_skip_fn_t skip_fn)
104 stream->skip_fn = skip_fn;
107 void
108 svn_stream_set_write(svn_stream_t *stream, svn_write_fn_t write_fn)
110 stream->write_fn = write_fn;
113 void
114 svn_stream_set_close(svn_stream_t *stream, svn_close_fn_t close_fn)
116 stream->close_fn = close_fn;
119 void
120 svn_stream_set_mark(svn_stream_t *stream, svn_stream_mark_fn_t mark_fn)
122 stream->mark_fn = mark_fn;
125 void
126 svn_stream_set_seek(svn_stream_t *stream, svn_stream_seek_fn_t seek_fn)
128 stream->seek_fn = seek_fn;
131 void
132 svn_stream__set_is_buffered(svn_stream_t *stream,
133 svn_stream__is_buffered_fn_t is_buffered_fn)
135 stream->is_buffered_fn = is_buffered_fn;
138 svn_error_t *
139 svn_stream_read(svn_stream_t *stream, char *buffer, apr_size_t *len)
141 SVN_ERR_ASSERT(stream->read_fn != NULL);
142 return svn_error_trace(stream->read_fn(stream->baton, buffer, len));
146 svn_error_t *
147 svn_stream_skip(svn_stream_t *stream, apr_size_t len)
149 if (stream->skip_fn == NULL)
150 return svn_error_trace(
151 skip_default_handler(stream->baton, len, stream->read_fn));
153 return svn_error_trace(stream->skip_fn(stream->baton, len));
157 svn_error_t *
158 svn_stream_write(svn_stream_t *stream, const char *data, apr_size_t *len)
160 SVN_ERR_ASSERT(stream->write_fn != NULL);
161 return svn_error_trace(stream->write_fn(stream->baton, data, len));
165 svn_error_t *
166 svn_stream_reset(svn_stream_t *stream)
168 return svn_error_trace(
169 svn_stream_seek(stream, NULL));
172 svn_boolean_t
173 svn_stream_supports_mark(svn_stream_t *stream)
175 return stream->mark_fn != NULL;
178 svn_error_t *
179 svn_stream_mark(svn_stream_t *stream, svn_stream_mark_t **mark,
180 apr_pool_t *pool)
182 if (stream->mark_fn == NULL)
183 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
185 return svn_error_trace(stream->mark_fn(stream->baton, mark, pool));
188 svn_error_t *
189 svn_stream_seek(svn_stream_t *stream, const svn_stream_mark_t *mark)
191 if (stream->seek_fn == NULL)
192 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
194 return svn_error_trace(stream->seek_fn(stream->baton, mark));
197 svn_boolean_t
198 svn_stream__is_buffered(svn_stream_t *stream)
200 if (stream->is_buffered_fn == NULL)
201 return FALSE;
203 return stream->is_buffered_fn(stream->baton);
206 svn_error_t *
207 svn_stream_close(svn_stream_t *stream)
209 if (stream->close_fn == NULL)
210 return SVN_NO_ERROR;
211 return svn_error_trace(stream->close_fn(stream->baton));
214 svn_error_t *
215 svn_stream_puts(svn_stream_t *stream,
216 const char *str)
218 apr_size_t len;
219 len = strlen(str);
220 return svn_error_trace(svn_stream_write(stream, str, &len));
223 svn_error_t *
224 svn_stream_printf(svn_stream_t *stream,
225 apr_pool_t *pool,
226 const char *fmt,
227 ...)
229 const char *message;
230 va_list ap;
232 va_start(ap, fmt);
233 message = apr_pvsprintf(pool, fmt, ap);
234 va_end(ap);
236 return svn_error_trace(svn_stream_puts(stream, message));
240 svn_error_t *
241 svn_stream_printf_from_utf8(svn_stream_t *stream,
242 const char *encoding,
243 apr_pool_t *pool,
244 const char *fmt,
245 ...)
247 const char *message, *translated;
248 va_list ap;
250 va_start(ap, fmt);
251 message = apr_pvsprintf(pool, fmt, ap);
252 va_end(ap);
254 SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding,
255 pool));
257 return svn_error_trace(svn_stream_puts(stream, translated));
260 /* Size that 90% of the lines we encounter will be not longer than.
261 used by stream_readline_bytewise() and stream_readline_chunky().
263 #define LINE_CHUNK_SIZE 80
265 /* Guts of svn_stream_readline().
266 * Returns the line read from STREAM in *STRINGBUF, and indicates
267 * end-of-file in *EOF. If DETECT_EOL is TRUE, the end-of-line indicator
268 * is detected automatically and returned in *EOL.
269 * If DETECT_EOL is FALSE, *EOL must point to the desired end-of-line
270 * indicator. STRINGBUF is allocated in POOL. */
271 static svn_error_t *
272 stream_readline_bytewise(svn_stringbuf_t **stringbuf,
273 svn_boolean_t *eof,
274 const char *eol,
275 svn_stream_t *stream,
276 apr_pool_t *pool)
278 svn_stringbuf_t *str;
279 apr_size_t numbytes;
280 const char *match;
281 char c;
283 /* Since we're reading one character at a time, let's at least
284 optimize for the 90% case. 90% of the time, we can avoid the
285 stringbuf ever having to realloc() itself if we start it out at
286 80 chars. */
287 str = svn_stringbuf_create_ensure(LINE_CHUNK_SIZE, pool);
289 /* Read into STR up to and including the next EOL sequence. */
290 match = eol;
291 while (*match)
293 numbytes = 1;
294 SVN_ERR(svn_stream_read(stream, &c, &numbytes));
295 if (numbytes != 1)
297 /* a 'short' read means the stream has run out. */
298 *eof = TRUE;
299 *stringbuf = str;
300 return SVN_NO_ERROR;
303 if (c == *match)
304 match++;
305 else
306 match = eol;
308 svn_stringbuf_appendbyte(str, c);
311 *eof = FALSE;
312 svn_stringbuf_chop(str, match - eol);
313 *stringbuf = str;
315 return SVN_NO_ERROR;
318 static svn_error_t *
319 stream_readline_chunky(svn_stringbuf_t **stringbuf,
320 svn_boolean_t *eof,
321 const char *eol,
322 svn_stream_t *stream,
323 apr_pool_t *pool)
325 /* Read larger chunks of data at once into this buffer and scan
326 * that for EOL. A good chunk size should be about 80 chars since
327 * most text lines will be shorter. However, don't use a much
328 * larger value because filling the buffer from the stream takes
329 * time as well.
331 char buffer[LINE_CHUNK_SIZE+1];
333 /* variables */
334 svn_stream_mark_t *mark;
335 apr_size_t numbytes;
336 const char *eol_pos;
337 apr_size_t total_parsed = 0;
339 /* invariant for this call */
340 const size_t eol_len = strlen(eol);
342 /* Remember the line start so this plus the line length will be
343 * the position to move to at the end of this function.
345 SVN_ERR(svn_stream_mark(stream, &mark, pool));
347 /* Read the first chunk. */
348 numbytes = LINE_CHUNK_SIZE;
349 SVN_ERR(svn_stream_read(stream, buffer, &numbytes));
350 buffer[numbytes] = '\0';
352 /* Look for the EOL in this first chunk. If we find it, we are done here.
354 eol_pos = strstr(buffer, eol);
355 if (eol_pos != NULL)
357 *stringbuf = svn_stringbuf_ncreate(buffer, eol_pos - buffer, pool);
358 total_parsed = eol_pos - buffer + eol_len;
360 else if (numbytes < LINE_CHUNK_SIZE)
362 /* We hit EOF but not EOL.
364 *stringbuf = svn_stringbuf_ncreate(buffer, numbytes, pool);
365 *eof = TRUE;
366 return SVN_NO_ERROR;
368 else
370 /* A larger buffer for the string is needed. */
371 svn_stringbuf_t *str;
372 str = svn_stringbuf_create_ensure(2*LINE_CHUNK_SIZE, pool);
373 svn_stringbuf_appendbytes(str, buffer, numbytes);
374 *stringbuf = str;
376 /* Loop reading chunks until an EOL was found. If we hit EOF, fall
377 * back to the standard implementation. */
380 /* Append the next chunk to the string read so far.
382 svn_stringbuf_ensure(str, str->len + LINE_CHUNK_SIZE);
383 numbytes = LINE_CHUNK_SIZE;
384 SVN_ERR(svn_stream_read(stream, str->data + str->len, &numbytes));
385 str->len += numbytes;
386 str->data[str->len] = '\0';
388 /* Look for the EOL in the new data plus the last part of the
389 * previous chunk because the EOL may span over the boundary
390 * between both chunks.
392 eol_pos = strstr(str->data + str->len - numbytes - (eol_len-1), eol);
394 if ((numbytes < LINE_CHUNK_SIZE) && (eol_pos == NULL))
396 /* We hit EOF instead of EOL. */
397 *eof = TRUE;
398 return SVN_NO_ERROR;
401 while (eol_pos == NULL);
403 /* Number of bytes we actually consumed (i.e. line + EOF).
404 * We need to "return" the rest to the stream by moving its
405 * read pointer.
407 total_parsed = eol_pos - str->data + eol_len;
409 /* Terminate the string at the EOL postion and return it. */
410 str->len = eol_pos - str->data;
411 str->data[str->len] = 0;
414 /* Move the stream read pointer to the first position behind the EOL.
416 SVN_ERR(svn_stream_seek(stream, mark));
417 return svn_error_trace(svn_stream_skip(stream, total_parsed));
420 /* Guts of svn_stream_readline().
421 * Returns the line read from STREAM in *STRINGBUF, and indicates
422 * end-of-file in *EOF. EOL must point to the desired end-of-line
423 * indicator. STRINGBUF is allocated in POOL. */
424 static svn_error_t *
425 stream_readline(svn_stringbuf_t **stringbuf,
426 svn_boolean_t *eof,
427 const char *eol,
428 svn_stream_t *stream,
429 apr_pool_t *pool)
431 *eof = FALSE;
433 /* Often, we operate on APR file or string-based streams and know what
434 * EOL we are looking for. Optimize that common case.
436 if (svn_stream_supports_mark(stream) &&
437 svn_stream__is_buffered(stream))
439 /* We can efficiently read chunks speculatively and reposition the
440 * stream pointer to the end of the line once we found that.
442 SVN_ERR(stream_readline_chunky(stringbuf,
443 eof,
444 eol,
445 stream,
446 pool));
448 else
450 /* Use the standard byte-byte implementation.
452 SVN_ERR(stream_readline_bytewise(stringbuf,
453 eof,
454 eol,
455 stream,
456 pool));
459 return SVN_NO_ERROR;
462 svn_error_t *
463 svn_stream_readline(svn_stream_t *stream,
464 svn_stringbuf_t **stringbuf,
465 const char *eol,
466 svn_boolean_t *eof,
467 apr_pool_t *pool)
469 return svn_error_trace(stream_readline(stringbuf, eof, eol, stream,
470 pool));
473 svn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to,
474 svn_cancel_func_t cancel_func,
475 void *cancel_baton,
476 apr_pool_t *scratch_pool)
478 char *buf = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE);
479 svn_error_t *err;
480 svn_error_t *err2;
482 /* Read and write chunks until we get a short read, indicating the
483 end of the stream. (We can't get a short write without an
484 associated error.) */
485 while (1)
487 apr_size_t len = SVN__STREAM_CHUNK_SIZE;
489 if (cancel_func)
491 err = cancel_func(cancel_baton);
492 if (err)
493 break;
496 err = svn_stream_read(from, buf, &len);
497 if (err)
498 break;
500 if (len > 0)
501 err = svn_stream_write(to, buf, &len);
503 if (err || (len != SVN__STREAM_CHUNK_SIZE))
504 break;
507 err2 = svn_error_compose_create(svn_stream_close(from),
508 svn_stream_close(to));
510 return svn_error_compose_create(err, err2);
513 svn_error_t *
514 svn_stream_contents_same2(svn_boolean_t *same,
515 svn_stream_t *stream1,
516 svn_stream_t *stream2,
517 apr_pool_t *pool)
519 char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
520 char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
521 apr_size_t bytes_read1 = SVN__STREAM_CHUNK_SIZE;
522 apr_size_t bytes_read2 = SVN__STREAM_CHUNK_SIZE;
523 svn_error_t *err = NULL;
525 *same = TRUE; /* assume TRUE, until disproved below */
526 while (bytes_read1 == SVN__STREAM_CHUNK_SIZE
527 && bytes_read2 == SVN__STREAM_CHUNK_SIZE)
529 err = svn_stream_read(stream1, buf1, &bytes_read1);
530 if (err)
531 break;
532 err = svn_stream_read(stream2, buf2, &bytes_read2);
533 if (err)
534 break;
536 if ((bytes_read1 != bytes_read2)
537 || (memcmp(buf1, buf2, bytes_read1)))
539 *same = FALSE;
540 break;
544 return svn_error_compose_create(err,
545 svn_error_compose_create(
546 svn_stream_close(stream1),
547 svn_stream_close(stream2)));
551 /*** Stream implementation utilities ***/
553 /* Skip data from any stream by reading and simply discarding it. */
554 static svn_error_t *
555 skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_fn)
557 apr_size_t bytes_read = 1;
558 char buffer[4096];
559 apr_size_t to_read = len;
561 while ((to_read > 0) && (bytes_read > 0))
563 bytes_read = sizeof(buffer) < to_read ? sizeof(buffer) : to_read;
564 SVN_ERR(read_fn(baton, buffer, &bytes_read));
565 to_read -= bytes_read;
568 return SVN_NO_ERROR;
573 /*** Generic readable empty stream ***/
575 static svn_error_t *
576 read_handler_empty(void *baton, char *buffer, apr_size_t *len)
578 *len = 0;
579 return SVN_NO_ERROR;
582 static svn_error_t *
583 write_handler_empty(void *baton, const char *data, apr_size_t *len)
585 return SVN_NO_ERROR;
588 static svn_error_t *
589 mark_handler_empty(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
591 *mark = NULL; /* Seek to start of stream marker */
592 return SVN_NO_ERROR;
595 static svn_error_t *
596 seek_handler_empty(void *baton, const svn_stream_mark_t *mark)
598 return SVN_NO_ERROR;
601 static svn_boolean_t
602 is_buffered_handler_empty(void *baton)
604 return FALSE;
608 svn_stream_t *
609 svn_stream_empty(apr_pool_t *pool)
611 svn_stream_t *stream;
613 stream = svn_stream_create(NULL, pool);
614 svn_stream_set_read(stream, read_handler_empty);
615 svn_stream_set_write(stream, write_handler_empty);
616 svn_stream_set_mark(stream, mark_handler_empty);
617 svn_stream_set_seek(stream, seek_handler_empty);
618 svn_stream__set_is_buffered(stream, is_buffered_handler_empty);
619 return stream;
624 /*** Stream duplication support ***/
625 struct baton_tee {
626 svn_stream_t *out1;
627 svn_stream_t *out2;
631 static svn_error_t *
632 write_handler_tee(void *baton, const char *data, apr_size_t *len)
634 struct baton_tee *bt = baton;
636 SVN_ERR(svn_stream_write(bt->out1, data, len));
637 SVN_ERR(svn_stream_write(bt->out2, data, len));
639 return SVN_NO_ERROR;
643 static svn_error_t *
644 close_handler_tee(void *baton)
646 struct baton_tee *bt = baton;
648 SVN_ERR(svn_stream_close(bt->out1));
649 SVN_ERR(svn_stream_close(bt->out2));
651 return SVN_NO_ERROR;
655 svn_stream_t *
656 svn_stream_tee(svn_stream_t *out1,
657 svn_stream_t *out2,
658 apr_pool_t *pool)
660 struct baton_tee *baton;
661 svn_stream_t *stream;
663 if (out1 == NULL)
664 return out2;
666 if (out2 == NULL)
667 return out1;
669 baton = apr_palloc(pool, sizeof(*baton));
670 baton->out1 = out1;
671 baton->out2 = out2;
672 stream = svn_stream_create(baton, pool);
673 svn_stream_set_write(stream, write_handler_tee);
674 svn_stream_set_close(stream, close_handler_tee);
676 return stream;
681 /*** Ownership detaching stream ***/
683 static svn_error_t *
684 read_handler_disown(void *baton, char *buffer, apr_size_t *len)
686 return svn_error_trace(svn_stream_read(baton, buffer, len));
689 static svn_error_t *
690 skip_handler_disown(void *baton, apr_size_t len)
692 return svn_error_trace(svn_stream_skip(baton, len));
695 static svn_error_t *
696 write_handler_disown(void *baton, const char *buffer, apr_size_t *len)
698 return svn_error_trace(svn_stream_write(baton, buffer, len));
701 static svn_error_t *
702 mark_handler_disown(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
704 return svn_error_trace(svn_stream_mark(baton, mark, pool));
707 static svn_error_t *
708 seek_handler_disown(void *baton, const svn_stream_mark_t *mark)
710 return svn_error_trace(svn_stream_seek(baton, mark));
713 static svn_boolean_t
714 is_buffered_handler_disown(void *baton)
716 return svn_stream__is_buffered(baton);
719 svn_stream_t *
720 svn_stream_disown(svn_stream_t *stream, apr_pool_t *pool)
722 svn_stream_t *s = svn_stream_create(stream, pool);
724 svn_stream_set_read(s, read_handler_disown);
725 svn_stream_set_skip(s, skip_handler_disown);
726 svn_stream_set_write(s, write_handler_disown);
727 svn_stream_set_mark(s, mark_handler_disown);
728 svn_stream_set_seek(s, seek_handler_disown);
729 svn_stream__set_is_buffered(s, is_buffered_handler_disown);
731 return s;
736 /*** Generic stream for APR files ***/
737 struct baton_apr {
738 apr_file_t *file;
739 apr_pool_t *pool;
742 /* svn_stream_mark_t for streams backed by APR files. */
743 struct mark_apr {
744 apr_off_t off;
747 static svn_error_t *
748 read_handler_apr(void *baton, char *buffer, apr_size_t *len)
750 struct baton_apr *btn = baton;
751 svn_error_t *err;
752 svn_boolean_t eof;
754 if (*len == 1)
756 err = svn_io_file_getc(buffer, btn->file, btn->pool);
757 if (err)
759 *len = 0;
760 if (APR_STATUS_IS_EOF(err->apr_err))
762 svn_error_clear(err);
763 err = SVN_NO_ERROR;
767 else
768 err = svn_io_file_read_full2(btn->file, buffer, *len, len,
769 &eof, btn->pool);
771 return svn_error_trace(err);
774 static svn_error_t *
775 skip_handler_apr(void *baton, apr_size_t len)
777 struct baton_apr *btn = baton;
778 apr_off_t offset = len;
780 return svn_error_trace(
781 svn_io_file_seek(btn->file, APR_CUR, &offset, btn->pool));
784 static svn_error_t *
785 write_handler_apr(void *baton, const char *data, apr_size_t *len)
787 struct baton_apr *btn = baton;
788 svn_error_t *err;
790 if (*len == 1)
792 err = svn_io_file_putc(*data, btn->file, btn->pool);
793 if (err)
794 *len = 0;
796 else
797 err = svn_io_file_write_full(btn->file, data, *len, len, btn->pool);
799 return svn_error_trace(err);
802 static svn_error_t *
803 close_handler_apr(void *baton)
805 struct baton_apr *btn = baton;
807 return svn_error_trace(svn_io_file_close(btn->file, btn->pool));
810 static svn_error_t *
811 mark_handler_apr(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
813 struct baton_apr *btn = baton;
814 struct mark_apr *mark_apr;
816 mark_apr = apr_palloc(pool, sizeof(*mark_apr));
817 mark_apr->off = 0;
818 SVN_ERR(svn_io_file_seek(btn->file, APR_CUR, &mark_apr->off, btn->pool));
819 *mark = (svn_stream_mark_t *)mark_apr;
820 return SVN_NO_ERROR;
823 static svn_error_t *
824 seek_handler_apr(void *baton, const svn_stream_mark_t *mark)
826 struct baton_apr *btn = baton;
827 apr_off_t offset = (mark != NULL) ? ((const struct mark_apr *)mark)->off : 0;
829 SVN_ERR(svn_io_file_seek(btn->file, APR_SET, &offset, btn->pool));
831 return SVN_NO_ERROR;
834 static svn_boolean_t
835 is_buffered_handler_apr(void *baton)
837 struct baton_apr *btn = baton;
838 return (apr_file_flags_get(btn->file) & APR_BUFFERED) != 0;
841 svn_error_t *
842 svn_stream_open_readonly(svn_stream_t **stream,
843 const char *path,
844 apr_pool_t *result_pool,
845 apr_pool_t *scratch_pool)
847 apr_file_t *file;
849 SVN_ERR(svn_io_file_open(&file, path, APR_READ | APR_BUFFERED,
850 APR_OS_DEFAULT, result_pool));
851 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
853 return SVN_NO_ERROR;
857 svn_error_t *
858 svn_stream_open_writable(svn_stream_t **stream,
859 const char *path,
860 apr_pool_t *result_pool,
861 apr_pool_t *scratch_pool)
863 apr_file_t *file;
865 SVN_ERR(svn_io_file_open(&file, path,
866 APR_WRITE
867 | APR_BUFFERED
868 | APR_CREATE
869 | APR_EXCL,
870 APR_OS_DEFAULT, result_pool));
871 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
873 return SVN_NO_ERROR;
877 svn_error_t *
878 svn_stream_open_unique(svn_stream_t **stream,
879 const char **temp_path,
880 const char *dirpath,
881 svn_io_file_del_t delete_when,
882 apr_pool_t *result_pool,
883 apr_pool_t *scratch_pool)
885 apr_file_t *file;
887 SVN_ERR(svn_io_open_unique_file3(&file, temp_path, dirpath,
888 delete_when, result_pool, scratch_pool));
889 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
891 return SVN_NO_ERROR;
895 svn_stream_t *
896 svn_stream_from_aprfile2(apr_file_t *file,
897 svn_boolean_t disown,
898 apr_pool_t *pool)
900 struct baton_apr *baton;
901 svn_stream_t *stream;
903 if (file == NULL)
904 return svn_stream_empty(pool);
906 baton = apr_palloc(pool, sizeof(*baton));
907 baton->file = file;
908 baton->pool = pool;
909 stream = svn_stream_create(baton, pool);
910 svn_stream_set_read(stream, read_handler_apr);
911 svn_stream_set_write(stream, write_handler_apr);
912 svn_stream_set_skip(stream, skip_handler_apr);
913 svn_stream_set_mark(stream, mark_handler_apr);
914 svn_stream_set_seek(stream, seek_handler_apr);
915 svn_stream__set_is_buffered(stream, is_buffered_handler_apr);
917 if (! disown)
918 svn_stream_set_close(stream, close_handler_apr);
920 return stream;
924 /* Compressed stream support */
926 #define ZBUFFER_SIZE 4096 /* The size of the buffer the
927 compressed stream uses to read from
928 the substream. Basically an
929 arbitrary value, picked to be about
930 page-sized. */
932 struct zbaton {
933 z_stream *in; /* compressed stream for reading */
934 z_stream *out; /* compressed stream for writing */
935 svn_read_fn_t read; /* substream's read function */
936 svn_write_fn_t write; /* substream's write function */
937 svn_close_fn_t close; /* substream's close function */
938 void *read_buffer; /* buffer used for reading from
939 substream */
940 int read_flush; /* what flush mode to use while
941 reading */
942 apr_pool_t *pool; /* The pool this baton is allocated
943 on */
944 void *subbaton; /* The substream's baton */
947 /* zlib alloc function. opaque is the pool we need. */
948 static voidpf
949 zalloc(voidpf opaque, uInt items, uInt size)
951 apr_pool_t *pool = opaque;
953 return apr_palloc(pool, items * size);
956 /* zlib free function */
957 static void
958 zfree(voidpf opaque, voidpf address)
960 /* Empty, since we allocate on the pool */
963 /* Helper function to figure out the sync mode */
964 static svn_error_t *
965 read_helper_gz(svn_read_fn_t read_fn,
966 void *baton,
967 char *buffer,
968 uInt *len, int *zflush)
970 uInt orig_len = *len;
972 /* There's no reason this value should grow bigger than the range of
973 uInt, but Subversion's API requires apr_size_t. */
974 apr_size_t apr_len = (apr_size_t) *len;
976 SVN_ERR((*read_fn)(baton, buffer, &apr_len));
978 /* Type cast back to uInt type that zlib uses. On LP64 platforms
979 apr_size_t will be bigger than uInt. */
980 *len = (uInt) apr_len;
982 /* I wanted to use Z_FINISH here, but we need to know our buffer is
983 big enough */
984 *zflush = (*len) < orig_len ? Z_SYNC_FLUSH : Z_SYNC_FLUSH;
986 return SVN_NO_ERROR;
989 /* Handle reading from a compressed stream */
990 static svn_error_t *
991 read_handler_gz(void *baton, char *buffer, apr_size_t *len)
993 struct zbaton *btn = baton;
994 int zerr;
996 if (btn->in == NULL)
998 btn->in = apr_palloc(btn->pool, sizeof(z_stream));
999 btn->in->zalloc = zalloc;
1000 btn->in->zfree = zfree;
1001 btn->in->opaque = btn->pool;
1002 btn->read_buffer = apr_palloc(btn->pool, ZBUFFER_SIZE);
1003 btn->in->next_in = btn->read_buffer;
1004 btn->in->avail_in = ZBUFFER_SIZE;
1006 SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer,
1007 &btn->in->avail_in, &btn->read_flush));
1009 zerr = inflateInit(btn->in);
1010 SVN_ERR(svn_error__wrap_zlib(zerr, "inflateInit", btn->in->msg));
1013 btn->in->next_out = (Bytef *) buffer;
1014 btn->in->avail_out = (uInt) *len;
1016 while (btn->in->avail_out > 0)
1018 if (btn->in->avail_in <= 0)
1020 btn->in->avail_in = ZBUFFER_SIZE;
1021 btn->in->next_in = btn->read_buffer;
1022 SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer,
1023 &btn->in->avail_in, &btn->read_flush));
1026 /* Short read means underlying stream has run out. */
1027 if (btn->in->avail_in == 0)
1029 *len = 0;
1030 return SVN_NO_ERROR;
1033 zerr = inflate(btn->in, btn->read_flush);
1034 if (zerr == Z_STREAM_END)
1035 break;
1036 else if (zerr != Z_OK)
1037 return svn_error_trace(svn_error__wrap_zlib(zerr, "inflate",
1038 btn->in->msg));
1041 *len -= btn->in->avail_out;
1042 return SVN_NO_ERROR;
1045 /* Compress data and write it to the substream */
1046 static svn_error_t *
1047 write_handler_gz(void *baton, const char *buffer, apr_size_t *len)
1049 struct zbaton *btn = baton;
1050 apr_pool_t *subpool;
1051 void *write_buf;
1052 apr_size_t buf_size, write_len;
1053 int zerr;
1055 if (btn->out == NULL)
1057 btn->out = apr_palloc(btn->pool, sizeof(z_stream));
1058 btn->out->zalloc = zalloc;
1059 btn->out->zfree = zfree;
1060 btn->out->opaque = btn->pool;
1062 zerr = deflateInit(btn->out, Z_DEFAULT_COMPRESSION);
1063 SVN_ERR(svn_error__wrap_zlib(zerr, "deflateInit", btn->out->msg));
1066 /* The largest buffer we should need is 0.1% larger than the
1067 compressed data, + 12 bytes. This info comes from zlib.h. */
1068 buf_size = *len + (*len / 1000) + 13;
1069 subpool = svn_pool_create(btn->pool);
1070 write_buf = apr_palloc(subpool, buf_size);
1072 btn->out->next_in = (Bytef *) buffer; /* Casting away const! */
1073 btn->out->avail_in = (uInt) *len;
1075 while (btn->out->avail_in > 0)
1077 btn->out->next_out = write_buf;
1078 btn->out->avail_out = (uInt) buf_size;
1080 zerr = deflate(btn->out, Z_NO_FLUSH);
1081 SVN_ERR(svn_error__wrap_zlib(zerr, "deflate", btn->out->msg));
1082 write_len = buf_size - btn->out->avail_out;
1083 if (write_len > 0)
1084 SVN_ERR(btn->write(btn->subbaton, write_buf, &write_len));
1087 svn_pool_destroy(subpool);
1089 return SVN_NO_ERROR;
1092 /* Handle flushing and closing the stream */
1093 static svn_error_t *
1094 close_handler_gz(void *baton)
1096 struct zbaton *btn = baton;
1097 int zerr;
1099 if (btn->in != NULL)
1101 zerr = inflateEnd(btn->in);
1102 SVN_ERR(svn_error__wrap_zlib(zerr, "inflateEnd", btn->in->msg));
1105 if (btn->out != NULL)
1107 void *buf;
1108 apr_size_t write_len;
1110 buf = apr_palloc(btn->pool, ZBUFFER_SIZE);
1112 while (TRUE)
1114 btn->out->next_out = buf;
1115 btn->out->avail_out = ZBUFFER_SIZE;
1117 zerr = deflate(btn->out, Z_FINISH);
1118 if (zerr != Z_STREAM_END && zerr != Z_OK)
1119 return svn_error_trace(svn_error__wrap_zlib(zerr, "deflate",
1120 btn->out->msg));
1121 write_len = ZBUFFER_SIZE - btn->out->avail_out;
1122 if (write_len > 0)
1123 SVN_ERR(btn->write(btn->subbaton, buf, &write_len));
1124 if (zerr == Z_STREAM_END)
1125 break;
1128 zerr = deflateEnd(btn->out);
1129 SVN_ERR(svn_error__wrap_zlib(zerr, "deflateEnd", btn->out->msg));
1132 if (btn->close != NULL)
1133 return svn_error_trace(btn->close(btn->subbaton));
1134 else
1135 return SVN_NO_ERROR;
1139 svn_stream_t *
1140 svn_stream_compressed(svn_stream_t *stream, apr_pool_t *pool)
1142 struct svn_stream_t *zstream;
1143 struct zbaton *baton;
1145 assert(stream != NULL);
1147 baton = apr_palloc(pool, sizeof(*baton));
1148 baton->in = baton->out = NULL;
1149 baton->read = stream->read_fn;
1150 baton->write = stream->write_fn;
1151 baton->close = stream->close_fn;
1152 baton->subbaton = stream->baton;
1153 baton->pool = pool;
1154 baton->read_buffer = NULL;
1155 baton->read_flush = Z_SYNC_FLUSH;
1157 zstream = svn_stream_create(baton, pool);
1158 svn_stream_set_read(zstream, read_handler_gz);
1159 svn_stream_set_write(zstream, write_handler_gz);
1160 svn_stream_set_close(zstream, close_handler_gz);
1162 return zstream;
1166 /* Checksummed stream support */
1168 struct checksum_stream_baton
1170 svn_checksum_ctx_t *read_ctx, *write_ctx;
1171 svn_checksum_t **read_checksum; /* Output value. */
1172 svn_checksum_t **write_checksum; /* Output value. */
1173 svn_stream_t *proxy;
1175 /* True if more data should be read when closing the stream. */
1176 svn_boolean_t read_more;
1178 /* Pool to allocate read buffer and output values from. */
1179 apr_pool_t *pool;
1182 static svn_error_t *
1183 read_handler_checksum(void *baton, char *buffer, apr_size_t *len)
1185 struct checksum_stream_baton *btn = baton;
1186 apr_size_t saved_len = *len;
1188 SVN_ERR(svn_stream_read(btn->proxy, buffer, len));
1190 if (btn->read_checksum)
1191 SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len));
1193 if (saved_len != *len)
1194 btn->read_more = FALSE;
1196 return SVN_NO_ERROR;
1200 static svn_error_t *
1201 write_handler_checksum(void *baton, const char *buffer, apr_size_t *len)
1203 struct checksum_stream_baton *btn = baton;
1205 if (btn->write_checksum && *len > 0)
1206 SVN_ERR(svn_checksum_update(btn->write_ctx, buffer, *len));
1208 return svn_error_trace(svn_stream_write(btn->proxy, buffer, len));
1212 static svn_error_t *
1213 close_handler_checksum(void *baton)
1215 struct checksum_stream_baton *btn = baton;
1217 /* If we're supposed to drain the stream, do so before finalizing the
1218 checksum. */
1219 if (btn->read_more)
1221 char *buf = apr_palloc(btn->pool, SVN__STREAM_CHUNK_SIZE);
1222 apr_size_t len = SVN__STREAM_CHUNK_SIZE;
1226 SVN_ERR(read_handler_checksum(baton, buf, &len));
1228 while (btn->read_more);
1231 if (btn->read_ctx)
1232 SVN_ERR(svn_checksum_final(btn->read_checksum, btn->read_ctx, btn->pool));
1234 if (btn->write_ctx)
1235 SVN_ERR(svn_checksum_final(btn->write_checksum, btn->write_ctx, btn->pool));
1237 return svn_error_trace(svn_stream_close(btn->proxy));
1241 svn_stream_t *
1242 svn_stream_checksummed2(svn_stream_t *stream,
1243 svn_checksum_t **read_checksum,
1244 svn_checksum_t **write_checksum,
1245 svn_checksum_kind_t checksum_kind,
1246 svn_boolean_t read_all,
1247 apr_pool_t *pool)
1249 svn_stream_t *s;
1250 struct checksum_stream_baton *baton;
1252 if (read_checksum == NULL && write_checksum == NULL)
1253 return stream;
1255 baton = apr_palloc(pool, sizeof(*baton));
1256 if (read_checksum)
1257 baton->read_ctx = svn_checksum_ctx_create(checksum_kind, pool);
1258 else
1259 baton->read_ctx = NULL;
1261 if (write_checksum)
1262 baton->write_ctx = svn_checksum_ctx_create(checksum_kind, pool);
1263 else
1264 baton->write_ctx = NULL;
1266 baton->read_checksum = read_checksum;
1267 baton->write_checksum = write_checksum;
1268 baton->proxy = stream;
1269 baton->read_more = read_all;
1270 baton->pool = pool;
1272 s = svn_stream_create(baton, pool);
1273 svn_stream_set_read(s, read_handler_checksum);
1274 svn_stream_set_write(s, write_handler_checksum);
1275 svn_stream_set_close(s, close_handler_checksum);
1276 return s;
1279 struct md5_stream_baton
1281 const unsigned char **read_digest;
1282 const unsigned char **write_digest;
1283 svn_checksum_t *read_checksum;
1284 svn_checksum_t *write_checksum;
1285 svn_stream_t *proxy;
1286 apr_pool_t *pool;
1289 static svn_error_t *
1290 read_handler_md5(void *baton, char *buffer, apr_size_t *len)
1292 struct md5_stream_baton *btn = baton;
1293 return svn_error_trace(svn_stream_read(btn->proxy, buffer, len));
1296 static svn_error_t *
1297 skip_handler_md5(void *baton, apr_size_t len)
1299 struct md5_stream_baton *btn = baton;
1300 return svn_error_trace(svn_stream_skip(btn->proxy, len));
1303 static svn_error_t *
1304 write_handler_md5(void *baton, const char *buffer, apr_size_t *len)
1306 struct md5_stream_baton *btn = baton;
1307 return svn_error_trace(svn_stream_write(btn->proxy, buffer, len));
1310 static svn_error_t *
1311 close_handler_md5(void *baton)
1313 struct md5_stream_baton *btn = baton;
1315 SVN_ERR(svn_stream_close(btn->proxy));
1317 if (btn->read_digest)
1318 *btn->read_digest
1319 = apr_pmemdup(btn->pool, btn->read_checksum->digest,
1320 APR_MD5_DIGESTSIZE);
1322 if (btn->write_digest)
1323 *btn->write_digest
1324 = apr_pmemdup(btn->pool, btn->write_checksum->digest,
1325 APR_MD5_DIGESTSIZE);
1327 return SVN_NO_ERROR;
1331 svn_stream_t *
1332 svn_stream_checksummed(svn_stream_t *stream,
1333 const unsigned char **read_digest,
1334 const unsigned char **write_digest,
1335 svn_boolean_t read_all,
1336 apr_pool_t *pool)
1338 svn_stream_t *s;
1339 struct md5_stream_baton *baton;
1341 if (! read_digest && ! write_digest)
1342 return stream;
1344 baton = apr_palloc(pool, sizeof(*baton));
1345 baton->read_digest = read_digest;
1346 baton->write_digest = write_digest;
1347 baton->pool = pool;
1349 /* Set BATON->proxy to a stream that will fill in BATON->read_checksum
1350 * and BATON->write_checksum (if we want them) when it is closed. */
1351 baton->proxy
1352 = svn_stream_checksummed2(stream,
1353 read_digest ? &baton->read_checksum : NULL,
1354 write_digest ? &baton->write_checksum : NULL,
1355 svn_checksum_md5,
1356 read_all, pool);
1358 /* Create a stream that will forward its read/write/close operations to
1359 * BATON->proxy and will fill in *READ_DIGEST and *WRITE_DIGEST (if we
1360 * want them) after it closes BATON->proxy. */
1361 s = svn_stream_create(baton, pool);
1362 svn_stream_set_read(s, read_handler_md5);
1363 svn_stream_set_skip(s, skip_handler_md5);
1364 svn_stream_set_write(s, write_handler_md5);
1365 svn_stream_set_close(s, close_handler_md5);
1366 return s;
1372 /* Miscellaneous stream functions. */
1373 struct stringbuf_stream_baton
1375 svn_stringbuf_t *str;
1376 apr_size_t amt_read;
1379 /* svn_stream_mark_t for streams backed by stringbufs. */
1380 struct stringbuf_stream_mark {
1381 apr_size_t pos;
1384 static svn_error_t *
1385 read_handler_stringbuf(void *baton, char *buffer, apr_size_t *len)
1387 struct stringbuf_stream_baton *btn = baton;
1388 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1390 *len = (*len > left_to_read) ? left_to_read : *len;
1391 memcpy(buffer, btn->str->data + btn->amt_read, *len);
1392 btn->amt_read += *len;
1393 return SVN_NO_ERROR;
1396 static svn_error_t *
1397 skip_handler_stringbuf(void *baton, apr_size_t len)
1399 struct stringbuf_stream_baton *btn = baton;
1400 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1402 len = (len > left_to_read) ? left_to_read : len;
1403 btn->amt_read += len;
1404 return SVN_NO_ERROR;
1407 static svn_error_t *
1408 write_handler_stringbuf(void *baton, const char *data, apr_size_t *len)
1410 struct stringbuf_stream_baton *btn = baton;
1412 svn_stringbuf_appendbytes(btn->str, data, *len);
1413 return SVN_NO_ERROR;
1416 static svn_error_t *
1417 mark_handler_stringbuf(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
1419 struct stringbuf_stream_baton *btn;
1420 struct stringbuf_stream_mark *stringbuf_stream_mark;
1422 btn = baton;
1424 stringbuf_stream_mark = apr_palloc(pool, sizeof(*stringbuf_stream_mark));
1425 stringbuf_stream_mark->pos = btn->amt_read;
1426 *mark = (svn_stream_mark_t *)stringbuf_stream_mark;
1427 return SVN_NO_ERROR;
1430 static svn_error_t *
1431 seek_handler_stringbuf(void *baton, const svn_stream_mark_t *mark)
1433 struct stringbuf_stream_baton *btn = baton;
1435 if (mark != NULL)
1437 const struct stringbuf_stream_mark *stringbuf_stream_mark;
1439 stringbuf_stream_mark = (const struct stringbuf_stream_mark *)mark;
1440 btn->amt_read = stringbuf_stream_mark->pos;
1442 else
1443 btn->amt_read = 0;
1445 return SVN_NO_ERROR;
1448 static svn_boolean_t
1449 is_buffered_handler_stringbuf(void *baton)
1451 return TRUE;
1454 svn_stream_t *
1455 svn_stream_from_stringbuf(svn_stringbuf_t *str,
1456 apr_pool_t *pool)
1458 svn_stream_t *stream;
1459 struct stringbuf_stream_baton *baton;
1461 if (! str)
1462 return svn_stream_empty(pool);
1464 baton = apr_palloc(pool, sizeof(*baton));
1465 baton->str = str;
1466 baton->amt_read = 0;
1467 stream = svn_stream_create(baton, pool);
1468 svn_stream_set_read(stream, read_handler_stringbuf);
1469 svn_stream_set_skip(stream, skip_handler_stringbuf);
1470 svn_stream_set_write(stream, write_handler_stringbuf);
1471 svn_stream_set_mark(stream, mark_handler_stringbuf);
1472 svn_stream_set_seek(stream, seek_handler_stringbuf);
1473 svn_stream__set_is_buffered(stream, is_buffered_handler_stringbuf);
1474 return stream;
1477 struct string_stream_baton
1479 const svn_string_t *str;
1480 apr_size_t amt_read;
1483 /* svn_stream_mark_t for streams backed by stringbufs. */
1484 struct string_stream_mark {
1485 apr_size_t pos;
1488 static svn_error_t *
1489 read_handler_string(void *baton, char *buffer, apr_size_t *len)
1491 struct string_stream_baton *btn = baton;
1492 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1494 *len = (*len > left_to_read) ? left_to_read : *len;
1495 memcpy(buffer, btn->str->data + btn->amt_read, *len);
1496 btn->amt_read += *len;
1497 return SVN_NO_ERROR;
1500 static svn_error_t *
1501 mark_handler_string(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
1503 struct string_stream_baton *btn;
1504 struct string_stream_mark *marker;
1506 btn = baton;
1508 marker = apr_palloc(pool, sizeof(*marker));
1509 marker->pos = btn->amt_read;
1510 *mark = (svn_stream_mark_t *)marker;
1511 return SVN_NO_ERROR;
1514 static svn_error_t *
1515 seek_handler_string(void *baton, const svn_stream_mark_t *mark)
1517 struct string_stream_baton *btn = baton;
1519 if (mark != NULL)
1521 const struct string_stream_mark *marker;
1523 marker = (const struct string_stream_mark *)mark;
1524 btn->amt_read = marker->pos;
1526 else
1527 btn->amt_read = 0;
1529 return SVN_NO_ERROR;
1532 static svn_error_t *
1533 skip_handler_string(void *baton, apr_size_t len)
1535 struct string_stream_baton *btn = baton;
1536 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1538 len = (len > left_to_read) ? left_to_read : len;
1539 btn->amt_read += len;
1540 return SVN_NO_ERROR;
1543 static svn_boolean_t
1544 is_buffered_handler_string(void *baton)
1546 return TRUE;
1549 svn_stream_t *
1550 svn_stream_from_string(const svn_string_t *str,
1551 apr_pool_t *pool)
1553 svn_stream_t *stream;
1554 struct string_stream_baton *baton;
1556 if (! str)
1557 return svn_stream_empty(pool);
1559 baton = apr_palloc(pool, sizeof(*baton));
1560 baton->str = str;
1561 baton->amt_read = 0;
1562 stream = svn_stream_create(baton, pool);
1563 svn_stream_set_read(stream, read_handler_string);
1564 svn_stream_set_mark(stream, mark_handler_string);
1565 svn_stream_set_seek(stream, seek_handler_string);
1566 svn_stream_set_skip(stream, skip_handler_string);
1567 svn_stream__set_is_buffered(stream, is_buffered_handler_string);
1568 return stream;
1572 svn_error_t *
1573 svn_stream_for_stdin(svn_stream_t **in, apr_pool_t *pool)
1575 apr_file_t *stdin_file;
1576 apr_status_t apr_err;
1578 apr_err = apr_file_open_stdin(&stdin_file, pool);
1579 if (apr_err)
1580 return svn_error_wrap_apr(apr_err, "Can't open stdin");
1582 *in = svn_stream_from_aprfile2(stdin_file, TRUE, pool);
1584 return SVN_NO_ERROR;
1588 svn_error_t *
1589 svn_stream_for_stdout(svn_stream_t **out, apr_pool_t *pool)
1591 apr_file_t *stdout_file;
1592 apr_status_t apr_err;
1594 apr_err = apr_file_open_stdout(&stdout_file, pool);
1595 if (apr_err)
1596 return svn_error_wrap_apr(apr_err, "Can't open stdout");
1598 *out = svn_stream_from_aprfile2(stdout_file, TRUE, pool);
1600 return SVN_NO_ERROR;
1604 svn_error_t *
1605 svn_stream_for_stderr(svn_stream_t **err, apr_pool_t *pool)
1607 apr_file_t *stderr_file;
1608 apr_status_t apr_err;
1610 apr_err = apr_file_open_stderr(&stderr_file, pool);
1611 if (apr_err)
1612 return svn_error_wrap_apr(apr_err, "Can't open stderr");
1614 *err = svn_stream_from_aprfile2(stderr_file, TRUE, pool);
1616 return SVN_NO_ERROR;
1620 svn_error_t *
1621 svn_string_from_stream(svn_string_t **result,
1622 svn_stream_t *stream,
1623 apr_pool_t *result_pool,
1624 apr_pool_t *scratch_pool)
1626 svn_stringbuf_t *work = svn_stringbuf_create_ensure(SVN__STREAM_CHUNK_SIZE,
1627 result_pool);
1628 char *buffer = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE);
1630 while (1)
1632 apr_size_t len = SVN__STREAM_CHUNK_SIZE;
1634 SVN_ERR(svn_stream_read(stream, buffer, &len));
1635 svn_stringbuf_appendbytes(work, buffer, len);
1637 if (len < SVN__STREAM_CHUNK_SIZE)
1638 break;
1641 SVN_ERR(svn_stream_close(stream));
1643 *result = apr_palloc(result_pool, sizeof(**result));
1644 (*result)->data = work->data;
1645 (*result)->len = work->len;
1647 return SVN_NO_ERROR;
1651 /* These are somewhat arbirary, if we ever get good empirical data as to
1652 actually valid values, feel free to update them. */
1653 #define BUFFER_BLOCK_SIZE 1024
1654 #define BUFFER_MAX_SIZE 100000
1656 svn_stream_t *
1657 svn_stream_buffered(apr_pool_t *result_pool)
1659 return svn_stream__from_spillbuf(BUFFER_BLOCK_SIZE, BUFFER_MAX_SIZE,
1660 result_pool);
1665 /*** Lazyopen Streams ***/
1667 /* Custom baton for lazyopen-style wrapper streams. */
1668 typedef struct lazyopen_baton_t {
1670 /* Callback function and baton for opening the wrapped stream. */
1671 svn_stream_lazyopen_func_t open_func;
1672 void *open_baton;
1674 /* The wrapped stream, or NULL if the stream hasn't yet been
1675 opened. */
1676 svn_stream_t *real_stream;
1677 apr_pool_t *pool;
1679 /* Whether to open the wrapped stream on a close call. */
1680 svn_boolean_t open_on_close;
1682 } lazyopen_baton_t;
1685 /* Use B->open_func/baton to create and set B->real_stream iff it
1686 isn't already set. */
1687 static svn_error_t *
1688 lazyopen_if_unopened(lazyopen_baton_t *b)
1690 if (b->real_stream == NULL)
1692 svn_stream_t *stream;
1693 apr_pool_t *scratch_pool = svn_pool_create(b->pool);
1695 SVN_ERR(b->open_func(&stream, b->open_baton,
1696 b->pool, scratch_pool));
1698 svn_pool_destroy(scratch_pool);
1700 b->real_stream = stream;
1703 return SVN_NO_ERROR;
1706 /* Implements svn_read_fn_t */
1707 static svn_error_t *
1708 read_handler_lazyopen(void *baton,
1709 char *buffer,
1710 apr_size_t *len)
1712 lazyopen_baton_t *b = baton;
1714 SVN_ERR(lazyopen_if_unopened(b));
1715 SVN_ERR(svn_stream_read(b->real_stream, buffer, len));
1717 return SVN_NO_ERROR;
1720 /* Implements svn_stream_skip_fn_t */
1721 static svn_error_t *
1722 skip_handler_lazyopen(void *baton,
1723 apr_size_t len)
1725 lazyopen_baton_t *b = baton;
1727 SVN_ERR(lazyopen_if_unopened(b));
1728 SVN_ERR(svn_stream_skip(b->real_stream, len));
1730 return SVN_NO_ERROR;
1733 /* Implements svn_write_fn_t */
1734 static svn_error_t *
1735 write_handler_lazyopen(void *baton,
1736 const char *data,
1737 apr_size_t *len)
1739 lazyopen_baton_t *b = baton;
1741 SVN_ERR(lazyopen_if_unopened(b));
1742 SVN_ERR(svn_stream_write(b->real_stream, data, len));
1744 return SVN_NO_ERROR;
1747 /* Implements svn_close_fn_t */
1748 static svn_error_t *
1749 close_handler_lazyopen(void *baton)
1751 lazyopen_baton_t *b = baton;
1753 if (b->open_on_close)
1754 SVN_ERR(lazyopen_if_unopened(b));
1755 if (b->real_stream)
1756 SVN_ERR(svn_stream_close(b->real_stream));
1758 return SVN_NO_ERROR;
1761 /* Implements svn_stream_mark_fn_t */
1762 static svn_error_t *
1763 mark_handler_lazyopen(void *baton,
1764 svn_stream_mark_t **mark,
1765 apr_pool_t *pool)
1767 lazyopen_baton_t *b = baton;
1769 SVN_ERR(lazyopen_if_unopened(b));
1770 SVN_ERR(svn_stream_mark(b->real_stream, mark, pool));
1772 return SVN_NO_ERROR;
1775 /* Implements svn_stream_seek_fn_t */
1776 static svn_error_t *
1777 seek_handler_lazyopen(void *baton,
1778 const svn_stream_mark_t *mark)
1780 lazyopen_baton_t *b = baton;
1782 SVN_ERR(lazyopen_if_unopened(b));
1783 SVN_ERR(svn_stream_seek(b->real_stream, mark));
1785 return SVN_NO_ERROR;
1788 /* Implements svn_stream__is_buffered_fn_t */
1789 static svn_boolean_t
1790 is_buffered_lazyopen(void *baton)
1792 lazyopen_baton_t *b = baton;
1794 /* No lazy open as we cannot handle an open error. */
1795 if (!b->real_stream)
1796 return FALSE;
1798 return svn_stream__is_buffered(b->real_stream);
1801 svn_stream_t *
1802 svn_stream_lazyopen_create(svn_stream_lazyopen_func_t open_func,
1803 void *open_baton,
1804 svn_boolean_t open_on_close,
1805 apr_pool_t *result_pool)
1807 lazyopen_baton_t *lob = apr_pcalloc(result_pool, sizeof(*lob));
1808 svn_stream_t *stream;
1810 lob->open_func = open_func;
1811 lob->open_baton = open_baton;
1812 lob->real_stream = NULL;
1813 lob->pool = result_pool;
1814 lob->open_on_close = open_on_close;
1816 stream = svn_stream_create(lob, result_pool);
1817 svn_stream_set_read(stream, read_handler_lazyopen);
1818 svn_stream_set_skip(stream, skip_handler_lazyopen);
1819 svn_stream_set_write(stream, write_handler_lazyopen);
1820 svn_stream_set_close(stream, close_handler_lazyopen);
1821 svn_stream_set_mark(stream, mark_handler_lazyopen);
1822 svn_stream_set_seek(stream, seek_handler_lazyopen);
1823 svn_stream__set_is_buffered(stream, is_buffered_lazyopen);
1825 return stream;