/*******************************************************************************
*                       Copyright (c) 1998 Gemplus Development
*
* Name        : COMPCERT.C
*
* Description : Programme de compression de certificat X.509
*
* Author      : Christophe Clavier
*
* Modify      : Laurent CASSIER
*
* Compiler    : Microsoft Visual C 5.0
*
* Host        : IBM PC and compatible machines under Windows 95.
*
* Release     : 1.10.001
*
* Last Modif  : 04/03/98: V1.10.001 - Change dictionary management and add
*                                     CC_Init(), CC_Exit() functions.
*               30/01/98: V1.00.005 - Cancel (_OPT_HEADER) the modification in
*                                     the length of subjectPKInfo and signature
*                                     made in the previous version.
*               28/01/98: V1.00.004 - Allows up to 32767 entries in the dictionary
*                                     and stores the length of the subjectPKInfo
*                                     and signature on one byte instead of two if
*                                     it is less than 128.
*               13/01/98: V1.00.003 - Modify for meta-compression and dictionary
*                                     version ascending compatibility.
*               11/12/97: V1.00.002 - Modify for new dictionary format
*                                     and compatible with CSP and PKCS.
*               27/08/97: V1.00.001 - First implementation.
*
********************************************************************************
*
* Warning     :
*
* Remark      : Flags de compilations :
*
*                - _STUDY : Lorsqu'il est d�fini, des fichiers de log utiles
*                           lors de l'�tude de l'efficacit� des algos
*                           de compression. sont g�n�r�s.
*
*                - _TRICKY_COMPRESSION : Lorsqu'il est d�fini, on ne tente pas
*                                        de compresser les champs
*                                        'subjectPublicKey' et 'signature' qui
*                                        sont essentiellement al�atoires.
*
*                - _OPT_HEADER : Lorsqu'il est d�fini, et si _TRICKY_COMPRESSION
*                                est d�fini �galement, le header de longueur des
*                                compress�s de subjectPKInfo et de signature
*                                sont optimis�s pour ne tenir sur un seul octet
*                                si la longueur est inf�rieure � 128 au lieu de
*                                deux octets dans tous les cas sinon.
*                                Ne pas d�finir ce flag permet d'�tre compatible
*                                avec les versions inf�rieures � 1.00.005 
*
*                - _GLOBAL_COMPRESSION : Lorsqu'il est d�fini, le compress� du
*                                        certificat est lui m�me envoy� � la
*                                        fonction CC_RawEncode afin d'y appliquer
*                                        le meilleur algo de compression dispo.
*
*                - _OPT_HEADER : Lorsqu'il est d�fini, l
*                                certificat est lui m�me envoy� � la
*                                      fonction CC_RawEncode afin d'y appliquer
*                                        le meilleur algo de compression dispo.
*
*                - _ALGO_x (x de 1 � 7) : Lorsqu'il est d�fini, l'algo de
*                                         compression num�ro x est utilis�.
*
*               Conseils pour la version release de GemPASS :
*
*                - _STUDY              : non d�fini
*                - _TRICKY_COMPRESSION : d�fini
*                - _OPT_HEADER         : non d�fini
*                - _GLOBAL_COMPRESSION : non d�fini
*                - _ALGO_1             : d�fini
*                - _ALGO_2             : d�fini
*                - _ALGO_x (x>2)       : non d�fini
*
*******************************************************************************/

/*------------------------------------------------------------------------------
                                 Includes files
------------------------------------------------------------------------------*/
#ifdef _WINDOWS
#include <windows.h>
#endif
#include <stdio.h>      
#include <io.h>      
#include <fcntl.h>      
#include <sys/types.h>
#include <sys/stat.h>

#include "ccdef.h"
#include "ac.h"
#include "compcert.h"
#include "gmem.h"
#include "resource.h"

extern HINSTANCE g_hInstRes;

/*------------------------------------------------------------------------------
                             Information section
------------------------------------------------------------------------------*/
#define G_NAME     "COMPCERT"
#define G_RELEASE  "1.10.001"


