text: /*
     +----------------------------------------------------------------------+
     | PHP Version 5                                                        |
     +----------------------------------------------------------------------+
     | Copyright (c) 1997-2010 The PHP Group                                |
     +----------------------------------------------------------------------+
     | This source file is subject to version 3.01 of the PHP license,      |
     | that is bundled with this package in the file LICENSE, and is        |
     | available through the world-wide-web at the following url:           |
     | http://www.php.net/license/3_01.txt                                  |
     | If you did not receive a copy of the PHP license and are unable to   |
     | obtain it through the world-wide-web, please send a note to          |
     | license@php.net so we can mail you a copy immediately.               |
     +----------------------------------------------------------------------+
     | Author: Wez Furlong <wez@thebrainroom.com>, based on work by:        |
     |         Hartmut Holzgraefe <hholzgra@php.net>                        |
     +----------------------------------------------------------------------+
   */
  
  /* $Id: zlib_fopen_wrapper.c 293036 2010-01-03 09:23:27Z sebastian $ */
  
  #define _GNU_SOURCE
  
  #include "php.h"
  #include "php_zlib.h"
  #include "fopen_wrappers.h"
  
  struct php_gz_stream_data_t	{
  	gzFile gz_file;
  	php_stream *stream;
  };
  
  static size_t php_gziop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
  {
  	struct php_gz_stream_data_t *self = (struct php_gz_stream_data_t *) stream->abstract;
  	int read;
  	
  	read = gzread(self->gz_file, buf, count);
  	
  	if (gzeof(self->gz_file)) {
  		stream->eof = 1;
  	}
  		
  	return (read < 0) ? 0 : read;
  }
  
  static size_t php_gziop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
  {
  	struct php_gz_stream_data_t *self = (struct php_gz_stream_data_t *) stream->abstract;
  	int wrote;
  
  	wrote = gzwrite(self->gz_file, (char *) buf, count);
  
  	return (wrote < 0) ? 0 : wrote;
  }
  
  static int php_gziop_seek(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC)
  {
  	struct php_gz_stream_data_t *self = (struct php_gz_stream_data_t *) stream->abstract;
  
  	assert(self != NULL);
  
  	if (whence == SEEK_END) {
  		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SEEK_END is not supported");
  		return -1;
  	}
  	*newoffs = gzseek(self->gz_file, offset, whence);
  
  	return (*newoffs < 0) ? -1 : 0;
  }
  
  static int php_gziop_close(php_stream *stream, int close_handle TSRMLS_DC)
  {
  	struct php_gz_stream_data_t *self = (struct php_gz_stream_data_t *) stream->abstract;
  	int ret = EOF;
  	
  	if (close_handle) {
  		if (self->gz_file) {
  			ret = gzclose(self->gz_file);
  			self->gz_file = NULL;
  		}
  		if (self->stream) {
  			php_stream_close(self->stream);
  			self->stream = NULL;
  		}
  	}
  	efree(self);
  
  	return ret;
  }
  
  static int php_gziop_flush(php_stream *stream TSRMLS_DC)
  {
  	struct php_gz_stream_data_t *self = (struct php_gz_stream_data_t *) stream->abstract;
  
  	return gzflush(self->gz_file, Z_SYNC_FLUSH);
  }
  
  static php_stream_ops php_stream_gzio_ops = {
  	php_gziop_write, php_gziop_read,
  	php_gziop_close, php_gziop_flush,
  	"ZLIB",
  	php_gziop_seek, 
  	NULL, /* cast */
  	NULL, /* stat */
  	NULL  /* set_option */
  };
  
  php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, char *path, char *mode, int options, 
  							  char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
  {
  	struct php_gz_stream_data_t *self = {0};
  	php_stream *stream = NULL, *innerstream = NULL;
  
  	/* sanity check the stream: it can be either read-only or write-only */
  	if (strchr(mode, '+')) {
  		if (options & REPORT_ERRORS) {
  			php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot open a zlib stream for reading and writing at the same time!");
  		}
  		return NULL;
  	}
  	
  	self = emalloc(sizeof(*self));
  
  	if (strncasecmp("compress.zlib://", path, 16) == 0) {
  		path += 16;
  	} else if (strncasecmp("zlib:", path, 5) == 0) {
  		path += 5;
  	}
  	
  	innerstream = php_stream_open_wrapper(path, mode, STREAM_MUST_SEEK | options | STREAM_WILL_CAST, opened_path);
  	
  	if (innerstream) {
  		int fd;
  
  		if (SUCCESS == php_stream_cast(innerstream, PHP_STREAM_AS_FD, (void **) &fd, REPORT_ERRORS)) {
  			self->gz_file = gzdopen(dup(fd), mode);
  			self->stream = innerstream;
  			if (self->gz_file)	{
  				stream = php_stream_alloc_rel(&php_stream_gzio_ops, self, 0, mode);
  				if (stream) {
  					stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
  					return stream;
  				}
  				gzclose(self->gz_file);
  			}
  			if (options & REPORT_ERRORS) {
  				php_error_docref(NULL TSRMLS_CC, E_WARNING, "gzopen failed");
  			}
  		} else if (innerstream) {
  			php_stream_close(innerstream);
  		}
  	}
  
  	if (stream) {
  		php_stream_close(stream);
  	}
  	
  	if (self) {
  		efree(self);
  	}
  	
  	return NULL;
  }
  
  static php_stream_wrapper_ops gzip_stream_wops = {
  	php_stream_gzopen,
  	NULL, /* close */
  	NULL, /* stat */
  	NULL, /* stat_url */
  	NULL, /* opendir */
  	"ZLIB",
  	NULL, /* unlink */
  	NULL, /* rename */
  	NULL, /* mkdir */
  	NULL  /* rmdir */
  };
  
  php_stream_wrapper php_stream_gzip_wrapper =	{
  	&gzip_stream_wops,
  	NULL,
  	0, /* is_url */
  };
  
  /*
   * Local variables:
   * tab-width: 4
   * c-basic-offset: 4
   * End:
   * vim600: noet sw=4 ts=4 fdm=marker
   * vim<600: noet sw=4 ts=4
   */
  