/*
 * Copyright(C) 2003 Проект ИОК
 *
 * Этот файл содержит информацию, являющуюся
 * собственностью компании Крипто Про.
 *
 * Любая часть этого файла не может быть скопирована,
 * исправлена, переведена на другие языки,
 * локализована или модифицирована любым способом,
 * откомпилирована, передана по сети с или на
 * любую компьютерную систему без предварительного
 * заключения соглашения с компанией Крипто Про.
 */

/*!
 * \file $RCSfile$
 * \version $Revision: 229089 $
 * \date $Date:: 2021-06-21 11:26:40 +0300#$
 * \author $Author: dim $
 *
 * \brief Классы свойств для ASN1 типов.
 *
 * Набор классов свойств для ASN1 типов определяющих операции get() и set()
 * для преобразований в типы использующиеся в capilite и pkix библиотеках.
 */

#ifndef _ASN1TRAITS_H
#define _ASN1TRAITS_H

#include <vector>

#include "ASN1Util.h"
#include "ASN1Types.h"

template<class T>
void copy_to_auto_ptr( std::auto_ptr<T>& dest, const T* src)
{
    std::auto_ptr<T> ptr(src?(new T(*src)):0 );
    dest = ptr;
}

template<class T>
void copy_to_auto_ptr( std::auto_ptr<T>& dest, const std::auto_ptr<T>& src)
{
    ::copy_to_auto_ptr(dest,src.get());
}

template<class ASN1_T_traits, class ASN1_T>
CACMPT_BLOB asn1Encode( const ASN1_T& src)
{
    ASN1BEREncodeBuffer encBuf;
    ASN1_T tObj;
    ASN1_T_traits::copy(encBuf.getCtxtPtr(),src,tObj);
    typename ASN1_T_traits::ASN1_C cObj(encBuf,tObj);
    int len = cObj.Encode();
    if( len < 0 )
	throw CA_ASN1_EXCEPTION(encBuf.getCtxtPtr());
    return CACMPT_BLOB(encBuf.getMsgPtr(),len);
}

template<class ASN1_T_traits, class ASN1_T>
void asn1Decode( const CACMPT_BLOB& encoded, ASN1CTXT* pctxt, ASN1_T& dest)
{
    ASN1BERDecodeBuffer decBuf(encoded.pbData,encoded.cbData);
    ASN1_T tObj;
    typename ASN1_T_traits::ASN1_C cObj(decBuf,tObj);
    if( cObj.Decode() < 0 )
	throw CA_ASN1_EXCEPTION(decBuf.getCtxtPtr());
    ASN1_T_traits::copy(pctxt,tObj,dest);
}

template<class ASN1_T, class ASN1_T_traits, class CACMP_T>
CACMPT_BLOB asn1Encode( const CACMP_T& src)
{
    ASN1BEREncodeBuffer encBuf;
    ASN1BERDecodeBuffer decBuf;
    ASN1_T tObj;
    ASN1_T_traits::set(decBuf.getCtxtPtr(),tObj,src);
    typename ASN1_T_traits::ASN1_C cObj(encBuf,tObj);
    int len = cObj.Encode();
    if( len < 0 )
	throw CA_ASN1_EXCEPTION(encBuf.getCtxtPtr());
    return CACMPT_BLOB(encBuf.getMsgPtr(),len);
}

template<class ASN1_T, class ASN1_T_traits, class CACMP_T>
void asn1Decode( const CACMPT_BLOB& encoded, CACMP_T& dest)
{
    ASN1BERDecodeBuffer decBuf(encoded.pbData,encoded.cbData);
    ASN1_T tObj;
    typename ASN1_T_traits::ASN1_C cObj(decBuf,tObj);
    if( cObj.Decode() < 0 )
	throw CA_ASN1_EXCEPTION(decBuf.getCtxtPtr());
    ASN1_T_traits::get(tObj,dest);
}

