Base64-kodingsbibliotek med Arduino
Base 64 er et kodesystem som bruker 64 symboler gruppert i meldinger som har en lengde på fire. Disse meldingene (datapakkene) kompletteres, om nødvendig, med et plusssymbol (så 65 brukes), ofte likhetstegnet (=), hvis den nyttige informasjonen som er kodet resulterer i en kortere lengde.
Ved å bruke 64 tegn kan du jobbe med de 10 tallene og store og små bokstaver (26+26) i koden ASCII, problemet er at det er 62, la oss si, entydige symboler pluss to som varierer i forskjellige implementeringer. Selv om noen ganger referert til med uttrykket "karakterer ASCII utskrivbare", i virkeligheten er de de som spenner fra den som er representert av koden 32 (mellomrom) til 126 (~) de 95 som virkelig kan skrives ut.
Implementering av koding Base 64 mest brukte, det av PEM, som også brukes av MIME, arbeid med de ekstra "+" og "/"-tegnet og "="-tegnet til puten slik at pakkene har et lengdemultiplum på fire. Bokstavene A-Z opptar posisjonene 0-25, bokstavene a-z opptar posisjonene 26-51, tallene 0-9 opptar posisjonene 52-61, plusstegnet (+) posisjoner 62, og posisjon 63 er okkupert av skråstreken (/ ).
Måten å representere data i format Base 64 består i å ta, fra de opprinnelige dataene, grupper av 6 biter som er representert med tilsvarende kode. Hvis det er biter til overs, fylles de med nuller til høyre. Hvis det resulterende antallet koder ikke er et multiplum av fire, fylles det ut med likhetstegn til høyre.
Følgende bilde viser kodingen ASCII av en tekst ("ohm") og måten den konverteres til Base 64. Siden det er 7 symboler, må den endelige meldingen fylles med et likhetstegn på slutten. Det kan sies at teksten "ohm" i ASCII tilsvarende «b2htaW8=" in Base 64.
Spesifikk bruk av koding Base 64 De pålegger vanligvis også en maksimal linjelengde. Implementeringen MIME Begrenser hver linje til 76 tegn. Normalt vil linjene være atskilt med en ende-på-linje-kode (CR, representert ved verdien 0x0D i ASCII) og en ny linje (NL, som tilsvarer koden ASCII 0x0A).
Uleiligheten som legges til ved implementering av koding Base 64 på en enhet med få ressurser, som ofte er tilfellet med en mikrokontroller er at du må kode etter hvert som informasjonen kommer eller med en buffer minimum, som også krever et system som indikerer at slutten av den opprinnelige meldingen er nådd, for eksempel ved å legge til en spesiell kode, eller ved å bruke en pinne hvis nivå (synkronisert med mottak) indikerer statusen til meldingen.
Eksempelkoden nedenfor er en bibliotek for Arduino å kode i Base64 som er implementert med begge kriteriene: koding av informasjonen som kommer (uten en buffer) og vent til et varselsignal er ferdig.
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 grunnleggende delen av kodeberegningen Base 64 Det gjøres med uttrykket:
(valor_original>>(2+(numero_valor%3)*2))|resto_base64
og beregningen av resten med uttrykket:
(valor_original&(MASCARA_B64>>desplazamiento))<<desplazamiento
,
være desplazamiento
en verdi som beregnes med uttrykket:
4-(numero_valor%3)*2
Prosessen som følges for å få disse uttrykkene består i å generalisere beregningen av hver av de fire kodene Base 64 som er resultatet av å representere tre byte av den opprinnelige verdien.
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 teksten Base64
Pseudokoden ovenfor refererer til koden i Base 64 som blir beregnet. Uttrykket er brukt byte_n
å referere til den n-te byten som kodes. Teksten resto
representerer de resterende bitene av byten som blir kodet. I begynnelsen av beregningen antas det at resten er null
For klarhetens skyld, i den forrige pseudokoden har 6-bits masken blitt inkludert i beregningen av alle kodene, selv om det bare er nødvendig å bestemme den siste av dem, siden de andre roteres slik at de to fleste bitene alltid går tapt. betydelige.
Som du kan se, er den fjerde koden alle rester og det er ikke nødvendig å beregne en rest etterpå; Det er derfor bare nødvendig å utføre tre trinn, ett per kodet byte. Det er viktig å huske at hvis en tredje byte i en pakke ikke var kodet, ville den siste koden måtte fylles med nuller til høyre. Base 64 oppnådd.
For å generalisere, høyrerotasjonen av uttrykket som beregner koden i Base 64 kan representeres som 2+(numero_byte%3)*2
slik at delen innenfor parentesen ville rotere fra null til to, noe som resulterer i 2, 4 og 6 ved hvert trinn. Det er selvfølgelig ikke den eneste måten å generalisere på, men jeg har valgt denne for funksjonalitet og fremfor alt for klarhet. Siden masken (AND) bare var nødvendig i den fjerde koden og det allerede har blitt sett at det ikke er nødvendig å beregne den (det er resten), er den ikke inkludert i det endelige uttrykket for å forenkle det, selv om vi må huske at typen data som brukes (byte ) bare de 6 minst signifikante bitene tas.
Venstrerotasjonen til resten kan generaliseres på en måte som er analog med den forrige. Det kan også ses at masken som påføres (AND) gjennomgår samme bitrotasjon, men i motsatt retning. Det er grunnen til å beregne forskyvningen med 4-(numero_valor%3)*2
før du bruker det i den betydningen som tilsvarer hver del av uttrykket.
Følgende eksempel viser hvordan du bruker biblioteket til å kode en tekststreng (husk at Base 64 kan brukes for ethvert datasett, for eksempel et bilde). I den følgende koden er det et par detaljer som er interessante å avklare. For det første har et spesielt symbol (~-symbolet) blitt brukt for å indikere slutten av teksten, i stedet for et maskinvaresignal eller som indikerer lengden på teksten. Logisk sett kan ikke dette symbolet være en del av dataene som er kodet.
Det andre spørsmålet som må vurderes, like viktig som det er åpenbart, er at dekoderen på destinasjonen må vite hvordan informasjonen som når den er representert. Teksten inneholder tegn som ikke tilhører settet ASCII utskrivbare (fra 32 til 126), bokstaver med aksent, for eksempel. Arduino vil bruke to byte (UTF-8) for å representere disse tegnene. Den vanlige kan ikke bare brukes \0
som en tekstterminator siden, i mange tilfeller, vil den første byten som et tegn er representert med, være nøyaktig null.
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()
{
}
|
Linje 26 i forrige eksempel viser bruken av bibliotek for Arduino å kode i Base64. Det er bare nødvendig å angi metoden convertir
hver byte du vil kode og eventuelt om det er den siste eller, hvis ikke, stopp konverteringen med metoden terminar
når du kommer til slutten.
Som du kan se på skjermbildet nedenfor, er eksempelprogrammet til bibliotek for Arduino å kode i Base64 viser først teksten som skal kodes inn Base 64, i dette tilfellet, begynnelsen på den berømte sangen til gigantene Les Luthiers, og deretter resultatet av innkoding Base 64 ved hjelp av formatlinjelengde MIME.
Legg inn kommentar