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

/*!
 * \file $RCSfile$
 * \version $Revision: 224891 $
 * \date $Date:: 2021-02-09 10:09:18 +0300#$
 * \author $Author: dim $
 *
 * \brief Классы и структуры для ASN1 типов.
 */

#ifndef _ASN1TYPES_H
#define _ASN1TYPES_H

#include "common.h"

#include <memory>
#include <vector>
#include <list>

#include "ASN1Blob.h"

struct CACMPT_ContentInfo
{
    CACMPT_OID contentType;
    CACMPT_BLOB content;
};

CACMPT_BLOB toOctetString( const CACMPT_BLOB& blob);
CACMPT_BLOB fromOctetString(const BYTE* p, size_t n);

class CACMPT_AttrValue /* похоже, что используется только в pkixcmp */
{    
  protected:
    std::string m_oid;
    CACMPT_BLOB m_der;
    CACMPT_AttrValue () {}
  public:
    CACMPT_AttrValue (const std::string& oid, const CACMPT_BLOB& der)
	: m_oid(oid), m_der(der) {}
    CACMPT_AttrValue (const CACMPT_AttrValue& src) 
	: m_oid (src.m_oid), m_der (src.m_der) {}
    CACMPT_AttrValue& operator= (const CACMPT_AttrValue& src)
    {
	if(this == &src)
	    return *this;
	m_oid = src.m_oid;
	m_der = src.m_der;
	return *this;
    }
    inline const std::string& get_oid () const { return m_oid; }
    inline const CACMPT_BLOB& get_der () const { return m_der; }
};

extern const char sz_emailAddress[];
extern const char sz_id_at_commonName[];
extern const char sz_id_at_surname[];
extern const char sz_id_at_countryName[];
extern const char sz_id_at_localityName[];
extern const char sz_id_at_stateOrProvinceName[];
extern const char sz_id_at_organizationName[];
extern const char sz_id_at_organizationalUnitName[];
extern const char sz_id_at_title[];
extern const char sz_id_at_givenName[];
extern const char sz_id_at_initials[];
extern const char sz_id_at_pseudonym[];

extern const char sz_id_contentType[];

class CACMPT_AttrContentType: public CACMPT_AttrValue
{
public:
    CACMPT_AttrContentType( const CACMPT_OID& contentType)
	: CACMPT_AttrValue(sz_id_contentType,CACMPT_BLOB()),
	  contentType_(contentType)
    { encode(); }
    void encode(); /* CMSSignedMessage.cpp */

private:
    CACMPT_OID contentType_;
};

extern const char sz_id_messageDigest[];

class CACMPT_AttrMessageDigest: public CACMPT_AttrValue
{
public:
    CACMPT_AttrMessageDigest() : CACMPT_AttrValue(sz_id_messageDigest,CACMPT_BLOB()) {}

    void encode(); /* CMSSignedMessage.cpp */

    void set_messageDigest(const CACMPT_BLOB& messageDigest) // CMSSignedMessage.cpp
    {
	messageDigest_ = messageDigest;
	encode();
    }
private:
    CACMPT_AttrMessageDigest(const CACMPT_AttrMessageDigest&);
    CACMPT_AttrMessageDigest& operator=( const CACMPT_AttrMessageDigest&);

    CACMPT_BLOB messageDigest_;
};

class CACMPT_Attribute
{
  public:
    typedef std::list<CACMPT_AttrValue> ValueList;
    typedef ValueList::iterator value_iterator;
    typedef ValueList::const_iterator const_value_iterator;
  protected:
    std::list<CACMPT_AttrValue> m_values;
    std::string m_oid;
  public:
    CACMPT_Attribute () { }
    CACMPT_Attribute(const char *oid) : m_oid(oid) { }
    CACMPT_Attribute(const std::string& oid) : m_oid(oid) { }
    CACMPT_Attribute(const CACMPT_Attribute& src) : m_values(src.m_values), m_oid(src.m_oid) {}
    CACMPT_Attribute& operator=( const CACMPT_Attribute& src)
    {
	m_oid = src.m_oid;
	m_values = src.m_values;
	return *this;
    }
    inline const std::string& get_oid () const { return m_oid; }
    inline const_value_iterator begin() const { return m_values.begin(); }
    inline const_value_iterator end() const { return m_values.end(); }
    inline value_iterator begin() { return m_values.begin(); }
    inline value_iterator end() { return m_values.end(); }
    void add( const CACMPT_BLOB& der)
    {
	m_values.push_back( CACMPT_AttrValue(m_oid,der) );
    }
    void add( const CACMPT_AttrValue& value)
    {
	m_values.push_back( value );
    }
    value_iterator erase( value_iterator pos)
    {
	return m_values.erase(pos);
    }
    size_t size() const { return m_values.size(); }

    CACMPT_BLOB encode() const;	/* используется в Службах */
};

class CACMPT_Attributes : public std::list<CACMPT_Attribute>
{
public:
    typedef std::list<CACMPT_Attribute> AttrList;
    CACMPT_Attributes() : AttrList() {}
    CACMPT_Attributes( const_iterator f, const_iterator l ) : 
	AttrList(f,l) {}
    ~CACMPT_Attributes(){}
    void Delete (const std::string& oid); /* CMSSignedMessage.cpp */

    iterator find( std::string oid )
    {	iterator e = end();
	for( iterator i = begin(); i != e; i++ )
	    { if( i->get_oid() == oid ) return i; }
	return e;
    }
};

CACMPT_Attributes CRYPTToCACMPTAttributes(PCRYPT_ATTRIBUTES pAttrs);

CACMPT_BigInteger StringToBigInteger( const std::string& strBigInt);
std::string BigIntegerToString( const CACMPT_BigInteger& blob);