/*------------------------------------------------------------------------------
                              Static Variables
------------------------------------------------------------------------------*/
                                                
	USHORT NbDaysInMonth[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};

   char* AlgorithmTypeDict[] = {
    /* x9-57 */
	"\x2A\x86\x48\xCE\x38\x02\x01", /*x9.57-holdinstruction-none (1 2 840 10040 2 1) */
	"\x2A\x86\x48\xCE\x38\x02\x02", /*x9.57-holdinstruction-callissuer (1 2 840 10040 2 2) */
	"\x2A\x86\x48\xCE\x38\x02\x03", /*x9.57-holdinstruction-reject (1 2 840 10040 2 3) */
	"\x2A\x86\x48\xCE\x38\x04\x01", /*x9.57-dsa (1 2 840 10040 4 1) */
	"\x2A\x86\x48\xCE\x38\x04\x03", /*x9.57-dsaWithSha1 (1 2 840 10040 4 3) */
    
    /* x9-42 */
	"\x2A\x86\x48\xCE\x3E\x02\x01", /*x9.42-dhPublicNumber (1 2 840 10046 2 1) */
	
    /* Nortel Secure Networks */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x42",     /*nsn-alg (1 2 840 113533 7 66) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0A", /*nsn-alg-cast5CBC (1 2 840 113533 7 66 10) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0B", /*nsn-alg-cast5MAC (1 2 840 113533 7 66 11) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0C", /*nsn-alg-pbeWithMD5AndCAST5-CBC (1 2 840 113533 7 66 12) */
	
    /* PKCS #1 */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01",     /*pkcs-1 (1 2 840 113549 1 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", /*pkcs-1-rsaEncryption (1 2 840 113549 1 1 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x02", /*pkcs-1-MD2withRSAEncryption (1 2 840 113549 1 1 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x03", /*pkcs-1-MD4withRSAEncryption (1 2 840 113549 1 1 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04", /*pkcs-1-MD5withRSAEncryption (1 2 840 113549 1 1 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05", /*pkcs-1-SHA1withRSAEncryption (1 2 840 113549 1 1 5) */
	/*need to determine which of the following 2 is correct */
    /*"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x06", pkcs-1-ripemd160WithRSAEncryption (1 2 840 113549 1 1 6) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x06", /*pkcs-1-rsaOAEPEncryptionSET (1 2 840 113549 1 1 6) */
	
    /* PKCS #3 */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x03",     /*pkcs-3 (1 2 840 113549 1 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x03\x01", /*pkcs-3-dhKeyAgreement (1 2 840 113549 1 3 1) */
	
    /* PKCS #5 */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05",     /*pkcs-5 (1 2 840 113549 1 5) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x01", /*pkcs-5-pbeWithMD2AndDES-CBC (1 2 840 113549 1 5 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x03", /*pkcs-5-pbeWithMD5AndDES-CBC (1 2 840 113549 1 5 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x04", /*pkcs-5-pbeWithMD2AndRC2-CBC (1 2 840 113549 1 5 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x06", /*pkcs-5-pbeWithMD5AndRC2-CBC (1 2 840 113549 1 5 6) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x09", /*pkcs-5-pbeWithMD5AndXOR (1 2 840 113549 1 5 9) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0A", /*pkcs-5-pbeWithSHA1AndDES-CBC (1 2 840 113549 1 5 10) */
	
    /* PKCS #12 */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C",         /*pkcs-12 (1 2 840 113549 1 12) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01",     /*pkcs-12-modeID (1 2 840 113549 1 12 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01\x01", /*pkcs-12-OfflineTransportMode (1 2 840 113549 1 12 1 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01\x02", /*pkcs-12-OnlineTransportMode (1 2 840 113549 1 12 1 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x02",     /*pkcs-12-ESPVKID (1 2 840 113549 1 12 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x02\x01", /*pkcs-12-PKCS8KeyShrouding (1 2 840 113549 1 12 2 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x03",     /*pkcs-12-BagID (1 2 840 113549 1 12 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x03\x01", /*pkcs-12-KeyBagID (1 2 840 113549 1 12 3 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x03\x02", /*pkcs-12-CertAndCRLBagID (1 2 840 113549 1 12 3 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x03\x03", /*pkcs-12-SecretBagID (1 2 840 113549 1 12 3 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x04",     /*pkcs-12-CertBagID (1 2 840 113549 1 12 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x04\x01", /*pkcs-12-X509CertCRLBag (1 2 840 113549 1 12 4 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x04\x02", /*pkcs-12-SDSICertBag (1 2 840 113549 1 12 4 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05",     /*pkcs-12-OID (1 2 840 113549 1 12 5) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01", /*pkcs-12-PBEID (1 2 840 113549 1 12 5 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x01", /*pkcs-12-PBEWithSha1And128BitRC4 (1 2 840 113549 1 12 5 1 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x02", /*pkcs-12-PBEWithSha1And40BitRC4 (1 2 840 113549 1 12 5 1 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x03", /*pkcs-12-PBEWithSha1AndTripleDESCBC (1 2 840 113549 1 12 5 1 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x04", /*pkcs-12-PBEWithSha1And128BitRC2CBC (1 2 840 113549 1 12 5 1 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x05", /*pkcs-12-PBEWithSha1And40BitRC2CBC (1 2 840 113549 1 12 5 1 5) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x06", /*pkcs-12-PBEWithSha1AndRC4 (1 2 840 113549 1 12 5 1 6) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x07", /*pkcs-12-PBEWithSha1AndRC2CBC (1 2 840 113549 1 12 5 1 7) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x02",     /*pkcs-12-EnvelopingID (1 2 840 113549 1 12 5 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x02\x01", /*pkcs-12-RSAEncryptionWith128BitRC4 (1 2 840 113549 1 12 5 2 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x02\x02", /*pkcs-12-RSAEncryptionWith40BitRC4 (1 2 840 113549 1 12 5 2 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x02\x03", /*pkcs-12-RSAEncryptionWithTripleDES (1 2 840 113549 1 12 5 2 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x03",     /*pkcs-12-SignatureID (1 2 840 113549 1 12 5 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x03\x01", /*pkcs-12-RSASignatureWithSHA1Digest (1 2 840 113549 1 12 5 3 1) */

    /* RSADSI digest algorithms */
	"\x2A\x86\x48\x86\xF7\x0D\x02",     /*RSADSI-digestAlgorithm (1 2 840 113549 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x02\x02", /*RSADSI-md2 (1 2 840 113549 2 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x02\x04", /*RSADSI-md4 (1 2 840 113549 2 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x02\x05", /*RSADSI-md5 (1 2 840 113549 2 5) */
	
    /* RSADSI encryption algorithms */
	"\x2A\x86\x48\x86\xF7\x0D\x03",     /*RSADSI-encryptionAlgorithm (1 2 840 113549 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x02", /*RSADSI-rc2CBC (1 2 840 113549 3 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x03", /*RSADSI-rc2ECB (1 2 840 113549 3 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x04", /*RSADSI-rc4 (1 2 840 113549 3 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x05", /*RSADSI-rc4WithMAC (1 2 840 113549 3 5) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x06", /*RSADSI-DESX-CBC (1 2 840 113549 3 6) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x07", /*RSADSI-DES-EDE3-CBC (1 2 840 113549 3 7) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x08", /*RSADSI-RC5CBC (1 2 840 113549 3 8) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x09", /*RSADSI-RC5CBCPad (1 2 840 113549 3 9) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x0A", /*RSADSI-CDMFCBCPad (1 2 840 113549 3 10) */
	
    /* cryptlib */
	"\x2B\x06\x01\x04\x01\x97\x55\x20\x01", /*cryptlibEnvelope (1 3 6 1 4 1 3029 32 1) */

    /* Not sure about these ones: */
	/*"\x2B\x0E\x02\x1A\x05",     sha (1 3 14 2 26 5) */
	/*"\x2B\x0E\x03\x02\x01\x01", rsa (1 3 14 3 2 1 1) */            //X-509
	/*"\x2B\x0E\x03\x02\x02\x01", sqmod-N (1 3 14 3 2 2 1) */        //X-509
	/*"\x2B\x0E\x03\x02\x03\x01", sqmod-NwithRSA (1 3 14 3 2 3 1) */ //X-509

   /* Miscellaneous partially-defunct OIW semi-standards aka algorithms */
	"\x2B\x0E\x03\x02\x02",     /*ISO-algorithm-md4WitRSA (1 3 14 3 2 2) */
	"\x2B\x0E\x03\x02\x03",     /*ISO-algorithm-md5WithRSA (1 3 14 3 2 3) */
	"\x2B\x0E\x03\x02\x04",     /*ISO-algorithm-md4WithRSAEncryption (1 3 14 3 2 4) */
	"\x2B\x0E\x03\x02\x06",     /*ISO-algorithm-desECB (1 3 14 3 2 6) */
	"\x2B\x0E\x03\x02\x07",     /*ISO-algorithm-desCBC (1 3 14 3 2 7) */
	"\x2B\x0E\x03\x02\x08",     /*ISO-algorithm-desOFB (1 3 14 3 2 8) */
	"\x2B\x0E\x03\x02\x09",     /*ISO-algorithm-desCFB (1 3 14 3 2 9) */
	"\x2B\x0E\x03\x02\x0A",     /*ISO-algorithm-desMAC (1 3 14 3 2 10) */
	"\x2B\x0E\x03\x02\x0B",     /*ISO-algorithm-rsaSignature (1 3 14 3 2 11) */   //ISO 9796
	"\x2B\x0E\x03\x02\x0C",     /*ISO-algorithm-dsa (1 3 14 3 2 12) */
	"\x2B\x0E\x03\x02\x0D",     /*ISO-algorithm-dsaWithSHA (1 3 14 3 2 13) */
	"\x2B\x0E\x03\x02\x0E",     /*ISO-algorithm-mdc2WithRSASignature (1 3 14 3 2 14) */
	"\x2B\x0E\x03\x02\x0F",     /*ISO-algorithm-shaWithRSASignature (1 3 14 3 2 15) */
	"\x2B\x0E\x03\x02\x10",     /*ISO-algorithm-dhWithCommonModulus (1 3 14 3 2 16) */
	"\x2B\x0E\x03\x02\x11",     /*ISO-algorithm-desEDE (1 3 14 3 2 17) */
	"\x2B\x0E\x03\x02\x12",     /*ISO-algorithm-sha (1 3 14 3 2 18) */
	"\x2B\x0E\x03\x02\x13",     /*ISO-algorithm-mdc-2 (1 3 14 3 2 19) */
	"\x2B\x0E\x03\x02\x14",     /*ISO-algorithm-dsaCommon (1 3 14 3 2 20) */
	"\x2B\x0E\x03\x02\x15",     /*ISO-algorithm-dsaCommonWithSHA (1 3 14 3 2 21) */
	"\x2B\x0E\x03\x02\x16",     /*ISO-algorithm-rsaKeyTransport (1 3 14 3 2 22) */
	"\x2B\x0E\x03\x02\x17",     /*ISO-algorithm-keyed-hash-seal (1 3 14 3 2 23) */
	"\x2B\x0E\x03\x02\x18",     /*ISO-algorithm-md2WithRSASignature (1 3 14 3 2 24) */
	"\x2B\x0E\x03\x02\x19",     /*ISO-algorithm-md5WithRSASignature (1 3 14 3 2 25) */
	"\x2B\x0E\x03\x02\x1A",     /*ISO-algorithm-sha1 (1 3 14 3 2 26) */
	"\x2B\x0E\x03\x02\x1B",     /*ISO-algorithm-ripemd160 (1 3 14 3 2 27) */
	"\x2B\x0E\x03\x02\x1D",     /*ISO-algorithm-sha-1WithRSAEncryption (1 3 14 3 2 29) */
	"\x2B\x0E\x03\x03\x01",     /*ISO-algorithm-simple-strong-auth-mechanism (1 3 14 3 3 1) */
    /* Not sure about these ones:
	/*"\x2B\x0E\x07\x02\x01\x01", ElGamal (1 3 14 7 2 1 1) */
	/*"\x2B\x0E\x07\x02\x03\x01", md2WithRSA (1 3 14 7 2 3 1) */
	/*"\x2B\x0E\x07\x02\x03\x02", md2WithElGamal (1 3 14 7 2 3 2) */
	
    /* X500 algorithms */
	"\x55\x08",         /*X500-Algorithms (2 5 8) */
	"\x55\x08\x01",     /*X500-Alg-Encryption (2 5 8 1) */
	"\x55\x08\x01\x01", /*rsa (2 5 8 1 1) */
	
    /* DMS-SDN-702 */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x01", /*id-sdnsSignatureAlgorithm (2 16 840 1 101 2 1 1 1) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x02", /*id-mosaicSignatureAlgorithm (2 16 840 1 101 2 1 1 2) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x03", /*id-sdnsConfidentialityAlgorithm (2 16 840 1 101 2 1 1 3) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x04", /*id-mosaicConfidentialityAlgorithm (2 16 840 1 101 2 1 1 4) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x05", /*id-sdnsIntegrityAlgorithm (2 16 840 1 101 2 1 1 5) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x06", /*id-mosaicIntegrityAlgorithm (2 16 840 1 101 2 1 1 6) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x07", /*id-sdnsTokenProtectionAlgorithm (2 16 840 1 101 2 1 1 7) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x08", /*id-mosaicTokenProtectionAlgorithm (2 16 840 1 101 2 1 1 8) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x09", /*id-sdnsKeyManagementAlgorithm (2 16 840 1 101 2 1 1 9) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0A", /*id-mosaicKeyManagementAlgorithm (2 16 840 1 101 2 1 1 10) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0B", /*id-sdnsKMandSigAlgorithm (2 16 840 1 101 2 1 1 11) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0C", /*id-mosaicKMandSigAlgorithm (2 16 840 1 101 2 1 1 12) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0D", /*id-SuiteASignatureAlgorithm (2 16 840 1 101 2 1 1 13) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0E", /*id-SuiteAConfidentialityAlgorithm (2 16 840 1 101 2 1 1 14) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0F", /*id-SuiteAIntegrityAlgorithm (2 16 840 1 101 2 1 1 15) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x10", /*id-SuiteATokenProtectionAlgorithm (2 16 840 1 101 2 1 1 16) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x11", /*id-SuiteAKeyManagementAlgorithm (2 16 840 1 101 2 1 1 17) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x12", /*id-SuiteAKMandSigAlgorithm (2 16 840 1 101 2 1 1 18) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x13", /*id-mosaicUpdatedSigAlgorithm (2 16 840 1 101 2 1 1 19) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x14", /*id-mosaicKMandUpdSigAlgorithms (2 16 840 1 101 2 1 1 20) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x15", /*id-mosaicUpdatedIntegAlgorithm (2 16 840 1 101 2 1 1 21) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x16", /*id-mosaicKeyEncryptionAlgorithm (2 16 840 1 101 2 1 1 22) */
	
   NULL	
   };


	char* AttributeTypeDict[] = {
    /* x9-57 */
	"\x2A\x86\x48\xCE\x38\x02\x01", /*x9.57-holdinstruction-none (1 2 840 10040 2 1) */
	"\x2A\x86\x48\xCE\x38\x02\x02", /*x9.57-holdinstruction-callissuer (1 2 840 10040 2 2) */
	"\x2A\x86\x48\xCE\x38\x02\x03", /*x9.57-holdinstruction-reject (1 2 840 10040 2 3) */
	"\x2A\x86\x48\xCE\x38\x04\x01", /*x9.57-dsa (1 2 840 10040 4 1) */
	"\x2A\x86\x48\xCE\x38\x04\x03", /*x9.57-dsaWithSha1 (1 2 840 10040 4 3) */
    
    /* x9-42 */
	"\x2A\x86\x48\xCE\x3E\x02\x01", /*x9.42-dhPublicNumber (1 2 840 10046 2 1) */
	
    /* Nortel Secure Networks */
	"\x2A\x86\x48\x86\xF6\x7D\x07",         /*nsn (1 2 840 113533 7) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x41\x00", /*nsn-ce-entrustVersInfo (1 2 840 113533 7 65 0) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x41",     /*nsn-ce (1 2 840 113533 7 65) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x42",     /*nsn-alg (1 2 840 113533 7 66) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0A", /*nsn-alg-cast5CBC (1 2 840 113533 7 66 10) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0B", /*nsn-alg-cast5MAC (1 2 840 113533 7 66 11) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0C", /*nsn-alg-pbeWithMD5AndCAST5-CBC (1 2 840 113533 7 66 12) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x43",     /*nsn-oc (1 2 840 113533 7 67) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x43\x0C", /*nsn-oc-entrustUser (1 2 840 113533 7 67 0) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x44\x00", /*nsn-at-entrustCAInfo (1 2 840 113533 7 68 0) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x44\x0A", /*nsn-at-attributeCertificate (1 2 840 113533 7 68 10) */
	"\x2A\x86\x48\x86\xF6\x7D\x07\x44",     /*nsn-at (1 2 840 113533 7 68) */
	
    /* PKCS #1 */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01",     /*pkcs-1 (1 2 840 113549 1 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", /*pkcs-1-rsaEncryption (1 2 840 113549 1 1 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x02", /*pkcs-1-MD2withRSAEncryption (1 2 840 113549 1 1 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x03", /*pkcs-1-MD4withRSAEncryption (1 2 840 113549 1 1 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04", /*pkcs-1-MD5withRSAEncryption (1 2 840 113549 1 1 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05", /*pkcs-1-SHA1withRSAEncryption (1 2 840 113549 1 1 5) */
	/*need to determine which of the following 2 is correct */
    /*"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x06", pkcs-1-ripemd160WithRSAEncryption (1 2 840 113549 1 1 6) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x06", /*pkcs-1-rsaOAEPEncryptionSET (1 2 840 113549 1 1 6) */
	
    /* PKCS #3 */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x03",     /*pkcs-3 (1 2 840 113549 1 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x03\x01", /*pkcs-3-dhKeyAgreement (1 2 840 113549 1 3 1) */
	
    /* PKCS #5 */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05",     /*pkcs-5 (1 2 840 113549 1 5) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x01", /*pkcs-5-pbeWithMD2AndDES-CBC (1 2 840 113549 1 5 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x03", /*pkcs-5-pbeWithMD5AndDES-CBC (1 2 840 113549 1 5 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x04", /*pkcs-5-pbeWithMD2AndRC2-CBC (1 2 840 113549 1 5 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x06", /*pkcs-5-pbeWithMD5AndRC2-CBC (1 2 840 113549 1 5 6) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x09", /*pkcs-5-pbeWithMD5AndXOR (1 2 840 113549 1 5 9) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0A", /*pkcs-5-pbeWithSHA1AndDES-CBC (1 2 840 113549 1 5 10) */
	
    /* PKCS #7 */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x07",     /*pkcs-7 (1 2 840 113549 1 7) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x07\x01", /*pkcs-7-data (1 2 840 113549 1 7 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02", /*pkcs-7-signedData (1 2 840 113549 1 7 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x07\x03", /*pkcs-7-envelopedData (1 2 840 113549 1 7 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x07\x04", /*pkcs-7-signedAndEnvelopedData (1 2 840 113549 1 7 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x07\x05", /*pkcs-7-digestData (1 2 840 113549 1 7 5) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x07\x06", /*pkcs-7-encryptedData (1 2 840 113549 1 7 6) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x07\x07", /*pkcs-7-dataWithAttributes (1 2 840 113549 1 7 7) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x07\x08", /*pkcs-7-encryptedPrivateKeyInfo (1 2 840 113549 1 7 8) */
	
    /* PKCS #9 */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09",     /*pkcs-9 (1 2 840 113549 1 9) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01", /*pkcs-9-emailAddress (1 2 840 113549 1 9 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x02", /*pkcs-9-unstructuredName (1 2 840 113549 1 9 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x03", /*pkcs-9-contentType (1 2 840 113549 1 9 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x04", /*pkcs-9-messageDigest (1 2 840 113549 1 9 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x05", /*pkcs-9-signingTime (1 2 840 113549 1 9 5) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x06", /*pkcs-9-countersignature (1 2 840 113549 1 9 6) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x07", /*pkcs-9-challengePassword (1 2 840 113549 1 9 7) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x08", /*pkcs-9-unstructuredAddress (1 2 840 113549 1 9 8) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x09", /*pkcs-9-extendedCertificateAttributes (1 2 840 113549 1 9 9) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x0A", /*pkcs-9-issuerAndSerialNumber (1 2 840 113549 1 9 10) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x0B", /*pkcs-9-passwordCheck (1 2 840 113549 1 9 11) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x0C", /*pkcs-9-publicKey (1 2 840 113549 1 9 12) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x0D", /*pkcs-9-signingDescription (1 2 840 113549 1 9 13) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x0E", /*pkcs-9-X.509 extension (1 2 840 113549 1 9 14) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x09\x0F", /*pkcs-9-SMIMECapabilities (1 2 840 113549 1 9 15) */
	
    /* PKCS #12 */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C",         /*pkcs-12 (1 2 840 113549 1 12) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01",     /*pkcs-12-modeID (1 2 840 113549 1 12 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01\x01", /*pkcs-12-OfflineTransportMode (1 2 840 113549 1 12 1 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01\x02", /*pkcs-12-OnlineTransportMode (1 2 840 113549 1 12 1 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x02",     /*pkcs-12-ESPVKID (1 2 840 113549 1 12 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x02\x01", /*pkcs-12-PKCS8KeyShrouding (1 2 840 113549 1 12 2 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x03",     /*pkcs-12-BagID (1 2 840 113549 1 12 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x03\x01", /*pkcs-12-KeyBagID (1 2 840 113549 1 12 3 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x03\x02", /*pkcs-12-CertAndCRLBagID (1 2 840 113549 1 12 3 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x03\x03", /*pkcs-12-SecretBagID (1 2 840 113549 1 12 3 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x04",     /*pkcs-12-CertBagID (1 2 840 113549 1 12 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x04\x01", /*pkcs-12-X509CertCRLBag (1 2 840 113549 1 12 4 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x04\x02", /*pkcs-12-SDSICertBag (1 2 840 113549 1 12 4 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05",     /*pkcs-12-OID (1 2 840 113549 1 12 5) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01", /*pkcs-12-PBEID (1 2 840 113549 1 12 5 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x01", /*pkcs-12-PBEWithSha1And128BitRC4 (1 2 840 113549 1 12 5 1 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x02", /*pkcs-12-PBEWithSha1And40BitRC4 (1 2 840 113549 1 12 5 1 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x03", /*pkcs-12-PBEWithSha1AndTripleDESCBC (1 2 840 113549 1 12 5 1 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x04", /*pkcs-12-PBEWithSha1And128BitRC2CBC (1 2 840 113549 1 12 5 1 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x05", /*pkcs-12-PBEWithSha1And40BitRC2CBC (1 2 840 113549 1 12 5 1 5) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x06", /*pkcs-12-PBEWithSha1AndRC4 (1 2 840 113549 1 12 5 1 6) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x01\x07", /*pkcs-12-PBEWithSha1AndRC2CBC (1 2 840 113549 1 12 5 1 7) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x02",     /*pkcs-12-EnvelopingID (1 2 840 113549 1 12 5 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x02\x01", /*pkcs-12-RSAEncryptionWith128BitRC4 (1 2 840 113549 1 12 5 2 1) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x02\x02", /*pkcs-12-RSAEncryptionWith40BitRC4 (1 2 840 113549 1 12 5 2 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x02\x03", /*pkcs-12-RSAEncryptionWithTripleDES (1 2 840 113549 1 12 5 2 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x03",     /*pkcs-12-SignatureID (1 2 840 113549 1 12 5 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x05\x03\x01", /*pkcs-12-RSASignatureWithSHA1Digest (1 2 840 113549 1 12 5 3 1) */

    /* RSADSI digest algorithms */
	"\x2A\x86\x48\x86\xF7\x0D\x02",     /*RSADSI-digestAlgorithm (1 2 840 113549 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x02\x02", /*RSADSI-md2 (1 2 840 113549 2 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x02\x04", /*RSADSI-md4 (1 2 840 113549 2 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x02\x05", /*RSADSI-md5 (1 2 840 113549 2 5) */
	
    /* RSADSI encryption algorithms */
	"\x2A\x86\x48\x86\xF7\x0D\x03",     /*RSADSI-encryptionAlgorithm (1 2 840 113549 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x02", /*RSADSI-rc2CBC (1 2 840 113549 3 2) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x03", /*RSADSI-rc2ECB (1 2 840 113549 3 3) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x04", /*RSADSI-rc4 (1 2 840 113549 3 4) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x05", /*RSADSI-rc4WithMAC (1 2 840 113549 3 5) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x06", /*RSADSI-DESX-CBC (1 2 840 113549 3 6) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x07", /*RSADSI-DES-EDE3-CBC (1 2 840 113549 3 7) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x08", /*RSADSI-RC5CBC (1 2 840 113549 3 8) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x09", /*RSADSI-RC5CBCPad (1 2 840 113549 3 9) */
	"\x2A\x86\x48\x86\xF7\x0D\x03\x0A", /*RSADSI-CDMFCBCPad (1 2 840 113549 3 10) */
	
    /* Microsoft OIDs */
	"\x2A\x86\x48\x86\xF7\x14\x04\x03", /*microsoftExcel (1 2 840 113556 4 3) */
	"\x2A\x86\x48\x86\xF7\x14\x04\x04", /*titledWithOID (1 2 840 113556 4 4) */
	"\x2A\x86\x48\x86\xF7\x14\x04\x05", /*microsoftPowerPoint (1 2 840 113556 4 5) */

    /* cryptlib */
	"\x2B\x06\x01\x04\x01\x97\x55\x20\x01", /*cryptlibEnvelope (1 3 6 1 4 1 3029 32 1) */

    /* PKIX */
	"\x2B\x06\x01\x05\x05\x07",     /*pkix-oid (1 3 6 1 5 5 7) */
	"\x2B\x06\x01\x05\x05\x07\x01", /*pkix-subjectInfoAccess (1 3 6 1 5 5 7 1) */
	"\x2B\x06\x01\x05\x05\x07\x02", /*pkix-authorityInfoAccess (1 3 6 1 5 5 7 2) */
	"\x2B\x06\x01\x05\x05\x07\x04", /*pkix-cps (1 3 6 1 5 5 7 4) */
	"\x2B\x06\x01\x05\x05\x07\x05", /*pkix-userNotice (1 3 6 1 5 5 7 5) */

    /* Not sure about these ones: */
	/*"\x2B\x0E\x02\x1A\x05",     sha (1 3 14 2 26 5) */
	/*"\x2B\x0E\x03\x02\x01\x01", rsa (1 3 14 3 2 1 1) */            //X-509
	/*"\x2B\x0E\x03\x02\x02\x01", sqmod-N (1 3 14 3 2 2 1) */        //X-509
	/*"\x2B\x0E\x03\x02\x03\x01", sqmod-NwithRSA (1 3 14 3 2 3 1) */ //X-509

   /* Miscellaneous partially-defunct OIW semi-standards aka algorithms */
	"\x2B\x0E\x03\x02\x02",     /*ISO-algorithm-md4WitRSA (1 3 14 3 2 2) */
	"\x2B\x0E\x03\x02\x03",     /*ISO-algorithm-md5WithRSA (1 3 14 3 2 3) */
	"\x2B\x0E\x03\x02\x04",     /*ISO-algorithm-md4WithRSAEncryption (1 3 14 3 2 4) */
	"\x2B\x0E\x03\x02\x06",     /*ISO-algorithm-desECB (1 3 14 3 2 6) */
	"\x2B\x0E\x03\x02\x07",     /*ISO-algorithm-desCBC (1 3 14 3 2 7) */
	"\x2B\x0E\x03\x02\x08",     /*ISO-algorithm-desOFB (1 3 14 3 2 8) */
	"\x2B\x0E\x03\x02\x09",     /*ISO-algorithm-desCFB (1 3 14 3 2 9) */
	"\x2B\x0E\x03\x02\x0A",     /*ISO-algorithm-desMAC (1 3 14 3 2 10) */
	"\x2B\x0E\x03\x02\x0B",     /*ISO-algorithm-rsaSignature (1 3 14 3 2 11) */   //ISO 9796
	"\x2B\x0E\x03\x02\x0C",     /*ISO-algorithm-dsa (1 3 14 3 2 12) */
	"\x2B\x0E\x03\x02\x0D",     /*ISO-algorithm-dsaWithSHA (1 3 14 3 2 13) */
	"\x2B\x0E\x03\x02\x0E",     /*ISO-algorithm-mdc2WithRSASignature (1 3 14 3 2 14) */
	"\x2B\x0E\x03\x02\x0F",     /*ISO-algorithm-shaWithRSASignature (1 3 14 3 2 15) */
	"\x2B\x0E\x03\x02\x10",     /*ISO-algorithm-dhWithCommonModulus (1 3 14 3 2 16) */
	"\x2B\x0E\x03\x02\x11",     /*ISO-algorithm-desEDE (1 3 14 3 2 17) */
	"\x2B\x0E\x03\x02\x12",     /*ISO-algorithm-sha (1 3 14 3 2 18) */
	"\x2B\x0E\x03\x02\x13",     /*ISO-algorithm-mdc-2 (1 3 14 3 2 19) */
	"\x2B\x0E\x03\x02\x14",     /*ISO-algorithm-dsaCommon (1 3 14 3 2 20) */
	"\x2B\x0E\x03\x02\x15",     /*ISO-algorithm-dsaCommonWithSHA (1 3 14 3 2 21) */
	"\x2B\x0E\x03\x02\x16",     /*ISO-algorithm-rsaKeyTransport (1 3 14 3 2 22) */
	"\x2B\x0E\x03\x02\x17",     /*ISO-algorithm-keyed-hash-seal (1 3 14 3 2 23) */
	"\x2B\x0E\x03\x02\x18",     /*ISO-algorithm-md2WithRSASignature (1 3 14 3 2 24) */
	"\x2B\x0E\x03\x02\x19",     /*ISO-algorithm-md5WithRSASignature (1 3 14 3 2 25) */
	"\x2B\x0E\x03\x02\x1A",     /*ISO-algorithm-sha1 (1 3 14 3 2 26) */
	"\x2B\x0E\x03\x02\x1B",     /*ISO-algorithm-ripemd160 (1 3 14 3 2 27) */
	"\x2B\x0E\x03\x02\x1D",     /*ISO-algorithm-sha-1WithRSAEncryption (1 3 14 3 2 29) */
	"\x2B\x0E\x03\x03\x01",     /*ISO-algorithm-simple-strong-auth-mechanism (1 3 14 3 3 1) */
    /* Not sure about these ones:
	/*"\x2B\x0E\x07\x02\x01\x01", ElGamal (1 3 14 7 2 1 1) */
	/*"\x2B\x0E\x07\x02\x03\x01", md2WithRSA (1 3 14 7 2 3 1) */
	/*"\x2B\x0E\x07\x02\x03\x02", md2WithElGamal (1 3 14 7 2 3 2) */
	
    /* X.520 id-at = 2 5 4*/
	"\x55\x04\x00", /*X.520-at-objectClass (2 5 4 0) */
	"\x55\x04\x01", /*X.520-at-aliasObjectName (2 5 4 1) */
	"\x55\x04\x02", /*X.520-at-knowledgeInformation (2 5 4 2) */
	"\x55\x04\x03", /*X.520-at-commonName (2 5 4 3) */
	"\x55\x04\x04", /*X.520-at-surname (2 5 4 4) */
	"\x55\x04\x05", /*X.520-at-serialNumber (2 5 4 5) */
	"\x55\x04\x06", /*X.520-at-countryName (2 5 4 6) */
	"\x55\x04\x07", /*X.520-at-localityName (2 5 4 7) */
	"\x55\x04\x08", /*X.520-at-stateOrProvinceName (2 5 4 8) */
	"\x55\x04\x09", /*X.520-at-streetAddress (2 5 4 9) */
	"\x55\x04\x0A", /*X.520-at-organizationName (2 5 4 10) */
	"\x55\x04\x0B", /*X.520-at-organizationalUnitName (2 5 4 11) */
	"\x55\x04\x0C", /*X.520-at-title (2 5 4 12) */
	"\x55\x04\x0D", /*X.520-at-description (2 5 4 13) */
	"\x55\x04\x0E", /*X.520-at-searchGuide (2 5 4 14) */
	"\x55\x04\x0F", /*X.520-at-businessCategory (2 5 4 15) */
	"\x55\x04\x10", /*X.520-at-postalAddress (2 5 4 16) */
	"\x55\x04\x11", /*X.520-at-postalCode (2 5 4 17) */
	"\x55\x04\x12", /*X.520-at-postOfficeBox (2 5 4 18) */
	"\x55\x04\x13", /*X.520-at-physicalDeliveryOfficeName (2 5 4 19) */
	"\x55\x04\x14", /*X.520-at-telephoneNumber (2 5 4 20) */
	"\x55\x04\x15", /*X.520-at-telexNumber (2 5 4 21) */
	"\x55\x04\x16", /*X.520-at-teletexTerminalIdentifier (2 5 4 22) */
	"\x55\x04\x17", /*X.520-at-facsimileTelephoneNumber (2 5 4 23) */
	"\x55\x04\x18", /*X.520-at-x121AddreX.520-at-ss (2 5 4 24) */
	"\x55\x04\x19", /*X.520-at-internationalISNNumber (2 5 4 25) */
	"\x55\x04\x1A", /*X.520-at-registeredAddress (2 5 4 26) */
	"\x55\x04\x1B", /*X.520-at-destinationIndicator (2 5 4 27) */
	"\x55\x04\x1C", /*X.520-at-preferredDeliveryMehtod (2 5 4 28) */
	"\x55\x04\x1D", /*X.520-at-presentationAddress (2 5 4 29) */
	"\x55\x04\x1E", /*X.520-at-supportedApplicationContext (2 5 4 30) */
	"\x55\x04\x1F", /*X.520-at-member (2 5 4 31) */
	"\x55\x04\x20", /*X.520-at-owner (2 5 4 32) */
	"\x55\x04\x21", /*X.520-at-roleOccupant (2 5 4 33) */
	"\x55\x04\x22", /*X.520-at-seeAlso (2 5 4 34) */
	"\x55\x04\x23", /*X.520-at-userPassword (2 5 4 35) */
	"\x55\x04\x24", /*X.520-at-userCertificate (2 5 4 36) */
	"\x55\x04\x25", /*X.520-at-CAcertificate (2 5 4 37) */
	"\x55\x04\x26", /*X.520-at-authorityRevocationList (2 5 4 38) */
	"\x55\x04\x27", /*X.520-at-certifcateRevocationList (2 5 4 39) */
	"\x55\x04\x28", /*X.520-at-crossCertificatePair (2 5 4 40) */
	"\x55\x04\x34", /*X.520-at-supportedAlgorithms (2 5 4 52) */
	"\x55\x04\x35", /*X.520-at-deltaRevocationList (2 5 4 53) */
	"\x55\x04\x3A", /*X.520-at-crossCertificatePair (2 5 4 58) */
	
    /* X500 algorithms */
	"\x55\x08",         /*X500-Algorithms (2 5 8) */
	"\x55\x08\x01",     /*X500-Alg-Encryption (2 5 8 1) */
	"\x55\x08\x01\x01", /*rsa (2 5 8 1 1) */
	
    /* X.509   id-ce = 2 5 29*/
	"\x55\x1D\x01", /*X.509-ce-authorityKeyIdentifier (2 5 29 1) */
	"\x55\x1D\x02", /*X.509-ce-keyAttributes (2 5 29 2) */
	"\x55\x1D\x03", /*X.509-ce-certificatePolicies (2 5 29 3) */
	"\x55\x1D\x04", /*X.509-ce-keyUsageRestriction (2 5 29 4) */
	"\x55\x1D\x05", /*X.509-ce-policyMapping (2 5 29 5) */
	"\x55\x1D\x06", /*X.509-ce-subtreesConstraint (2 5 29 6) */
	"\x55\x1D\x07", /*X.509-ce-subjectAltName (2 5 29 7) */
	"\x55\x1D\x08", /*X.509-ce-issuerAltName (2 5 29 8) */
	"\x55\x1D\x09", /*X.509-ce-subjectDirectoryAttributes (2 5 29 9) */
	"\x55\x1D\x0A", /*X.509-ce-basicConstraints  x.509 (2 5 29 10) */
	"\x55\x1D\x0B", /*X.509-ce-nameConstraints (2 5 29 11) */
	"\x55\x1D\x0C", /*X.509-ce-policyConstraints (2 5 29 12) */
	"\x55\x1D\x0D", /*X.509-ce-basicConstraints  9.55 (2 5 29 13) */
	"\x55\x1D\x0E", /*X.509-ce-subjectKeyIdentifier (2 5 29 14) */
	"\x55\x1D\x0F", /*X.509-ce-keyUsage (2 5 29 15) */
	"\x55\x1D\x10", /*X.509-ce-privateKeyUsagePeriod (2 5 29 16) */
	"\x55\x1D\x11", /*X.509-ce-subjectAltName (2 5 29 17) */
	"\x55\x1D\x12", /*X.509-ce-issuerAltName (2 5 29 18) */
	"\x55\x1D\x13", /*X.509-ce-basicConstraints (2 5 29 19) */
	"\x55\x1D\x14", /*X.509-ce-cRLNumber (2 5 29 20) */
	"\x55\x1D\x15", /*X.509-ce-reasonCode (2 5 29 21) */
	"\x55\x1D\x17", /*X.509-ce-instructionCode (2 5 29 23) */
	"\x55\x1D\x18", /*X.509-ce-invalidityDate (2 5 29 24) */
	"\x55\x1D\x1B", /*X.509-ce-deltaCRLIndicator (2 5 29 27) */
	"\x55\x1D\x1C", /*X.509-ce-issuingDistributionPoint (2 5 29 28) */
	"\x55\x1D\x1D", /*X.509-ce-certificateIssuer (2 5 29 29) */
	"\x55\x1D\x1E", /*X.509-ce-nameConstraints (2 5 29 30) */
	"\x55\x1D\x1F", /*X.509-ce-cRLDistPoints (2 5 29 31) */
	"\x55\x1D\x20", /*X.509-ce-certificatePolicies (2 5 29 32) */
	"\x55\x1D\x21", /*X.509-ce-policyMappings (2 5 29 33) */
	"\x55\x1D\x23", /*X.509-ce-authorityKeyIdentifier (2 5 29 35) */
	"\x55\x1D\x24", /*X.509-ce-policyConstraints (2 5 29 36) */
	
    /* DMS-SDN-702 */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x01", /*id-sdnsSignatureAlgorithm (2 16 840 1 101 2 1 1 1) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x02", /*id-mosaicSignatureAlgorithm (2 16 840 1 101 2 1 1 2) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x03", /*id-sdnsConfidentialityAlgorithm (2 16 840 1 101 2 1 1 3) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x04", /*id-mosaicConfidentialityAlgorithm (2 16 840 1 101 2 1 1 4) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x05", /*id-sdnsIntegrityAlgorithm (2 16 840 1 101 2 1 1 5) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x06", /*id-mosaicIntegrityAlgorithm (2 16 840 1 101 2 1 1 6) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x07", /*id-sdnsTokenProtectionAlgorithm (2 16 840 1 101 2 1 1 7) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x08", /*id-mosaicTokenProtectionAlgorithm (2 16 840 1 101 2 1 1 8) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x09", /*id-sdnsKeyManagementAlgorithm (2 16 840 1 101 2 1 1 9) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0A", /*id-mosaicKeyManagementAlgorithm (2 16 840 1 101 2 1 1 10) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0B", /*id-sdnsKMandSigAlgorithm (2 16 840 1 101 2 1 1 11) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0C", /*id-mosaicKMandSigAlgorithm (2 16 840 1 101 2 1 1 12) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0D", /*id-SuiteASignatureAlgorithm (2 16 840 1 101 2 1 1 13) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0E", /*id-SuiteAConfidentialityAlgorithm (2 16 840 1 101 2 1 1 14) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x0F", /*id-SuiteAIntegrityAlgorithm (2 16 840 1 101 2 1 1 15) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x10", /*id-SuiteATokenProtectionAlgorithm (2 16 840 1 101 2 1 1 16) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x11", /*id-SuiteAKeyManagementAlgorithm (2 16 840 1 101 2 1 1 17) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x12", /*id-SuiteAKMandSigAlgorithm (2 16 840 1 101 2 1 1 18) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x13", /*id-mosaicUpdatedSigAlgorithm (2 16 840 1 101 2 1 1 19) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x14", /*id-mosaicKMandUpdSigAlgorithms (2 16 840 1 101 2 1 1 20) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x15", /*id-mosaicUpdatedIntegAlgorithm (2 16 840 1 101 2 1 1 21) */
	"\x60\x86\x48\x01\x65\x02\x01\x01\x16", /*id-mosaicKeyEncryptionAlgorithm (2 16 840 1 101 2 1 1 22) */

	/* Netscape */
	"\x60\x86\x48\x01\x86\xF8\x42\x01\x01", /*netscape-cert-type (2 16 840 1 113730 1 1) */
	"\x60\x86\x48\x01\x86\xF8\x42\x01\x02", /*netscape-base-url (2 16 840 1 113730 1 2) */
	"\x60\x86\x48\x01\x86\xF8\x42\x01\x03", /*netscape-revocation-url (2 16 840 1 113730 1 3) */
	"\x60\x86\x48\x01\x86\xF8\x42\x01\x04", /*netscape-ca-revocation-url (2 16 840 1 113730 1 4) */
	"\x60\x86\x48\x01\x86\xF8\x42\x02\x05", /*netscape-cert-sequence (2 16 840 1 113730 2 5) */
	"\x60\x86\x48\x01\x86\xF8\x42\x02\x06", /*netscape-cert-url (2 16 840 1 113730 2 6) */
	"\x60\x86\x48\x01\x86\xF8\x42\x01\x07", /*netscape-renewal-url (2 16 840 1 113730 1 7) */
	"\x60\x86\x48\x01\x86\xF8\x42\x01\x08", /*netscape-ca-policy-url (2 16 840 1 113730 1 8) */
	"\x60\x86\x48\x01\x86\xF8\x42\x01\x09", /*netscape-HomePage-url (2 16 840 1 113730 1 9) */
	"\x60\x86\x48\x01\x86\xF8\x42\x01\x0A", /*netscape-EntityLogo (2 16 840 1 113730 1 10) */
	"\x60\x86\x48\x01\x86\xF8\x42\x01\x0B", /*netscape-UserPicture (2 16 840 1 113730 1 11) */
	"\x60\x86\x48\x01\x86\xF8\x42\x01\x0C", /*netscape-ssl-server-name (2 16 840 1 113730 1 12) */
	"\x60\x86\x48\x01\x86\xF8\x42\x01\x0D", /*netscape-comment (2 16 840 1 113730 1 13) */
	"\x60\x86\x48\x01\x86\xF8\x42\x02",     /*netscape-data-type (2 16 840 1 113730 2) */
	"\x60\x86\x48\x01\x86\xF8\x42\x02\x01", /*netscape-dt-GIF (2 16 840 1 113730 2 1) */
	"\x60\x86\x48\x01\x86\xF8\x42\x02\x02", /*netscape-dt-JPEG (2 16 840 1 113730 2 2) */
	"\x60\x86\x48\x01\x86\xF8\x42\x02\x03", /*netscape-dt-URL (2 16 840 1 113730 2 3) */
	"\x60\x86\x48\x01\x86\xF8\x42\x02\x04", /*netscape-dt-HTML (2 16 840 1 113730 2 4) */
	"\x60\x86\x48\x01\x86\xF8\x42\x02\x05", /*netscape-dt-CertSeq (2 16 840 1 113730 2 5) */
	"\x60\x86\x48\x01\x86\xF8\x42\x03",     /*netscape-directory (2 16 840 1 113730 3) */
	
    /* SET */
	"\x86\x8D\x6F\x02", /*hashedRootKey (2 54 1775 2) */
	"\x86\x8D\x6F\x03", /*certificateType (2 54 1775 3) */
	"\x86\x8D\x6F\x04", /*merchantData (2 54 1775 4) */
	"\x86\x8D\x6F\x05", /*cardCertRequired (2 54 1775 5) */
	"\x86\x8D\x6F\x06", /*tunneling (2 54 1775 6) */
	"\x86\x8D\x6F\x07", /*setQualifier (2 54 1775 7) */
	"\x86\x8D\x6F\x63", /*set-data (2 54 1775 99) */
	
   NULL	
   };
/*------------------------------------------------------------------------------
                              Global Variables
------------------------------------------------------------------------------*/

BYTE
   *pDictMemory = NULL_PTR,
   DictVersion = 0;

BYTE*
   dwPtrMax = 0;

USHORT
   usDictCount = 0;

#ifdef _STUDY
FILE
   *pfdLog,
   *pfdLogFreq,
	*pfdBinAc256,
	*pfdBinAc16,
	*pfdBinAc4,
	*pfdBinAc2;
int
	sum, i,
   Ac256[256],
   Ac16[16],
   Ac4[4],
   Ac2[2];
#endif

/*------------------------------------------------------------------------------
                       Static Functions Declaration 
------------------------------------------------------------------------------*/

static int CC_Comp(BLOC *pCertificate,
                   BLOC *pCompressedCertificate
                  );

static int CC_Uncomp(BLOC *pCompressedCertificate,
                     BLOC *pUncompressedCertificate
                    );

static int CC_ExtractContent(ASN1 *pAsn1
                            );

static int CC_BuildAsn1(ASN1 *pAsn1
                       );

static int SearchDataByIndex(USHORT usIndex,
                             BYTE   *pDict,
                             BLOC   *pOutBloc
                            );

static int CC_RawEncode(BLOC *pInBloc,
                        BLOC *pOutBloc,
								BOOL bUseDictionnary
                       );

static int CC_RawDecode(BYTE     *pInData,
                        BLOC     *pOutBloc,
                        USHORT   *pLength,
								BOOL		bUseDictionnary
                       );

static int CC_GenericCompress(BLOC *pUncompBloc,
                              BLOC *pCompBloc,
                              BYTE AlgoID
                             );

static int CC_GenericUncompress(BLOC *pCompBloc,
                                BLOC *pUncompBloc,
                                BYTE AlgoID
                               );

static int CC_Encode_TBSCertificate(BLOC *pInBloc,
                                    BLOC *pOutBloc
                                   );

static int CC_Encode_CertificateSerialNumber(BLOC *pInBloc,
                                             BLOC *pOutBloc
                                            );

static int CC_Encode_AlgorithmIdentifier(BLOC *pInBloc,
                                         BLOC *pOutBloc
                                        );

static int CC_Encode_Name(BLOC *pInBloc,
                          BLOC *pOutBloc
                         );

static int CC_Encode_RDN(BLOC *pInBloc,
                         BLOC *pOutBloc
                        );

static int CC_Encode_AVA(BLOC *pInBloc,
                         BLOC *pOutBloc
                        );

static int CC_Encode_Validity(BLOC *pInBloc,
                              BLOC *pOutBloc
                             );

static int CC_Encode_UTCTime(BLOC *pInBloc,
                             BLOC *pOutBloc,
                             BYTE *pFormat
                            );

static int CC_Encode_SubjectPKInfo(BLOC *pInBloc,
                                   BLOC *pOutBloc
                                  );

static int CC_Encode_UniqueIdentifier(BLOC *pInBloc,
                                      BLOC *pOutBloc
                                     );

static int CC_Encode_Extensions(BLOC *pInBloc,
                                BLOC *pOutBloc
                               );

