//
// $Id: GzipOutStream.h,v 1.13 2007/03/06 20:42:19 will_mason Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004-2007
 * Will Mason
 *
 * Portions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Copyright (c) 1996,1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Copyright (c) 1997
 * Moscow Center for SPARC Technology
 *
 * Copyright (c) 1999 
 * Boris Fomitchev
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * You may contact the author at will_mason@users.sourceforge.net.
 */

#if !defined(GZIPOUTSTREAM_OL_GUARD)
#define GZIPOUTSTREAM_OL_GUARD

#include <ObjectiveLib/ZlibOutStream.h>

@class OLDataOutStream;

/**
 * @class OLGzipOutStream GzipOutStream.h ObjecitveLib/GzipOutStream.h
 *
 * A stream for zlib compression that writes data in the gzip format.
 * The data are written using the format described in
 * <a href=http://www.faqs.org/rfcs/rfc1952.html>RFC 1952</a>, and can be read
 * by the command-line tool @c gzip.
 *
 * @sa OLGzipInStream, OLZlibOutStream
 *
 * @ingroup Streams
 */
@interface OLGzipOutStream : OLZlibOutStream
{
@protected
    /**
     * The CRC-32 value of the data
     */
    uint32_t            crc;

    /**
     * The gzip comment
     */
    uint8_t*            commentData;

    /**
     * The original file name associated with the data
     */
    uint8_t*            fileNameData;

    /**
     * The modification time
     */
    uint32_t            modTime;

    /**
     * The extra fields
     */
    OLDataOutStream*    extraFields;

    /**
     * Whether the header has been written
     */
    BOOL                headerWritten;

    /**
     * Whether the trailer has been written
     */
    BOOL                trailerWritten;
}

+ (id) streamWithOutStream: (OLOutStream*)underStream;
+ (id) streamWithOutStream: (OLOutStream*)underStream compressionLevel: (int)level;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
/**
 * Initialize the compression stream. The the given compression level and
 * buffer size. The given out stream
 * @a underStream is the next lower stream in the stream stack. If @a zlibHeader is
 * YES, then the zlib header will be written to the stream, otherwise it will not be
 * written.
 *
 * @attention You probably do not want to use this initializer. This initializer is
 * overriden so that the argument @a zlibHeader will always be NO, as the gzip data
 * format cannot be used with the zlib header.
 *
 * @pre The indicated compression level must be in the range [0,9].
 *
 * @if OL_NO_OPENSTEP
 * @exception OLInvalidArgumentException if the compression level is not in the range [0,9]
 * @else
 * @exception NSInvalidArgumentException if the compression level is not in the range [0,9]
 * @endif
 * @exception OLInputOutputException if the stream cannot be created for deflation
 * @param underStream the next lower stream in the stack
 * @param level the compression level which must be in the range [0,9]
 * @param size the size of the internal buffer
 * @param zlibHeader it doesn't matter what you use, as it will be overridden
 * @return a reference to this stream
 */
- (id) initWithOutStream: (OLOutStream*)underStream compressionLevel: (int)level bufferSize: (unsigned)size writeZlibHeader: (BOOL)zlibHeader;

#if !defined(OL_NO_OPENSTEP)
- (void) dealloc;
#endif
/* @} */

/**
 * Add an extra field. The bytes in @a buf are associated with @a identifier in the
 * gzip data.
 *
 * @note If this message is sent after the first bytes have been written to the
 * stream, then adding an extra field will have no effect.
 *
 * @pre The length of the string @a identifier must be 2.
 *
 * @exception OLInputOutputException if the length of identifier is not 2
 * @param identifier the identifier of the extra field
 * @param buf the bytes associated with the extra field
 * @param num the number of bytes in @a buffer
 */
- (void) addExtraField: (const char*)identifier withBytes: (const uint8_t*)buf count: (unsigned)num;
- (void) close;

#if defined(OL_NO_OPENSTEP)
- (void) freeStreamResources;
#endif

/**
 * Set the modification time to now. This message should be sent if a modification
 * time is desired, but there is no original file name in the data. The time is
 * set to the current time.
 *
 * @note If this message is sent after the first bytes have been written to the
 * stream, then setting the modification time will have no effect.
 */
- (void) markModificationTime;

/**
 * Set the comment of the gzip data. The string @a comment is set as the data's comment.
 *
 * @note The data in @a comment must be encoded using the ISO 8859-1 encoding as described
 * in <a href=http://www.faqs.org/rfcs/rfc1952.html>RFC 1952</a>.
 *
 * @note If this message is sent after the first bytes have been written to the
 * stream, then setting the comment will have no effect.
 *
 * @param comment the gzip data's new comment
 */
- (void) setComment: (const char*)comment;

/**
 * Set the comment of the gzip data. The string @a comment is set as the data's comment.
 *
 * @note If this message is sent after the first bytes have been written to the
 * stream, then setting the comment will have no effect.
 *
 * @param comment the gzip data's new comment
 */
- (void) setCommentText: (OLText*)comment;

/**
 * Set the original file name of the data. To preserve the original file name when
 * the data are extracted this message can be sent. Also, to set the modification
 * time of the original file name, the arguement @a mtime can be YES, in which case
 * the modification time of the gzip stream will be set to the modification time
 * of the file at @a name.
 *
 * @note The data in @a name must be encoded using the ISO 8859-1 encoding as described
 * in <a href=http://www.faqs.org/rfcs/rfc1952.html>RFC 1952</a>.
 *
 * @note If this message is sent after the first bytes have been written to the
 * stream, then setting the file name will have no effect.
 *
 * @pre The file name should not contain any directories.
 *
 * @param name the name of the original file
 * @param mtime YES if the modification time should be set, NO otherwise
 */
- (void) setOriginalFileName: (const char*)name includeModificationTime: (BOOL)mtime;

/**
 * Set the original file name of the data. To preserve the original file name when
 * the data are extracted this message can be sent. Also, to set the modification
 * time of the original file name, the arguement @a mtime can be YES, in which case
 * the modification time of the gzip stream will be set to the modification time
 * of the file at @a name.
 *
 * @note If this message is sent after the first bytes have been written to the
 * stream, then setting the file name will have no effect.
 *
 * @pre The file name should not contain any directories.
 *
 * @param name the name of the original file
 * @param mtime YES if the modification time should be set, NO otherwise
 */
- (void) setOriginalFileNameText: (OLText*)name includeModificationTime: (BOOL)mtime;
- (unsigned) writeBytes: (const uint8_t*)bytes count: (unsigned)num;

@end

#endif
