/*
* Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
* Declares all classes used to decode ASN.1 data, including the 
* base interface.
*
*/




/**
 @file
 @publishedAll
 @released
*/

#ifndef __ASN1ENC_H__
#define __ASN1ENC_H__

#include <e32base.h>
#include <asn1cons.h>

class CASN1EncBase;
class TASN1EncBase128DER;

class TInteger;

typedef void (CASN1EncBase::* WriteFunc)(TDes8& aBuf) const;

/**
 * Base class for all ASN.1 types that we can encode.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncBase : public CBase
	{
public:
	/**
	 * Gives total number of octets in the DER encoding of this 
	 * object.
	 * @return Number of octets in DER encoding of this object.
	 */
	IMPORT_C TUint LengthDER() const;
	
	/**
	 * Writes entire DER encoding of this object into the given 
	 * buffer.
	 * @param aBuf Buffer receiving the encoding.
	 * @param aPos Position to start writing at.
	 */
	IMPORT_C void WriteDERL(TDes8& aBuf, TUint& aPos) const;

	/**
	 * Sets tag type/class of the encoding object
	 * @param aType Tag type to set
	 * @param aClass Tag class to set.
	 */
	IMPORT_C void SetTag(const TTagType aType,
		const TASN1Class aClass = EContextSpecific);

	IMPORT_C ~CASN1EncBase();

	/**
	 * @internalComponent
	 * 
	 * Sets parent for the object
	 * @param aParent Pointer to an ASN.1 object that becomes this 
	 *     object's parent.
	 */
	void SetParent(CASN1EncBase* aParent);

protected:
	/**
	 * Protected constructor
	 * @param aType Tag type of the new object
	 * @param aClass Tag class of the new object.
	 */
	IMPORT_C CASN1EncBase(const TTagType aType, const TASN1Class aClass);

	/** 
	 * Must call this version from derived classes in their 
	 * ConstructL, but only once they're ready to have 
	 * CalculateContentsLengthDER called on them.
	 */
	IMPORT_C virtual void ConstructL();

	/**
	 * @internalComponent
	 *
	 * Derived classes must call this if the length of their 
	 * contents changes after construction.
	 */
	void ContentsLengthChanged();

protected:
	/** 
	 * @internalComponent
	 * 
	 * Calculates number of octets in DER length encoding. Must set 
	 * value of the appropriate data member. Made protected because it is 
	 * needed by CASN1EncEncoding class.
	 */
	void CalculateLengthLengthDER();

private:
	/** 
	 * Calculates number of octets in DER tag encoding. Must set 
	 * value of the appropriate data member.
	 */
	void CalculateTagLengthDER();

	/** 
	 * Calculates number of octets in DER content encoding. Must set 
	 * value of the appropriate data member.
	 */
	virtual void CalculateContentsLengthDER() = 0;

	virtual TBool IsConstructed() const = 0;
	
	// Write the octet data in each section
	// Note that buffer *will* be big enough: these are called only 
	// after checking.

	/** 
	 * Writes DER tag encoding into supplied buffer, which is 
	 * already verified to be big enough.
	 * @param aBuf Buffer to write to.
	 */
	void WriteTagDERL(TDes8& aBuf) const;

	/** 
	 * Writes DER length encoding into supplied buffer, which is 
	 * already verified to be big enough.
	 * @param aBuf Buffer to write to.
	 */
	virtual void WriteLengthDER(TDes8& aBuf) const;

	/** 
	 * Writes DER content encoding into supplied buffer, which is 
	 * already verified to be big enough. Must be implemented by 
	 * derived classes.
	 * @param aBuf Buffer to write to.
	 */
	virtual void WriteContentsDERL(TDes8& aBuf) const = 0;

	/** 
	 * Helper function, used for efficiency
	 * @param aBuf Buffer to write to
	 * @param aPos Position in the buffer to start writing at 
	 *     (updated on exit)
	 * @param aLength Length of data to write
	 * @param aWriteFunc Points to the function used to perform 
	 *     the actual write operation.
	 */
	void WriteHelperL(TDes8& aBuf, TUint& aPos, const TUint aLength,
		WriteFunc aWriteFunc) const;

protected:
	// Cached length data - data set from the CalculateXxxx methods above
	TUint iTagLengthDER; ///< Length of DER encoded tag
	TUint iLengthLengthDER; ///< Length of DER encoded length
	TUint iContentsLengthDER; ///< Length of DER encoded content