template<class ASN1_T, class ASN1_T_traits, class CACMP_T, class CACMPList_T>
class ASN1TSeqOfList_traits
{
public:
    static void set(
	ASN1CTXT* pctxt,
	ASN1TSeqOfList& dest, 
	const CACMPList_T& src);
    static void get(
	const ASN1TSeqOfList& src, 
	CACMPList_T& dest);
    static void copy(
	ASN1CTXT* pctxt,
        const ASN1TSeqOfList& src,
        ASN1TSeqOfList &dest);
};

//static 
template<class ASN1_T, class ASN1_T_traits, class CACMP_T, class CACMPList_T>
void ASN1TSeqOfList_traits<ASN1_T,ASN1_T_traits,CACMP_T,CACMPList_T>::set(
    ASN1CTXT* pctxt,
    ASN1TSeqOfList& dest, 
    const CACMPList_T& src)
{
    ASN1BEREncodeBuffer encBuf;
    ASN1TSeqOfList tList;
    ASN1CSeqOfList cList(encBuf,tList);
    typename CACMPList_T::const_iterator it = src.begin();
    typename CACMPList_T::const_iterator end = src.end();
    for(; it != end; ++it)
    {
	ASN1_T* tElem = ALLOC_ASN1ELEM( pctxt, ASN1_T);
	if(!tElem)
	    throw CA_MEMORY_EXCEPTION;
	ASN1_T_traits::set( pctxt, *tElem, *it);
	cList.append(tElem);
    }
    ASN1TSeqOfList_traits<ASN1_T,ASN1_T_traits,CACMP_T,CACMPList_T>::copy(
	pctxt,tList,dest);
}

//static 
template<class ASN1_T, class ASN1_T_traits, class CACMP_T, class CACMPList_T>
void ASN1TSeqOfList_traits<ASN1_T,ASN1_T_traits,CACMP_T,CACMPList_T>::get(
    const ASN1TSeqOfList& src, 
    CACMPList_T& dest)
{
    ASN1BERDecodeBuffer buf;
    ASN1CSeqOfList cList(buf,const_cast<ASN1TSeqOfList&>(src));
    ASN1CSeqOfListIterator* it = cList.iterator();
    ASN1_T* tElem = static_cast<ASN1_T*>(it->next());
    while(tElem)
    {
	CACMP_T elem;
	ASN1_T_traits::get(*tElem,elem);
	dest.push_back(elem);
	tElem = static_cast<ASN1_T*>(it->next());
    }
}

template<class ASN1_T, class ASN1_T_traits, class CACMP_T, class CACMPList_T>
//static 
void ASN1TSeqOfList_traits<ASN1_T,ASN1_T_traits,CACMP_T,CACMPList_T>::copy(
    ASN1CTXT* pctxt,
    const ASN1TSeqOfList& src,
    ASN1TSeqOfList &dest)
{
    ASN1UINT xx1;
    ASN1_T* pSrcData;
    Asn1RTDListNode* pnode;

    ::rtDListInit (&dest);
    pnode = src.head;
    for (xx1 = 0; xx1 < src.count; xx1++) {
        ASN1_T* pDstData = ALLOC_ASN1ELEM (pctxt, ASN1_T);
        if (!pDstData)
		throw CA_MEMORY_EXCEPTION;
	::rtDListAppend (pctxt, &dest, pDstData);
        pSrcData = static_cast<ASN1_T*>(pnode->data);
	ASN1_T_traits::copy(pctxt, *pSrcData, *pDstData);
        pnode = pnode->next;
    }
}

// используется в CMS
class ASN1TDynOctStr_traits
{
public:
    static void set( 
	ASN1CTXT* pctxt,
	ASN1TDynOctStr& dest, 
	const CACMPT_BLOB& src);
    static void set( 
	ASN1CTXT* pctxt,
	ASN1TDynOctStr& dest, 
	const CRYPT_DATA_BLOB& src);
    static void get(
	const ASN1TDynOctStr& src, 
	CACMPT_BLOB& dest);
};

