1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
| #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define ASCII_SIZE 128
/* Valeur sentinelle pour les valeurs 6 bits */
#define BASE64_SENTINELLE ((char)-1)
/* ---------------------------------------------------------------------------
Initialise le tableau de decodage avec les caracteres base64 donnes */
void base64_init(
unsigned char decode[ASCII_SIZE], /*[out] Tableau qui servira au décodage */
char const *encode /*[in] Chaîne de 64 caractères */
)
{
size_t i;
memset(decode, '\0', ASCII_SIZE);
for(i=0 ; encode[i]!='\0' ; i++)
{
int c = (unsigned char)(encode[i]);
assert(c < ASCII_SIZE);
decode[c] = (unsigned char)i;
}
assert(i==64);
}
/* ---------------------------------------------------------------------------
Remplace les caractères par leur valeur sur 6 bits
En cas d'erreur, la fonction retourne une valeur inférieure à zéro,
*pTaille est inchangé,
et la chaîne est inutilisable. */
static int base64_charToValues(
char *str, /*[in/modif] Chaîne base64 en entrée, valeurs 6 bits en sortie */
size_t *pTaille, /*[out/opt] Taille effective des données à décoder */
unsigned char const decode[ASCII_SIZE] /*[in] valeurs pour le décodage */
)
{
size_t i;
for(i=0 ; str[i]!='\0' ; i++)
{
int c = (unsigned char)(str[i]);
/*rejeter les caractères non-ASCII*/
if(c >= ASCII_SIZE)
return -1;
/*traitement spécial pour les = de fin de chaîne */
if(c == '=')
break;
/*rejeter les caractères non-base64*/
if(decode[c]=='\0')
return -1;
/*remplacer le caractère par sa valeur*/
str[i] = decode[c];
}
str[i] = BASE64_SENTINELLE;
if(pTaille!=NULL)
*pTaille = i;
return 0;
}
/*----------------------------------------------------------------------------
Fonction de conversion nb caractères lus -> nb octets lus */
static size_t base64_4to3(size_t nValeurs6bitsLues)
{
switch(nValeurs6bitsLues)
{
case 0:
return 0;
case 1:
default:
assert(0);
return 0;
case 2:
return 1;
case 3:
return 2;
case 4:
return 3;
}
}
/*----------------------------------------------------------------------------
Fonction de décodage des valeurs 6 bits */
static void * base64_decodeValuesN(
char const *valeurs, /*[in] Valeurs 6 bits */
size_t taille, /*[in] Taille de la zone à décoder */
size_t *pTailleDecodee /*[out/opt] Taille de la zone une fois décodée */
)
{
size_t const twoLowerBits = 3;
/*Taille arrondie aux 4 supérieurs */
size_t const taille2 = ( ((taille & twoLowerBits)!=0)
? ((taille & ~twoLowerBits) + 4)
: taille
);
/*Taille des données décodées, arrondie au 3 supérieurs */
size_t const tailleDecodee = (taille2/4) * 3;
/* Alloue toujours 1 de plus pour ajouter un caractère nul */
unsigned char * pDecode = malloc(sizeof *pDecode * (tailleDecodee+1));
if(pDecode!=NULL)
{
size_t iValeur = 0;
size_t iDecode = 0;
size_t nOctetsLus = 0;
do
{
long troisOctets = 0;
size_t oldIValeur = iValeur;
size_t iOctet;
nOctetsLus = 0;
if(iValeur < taille && valeurs[iValeur]!=BASE64_SENTINELLE)
troisOctets |= valeurs[iValeur++] << 18;
if(iValeur < taille && valeurs[iValeur]!=BASE64_SENTINELLE)
troisOctets |= valeurs[iValeur++] << 12;
if(iValeur < taille && valeurs[iValeur]!=BASE64_SENTINELLE)
troisOctets |= valeurs[iValeur++] << 6;
if(iValeur < taille && valeurs[iValeur]!=BASE64_SENTINELLE)
troisOctets |= valeurs[iValeur++] << 0;
nOctetsLus = base64_4to3(iValeur - oldIValeur);
for(iOctet=0 ; iOctet<nOctetsLus ; iOctet++)
{
int valDecode = ( troisOctets >> ((2-iOctet)*8) ) & 0x000000FF;
pDecode[iDecode++] = (unsigned char)valDecode;
}
assert(iDecode <= tailleDecodee);
} while(nOctetsLus == 3);
assert(iDecode > tailleDecodee-3 && iDecode <= tailleDecodee);
/* Ajoute un caractère nul (non-compté dans la taille retournée) */
pDecode[iDecode] = '\0';
if(pTailleDecodee!=NULL)
*pTailleDecodee = iDecode;
}
return pDecode;
}
/*----------------------------------------------------------------------------
Fonction de décodage de chaîne base64.
Retourne un pointeur vers les données décodées,
suivies d'un octet nul en prime (non compté dans la taille).
Attention, la fonction modifie la chaîne et la rend inutilisable.
En cas d'échec, retourne NULL et *pTailleDecodee est inchangé. */
void * base64_decode(
char *str, /*[in/modif] Chaîne base64 en entrée, valeurs 6 bits en sortie. */
size_t *pTailleDecodee, /*[out/opt] Taille de la zone une fois décodée */
unsigned char const decode[ASCII_SIZE] /*[in] valeurs pour le décodage */
)
{
size_t tailleEncodee = 0;
if(base64_charToValues(str, &tailleEncodee, decode)<0)
return NULL;
return base64_decodeValuesN(str, tailleEncodee, pTailleDecodee);
}
/*
==============================================================================
Fonction de test*/
void TestBase64(void)
{
unsigned char decode[ASCII_SIZE];
char const * MIME = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
printf("\n--- Test : %s ---\n", __FUNCTION__);
base64_init(decode, MIME);
{
/* Les chaînes viennent de Wikipédia */
char str1[] = "bGVhc3VyZS4=";
char str2[] = "ZWFzdXJlLg==";
char str3[] = "YXN1cmUu";
char str4[] = "c3VyZS4=";
char * decode1 = base64_decode(str1, NULL, decode);
char * decode2 = base64_decode(str2, NULL, decode);
char * decode3 = base64_decode(str3, NULL, decode);
char * decode4 = base64_decode(str4, NULL, decode);
if(decode1==NULL || strcmp(decode1, "leasure.")!=0)
puts("Echec test base64 1.");
else
printf("Succes test base64 1 \"%s\".\n", decode1);
if(decode2==NULL || strcmp(decode2, "easure.")!=0)
puts("Echec test base64 2.");
else
printf("Succes test base64 2 \"%s\".\n", decode2);
if(decode3==NULL || strcmp(decode3, "asure.")!=0)
puts("Echec test base64 3.");
else
printf("Succes test base64 3 \"%s\".\n", decode3);
if(decode4==NULL || strcmp(decode4, "sure.")!=0)
puts("Echec test base64 4.");
else
printf("Succes test base64 4 \"%s\".\n", decode4);
free(decode1);
free(decode2);
free(decode3);
free(decode4);
}
} |