示例#1
0
文件: buffer.c 项目: gokzy/netbsd-src
/* Get a new buffer_data structure.  */
static struct buffer_data *
get_buffer_data (void)
{
    struct buffer_data *ret;

    ret = xmalloc (sizeof (struct buffer_data));
    ret->text = pagealign_xalloc (BUFFER_DATA_SIZE);

    return ret;
}
示例#2
0
/* Flush a compression buffer.  */
static int
compress_buffer_flush (void *closure)
{
    struct compress_buffer *cb = closure;

    /* This is only used within the while loop below, but allocated here for
     * efficiency.
     */
    static char *buffer = NULL;
    if (!buffer)
	buffer = pagealign_xalloc (BUFFER_DATA_SIZE);

    cb->zstr.avail_in = 0;
    cb->zstr.next_in = NULL;

    while (1)
    {
	int zstatus;

	cb->zstr.avail_out = BUFFER_DATA_SIZE;
	cb->zstr.next_out = (unsigned char *) buffer;

	zstatus = deflate (&cb->zstr, Z_SYNC_FLUSH);

	/* The deflate function will return Z_BUF_ERROR if it can't do
           anything, which in this case means that all data has been
           flushed.  */
	if (zstatus == Z_BUF_ERROR)
	    break;

	if (zstatus != Z_OK)
	{
	    compress_error (0, zstatus, &cb->zstr, "deflate flush");
	    return EIO;
	}

	if (cb->zstr.avail_out != BUFFER_DATA_SIZE)
	    buf_output (cb->buf, buffer,
			BUFFER_DATA_SIZE - cb->zstr.avail_out);

	/* If the deflate function did not fill the output buffer,
           then all data has been flushed.  */
	if (cb->zstr.avail_out > 0)
	    break;
    }

    /* Now flush the underlying buffer.  Note that if the original
       call to buf_flush passed 1 for the BLOCK argument, then the
       buffer will already have been set into blocking mode, so we
       should always pass 0 here.  */
    return buf_flush (cb->buf, 0);
}
示例#3
0
/* Output data to a compression buffer.
 *
 * GLOBALS
 *   gzip_level		If GZIP_LEVEL has changed to a value different from
 *			CLOSURE->level, then set the compression level on the
 *			stream to the new value.
 */