private:
	/** 
	 * The object owning this one (if we're held in a sequence, 
	 * for example).
	 */
	CASN1EncBase* iParent;

	// Tag data
	TTagType iType; ///< Tag type of this object
	TASN1Class iClass; ///< Tag class of this object
	};


/** 
 * Base class for all ASN1 constructed-type objects.  Most of these 
 * are container classes, but another type is the explicit-tagging 
 * wrapper object.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncConstructed : public CASN1EncBase
	{
protected:
	/** 
	 * @internalComponent
	 * 
	 * Protected constructor
	 * @param aType Tag type for the new object
	 * @param aClass Tag class for the new object.
	 */
	CASN1EncConstructed(const TTagType aType, const TASN1Class aClass);

private:
	virtual const CASN1EncBase& Child(const TUint aIndex) const = 0;
	virtual TUint NumChildren() const = 0;

private:
	// From CASN1EncBase
	void CalculateContentsLengthDER();
	TBool IsConstructed() const;
	void WriteContentsDERL(TDes8& aBuf) const;
	};


/** 
 * Class used to wrap other encoding objects in order to give 
 * them an explicit tag.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncExplicitTag : public CASN1EncConstructed
	{
public:
	/** 
	 * Takes ownership of the encoder, *including* the case when
	 * this method leaves.
	 * @param aEncoder ASN.1 encoding object to wrap
	 * @param aType Tag type to assign
	 * @param aClass Tag class to assign
	 * @return Wrapped encoding object pushed on the cleanup stack.
	 */
	IMPORT_C static CASN1EncExplicitTag* NewLC(CASN1EncBase* aEncoder,
		const TTagType aType, const TASN1Class aClass = EContextSpecific);

	/** 
	 * Takes ownership of the encoder, *including* the case when
	 * this method leaves.
	 * @param aEncoder ASN.1 encoding object to wrap
	 * @param aType Tag type to assign
	 * @param aClass Tag class to assign
	 * @return Wrapped encoding object.
	 */
	IMPORT_C static CASN1EncExplicitTag* NewL(CASN1EncBase* aEncoder,
		const TTagType aType, const TASN1Class aClass = EContextSpecific);

	IMPORT_C ~CASN1EncExplicitTag(); // virtual from base

private:
	CASN1EncExplicitTag(CASN1EncBase* aEncoder, const TTagType aType, 
		const TASN1Class aClass);

	// From CASN1EncConstructed
	TUint NumChildren() const;
	const CASN1EncBase& Child(const TUint aIndex) const;

private:
	CASN1EncBase* iEncoder;  // Inner encoding object
	};


/** 
 * Base class for all ASN1 container types - sequences, 
 * sets, etc.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncContainer : public CASN1EncConstructed
	{
public:
	/** 
	 * Call this to add a child object to the container.
	 * Takes ownership if and only if it doesn't Leave.
	 * Checks for null input, calls AddChildInt, calls 
	 * ContentsLengthChanged().
	 * @param aChild Child ASN1 encoding object to add.
	 */
	IMPORT_C void AddChildL(CASN1EncBase* aChild);

	/** 
	 * Call this to add a child object to the container.
	 * Takes ownership if and only if it doesn't Leave.
	 * Checks for null input, calls AddChildInt, calls 
	 * ContentsLengthChanged(). Pops added child object 
	 * off the cleanup stack.
	 * @param aChild Child ASN1 encoding object to add.
	 */
	IMPORT_C void AddAndPopChildL(CASN1EncBase* aChild);

protected:
	/** @internalComponent */
	CASN1EncContainer(const TTagType aType);

private:
	/** 
	 * Internal method, derived classes implement to add a child.
	 * No need to check for null input or call 
	 * ContentsLengthChanged(). Takes ownership, but only if you 
	 * don't leave.
	 * @param aChild Child encoding object to add.
	 */
	virtual void AddChildIntL(const CASN1EncBase* aChild) = 0;
	};

/** 
 * Class for encoding SEQUENCE and SEQUENCE-OF data types.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncSequence : public CASN1EncContainer
	{
public:
	IMPORT_C static CASN1EncSequence* NewL();
	IMPORT_C static CASN1EncSequence* NewLC();

	IMPORT_C ~CASN1EncSequence(); // virtual from base

protected:
	/** @internalComponent */ 
	CASN1EncSequence();

private:
	// From CASN1EncContainer
	const CASN1EncBase& Child(const TUint aIndex) const;
	void AddChildIntL(const CASN1EncBase* aChild);
	TUint NumChildren() const;