static int CC_Encode_Extension(BLOC *pInBloc,
                               BLOC *pOutBloc
                              );

static int CC_Encode_Signature(BLOC *pInBloc,
                               BLOC *pOutBloc
                              );

static int CC_Decode_TBSCertificate(BYTE    *pInData,
                                    BLOC    *pOutBloc,
                                    USHORT  *pLength
                                   );

static int CC_Decode_CertificateSerialNumber(BYTE    *pInData,
                                             BLOC    *pOutBloc,
                                             USHORT  *pLength
                                            );

static int CC_Decode_AlgorithmIdentifier(BYTE    *pInData,
                                         BLOC    *pOutBloc,
                                         USHORT  *pLength
                                        );

static int CC_Decode_Name(BYTE    *pInData,
                          BLOC    *pOutBloc,
                          USHORT  *pLength
                         );

static int CC_Decode_RDN(BYTE    *pInData,
                         BLOC    *pOutBloc,
                         USHORT  *pLength
                        );

static int CC_Decode_AVA(BYTE    *pInData,
                         BLOC    *pOutBloc,
                         USHORT  *pLength
                        );

static int CC_Decode_Validity(BYTE    *pInData,
                              BLOC    *pOutBloc,
                              USHORT  *pLength
                             );

static int CC_Decode_UTCTime(BYTE   *pInData,
                             BYTE   Format,
                             BLOC   *pOutBloc,
                             USHORT *pLength
                            );

static int CC_Decode_SubjectPKInfo(BYTE    *pInData,
                                   BLOC    *pOutBloc,
                                   USHORT  *pLength
                                  );

static int CC_Decode_UniqueIdentifier(BYTE    *pInData,
                                      BLOC    *pOutBloc,
                                      USHORT  *pLength
                                     );

static int CC_Decode_Extensions(BYTE    *pInData,
                                BLOC    *pOutBloc,
                                USHORT  *pLength
                               );

static int CC_Decode_Extension(BYTE    *pInData,
                               BLOC    *pOutBloc,
                               USHORT  *pLength
                              );

static int CC_Decode_Signature(BYTE    *pInData,
                               BLOC    *pOutBloc,
                               USHORT  *pLength
                              );

/*------------------------------------------------------------------------------
* static DWORD get_file_len(BYTE *lpszFileName)
* 
* Description : Get length of file.
*
* Remarks     : Nothing.
*
* In          : lpszFileName = Name of file.
*
* Out         : Nothing.
*
* Responses   : size of file, -1 if error occur.
*
------------------------------------------------------------------------------*/                                    
static DWORD get_file_len(BYTE *lpszFileName)
{                                             
   int    fp;
   DWORD  nLen;

   fp = _open(lpszFileName, O_RDONLY);
   if (fp != 0)
   {
	   nLen = _filelength(fp);
	   _close(fp);
   }
   else
   {
	   nLen = -1;
   }

   return(nLen);
} 



/*******************************************************************************
* int CC_Init(BYTE  bDictMode, BYTE *pszDictName)
*
* Description : Lit le dictionnaire et son num�ro de version depuis la base de
*               registre vers la m�moire.
*
* Remarks     :
*
* In          : 
*
* Out         : 
*
* Responses   : 
*
*******************************************************************************/
int CC_Init(BYTE  bDictMode, BYTE *pszDictName)
{
   switch (bDictMode)
   {
#ifndef _STATIC
      /* Dictionary read as resource data GPK_X509_DICTIONARY                 */
      case DICT_STANDARD:
      {
         LPBYTE pbDict;
         DWORD cbDict;
         HRSRC hRsrc;
         HGLOBAL hDict;

         hRsrc = FindResource(g_hInstRes, 
                              //MAKEINTRESOURCE(GPK_X509_DICTIONARY), 
                              TEXT("GPK_X509_DICTIONARY"),
                              RT_RCDATA
                             );
         if (NULL == hRsrc)
         {
           goto ERROR_INIT;
         }
         cbDict = SizeofResource(g_hInstRes, hRsrc);
         if (0 == cbDict)
         {
           goto ERROR_INIT;
         }
         hDict = LoadResource(g_hInstRes, hRsrc);
         if (NULL == hDict)
         {
           goto ERROR_INIT;
         }
         pbDict = LockResource(hDict);
         if (NULL == pbDict)
         {
           goto ERROR_INIT;
         }

         DictVersion = *pbDict;
         usDictCount = (WORD)cbDict - 1;
         pDictMemory = GMEM_Alloc(usDictCount);
		 if (pDictMemory == NULL)
		 {
           goto ERROR_INIT;
         }
         memcpy(pDictMemory, &pbDict[1], usDictCount);
    
         return(RV_SUCCESS);
      }  
      break;
#endif
      
      /* Dictionary read as registyry entry in HKEY_LOCAL_MACHINE with key as */
      /* pszDictName parameter                                                */
      case DICT_REGISTRY:
      {
         DWORD  
            err,
            dwIgn;
         HKEY   
            hRegKey;
         BYTE
            *ptr;

         if (pszDictName == NULL_PTR)
         {
            goto ERROR_INIT;
         }

         err = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
                              (const char *) pszDictName,
                              0L, 
                              "", 
                              REG_OPTION_NON_VOLATILE,
                              KEY_ALL_ACCESS, 
                              NULL, 
                              &hRegKey,
                              &dwIgn
                             );
         if(err != ERROR_SUCCESS)
         {
            goto ERROR_INIT;
         }
 
         dwIgn = 0;
         err = RegQueryValueEx(hRegKey,  
                               "X509 Dictionary", 
                               NULL,    
                               NULL,   
                               NULL,   
                               &dwIgn   
                              );
         if(err != ERROR_SUCCESS)
         {
			 RegCloseKey(hRegKey);
			 goto ERROR_INIT;
         }

         ptr = GMEM_Alloc(dwIgn);
		 if (ptr == NULL)
		 {
           RegCloseKey(hRegKey);
		   goto ERROR_INIT;
         }

         err = RegQueryValueEx(hRegKey,  
                               "X509 Dictionary", 
                               NULL,    
                               NULL,   
                               ptr,   
                               &dwIgn   
                              );
         if(err != ERROR_SUCCESS)
         {
            RegCloseKey(hRegKey);
			GMEM_Free(ptr);
            goto ERROR_INIT;
         }

	      DictVersion = (BYTE)ptr[0];

         usDictCount = (WORD)dwIgn - 1;
         pDictMemory = GMEM_Alloc(usDictCount);

		 if (pDictMemory == NULL)
		 {
			RegCloseKey(hRegKey);
			GMEM_Free(ptr);
            goto ERROR_INIT;
		 }

         memcpy(pDictMemory, &ptr[1], usDictCount);

         RegCloseKey(hRegKey);
		 GMEM_Free(ptr);
         return(RV_SUCCESS);
      }
      break;

      /* Dictionary read as file in path pszDictName parameter                */
      case DICT_FILE:
      {
         DWORD  
            dwFileLen;
         BYTE
            *ptr;
         FILE
            *fp;

         if (pszDictName == NULL_PTR)
         {
            goto ERROR_INIT;
         }
         dwFileLen = get_file_len(pszDictName);
         ptr = GMEM_Alloc(dwFileLen);
		 if (ptr == NULL)
		 {
			 goto ERROR_INIT;
         }
            
         fp = fopen(pszDictName, "rb");
         if (fp == NULL)
         {
            GMEM_Free(ptr);
			goto ERROR_INIT;
         }

         if (!fread(ptr, dwFileLen, 1, fp))
         {
            fclose(fp);
			GMEM_Free(ptr);
            goto ERROR_INIT;
         }
         fclose(fp);
            
	     DictVersion = (BYTE)ptr[0];

         usDictCount = (WORD)dwFileLen - 1;
         pDictMemory = GMEM_Alloc(usDictCount);

		 if (pDictMemory == NULL)
		 {
			 GMEM_Free(ptr);
			 goto ERROR_INIT;
		 }

         memcpy(pDictMemory, &ptr[1], usDictCount);

         GMEM_Free(ptr);

         return(RV_SUCCESS);
      }
      break;

      default:
         break;
   }

ERROR_INIT:
   DictVersion = 0;
   usDictCount = 0;
   pDictMemory = NULL_PTR;
   return(RV_BAD_DICTIONARY);
}


