/*
 * steghide 0.5.1 - a steganography program
 * Copyright (C) 1999-2003 Stefan Hetzl <shetzl@chello.at>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

#ifndef SH_BITSTRING_H
#define SH_BITSTRING_H

#include <vector>
#include <string>

#include "AUtils.h"
#include "common.h"

/**
 * \class BitString
 * \brief a string of bits
 *
 * This class provides a way to conveniently store and
 * manipulate a string of bits. Various objects can be
 * appended to a BitString.
 * 
 * For data storage a vector of BYTEs is used with little
 * endian bit encoding, i.e. the first bit is the least
 * significant bit of the first byte and so on.
 **/
class BitString {
	public:
	/**
	 * construct an empty BitString
	 **/
	BitString (EmbValue arity = 2) ;
	
	/**
	 * copy constructor
	 **/
	BitString (const BitString& bs) ;
	
	/**
	 * construct a BitString containing l bits with value zero
	 **/
	BitString (const unsigned long l) ;
	
	/**
	 * construct a BitString containing the data in d
	 **/
	BitString (const std::vector<BYTE>& d) ;
	
	/**
	 * construct a BitString containing the characters in d as 8 bit unsigned chars
	 **/
	BitString (const std::string& d) ;

	void setArity (EmbValue arity) ;

	EmbValue getArity (void) const
		{ return Arity ; } ;

	/**
	 * get the number of bits in this BitString
	 **/
	UWORD32 getLength (void) const
		{ return Length ; } ;

	/**
	 * get the number of EmbValues in this BitString (using this BitString's arity)
	 **/
	UWORD32 getNAryLength (void) const
		{ return AUtils::div_roundup<UWORD32> (Length, ArityNBits) ; } ;

	/**
	 * delete the contents of this Bitstring
	 **/
	BitString& clear (void) ;

	/**
	 * append the bit v to this BitString
	 **/
	BitString& append (const BIT v) ;

	/**
	 * append n lower order bits of v to this BitString
	 * \param v the value to be appended
	 * \param n the number of bits to be appended
	 **/
	BitString& append (const BYTE v, const unsigned short n = 8) ;
	
	/**
	 * append n lower order bits of v to this BitString
	 * \param v the value to be appended
	 * \param n the number of bits to be appended
	 **/
	BitString& append (const UWORD16 v, const unsigned short n = 16) ;
	
	/**
	 * append n lower order bits of v to this BitString
	 * \param v the value to be appended
	 * \param n the number of bits to be appended
	 **/
	BitString& append (const UWORD32 v, const unsigned short n = 32) ;
	
	/**
	 * append the string v to this BitString
	 **/
	BitString& append (const std::string& v) ;

	/**
	 * append the vector v byte-wise to this BitString
	 **/
	BitString& append (const std::vector<BYTE>& v) ;

	/**
	 * append the BitString v to this BitString
	 * \param v the BitString to be appended
	 **/
	BitString& append (const BitString& v) ;

	/**
	 * set the p-th bit to v
	 * \param i the index (must be < getLength())
	 * \param v the value
	 **/
	BitString& setBit (unsigned long i, BIT v) ;

	/**
	 * get a BitString that is a part of this BitString
	 * \param s the index of the first bit to be copied from this BitString
	 * \param l the total number of bits to be used for the return value
	 * \return the BitString containing of the bits [s...s+(l-1)] of this BitString
	 **/
	BitString getBits (const unsigned long s, const unsigned long l) const ;

	/**
	 * cut some bits out of this BitString
	 * \param s the index of the first bit to be removed from this BitString
	 * \param l the total number of bits to be removed
	 * \return the BitString containing of the bits [s...s+(l-1)] of this BitString
	 *
	 * After calling cutBits, this BitString consists of the bits 0,...,s-1,s+l,... .
	 **/
	BitString cutBits (const unsigned long s, const unsigned long l) ;