private:
	RPointerArray<CASN1EncBase> iChildren;
	};

/** 
 * Class for encoding SET and SET-OF data types.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncSet : public CASN1EncContainer
	{
public:
	/**
	Creates an ASN.1 Set encoder.
	@return The fully constructed object.
	*/
	IMPORT_C static CASN1EncSet* NewL();

	/**
	Creates an ASN.1 Set encoder, and puts it onto the cleanup stack.
	@return The fully constructed object.
	*/
	IMPORT_C static CASN1EncSet* NewLC();

	/**
	Destructor.
	*/
	IMPORT_C ~CASN1EncSet(); // virtual from base

protected:
	/**
	 * @internalComponent
	 * 
	 * Constructor
	 */
	CASN1EncSet();

private:
	// From CASN1EncContainer
	const CASN1EncBase& Child(const TUint aIndex) const;
	void AddChildIntL(const CASN1EncBase* aChild);
	TUint NumChildren() const;

private:
	RPointerArray<CASN1EncBase> iChildren;
	};



/**
 * All ASN1 primitive type encoding classes derive from here.
 *
 * @publishedAll
 * @released
 */
class CASN1EncPrimitive : public CASN1EncBase
	{
protected:
	IMPORT_C CASN1EncPrimitive(const TTagType aType);

private:
	TBool IsConstructed() const; ///< Inherited from CASN1EncBase
	};


/** 
 * Class for encoding NULLs.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncNull : public CASN1EncPrimitive
	{
public:
	IMPORT_C static CASN1EncNull* NewL();
	IMPORT_C static CASN1EncNull* NewLC();

private:
	CASN1EncNull();

	// Methods from CASN1EncBase
	void CalculateContentsLengthDER() ;
	void WriteContentsDERL(TDes8& aBuf) const;
	};


/** 
 * Class for encoding Boolean values.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncBoolean : public CASN1EncPrimitive
	{
public:
	IMPORT_C static CASN1EncBoolean* NewLC(const TBool aBool);
	IMPORT_C static CASN1EncBoolean* NewL(const TBool aBool);

private:
	CASN1EncBoolean(const TBool aBool);

	// Methods from CASN1EncBase
	void CalculateContentsLengthDER() ;
	void WriteContentsDERL(TDes8& aBuf) const;

	const TBool iBool;
	};


/** 
 * Class for encoding TInts only. Use CASN1EncBigInt for encoding 
 * Big Integer objects.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncInt : public CASN1EncPrimitive
	{
public:
	IMPORT_C static CASN1EncInt* NewLC(const TInt aInt);
	IMPORT_C static CASN1EncInt* NewL(const TInt aInt);

private:
	CASN1EncInt(const TInt aInt);

	// Methods from CASN1EncBase
	void CalculateContentsLengthDER() ;
	void WriteContentsDERL(TDes8& aBuf) const;

private:
	const TInt iInt;
	};


/** 
 * Class for encoding Big Integer objects only - use CASN1EncInt 
 * for TInts.
 *
 * @publishedAll
 * @released
 */
class CASN1EncBigInt : public CASN1EncPrimitive
	{
public:
	// Takes a deep copy
	IMPORT_C static CASN1EncBigInt* NewLC(const TInteger& aInteger);
	IMPORT_C static CASN1EncBigInt* NewL(const TInteger& aInteger);

	IMPORT_C ~CASN1EncBigInt(); // virtual from base

private:
	CASN1EncBigInt();
	void ConstructL(const TInteger& aInteger);

	// Methods from CASN1EncBase
	void CalculateContentsLengthDER();
	void WriteContentsDERL(TDes8& aBuf) const;

private:
	HBufC8* iContents;
	TPtrC8 iWriteContents;
	};


/** 
 * Class for encoding octet strings.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncOctetString : public CASN1EncPrimitive
	{
public:
	// Takes a deep copy
	IMPORT_C static CASN1EncOctetString* NewLC(const TDesC8& aStr);
	IMPORT_C static CASN1EncOctetString* NewL(const TDesC8& aStr);

	IMPORT_C ~CASN1EncOctetString(); // virtual from base

private:
	CASN1EncOctetString();
	void ConstructL(const TDesC8& aStr);

	// Methods from CASN1EncBase
	void CalculateContentsLengthDER();
	void WriteContentsDERL(TDes8& aBuf) const;

private:
	HBufC8* iContents;
	};


/** 
 * Class for encoding printable strings.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncPrintableString : public CASN1EncPrimitive
	{
public:
	/**
	Creates an ASN.1 Printable String encoder, and puts it onto the cleanup stack.
	@return The fully constructed object.
	*/
	IMPORT_C static CASN1EncPrintableString* NewLC(const TDesC8& aStr);

	/**
	Creates an ASN.1 Printable String encoder.
	@return The fully constructed object.
	*/
	IMPORT_C static CASN1EncPrintableString* NewL(const TDesC8& aStr);

	/**
	Destructor.
	*/
	IMPORT_C ~CASN1EncPrintableString(); // virtual from base

