//*********************************************************************/
// dar - disk archive - a backup/restoration program
// Copyright (C) 2002-2052 Denis Corbin
//
// 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.
//
// to contact the author : dar.linux@free.fr
/*********************************************************************/
// $Id: tronconneuse.hpp,v 1.7 2004/12/07 18:04:52 edrusb Rel $
//
/*********************************************************************/
//

    /// \file tronconneuse.hpp
    /// \brief defines a block structured file.
    ///
    /// Mainly used for strong encryption.


#ifndef TRONCONNEUSE_HPP
#define TRONCONNEUSE_HPP

#include "/usr/local/include/dar/my_config.h"
#include <string>

#include "/usr/local/include/dar/infinint.hpp"
#include "/usr/local/include/dar/generic_file.hpp"

namespace libdar
{

	/// this is a partial implementation of the generic_file interface to encrypt/decrypt data block by block.

	//! This class is a pure virtual one, as several calls have to be defined by inherited classes
	//! - encrypted_block_size_for
	//! - clear_block_allocated_size_for
	//! - encrypt_data
	//! - decrypt_data
	//! .
	//! tronconneuse is either read_only or write_only, read_write is not allowed.
	//! The openning mode his mode is defined by encrupted_side's mode.
	//! In write_only no skip() is allowed, writing is sequential from the beginning of the file to the end
	//! (like writing to a pipe).
	//! In read_only all skip() functions are available.
	//! \ingroup Private
    class tronconneuse : public generic_file
    {
    public:
	    /// This is the constructor

	    //! \param[in] dialog for user interaction.
	    //! \param[in] block_size is the size of block encryption (the size of clear data encrypted toghether).
	    //! \param[in] encrypted_side where encrypted data are read from or written to.
	    //! \note that encrypted_side is not owned and destroyed by tronconneuse, it must exist during all the life of the
	    //! tronconneuse object, and is not destroyed by the tronconneuse's destructor
	tronconneuse(user_interaction & dialog, U_32 block_size, generic_file & encrypted_side);

	    /// copy constructor
	tronconneuse(const tronconneuse & ref) : generic_file(ref) { copy_from(ref); };

	    /// assignment operator
	tronconneuse & operator = (const tronconneuse & ref);

	    /// destructor
	virtual ~tronconneuse() { detruit(); };

	    /// inherited from generic_file
	bool skip(const infinint & pos);
	    /// inherited from generic_file
	bool skip_to_eof();
	    /// inherited from generic_file
	bool skip_relative(S_I x);
	    /// inherited from generic_file
	infinint get_position() { return current_position; };

	    /// in write_only mode indicate that end of file is reached

	    //! this call must be called in write mode to purge the
	    //! internal cache before deleting the object (else some data may be lost)
	    //! no further write call is allowed
	void write_end_of_file() { flush(); weof = true; };

    private:

	    /// inherited from generic_file

	    //! this protected inherited method is now private for inherited classes of tronconneuse
	S_I inherited_read(char *a, size_t size);

	    /// inherited from generic_file

	    //! this protected inherited method is now private for inherited classes of tronconneuse
	S_I inherited_write(char *a, size_t size);

    protected:
	    /// defines the size necessary to encrypt a given amount of clear data

	    //! \param[in] clear_block_size is the size of the clear block to encrypt.
	    //! \return the size of the memory to allocate to receive corresponding encrypted data.
	    //! \note this implies that encryption algorithm must always generate a fixed size encrypted block of data for
	    //! a given fixed size block of data. However, the size of the encrypted block of data may differ from
	    //! the size of the clear block of data
	virtual U_32 encrypted_block_size_for(U_32 clear_block_size) = 0;

	    /// it may be necessary by the inherited class have few more bytes allocated after the clear data given for encryption