	/**
	 * return a value composed from bits in this BitString
	 * \param s the index of the first bit to be used for the return value
	 * \param l the total number of bits to be used for the return value (must be <= 32)
	 * \return the value (*this)[s],...,(*this)[s+l-1]
	 **/
	UWORD32 getValue (const unsigned long s, const unsigned short l) const ;

	/**
	 * get the contents of this BitString as vector of bytes
	 * \return the contents of this BitString as vector of bytes
	 *
	 * getLength() % 8 must be 0 to call this function
	 **/
	const std::vector<BYTE>& getBytes (void) const ;

	/**
	 * truncate this BitString
	 * \param s start
	 * \param e end
	 * \return this BitString modified to contain only (*this)[s]...(*this)[e - 1]
	 **/
	BitString& truncate (const unsigned long s, const unsigned long e) ;

	/**
	 * pad this BitString with the value in v
	 * \param mult this BitString is padded until size is a multiple of mult (given in bits)
	 * \param v the value this BitString should be padded with
	 **/
	BitString& pad (const unsigned long mult, const BIT v) ;

	/**
	 * pad this BitString with random data
	 * \param mult this BitString is padded until size is a multiple of mult (given in bits)
	 **/
	BitString& padRandom (const unsigned long mult) ;

	/**
	 * get an n-ary digit from this BitString
	 * \param p the position (in the n-ary representation of this BitString)
	 * \return the p-th n-ary digit
	 **/
	BYTE getNAry (unsigned long p) const ;

	/**
	 * append an n-ary digit to this BitString
	 * \param v the n-ary value to be appended
	 **/
	void appendNAry (BYTE v) ;

	/**
	 * compress this BitString using zlib's compress2 function
	 * \param level the compression level (ranging from 1 (best speed) to 9 (best compression)
	 *
	 * As zlib operates on byte vectors and not on bit vectors, this BitString is padded
	 * with zeros until the next byte boundary before starting the compression.
	 **/
	BitString& compress (int level) ;

	/**
	 * uncompress this BitString using zlib's uncompress function
	 * \param idestlen the length of the uncompressed data (in bits)
	 * \return this BitString modified to contain exactly idestlen uncompressed bits
	 *
	 * idestlen must be the size of the uncompressed data (in bits) to make
	 * it possible to allocate a destination buffer and to give information
	 * about the length of the uncompressed data without padding.
	 *
	 * A precondition for calling this function is that this BitString actually
	 * contains data that has been compressed by the BitString::compress function,
	 * and especially that the Length % 8 is 0.
	 **/
	BitString& uncompress (unsigned long idestlen) ;

	/**
	 * get the value of the i-th bit
	 **/
	BIT operator[] (const unsigned long i) const ;

	/**
	 * xor v with this BitString, saving the result in this Bitstring.
	 * The result has the same length as this BitString.
	 **/
	BitString& operator^= (const BitString &v) ;

	/**
	 * compare this BitString with the BitString v
	 * \return true iff the lengths are equal and for every valid index the value is equal
	 **/
	bool operator== (const BitString& v) const ;

	/**
	 * compare this BitString with the BitString v
	 * \return true iff the lengths are not equal or there exists an index with different values
	 **/
	bool operator!= (const BitString& v) const ;

	void print (unsigned short spc = 0) const ;
#ifdef DEBUG
	void printDebug (unsigned short level, unsigned short spc = 0) const ;
#endif

	private:
	/// the number of bits in Data
	UWORD32 Length ;
	/// the arity that will be used for getLength/getNAry/appendNAry
	EmbValue Arity ;
	/// the number of Bits per n-ary digit (where n is Arity)
	unsigned short ArityNBits ;
	/// the actual data
	std::vector<BYTE> Data ;

	void _append (BIT v) ;

	/**
	 * clear unused part of last byte (_append depends on this)
	 **/
	void clearUnused (void) ;
} ;

#endif // ndef SH_BITSTRING_H