/*******************************************************************************
* int CC_Exit(void)
*
* Description : Free dictionary.
*
* Remarks     :
*
* In          : 
*
* Out         : 
*
* Responses   : 
*
*******************************************************************************/
int CC_Exit(void)
{
   DictVersion = 0;
   usDictCount = 0;
   if (pDictMemory != NULL_PTR)
   {
      GMEM_Free(pDictMemory);
   }
   pDictMemory = NULL_PTR;
   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Compress(BLOC *pCertificate,
*                 BLOC *pCompressedCertificate
*                )
*
* Description : Fonction de m�ta-compression visible depuis l'ext�rieur.
*					 Adapte la sortie en fonction de la faisabilit� d'une compression
*               suivie d'une d�compression.
*
* Remarks     : Le champ pData du bloc d'entr�e a �t� allou� par la fonction appelant.
*               Le champ pData du bloc de sortie est allou� ici. Il doit �tre
*               d�sallou� par la fonction appelant (sauf si RV_MALLOC_FAILED).
*
* In          : *pCert : Bloc � m�ta-compresser
*
* Out         : *pCompCert : Bloc 'meta-compress�'
*               Si probl�me lors de la compression/decompression : Renvoie le bloc
*               d'entr�e pr�c�d� d'un tag sp�cifique.
*               Sinon : Renvoie le bloc compress� pr�c�d� du num�ro de version
*               du dictionnaire.
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_COMPRESSION_FAILED : Un probl�me a eu lieu lors de l'�tape
*                                       de compression/d�compression donc le
*                                       bloc de sortie contient le bloc d'entr�e
*                                       pr�c�d� du tag TAG_COMPRESSION_FAILED.
*               RV_BLOC_TOO_LONG : Le bloc d'entr�e *commence* par un certificat
*                                  dont la compression a pu �tre invers�e.
*                                  Le bloc de sortie contient donc le compress�
*                                  de cette partie initiale seulement.
*               RV_MALLOC_FAILED : Un malloc a �chou� au niveau 'm�ta'. C'est le
*                                  seul r�el retour d'erreur.
*
*******************************************************************************/
int CC_Compress(BLOC *pCert,
                BLOC *pCompCert
               )

{
   BLOC
      TryCompCert,
      TryUncompCert;

	TryCompCert.pData = NULL_PTR;
	TryCompCert.usLen = 0;
	TryUncompCert.pData = NULL_PTR;
	TryUncompCert.usLen = 0;

#ifdef _STUDY

   /* Ouverture des fichiers de log                                           */

   if ((pfdLog = fopen("CompCert.log", "a+")) == 0)
   {
      return(RV_FILE_OPEN_FAILED);
   }
	fprintf(pfdLog, "\n*****************************************************\n");

   if ((pfdBinAc256 = fopen("Freq256.bin", "r+b")) == 0)
	{
		if ((pfdBinAc256 = fopen("Freq256.bin", "w+b")) == 0)
		{
			return(RV_FILE_OPEN_FAILED);
		}
		memset(Ac256, 0x00, 256 * sizeof(int));
   }
	else
	{
		fread(Ac256, sizeof(int), 256, pfdBinAc256);
	}

   if ((pfdBinAc16 = fopen("Freq016.bin", "r+b")) == 0)
	{
		if ((pfdBinAc16 = fopen("Freq016.bin", "w+b")) == 0)
		{
			return(RV_FILE_OPEN_FAILED);
		}
		memset(Ac16, 0x00, 16 * sizeof(int));
   }
	else
	{
		fread(Ac16, sizeof(int), 16, pfdBinAc16);
	}

   if ((pfdBinAc4 = fopen("Freq004.bin", "r+b")) == 0)
	{
		if ((pfdBinAc4 = fopen("Freq004.bin", "w+b")) == 0)
		{
			return(RV_FILE_OPEN_FAILED);
		}
		memset(Ac4, 0x00, 4 * sizeof(int));
   }
	else
	{
		fread(Ac4, sizeof(int), 4, pfdBinAc4);
	}

   if ((pfdBinAc2 = fopen("Freq002.bin", "r+b")) == 0)
	{
		if ((pfdBinAc2 = fopen("Freq002.bin", "w+b")) == 0)
		{
			return(RV_FILE_OPEN_FAILED);
		}
		memset(Ac2, 0x00, 2 * sizeof(int));
   }
	else
	{
		fread(Ac2, sizeof(int), 2, pfdBinAc2);
	}

#endif

	if (CC_Comp(pCert, &TryCompCert) != RV_SUCCESS)
	{
		/* Si la compression s'est mal pass�e alors on renvoie le fichier
		   d'entr�e en indiquant que le fichier n'est pas compress�             */

		if (TryCompCert.pData) 
      {
         GMEM_Free(TryCompCert.pData);
         TryCompCert.pData = NULL_PTR;
      }

      /* Allocation de la m�moire pour le certificat compress�                */
      if (pCompCert->usLen < pCert->usLen + 1)
      {
         pCompCert->usLen = pCert->usLen + 1;
         if (pCompCert->pData)
         {
            return(RV_BUFFER_TOO_SMALL);
         }
         else
         {
            return(RV_SUCCESS);
         }
      }

      pCompCert->usLen = pCert->usLen + 1;
		pCompCert->pData[0] = TAG_COMPRESSION_FAILED;
      if (pCompCert->pData)
      {
   		memcpy(&pCompCert->pData[1], pCert->pData, pCert->usLen);
      }
		return(RV_COMPRESSION_FAILED);
	}


	if (   (  (CC_Uncomp(&TryCompCert, &TryUncompCert) != RV_SUCCESS)
		    || (pCert->usLen != TryUncompCert.usLen)
		    || (memcmp(TryUncompCert.pData, pCert->pData, pCert->usLen) != 0)
			 )
		 && (memcmp(TryUncompCert.pData, pCert->pData, TryUncompCert.usLen) != 0)
		)
	{
		/* Si la d�compression s'est mal pass�e ou bien si elle n'est pas fid�le
		   alors on renvoie le fichier d'entr�e en indiquant que le fichier
		   n'est pas compress�                                                  */

		if (TryCompCert.pData)
      {
         GMEM_Free(TryCompCert.pData);
         TryCompCert.pData = NULL_PTR;
      }
		if (TryUncompCert.pData) 
      {
         GMEM_Free(TryUncompCert.pData);
         TryUncompCert.pData = NULL_PTR;
      }

      /* Allocation de la m�moire pour le certificat                          */
      if (pCompCert->usLen < pCert->usLen + 1)
      {
         pCompCert->usLen = pCert->usLen + 1;
         if (pCompCert->pData)
         {
            return(RV_BUFFER_TOO_SMALL);
         }
         else
         {
            return(RV_SUCCESS);
         }
      }

      pCompCert->usLen = pCert->usLen + 1;
		pCompCert->pData[0] = TAG_COMPRESSION_FAILED;
      if (pCompCert->pData)
      {
   		memcpy(&pCompCert->pData[1], pCert->pData, pCert->usLen);
      }
		return(RV_COMPRESSION_FAILED);
	}

#ifdef _STUDY

	fseek(pfdBinAc256, 0, SEEK_SET);
	fwrite(Ac256, sizeof(int), 256, pfdBinAc256);
	fseek(pfdBinAc16, 0, SEEK_SET);
	fwrite(Ac16, sizeof(int), 16, pfdBinAc16);
	fseek(pfdBinAc4, 0, SEEK_SET);
	fwrite(Ac4, sizeof(int), 4, pfdBinAc4);
	fseek(pfdBinAc2, 0, SEEK_SET);
	fwrite(Ac2, sizeof(int), 2, pfdBinAc2);

   if ((pfdLogFreq = fopen("Freq.log", "w")) == 0)
   {
      return(RV_FILE_OPEN_FAILED);
   }

	for (sum = 0, i = 0; i < 256; sum += Ac256[i], i++) ;

	fprintf(pfdLogFreq, "\nTotal = %d\n\n", sum * 8);
	for (i = 0; i < 2; i++)
	{
		fprintf(pfdLogFreq, "0x%02X (%03d) '%c' : %8d - %04.2f %%\n",
									i, i, (isgraph(i) ? i : ' '),
									Ac2[i], ((float) 100 * Ac2[i] / (sum * 8)));
	}

	fprintf(pfdLogFreq, "\nTotal = %d\n\n", sum * 4);
	for (i = 0; i < 4; i++)
	{
		fprintf(pfdLogFreq, "0x%02X (%03d) '%c' : %8d - %04.2f %%\n",
									i, i, (isgraph(i) ? i : ' '),
									Ac4[i], ((float) 100 * Ac4[i] / (sum * 4)));
	}

	fprintf(pfdLogFreq, "\nTotal = %d\n\n", sum * 2);
	for (i = 0; i < 16; i++)
	{
		fprintf(pfdLogFreq, "0x%02X (%03d) '%c' : %8d - %04.2f %%\n",
									i, i, (isgraph(i) ? i : ' '),
									Ac16[i], ((float) 100 * Ac16[i] / (sum * 2)));
	}

	fprintf(pfdLogFreq, "\nTotal = %d\n\n", sum);
	for (i = 0; i < 256; i++)
	{
		fprintf(pfdLogFreq, "0x%02X (%03d) '%c' : %8d - %04.2f %%\n",
									i, i, (isgraph(i) ? i : ' '),
									Ac256[i], ((float) 100 * Ac256[i] / sum));
	}

	fclose(pfdBinAc256);
	fclose(pfdBinAc16);
	fclose(pfdBinAc4);
	fclose(pfdBinAc2);

	fclose(pfdLogFreq);
	fclose(pfdLog);

#endif

	/* Si tout s'est bien pass�, on renvoie le r�sultat en indiquant
	   qu'il est compress� (DictVersion != 0xFF)                               */
	
	/* Allocation de la m�moire pour le certificat                             */
   if (pCompCert->usLen < TryCompCert.usLen + 1)
   {
	   if (TryCompCert.pData)
      {
         GMEM_Free(TryCompCert.pData);
         TryCompCert.pData = NULL_PTR;
      }
	   if (TryUncompCert.pData) 
      {
         GMEM_Free(TryUncompCert.pData);
         TryUncompCert.pData = NULL_PTR;
      }

      pCompCert->usLen = TryCompCert.usLen + 1;
      if (pCompCert->pData)
      {
         return(RV_BUFFER_TOO_SMALL);
      }
      else
      {
         return(RV_SUCCESS);
      }
   }

   pCompCert->usLen = TryCompCert.usLen + 1;
   if (pCompCert->pData)
   {
   	pCompCert->pData[0] = DictVersion;
   	memcpy(&pCompCert->pData[1], TryCompCert.pData, TryCompCert.usLen);
   }
	if (TryCompCert.pData)
   {
      GMEM_Free(TryCompCert.pData);
      TryCompCert.pData = NULL_PTR;
   }
	if (TryUncompCert.pData) 
   {
      GMEM_Free(TryUncompCert.pData);
      TryUncompCert.pData = NULL_PTR;
   }

	if (pCert->usLen != TryUncompCert.usLen)
	{
		return(RV_BLOC_TOO_LONG);
	}
   
   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Uncompress(BLOC *pCompCert,
*                   BLOC *pUncompCert
*                  )
*
* Description : Fonction de m�ta-d�compression visible depuis l'ext�rieur.
*					 Retourne le bloc original (entr�e de la fonction CC_Compress)
*               sous r�serve toutefois d'une version ad�quate du dictionnaire.
*
* Remarks     : Le champ pData du bloc d'entr�e a �t� allou� par la fonction appelant.
*               Le champ pData du bloc de sortie est allou� ici. Il doit �tre
*               d�sallou� par la fonction appelant (sauf si erreur).
*               Le comportement est impr�visible dans le cas o� le bloc d'entr�e
*               n'est pas le bloc de sortie d'un appel � la fonction CC_Compress.
*
* In          : *pCompCert : Bloc � m�ta-d�compresser
*
* Out         : *pUncompCert : Bloc 'm�ta-d�compress�'
*                              (ou vide si RV_BAD_DICTIONARY) 
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_BAD_DICTIONARY : La version du dictionnaire utilis�e pour la
*                                    d�compression est plus ancienne que celle
*                                    utilis�e pour la compression.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s lors de
*                       la d�compression.
*
*******************************************************************************/
int CC_Uncompress(BLOC *pCompCert,
                  BLOC *pUncompCert
                 )

{
   int
      resp;

	BLOC
		TempCompCert,
      TempUncompCert;

	if (pCompCert->pData[0] == TAG_COMPRESSION_FAILED)
	{
		/* Allocation de la m�moire pour le certificat
			On  pourrait se contenter de ne retourner que la zone m�moire
			� partir de l'octet 1 mais la fonction de d�compression est sens�e
			toujours allouer la zone dans laquelle elle renvoie le d�compress� */

		if(pUncompCert->usLen < pCompCert->usLen - 1)
      {
   		pUncompCert->usLen = pCompCert->usLen - 1;
         if (pUncompCert->pData)
         {
            return(RV_BUFFER_TOO_SMALL);
         }
         else
         {
            return(RV_SUCCESS);
         }
      }

		pUncompCert->usLen = pCompCert->usLen - 1;
      if (pUncompCert->pData)
      {
		   memcpy(pUncompCert->pData, &pCompCert->pData[1], pUncompCert->usLen);
      }
		return (RV_SUCCESS);
	}
	else if (pCompCert->pData[0] <= DictVersion)
	{
	  TempCompCert.pData = &pCompCert->pData[1];
	  TempCompCert.usLen = pCompCert->usLen - 1;

      TempUncompCert.usLen = 0;		
      resp = CC_Uncomp(&TempCompCert, &TempUncompCert);
      
	  if (resp == RV_SUCCESS)
	  {
		 if(pUncompCert->usLen < TempUncompCert.usLen)
		 {
            GMEM_Free(TempUncompCert.pData);

   		    pUncompCert->usLen = TempUncompCert.usLen;
            if (pUncompCert->pData)
			{
               return(RV_BUFFER_TOO_SMALL);
			}
            else
			{
               return(RV_SUCCESS);
			}
		 }

 		 pUncompCert->usLen = TempUncompCert.usLen;
		 if (pUncompCert->pData)
		 {
		    memcpy(pUncompCert->pData, TempUncompCert.pData, TempUncompCert.usLen);
		 }
         GMEM_Free(TempUncompCert.pData);
	  }
	  return (resp);
	}
	else
	{
		return (RV_BAD_DICTIONARY);
	}
}


/*******************************************************************************
* int CC_Comp(BLOC *pCertificate,
*             BLOC *pCompressedCertificate
*            )
*
* Description : Fonction interne de compression d'un certificat.
*
* Remarks     : Le champ pData du bloc d'entr�e a �t� allou� par la fonction appelant.
*               Le champ pData du bloc de sortie est allou� ici. Il doit �tre
*               d�sallou� par la fonction appelant (sauf si erreur).
*
* In          : *pCertificate : Bloc � compresser
*
* Out         : *pCompressedCertificate : Bloc compress�
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Comp(BLOC *pCertificate,
            BLOC *pCompressedCertificate
           )

{
   ASN1
      Cert,
      tbsCert,
      signatureAlgo,
      signature;
   BLOC
		TmpCompCert,
      tbsCertEncoded,
      signatureAlgoEncoded,
      signatureEncoded;
   BYTE
      *pCurrent;
   int
      rv;


   /* Eclatement du certificat en ses trois composants principaux             */
   dwPtrMax = pCertificate->pData + pCertificate->usLen;
   
   Cert.Asn1.pData = pCertificate->pData;
   rv = CC_ExtractContent(&Cert);
   if (rv != RV_SUCCESS) return rv;
   if (Cert.Asn1.usLen != pCertificate->usLen)
   {
      return(RV_INVALID_DATA);
   }

   tbsCert.Asn1.pData = Cert.Content.pData;
   rv = CC_ExtractContent(&tbsCert);
   if (rv != RV_SUCCESS) return rv;

   signatureAlgo.Asn1.pData = tbsCert.Content.pData + tbsCert.Content.usLen;
   rv = CC_ExtractContent(&signatureAlgo);
   if (rv != RV_SUCCESS) return rv;

   signature.Asn1.pData = signatureAlgo.Content.pData + signatureAlgo.Content.usLen;
   rv = CC_ExtractContent(&signature);
   if (rv != RV_SUCCESS) return rv;

   ASSERT(signature.Content.pData + signature.Content.usLen ==
          Cert.Content.pData + Cert.Content.usLen);


   /* Elaboration des composants principaux compress�s                        */

	/* Les pData des blocs *Encoded sont allou�s par les fonctions CC_Encode_*.
	   Ils sont lib�r�s dans cette fonction apr�s usage                        */

   tbsCertEncoded.pData       = NULL;
   signatureAlgoEncoded.pData = NULL;
   signatureEncoded.pData     = NULL;

   rv = CC_Encode_TBSCertificate(&tbsCert.Content, &tbsCertEncoded);
   if (rv != RV_SUCCESS) goto err;

   rv = CC_Encode_AlgorithmIdentifier(&signatureAlgo.Content, &signatureAlgoEncoded);
   if (rv != RV_SUCCESS) goto err;

   rv = CC_Encode_Signature(&signature.Content, &signatureEncoded);
   if (rv != RV_SUCCESS) goto err;


   /* Reconstruction du certificat compress� � partir de ses composants       */

   TmpCompCert.usLen = tbsCertEncoded.usLen
                     + signatureAlgoEncoded.usLen
                     + signatureEncoded.usLen;

   /* A d�sallouer par le programme appelant                                  */
   if ((TmpCompCert.pData = GMEM_Alloc(TmpCompCert.usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }

   pCurrent = TmpCompCert.pData;

   memcpy(pCurrent, tbsCertEncoded.pData, tbsCertEncoded.usLen);
   GMEM_Free(tbsCertEncoded.pData);
   pCurrent += tbsCertEncoded.usLen;

   memcpy(pCurrent, signatureAlgoEncoded.pData, signatureAlgoEncoded.usLen);
   GMEM_Free(signatureAlgoEncoded.pData);
   pCurrent += signatureAlgoEncoded.usLen;

   memcpy(pCurrent, signatureEncoded.pData, signatureEncoded.usLen);
   GMEM_Free(signatureEncoded.pData);
   pCurrent += signatureEncoded.usLen;


	/* Et maintenant on compresse le certificat compress� !!                   */

#ifdef _GLOBAL_COMPRESSION
   rv = CC_RawEncode(&TmpCompCert, pCompressedCertificate, FALSE);
   GMEM_Free(TmpCompCert.pData);
   if (rv != RV_SUCCESS) goto err;
#else
	*pCompressedCertificate = TmpCompCert;
#endif

   return(RV_SUCCESS);

err:
   GMEM_Free(tbsCertEncoded.pData);
   GMEM_Free(signatureAlgoEncoded.pData);
   GMEM_Free(signatureEncoded.pData);

   return (rv);


}


/*******************************************************************************
* int CC_Uncomp(BLOC *pCompressedCertificate,
*               BLOC *pUncompressedCertificate
*              )
*
* Description : Fonction interne de d�compression d'un certificat.
*
* Remarks     : Le champ pData du bloc d'entr�e a �t� allou� par la fonction appelant.
*               Le champ pData du bloc de sortie est allou� ici. Il doit �tre
*               d�sallou� par la fonction appelant (sauf si erreur).
*
* In          : *pCertificate : Bloc � compresser
*
* Out         : *pCompressedCertificate : Bloc compress�
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Uncomp(BLOC *pCompressedCertificate,
              BLOC *pUncompressedCertificate
             )

{
   ASN1
      Cert,
      tbsCert,
      signatureAlgo,
      signature;
   BLOC
      TmpCompCert;
   BYTE
      *pCurrent;
   int
      rv;
   USHORT
      Length;

   tbsCert.Asn1.pData       = NULL;
   signatureAlgo.Asn1.pData = NULL;
   signature.Asn1.pData     = NULL;


#ifdef _GLOBAL_COMPRESSION
	/* Length est ici inutile                                                  */
   rv = CC_RawDecode(pCompressedCertificate->pData, &TmpCompCert, &Length, FALSE);
   if (rv != RV_SUCCESS) return rv;
#else
	TmpCompCert = *pCompressedCertificate;
#endif

   /* D�codage des diff�rents composants du certificat                        */
   
	/* CC_Decode_* et cc_BuildAsn1 allouent les pData de leurs arguments de
		sortie. Ces zones sont � d�sallouer � ce niveau apr�s usage.            */

   pCurrent = TmpCompCert.pData;

   rv = CC_Decode_TBSCertificate(pCurrent, &tbsCert.Content, &Length);
   if (rv != RV_SUCCESS) goto err;
   tbsCert.Tag = TAG_SEQUENCE;
   rv = CC_BuildAsn1(&tbsCert);
   GMEM_Free(tbsCert.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;
   
   rv = CC_Decode_AlgorithmIdentifier(pCurrent, &signatureAlgo.Content, &Length);
   if (rv != RV_SUCCESS) goto err;
   signatureAlgo.Tag = TAG_SEQUENCE;
   rv = CC_BuildAsn1(&signatureAlgo);
   GMEM_Free(signatureAlgo.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;
   
   rv = CC_Decode_Signature(pCurrent, &signature.Content, &Length);
   if (rv != RV_SUCCESS) goto err;
   signature.Tag = TAG_BIT_STRING;
   rv = CC_BuildAsn1(&signature);
   GMEM_Free(signature.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;

	ASSERT(pCurrent == TmpCompCert.pData + TmpCompCert.usLen);

#ifdef _GLOBAL_COMPRESSION
	GMEM_Free(TmpCompCert.pData);
#endif

   /* Reconstruction de l'enveloppe Asn1 du certificat                        */

	/* A d�sallouer � ce niveau apr�s usage                                    */
   Cert.Content.usLen = tbsCert.Asn1.usLen
                      + signatureAlgo.Asn1.usLen
                      + signature.Asn1.usLen;

   if ((Cert.Content.pData = GMEM_Alloc(Cert.Content.usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }

   pCurrent = Cert.Content.pData;

   memcpy(pCurrent, tbsCert.Asn1.pData, tbsCert.Asn1.usLen);
   GMEM_Free(tbsCert.Asn1.pData);
   pCurrent += tbsCert.Asn1.usLen;

   memcpy(pCurrent, signatureAlgo.Asn1.pData, signatureAlgo.Asn1.usLen);
   GMEM_Free(signatureAlgo.Asn1.pData);
   pCurrent += signatureAlgo.Asn1.usLen;

   memcpy(pCurrent, signature.Asn1.pData, signature.Asn1.usLen);
   GMEM_Free(signature.Asn1.pData);
   pCurrent += signature.Asn1.usLen;

   Cert.Tag = TAG_SEQUENCE;
   rv = CC_BuildAsn1(&Cert);
   GMEM_Free(Cert.Content.pData);
   if (rv != RV_SUCCESS) return rv;

   *pUncompressedCertificate = Cert.Asn1;

   return(RV_SUCCESS);

err:
   GMEM_Free(tbsCert.Asn1.pData);
   GMEM_Free(signatureAlgo.Asn1.pData);
   GMEM_Free(signature.Asn1.pData);

   return(rv);
}


/*******************************************************************************
* int CC_ExtractContent(ASN1 *pAsn1)
*
* Description : Extrait d'un bloc Asn1 (pAsn1->Asn1) son contenu en �laguant son
*               enrobage (identifier bytes, length bytes) et le place dans le
*               bloc pAsn1->Content.
*
* Remarks     : Le champ Asn1.pData a �t� allou� par la fonction appelant.
*
* In          : pAsn1->Asn1.pData
*
* Out         : Les champs suivants sont renseign�s (si RV_SUCCESS) :
*                - Tag
*                - Asn1.usLen
*                - Content.usLen
*                - Content.pData (pas d'allocation : on fait pointer sur la partie
*                                 ad�quate du contenu de Asn1.pData)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_INVALID_DATA : Le format du bloc Asn1 n'est pas support�.
*
*******************************************************************************/
int CC_ExtractContent(ASN1 *pAsn1)

{
   BYTE
      *pData;
   int
      NbBytes,
      i;

   pData = pAsn1->Asn1.pData;

   if ((pData[0] & 0x1F) == 0x1F)
   {
      /* High-tag-number : non support�                                       */
      return(RV_INVALID_DATA);
   }
   else
	{
		pAsn1->Tag = pData[0];
	}

   if (pData[1] == 0x80)
   {
      /* Constructed, indefinite-length method : non support�                 */
      return(RV_INVALID_DATA);
   }
   else if (pData[1] > 0x82)
   {
      /* Constructed, definite-length method : longueur trop grande           */
      return(RV_INVALID_DATA);
   }
   else if (pData[1] < 0x80)
   {
      /* Primitive, definite-length method                                    */
      pAsn1->Content.usLen = pData[1];
      pAsn1->Content.pData = &pData[2];

      pAsn1->Asn1.usLen = pAsn1->Content.usLen + 2;

      /* Looking for memory violation                                         */
      if (pData + pAsn1->Content.usLen + 2 > dwPtrMax)
      {
         return(RV_INVALID_DATA);
      }
   }
   else
   {
      /* Constructed, definite-length method                                  */

      NbBytes = pData[1] & 0x7F;
      ASSERT(NbBytes <= 2);

      pAsn1->Content.usLen = 0;
      for (i = 0; i < NbBytes; i++)
      {
          pAsn1->Content.usLen = (pAsn1->Content.usLen << 8) + pData[2+i];
      }

      /* Looking for memory violation                                         */
      if (pData + pAsn1->Content.usLen+2+NbBytes > dwPtrMax)
      {
         return(RV_INVALID_DATA);
      }

      pAsn1->Content.pData = &pData[2+NbBytes];

      pAsn1->Asn1.usLen = pAsn1->Content.usLen + 2 + NbBytes;
   }

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_BuildAsn1(ASN1 *pAsn1)
*
* Description : Reconstruit un bloc Asn1 (pAsn1->Asn1) � partir de son contenu
*               (pAsn1->Content) et de son Tag suppos� sp�cifi� (pAsn1->Tag)
*               en synth�tisant son enrobage (identifier bytes, length bytes).
*
* Remarks     : Le champ Content.pData a �t� allou� par la fonction appelant.
*               Seulement la forme 'low-tag-number' (tag sur un seul octet) est
*               support�e.
*
* In          : pAsn1->Content.usLen
*               pAsn1->Content.pData
*               pAsn1->Tag
*
* Out         : Les champs suivants sont renseign�s (si RV_SUCCESS) :
*                - Asn1.usLen
*                - Asn1.pData (allou� ici, � lib�rer par la fonction appelant)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*
*******************************************************************************/
int CC_BuildAsn1(ASN1 *pAsn1)

{
   if (pAsn1->Content.usLen < 0x0080)
   {
      pAsn1->Asn1.usLen = pAsn1->Content.usLen + 2;

      if ((pAsn1->Asn1.pData = GMEM_Alloc(pAsn1->Asn1.usLen)) == NULL_PTR)
      {
         return(RV_MALLOC_FAILED);
      }

      pAsn1->Asn1.pData[0] = (BYTE) pAsn1->Tag;
      pAsn1->Asn1.pData[1] = (BYTE) pAsn1->Content.usLen;
      memcpy(&(pAsn1->Asn1.pData[2]), pAsn1->Content.pData, pAsn1->Content.usLen); 
   }
   else
   {
      if (pAsn1->Content.usLen < 0x0100)
      {
         pAsn1->Asn1.usLen = pAsn1->Content.usLen + 3;

         if ((pAsn1->Asn1.pData = GMEM_Alloc(pAsn1->Asn1.usLen)) == NULL_PTR)
         {
            return(RV_MALLOC_FAILED);
         }

         pAsn1->Asn1.pData[0] = pAsn1->Tag;
         pAsn1->Asn1.pData[1] = 0x81;
         pAsn1->Asn1.pData[2] = (BYTE)pAsn1->Content.usLen;
         memcpy(&(pAsn1->Asn1.pData[3]), pAsn1->Content.pData, pAsn1->Content.usLen); 
      }
      else
      {
         pAsn1->Asn1.usLen = pAsn1->Content.usLen + 4;

         if ((pAsn1->Asn1.pData = GMEM_Alloc(pAsn1->Asn1.usLen)) == NULL_PTR)
         {
            return(RV_MALLOC_FAILED);
         }

         pAsn1->Asn1.pData[0] = pAsn1->Tag;
         pAsn1->Asn1.pData[1] = 0x82;
         pAsn1->Asn1.pData[2] = pAsn1->Content.usLen >> 8;
         pAsn1->Asn1.pData[3] = pAsn1->Content.usLen & 0x00FF;
         memcpy(&(pAsn1->Asn1.pData[4]), pAsn1->Content.pData, pAsn1->Content.usLen); 
      }
   }

   return(RV_SUCCESS);
}


/*******************************************************************************
* int SearchDataByIndex(USHORT usIndex,
*                       BYTE   *pDict,
*                       BLOC   *pOutBloc
*                      )
*
* Description : Recherche l'entr�e (mot/phrase) dans le dictionnaire dont
*               l'index est sp�cifi� en entr�e.
*
* Remarks     : Le format du dictionnaire est le suivant :
*
*                - 2 octets  : le nombre d'entr�es
*                - 2 octets  : la longueur totale du dictionnaire
*
*                - 2 octets  : I0, l'index de l'entr�e 0
*                - 2 octets  : L0, la longueur de l'entr�e 0
*                - L0 octets : l'entr�e 0
*
*                - 2 octets  : I1, l'index de l'entr�e 1
*                - 2 octets  : L1, la longueur de l'entr�e 1
*                - L1 octets : l'entr�e 1
*
*                - ........
*
* In          : usIndex : l'index du mot/phrase recherch�
*               pDict : pointe sur le dictionnaire charg� en m�moire
*
* Out         : pOutBloc : l'entr�e correspondant � l'index
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_BAD_DICTIONARY : Aucune entr�e ayant le bon index n'a �t�
*                                   trouv�e dans le dictionnaire.
*
*******************************************************************************/
int SearchDataByIndex(USHORT usIndex,
                      BYTE   *pDict,
                      BLOC   *pOutBloc
                      )

{
   BYTE
      *pCurrent;
   BOOL 
      bFound = FALSE;
   USHORT
      i,
      usLength,
      usCount,
      usCurrent;

   usCount = *(USHORT *)pDict; //memcpy(&usCount, pDict, sizeof(usCount));
   pCurrent = pDict + 4;

   bFound = FALSE;

   for (i = 0; i < usCount; i++)
   {
      usCurrent = *(USHORT UNALIGNED *)pCurrent; //memcpy(&usCurrent, (USHORT *) pCurrent, 2);
      pCurrent += 2;
      if (usCurrent == usIndex)
      {
         bFound = TRUE;
         break;
      }   
      usLength = *(USHORT UNALIGNED *)pCurrent; //memcpy(&usLength, (USHORT *) pCurrent, 2);
      pCurrent += (2 + usLength);
   }
   if (!bFound)
   {
      return(RV_BAD_DICTIONARY);
   }

   usLength = *(USHORT UNALIGNED *)pCurrent; //memcpy(&usLength, (USHORT *) pCurrent, 2);
   pCurrent += 2;

   pOutBloc->pData = pCurrent;
   pOutBloc->usLen = usLength;

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_RawEncode(BLOC *pInBloc,
*                  BLOC *pOutBloc,
*						 BOOL bUseDictionary
*                 )
*
* Description : Traite le bloc d'entr�e comme une donn�e terminale dans le
*               processus d'extractions successives des enrobages Asn1.
*               Le but est ici de compresser au maximum ce bloc sans faire
*               aucune hypoth�se sur sa structure Asn1. Pour ce faire, on
*               commence (si bUseDictionary == TRUE) par remplacer chaque
*               mot/phrase du dictionnaire rencontr� par son index pr�c�d� d'un
*               caract�re d'�chappement, puis on applique � la donn�e r�siduelle
*               successivement chaque algorithme de compression statistique pour
*               n'en retenir que le meilleur. La sortie est le meilleur
*               compress� du r�sidu pr�c�d� d'un header codant le num�ro de
*               l'algo ainsi que la longueur du compress�.           
*
* Remarks     :
*
* In          : pInBloc : le bloc � encoder
*               bUseDictionary : on peut ne pas utiliser le dictionnaire
*
* Out         : pOutBloc : le bloc encod� (m�moire allou�e ici � lib�rer par le
*                          programme appelant)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               RV_INVALID_DATA : Le meilleur compress� du r�sidu est trop long.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_RawEncode(BLOC *pInBloc,
                 BLOC *pOutBloc,
					  BOOL bUseDictionary
                )

{
   BLOC
      OldBloc,
      NewBloc,
      CompBloc,
      BestBloc;
   BOOL
      bFound;
   BYTE
      *pCurrent,
      *pToCurrent,
      *pFromCurrent,
      *pData,
      BestAlgoId;
   int
//	  value,
	  rv;
   USHORT
      pos,
      usEscapeCount,
      usIndex,
      usLength,
      usCount,
      usCurrent;


	/* Il peut �tre int�ressant de ne pas utiliser le dictionnaire si on sait 
	   qu'il ne va pas servir car cela evite de doubler les 0xFF pour rien */

	if (bUseDictionary == FALSE)
	{
		OldBloc.usLen = pInBloc->usLen;
		if ((OldBloc.pData = GMEM_Alloc(OldBloc.usLen)) == NULL_PTR)
		{
			return(RV_MALLOC_FAILED);
		}
		memcpy(OldBloc.pData, pInBloc->pData, OldBloc.usLen);
	}
	else
	{
		/* On recopie le bloc d'entr�e dans un bloc de travail en doublant les 'escape' */

		pCurrent = pInBloc->pData;
		usEscapeCount = 0;
		for (pos = 0; pos < pInBloc->usLen; pos++)
		{
			if (*pCurrent == ESCAPE_CHAR)
			{
				usEscapeCount++;
			}
			pCurrent++;
		}

		OldBloc.usLen = pInBloc->usLen + usEscapeCount;
		if ((OldBloc.pData = GMEM_Alloc(OldBloc.usLen)) == NULL_PTR)
		{
			return(RV_MALLOC_FAILED);
		}

		pFromCurrent = pInBloc->pData;
		pToCurrent = OldBloc.pData;
		for (pos = 0; pos < pInBloc->usLen; pos++)
		{
			if ((*pToCurrent = *pFromCurrent) == ESCAPE_CHAR)
			{
				pToCurrent++; 
				*pToCurrent = ESCAPE_CHAR; 
			}
			pFromCurrent++;
			pToCurrent++;
		}


		/* Si un dictionnaire existe, on l'utilise pour coder ses entr�es rencontr�es */

		if (pDictMemory != NULL_PTR)
		{
			pCurrent = pDictMemory;

			memcpy(&usCount, pCurrent, sizeof(usCount));
			pCurrent += 4;

			for (usCurrent = 0; usCurrent < usCount; usCurrent++)
			{
				memcpy(&usIndex, pCurrent, sizeof(usIndex));
				pCurrent += 2;

				memcpy(&usLength, pCurrent, sizeof(usLength));
				pCurrent += 2;

				if (usLength <= OldBloc.usLen)
				{
					bFound = FALSE;
					for (pos = 0; pos < OldBloc.usLen - usLength + 1; pos++)
					{
						if (memcmp(pCurrent, OldBloc.pData + pos, usLength) == 0)
						{
							bFound = TRUE;
							break;
						}
					}

					if (bFound)
					{
						if (usIndex < 0x80)
						{
							NewBloc.usLen = OldBloc.usLen - usLength + 2;
							if ((NewBloc.pData = GMEM_Alloc(NewBloc.usLen)) == NULL_PTR)
							{
								GMEM_Free(OldBloc.pData);
								return(RV_MALLOC_FAILED);
							}
							memcpy(NewBloc.pData, OldBloc.pData, pos);
							NewBloc.pData[pos] = ESCAPE_CHAR;
							NewBloc.pData[pos + 1] = (BYTE) usIndex;
							memcpy(NewBloc.pData + pos + 2,
										 OldBloc.pData + pos + usLength,
										 OldBloc.usLen - pos - usLength);
							GMEM_Free(OldBloc.pData);
						}
						else
						{
							NewBloc.usLen = OldBloc.usLen - usLength + 3;
							if ((NewBloc.pData = GMEM_Alloc(NewBloc.usLen)) == NULL_PTR)
							{
								GMEM_Free(OldBloc.pData);
								return(RV_MALLOC_FAILED);
							}
							memcpy(NewBloc.pData, OldBloc.pData, pos);
							NewBloc.pData[pos] = ESCAPE_CHAR;
							NewBloc.pData[pos + 1] = (BYTE) (usIndex >> 8) | 0x80;
							NewBloc.pData[pos + 2] = (BYTE) (usIndex & 0x00FF);
							memcpy(NewBloc.pData + pos + 3,
										 OldBloc.pData + pos + usLength,
										 OldBloc.usLen - pos - usLength);
							GMEM_Free(OldBloc.pData);
						}

						OldBloc = NewBloc;
					}
				}

				pCurrent += usLength;
			}
		}
	}

#ifdef _STUDY
	for (i = 0; i < OldBloc.usLen; i++)
	{
		value = OldBloc.pData[i];
		Ac256[value]++;

		Ac16[value & 0x0F]++;
		Ac16[(value & 0xF0) >> 4]++;

		Ac4[value & 0x03]++;
		Ac4[(value & 0x0C) >> 2]++;
		Ac4[(value & 0x30) >> 4]++;
		Ac4[(value & 0xC0) >> 6]++;

		Ac2[value & 0x01]++; value >>= 1;
		Ac2[value & 0x01]++; value >>= 1;
		Ac2[value & 0x01]++; value >>= 1;
		Ac2[value & 0x01]++; value >>= 1;
		Ac2[value & 0x01]++; value >>= 1;
		Ac2[value & 0x01]++; value >>= 1;
		Ac2[value & 0x01]++; value >>= 1;
		Ac2[value & 0x01]++; value >>= 1;
	}

	fprintf(pfdLog, "\n");
	for  (i = 0; i < (OldBloc.usLen <= 8 ? OldBloc.usLen : 8); i++)
	{
		fprintf(pfdLog, "%02X", OldBloc.pData[i]);
	}
	fprintf(pfdLog, " (");
	for  (i = 0; i < (OldBloc.usLen <= 8 ? OldBloc.usLen : 8); i++)
	{
		fprintf(pfdLog, "%c", OldBloc.pData[i]);
	}
	fprintf(pfdLog, ")\n");

#endif

	BestBloc = OldBloc;
	BestAlgoId = ALGO_NONE;

#ifdef _ALGO_1
	rv = CC_GenericCompress(&OldBloc, &CompBloc, ALGO_ACFX8);
	if (rv == RV_MALLOC_FAILED) return rv;
	// The compression algorithm may return RV_COMPRESSION_FAILED when
	// the compression algorithm wants to use MORE space than the input data.
	// In such a case, the algorithm returns the raw data in the compressed block
	if (CompBloc.usLen < BestBloc.usLen)
	{
		/* On pr�serve OldBloc.pData qui sert pour les autres algos */
		if (BestBloc.pData != OldBloc.pData)
		{
			GMEM_Free(BestBloc.pData);
		}
		BestBloc = CompBloc;
		BestAlgoId = ALGO_ACFX8;
	}
	else
	{
		GMEM_Free(CompBloc.pData);
	}
#endif

#ifdef _ALGO_2
	rv = CC_GenericCompress(&OldBloc, &CompBloc, ALGO_ACAD8);
	if (rv == RV_MALLOC_FAILED) return rv;
	// The compression algorithm may return RV_COMPRESSION_FAILED when
	// the compression algorithm wants to use MORE space than the input data.
	// In such a case, the algorithm returns the raw data in the compressed block
	if (CompBloc.usLen < BestBloc.usLen)
	{
		/* On pr�serve OldBloc.pData qui sert pour les autres algos */
		if (BestBloc.pData != OldBloc.pData)
		{
			GMEM_Free(BestBloc.pData);
		}
		BestBloc = CompBloc;
		BestAlgoId = ALGO_ACAD8;
	}
	else
	{
		GMEM_Free(CompBloc.pData);
	}
#endif


   if (BestBloc.usLen < 0x1F) /* La valeur 0x1F peut engendrer 0xFF = ESCAPE_CHAR */
   {
      if ((pData = GMEM_Alloc(BestBloc.usLen + 1)) == NULL_PTR)
      {
          GMEM_Free(BestBloc.pData);
		  return(RV_MALLOC_FAILED);
      }
      else
      {
         pData[0] = (BestAlgoId << 5) | BestBloc.usLen;
         memcpy(&pData[1], BestBloc.pData, BestBloc.usLen);

         pOutBloc->usLen = BestBloc.usLen + 1;
         pOutBloc->pData = pData;

		 GMEM_Free(BestBloc.pData);
      }      
   }
   else if (BestBloc.usLen < 0x2000)
   {
      if ((pData = GMEM_Alloc(BestBloc.usLen + 3)) == NULL_PTR)
      {
         GMEM_Free(BestBloc.pData);
		 return(RV_MALLOC_FAILED);
      }
      else
      {
         pData[0] = ESCAPE_CHAR;
         pData[1] = (BestAlgoId << 5) | (BestBloc.usLen >> 8);
         pData[2] = BestBloc.usLen & 0xFF;
         memcpy(&pData[3], BestBloc.pData, BestBloc.usLen);

         pOutBloc->usLen = BestBloc.usLen + 3;
         pOutBloc->pData = pData;

		 GMEM_Free(BestBloc.pData);
      }      
   }
   else
   {
      GMEM_Free(BestBloc.pData);
	  return(RV_INVALID_DATA);
   }

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_RawDecode(BYTE    *pInBloc,
*                  BLOC    *pOutBloc,
*                  USHORT  *pLength,
*				   BOOL		bUseDictionnary
*                 )
*
* Description : Transformation inverse de 'CC_RawEncode'.           
*
* Remarks     :
*
* In          : pInBloc : le bloc � d�coder
*               bUseDictionary : on peut ne pas utiliser le dictionnaire (doit
*                                �tre consistent avec l'encodage)
*
* Out         : pOutBloc : le bloc d�cod� (m�moire allou�e ici � lib�rer par le
*                          programme appelant)
*               pLength : la longueur de donn�es encod�s utilis�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_RawDecode(BYTE   *pInData,
                 BLOC   *pOutBloc,
                 USHORT *pLength,
					  BOOL	bUseDictionary
                )

{
   BLOC
      OldBloc,
      NewBloc,
      RecordBloc,
      CompData;
   BYTE
      AlgoId;
   int
      rv;
   USHORT
      pos,
      usIndex;


   if (pInData[0] == ESCAPE_CHAR)
   {
      AlgoId = pInData[1] >> 5;
      CompData.usLen = ((pInData[1] & 0x1F) << 8) + pInData[2];
      CompData.pData = &(pInData[3]);
      *pLength = CompData.usLen + 3;
   }
   else
   {
      AlgoId = pInData[0] >> 5;
      CompData.usLen = pInData[0] & 0x1F;
      CompData.pData = &(pInData[1]);
      *pLength = CompData.usLen + 1;
   }

   rv = CC_GenericUncompress(&CompData, &OldBloc, AlgoId);
   if (rv != RV_SUCCESS) return rv;

	if (bUseDictionary)
	{
		pos = 0;
		while (pos < OldBloc.usLen)
		{
			if (OldBloc.pData[pos] == ESCAPE_CHAR)
			{
				if (OldBloc.pData[pos + 1] == ESCAPE_CHAR)
				{
					NewBloc.usLen = OldBloc.usLen - 1;
					if ((NewBloc.pData = GMEM_Alloc(NewBloc.usLen)) == NULL_PTR)
					{
						GMEM_Free(OldBloc.pData);
						return(RV_MALLOC_FAILED);
					}

					memcpy(NewBloc.pData, OldBloc.pData, pos);
					NewBloc.pData[pos] = ESCAPE_CHAR;
					memcpy(NewBloc.pData + pos + 1,
							 OldBloc.pData + pos + 2,
							 OldBloc.usLen - pos - 2);

					GMEM_Free(OldBloc.pData);
					OldBloc = NewBloc;

					pos++;
				}
				else if (OldBloc.pData[pos + 1] < 0x80)
				{
					usIndex = OldBloc.pData[pos + 1];

					rv = SearchDataByIndex(usIndex, pDictMemory, &RecordBloc);
					if (rv != RV_SUCCESS)
					{
						GMEM_Free(OldBloc.pData);
						return rv;
					}

					NewBloc.usLen = OldBloc.usLen - 2 + RecordBloc.usLen;
					if ((NewBloc.pData = GMEM_Alloc(NewBloc.usLen)) == NULL_PTR)
					{
						GMEM_Free(OldBloc.pData);
						return(RV_MALLOC_FAILED);
					}

					memcpy(NewBloc.pData, OldBloc.pData, pos);
					memcpy(NewBloc.pData + pos, RecordBloc.pData, RecordBloc.usLen);
					memcpy(NewBloc.pData + pos + RecordBloc.usLen,
							 OldBloc.pData + pos + 2,
							 OldBloc.usLen - pos - 2);

					GMEM_Free(OldBloc.pData);
					OldBloc = NewBloc;

					pos += RecordBloc.usLen;
				}
				else
				{
					usIndex = ((OldBloc.pData[pos + 1] & 0x7F) << 8) + OldBloc.pData[pos + 2];

					rv = SearchDataByIndex(usIndex, pDictMemory, &RecordBloc);
					if (rv != RV_SUCCESS)
					{
						GMEM_Free(OldBloc.pData);
						return rv;
					}

					NewBloc.usLen = OldBloc.usLen - 3 + RecordBloc.usLen;
					if ((NewBloc.pData = GMEM_Alloc(NewBloc.usLen)) == NULL_PTR)
					{
						GMEM_Free(OldBloc.pData);
						return(RV_MALLOC_FAILED);
					}

					memcpy(NewBloc.pData, OldBloc.pData, pos);
					memcpy(NewBloc.pData + pos, RecordBloc.pData, RecordBloc.usLen);
					memcpy(NewBloc.pData + pos + RecordBloc.usLen,
							 OldBloc.pData + pos + 3,
							 OldBloc.usLen - pos - 3);

					GMEM_Free(OldBloc.pData);
					OldBloc = NewBloc;

					pos += RecordBloc.usLen;
				}
			}
			else
			{
				pos++;
			}
		}
	}

   *pOutBloc = OldBloc;

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_GenericCompress(BLOC *pUncompBloc,
*                        BLOC *pCompBloc,
*                        BYTE AlgoId
*                       )
*
* Description : Effectue une compression statistique sur la donn�e d'entr�e en
*               utilisant l'algorithme sp�cifi� dans AlgoId.
*
* Remarks     : Si l'algorithme sp�cifi� n'est pas impl�ment�, renvoie la donn�e
*               originale.
*
* In          : pUncompBloc : la donn�e � compresser
*               AlgoId : num�ro de l'algorithme � employer
*
* Out         : pCompBloc : la donn�e compress�e (m�moire allou�e ici � lib�rer
*                           par la fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*
*******************************************************************************/
int CC_GenericCompress(BLOC *pUncompBloc,
                       BLOC *pCompBloc,
                       BYTE AlgoId
                      )

{
	switch(AlgoId)
	{
#ifdef _ALGO_1
		case ALGO_ACFX8 :	/* Arithmetic coding, byte oriented, fixed model */
		{
			if (AcFx8_Encode(pUncompBloc, pCompBloc) != RV_SUCCESS)
			{
				return(RV_INVALID_DATA);
			}
			break;
		}
#endif

#ifdef _ALGO_2
		case ALGO_ACAD8 :	/* Arithmetic coding, byte oriented, adaptative model */
		{
			if (AcAd8_Encode(pUncompBloc, pCompBloc) != RV_SUCCESS)
			{
				return(RV_INVALID_DATA);
			}
			break;
		}
#endif

		default :
		{
         if ((pCompBloc->pData = GMEM_Alloc(pUncompBloc->usLen)) == NULL_PTR)
         {
            return(RV_MALLOC_FAILED);
         }
			pCompBloc->usLen = pUncompBloc->usLen;
			memcpy(pCompBloc->pData, pUncompBloc->pData, pCompBloc->usLen);
			break;
		}
	}

#ifdef _STUDY
	fprintf(pfdLog, "Algo : %d | 0x%04x (%04d) -> 0x%04x (%04d)", AlgoId,
						 pUncompBloc->usLen, pUncompBloc->usLen,
						 pCompBloc->usLen, pCompBloc->usLen
			 );
	if (pUncompBloc->usLen > pCompBloc->usLen)
	{
		fprintf(pfdLog, " | %d", pCompBloc->usLen - pUncompBloc->usLen);
	}
	fprintf(pfdLog, "\n");
#endif

	return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_GenericUncompress(BLOC *pCompBloc,
*                          BLOC *pUncompBloc,
*                          BYTE AlgoID
*                         )
*
* Description : Effectue une d�compression statistique sur la donn�e d'entr�e en
*               utilisant l'algorithme sp�cifi� dans AlgoId.
*
* Remarks     : 
*
* In          : pUncompBloc : la donn�e � d�compresser
*               AlgoId : num�ro de l'algorithme � employer
*
* Out         : pCompBloc : la donn�e d�compress�e (m�moire allou�e ici �
*                           lib�rer par la fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               RV_INVALID_DATA : L'algorithme sp�cifi� n'existe pas.
*
*******************************************************************************/
int CC_GenericUncompress(BLOC *pCompBloc,
                         BLOC *pUncompBloc,
                         BYTE AlgoId
                        )

{
   switch(AlgoId)
   {
		case ALGO_NONE :
			pUncompBloc->usLen = pCompBloc->usLen;
			if ((pUncompBloc->pData = GMEM_Alloc(pUncompBloc->usLen)) == NULL_PTR)
			{
				return(RV_MALLOC_FAILED);
			}
			memcpy(pUncompBloc->pData, pCompBloc->pData, pUncompBloc->usLen);
			break;

#ifdef _ALGO_1
		case ALGO_ACFX8 :
			if (AcFx8_Decode(pCompBloc, pUncompBloc) != RV_SUCCESS)
			{
				return(RV_INVALID_DATA);
			}
			break;
#endif

#ifdef _ALGO_2
		case ALGO_ACAD8 :
			if (AcAd8_Decode(pCompBloc, pUncompBloc) != RV_SUCCESS)
			{
				return(RV_INVALID_DATA);
			}
			break;
#endif

		default :
			return(RV_INVALID_DATA);
			break;
   }

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Encode_TBSCertificate(BLOC *pInBloc,
*                              BLOC *pOutBloc
*                             )
*
* Description : Encode une donn�e de type TBSCertificate.
*               Ceci consiste en l'�clatement en ses diff�rents composants,
*               leurs d�senrobages Asn1 et leurs encodages respectifs, et la
*               concat�nation de ces r�sultats.
*
* Remarks     : Certaines parties d'un TBSCertificate sont optionnelles. On
*               d�tecte pour chacune d'elles si elle est pr�sente et on
*               l'indique dans des bits r�serv�s d'un octet de contr�le plac�
*               en d�but du r�sultat encod�. Cet octet de contr�le contient
*               �galement le num�ro de version X.509 du certificat.
*
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_TBSCertificate(BLOC *pInBloc,
                             BLOC *pOutBloc
                            )

{
   ASN1
      serialNumberPart,
      signaturePart,
      issuerPart,
      validityPart,
      subjectPart,
      subjectPKInfoPart,
      issuerUIDPart,
      subjectUIDPart,
      extensionsPart;
   BLOC
      serialNumberEncoded,
      signatureEncoded,
      issuerEncoded,
      validityEncoded,
      subjectEncoded,
      subjectPKInfoEncoded,
      issuerUIDEncoded,
      subjectUIDEncoded,
      extensionsEncoded;
   BOOL
      bVersionPresent = FALSE,
      bIssuerUIDPresent = FALSE,
      bSubjectUIDPresent = FALSE,
      bExtensionsPresent = FALSE;
   BYTE
      *pCurrent;
   int
      rv;
   USHORT
      usVersion = 0;


   /* D�composition du tbsCertificate en ses diff�rents composants            */
   
   pCurrent = pInBloc->pData;

   if (pCurrent[0] == TAG_OPTION_VERSION)
   {
      /* On a alors A0 03 02 01 vv  o� vv est la version                      */
      bVersionPresent = TRUE;
      usVersion = pCurrent[4];
      pCurrent += 5;
   }

   serialNumberPart.Asn1.pData = pCurrent;
   rv = CC_ExtractContent(&serialNumberPart);
   if (rv != RV_SUCCESS) return rv;
   pCurrent = serialNumberPart.Content.pData + serialNumberPart.Content.usLen;

   signaturePart.Asn1.pData = pCurrent;
   rv = CC_ExtractContent(&signaturePart);
   if (rv != RV_SUCCESS) return rv;
   pCurrent = signaturePart.Content.pData + signaturePart.Content.usLen;

   issuerPart.Asn1.pData = pCurrent;
   rv = CC_ExtractContent(&issuerPart);
   if (rv != RV_SUCCESS) return rv;
   pCurrent = issuerPart.Content.pData + issuerPart.Content.usLen;

   validityPart.Asn1.pData = pCurrent;
   rv = CC_ExtractContent(&validityPart);
   if (rv != RV_SUCCESS) return rv;
   pCurrent = validityPart.Content.pData + validityPart.Content.usLen;

   subjectPart.Asn1.pData = pCurrent;
   rv = CC_ExtractContent(&subjectPart);
#ifdef _STUDY
//	fprintf(pfdLog, "Subject : %d octets\n", subjectPart.Asn1.usLen);
#endif
   if (rv != RV_SUCCESS) return rv;
   pCurrent = subjectPart.Content.pData + subjectPart.Content.usLen;

   subjectPKInfoPart.Asn1.pData = pCurrent;
   rv = CC_ExtractContent(&subjectPKInfoPart);
   if (rv != RV_SUCCESS) return rv;
   pCurrent = subjectPKInfoPart.Content.pData + subjectPKInfoPart.Content.usLen;

   if (pCurrent[0] == TAG_OPTION_ISSUER_UID)
   {
      bIssuerUIDPresent = TRUE;

      issuerUIDPart.Asn1.pData = pCurrent;
      rv = CC_ExtractContent(&issuerUIDPart);
      if (rv != RV_SUCCESS) return rv;
      pCurrent = issuerUIDPart.Content.pData + issuerUIDPart.Content.usLen;
   }

   if (pCurrent[0] == TAG_OPTION_SUBJECT_UID)
   {
      bSubjectUIDPresent = TRUE;

      subjectUIDPart.Asn1.pData = pCurrent;
      rv = CC_ExtractContent(&subjectUIDPart);
      if (rv != RV_SUCCESS) return rv;
      pCurrent = subjectUIDPart.Content.pData + subjectUIDPart.Content.usLen;
   }

   if (pCurrent[0] == TAG_OPTION_EXTENSIONS)
   {
      bExtensionsPresent = TRUE;

      extensionsPart.Asn1.pData = pCurrent;
      rv = CC_ExtractContent(&extensionsPart);
      if (rv != RV_SUCCESS) return rv;
      pCurrent = extensionsPart.Content.pData + extensionsPart.Content.usLen;
   }


   /* Encodages des diff�rents composants et calcul de la longueur n�cessaire */

	/* Les pData des blocs *Encoded sont allou�s par les fonctions CC_Encode_*.
	   Ils sont lib�r�s dans cette fonction apr�s usage                        */

   serialNumberEncoded.pData = NULL;
   signatureEncoded.pData    = NULL;
   issuerEncoded.pData       = NULL;
   validityEncoded.pData     = NULL;
   subjectEncoded.pData      = NULL;
   subjectPKInfoEncoded.pData= NULL;
   issuerUIDEncoded.pData    = NULL;
   subjectUIDEncoded.pData   = NULL;
   extensionsEncoded.pData   = NULL;

   pOutBloc->usLen = 1;

   rv = CC_Encode_CertificateSerialNumber(&serialNumberPart.Content, &serialNumberEncoded);
   if (rv != RV_SUCCESS) goto err;
   pOutBloc->usLen += serialNumberEncoded.usLen;

   rv = CC_Encode_AlgorithmIdentifier(&signaturePart.Content, &signatureEncoded);
   if (rv != RV_SUCCESS) goto err;
   pOutBloc->usLen += signatureEncoded.usLen;

   rv = CC_Encode_Name(&issuerPart.Content, &issuerEncoded);
   if (rv != RV_SUCCESS) goto err;
   pOutBloc->usLen += issuerEncoded.usLen;

   rv = CC_Encode_Validity(&validityPart.Content, &validityEncoded);
   if (rv != RV_SUCCESS) goto err;
   pOutBloc->usLen += validityEncoded.usLen;

   rv = CC_Encode_Name(&subjectPart.Content, &subjectEncoded);
   if (rv != RV_SUCCESS) goto err;
   pOutBloc->usLen += subjectEncoded.usLen;

   rv = CC_Encode_SubjectPKInfo(&subjectPKInfoPart.Content, &subjectPKInfoEncoded);
   if (rv != RV_SUCCESS) goto err;
   pOutBloc->usLen += subjectPKInfoEncoded.usLen;

   if (bIssuerUIDPresent == TRUE)
   {
      rv = CC_Encode_UniqueIdentifier(&issuerUIDPart.Content, &issuerUIDEncoded);
      if (rv != RV_SUCCESS) goto err;
      pOutBloc->usLen += issuerUIDEncoded.usLen;
   }

   if (bSubjectUIDPresent == TRUE)
   {
      rv = CC_Encode_UniqueIdentifier(&subjectUIDPart.Content, &subjectUIDEncoded);
      if (rv != RV_SUCCESS) goto err;
      pOutBloc->usLen += subjectUIDEncoded.usLen;
   }

   if (bExtensionsPresent == TRUE)
   {
      rv = CC_Encode_Extensions(&extensionsPart.Content, &extensionsEncoded);
      if (rv != RV_SUCCESS) goto err;
      pOutBloc->usLen += extensionsEncoded.usLen;
   }


   /* Reconstruction � partir des composants                                  */

   /* A d�sallouer par le programme appelant                                  */
   if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }

   pCurrent = pOutBloc->pData;

   *pCurrent = 0x80 * (bVersionPresent == TRUE)
             + 0x40 * (bIssuerUIDPresent == TRUE)
             + 0x20 * (bSubjectUIDPresent == TRUE)
             + 0x10 * (bExtensionsPresent == TRUE)
             + usVersion;
   pCurrent++;

   memcpy(pCurrent, serialNumberEncoded.pData, serialNumberEncoded.usLen);
   GMEM_Free(serialNumberEncoded.pData); 
   pCurrent += serialNumberEncoded.usLen;

   memcpy(pCurrent, signatureEncoded.pData, signatureEncoded.usLen);
   GMEM_Free(signatureEncoded.pData); 
   pCurrent += signatureEncoded.usLen;

   memcpy(pCurrent, issuerEncoded.pData, issuerEncoded.usLen);
   GMEM_Free(issuerEncoded.pData); 
   pCurrent += issuerEncoded.usLen;

   memcpy(pCurrent, validityEncoded.pData, validityEncoded.usLen);
   GMEM_Free(validityEncoded.pData); 
   pCurrent += validityEncoded.usLen;

   memcpy(pCurrent, subjectEncoded.pData, subjectEncoded.usLen);
   GMEM_Free(subjectEncoded.pData); 
   pCurrent += subjectEncoded.usLen;

   memcpy(pCurrent, subjectPKInfoEncoded.pData, subjectPKInfoEncoded.usLen);
   GMEM_Free(subjectPKInfoEncoded.pData); 
   pCurrent += subjectPKInfoEncoded.usLen;

   if (bIssuerUIDPresent == TRUE)
   {
      memcpy(pCurrent, issuerUIDEncoded.pData, issuerUIDEncoded.usLen);
      GMEM_Free(issuerUIDEncoded.pData); 
      pCurrent += issuerUIDEncoded.usLen;
   }

   if (bSubjectUIDPresent == TRUE)
   {
      memcpy(pCurrent, subjectUIDEncoded.pData, subjectUIDEncoded.usLen);
      GMEM_Free(subjectUIDEncoded.pData); 
      pCurrent += subjectUIDEncoded.usLen;
   }

   if (bExtensionsPresent == TRUE)
   {
      memcpy(pCurrent, extensionsEncoded.pData, extensionsEncoded.usLen);
      GMEM_Free(extensionsEncoded.pData); 
      pCurrent += extensionsEncoded.usLen;
   }

   return(RV_SUCCESS);

err:
   GMEM_Free(serialNumberEncoded.pData);
   GMEM_Free(signatureEncoded.pData); 
   GMEM_Free(issuerEncoded.pData);  
   GMEM_Free(validityEncoded.pData); 
   GMEM_Free(subjectEncoded.pData); 
   GMEM_Free(subjectPKInfoEncoded.pData); 
   GMEM_Free(issuerUIDEncoded.pData);
   GMEM_Free(subjectUIDEncoded.pData);
   GMEM_Free(extensionsEncoded.pData);  
   return rv;
}


/*******************************************************************************
* int CC_Encode_CertificateSerialNumber(BLOC *pInBloc,
*                                       BLOC *pOutBloc
*                                      )
*
* Description : Encode une donn�e de type CertificateSerialNumber.
*               Ceci consiste seulement en l'encodage brute (CC_RawEncode) de la
*               donn�e d'entr�e.
*
* Remarks     : 
*
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_CertificateSerialNumber(BLOC *pInBloc,
                                      BLOC *pOutBloc
                                     )

{
   int
      rv;


   rv = CC_RawEncode(pInBloc, pOutBloc, TRUE);
   if (rv != RV_SUCCESS) return rv;

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Encode_AlgorithmIdentifier(BLOC *pInBloc,
*                                   BLOC *pOutBloc
*                                  )
*
* Description : Encode une donn�e de type AlgorithmIdentifier.
*               Ceci consiste en l'�clatement en ses diff�rents composants,
*               leurs d�senrobages Asn1 et leurs encodages respectifs, et la
*               concat�nation de ces r�sultats.
*
* Remarks     : bNullParam sert � coder sur un bit l'information qu'il n'y a pas
*               de param�tre � l'algorithme. Cette information occupe toujours
*               deux octets dans le certificat est vaut toujours {0x05, 0x00}.
*               On utilise un dictionnaire statique (d�fini au d�but de ce
*               source) pour remplacer le type d'algorithme par un index.
*               Un octet de contr�le (en d�but du r�sultat) indique, ou bien que
*               l'on n'a pas trouv� le type d'algo dans le dico (valeur 0xFF ->
*               Encodage brut de la donn�e d'entr�e int�grale), ou bien un flag
*               pr�cisant s'il y a des param�tres et l'index du type d'algo.
*
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_AlgorithmIdentifier(BLOC  *pInBloc,
                                  BLOC  *pOutBloc
                                 )

{
    ASN1
        AlgorithmPart,
        ParametersPart;
    BLOC
        AlgorithmIdentifierEncoded,
        ParametersAsn1Encoded;
    BOOL
        bFound,
        bNoParam   = FALSE,
        bNullParam = FALSE;
    int
        rv;
    USHORT
        Index,
        AlgoIndex;


    AlgorithmPart.Asn1.pData = pInBloc->pData;
    rv = CC_ExtractContent(&AlgorithmPart);
    if (rv != RV_SUCCESS) return rv;

    if (AlgorithmPart.Asn1.usLen == pInBloc->usLen)
    {
        bNoParam   = TRUE;
        bNullParam = FALSE;
    }
    else
    {
        ParametersPart.Asn1.pData = AlgorithmPart.Content.pData + AlgorithmPart.Content.usLen;
        rv = CC_ExtractContent(&ParametersPart);
        if (rv != RV_SUCCESS) return rv;

        if (ParametersPart.Content.usLen == 0)
        {
            bNoParam  = TRUE;
            bNullParam = TRUE;
        }
    }

    /* Recherche de l'identifiant de l'algorithme dans le dictionnaire         */

    Index = 0;
    bFound = FALSE;
    while ((bFound == FALSE) && (AlgorithmTypeDict[Index] != NULL))
    {
        if (!memcmp(AlgorithmTypeDict[Index],
                    AlgorithmPart.Content.pData,
                    AlgorithmPart.Content.usLen))
        {
            bFound = TRUE;
            AlgoIndex = Index;
        }
        Index++;
    }

    /* Construction de l'encodage                                              */

    if (bFound == TRUE)
    {
        if (bNoParam == TRUE)
        {
            if (bNullParam == TRUE)
            {
                /* Si on a trouv� l'algorithme et il n'y a pas de param�tre          */

                pOutBloc->usLen = 1;
                if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
                {
                    return (RV_MALLOC_FAILED);
                }

                pOutBloc->pData[0] = (AlgoIndex | 0x80);
            }
            else
            {
                pOutBloc->usLen = 2;
                if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
                {
                    return (RV_MALLOC_FAILED);
                }

                pOutBloc->pData[0] = ABSENT_PARAMETER_CHAR;
                pOutBloc->pData[1] = (BYTE) AlgoIndex;
            }
        }
        else
        {

            /* Si on a trouv� l'algorithme et il y a des param�tres              */
            /* On RawEncode non pas le contenu des param�tres mais l'Asn1 entier
                              car on n'est pas s�r de l'encapsulage                             */

            rv = CC_RawEncode(&(ParametersPart.Asn1), &ParametersAsn1Encoded, TRUE);
            if (rv != RV_SUCCESS) return rv;

            pOutBloc->usLen = 1 + ParametersAsn1Encoded.usLen;
            if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
            {
                GMEM_Free(ParametersAsn1Encoded.pData);
                return (RV_MALLOC_FAILED);
            }

            pOutBloc->pData[0] = (BYTE) AlgoIndex;
            memcpy(&(pOutBloc->pData[1]),
                   ParametersAsn1Encoded.pData,
                   ParametersAsn1Encoded.usLen);

            GMEM_Free(ParametersAsn1Encoded.pData);
        }
    }
    else
    {
        /* Si on n'a pas trouv� l'algorithme dans le dictionnaire               */
        /* On RawEncode le contenu de AlgorithmIdentifier c'est � dire la
                     concat�nation du asn1 de AlgorithmPart et du asn1 de ParametersPart  */

        rv = CC_RawEncode(pInBloc, &AlgorithmIdentifierEncoded, TRUE);
        if (rv != RV_SUCCESS) return rv;

        pOutBloc->usLen = 1 + AlgorithmIdentifierEncoded.usLen;
        if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
        {
            GMEM_Free(AlgorithmIdentifierEncoded.pData);
            return (RV_MALLOC_FAILED);
        }

        pOutBloc->pData[0] = ESCAPE_CHAR;
        memcpy(&(pOutBloc->pData[1]),
               AlgorithmIdentifierEncoded.pData,
               AlgorithmIdentifierEncoded.usLen);

        GMEM_Free(AlgorithmIdentifierEncoded.pData);
    }

    return (RV_SUCCESS);
}


/*******************************************************************************
* int CC_Encode_Name(BLOC *pInBloc,
*                    BLOC *pOutBloc
*                   )
*
* Description : Encode une donn�e de type Name.
*               Ceci consiste en l'�clatement en ses diff�rents composants,
*               leurs d�senrobages Asn1 et leurs encodages respectifs, et la
*               concat�nation de ces r�sultats.
*
* Remarks     : Un octet de contr�le (en d�but du r�sultat) indique le nombre
*               de RelativeDistinguishedName dont est compos� le Name.
*
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_Name(BLOC *pInBloc,
                   BLOC *pOutBloc
                  )

{
   ASN1
      RDN[MAX_RDN];
   BLOC
      RDNEncoded[MAX_RDN];
   BYTE
      *pCurrent;
   USHORT
      i,
      usNbRDN;
   int
      rv;


   /* D�composition du Name en ses diff�rents RelativeDistinguishedName       */

   pCurrent = pInBloc->pData;
   usNbRDN = 0;

   while (pCurrent < pInBloc->pData + pInBloc->usLen)
   {
      RDN[usNbRDN].Asn1.pData = pCurrent;
      rv = CC_ExtractContent(&(RDN[usNbRDN]));
      if (rv != RV_SUCCESS) return rv;
      pCurrent = RDN[usNbRDN].Content.pData + RDN[usNbRDN].Content.usLen;
      usNbRDN++;
   }

   ASSERT(pCurrent == pInBloc->pData + pInBloc->usLen);


   /* Encodages des diff�rents composants et calcul de la longueur n�cessaire */

   for (i = 0; i < usNbRDN; i++)
   {
	   RDNEncoded[i].pData = NULL;
   }

   pOutBloc->usLen = 1;
   for (i = 0; i < usNbRDN; i++)
   {
      rv = CC_Encode_RDN(&RDN[i].Content, &RDNEncoded[i]);
      if (rv != RV_SUCCESS) goto err;
      pOutBloc->usLen += RDNEncoded[i].usLen;
   }
   

   /* Reconstruction � partir des composants                                  */

   if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }

   pCurrent = pOutBloc->pData;

   *pCurrent = (BYTE) usNbRDN;
   pCurrent++;

   for (i = 0; i < usNbRDN; i++)
   {
      memcpy(pCurrent, RDNEncoded[i].pData, RDNEncoded[i].usLen);
      GMEM_Free(RDNEncoded[i].pData); 
      pCurrent += RDNEncoded[i].usLen;
   }

   return(RV_SUCCESS);

err:
   for (i = 0; i < usNbRDN; i++)
   {
      GMEM_Free(RDNEncoded[i].pData);
   }
   return (rv);
}


/*******************************************************************************
* int CC_Encode_RDN(BLOC *pInBloc,
*                   BLOC *pOutBloc
*                  )
*
* Description : Encode une donn�e de type RelativeDistinguishedName (RDN).
*               Ceci consiste en l'�clatement en ses diff�rents composants,
*               leurs d�senrobages Asn1 et leurs encodages respectifs, et la
*               concat�nation de ces r�sultats.
*
* Remarks     : Un octet de contr�le (en d�but du r�sultat) indique le nombre
*               de AttributeValueAssertion dont est compos� le RDN.
*
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_RDN(BLOC *pInBloc,
                  BLOC *pOutBloc
                 )

{
   ASN1
      AVA[MAX_AVA];
   BLOC
      AVAEncoded[MAX_AVA];
   BYTE
      *pCurrent;
   USHORT
      i,
      usNbAVA;
   int
      rv;


   /* D�composition du RDN en ses diff�rents AVA                              */

   pCurrent = pInBloc->pData;
   usNbAVA = 0;

   while (pCurrent < pInBloc->pData + pInBloc->usLen)
   {
      AVA[usNbAVA].Asn1.pData = pCurrent;
      rv = CC_ExtractContent(&(AVA[usNbAVA]));
      if (rv != RV_SUCCESS) return rv;
      pCurrent = AVA[usNbAVA].Content.pData + AVA[usNbAVA].Content.usLen;
      usNbAVA++;
   }

   ASSERT(pCurrent == pInBloc->pData + pInBloc->usLen);


   /* Encodages des diff�rents composants et calcul de la longueur n�cessaire */

   for (i = 0; i < usNbAVA; i++)
   {
	   AVAEncoded[i].pData = NULL;
   }

   pOutBloc->usLen = 1;
   for (i = 0; i < usNbAVA; i++)
   {
      rv = CC_Encode_AVA(&AVA[i].Content, &AVAEncoded[i]);
      if (rv != RV_SUCCESS) goto err;
      pOutBloc->usLen += AVAEncoded[i].usLen;
   }
   

   /* Reconstruction � partir des composants                                  */

   if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }

   pCurrent = pOutBloc->pData;

   *pCurrent = (BYTE) usNbAVA;
   pCurrent++;

   for (i = 0; i < usNbAVA; i++)
   {
      memcpy(pCurrent, AVAEncoded[i].pData, AVAEncoded[i].usLen);
      GMEM_Free(AVAEncoded[i].pData); 
      pCurrent += AVAEncoded[i].usLen;
   }

   return(RV_SUCCESS);

err:
   for (i = 0; i < usNbAVA; i++)
   {
      GMEM_Free(AVAEncoded[i].pData);
   }

   return(rv);

}


/*******************************************************************************
* int CC_Encode_AVA(BLOC *pInBloc,
*                   BLOC *pOutBloc
*                  )
*
* Description : Encode une donn�e de type AttributeValueAssertion (AVA).
*               Ceci consiste en l'�clatement en ses diff�rents composants,
*               leurs d�senrobages Asn1 et leurs encodages respectifs, et la
*               concat�nation de ces r�sultats.
*
* Remarks     : On utilise un dictionnaire statique (d�fini au d�but de ce
*               source) pour remplacer le type d'attribut par un index.
*               Un octet de contr�le (en d�but du r�sultat) indique, ou bien que
*               l'on n'a pas trouv� le type d'attribut dans le dico (0xFF)
*               ou l'index du type d'attribut.
*               On ne code pas le Content de AttributeValue mais son Asn1 car on
*               n'est pas s�r du tag employ�.
*
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_AVA(BLOC *pInBloc,
                  BLOC *pOutBloc
                 )

{
   ASN1
      AttributeTypePart,
      AttributeValuePart;
   BLOC
      AttributeTypeEncoded,
      AttributeValueEncoded;
   BOOL
      bFound;
   USHORT
      Index,
      AttributeTypeIndex;
   int
      rv;


   /* D�composition                                                           */

   AttributeTypePart.Asn1.pData = pInBloc->pData;
   rv = CC_ExtractContent(&AttributeTypePart);
   if (rv != RV_SUCCESS) return rv;

   AttributeValuePart.Asn1.pData = AttributeTypePart.Content.pData
                                 + AttributeTypePart.Content.usLen;
   rv = CC_ExtractContent(&AttributeValuePart);   /* Pas n�cessaire */
   if (rv != RV_SUCCESS) return rv;


   /* Recherche de l'identifiant de l'AttributeType dans le dictionnaire      */

   Index = 0;
   bFound = FALSE;
	while((bFound == FALSE) && (AttributeTypeDict[Index] != NULL))
	{
		if (!memcmp(AttributeTypeDict[Index],
                  AttributeTypePart.Content.pData,
                  AttributeTypePart.Content.usLen))
      {
         bFound = TRUE;
         AttributeTypeIndex = Index;
      }
		Index++;
   }


   /* Construction de l'encodage                                              */

   /* Attention : on encode aussi l'enrobage de AttributeValue !              */

   if (bFound == TRUE)
   {
      /* Il nous faut la longueur enrobage compris mais cette ligne est-elle
		   vraiment n�cessaire ?                                                */
      AttributeValuePart.Asn1.usLen = (unsigned short) (DWORD)((pInBloc->pData + pInBloc->usLen)
                                    - AttributeValuePart.Asn1.pData);

      rv = CC_RawEncode(&(AttributeValuePart.Asn1), &AttributeValueEncoded, TRUE);
		if (rv != RV_SUCCESS) return rv;

      pOutBloc->usLen = 1 + AttributeValueEncoded.usLen;
      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         GMEM_Free(AttributeValueEncoded.pData);
		 return(RV_MALLOC_FAILED);
      }

      pOutBloc->pData[0] = (BYTE) AttributeTypeIndex;
      memcpy(&(pOutBloc->pData[1]), AttributeValueEncoded.pData, AttributeValueEncoded.usLen);

      GMEM_Free(AttributeValueEncoded.pData);
   }
   else
   {
      /* Si on n'a pas trouv� l'attribut dans le dictionnaire                 */

      rv = CC_RawEncode(&(AttributeTypePart.Content), &AttributeTypeEncoded, TRUE);
      if (rv != RV_SUCCESS) return rv;

      rv = CC_RawEncode(&(AttributeValuePart.Asn1), &AttributeValueEncoded, TRUE);
      if (rv != RV_SUCCESS)
	  {
		  GMEM_Free(AttributeTypeEncoded.pData);
		  return rv;
	  }

      pOutBloc->usLen = 1
                      + AttributeTypeEncoded.usLen
                      + AttributeValueEncoded.usLen;

      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         GMEM_Free(AttributeTypeEncoded.pData);
         GMEM_Free(AttributeValueEncoded.pData);
	     return(RV_MALLOC_FAILED);
      }

      pOutBloc->pData[0] = ESCAPE_CHAR;
      memcpy(&(pOutBloc->pData[1]),
                AttributeTypeEncoded.pData,
                AttributeTypeEncoded.usLen);
      memcpy(&(pOutBloc->pData[1 + AttributeTypeEncoded.usLen]),
                AttributeValueEncoded.pData,
                AttributeValueEncoded.usLen);

      GMEM_Free(AttributeTypeEncoded.pData);
      GMEM_Free(AttributeValueEncoded.pData);
   }

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Encode_Validity(BLOC *pInBloc,
*                        BLOC *pOutBloc
*                       )
*
* Description : Encode une donn�e de type Validity.
*               Ceci consiste en l'�clatement en ses diff�rents composants,
*               leurs d�senrobages Asn1 et leurs encodages respectifs, et la
*               concat�nation de ces r�sultats.
*
* Remarks     : Un octet de contr�le (en d�but du r�sultat) indique les formats
*               des deux parties notBefore et notAfter.
*               
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_Validity(BLOC *pInBloc,
                       BLOC *pOutBloc
                      )

{
   ASN1
      notBeforePart,
      notAfterPart;
   BLOC
      notBeforeEncoded,
      notAfterEncoded;
   BYTE
      notBeforeFormat,
      notAfterFormat,
      *pCurrent;
   int
      rv;


   /* D�composition                                                           */
   
   pCurrent = pInBloc->pData;

   notBeforePart.Asn1.pData = pCurrent;
   rv = CC_ExtractContent(&notBeforePart);
   if (rv != RV_SUCCESS) return rv;
   pCurrent = notBeforePart.Content.pData + notBeforePart.Content.usLen;

   notAfterPart.Asn1.pData = pCurrent;
   rv = CC_ExtractContent(&notAfterPart);
   if (rv != RV_SUCCESS) return rv;
   pCurrent = notAfterPart.Content.pData + notAfterPart.Content.usLen;


   /* Encodages des diff�rents composants et calcul de la longueur n�cessaire */

   pOutBloc->usLen = 1;

   rv = CC_Encode_UTCTime(&notBeforePart.Content, &notBeforeEncoded, &notBeforeFormat);
   if (rv != RV_SUCCESS) return rv;
   pOutBloc->usLen += notBeforeEncoded.usLen;

   rv = CC_Encode_UTCTime(&notAfterPart.Content, &notAfterEncoded, &notAfterFormat);
   if (rv != RV_SUCCESS)
   {
	   GMEM_Free(notBeforeEncoded.pData);
	   return rv;
   }
   pOutBloc->usLen += notAfterEncoded.usLen;


   /* Reconstruction � partir des composants                                  */

   if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
   {
      GMEM_Free(notBeforeEncoded.pData); 
	  GMEM_Free(notAfterEncoded.pData);
	  return(RV_MALLOC_FAILED);
   }

   pCurrent = pOutBloc->pData;

   *pCurrent = (notBeforeFormat << 4) + notAfterFormat;
   pCurrent++;

   memcpy(pCurrent, notBeforeEncoded.pData, notBeforeEncoded.usLen);
   GMEM_Free(notBeforeEncoded.pData); 
   pCurrent += notBeforeEncoded.usLen;

   memcpy(pCurrent, notAfterEncoded.pData, notAfterEncoded.usLen);
   GMEM_Free(notAfterEncoded.pData); 
   pCurrent += notAfterEncoded.usLen;

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Encode_UTCTime(BLOC *pInBloc,
*                       BLOC *pOutBloc,
*                       BYTE *pFormat
*                      )
*
* Description : Encode une donn�e de type UTCTime.
*               Suivant le format d�tect�, l'encodage consiste en :
*                - sur 32 bits : le nombre de minutes ou de secondes depuis une
*                                date de r�f�rence.
*                - sur 16 bits : le nombre de minutes de d�calage UTC
*                                s'il y a lieu.
*
* Remarks     : 
*               
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*               pFormat : indique au quel format �tait la donn�e d'entr�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_UTCTime(BLOC *pInBloc,
                      BLOC *pOutBloc,
                      BYTE *pFormat
                     )

{
   BYTE
      *pData;
   ULONG
      ulNbMinute,
      ulNbSecond;
   USHORT
      usNbDeltaMinute,
      usYear,
      usMonth,
      usDay,
      usHour,
      usMinute,
      usSecond,
      usDeltaHour,
      usDeltaMinute,
      usDayInYear;


   pData = pInBloc->pData;


   /* Calcul du nombre de minutes                                             */

   usYear   = 10 * (pData[0] - '0') + (pData[1] - '0');
   usMonth  = 10 * (pData[2] - '0') + (pData[3] - '0');
   usDay    = 10 * (pData[4] - '0') + (pData[5] - '0');
   usHour   = 10 * (pData[6] - '0') + (pData[7] - '0');
   usMinute = 10 * (pData[8] - '0') + (pData[9] - '0');

   ASSERT((usYear >= 0) && (usYear <= 99));
   ASSERT((usMonth >= 1) && (usMonth <= 12));
   ASSERT((usDay >= 1) && (usDay <= 31));
   ASSERT((usHour >= 0) && (usHour <= 23));
   ASSERT((usMinute >= 0) && (usMinute <= 59));

   /* Le nombre de jours dans l'ann�e vaut 0 le 1er janvier                   */

   usDayInYear = NbDaysInMonth[usMonth - 1] + (usDay - 1);
   if (((usYear % 4) == 0) && (usMonth >= 3)) usDayInYear++;

   /* L'ann�e 00 est compt�e bissextile ci-dessous                            */
   /* L'ann�e courante si elle l'est a d�j� �t� compt�e dans usDayInYear      */

	/*
	Probl�me sur l'�valuation de (usYear - 1) / 4 :
				usYear = 8 -> 1
				usYear = 4 -> 0
				usYear = 0 -> 0 !!

	ulNbMinute = usYear * UTCT_MINUTE_IN_YEAR
              + (1 + (usYear - 1) / 4) * UTCT_MINUTE_IN_DAY
              + usDayInYear * UTCT_MINUTE_IN_DAY
              + usHour * UTCT_MINUTE_IN_HOUR
              + usMinute;
	*/

   ulNbMinute = usYear * UTCT_MINUTE_IN_YEAR
              + (usYear + 3) / 4 * UTCT_MINUTE_IN_DAY		// Ann�es bissextiles
              + usDayInYear * UTCT_MINUTE_IN_DAY
              + usHour * UTCT_MINUTE_IN_HOUR
              + usMinute;


   /* Le format et la suite des calculs en fonction de la longueur            */

   switch(pInBloc->usLen)
   {
   case 11 :
      *pFormat = UTCT_YYMMDDhhmmZ;

      ASSERT(pData[10] == 'Z');

      pOutBloc->usLen = 4;
      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         return(RV_MALLOC_FAILED);
      }
      *(ULONG *)pOutBloc->pData = ulNbMinute;

      break;

   case 13 :
      *pFormat = UTCT_YYMMDDhhmmssZ;

      usSecond = 10 * (pData[10] - '0') + (pData[11] - '0');
      ASSERT((usSecond >= 0) && (usSecond <= 59));
      ASSERT(pData[12] == 'Z');

      ulNbSecond = 60 * ulNbMinute + usSecond;
      
      pOutBloc->usLen = 4;
      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         return(RV_MALLOC_FAILED);
      }
      *(ULONG *)pOutBloc->pData = ulNbSecond;

      break;

   case 15 :
      if (pData[10] == '+')
      {
         *pFormat = UTCT_YYMMDDhhmmphhmm;
      }
      else if (pData[10] == '-')
      {
         *pFormat = UTCT_YYMMDDhhmmmhhmm;
      }
      else
      {
         return(RV_INVALID_DATA);
      }

      usDeltaHour   = 10 * (pData[11] - '0') + (pData[12] - '0');
      usDeltaMinute = 10 * (pData[13] - '0') + (pData[14] - '0');
      ASSERT((usDeltaHour >= 0) && (usDeltaHour <= 23));
      ASSERT((usDeltaMinute >= 0) && (usDeltaMinute <= 59));

      usNbDeltaMinute = 60 * usDeltaHour + usDeltaMinute;
      
      pOutBloc->usLen = 4 + 2;
      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         return(RV_MALLOC_FAILED);
      }
      *(ULONG *)pOutBloc->pData = ulNbMinute;
      *(USHORT *)(pOutBloc->pData + sizeof(ulNbMinute)) = usNbDeltaMinute;

      break;

   case 17 :
      if (pData[12] == '+')
      {
         *pFormat = UTCT_YYMMDDhhmmphhmm;
      }
      else if (pData[12] == '-')
      {
         *pFormat = UTCT_YYMMDDhhmmmhhmm;
      }
      else
      {
         return(RV_INVALID_DATA);
      }

      usSecond = 10 * (pData[10] - '0') + (pData[11] - '0');
      ASSERT((usSecond >= 0) && (usSecond <= 59));

      ulNbSecond = 60 * ulNbMinute + usSecond;
      
      usDeltaHour   = 10 * (pData[13] - '0') + (pData[14] - '0');
      usDeltaMinute = 10 * (pData[15] - '0') + (pData[16] - '0');
      ASSERT((usDeltaHour >= 0) && (usDeltaHour <= 23));
      ASSERT((usDeltaMinute >= 0) && (usDeltaMinute <= 59));

      usNbDeltaMinute = 60 * usDeltaHour + usDeltaMinute;
      
      pOutBloc->usLen = 4 + 2;
      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         return(RV_MALLOC_FAILED);
      }
      *(ULONG *)pOutBloc->pData = ulNbSecond;
      *(USHORT *)(pOutBloc->pData + sizeof(ulNbSecond)) = usNbDeltaMinute;

      break;

   default :
      return(RV_INVALID_DATA);
   }

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Encode_SubjectPKInfo(BLOC *pInBloc,
*                             BLOC *pOutBloc
*                            )
*
* Description : Encode une donn�e de type SubjectPublicKeyInfo.
*               Ceci consiste en l'�clatement en ses diff�rents composants,
*               leurs d�senrobages Asn1 et leurs encodages respectifs, et la
*               concat�nation de ces r�sultats.
*
* Remarks     : 
*
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_SubjectPKInfo(BLOC *pInBloc,
                            BLOC *pOutBloc
                           )

{
   ASN1
      algorithmPart,
      subjectPKPart;
   BLOC
      algorithmEncoded,
      subjectPKEncoded;
   BYTE
//      *pData,
      *pCurrent;
   int
      rv;


   /* D�composition du SubjectPKInfo en ses diff�rents composants             */
   
   pCurrent = pInBloc->pData;

   algorithmPart.Asn1.pData = pCurrent;
   rv = CC_ExtractContent(&algorithmPart);
   if (rv != RV_SUCCESS) return rv;
   pCurrent = algorithmPart.Content.pData + algorithmPart.Content.usLen;

   subjectPKPart.Asn1.pData = pCurrent;
   rv = CC_ExtractContent(&subjectPKPart);
   if (rv != RV_SUCCESS) return rv;
   pCurrent = subjectPKPart.Content.pData + subjectPKPart.Content.usLen;


   /* Encodages des diff�rents composants et calcul de la longueur n�cessaire */

   pOutBloc->usLen = 0;

   rv = CC_Encode_AlgorithmIdentifier(&algorithmPart.Content, &algorithmEncoded);
   if (rv != RV_SUCCESS) return rv;
   pOutBloc->usLen += algorithmEncoded.usLen;

#ifdef _TRICKY_COMPRESSION
	/* Ne pas faire le RawEncode permet de gagner l'octet 0xFF et �ventuellement plus */
#ifdef _OPT_HEADER
	if (subjectPKPart.Content.usLen < 0x80)
	{
		if ((pData = GMEM_Alloc(pInBloc->usLen + 1)) == NULL_PTR)
		{
			return(RV_MALLOC_FAILED);
		}
		else
		{
			pData[0] = subjectPKPart.Content.usLen;
			memcpy(&pData[1],
					 subjectPKPart.Content.pData,
					 subjectPKPart.Content.usLen);

			subjectPKEncoded.usLen = subjectPKPart.Content.usLen + 1;
			subjectPKEncoded.pData = pData;
		}
		pOutBloc->usLen += subjectPKEncoded.usLen;
	}
	else
	{
		if ((pData = GMEM_Alloc(pInBloc->usLen + 2)) == NULL_PTR)
		{
			return(RV_MALLOC_FAILED);
		}
		else
		{
			pData[0] = 0x80 | (subjectPKPart.Content.usLen >> 8);
			pData[1] = subjectPKPart.Content.usLen & 0x00FF;
			memcpy(&pData[2],
					 subjectPKPart.Content.pData,
					 subjectPKPart.Content.usLen);

			subjectPKEncoded.usLen = subjectPKPart.Content.usLen + 2;
			subjectPKEncoded.pData = pData;
		} 
		pOutBloc->usLen += subjectPKEncoded.usLen;
	}
#else	/* _OPT_HEADER */
	if ((pData = GMEM_Alloc(pInBloc->usLen + 2)) == NULL_PTR)
	{
		return(RV_MALLOC_FAILED);
	}
	else
	{
		pData[0] = subjectPKPart.Content.usLen >> 8;
		pData[1] = subjectPKPart.Content.usLen & 0x00FF;
		memcpy(&pData[2],
				 subjectPKPart.Content.pData,
				 subjectPKPart.Content.usLen);

		subjectPKEncoded.usLen = subjectPKPart.Content.usLen + 2;
		subjectPKEncoded.pData = pData;
	} 
	pOutBloc->usLen += subjectPKEncoded.usLen;
#endif
#else /* _TRICKY_COMPRESSION */
   rv = CC_RawEncode(&subjectPKPart.Content, &subjectPKEncoded, FALSE);
   if (rv != RV_SUCCESS)
   {
	   GMEM_Free(algorithmEncoded.pData);
	   return rv;
   }
   pOutBloc->usLen += subjectPKEncoded.usLen;
#endif


   /* Reconstruction � partir des composants                                  */

   if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
   {
      GMEM_Free(algorithmEncoded.pData); 
	  GMEM_Free(subjectPKEncoded.pData);
	  return(RV_MALLOC_FAILED);
   }

   pCurrent = pOutBloc->pData;

   memcpy(pCurrent, algorithmEncoded.pData, algorithmEncoded.usLen);
   GMEM_Free(algorithmEncoded.pData); 
   pCurrent += algorithmEncoded.usLen;

   memcpy(pCurrent, subjectPKEncoded.pData, subjectPKEncoded.usLen);
   GMEM_Free(subjectPKEncoded.pData); 
   pCurrent += subjectPKEncoded.usLen;

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Encode_UniqueIdentifier(BLOC *pInBloc,
*                                BLOC *pOutBloc
*                               )
*
* Description : Encode une donn�e de type UniqueIdentifier.
*               Ceci consiste seulement en l'encodage brute (CC_RawEncode) de la
*               donn�e d'entr�e.
*
* Remarks     : 
*
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_UniqueIdentifier(BLOC *pInBloc,
                               BLOC *pOutBloc
                              )

{
   int
      rv;


   rv = CC_RawEncode(pInBloc, pOutBloc, TRUE);
   if (rv != RV_SUCCESS) return rv;

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Encode_Extensions(BLOC *pInBloc,
*                          BLOC *pOutBloc
*                         )
*
* Description : Encode une donn�e de type Extensions.
*               Ceci consiste seulement en l'encodage brute (CC_RawEncode) de la
*               donn�e d'entr�e.
*
* Remarks     : Un d�senrobage suppl�mentaire (context specific) est requis. 
*               Un octet de contr�le (en d�but du r�sultat) indique le nombre
*               de Extension dont est compos� le Extensions.
*
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_Extensions(BLOC *pInBloc,
                         BLOC *pOutBloc
                        )

{
   ASN1
      ExtensionPart[MAX_EXTENSION],
      InInAsn1;
   BLOC
      ExtensionEncoded[MAX_EXTENSION],
      *pInInBloc;
   BYTE
      *pCurrent;
   int
      rv;
   USHORT
      i,
      usNbExtension;


   /* On enl�ve l'enrobage 'context specific' suppl�mentaire                  */
   /* et on travaille avec pInInBloc au lieu de pInBloc                       */

   InInAsn1.Asn1.pData = pInBloc->pData;
   rv = CC_ExtractContent(&InInAsn1);
   if (rv != RV_SUCCESS) return rv;

   pInInBloc = &(InInAsn1.Content);

   
   /* D�composition de Extensions en ses diff�rents Extension                 */

   pCurrent = pInInBloc->pData;
   usNbExtension = 0;

   while (pCurrent < pInInBloc->pData + pInInBloc->usLen)
   {
      ExtensionPart[usNbExtension].Asn1.pData = pCurrent;
      rv = CC_ExtractContent(&(ExtensionPart[usNbExtension]));
      if (rv != RV_SUCCESS) return rv;
      pCurrent = ExtensionPart[usNbExtension].Content.pData
               + ExtensionPart[usNbExtension].Content.usLen;
      usNbExtension++;
   }

   ASSERT(pCurrent == pInInBloc->pData + pInInBloc->usLen);


   /* Encodages des diff�rents composants et calcul de la longueur n�cessaire */

   for (i = 0; i < usNbExtension; i++)
   {
	   ExtensionEncoded[i].pData = NULL;
   }

   pOutBloc->usLen = 1;
   for (i = 0; i < usNbExtension; i++)
   {
      rv = CC_Encode_Extension(&ExtensionPart[i].Content, &ExtensionEncoded[i]);
      if (rv != RV_SUCCESS) goto err;
      pOutBloc->usLen += ExtensionEncoded[i].usLen;
   }
   

   /* Reconstruction � partir des composants                                  */

   if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }

   pCurrent = pOutBloc->pData;

   *pCurrent = (BYTE) usNbExtension;
   pCurrent++;

   for (i = 0; i < usNbExtension; i++)
   {
      memcpy(pCurrent, ExtensionEncoded[i].pData, ExtensionEncoded[i].usLen);
      GMEM_Free(ExtensionEncoded[i].pData); 
      pCurrent += ExtensionEncoded[i].usLen;
   }

   return(RV_SUCCESS);

err:
   for (i = 0; i < usNbExtension; i++)
   {
      GMEM_Free(ExtensionEncoded[i].pData);
   }

   return(rv);
}


/*******************************************************************************
* int CC_Encode_Extension(BLOC *pInBloc,
*                         BLOC *pOutBloc
*                        )
*
* Description : Encode une donn�e de type Extension.
*               Ceci consiste seulement en l'encodage brute (CC_RawEncode) de la
*               donn�e d'entr�e.
*
* Remarks     : 
*
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_Extension(BLOC *pInBloc,
                        BLOC *pOutBloc
                       )

{
   int
      rv;


   rv = CC_RawEncode(pInBloc, pOutBloc, TRUE);
   if (rv != RV_SUCCESS) return rv;

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Encode_Signature(BLOC *pInBloc,
*                         BLOC *pOutBloc
*                        )
*
* Description : Encode la signature du certificat.
*               Ceci consiste seulement en l'encodage brute (CC_RawEncode) de la
*               donn�e d'entr�e.
*
* Remarks     : On peut �viter de tenter de compresser (CC_RawEncode) si on
*               estime que cela ne sera pas efficace (donn�e al�atoire).
*               Cela permet de gagner un octet (0xFF) pour les donn�es de taille
*               sup�rieure � 30 octets (cas g�n�ral).
*
* In          : pInBloc : la partie � encoder (champ Content)
*
* Out         : pOutBloc : l'encod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Encode_Signature(BLOC *pInBloc,
                        BLOC *pOutBloc
                       )

{
//	BYTE
//		*pData;
   int
      rv;


#ifdef _TRICKY_COMPRESSION
	/* Ne pas faire le RawEncode permet de gagner l'octet 0xFF */
#ifdef _OPT_HEADER
	if (pInBloc->usLen < 0x80)
	{
		if ((pData = GMEM_Alloc(pInBloc->usLen + 1)) == NULL_PTR)
		{
			return(RV_MALLOC_FAILED);
		}
		else
		{
			pData[0] = pInBloc->usLen;
			memcpy(&pData[1], pInBloc->pData, pInBloc->usLen);

			pOutBloc->usLen = pInBloc->usLen + 1;
			pOutBloc->pData = pData;
		}
	}
	else
	{
		if ((pData = GMEM_Alloc(pInBloc->usLen + 2)) == NULL_PTR)
		{
			return(RV_MALLOC_FAILED);
		}
		else
		{
			pData[0] = 0x80 | (pInBloc->usLen >> 8);
			pData[1] = pInBloc->usLen & 0x00FF;
			memcpy(&pData[2], pInBloc->pData, pInBloc->usLen);

			pOutBloc->usLen = pInBloc->usLen + 2;
			pOutBloc->pData = pData;
		}
	}
#else	/* _OPT_HEADER */
	if ((pData = GMEM_Alloc(pInBloc->usLen + 2)) == NULL_PTR)
	{
		return(RV_MALLOC_FAILED);
	}
	else
	{
		pData[0] = pInBloc->usLen >> 8;
		pData[1] = pInBloc->usLen & 0x00FF;
		memcpy(&pData[2], pInBloc->pData, pInBloc->usLen);

		pOutBloc->usLen = pInBloc->usLen + 2;
		pOutBloc->pData = pData;
	}
#endif
#else	/* _TRICKY_COMPRESSION */
   rv = CC_RawEncode(pInBloc, pOutBloc, TRUE);
   if (rv != RV_SUCCESS) return rv;
#endif

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Decode_TBSCertificate(BYTE    *pInData,
*                              BLOC    *pOutBloc,
*                              USHORT  *pLength
*                             )
*
* Description : D�code une donn�e de type TBSCertificate.
*               Ceci consiste en le d�codage des diff�rentes parties encod�es
*               successives, leurs enrobages respectifs (tags uniquement
*               par la spec X.509), et la concat�nation de ces r�sultats.
*
* Remarks     : 
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*               pLength : la longueur de donn�es encod�s utilis�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_TBSCertificate(BYTE    *pInData,
                             BLOC    *pOutBloc,
                             USHORT  *pLength
                            )

{
   ASN1
      serialNumberPart,
      signaturePart,
      issuerPart,
      validityPart,
      subjectPart,
      subjectPKInfoPart,
      issuerUIDPart,
      subjectUIDPart,
      extensionsPart;
   BOOL
      bVersionPresent,
      bIssuerUIDPresent,
      bSubjectUIDPresent,
      bExtensionsPresent;
   BYTE
      *pCurrent;
   int
      rv;
   USHORT
      usVersion = 0,
      Length;

   serialNumberPart.Asn1.pData  = NULL;
   signaturePart.Asn1.pData     = NULL;
   issuerPart.Asn1.pData        = NULL;
   validityPart.Asn1.pData      = NULL;
   subjectPart.Asn1.pData       = NULL;
   subjectPKInfoPart.Asn1.pData = NULL;
   issuerUIDPart.Asn1.pData     = NULL;
   subjectUIDPart.Asn1.pData    = NULL;
   extensionsPart.Asn1.pData    = NULL;


   pCurrent = pInData;
   
   bVersionPresent = ((*pCurrent & 0x80) != 0);
   bIssuerUIDPresent = ((*pCurrent & 0x40) != 0);
   bSubjectUIDPresent = ((*pCurrent & 0x20) != 0);
   bExtensionsPresent = ((*pCurrent & 0x10) != 0);
   usVersion = *pCurrent & 0x03;
   pCurrent++;

   rv = CC_Decode_CertificateSerialNumber(pCurrent, &(serialNumberPart.Content), &Length);
   if (rv != RV_SUCCESS) goto err;
   serialNumberPart.Tag = TAG_INTEGER;
   rv = CC_BuildAsn1(&serialNumberPart);
   GMEM_Free(serialNumberPart.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;

   rv = CC_Decode_AlgorithmIdentifier(pCurrent, &(signaturePart.Content), &Length);
   if (rv != RV_SUCCESS) goto err;
   signaturePart.Tag = TAG_SEQUENCE;
   rv = CC_BuildAsn1(&signaturePart);
   GMEM_Free(signaturePart.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;

   rv = CC_Decode_Name(pCurrent, &(issuerPart.Content), &Length);
   if (rv != RV_SUCCESS) goto err;
   issuerPart.Tag = TAG_SEQUENCE_OF;
   rv = CC_BuildAsn1(&issuerPart);
   GMEM_Free(issuerPart.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;

   rv = CC_Decode_Validity(pCurrent, &(validityPart.Content), &Length);
   if (rv != RV_SUCCESS) goto err;
   validityPart.Tag = TAG_SEQUENCE;
   rv = CC_BuildAsn1(&validityPart);
   GMEM_Free(validityPart.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;

   rv = CC_Decode_Name(pCurrent, &(subjectPart.Content), &Length);
   if (rv != RV_SUCCESS) goto err;
   subjectPart.Tag = TAG_SEQUENCE_OF;
   rv = CC_BuildAsn1(&subjectPart);
   GMEM_Free(subjectPart.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;

   rv = CC_Decode_SubjectPKInfo(pCurrent, &(subjectPKInfoPart.Content), &Length);
   if (rv != RV_SUCCESS) goto err;
   subjectPKInfoPart.Tag = TAG_SEQUENCE;
   rv = CC_BuildAsn1(&subjectPKInfoPart);
   GMEM_Free(subjectPKInfoPart.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;

   if (bIssuerUIDPresent == TRUE)
   {
      rv = CC_Decode_UniqueIdentifier(pCurrent, &(issuerUIDPart.Content), &Length);
      if (rv != RV_SUCCESS) goto err;
      issuerUIDPart.Tag = TAG_OPTION_ISSUER_UID;
      rv = CC_BuildAsn1(&issuerUIDPart);
      GMEM_Free(issuerUIDPart.Content.pData);
      if (rv != RV_SUCCESS) goto err;
      pCurrent += Length;
   }

   if (bSubjectUIDPresent == TRUE)
   {
      rv = CC_Decode_UniqueIdentifier(pCurrent, &(subjectUIDPart.Content), &Length);
      if (rv != RV_SUCCESS) goto err;
      subjectUIDPart.Tag = TAG_OPTION_SUBJECT_UID;
      rv = CC_BuildAsn1(&subjectUIDPart);
      GMEM_Free(subjectUIDPart.Content.pData);
      if (rv != RV_SUCCESS) goto err;
      pCurrent += Length;
   }

   if (bExtensionsPresent == TRUE)
   {
      rv = CC_Decode_Extensions(pCurrent, &(extensionsPart.Content), &Length);
      if (rv != RV_SUCCESS) goto err;
      extensionsPart.Tag = TAG_OPTION_EXTENSIONS;
      rv = CC_BuildAsn1(&extensionsPart);
      GMEM_Free(extensionsPart.Content.pData);
      if (rv != RV_SUCCESS) goto err;
      pCurrent += Length;
   }

   *pLength = (unsigned short)(DWORD) (pCurrent - pInData);


   /* Calcul de la longueur du tbsCertificate d�cod� et allocation            */
   
   pOutBloc->usLen = (bVersionPresent ? 5 : 0)
                   + serialNumberPart.Asn1.usLen
                   + signaturePart.Asn1.usLen
                   + issuerPart.Asn1.usLen
                   + validityPart.Asn1.usLen
                   + subjectPart.Asn1.usLen
                   + subjectPKInfoPart.Asn1.usLen
                   + (bIssuerUIDPresent ? issuerUIDPart.Asn1.usLen : 0)
                   + (bSubjectUIDPresent ? subjectUIDPart.Asn1.usLen : 0)
                   + (bExtensionsPresent ? extensionsPart.Asn1.usLen : 0);

   if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }


   /* Reconstruction du tbsCertificate d�cod�                                 */
   
   pCurrent = pOutBloc->pData;

   if (bVersionPresent == TRUE)
   {
      pCurrent[0] = TAG_OPTION_VERSION;
      pCurrent[1] = 0x03;
      pCurrent[2] = 0x02;
      pCurrent[3] = 0x01;
      pCurrent[4] = (BYTE)usVersion;
      pCurrent += 5;
   }

   memcpy(pCurrent, serialNumberPart.Asn1.pData, serialNumberPart.Asn1.usLen);
   GMEM_Free(serialNumberPart.Asn1.pData);
   pCurrent += serialNumberPart.Asn1.usLen;

   memcpy(pCurrent, signaturePart.Asn1.pData, signaturePart.Asn1.usLen);
   GMEM_Free(signaturePart.Asn1.pData);
   pCurrent += signaturePart.Asn1.usLen;

   memcpy(pCurrent, issuerPart.Asn1.pData, issuerPart.Asn1.usLen);
   GMEM_Free(issuerPart.Asn1.pData);
   pCurrent += issuerPart.Asn1.usLen;

   memcpy(pCurrent, validityPart.Asn1.pData, validityPart.Asn1.usLen);
   GMEM_Free(validityPart.Asn1.pData);
   pCurrent += validityPart.Asn1.usLen;

   memcpy(pCurrent, subjectPart.Asn1.pData, subjectPart.Asn1.usLen);
   GMEM_Free(subjectPart.Asn1.pData);
   pCurrent += subjectPart.Asn1.usLen;

   memcpy(pCurrent, subjectPKInfoPart.Asn1.pData, subjectPKInfoPart.Asn1.usLen);
   GMEM_Free(subjectPKInfoPart.Asn1.pData);
   pCurrent += subjectPKInfoPart.Asn1.usLen;

   if (bIssuerUIDPresent == TRUE)
   {
      memcpy(pCurrent, issuerUIDPart.Asn1.pData, issuerUIDPart.Asn1.usLen);
      GMEM_Free(issuerUIDPart.Asn1.pData);
      pCurrent += issuerUIDPart.Asn1.usLen;
   }

   if (bSubjectUIDPresent == TRUE)
   {
      memcpy(pCurrent, subjectUIDPart.Asn1.pData, subjectUIDPart.Asn1.usLen);
      GMEM_Free(subjectUIDPart.Asn1.pData);
      pCurrent += subjectUIDPart.Asn1.usLen;
   }

   if (bExtensionsPresent == TRUE)
   {
      memcpy(pCurrent, extensionsPart.Asn1.pData, extensionsPart.Asn1.usLen);
      GMEM_Free(extensionsPart.Asn1.pData);
      pCurrent += extensionsPart.Asn1.usLen;
   }

   return(RV_SUCCESS);

err:
   GMEM_Free(serialNumberPart.Asn1.pData);
   GMEM_Free(signaturePart.Asn1.pData);
   GMEM_Free(issuerPart.Asn1.pData);
   GMEM_Free(validityPart.Asn1.pData);
   GMEM_Free(subjectPart.Asn1.pData);
   GMEM_Free(subjectPKInfoPart.Asn1.pData);
   GMEM_Free(issuerUIDPart.Asn1.pData);
   GMEM_Free(subjectUIDPart.Asn1.pData);
   GMEM_Free(extensionsPart.Asn1.pData);

   return (rv);
}


/*******************************************************************************
* int CC_Decode_CertificateSerialNumber(BYTE    *pInData,
*                                       BLOC    *pOutBloc,
*                                       USHORT  *pLength
*                                      )
*
* Description : D�code une donn�e de type CertificateSerialNumber.
*               Ceci consiste seulement en le d�codage brute (CC_RawDecode) de
*               la donn�e d'entr�e.
*
* Remarks     : 
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*               pLength : la longueur de donn�es encod�s utilis�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_CertificateSerialNumber(BYTE    *pInData,
                                      BLOC    *pOutBloc,
                                      USHORT  *pLength
                                     )

{
   int
      rv;


   rv = CC_RawDecode(pInData, pOutBloc, pLength, TRUE);
   if (rv != RV_SUCCESS) return rv;

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Decode_AlgorithmIdentifier(BYTE    *pInData,
*                                   BLOC    *pOutBloc,
*                                   USHORT  *pLength
*                                  )
*
* Description : D�code une donn�e de type AlgorithmIdentifier.
*               Ceci consiste en le d�codage des diff�rentes parties encod�es
*               successives, leurs enrobages respectifs (tags uniquement
*               par la spec X.509), et la concat�nation de ces r�sultats.
*
* Remarks     : Voir l'encodage
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*               pLength : la longueur de donn�es encod�s utilis�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_AlgorithmIdentifier(BYTE    *pInData,
                                  BLOC    *pOutBloc,
                                  USHORT  *pLength
                                 )

{
    ASN1
        AlgorithmPart,
        ParametersPart;
    BOOL
        bNullParam = FALSE,
        bNoParam   = FALSE;
    int
        rv;
    USHORT
        AlgoIndex,
        Length;

    AlgorithmPart.Asn1.pData  = NULL;
    ParametersPart.Asn1.pData = NULL;

    if (pInData[0] == ESCAPE_CHAR)
    {
        rv = CC_RawDecode(&pInData[1], pOutBloc, &Length, TRUE);
        *pLength = 1 + Length;
    }
    else
    {
        if (pInData[0] == ABSENT_PARAMETER_CHAR)
        {
            bNoParam   = TRUE;
            bNullParam = FALSE;
            AlgoIndex  = pInData[1];
        }
        else
        {
            bNoParam   = ((pInData[0] & 0x80) != 0);
            bNullParam = bNoParam;
            AlgoIndex  = pInData[0] & 0x7F;
        }

        if (bNoParam == TRUE)
        {
            AlgorithmPart.Content.usLen = (USHORT)strlen(AlgorithmTypeDict[AlgoIndex]);
            if ((AlgorithmPart.Content.pData = GMEM_Alloc(AlgorithmPart.Content.usLen)) == NULL_PTR)
            {
                return (RV_MALLOC_FAILED);
            }
            memcpy(AlgorithmPart.Content.pData,
                   AlgorithmTypeDict[AlgoIndex],
                   AlgorithmPart.Content.usLen);

            AlgorithmPart.Tag = TAG_OBJECT_IDENTIFIER;
            rv = CC_BuildAsn1(&AlgorithmPart);
            GMEM_Free(AlgorithmPart.Content.pData);
            if (rv != RV_SUCCESS) goto err;

            if (bNullParam == FALSE)
            {
                pOutBloc->usLen = AlgorithmPart.Asn1.usLen;
                if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
                {
                    rv = RV_MALLOC_FAILED;
                    goto err;
                }

                memcpy(pOutBloc->pData, AlgorithmPart.Asn1.pData, AlgorithmPart.Asn1.usLen);

                *pLength = 2;

                GMEM_Free(AlgorithmPart.Asn1.pData);
            }
            else
            {
                pOutBloc->usLen = AlgorithmPart.Asn1.usLen + 2;
                if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
                {
                    rv = RV_MALLOC_FAILED;
                    goto err;
                }

                memcpy(pOutBloc->pData, AlgorithmPart.Asn1.pData, AlgorithmPart.Asn1.usLen);

                pOutBloc->pData[AlgorithmPart.Asn1.usLen]   = 0x05;
                pOutBloc->pData[AlgorithmPart.Asn1.usLen+1] = 0x00;

                *pLength = 1;

                GMEM_Free(AlgorithmPart.Asn1.pData);

            }
        }
        else
        {
            AlgorithmPart.Content.usLen = (USHORT)strlen(AlgorithmTypeDict[AlgoIndex]);
            if ((AlgorithmPart.Content.pData = GMEM_Alloc(AlgorithmPart.Content.usLen)) == NULL_PTR)
            {
                return (RV_MALLOC_FAILED);
            }
            memcpy(AlgorithmPart.Content.pData,
                   AlgorithmTypeDict[AlgoIndex],
                   AlgorithmPart.Content.usLen);

            AlgorithmPart.Tag = TAG_OBJECT_IDENTIFIER;
            rv = CC_BuildAsn1(&AlgorithmPart);
            GMEM_Free(AlgorithmPart.Content.pData);
            if (rv != RV_SUCCESS) goto err;

            /* On recup�re directement l'asn1 des param�tres                     */
            rv = CC_RawDecode(&pInData[1], &(ParametersPart.Asn1), &Length, TRUE);
            if (rv != RV_SUCCESS) goto err;

            pOutBloc->usLen = AlgorithmPart.Asn1.usLen + ParametersPart.Asn1.usLen;
            if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
            {
                rv = RV_MALLOC_FAILED;
                goto err;
            }
            memcpy(pOutBloc->pData,
                   AlgorithmPart.Asn1.pData,
                   AlgorithmPart.Asn1.usLen);
            memcpy(pOutBloc->pData + AlgorithmPart.Asn1.usLen,
                   ParametersPart.Asn1.pData,
                   ParametersPart.Asn1.usLen);

            *pLength = 1 + Length;

            GMEM_Free(AlgorithmPart.Asn1.pData);
            GMEM_Free(ParametersPart.Asn1.pData);
        }
    }

    return (RV_SUCCESS);

    err:
    GMEM_Free(AlgorithmPart.Asn1.pData);
    GMEM_Free(ParametersPart.Asn1.pData);

    return rv;
}


/*******************************************************************************
* int CC_Decode_Name(BYTE    *pInData,
*                    BLOC    *pOutBloc,
*                    USHORT  *pLength
*                   )
*
* Description : D�code une donn�e de type Name.
*               Ceci consiste en le d�codage des diff�rentes parties encod�es
*               successives, leurs enrobages respectifs (tags uniquement
*               par la spec X.509), et la concat�nation de ces r�sultats.
*
* Remarks     : Voir l'encodage
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*               pLength : la longueur de donn�es encod�s utilis�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_Name(BYTE    *pInData,
                   BLOC    *pOutBloc,
                   USHORT  *pLength
                  )

{
   ASN1
      RDN[MAX_RDN];
   BYTE
      *pCurrent;
   int
      rv;
   USHORT
      i,
      usNbRDN,
      Length;


   /* D�codage des diff�rents composants et calcul de la longueur n�cessaire  */

   pCurrent = pInData;
   pOutBloc->usLen = 0;
   
   usNbRDN = (USHORT) *pCurrent;
   pCurrent++;
   
   for (i = 0; i < usNbRDN; i++)
   {
	  RDN[i].Asn1.pData = NULL;
   }


   for (i = 0; i < usNbRDN; i++)
   {
      rv = CC_Decode_RDN(pCurrent, &(RDN[i].Content), &Length);
      if (rv != RV_SUCCESS) goto err;
      RDN[i].Tag = TAG_SET_OF;
      rv = CC_BuildAsn1(&RDN[i]);
      GMEM_Free(RDN[i].Content.pData);
      if (rv != RV_SUCCESS) goto err;
      pOutBloc->usLen += RDN[i].Asn1.usLen;
      pCurrent += Length;
   }

   *pLength = (unsigned short)(DWORD) (pCurrent - pInData);


   /* Reconstruction du Name d�cod�                                           */
   
   if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }

   pCurrent = pOutBloc->pData;

   for (i = 0; i < usNbRDN; i++)
   {
      memcpy(pCurrent, RDN[i].Asn1.pData, RDN[i].Asn1.usLen);
      GMEM_Free(RDN[i].Asn1.pData);
      pCurrent += RDN[i].Asn1.usLen;
   }

   return(RV_SUCCESS);

err:
   for (i = 0; i < usNbRDN; i++)
   {
	   GMEM_Free(RDN[i].Asn1.pData);
   }

   return rv;
}


/*******************************************************************************
* int CC_Decode_RDN(BYTE    *pInData,
*                   BLOC    *pOutBloc,
*                   USHORT  *pLength
*                  )
*
* Description : D�code une donn�e de type RelativeDistinguishedName.
*               Ceci consiste en le d�codage des diff�rentes parties encod�es
*               successives, leurs enrobages respectifs (tags uniquement
*               par la spec X.509), et la concat�nation de ces r�sultats.
*
* Remarks     : Voir l'encodage
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*               pLength : la longueur de donn�es encod�s utilis�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_RDN(BYTE    *pInData,
                  BLOC    *pOutBloc,
                  USHORT  *pLength
                 )

{
   ASN1
      AVA[MAX_AVA];
   BYTE
      *pCurrent;
   int
      rv;
   USHORT
      i,
      usNbAVA,
      Length;


   /* D�codage des diff�rents composants et calcul de la longueur n�cessaire  */

   pCurrent = pInData;
   pOutBloc->usLen = 0;
   
   usNbAVA = *pCurrent;
   pCurrent++;
   
   for (i = 0; i < usNbAVA; i++)
   {
	  AVA[i].Asn1.pData = NULL;
   }
	  
   for (i = 0; i < usNbAVA; i++)
   {
      rv = CC_Decode_AVA(pCurrent, &(AVA[i].Content), &Length);
      if (rv != RV_SUCCESS) goto err;
      AVA[i].Tag = TAG_SEQUENCE;
      rv = CC_BuildAsn1(&AVA[i]);
      GMEM_Free(AVA[i].Content.pData);
      if (rv != RV_SUCCESS) goto err;
      pOutBloc->usLen += AVA[i].Asn1.usLen;
      pCurrent += Length;
   }

   *pLength = (unsigned short)(DWORD) (pCurrent - pInData);


   /* Reconstruction du Name d�cod�                                           */
   
   if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }

   pCurrent = pOutBloc->pData;

   for (i = 0; i < usNbAVA; i++)
   {
      memcpy(pCurrent, AVA[i].Asn1.pData, AVA[i].Asn1.usLen);
      GMEM_Free(AVA[i].Asn1.pData);
      pCurrent += AVA[i].Asn1.usLen;
   }

   return(RV_SUCCESS);

err:
   for (i = 0; i < usNbAVA; i++)
   {  
      GMEM_Free(AVA[i].Asn1.pData);
   }

   return rv;
}


/*******************************************************************************
* int CC_Decode_AVA(BYTE    *pInData,
*                   BLOC    *pOutBloc,
*                   USHORT  *pLength
*                  )
*
* Description : D�code une donn�e de type AttributeValueAssertion.
*               Ceci consiste en le d�codage des diff�rentes parties encod�es
*               successives, leurs enrobages respectifs (tags uniquement
*               par la spec X.509), et la concat�nation de ces r�sultats.
*
* Remarks     : Voir l'encodage
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*               pLength : la longueur de donn�es encod�s utilis�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_AVA(BYTE    *pInData,
                  BLOC    *pOutBloc,
                  USHORT  *pLength
                 )

{
   ASN1
      AttributeTypePart,
      AttributeValuePart;
   BYTE
      *pCurrent;
   int
      rv;
   USHORT
      AttributeTypeIndex,
      Length;

   AttributeTypePart.Asn1.pData  = NULL;
   AttributeValuePart.Asn1.pData = NULL;
   
   if (pInData[0] == ESCAPE_CHAR)
   {
      pCurrent = &pInData[1];

      rv = CC_RawDecode(pCurrent, &(AttributeTypePart.Content), &Length, TRUE);
      if (rv != RV_SUCCESS) goto err;
      AttributeTypePart.Tag = TAG_OBJECT_IDENTIFIER;
      rv = CC_BuildAsn1(&AttributeTypePart);
      GMEM_Free(AttributeTypePart.Content.pData);
      if (rv != RV_SUCCESS) goto err;
      pCurrent += Length;

      /* Ce que l'on d�code contient d�j� l'enrobage                          */
      rv = CC_RawDecode(pCurrent, &(AttributeValuePart.Asn1), &Length, TRUE);
      if (rv != RV_SUCCESS) goto err;
      pCurrent += Length;

      *pLength = (unsigned short)(DWORD) (pCurrent - pInData);


      pOutBloc->usLen = AttributeTypePart.Asn1.usLen
                      + AttributeValuePart.Asn1.usLen;

      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         rv = RV_MALLOC_FAILED;
		 goto err;
      }

      pCurrent = pOutBloc->pData;

      memcpy(pCurrent, AttributeTypePart.Asn1.pData, AttributeTypePart.Asn1.usLen);
      GMEM_Free(AttributeTypePart.Asn1.pData);
      pCurrent += AttributeTypePart.Asn1.usLen;

      memcpy(pCurrent, AttributeValuePart.Asn1.pData, AttributeValuePart.Asn1.usLen);
      GMEM_Free(AttributeValuePart.Asn1.pData);
      pCurrent += AttributeValuePart.Asn1.usLen;
   }
   else
   {
      AttributeTypeIndex = pInData[0];

      AttributeTypePart.Content.usLen = (USHORT)strlen(AttributeTypeDict[AttributeTypeIndex]);
      if ((AttributeTypePart.Content.pData = GMEM_Alloc(AttributeTypePart.Content.usLen))
           == NULL_PTR)
      {
         rv = RV_MALLOC_FAILED;
		 goto err;
      }
      memcpy(AttributeTypePart.Content.pData,
                AttributeTypeDict[AttributeTypeIndex],
                AttributeTypePart.Content.usLen);

      AttributeTypePart.Tag = TAG_OBJECT_IDENTIFIER;
      rv = CC_BuildAsn1(&AttributeTypePart);
      GMEM_Free(AttributeTypePart.Content.pData);
      if (rv != RV_SUCCESS) goto err;

      rv = CC_RawDecode(&pInData[1], &(AttributeValuePart.Asn1), &Length, TRUE);
      if (rv != RV_SUCCESS) goto err;

      pOutBloc->usLen = AttributeTypePart.Asn1.usLen
                      + AttributeValuePart.Asn1.usLen;

      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         rv = RV_MALLOC_FAILED;
		 goto err;
      }

      pCurrent = pOutBloc->pData;

      memcpy(pCurrent, AttributeTypePart.Asn1.pData, AttributeTypePart.Asn1.usLen);
      GMEM_Free(AttributeTypePart.Asn1.pData);
      pCurrent += AttributeTypePart.Asn1.usLen;

      memcpy(pCurrent, AttributeValuePart.Asn1.pData, AttributeValuePart.Asn1.usLen);
      GMEM_Free(AttributeValuePart.Asn1.pData);
      pCurrent += AttributeValuePart.Asn1.usLen;

      *pLength = 1 + Length;
   }
   
   return(RV_SUCCESS);

err:
   GMEM_Free(AttributeTypePart.Asn1.pData);
   GMEM_Free(AttributeValuePart.Asn1.pData);

   return rv;
}