	    //! \param[in] clear_block_size is the size in byte of the clear data that will be asked to encrypt.
	    //! \return the requested allocated buffer size (at least the size of the clear data).
	    //! \note when giving clear buffer of data of size "clear_block_size" some inherited class may requested
	    //! that a bit more of data must be allocated.
	    //! this is to avoid copying data when the algorithm needs to add some data after the
	    //! clear data before encryption.
	virtual U_32 clear_block_allocated_size_for(U_32 clear_block_size) = 0;

	    /// this method encrypts the clear data given

	    //! \param block_num is the number of the block to which correspond the given data, This is an informational field for inherited classes.
	    //! \param[in] clear_buf points to the first byte of clear data to encrypt.
	    //! \param[in] clear_size is the length in byte of data to encrypt.
	    //! \param[in] clear_allocated is the size of the allocated memory (modifiable bytes) in clear_buf.
	    //! \param[in,out] crypt_buf is the area where to put corresponding encrypted data.
	    //! \param[in] crypt_size is the allocated memory size for crypt_buf.
	    //! \return is the amount of data put in crypt_buf (<= crypt_size).
	    //! \note it must respect that : returned value = encrypted_block_size_for(clear_size argument)
	virtual U_32 encrypt_data(const infinint & block_num,
				  const char *clear_buf, const U_32 clear_size, const U_32 clear_allocated,
				  char *crypt_buf, U_32 crypt_size) = 0;

	    /// this method is for decrypts data

	    //! \param[in] block_num block number of the data to decrypt.
	    //! \param[in] crypt_buf pointer to the first byte of encrypted data.
	    //! \param[in] crypt_size size of encrypted data to decrypt.
	    //! \param[in,out] clear_buf pointer where to put clear data.
	    //! \param[in] clear_size allocated size of clear_buf.
	    //! \return is the amount of data put in clear_buf (<= clear_size)
	virtual U_32 decrypt_data(const infinint & block_num,
				  const char *crypt_buf, const U_32 crypt_size,
				  char *clear_buf, U_32 clear_size) = 0;


    private:
	infinint initial_shift;    // the initial_shift first bytes of the underlying file are not encrypted
	infinint buf_offset;       // offset of the first byte in buf
	U_32 buf_byte_data;        // number of byte of information in buf (buf_byte_data <= buf_size)
	U_32 buf_size;             // size of allocated memory for clear data in buf
	char *buf;                 // decrypted data (or data to encrypt)
	U_32 clear_block_size;     // max amount of data that will be encrypted (must stay less than buf_size)
	infinint current_position; // position of the next character to read or write
	infinint block_num;        // block number we next read or write
	generic_file *encrypted;   // generic_file where is put / get the encrypted data
	char *encrypted_buf;       // buffer of encrypted data (read or to write)
	U_32 encrypted_buf_size;   // allocated size of encrypted_buf
	bool weof;                 // whether write_end_of_file() has been called


	void detruit();
	void copy_from(const tronconneuse & ref);
	U_32 fill_buf();       // returns the position (of the next read) inside the buffer and fill the buffer with clear data
	void flush();          // flush any pending data (write mode only) to encrypted device
	void init_buf();       // initialize if necessary the various buffers that relies on inherited method values

	void position_clear2crypt(const infinint & pos, infinint & file_buf_start,
				  infinint & clear_buf_start, infinint & pos_in_buf, infinint & block_num);
	    // pos (input) is the position in the clear data
	    // file_buf_start (output) is the position of the begining of the crypted block where can be found the data
	    // file_buf_clear (output) is the position of the beginning of the corresponding clear block
	    // pos_in_buf (output) is the position in the clear block of the 'pos' offset
	    // block_num (output) is the block number we have our requested position inside

	void position_crypt2clear(const infinint & pos, infinint & clear_pos);
	    // gives the position of the next character
	    // of clear data that corresponds to the encrypted data which index is pos

	bool check_current_position() { return fill_buf() < buf_byte_data; };
	    // return true if a there is a byte of information at the given offset
    };


} // end of namespace

#endif