enum CACMPT_StringType
{
    stDefault,
    stUTF8String,
    stPrintableString,
    stTeletexString,
    stBMPString,
    stIA5String,
    stUniversalString,
    stNumericString
};

class CACMPT_AttributeTypeAndValue
{
public:
    CACMPT_AttributeTypeAndValue() {}
    CACMPT_AttributeTypeAndValue( const CACMPT_AttrValue& attrValue);
    CACMPT_AttributeTypeAndValue( const CACMPT_OID& type, const CACMPT_BLOB& value);
    CACMPT_AttributeTypeAndValue( 
	const std::wstring& type, const std::wstring& value,
        size_t &pos, CACMPT_StringType stringType = stDefault,
        DWORD dwStrType = 0);
    CACMPT_AttributeTypeAndValue( 
	const std::wstring& str, size_t& pos,
        CACMPT_StringType stringType = stDefault, DWORD dwStrType = 0);
    CACMPT_AttributeTypeAndValue( const CACMPT_AttributeTypeAndValue& src);
    CACMPT_AttributeTypeAndValue& operator=( const CACMPT_AttributeTypeAndValue& src);
    CACMPT_OID get_type() const { return type_; }
    std::wstring get_type_str(DWORD dwStrType = CERT_X500_NAME_STR|CERT_NAME_STR_NO_QUOTING_FLAG) const;
    CACMPT_BLOB get_value() const {return value_; }
    std::wstring get_value_str(DWORD dwStrType = CERT_X500_NAME_STR|CERT_NAME_STR_NO_QUOTING_FLAG) const;

    void set_type( const CACMPT_OID& type) { type_ = type; }
    void set_type_str( const std::wstring& type);
    void set_value( const CACMPT_BLOB& value) { value_ = value; }
    void set_value_str(
	const std::wstring& value, 
	CACMPT_StringType stringType = stDefault);

    std::wstring toString(DWORD dwStrType = CERT_X500_NAME_STR|CERT_NAME_STR_NO_QUOTING_FLAG) const;
    void fromString( 
	const std::wstring& str,
        size_t& pos,
	CACMPT_StringType stringType = stDefault,
        DWORD dwStrType = 0);

private:
    CACMPT_OID type_;
    CACMPT_BLOB value_;
};

typedef std::vector<CACMPT_AttributeTypeAndValue> CACMPT_AttributeTypeAndValueSet;

class CACMPT_RelativeDistinguishedName: public CACMPT_AttributeTypeAndValueSet
{
public:
    CACMPT_RelativeDistinguishedName() {}
    CACMPT_RelativeDistinguishedName( const std::wstring& str, DWORD dwStrType = 0);
    CACMPT_RelativeDistinguishedName( const std::wstring& str, DWORD dwStrType, 
        size_t& pos);

    std::wstring toString(DWORD dwStrType = CERT_X500_NAME_STR|CERT_NAME_STR_NO_QUOTING_FLAG) const;
    void fromString( const std::wstring& str, DWORD dwStrType = 0);
    void fromString( const std::wstring& str, DWORD dwStrType, size_t& pos);
};

typedef std::list<CACMPT_RelativeDistinguishedName> CACMPT_RDNSequence;

class CACMPT_Name: public CACMPT_RDNSequence
{
public:
    CACMPT_Name() {}
    CACMPT_Name( const std::wstring& str, DWORD dwStrType = 0, size_t *errorPos = 0 );

    std::wstring toString(DWORD dwStrType = CERT_X500_NAME_STR|CERT_NAME_STR_NO_QUOTING_FLAG) const;
    void fromString( const std::wstring& str, DWORD dwStrType, size_t *errorPos = 0 );

    void decode( const CACMPT_BLOB& encoded); /* CACMPT_PARSED_RDN::tostring */
    CACMPT_BLOB encode() const;		      /* CACMPT_PARSED_RDN::assign */
};

namespace Capilite {

class CExtValue
{
public:
    CExtValue() {};
    ~CExtValue() {};

    CExtValue(const char* oid) : oid_(oid) {};
    CExtValue(const char* oid, const CACMPT_BLOB& value) : oid_(oid), value_(value) {};
    CExtValue(const CExtValue& src) : oid_(src.oid_), value_(src.value_) {};

    CExtValue& operator=(const CExtValue& src) {
	if (this == &src)
	    return *this;
	oid_ = src.oid_;
	value_ = src.value_;
	return *this;
    }

    const char* get_oid() const;
    const CACMPT_BLOB& get_value() const;

private:
    CACMPT_OID oid_;
    CACMPT_BLOB value_;
};

class CExtension
{
public:
    CExtension(
	const CExtValue& value,
	bool critical = false) : value_(value), critical_(critical)
    {
    }

    CExtension() : value_(CExtValue()), critical_(false)
    {
    }

    CExtension(const CExtension& src) : value_(src.value_), critical_(src.critical_)
    {
    }

    CExtension& operator=(const CExtension& src)
    {
	value_ = src.value_; critical_ = src.critical_; return *this;
    }

    friend bool operator==(const CExtension& lhs, const CExtension& rhs)
    {
	return lhs.get_critical() == rhs.get_critical()
	    && std::string(lhs.get_extnID()) == std::string(rhs.get_extnID())
	    && lhs.get_extnValue() == rhs.get_extnValue();
    }

    friend bool operator!=(const CExtension& lhs, const CExtension& rhs)
    {
	return !(lhs == rhs);
    }

    const char* get_extnID() const;
    const CACMPT_BLOB& get_extnValue() const;
    bool get_critical() const;

    CACMPT_BLOB encode() const;
    void decode(const CACMPT_BLOB& encoded);

private:
    CExtValue value_;
    bool critical_;
};

} /* namespace Capilite */

#endif // _ASN1TYPES_H