/*******************************************************************************
* int CC_Decode_Validity(BYTE    *pInData,
*                        BLOC    *pOutBloc,
*                        USHORT  *pLength
*                       )
*
* Description : D�code une donn�e de type Validity.
*               Ceci consiste en le d�codage des diff�rentes parties encod�es
*               successives, leurs enrobages respectifs (tags uniquement
*               par la spec X.509), et la concat�nation de ces r�sultats.
*
* Remarks     : Voir l'encodage
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*               pLength : la longueur de donn�es encod�s utilis�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_Validity(BYTE    *pInData,
                       BLOC    *pOutBloc,
                       USHORT  *pLength
                      )

{
   ASN1
      notBeforePart,
      notAfterPart;
   BYTE
      notBeforeFormat,
      notAfterFormat,
      *pCurrent;
   int
      rv;
   USHORT
      Length;

   notBeforePart.Asn1.pData = NULL;
   notAfterPart.Asn1.pData  = NULL;

   pCurrent = pInData;

   notBeforeFormat = (*pCurrent & 0xF0) >> 4;
   notAfterFormat  = *pCurrent & 0x0F;
   pCurrent++;

   rv = CC_Decode_UTCTime(pCurrent, notBeforeFormat, &(notBeforePart.Content), &Length);
   if (rv != RV_SUCCESS) goto err;
   notBeforePart.Tag = TAG_UTCT;
   rv = CC_BuildAsn1(&notBeforePart);
   GMEM_Free(notBeforePart.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;

   rv = CC_Decode_UTCTime(pCurrent, notAfterFormat, &(notAfterPart.Content), &Length);
   if (rv != RV_SUCCESS) goto err;
   notAfterPart.Tag = TAG_UTCT;
   rv = CC_BuildAsn1(&notAfterPart);
   GMEM_Free(notAfterPart.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;

   *pLength = (unsigned short)(DWORD) (pCurrent - pInData);


   /* Calcul de la longueur de Validity d�cod� et allocation                  */
   
   pOutBloc->usLen = notBeforePart.Asn1.usLen
                   + notAfterPart.Asn1.usLen;

   if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }


   /* Reconstruction de Validity d�cod�                                       */
   
   pCurrent = pOutBloc->pData;

   memcpy(pCurrent, notBeforePart.Asn1.pData, notBeforePart.Asn1.usLen);
   GMEM_Free(notBeforePart.Asn1.pData);
   pCurrent += notBeforePart.Asn1.usLen;

   memcpy(pCurrent, notAfterPart.Asn1.pData, notAfterPart.Asn1.usLen);
   GMEM_Free(notAfterPart.Asn1.pData);
   pCurrent += notAfterPart.Asn1.usLen;

   return(RV_SUCCESS);

