
/*
 * Copyright (c) 2001-2002 Packet Design, LLC.
 * All rights reserved.
 * 
 * Subject to the following obligations and disclaimer of warranty,
 * use and redistribution of this software, in source or object code
 * forms, with or without modifications are expressly permitted by
 * Packet Design; provided, however, that:
 * 
 *    (i)  Any and all reproductions of the source or object code
 *         must include the copyright notice above and the following
 *         disclaimer of warranties; and
 *    (ii) No rights are granted, in any manner or form, to use
 *         Packet Design trademarks, including the mark "PACKET DESIGN"
 *         on advertising, endorsements, or otherwise except as such
 *         appears in the above copyright notice or in the software.
 * 
 * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
 * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
 * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
 * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
 * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
 * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
 * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
 * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
 * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Archie Cobbs <archie@freebsd.org>
 */

#ifndef _PDEL_IO_FILTER_H_
#define _PDEL_IO_FILTER_H_

/*
 * Filters
 *
 * A filter is an object that has an input side and an output side
 * and performs some kind of encoding on the data as it passes through.
 *
 * Filters are useful because they can be pushed on top of a FILE *
 * stream in order to encode or decode data.
 */

struct filter;

/***********************************************************************
			FILTER METHODS
***********************************************************************/

/*
 * Read up to 'len' bytes from a filter.
 *
 * Returns the number of bytes read, or -1 and sets errno on error.
 * Returns zero if the filter is empty and needs more data to be written in.
 */
typedef int	filter_read_t(struct filter *f, void *buf, int len);

/*
 * Write up to 'len' bytes into a filter.
 *
 * Returns the number of bytes written, or -1 and sets errno on error.
 * Returns zero if the filter is full and needs more data to be read out.
 */ 
typedef int	filter_write_t(struct filter *f, const void *data, int len);

/*
 * Indicate to a filter that no more data is to be written.
 *
 * Returns zero if successful, or -1 and sets errno on error.
 * Once this is called, the write method will return -1 and errno = EPIPE.
 */
typedef int	filter_end_t(struct filter *f);

/*
 * Convert the number of bytes of input vs. output.
 *
 * If 'forward' is true, this should return an upper bound on the
 * number of bytes of that 'num' bytes of input will generate.
 * Otherwise, this should return an upper bound on the number of bytes
 * of input that would be required to generate 'num' (or more) bytes
 * of output.
 */
typedef int	filter_convert_t(struct filter *f, int num, int forward);

/*
 * Destroy a filter.
 *
 * This method must do two things:
 *	(a) Free all resources associated with the filter *fp
 *	(b) Set *fp to NULL
 *
 * If *fp is already equal to NULL, this method must do nothing.
 */
typedef void	filter_destroy_t(struct filter **fp);

/***********************************************************************
			FILTER STRUCTURE
***********************************************************************/

/* Filter object structure */
struct filter {
	filter_read_t		*read;		/* read data out of filter */
	filter_write_t		*write;		/* write data into filter */
	filter_end_t		*end;		/* signal end of data */
	filter_convert_t	*convert;	/* map # bytes in <-> out */
	filter_destroy_t	*destroy;	/* destroy filter */
	void			*private;	/* object private data */
};

/***********************************************************************
			FILTER LIBRARY ROUTINES
***********************************************************************/

__BEGIN_DECLS

#ifndef _KERNEL

/*
 * Given a read-only or write-only stream, return another stream
 * that reads or writes data from the supplied stream using
 * the filter. In other words, in the returned stream, the filter
 * is sitting on top of the supplied stream.
 *
 * When the stream is closed, the underlying stream is closed unless
 * the FILTER_NO_CLOSE_STREAM flag was given, and the filter is destroyed
 * unless the FILTER_NO_DESTROY_FILTER flags was given.
 *
 * Returns NULL and sets errno on error.
 */
#define FILTER_NO_CLOSE_STREAM		0x01	/* fclose() doesn't close fp */
#define FILTER_NO_DESTROY_FILTER	0x02	/* fclose() doesn't rm filter */

extern FILE	*filter_fopen(struct filter *filter, int flags,
			FILE *fp, const char *mode);

#endif	/* !_KERNEL */

/*
 * Filter data in memory using a filter.
 *
 * The filtered data is in *outputp and the length of the data is returned.
 * *outputp is guaranteed to have one extra byte allocated and set to zero.
 * If 'final' is non-zero then the write side of the filter is closed.
 *
 * Returns -1 and sets errno on error.
 */
extern int	filter_process(struct filter *filter, const void *input,
			int len, int final, u_char **outputp,
			const char *mtype);

/*
 * Wrappers for the filter methods.
 */
extern filter_read_t	filter_read;
extern filter_write_t	filter_write;
extern filter_end_t	filter_end;
extern filter_convert_t	filter_convert;
extern filter_destroy_t	filter_destroy;

__END_DECLS

#endif	/* _PDEL_IO_FILTER_H_ */