private:
	CASN1EncPrintableString();
	void ConstructL(const TDesC8& aStr);
	TInt CheckValid(const TDesC8& aStr);

	// Methods from CASN1EncBase
	void CalculateContentsLengthDER();
	void WriteContentsDERL(TDes8& aBuf) const;

private:
	HBufC8* iContents;
	};


/**
 * Class for encoding bit strings (keys, for example).
 *
 * @publishedAll
 * @released
 */
class CASN1EncBitString : public CASN1EncPrimitive
	{
public:
	/** 
	 * Constructs a new DER bit string encoder from a bit string that 
	 * does not have unused bits at the end, i.e. is octet-aligned. 
	 * The passed string must be in big-endian format. 
	 * @param aBitStr	Octet-aligned bit string.
	 * @return			A new DER bit string encoder object, 
	 *					which is left on the cleanup stack.
	 */
	IMPORT_C static CASN1EncBitString* NewLC(const TDesC8& aBitStr);

	/** 
	 * Constructs a new DER bit string encoder from a bit string that 
	 * does not have unused bits at the end, i.e. is octet-aligned. 
	 * The passed string must be in big-endian format. 
	 * @param aBitStr	Octet-aligned bit string.
	 * @return			A new DER bit string encoder object.
	 */
	IMPORT_C static CASN1EncBitString* NewL(const TDesC8& aBitStr);
	
	/** 
	 * Constructs a new DER bit string encoder from a bit string that 
	 * is not octet-aligned, which means it has unused bits in its last 
	 * octet. The passed string must be in big-endian format.
	 * @param aBitStr		Bit string.
	 * @param aLengthBits	Length in bits of the passed bit string. 
	 *     					The function will panic if aLengthBits is greater than 
	 *     					the actual bit length of aBitString, or the difference 
	 *     					is more that 7 bits.
	 * @return				A new DER bit string encoder object which is left on the 
	 *						cleanup stack.
	 */
	IMPORT_C static CASN1EncBitString* NewLC(const TDesC8& aBitStr, TUint aLengthBits);
	
	/** 
	 * Constructs a new DER bit string encoder from a bit string that 
	 * is not octet-aligned, which means it has unused bits in its last 
	 * octet. The passed string must be in big-endian format.
	 * @param aBitStr		Bit string.
	 * @param aLengthBits	Length in bits of the passed bit string. 
	 *     					The function will panic if aLengthBits is greater than 
	 *     					the actual bit length of aBitString, or the difference 
	 *     					is more that 7 bits.
	 * @return				A new DER bit string encoder object.
	 */
	IMPORT_C static CASN1EncBitString* NewL(const TDesC8& aBitStr, TUint aLengthBits);

	/**
	 * Wraps the passed encoding object into a bit string.
	 * @param aAsnObj	Encoding object to wrap.
	 * @return			A new bit string containing the passed encoding object.
	 */
	IMPORT_C static CASN1EncBitString* NewL(const CASN1EncBase& aAsnObj);

	/**
	 * Wraps the passed encoding object into a bit string.
	 * @param aAsnObj	Encoding object to wrap.
	 * @return			A new bit string containing the passed encoding object
	 *     				on the cleanup stack.
	 */
	IMPORT_C static CASN1EncBitString* NewLC(const CASN1EncBase& aAsnObj);
	
	IMPORT_C ~CASN1EncBitString(); // virtual from base

private:
	CASN1EncBitString();
	void ConstructL(const TDesC8& aBitStr);
	void ConstructL(const TDesC8& aBitStr, TUint aLengthBits);
	void ConstructL(const CASN1EncBase& aAsnObj);

	// Methods from CASN1EncBase
	void CalculateContentsLengthDER();
	void WriteContentsDERL(TDes8& aBuf) const;

private:
	HBufC8* iContents;
	TUint8 iPadding;
	};