err:
   GMEM_Free(notBeforePart.Asn1.pData);
   GMEM_Free(notAfterPart.Asn1.pData);

   return rv;
}


/*******************************************************************************
* int CC_Decode_UTCTime(BYTE     *pInData,
*                       BYTE     Format,    
*                       BLOC     *pOutBloc,
*                       USHORT   *pLength
*                      )
*
* Description : D�code une donn�e de type UTCTime.
*               Ceci consiste en la reconstruction de la chaine initiale suivant
*               le format au quel elle �tait exprim�e.
*
* Remarks     : Voir l'encodage
*
* In          : pInBloc : la partie � d�coder (champ Content)
*               Format : indique au quel format �tait la donn�e d'entr�e
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*               pLength : la longueur de donn�es encod�s utilis�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               RV_INVALID_DATA : Le format sp�cifi� en entr�e est invalide.
*
*******************************************************************************/
int CC_Decode_UTCTime(BYTE    *pInData,
                      BYTE    Format,
                      BLOC    *pOutBloc,
                      USHORT  *pLength
                     ) 

{
   BOOL
      bBissextile = FALSE;
   BYTE
      *pCurrent;
   ULONG
      ulTime,
      ulNbHour,
      ulNbMinute;
   USHORT
      usNbDeltaMinute,
      usNbDay,
      usNbFourYears,
      usNbDayInYear,
      usYear,
      usMonth,
      usDay,
      usHour,
      usMinute,
      usSecond,
      usDeltaHour,
      usDeltaMinute;


   ulTime = *(ULONG UNALIGNED *)pInData; //memcpy( &ulTime, (ULONG *) &pInData[0],4);

   switch(Format)
   {
   case UTCT_YYMMDDhhmmssZ :
   case UTCT_YYMMDDhhmmssphhmm :
   case UTCT_YYMMDDhhmmssmhhmm :

      usSecond   = (USHORT) (ulTime % 60);
      ulNbMinute = ulTime / 60;

      break;

   default :

      ulNbMinute = ulTime;

      break;
   }

   switch(Format)
   {
   case UTCT_YYMMDDhhmmphhmm :
   case UTCT_YYMMDDhhmmmhhmm :
   case UTCT_YYMMDDhhmmssphhmm :
   case UTCT_YYMMDDhhmmssmhhmm :

      *pLength = 6;

      usNbDeltaMinute = *(USHORT UNALIGNED *)&pInData[4]; //memcpy(&usNbDeltaMinute, (USHORT *) &pInData[4], 2);

      ASSERT((usNbDeltaMinute >= 0) && (usNbDeltaMinute < 3600));

      usDeltaMinute = usNbDeltaMinute % 60;
      usDeltaHour   = usNbDeltaMinute / 60;

      break;

   default :

      *pLength = 4;

      break;
   }

   usMinute = (USHORT) (ulNbMinute % 60);
   ulNbHour = ulNbMinute / 60;

   usHour   = (USHORT) (ulNbHour % 24);
   usNbDay  = (USHORT) (ulNbHour / 24);

   usNbFourYears = usNbDay / 1461;
   usNbDay       = usNbDay % 1461;
   usYear = 4 * usNbFourYears;


   if ((usNbDay >= 0) && (usNbDay <= 365))
   {
      bBissextile = TRUE;
      usNbDayInYear = usNbDay;
   }
   if ((usNbDay >= 366) && (usNbDay <= 730))
   {
      usYear += 1;
      usNbDayInYear = usNbDay - 366;
   }
   if ((usNbDay >= 731) && (usNbDay <= 1095))
   {
      usYear += 2;
      usNbDayInYear = usNbDay - 731;
   }
   if ((usNbDay >= 1096) && (usNbDay <= 1460))
   {
      usYear += 3;
      usNbDayInYear = usNbDay - 1096;
   }


   usMonth = 1;
   while (usNbDayInYear >= (((usMonth >= 2) && (bBissextile)) ?
                            NbDaysInMonth[usMonth] + 1 :
                            NbDaysInMonth[usMonth]))
   {
      usMonth++;
   }

   usDay = usNbDayInYear - (((usMonth - 1 >= 2) && (bBissextile)) ?
                            NbDaysInMonth[usMonth - 1] + 1 :
                            NbDaysInMonth[usMonth - 1])
                         + 1;
   
   switch(Format)
   {
   case UTCT_YYMMDDhhmmZ :

      pOutBloc->usLen = 11;

      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         return(RV_MALLOC_FAILED);
      }

      pCurrent = pOutBloc->pData;

      *pCurrent++ = '0' + usYear / 10;
      *pCurrent++ = '0' + usYear % 10;
      *pCurrent++ = '0' + usMonth / 10;
      *pCurrent++ = '0' + usMonth % 10;
      *pCurrent++ = '0' + usDay / 10;
      *pCurrent++ = '0' + usDay % 10;
      *pCurrent++ = '0' + usHour / 10;
      *pCurrent++ = '0' + usHour % 10;
      *pCurrent++ = '0' + usMinute / 10;
      *pCurrent++ = '0' + usMinute % 10;
      *pCurrent = 'Z';

      break;

   case UTCT_YYMMDDhhmmphhmm :

      pOutBloc->usLen = 15;

      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         return(RV_MALLOC_FAILED);
      }

      pCurrent = pOutBloc->pData;

      *pCurrent++ = '0' + usYear / 10;
      *pCurrent++ = '0' + usYear % 10;
      *pCurrent++ = '0' + usMonth / 10;
      *pCurrent++ = '0' + usMonth % 10;
      *pCurrent++ = '0' + usDay / 10;
      *pCurrent++ = '0' + usDay % 10;
      *pCurrent++ = '0' + usHour / 10;
      *pCurrent++ = '0' + usHour % 10;
      *pCurrent++ = '0' + usMinute / 10;
      *pCurrent++ = '0' + usMinute % 10;
      *pCurrent++ = '+';
      *pCurrent++ = '0' + usDeltaHour / 10;
      *pCurrent++ = '0' + usDeltaHour % 10;
      *pCurrent++ = '0' + usDeltaMinute / 10;
      *pCurrent++ = '0' + usDeltaMinute % 10;

      break;

   case UTCT_YYMMDDhhmmmhhmm :

      pOutBloc->usLen = 15;

      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         return(RV_MALLOC_FAILED);
      }

      pCurrent = pOutBloc->pData;

      *pCurrent++ = '0' + usYear / 10;
      *pCurrent++ = '0' + usYear % 10;
      *pCurrent++ = '0' + usMonth / 10;
      *pCurrent++ = '0' + usMonth % 10;
      *pCurrent++ = '0' + usDay / 10;
      *pCurrent++ = '0' + usDay % 10;
      *pCurrent++ = '0' + usHour / 10;
      *pCurrent++ = '0' + usHour % 10;
      *pCurrent++ = '0' + usMinute / 10;
      *pCurrent++ = '0' + usMinute % 10;
      *pCurrent++ = '-';
      *pCurrent++ = '0' + usDeltaHour / 10;
      *pCurrent++ = '0' + usDeltaHour % 10;
      *pCurrent++ = '0' + usDeltaMinute / 10;
      *pCurrent++ = '0' + usDeltaMinute % 10;

      break;

   case UTCT_YYMMDDhhmmssZ :

      pOutBloc->usLen = 13;

      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         return(RV_MALLOC_FAILED);
      }

      pCurrent = pOutBloc->pData;

      *pCurrent++ = '0' + usYear / 10;
      *pCurrent++ = '0' + usYear % 10;
      *pCurrent++ = '0' + usMonth / 10;
      *pCurrent++ = '0' + usMonth % 10;
      *pCurrent++ = '0' + usDay / 10;
      *pCurrent++ = '0' + usDay % 10;
      *pCurrent++ = '0' + usHour / 10;
      *pCurrent++ = '0' + usHour % 10;
      *pCurrent++ = '0' + usMinute / 10;
      *pCurrent++ = '0' + usMinute % 10;
      *pCurrent++ = '0' + usSecond / 10;
      *pCurrent++ = '0' + usSecond % 10;
      *pCurrent++ = 'Z';

      break;

   case UTCT_YYMMDDhhmmssphhmm :

      pOutBloc->usLen = 17;

      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         return(RV_MALLOC_FAILED);
      }

      pCurrent = pOutBloc->pData;

      *pCurrent++ = '0' + usYear / 10;
      *pCurrent++ = '0' + usYear % 10;
      *pCurrent++ = '0' + usMonth / 10;
      *pCurrent++ = '0' + usMonth % 10;
      *pCurrent++ = '0' + usDay / 10;
      *pCurrent++ = '0' + usDay % 10;
      *pCurrent++ = '0' + usHour / 10;
      *pCurrent++ = '0' + usHour % 10;
      *pCurrent++ = '0' + usMinute / 10;
      *pCurrent++ = '0' + usMinute % 10;
      *pCurrent++ = '0' + usSecond / 10;
      *pCurrent++ = '0' + usSecond % 10;
      *pCurrent++ = '+';
      *pCurrent++ = '0' + usDeltaHour / 10;
      *pCurrent++ = '0' + usDeltaHour % 10;
      *pCurrent++ = '0' + usDeltaMinute / 10;
      *pCurrent++ = '0' + usDeltaMinute % 10;

      break;

   case UTCT_YYMMDDhhmmssmhhmm :

      pOutBloc->usLen = 17;

      if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
      {
         return(RV_MALLOC_FAILED);
      }

      pCurrent = pOutBloc->pData;

      *pCurrent++ = '0' + usYear / 10;
      *pCurrent++ = '0' + usYear % 10;
      *pCurrent++ = '0' + usMonth / 10;
      *pCurrent++ = '0' + usMonth % 10;
      *pCurrent++ = '0' + usDay / 10;
      *pCurrent++ = '0' + usDay % 10;
      *pCurrent++ = '0' + usHour / 10;
      *pCurrent++ = '0' + usHour % 10;
      *pCurrent++ = '0' + usMinute / 10;
      *pCurrent++ = '0' + usMinute % 10;
      *pCurrent++ = '0' + usSecond / 10;
      *pCurrent++ = '0' + usSecond % 10;
      *pCurrent++ = '-';
      *pCurrent++ = '0' + usDeltaHour / 10;
      *pCurrent++ = '0' + usDeltaHour % 10;
      *pCurrent++ = '0' + usDeltaMinute / 10;
      *pCurrent++ = '0' + usDeltaMinute % 10;

      break;

   default :

      return(RV_INVALID_DATA);

      break;
   }


   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Decode_SubjectPKInfo(BYTE    *pInData,
*                             BLOC    *pOutBloc,
*                             USHORT  *pLength
*                            )
*
* Description : D�code une donn�e de type SubjectPublicKeyInfo.
*               Ceci consiste en le d�codage des diff�rentes parties encod�es
*               successives, leurs enrobages respectifs (tags uniquement
*               par la spec X.509), et la concat�nation de ces r�sultats.
*
* Remarks     : Voir l'encodage
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*               pLength : la longueur de donn�es encod�s utilis�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_SubjectPKInfo(BYTE    *pInData,
                            BLOC    *pOutBloc,
                            USHORT  *pLength
                           )