// используется в CMS
class ASN1TObjId_traits
{
public:
    typedef ASN1C_ContentType ASN1_C;

    static void set( 
	ASN1CTXT* pctxt,
	ASN1TObjId& dest, 
	const CACMPT_OID& src);
    static void get(
	const ASN1TObjId& src, 
	CACMPT_OID& dest);
};

class ASN1T_ContentInfo_traits
{
public:
    typedef ASN1C_ContentInfo ASN1_C;

    // Службы
    static void set(
    	ASN1CTXT* pctxt,
    	ASN1T_ContentInfo& dest,
    	const CACMPT_BLOB& src);
    // CMSHashedMessage.cpp
    static void set(
	ASN1CTXT* pctxt,
	ASN1T_ContentInfo& dest,
	const CACMPT_ContentInfo& src);
    // Службы
    static void get(
    	const ASN1T_ContentInfo& src,
    	CACMPT_BLOB& dest);
    // CMSHashedMessage.cpp
    static void get(
	const ASN1T_ContentInfo& src,
	CACMPT_ContentInfo& dest);
    // ASN1T_ContentInfo_traits::
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1T_ContentInfo& src,
	ASN1T_ContentInfo& dest);
};

class ASN1TOpenType_traits
{
public:
    // ASN1T_ContentInfo_traits::set()
    static void set(
	ASN1CTXT* pctxt,
	ASN1OpenType& dest,
	const CACMPT_BLOB& src);
    // ASN1T_ContentInfo_traits::get()
    static void get(
	const ASN1OpenType& src,
	CACMPT_BLOB& dest);
};

class ASN1T_CertificateList_traits
{
public:
    typedef ASN1C_CertificateList ASN1_C;

    // оба в Службах
    static void set(
    	ASN1CTXT* pctxt,
    	ASN1T_CertificateList& dest,
    	const CACMPT_BLOB& src);
    static void get(
    	const ASN1T_CertificateList& src,
    	CACMPT_BLOB& dest);
    // CMSSignedMessage.cpp
    static void copy(
    	ASN1CTXT* pctxt,
    	const ASN1T_CertificateList& src,
    	ASN1T_CertificateList& dest);
};

// используется в CMS
class ASN1T_AlgorithmIdentifier_traits
{
public:
    typedef ASN1C_AlgorithmIdentifier ASN1_C;

    static void set(
    	ASN1CTXT* pctxt,
    	ASN1T_AlgorithmIdentifier& dest,
    	const CACMPT_AlgorithmIdentifier& src,
	DWORD dwGroupId = 0);
    static void set(
    	ASN1CTXT* pctxt,
    	ASN1T_AlgorithmIdentifier& dest,
    	const CRYPT_ALGORITHM_IDENTIFIER& src,
	DWORD dwGroupId = 0);
    static void get(
    	const ASN1T_AlgorithmIdentifier& src,
    	CACMPT_AlgorithmIdentifier& dest);
};

class Asn1TObject_traits
{
public:
    static void set(
	ASN1CTXT* pctxt,
	Asn1Object& dest,
	const CACMPT_BLOB& src);
    static void get(
	const Asn1Object& src,
	CACMPT_BLOB& dest);
    // ASN1T_Attribute_traits::set()
    static void copy(
    	ASN1CTXT* pctxt,
    	const Asn1Object& src,
    	Asn1Object& dest);
};

typedef ASN1TSeqOfList_traits<
    Asn1TObject,
    Asn1TObject_traits,
    CACMPT_BLOB,
    std::vector<CACMPT_BLOB> > Asn1TObjectList_traits;

class ASN1T_Attribute_traits
{
public:
    typedef ASN1C_Attribute ASN1_C;

