Biblioteka kodowania Base64 z Arduino
Baza 64 to system kodowania wykorzystujący 64 symbole pogrupowane w wiadomości o długości będącej wielokrotnością czterech. Te komunikaty (pakiety danych) są uzupełniane, jeśli to konieczne, symbolem plusa (więc używa się 65), często znakiem równości (=), jeśli zakodowana użyteczna informacja skutkuje krótszą długością.
Za pomocą 64 znaków możesz pracować z 10 cyframi oraz dużymi i małymi literami (26+26) kodu ASCII, problem polega na tym, że istnieją 62, powiedzmy, jednoznaczne symbole plus dwa, które różnią się w różnych implementacjach. Chociaż czasami określa się je wyrażeniem „znaki”. ASCII nadające się do druku”, w rzeczywistości są to te, które wahają się od tego reprezentowanego przez kod 32 (spacja) do 126 (~), czyli 95, które naprawdę można wydrukować.
Implementacja kodowania Baza 64 najczęściej używane, to PEM, z którego również korzysta MIM, pracuj z dodatkowymi znakami „+” i „/” oraz znakiem „=” w dopełnieniu, tak aby pakiety miały długość stanowiącą wielokrotność czterech. Litery A-Z zajmują pozycje 0-25, litery a-z zajmują pozycje 26-51, cyfry 0-9 zajmują pozycje 52-61, znak plus (+) zajmuje pozycje 62, a pozycję 63 zajmuje ukośnik (/ ).
Sposób reprezentacji danych w formacie Baza 64 polega na pobraniu z danych oryginalnych grup 6 bitów które są reprezentowane przez odpowiedni kod. Jeśli pozostały bity, są one wypełniane zerami po prawej stronie. Jeśli wynikowa liczba kodów nie jest wielokrotnością czterech, jest ona wypełniana znakami równości po prawej stronie.
Poniższy obrazek przedstawia kodowanie ASCII tekstu („om”) i sposobu, w jaki jest on konwertowany Baza 64. Ponieważ jest 7 symboli, końcową wiadomość należy wypełnić znakiem równości na końcu. Można powiedzieć, że tekst „ohm” w ASCII odpowiednik «b2htaW8=" w Baza 64.
Specyficzne zastosowania kodowania Baza 64 Zwykle narzucają również maksymalną długość linii. Implementacja MIM Ogranicza długość każdej linii do 76 znaków. Zwykle linie będą oddzielone kodem końca linii (CR, reprezentowanym przez wartość 0x0D w ASCII) i kolejna nowa linia (NL, która odpowiada kodowi ASCII 0x0A).
Niedogodności dodawane przy wdrażaniu kodowania Baza 64 na urządzeniu z niewielkimi zasobami, jak to często bywa w przypadku mikrokontroler polega na tym, że musisz kodować w momencie nadejścia informacji lub za pomocą bufor minimum, co wymaga również zapewnienia systemu sygnalizującego dotarcie do końca pierwotnego komunikatu, na przykład poprzez dodanie specjalnego kodu lub użycie pinu, którego poziom (zsynchronizowany z odbiorem) wskazuje stan komunikatu.
Przykładowy kod poniżej to a biblioteka dla Arduino do kodowania w Base64 który jest realizowany z obydwoma kryteriami: kodowaniem przychodzącej informacji (bez pliku bufor) i poczekaj na zakończenie sygnału ostrzegawczego.
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”
}
}
|
Podstawowa część obliczeń kodu Baza 64 Robi się to za pomocą wyrażenia:
(valor_original>>(2+(numero_valor%3)*2))|resto_base64
i obliczenie reszty za pomocą wyrażenia:
(valor_original&(MASCARA_B64>>desplazamiento))<<desplazamiento
,
bycie desplazamiento
wartość obliczana za pomocą wyrażenia:
4-(numero_valor%3)*2
Proces uzyskiwania tych wyrażeń polega na uogólnieniu obliczeń każdego z czterech kodów Baza 64 które wynikają z reprezentowania trzech bajtów oryginalnej wartości.
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 |
Z tekstem Base64
Pseudokod powyżej odnosi się do kodu w Baza 64 to się oblicza. Wyrażenie zostało użyte byte_n
odnosić się do kodowanego n-tego bajtu. Tekst resto
reprezentuje pozostałe bity kodowanego bajtu. Na początku obliczeń zakłada się, że reszta wynosi zero
Dla jasności, w poprzednim pseudokodzie przy obliczaniu wszystkich kodów uwzględniono maskę 6-bitową, chociaż konieczne jest jedynie określenie ostatniego z nich, ponieważ pozostałe są obracane w taki sposób, że zawsze tracone są dwa największe bity. istotne.
Jak widać, czwarty kod to cała reszta i nie ma potrzeby późniejszego obliczania reszty; Dlatego konieczne jest wykonanie tylko trzech kroków, po jednym na zakodowany bajt. Należy pamiętać, że gdyby trzeci bajt w pakiecie nie był zakodowany, ostatni kod musiałby zostać wypełniony zerami po prawej stronie. Baza 64 uzyskane.
Uogólniając, prawy obrót wyrażenia, które oblicza kod Baza 64 można przedstawić jako 2+(numero_byte%3)*2
tak aby część wewnątrz nawiasów obróciła się od zera do dwóch, co dałoby 2, 4 i 6 w każdym kroku. Oczywiście nie jest to jedyny sposób na uogólnianie, ale wybrałem ten ze względu na funkcjonalność, a przede wszystkim dla przejrzystości. Ponieważ maska (AND) była konieczna tylko w czwartym kodzie i już widać, że nie trzeba jej obliczać (to cała reszta), nie jest ona uwzględniona w końcowym wyrażeniu, aby ją uprościć, chociaż musimy pamiętać że typ używanych danych (bajt) uwzględnia tylko 6 najmniej znaczących bitów.
Lewy obrót reszty można uogólnić w sposób analogiczny do poprzedniego. Można również zauważyć, że zastosowana maska (AND) podlega temu samemu obrotowi bitu, ale w przeciwnym kierunku. To jest powód obliczenia przemieszczenia za pomocą 4-(numero_valor%3)*2
przed zastosowaniem go w znaczeniu odpowiadającym każdej części wyrażenia.
Poniższy przykład pokazuje, jak używać biblioteki do kodowania ciągu tekstowego (pamiętaj o tym Baza 64 można użyć do dowolnego zestawu danych, takiego jak na przykład obraz). W poniższym kodzie znajduje się kilka szczegółów, które warto wyjaśnić. Po pierwsze, zamiast sygnału sprzętowego lub wskazania długości tekstu, zastosowano specjalny symbol (symbol ~) do wskazania końca tekstu. Logicznie rzecz biorąc, symbol ten nie może być częścią zakodowanych danych.
Drugą kwestią, którą należy rozważyć, równie ważną, jak oczywistą, jest to, że dekoder w miejscu docelowym musi wiedzieć, w jaki sposób reprezentowana jest docierająca do niego informacja. W tekście znajdują się znaki nie należące do zestawu ASCII do druku (od 32 do 126), np. litery z akcentem. Arduino użyje dwóch bajtów (UTF-8) do reprezentowania tych znaków. Zwykłego nie można po prostu użyć \0
jako terminator tekstu, ponieważ w wielu przypadkach pierwszy bajt, za pomocą którego reprezentowany jest znak, będzie miał dokładnie wartość 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 poprzedniego przykładu pokazuje użycie metody biblioteka dla Arduino do kodowania w Base64. Konieczne jest jedynie wskazanie metody convertir
każdy bajt, który chcesz zakodować i opcjonalnie, czy jest to ostatni, lub jeśli nie, zatrzymaj konwersję metodą terminar
kiedy dojdziesz do końca.
Jak widać na zrzucie ekranu poniżej, przykładowy program biblioteka dla Arduino do kodowania w Base64 najpierw wyświetla tekst, który ma zostać zakodowany Baza 64, w tym przypadku początek słynnej pieśni gigantów Les Luthiers, a następnie wynik kodowania w Baza 64 przy użyciu długości linii formatu MIM.
Zamieść komentarz