static int
compress_buffer_output (void *closure, const char *data, size_t have,
			size_t *wrote)
{
    struct compress_buffer *cb = closure;

    /* This is only used within the while loop below, but allocated here for
     * efficiency.
     */
    static char *buffer = NULL;
    if (!buffer)
	buffer = pagealign_xalloc (BUFFER_DATA_SIZE);

    if (cb->level != gzip_level)
    {
	cb->level = gzip_level;
	deflateParams (&cb->zstr, gzip_level, Z_DEFAULT_STRATEGY);
    }

    cb->zstr.avail_in = have;
    cb->zstr.next_in = (unsigned char *) data;

    while (cb->zstr.avail_in > 0)
    {
	int zstatus;

	cb->zstr.avail_out = BUFFER_DATA_SIZE;
	cb->zstr.next_out = (unsigned char *) buffer;

	zstatus = deflate (&cb->zstr, Z_NO_FLUSH);
	if (zstatus != Z_OK)
	{
	    compress_error (0, zstatus, &cb->zstr, "deflate");
	    return EIO;
	}

	if (cb->zstr.avail_out != BUFFER_DATA_SIZE)
	    buf_output (cb->buf, buffer,
			BUFFER_DATA_SIZE - cb->zstr.avail_out);
    }

    *wrote = have;

    /* We will only be here because buf_send_output was called on the
       compression buffer.  That means that we should now call
       buf_send_output on the underlying buffer.  */
    return buf_send_output (cb->buf);
}
示例#4
0
/* Shut down an output buffer.  */
static int
compress_buffer_shutdown_output (struct buffer *buf)
{
    struct compress_buffer *cb = buf->closure;
    int zstatus, status;

    /* This is only used within the while loop below, but allocated here for
     * efficiency.
     */
    static char *buffer = NULL;
    if (!buffer)
	buffer = pagealign_xalloc (BUFFER_DATA_SIZE);

    do
    {
	cb->zstr.avail_out = BUFFER_DATA_SIZE;
	cb->zstr.next_out = (unsigned char *) buffer;

	zstatus = deflate (&cb->zstr, Z_FINISH);
	if (zstatus != Z_OK && zstatus != Z_STREAM_END)
	{
	    compress_error (0, zstatus, &cb->zstr, "deflate finish");
	    return EIO;
	}

	if (cb->zstr.avail_out != BUFFER_DATA_SIZE)
	    buf_output (cb->buf, buffer,
			BUFFER_DATA_SIZE - cb->zstr.avail_out);
    } while (zstatus != Z_STREAM_END);

    zstatus = deflateEnd (&cb->zstr);
    if (zstatus != Z_OK)
    {
	compress_error (0, zstatus, &cb->zstr, "deflateEnd");
	return EIO;
    }

    status = buf_flush (cb->buf, 1);
    if (status != 0)
	return status;

    return buf_shutdown (cb->buf);
}
示例#5
0
/* Input data from a compression buffer.  */
static int
compress_buffer_input (void *closure, char *data, size_t need, size_t size,
		       size_t *got)
{
    struct compress_buffer *cb = closure;
    struct buffer_data *bd;

    assert (cb->buf->input);

    /* We use a single buffer_data structure to buffer up data which
       the z_stream structure won't use yet.  We can safely store this
       on cb->buf->data, because we never call the buffer routines on
       cb->buf; we only call the buffer input routine, since that
       gives us the semantics we want.  As noted in
       compress_buffer_initialize, the buffer_data structure may
       already exist, and hold data which was already read and
       buffered before the decompression began.  */
    bd = cb->buf->data;
    if (bd == NULL)
    {
	bd = xmalloc (sizeof (struct buffer_data));
	if (bd == NULL)
	    return -2;
	bd->text = pagealign_xalloc (BUFFER_DATA_SIZE);
	if (bd->text == NULL)
	{
	    free (bd);
	    return -2;
	}
	bd->bufp = bd->text;
	bd->size = 0;
	cb->buf->data = bd;
    }

    cb->zstr.avail_out = size;
    cb->zstr.next_out = (Bytef *) data;

    while (1)
    {
	int zstatus, sofar, status;
	size_t nread;

	/* First try to inflate any data we already have buffered up.
	   This is useful even if we don't have any buffered data,
	   because there may be data buffered inside the z_stream
	   structure.  */

	cb->zstr.avail_in = bd->size;
	cb->zstr.next_in = (Bytef *) bd->bufp;

	do
	{
	    zstatus = inflate (&cb->zstr, Z_NO_FLUSH);
	    if (zstatus == Z_STREAM_END)
		break;
	    if (zstatus != Z_OK && zstatus != Z_BUF_ERROR)
	    {
		compress_error (0, zstatus, &cb->zstr, "inflate");
		return EIO;
	    }
	} while (cb->zstr.avail_in > 0
		 && cb->zstr.avail_out > 0);

	bd->size = cb->zstr.avail_in;
	bd->bufp = (char *) cb->zstr.next_in;

	sofar = size - cb->zstr.avail_out;

	if (zstatus == Z_STREAM_END)
	{
	    /* If we read any data, then return it, relying on the fact that
	     * we will get Z_STREAM_END on the next read too.
	     */
	    if (sofar > 0) break;

	    /* Otherwise, return EOF.  */
	    return -1;
	}

	/* If we have obtained NEED bytes, then return, unless NEED is
           zero and we haven't obtained anything at all.  If NEED is
           zero, we will attempt at least one nonblocking read and see if
	   we can inflate anything then.  */
	if (sofar > 0 && sofar >= need)
	    break;

	/* All our buffered data should have been processed at this
           point.  */
	assert (bd->size == 0);

	/* This will work well in the server, because this call will
	   do an unblocked read and fetch all the available data.  In
	   the client, this will read a single byte from the stdio
	   stream, which will cause us to call inflate once per byte.
	   It would be more efficient if we could make a call which
	   would fetch all the available bytes, and at least one byte.  */

	status = (*cb->buf->input) (cb->buf->closure, bd->text,
				    need > 0 ? 1 : 0, BUFFER_DATA_SIZE, &nread);

	if (status == -2)
	    /* Don't try to recover from memory allcoation errors.  */
	    return status;

	if (status != 0)
	{
	    /* If we read any data, then return it, relying on the fact that
	     * we will get the same error reading the underlying buffer
	     * on the next read too.
	     */
	    if (sofar > 0) break;

	    /* Otherwise, return EOF.  */
	    return status;
	}

	/* If we didn't read anything, then presumably the buffer is
           in nonblocking mode, and we should just get out now with
           whatever we've inflated.  */
	if (nread == 0)
	{
	    assert (need == 0);
	    break;
	}

	bd->bufp = bd->text;
	bd->size = nread;
    }

    *got = size - cb->zstr.avail_out;

    return 0;
}