Biblioteca de codificare Base64 cu Arduino
Baza64 este un sistem de codare care folosește 64 de simboluri grupate în mesaje care au un multiplu de lungime de patru. Aceste mesaje (pachete de date) se completează, dacă este necesar, cu un simbol plus (deci se folosesc 65), adesea semnul egal (=), dacă informația utilă codificată are ca rezultat o lungime mai scurtă.
Folosind 64 de semne puteți lucra cu cele 10 numere și litere mari și mici (26+26) ale codului ASCII, problema este că există 62, să spunem, simboluri fără ambiguitate plus două care variază în implementări diferite. Deși uneori la care se face referire prin expresia „personaje ASCII imprimabile”, în realitate sunt cele care variază de la cel reprezentat de codul 32 (spațiu) până la 126 (~) cel 95 cu adevărat imprimabil.
Implementarea codificării Baza64 cel mai folosit, cel al PEM, care este folosit și de MIMA, lucrați cu semnele suplimentare „+” și „/” și semnul „=" la pad, astfel încât pachetele să aibă un multiplu de lungime de patru. Literele A-Z ocupă pozițiile 0-25, literele a-z ocupă pozițiile 26-51, numerele 0-9 ocupă pozițiile 52-61, semnul plus (+) pozițiile 62 și poziția 63 este ocupată de bară oblică (/ ).
Modul de a reprezenta datele în format Baza64 constă în preluarea, din datele originale, de grupuri de 6 biți care sunt reprezentate cu codul corespunzător. Dacă au mai rămas biți, aceștia sunt umpluți cu zerouri la dreapta. Dacă numărul de coduri rezultat nu este un multiplu de patru, acesta este completat cu semne egale în dreapta.
Următoarea imagine arată codarea ASCII a unui text ("ohm") și modul în care acesta este convertit Baza64. Deoarece există 7 simboluri, mesajul final ar trebui să fie completat cu un semn egal la sfârșit. S-ar putea spune că textul „ohm” în ASCII echivalent cu «b2htaW8=" în Baza64.
Utilizări specifice ale codificării Baza64 De asemenea, de obicei impun o lungime maximă a liniei. Implementarea MIMA Limitează fiecare rând la 76 de caractere. În mod normal, liniile vor fi separate printr-un cod de sfârșit de linie (CR, reprezentat prin valoarea 0x0D în ASCII) și o altă linie nouă (NL, care corespunde codului ASCII 0x0A).
Inconvenientul care se adauga la implementarea codarii Baza64 pe un dispozitiv cu puține resurse, așa cum este adesea cazul cu a microcontroler este că trebuie să codificați pe măsură ce informația sosește sau cu a tampon minim, care necesită și furnizarea unui sistem care să indice că s-a ajuns la finalul mesajului inițial, de exemplu, prin adăugarea unui cod special, sau prin utilizarea unui pin al cărui nivel (sincronizat cu recepția) indică starea mesajului.
Exemplul de cod de mai jos este a bibliotecă pentru Arduino pentru a codifica în Base64 care se implementează cu ambele criterii: codificarea informațiilor care sosesc (fără a tampon) și așteptați ca un semnal de avertizare să se termine.
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”
}
}
|
Partea fundamentală a calculului codului Baza64 Se face cu expresia:
(valor_original>>(2+(numero_valor%3)*2))|resto_base64
iar calculul restului cu expresia:
(valor_original&(MASCARA_B64>>desplazamiento))<<desplazamiento
,
siendo desplazamiento
o valoare care se calculează cu expresia:
4-(numero_valor%3)*2
Procesul urmat pentru obținerea acestor expresii constă în generalizarea calculului fiecăruia dintre cele patru coduri Baza64 care rezultă din reprezentarea a trei octeți ai valorii inițiale.
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 |
Cu textul Base64
Pseudocodul de mai sus se referă la codul din Baza64 care se calculează. S-a folosit expresia byte_n
pentru a se referi la al n-lea octet care este codificat. Textul resto
reprezintă biții rămași din octetul care este codificat. La începutul calculului se presupune că restul este zero
Pentru claritate, în pseudocodul anterior, masca de 6 biți a fost inclusă în calculul tuturor codurilor, deși este necesar doar să se determine ultimul dintre ele, deoarece celelalte sunt rotite astfel încât cei mai mulți biți să se piardă întotdeauna. semnificativ.
După cum se poate vedea, al patrulea cod este tot restul și nu este nevoie să calculați un rest ulterior; Prin urmare, este necesar doar să efectuați trei pași, unul pe octet codificat. Este important de reținut că, dacă un al treilea octet dintr-un pachet nu ar fi codificat, ultimul cod ar trebui să fie completat cu zerouri în partea dreaptă. Baza64 obținut.
Pentru a generaliza, rotația la dreapta a expresiei care calculează codul în Baza64 poate fi reprezentat ca 2+(numero_byte%3)*2
astfel încât partea din paranteze s-ar roti de la zero la doi, rezultând 2, 4 și 6 la fiecare pas. Bineînțeles că nu este singura modalitate de generalizare, dar am ales-o pentru funcționalitate și mai ales pentru claritate. Deoarece masca (ȘI) era necesară doar în al patrulea cod și deja s-a văzut că nu este necesar să o calculăm (este tot rest), nu este inclusă în expresia finală pentru a o simplifica, deși trebuie să ne amintim că tipul de date utilizate (octet ) sunt luați doar cei 6 biți cei mai puțin semnificativi.
Rotația la stânga a restului poate fi generalizată într-un mod analog celui precedent. De asemenea, se poate observa că masca care este aplicată (ȘI) suferă aceeași rotație a biților, dar în sens opus. Acesta este motivul pentru care se calculează deplasarea cu 4-(numero_valor%3)*2
înainte de a-l aplica în sensul corespunzător fiecărei părți a expresiei.
Următorul exemplu arată cum să utilizați biblioteca pentru a codifica un șir de text (rețineți că Baza64 poate fi folosit pentru orice set de date, cum ar fi o imagine, de exemplu). În următorul cod există câteva detalii care sunt interesante de clarificat. În primul rând, un simbol special (simbolul ~) a fost folosit pentru a indica sfârșitul textului, în loc de un semnal hardware sau de a indica lungimea textului. În mod logic, acel simbol nu poate face parte din datele care sunt codificate.
A doua problemă care trebuie luată în considerare, pe cât de importantă, pe atât de evidentă, este aceea că decodorul de la destinație trebuie să știe cum este reprezentată informația care ajunge la el. Textul include personaje care nu aparțin setului ASCII imprimabile (de la 32 la 126), litere cu accent, de exemplu. Arduino va folosi doi octeți (UTF-8) pentru a reprezenta aceste personaje. Cel obișnuit nu poate fi folosit pur și simplu \0
ca terminator de text deoarece, în multe cazuri, primul octet cu care este reprezentat un caracter va fi exact zero.
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()
{
}
|
Linia 26 din exemplul anterior arată utilizarea bibliotecă pentru Arduino pentru a codifica în Base64. Este necesar doar să indicați metoda convertir
fiecare octet pe care doriți să îl codificați și, opțional, dacă este ultimul sau, dacă nu, opriți conversia cu metoda terminar
când ajungi la capăt.
După cum se poate vedea în captura de ecran de mai jos, exemplul de program al bibliotecă pentru Arduino pentru a codifica în Base64 mai întâi afișează textul în care trebuie codificat Baza64, în acest caz, începutul celebrului cântec al uriașilor Les Luthiers, iar ulterior rezultatul codificării în Baza64 folosind lungimea liniei de format MIMA.
Posteaza un comentariu