{
   ASN1
      algorithmPart,
      subjectPKPart;
//   BLOC
//      CompData;
   BYTE
      *pCurrent;
   int
      rv;
   USHORT
      Length;

   algorithmPart.Asn1.pData = NULL;
   subjectPKPart.Asn1.pData = NULL;

   pCurrent = pInData;
   
   rv = CC_Decode_AlgorithmIdentifier(pCurrent, &(algorithmPart.Content), &Length);
   if (rv != RV_SUCCESS) goto err;
   algorithmPart.Tag = TAG_SEQUENCE;
   rv = CC_BuildAsn1(&algorithmPart);
   GMEM_Free(algorithmPart.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;

#ifdef _TRICKY_COMPRESSION
	/* Ne pas faire le RawDecode a permis de gagner l'octet 0xFF */
#ifdef _OPT_HEADER
	if (pCurrent[0] < 0x80)
	{
		CompData.usLen = pCurrent[0];
		CompData.pData = &(pCurrent[1]);
		Length = CompData.usLen + 1;
	}
	else
	{
		CompData.usLen = ((pCurrent[0] & 0x7F) << 8) + pCurrent[1];
		CompData.pData = &(pCurrent[2]);
		Length = CompData.usLen + 2;
	}
#else	/* _OPT_HEADER */
	CompData.usLen = (pCurrent[0] << 8) + pCurrent[1];
	CompData.pData = &(pCurrent[2]);
	Length = CompData.usLen + 2;
#endif
	subjectPKPart.Content.usLen = CompData.usLen;
	if ((subjectPKPart.Content.pData = 
		  GMEM_Alloc(subjectPKPart.Content.usLen)) == NULL_PTR)
	{
		rv = RV_MALLOC_FAILED;
		goto err;
	}
	memcpy(subjectPKPart.Content.pData,
			 CompData.pData,
			 subjectPKPart.Content.usLen
			);

   subjectPKPart.Tag = TAG_BIT_STRING;
   rv = CC_BuildAsn1(&subjectPKPart);
   GMEM_Free(subjectPKPart.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;
#else	/* _TRICKY_COMPRESSION */
	rv = CC_RawDecode(pCurrent, &(subjectPKPart.Content), &Length, FALSE);
   if (rv != RV_SUCCESS) goto err;
   subjectPKPart.Tag = TAG_BIT_STRING;
   rv = CC_BuildAsn1(&subjectPKPart);
   GMEM_Free(subjectPKPart.Content.pData);
   if (rv != RV_SUCCESS) goto err;
   pCurrent += Length;
#endif

   *pLength = (unsigned short)(DWORD) (pCurrent - pInData);

   /* Calcul de la longueur du d�cod� et allocation                           */
   
   pOutBloc->usLen = algorithmPart.Asn1.usLen
                   + subjectPKPart.Asn1.usLen;

   if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }


   /* Reconstruction                                                          */
   
   pCurrent = pOutBloc->pData;

   memcpy(pCurrent, algorithmPart.Asn1.pData, algorithmPart.Asn1.usLen);
   GMEM_Free(algorithmPart.Asn1.pData);
   pCurrent += algorithmPart.Asn1.usLen;

   memcpy(pCurrent, subjectPKPart.Asn1.pData, subjectPKPart.Asn1.usLen);
   GMEM_Free(subjectPKPart.Asn1.pData);
   pCurrent += subjectPKPart.Asn1.usLen;

   return(RV_SUCCESS);

err:
   GMEM_Free(algorithmPart.Asn1.pData);
   GMEM_Free(subjectPKPart.Asn1.pData);

   return rv;
}


/*******************************************************************************
* int CC_Decode_UniqueIdentifier(BYTE    *pInData,
*                                BLOC    *pOutBloc,
*                                USHORT  *pLength
*                               )
*
* Description : D�code une donn�e de type UniqueIdentifier.
*               Ceci consiste seulement en le d�codage brute (CC_RawDecode) de
*               la donn�e d'entr�e.
*
* Remarks     : 
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_UniqueIdentifier(BYTE    *pInData,
                               BLOC    *pOutBloc,
                               USHORT  *pLength
                              )

{
   int
      rv;


   rv = CC_RawDecode(pInData, pOutBloc, pLength, TRUE);
   if (rv != RV_SUCCESS) return rv;

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Decode_Extensions(BYTE    *pInData,
*                          BLOC    *pOutBloc,
*                          USHORT  *pLength
*                         )
*
* Description : D�code une donn�e de type Extensions.
*               Ceci consiste en le d�codage des diff�rentes parties encod�es
*               successives, leurs enrobages respectifs (tags uniquement
*               par la spec X.509), et la concat�nation de ces r�sultats.
*
* Remarks     : Voir l'encodage
*               L'ajout d'un enrobage 'context sp�cifique' est requis
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*               pLength : la longueur de donn�es encod�s utilis�e
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_Extensions(BYTE    *pInData,
                         BLOC    *pOutBloc,
                         USHORT  *pLength
                        )

{
   ASN1
      ExtensionPart[MAX_AVA],
      InOutAsn1;
   BYTE
      *pCurrent;
   int
      rv;
   USHORT
      i,
      usNbExtension,
      Length;


   /* D�codage des diff�rents composants et calcul de la longueur n�cessaire  */

   pCurrent = pInData;
   InOutAsn1.Content.usLen = 0;
   
   usNbExtension = *pCurrent;
   pCurrent++;

   for (i = 0; i < usNbExtension; i++)
   {
	  ExtensionPart[i].Asn1.pData = NULL;
   }

   for (i = 0; i < usNbExtension; i++)
   {
      rv = CC_Decode_Extension(pCurrent, &(ExtensionPart[i].Content), &Length);
      if (rv != RV_SUCCESS) goto err;
      ExtensionPart[i].Tag = TAG_SEQUENCE;
      rv = CC_BuildAsn1(&ExtensionPart[i]);
      GMEM_Free(ExtensionPart[i].Content.pData);
      if (rv != RV_SUCCESS) goto err;
      InOutAsn1.Content.usLen += ExtensionPart[i].Asn1.usLen;
      pCurrent += Length;
   }

   *pLength = (unsigned short)(DWORD) (pCurrent - pInData);


   /* Reconstruction de la partie int�rieure au 'context specific'            */
   
   if ((InOutAsn1.Content.pData = GMEM_Alloc(InOutAsn1.Content.usLen)) == NULL_PTR)
   {
      rv = RV_MALLOC_FAILED;
	  goto err;
   }

   pCurrent = InOutAsn1.Content.pData;

   for (i = 0; i < usNbExtension; i++)
   {
      memcpy(pCurrent, ExtensionPart[i].Asn1.pData, ExtensionPart[i].Asn1.usLen);
      GMEM_Free(ExtensionPart[i].Asn1.pData);
      pCurrent += ExtensionPart[i].Asn1.usLen;
   }

   /* Ajout de l'enrobage 'context specific'                                  */

   InOutAsn1.Tag = TAG_SEQUENCE;
   rv = CC_BuildAsn1(&InOutAsn1);
   GMEM_Free(InOutAsn1.Content.pData);
   if (rv != RV_SUCCESS) return rv;

   *pOutBloc = InOutAsn1.Asn1;
   
   return(RV_SUCCESS);

err:
   for (i = 0; i < usNbExtension; i++)
   {
      GMEM_Free(ExtensionPart[i].Asn1.pData);
   }

   return rv;
}