/**
 * Class for encoding object identifiers.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncObjectIdentifier : public CASN1EncPrimitive
	{
public:
	/** 
	 * Takes ints in a string, delimited by '.' characters in 
	 * between (not at ends). Takes a deep copy of the info.
	 * @param aStr	OID string.
	 * @return		New ASN.1 OID object on the cleanup stack.
	 */
	IMPORT_C static CASN1EncObjectIdentifier* NewLC(const TDesC& aStr);

	/** 
	 * Takes ints in a string, delimited by '.' characters in 
	 * between (not at ends). Takes a deep copy of the info.
	 * @param aStr	OID string.
	 * @return		New ASN.1 OID object.
	 */
	IMPORT_C static CASN1EncObjectIdentifier* NewL(const TDesC& aStr);

	/** Destructor */
	IMPORT_C ~CASN1EncObjectIdentifier(); // virtual from base

private:
	CASN1EncObjectIdentifier();
	void ConstructL(const TDesC& aStr);

	// Methods from CASN1EncBase
	void CalculateContentsLengthDER();
	void WriteContentsDERL(TDes8& aBuf) const;

private:
	// Data to encode
	RArray<TASN1EncBase128DER> iData;
	TUint8 iFirstOctet;
	};


/** 
 * Class for encoding GeneralisedTime objects. 
 *
 * Doesn't support fractions of seconds or regional time zone offsets.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncGeneralizedTime : public CASN1EncPrimitive
	{
public:
	IMPORT_C static CASN1EncGeneralizedTime* NewLC(const TTime& aTime);
	IMPORT_C static CASN1EncGeneralizedTime* NewL(const TTime& aTime);

private:
	CASN1EncGeneralizedTime(const TTime& aTime);

	// Methods from CASN1EncBase
	void CalculateContentsLengthDER();
	void WriteContentsDERL(TDes8& aBuf) const;

private:
	TDateTime iDateTime;
	};

/** 
 * Class for encapsulation of already encoded data. 
 *
 * Wraps it so that the data could be used in the ASN.1 hierarchy. 
 * It reverse-engineers and stores the encoded data, providing whatever 
 * information is needed to override pure virtual methods of the base 
 * class and write out the DER encoding in its initial form.
 * 
 * @publishedAll
 * @released
 */
class CASN1EncEncoding : public CASN1EncBase
	{
public:
	/** 
	 * Creates a new object from raw DER encoding and places it on the 
	 * cleanup stack.
	 * @param aEncoding	Raw DER encoding.
	 * @return			New wrapper object placed on the cleanup stack.
	 */
	IMPORT_C static CASN1EncEncoding* NewLC(const TDesC8& aEncoding);

	/** 
	 * Creates a new object from raw DER encoding.
	 * @param aEncoding	Raw DER encoding.
	 * @return			New wrapper object.
	 */
	IMPORT_C static CASN1EncEncoding* NewL(const TDesC8& aEncoding);

	IMPORT_C static CASN1EncEncoding* NewLC(const TDesC8& aEncoding, TTagType aType, TASN1Class aClass);

	IMPORT_C ~CASN1EncEncoding();

protected:
	/** 
	 * Protected constructor.
	 * <!--
	 * @param aType		Tag type of the new object
	 * @param aClass	Tag class of the new object.
	 * -->
	 */
	IMPORT_C CASN1EncEncoding();

private:
	/** 
	 * Constructs the wrapper around the passed raw DER encoding. 
	 * Calculates element sizes. Decodes it to get type and length.
	 * @param aEncoding Raw DER encoding.
	 */
	void ConstructL(const TDesC8& aEncoding);

	void ConstructL(const TDesC8& aEncoding, TTagType aType, TASN1Class aClass);

	virtual TBool IsConstructed() const;
	
	/** 
	 * Writes DER content encoding into supplied buffer, which is 
	 * already verified to be big enough.
	 * @param aBuf	Buffer to write to.
	 */
	virtual void WriteContentsDERL(TDes8& aBuf) const;

	/** 
	 * Calculates number of octets in DER content encoding. Sets 
	 * value of the appropriate data member.
	 */
	virtual void CalculateContentsLengthDER();

private:
	HBufC8* iContents; ///< Copy of the supplied DER encoded data (contents only).
	TASN1Class iClass; ///< ASN.1 class of the encoded object.
	TTagType iTag; ///< ASN.1 tag of the encoding.
	};

#endif // __ASN1ENC_H__