    // все используются в CMSEnvelopedMessage.cpp
    static void set(
	ASN1CTXT* pctxt,
	ASN1T_Attribute& dest,
	const CACMPT_Attribute& src);
    static void get(
	const ASN1T_Attribute& src,
	CACMPT_Attribute& dest);
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1T_Attribute& src,
	ASN1T_Attribute& dest);
};

// CMSSignedMessage.cpp
class ASN1T_Attributes_traits: 
public ASN1TSeqOfList_traits< 
    ASN1T_Attribute,
    ASN1T_Attribute_traits,
    CACMPT_Attribute,
    CACMPT_Attributes>
{
public:
    typedef ASN1C_SignedAttributes ASN1_C;
};

// CMSSignedMessage.cpp
class ASN1T_UnorderedAttributes_traits:
public ASN1TSeqOfList_traits<
    ASN1T_Attribute,
    ASN1T_Attribute_traits,
    CACMPT_Attribute,
    CACMPT_Attributes>
{
public:
    typedef ASN1C_AttributesSyntax ASN1_C;
};

class ASN1T_AttributeTypeAndValue_traits
{
public:
    typedef ASN1C_AttributeTypeAndValue ASN1_C;

    static void set(
	ASN1CTXT* pctxt,
	ASN1T_AttributeTypeAndValue& dest,
	const CACMPT_AttributeTypeAndValue& src);
    static void get(
	const ASN1T_AttributeTypeAndValue& src,
	CACMPT_AttributeTypeAndValue& dest);
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1T_AttributeTypeAndValue& src,
	ASN1T_AttributeTypeAndValue& dest);
};

class ASN1T_RelativeDistinguishedName_traits
    : public ASN1TSeqOfList_traits< 
    ASN1T_AttributeTypeAndValue,
    ASN1T_AttributeTypeAndValue_traits,
    CACMPT_AttributeTypeAndValue,
    CACMPT_RelativeDistinguishedName>
{
public:
    typedef ASN1C_RelativeDistinguishedName ASN1_C;
};

class ASN1T_Name_traits
{
public:
    typedef ASN1C_Name ASN1_C;

    static void set( 
	ASN1CTXT* pctxt,
	ASN1T_Name& dest, 
	const CACMPT_BLOB& src);
    static void set( 
	ASN1CTXT* pctxt,
	ASN1T_Name& dest, 
	const CACMPT_Name& src)
    {
	dest.t = T_Name_rdnSequence;
	dest.u.rdnSequence = ::asn1New<ASN1TSeqOfList>(pctxt);
	ASN1TSeqOfList_traits< 
	    ASN1T_RelativeDistinguishedName,
	    ASN1T_RelativeDistinguishedName_traits,
	    CACMPT_RelativeDistinguishedName,
	    CACMPT_RDNSequence>::set(pctxt,*dest.u.rdnSequence,src);
    }
    static void get(
	const ASN1T_Name& src, 
	CACMPT_BLOB& dest);
    static void get(
	const ASN1T_Name& src, 
	CACMPT_Name& dest)
    {
	ASN1TSeqOfList_traits<
	    ASN1T_RelativeDistinguishedName,
	    ASN1T_RelativeDistinguishedName_traits,
	    CACMPT_RelativeDistinguishedName,
	    CACMPT_RDNSequence>::get(*src.u.rdnSequence,dest);
    }
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1T_Name& src,
	ASN1T_Name& dest)
    { ::asn1Copy_Name(pctxt,const_cast<ASN1T_Name*>(&src),&dest); }
};

namespace Capilite {

class ASN1T_Extension_traits
{
public:
    typedef ASN1C_Extension ASN1_C;

    static void set(
	ASN1CTXT* pctxt,
	ASN1T_Extension& dest,
	const CExtension& src);

    static void get(
	const ASN1T_Extension& src,
	CExtension& dest);

    static void copy(
	ASN1CTXT* pctxt,
	const ASN1T_Extension& src,
	ASN1T_Extension& dest);
};

} /* namespace Capilite */

#endif // _ASN1TRAITS_H
