📄 stream.c
字号:
/*
* stream.c: svn_stream operations
*
* ====================================================================
* Copyright (c) 2000-2004 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>
#ifdef SVN_HAVE_ZLIB
#include <zlib.h>
#endif
#include "svn_pools.h"
#include "svn_io.h"
#include "svn_error.h"
#include "svn_string.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;
}
void
svn_stream_set_baton (svn_stream_t *stream, void *baton)
{
stream->baton = baton;
}
void
svn_stream_set_read (svn_stream_t *stream, svn_read_fn_t read_fn)
{
stream->read_fn = read_fn;
}
void
svn_stream_set_write (svn_stream_t *stream, svn_write_fn_t write_fn)
{
stream->write_fn = write_fn;
}
void
svn_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_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[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 = sizeof (buf);
SVN_ERR (svn_stream_read (from, buf, &len));
if (len > 0)
SVN_ERR (svn_stream_write (to, buf, &len));
if (len != sizeof (buf))
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;
}
/*** 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);
}
svn_stream_t *
svn_stream_from_aprfile (apr_file_t *file, 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);
return stream;
}
/* 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 voidpf
zalloc(voidpf opaque, uInt items, uInt size)
{
apr_pool_t *pool = opaque;
return apr_palloc(pool, items * size);
}
/* zlib free function */
static void
zfree(voidpf opaque, voidpf address)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -