Base64-kodningsbibliotek med Arduino
Base64 är ett kodsystem som använder 64 symboler grupperade i meddelanden som har en längdmultipel av fyra. Dessa meddelanden (datapaket) kompletteras vid behov med ett plussymbol (så 65 används), ofta likhetstecknet (=), om den användbara informationen som kodas resulterar i en kortare längd.
Med hjälp av 64 tecken kan du arbeta med de 10 siffrorna och stora och små bokstäverna (26+26) i koden ASCII, problemet är att det finns 62, låt oss säga, entydiga symboler plus två som varierar i olika implementeringar. Även om det ibland hänvisas till med uttrycket "karaktärer ASCII utskrivbara", i verkligheten är de de som sträcker sig från den som representeras av koden 32 (mellanslag) till 126 (~) de 95 som verkligen kan skrivas ut.
Implementeringen av kodning Base64 mest använda, det av PEM, som också används av MIMA, arbeta med de extra "+" och "/"-tecknen och "="-tecknet till pad så att paketen har en längdmultipel av fyra. Bokstäverna A-Z upptar positionerna 0-25, bokstäverna a-z upptar positionerna 26-51, siffrorna 0-9 upptar positionerna 52-61, plustecknet (+) positionerna 62 och position 63 upptas av snedstrecket (/ ).
Sättet att representera data i format Base64 består av att ta, från originaldata, grupper av 6 bitar som representeras med motsvarande kod. Om det finns bitar över fylls de med nollor till höger. Om det resulterande antalet koder inte är en multipel av fyra, fylls det i med likhetstecken till höger.
Följande bild visar kodningen ASCII av en text ("ohm") och det sätt på vilket den konverteras till Base64. Eftersom det finns 7 symboler, skulle det slutliga meddelandet behöva fyllas med ett likhetstecken i slutet. Man kan säga att texten "ohm" in ASCII motsvarar «b2htaW8=" in Base64.
Specifik användning av kodning Base64 De anger vanligtvis också en maximal linjelängd. Genomförandet MIMA Begränsar varje rad till 76 tecken. Normalt kommer raderna att separeras av en radslutkod (CR, representerad av värdet 0x0D i ASCII) och ytterligare en ny rad (NL, som motsvarar koden ASCII 0x0A).
Det besvär som tillkommer vid implementering av kodning Base64 på en enhet med få resurser, som ofta är fallet med en mikrokontroller är att du måste koda allt eftersom informationen kommer eller med en buffert minimum, vilket också kräver tillhandahållande av ett system som indikerar att slutet av det ursprungliga meddelandet har nåtts, till exempel genom att lägga till en speciell kod, eller genom att använda en pin vars nivå (synkroniserad med mottagning) indikerar meddelandets status.
Exempelkoden nedan är en bibliotek för Arduino att koda i Base64 som implementeras med båda kriterierna: kodning av informationen som kommer (utan en buffert) och vänta på att en varningssignal ska avslutas.
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
|
//base64.h
#include <string.h> // memcpy/strncpy
#define LONGITUD_LINEA 76
#define MASCARA_B64 0B00111111
#define ULTIMO_CODIGO_BASE64 64 // 64 caracteres más el signo igual (empezando a contar desde cero)
#define MAXIMA_LONGITUD_RESULTADO 6 // Máximo número de caracteres del resultado parcial de la codificación. Puede ser 1 si no se ha llegado al final de un bloque (2 bytes en el original, 4 en la conversión), 2 si se ha llegado al final de un bloque, 3 si no se ha llegado al final de un bloque pero se supera la longitud máxima de la línea, 4 si se llega al final de un bloque y se supera la longitud máxima de la línea, 5 si hay que rellenar con un signo igual o 6 si hay que rellenar con dos signos igual
class Base64
{
private:
unsigned char simbolo_base64[ULTIMO_CODIGO_BASE64+1]; // Espacio para la codificación Base64, el relleno (=) una terminación en \0
unsigned int numero_valor; // Posición (empezando en cero) que ocupa el valor que se desea convertir en el mensaje completo original
unsigned int numero_codigo; // Posición del último código calculado. Podría limitarse al ancho de la línea (LONGITUD_LINEA, 76 caracteres) pero usando un contenedor alto se podría implementar también una cuenta estadística
unsigned char resto_base64; // Último resto obtenido al calcular el último código
unsigned char resultado[MAXIMA_LONGITUD_RESULTADO+1]; // Resultado de la conversión actual. Si es terminal puede incluir el caracter 65 (=) una o dos veces
unsigned char contador_caracteres_resultado=0;
void acumular_resultado(unsigned char valor);
public:
Base64();
~Base64();
void iniciar_conversion();
unsigned char *convertir(unsigned char valor_original, bool terminar_conversion);
unsigned char *convertir(unsigned char valor_original);
unsigned char *terminar();
};
|
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
|
//base64.cpp
#include “base64.h”
Base64::Base64() // Constructor
{
memcpy(simbolo_base64,“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=”,ULTIMO_CODIGO_BASE64+1);
iniciar_conversion();
}
Base64::~Base64() // Destructor
{
}
void Base64::iniciar_conversion()
{
numero_valor=0;
numero_codigo=0;
resto_base64=0;
}
unsigned char *Base64::convertir(unsigned char valor_original, bool terminar_conversion) // Valor que se desea convertir a Base64
{
convertir(valor_original);
if(terminar_conversion)
{
terminar();
}
return resultado;
}
unsigned char *Base64::convertir(unsigned char valor_original) // Valor que se desea convertir a Base64
{
unsigned char desplazamiento;
contador_caracteres_resultado=0;
acumular_resultado((valor_original>>(2+(numero_valor%3)*2))|resto_base64);
desplazamiento=4–(numero_valor%3)*2;
resto_base64=(valor_original&(MASCARA_B64>>desplazamiento))<<desplazamiento;
if(((numero_codigo+1)%4==0))
{
acumular_resultado(resto_base64);
resto_base64=0;
}
numero_valor++;
resultado[contador_caracteres_resultado]=0;
return resultado;
}
unsigned char *Base64::terminar()
{
if(numero_codigo%4)
{
acumular_resultado(resto_base64);
while(numero_codigo%4)
{
acumular_resultado(ULTIMO_CODIGO_BASE64);
}
}
resultado[contador_caracteres_resultado]=0;
iniciar_conversion();
return resultado;
}
void Base64::acumular_resultado(unsigned char valor)
{
numero_codigo++;
resultado[contador_caracteres_resultado++]=simbolo_base64[valor];
if((numero_codigo%LONGITUD_LINEA)==0)
{
resultado[contador_caracteres_resultado++]=13; // CR “\r”
resultado[contador_caracteres_resultado++]=10; // LF “\n”
}
}
|
Den grundläggande delen av kodberäkningen Base64 Det görs med uttrycket:
(valor_original>>(2+(numero_valor%3)*2))|resto_base64
och beräkningen av resten med uttrycket:
(valor_original&(MASCARA_B64>>desplazamiento))<<desplazamiento
,
vara desplazamiento
ett värde som beräknas med uttrycket:
4-(numero_valor%3)*2
Processen som följs för att erhålla dessa uttryck består av att generalisera beräkningen av var och en av de fyra koderna Base64 som är resultatet av att representera tre byte av det ursprungliga värdet.
Base64=((byte_1>>2)|resto)&0b00111111 |
resto=(byte_1&0b00000011)<<4 |
Base64=((byte_2>>4)|resto)&0b00111111 |
resto=(byte_2&0b00001111)<<2 |
Base64=((byte_3>>6)|resto)&0b00111111 |
resto=(byte_3&0b00111111)<<0 |
Base64=((byte_3>>0)|resto)&0b00111111 |
resto=(byte_3&0b00111111)<<0 |
Med texten Base64
Pseudokoden ovan hänvisar till koden i Base64 som beräknas. Uttrycket har använts byte_n
för att hänvisa till den n:e byten som kodas. Texten resto
representerar de överblivna bitarna av byten som kodas. I början av beräkningen antas det att resten är noll
För tydlighetens skull har 6-bitarsmasken i den föregående pseudokoden inkluderats i beräkningen av alla koder, även om det bara är nödvändigt att bestämma den sista av dem, eftersom de andra roteras så att de två flesta bitarna alltid går förlorade. signifikant.
Som kan ses är den fjärde koden all rest och det finns inget behov av att beräkna en rest efteråt; Det är därför bara nödvändigt att utföra tre steg, ett per kodad byte. Det är viktigt att komma ihåg att om en tredje byte i ett paket inte var kodad, skulle den sista koden behöva fyllas med nollor till höger. Base64 erhålles.
För att generalisera, rätt rotation av uttrycket som beräknar koden i Base64 kan representeras som 2+(numero_byte%3)*2
så att delen innanför parentesen skulle rotera från noll till två, vilket resulterar i 2, 4 och 6 vid varje steg. Det är såklart inte det enda sättet att generalisera, men jag har valt den här för funktionalitet och framför allt för tydlighetens skull. Eftersom masken (AND) bara var nödvändig i den fjärde koden och det redan har setts att det inte är nödvändigt att beräkna den (det är resten), ingår den inte i det slutliga uttrycket för att förenkla det, även om vi måste komma ihåg att den typ av data som används (byte) endast de 6 minst signifikanta bitarna tas.
Restens vänsterrotation kan generaliseras på ett sätt analogt med det föregående. Det kan också ses att masken som appliceras (AND) genomgår samma bitrotation men i motsatt riktning. Det är anledningen till att beräkna förskjutningen med 4-(numero_valor%3)*2
innan den tillämpas i den mening som motsvarar varje del av uttrycket.
Följande exempel visar hur du använder biblioteket för att koda en textsträng (kom ihåg att Base64 kan användas för vilken datauppsättning som helst, till exempel en bild). I följande kod finns ett par detaljer som är intressanta att förtydliga. Först har en speciell symbol (symbolen ~) använts för att indikera slutet på texten, istället för en hårdvarusignal eller för att indikera textens längd. Logiskt sett kan den symbolen inte vara en del av den data som kodas.
Den andra frågan som måste beaktas, lika viktig som den är uppenbar, är att avkodaren på destinationen måste veta hur informationen som når den representeras. Texten innehåller tecken som inte hör till uppsättningen ASCII utskrivbara (från 32 till 126), bokstäver med accent, till exempel. Arduino kommer att använda två byte (UTF-8) för att representera dessa tecken. Den vanliga kan inte helt enkelt användas \0
som en textterminator eftersom, i många fall, den första byten som ett tecken representeras med kommer att vara exakt noll.
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
|
#include “base64.h”
char texto_prueba[]=“La bella y graciosa moza marchose a lavar la ropa.\nLa mojó en el arroyuelo y cantando la lavó.\nLa frotó sobre una piedra, la colgó de un abedul.\nDespués de lavar la ropa, la niña se fue al mercado.\nUn pastor vendía ovejas pregonando a viva voz:\nved qué oveja, ved qué lana, ved qué bestia, qué animal.\nLa niña la vio muy flaca, sin embargo le gustó.\nYo te pago veinte escudos y no discutamos más.\nVuelve la niña cantando muy contenta con su oveja.\nCuando llegaron al bosque la ovejita se escapó.\nLa niña desesperada arrojose encima de ella.\nVelozmente y con destreza aferrola por detrás.\nLlegaba por el camino jinete de altivo porte.\nDescendió de su caballo y a la niña le cantó…~”;
char *resultado;
Base64 base64;
void setup()
{
Serial.begin(9600);
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) // ¿Es un Arduino Leonardo (ATmega32U4)?
while(!Serial){}; // Esperar a Arduino Leonardo
#endif
// Mostrar el texto original
unsigned int contador=0;
while(texto_prueba[contador]!=‘~’)
{
//Serial.println(String(texto_prueba[contador])+”=”+String(texto_prueba[contador],DEC));
Serial.print(String(texto_prueba[contador]));
contador++;
}
Serial.println(“\n”);
// Mostrar el texto codificado en Base64
contador=0;
while(texto_prueba[contador]!=‘~’)
{
resultado=base64.convertir(texto_prueba[contador],texto_prueba[contador+1]==‘~’);
byte contador_resultado=0;
while(resultado[contador_resultado]>0)
{
Serial.print(String(resultado[contador_resultado]));
contador_resultado++;
}
contador++;
}
}
void loop()
{
}
|
Rad 26 i föregående exempel visar användningen av bibliotek för Arduino att koda i Base64. Det är bara nödvändigt att ange metoden convertir
varje byte du vill koda och valfritt om det är den sista eller, om inte, stoppa konverteringen med metoden terminar
när du når slutet.
Som kan ses i skärmdumpen nedan, exempelprogrammet för bibliotek för Arduino att koda i Base64 visar först texten som ska kodas in Base64, i det här fallet, början på jättarnas berömda sång Les Luthiers, och därefter resultatet av inkodning Base64 använder formatradslängd MIMA.
Post kommentar