/*******************************************************************************
* int CC_Decode_Extension(BYTE    *pInData,
*                         BLOC    *pOutBloc,
*                         USHORT  *pLength
*                        )
*
* Description : D�code une donn�e de type Extension.
*               Ceci consiste seulement en le d�codage brute (CC_RawDecode) de
*               la donn�e d'entr�e.
*
* Remarks     : 
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_Extension(BYTE    *pInData,
                        BLOC    *pOutBloc,
                        USHORT  *pLength
                       )

{
   int
      rv;


   rv = CC_RawDecode(pInData, pOutBloc, pLength, TRUE);
   if (rv != RV_SUCCESS) return rv;

   return(RV_SUCCESS);
}


/*******************************************************************************
* int CC_Decode_Signature(BYTE    *pInData,
*                         BLOC    *pOutBloc,
*                         USHORT  *pLength
*                        )
*
* Description : D�code la signature du certificat.
*               Ceci consiste seulement en le d�codage brute (CC_RawDecode) de
*               la donn�e d'entr�e.
*
* Remarks     : Voir l'encodage
*
* In          : pInBloc : la partie � d�coder (champ Content)
*
* Out         : pOutBloc : le d�cod� (m�moire allou�e ici � lib�rer par la
*                          fonction appelante)
*
* Responses   : RV_SUCCESS : All is OK.
*               RV_MALLOC_FAILED : Un malloc a �chou�.
*               Autre : D'autres codes d'erreur peuvent �tre retourn�s par des
*                       fonctions d'un niveau inf�rieur.
*
*******************************************************************************/
int CC_Decode_Signature(BYTE    *pInData,
                        BLOC    *pOutBloc,
                        USHORT  *pLength
                       )

{
//	BLOC
//		CompData;
   int
      rv;


#ifdef _TRICKY_COMPRESSION
	/* Ne pas faire le RawDecode a permis de gagner l'octet 0xFF */
#ifdef _OPT_HEADER
	if (pInData[0] < 0x80)
	{
		CompData.usLen = pInData[0];
		CompData.pData = &(pInData[1]);
		*pLength = CompData.usLen + 1;
	}
	else
	{
		CompData.usLen = ((pInData[0] & 0x7F) << 8) + pInData[1];
		CompData.pData = &(pInData[2]);
		*pLength = CompData.usLen + 2;
	}
#else	/* _OPT_HEADER */
	CompData.usLen = (pInData[0] << 8) + pInData[1];
	CompData.pData = &(pInData[2]);
	*pLength = CompData.usLen + 2;
#endif
	pOutBloc->usLen = CompData.usLen;
	if ((pOutBloc->pData = GMEM_Alloc(pOutBloc->usLen)) == NULL_PTR)
	{
		return(RV_MALLOC_FAILED);
	}
	memcpy(pOutBloc->pData, CompData.pData, pOutBloc->usLen);
#else	/* _TRICKY_COMPRESSION */
   rv = CC_RawDecode(pInData, pOutBloc, pLength, TRUE);
   if (rv != RV_SUCCESS) return rv;
#endif

   return(RV_SUCCESS);
}