📄 stream.c
字号:
/* * stream.c: svn_stream operations * * ==================================================================== * Copyright (c) 2000-2004, 2006 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#include "svn_private_config.h"#include <assert.h>#include <stdio.h>#include <apr.h>#include <apr_pools.h>#include <apr_strings.h>#include <apr_file_io.h>#include <apr_errno.h>#include <apr_md5.h>#ifdef SVN_HAVE_ZLIB#include <zlib.h>#endif#include "svn_pools.h"#include "svn_io.h"#include "svn_error.h"#include "svn_string.h"#include "svn_utf.h"struct svn_stream_t { void *baton; svn_read_fn_t read_fn; svn_write_fn_t write_fn; svn_close_fn_t close_fn;};/*** Generic streams. ***/svn_stream_t *svn_stream_create(void *baton, apr_pool_t *pool){ svn_stream_t *stream; stream = apr_palloc(pool, sizeof(*stream)); stream->baton = baton; stream->read_fn = NULL; stream->write_fn = NULL; stream->close_fn = NULL; return stream;}voidsvn_stream_set_baton(svn_stream_t *stream, void *baton){ stream->baton = baton;}voidsvn_stream_set_read(svn_stream_t *stream, svn_read_fn_t read_fn){ stream->read_fn = read_fn;}voidsvn_stream_set_write(svn_stream_t *stream, svn_write_fn_t write_fn){ stream->write_fn = write_fn;}voidsvn_stream_set_close(svn_stream_t *stream, svn_close_fn_t close_fn){ stream->close_fn = close_fn;}svn_error_t *svn_stream_read(svn_stream_t *stream, char *buffer, apr_size_t *len){ assert(stream->read_fn != NULL); return stream->read_fn(stream->baton, buffer, len);}svn_error_t *svn_stream_write(svn_stream_t *stream, const char *data, apr_size_t *len){ assert(stream->write_fn != NULL); return stream->write_fn(stream->baton, data, len);}svn_error_t *svn_stream_close(svn_stream_t *stream){ if (stream->close_fn == NULL) return SVN_NO_ERROR; return stream->close_fn(stream->baton);}svn_error_t *svn_stream_printf(svn_stream_t *stream, apr_pool_t *pool, const char *fmt, ...){ const char *message; va_list ap; apr_size_t len; va_start(ap, fmt); message = apr_pvsprintf(pool, fmt, ap); va_end(ap); len = strlen(message); return svn_stream_write(stream, message, &len);}svn_error_t *svn_stream_printf_from_utf8(svn_stream_t *stream, const char *encoding, apr_pool_t *pool, const char *fmt, ...){ const char *message, *translated; va_list ap; apr_size_t len; va_start(ap, fmt); message = apr_pvsprintf(pool, fmt, ap); va_end(ap); SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding, pool)); len = strlen(translated); return svn_stream_write(stream, translated, &len);}svn_error_t *svn_stream_readline(svn_stream_t *stream, svn_stringbuf_t **stringbuf, const char *eol, svn_boolean_t *eof, apr_pool_t *pool){ apr_size_t numbytes; const char *match; char c; svn_stringbuf_t *str = svn_stringbuf_create("", pool); /* Since we're reading one character at a time, let's at least optimize for the 90% case. 90% of the time, we can avoid the stringbuf ever having to realloc() itself if we start it out at 80 chars. */ svn_stringbuf_ensure(str, 80); match = eol; while (*match) { numbytes = 1; SVN_ERR(svn_stream_read(stream, &c, &numbytes)); if (numbytes != 1) { /* a 'short' read means the stream has run out. */ *eof = TRUE; *stringbuf = str; return SVN_NO_ERROR; } if (c == *match) match++; else match = eol; svn_stringbuf_appendbytes(str, &c, 1); } *eof = FALSE; svn_stringbuf_chop(str, match - eol); *stringbuf = str; return SVN_NO_ERROR;}svn_error_t *svn_stream_copy(svn_stream_t *from, svn_stream_t *to, apr_pool_t *pool){ char *buf = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); apr_size_t len; /* Read and write chunks until we get a short read, indicating the end of the stream. (We can't get a short write without an associated error.) */ while (1) { len = SVN__STREAM_CHUNK_SIZE; SVN_ERR(svn_stream_read(from, buf, &len)); if (len > 0) SVN_ERR(svn_stream_write(to, buf, &len)); if (len != SVN__STREAM_CHUNK_SIZE) break; } return SVN_NO_ERROR;}svn_error_t *svn_stream_contents_same(svn_boolean_t *same, svn_stream_t *stream1, svn_stream_t *stream2, apr_pool_t *pool){ char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); apr_size_t bytes_read1 = SVN__STREAM_CHUNK_SIZE; apr_size_t bytes_read2 = SVN__STREAM_CHUNK_SIZE; *same = TRUE; /* assume TRUE, until disproved below */ while (bytes_read1 == SVN__STREAM_CHUNK_SIZE && bytes_read2 == SVN__STREAM_CHUNK_SIZE) { SVN_ERR(svn_stream_read(stream1, buf1, &bytes_read1)); SVN_ERR(svn_stream_read(stream2, buf2, &bytes_read2)); if ((bytes_read1 != bytes_read2) || (memcmp(buf1, buf2, bytes_read1))) { *same = FALSE; break; } } return SVN_NO_ERROR;}/*** Generic readable empty stream ***/static svn_error_t *read_handler_empty(void *baton, char *buffer, apr_size_t *len){ *len = 0; return SVN_NO_ERROR;}static svn_error_t *write_handler_empty(void *baton, const char *data, apr_size_t *len){ return SVN_NO_ERROR;}svn_stream_t *svn_stream_empty(apr_pool_t *pool){ svn_stream_t *stream; stream = svn_stream_create(NULL, pool); svn_stream_set_read(stream, read_handler_empty); svn_stream_set_write(stream, write_handler_empty); return stream;}/*** Ownership detaching stream ***/static svn_error_t *read_handler_disown(void *baton, char *buffer, apr_size_t *len){ return svn_stream_read((svn_stream_t *)baton, buffer, len);}static svn_error_t *write_handler_disown(void *baton, const char *buffer, apr_size_t *len){ return svn_stream_write((svn_stream_t *)baton, buffer, len);}svn_stream_t *svn_stream_disown(svn_stream_t *stream, apr_pool_t *pool){ svn_stream_t *s = svn_stream_create(stream, pool); svn_stream_set_read(s, read_handler_disown); svn_stream_set_write(s, write_handler_disown); return s;}/*** Generic stream for APR files ***/struct baton_apr { apr_file_t *file; apr_pool_t *pool;};static svn_error_t *read_handler_apr(void *baton, char *buffer, apr_size_t *len){ struct baton_apr *btn = baton; svn_error_t *err; err = svn_io_file_read_full(btn->file, buffer, *len, len, btn->pool); if (err && APR_STATUS_IS_EOF(err->apr_err)) { svn_error_clear(err); err = SVN_NO_ERROR; } return err;}static svn_error_t *write_handler_apr(void *baton, const char *data, apr_size_t *len){ struct baton_apr *btn = baton; return svn_io_file_write_full(btn->file, data, *len, len, btn->pool);}static svn_error_t *close_handler_apr(void *baton){ struct baton_apr *btn = baton; return svn_io_file_close(btn->file, btn->pool);}svn_stream_t *svn_stream_from_aprfile2(apr_file_t *file, svn_boolean_t disown, apr_pool_t *pool){ struct baton_apr *baton; svn_stream_t *stream; if (file == NULL) return svn_stream_empty(pool); baton = apr_palloc(pool, sizeof(*baton)); baton->file = file; baton->pool = pool; stream = svn_stream_create(baton, pool); svn_stream_set_read(stream, read_handler_apr); svn_stream_set_write(stream, write_handler_apr); if (! disown) svn_stream_set_close(stream, close_handler_apr); return stream;}svn_stream_t *svn_stream_from_aprfile(apr_file_t *file, apr_pool_t *pool){ return svn_stream_from_aprfile2(file, TRUE, pool);}/* Compressed stream support */#ifdef SVN_HAVE_ZLIB#define ZBUFFER_SIZE 4096 /* The size of the buffer the compressed stream uses to read from the substream. Basically an arbitrary value, picked to be about page-sized. */struct zbaton { z_stream *in; /* compressed stream for reading */ z_stream *out; /* compressed stream for writing */ svn_read_fn_t read; /* substream's read function */ svn_write_fn_t write; /* substream's write function */ svn_close_fn_t close; /* substream's close function */ void *read_buffer; /* buffer used for reading from substream */ int read_flush; /* what flush mode to use while reading */ apr_pool_t *pool; /* The pool this baton is allocated on */ void *subbaton; /* The substream's baton */};/* zlib alloc function. opaque is the pool we need. */static voidpfzalloc(voidpf opaque, uInt items, uInt size){ apr_pool_t *pool = opaque; return apr_palloc(pool, items * size);}/* zlib free function */static voidzfree(voidpf opaque, voidpf address){ /* Empty, since we allocate on the pool */}/* Converts a zlib error to an svn_error_t. zerr is the error code, function is the function name, and stream is the z_stream we are using. */static svn_error_t *zerr_to_svn_error(int zerr, const char *function, z_stream *stream){ apr_status_t status; const char *message; if (zerr == Z_OK)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -