Pustaka pengkodean Base64 dengan Arduino
Base64 adalah sistem pengkodean yang menggunakan 64 simbol yang dikelompokkan menjadi pesan yang memiliki kelipatan empat panjang. Pesan-pesan ini (paket data) dilengkapi, jika perlu, dengan simbol plus (sehingga digunakan 65), sering kali dengan tanda sama dengan (=), jika informasi berguna yang dikodekan menghasilkan panjang yang lebih pendek.
Dengan menggunakan 64 tanda, Anda dapat bekerja dengan 10 angka dan huruf besar dan kecil (26+26) dari kode tersebut ASCII, masalahnya adalah terdapat 62, katakanlah, simbol yang tidak ambigu ditambah dua simbol yang bervariasi dalam implementasi yang berbeda. Walaupun terkadang disebut dengan ungkapan “karakter ASCII dapat dicetak", pada kenyataannya berkisar dari yang diwakili oleh kode 32 (spasi) hingga 126 (~) yang 95 benar-benar dapat dicetak.
Implementasi pengkodean Base64 paling banyak digunakan, yaitu KEP, yang juga digunakan oleh PANTOMIM, gunakan tanda "+" dan "/" tambahan serta tanda "=" agar paket memiliki kelipatan panjang empat. Huruf A-Z menempati posisi 0-25, huruf a-z menempati posisi 26-51, angka 0-9 menempati posisi 52-61, tanda tambah (+) posisi 62, dan posisi 63 ditempati oleh garis miring (/).
Cara merepresentasikan data dalam format Base64 terdiri dari pengambilan, dari data asli, kelompok 6 bit yang diwakili dengan kode yang sesuai. Jika ada bit yang tersisa, bit tersebut diisi dengan angka nol di sebelah kanan. Apabila jumlah kode yang dihasilkan bukan kelipatan empat, maka diisi dengan tanda sama dengan di sebelah kanan.
Gambar berikut menunjukkan pengkodeannya ASCII dari sebuah teks ("ohm") dan cara konversinya Base64. Karena ada 7 simbol, pesan terakhir harus diisi dengan tanda sama dengan di akhir. Bisa dikatakan teks "ohm" di ASCII setara dengan «b2htaW8=" di Base64.
Kegunaan khusus dari pengkodean Base64 Mereka juga biasanya memberlakukan panjang garis maksimal. Pelaksanaan PANTOMIM Membatasi setiap baris hingga 76 karakter. Biasanya baris akan dipisahkan dengan kode akhir baris (CR, diwakili oleh nilai 0x0D di ASCII) dan baris baru lainnya (NL, yang sesuai dengan kodenya ASCII 0x0A).
Ketidaknyamanan yang ditambahkan saat mengimplementasikan coding Base64 pada perangkat dengan sumber daya yang sedikit, seperti yang sering terjadi pada a mikrokontroler adalah Anda harus membuat kode saat informasi tiba atau dengan a penyangga minimum, yang juga memerlukan penyediaan sistem yang menunjukkan bahwa akhir pesan asli telah tercapai, misalnya dengan menambahkan kode khusus, atau dengan menggunakan pin yang levelnya (disinkronkan dengan penerimaan) menunjukkan status pesan.
Contoh kode di bawah ini adalah a perpustakaan untuk Arduino untuk dikodekan di Base64 yang diimplementasikan dengan kedua kriteria: pengkodean informasi yang masuk (tanpa a penyangga) dan tunggu hingga sinyal peringatan selesai.
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”
}
}
|
Bagian mendasar dari perhitungan kode Base64 Hal ini dilakukan dengan ekspresi:
(valor_original>>(2+(numero_valor%3)*2))|resto_base64
dan perhitungan sisanya dengan ekspresi:
(valor_original&(MASCARA_B64>>desplazamiento))<<desplazamiento
,
sedang desplazamiento
nilai yang dihitung dengan ekspresi:
4-(numero_valor%3)*2
Proses yang diikuti untuk memperoleh ekspresi ini terdiri dari menggeneralisasi perhitungan masing-masing dari empat kode Base64 yang dihasilkan dari mewakili tiga byte dari nilai aslinya.
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 |
Dengan teks Base64
Pseudocode di atas mengacu pada kode yang ada di Base64 itu sedang dihitung. Ekspresi tersebut telah digunakan byte_n
untuk merujuk pada byte ke-n yang sedang dikodekan. Teks resto
mewakili bit sisa dari byte yang dikodekan. Pada awal perhitungan diasumsikan sisanya nol
Untuk lebih jelasnya, pada pseudocode sebelumnya mask 6-bit telah disertakan dalam perhitungan semua kode, meskipun hanya perlu menentukan yang terakhir saja, karena yang lain diputar sehingga dua bit terbanyak selalu hilang. penting.
Seperti yang bisa dilihat, kode keempat semuanya adalah sisa dan tidak perlu menghitung sisanya setelahnya; Oleh karena itu, hanya perlu melakukan tiga langkah, satu langkah per byte yang disandikan. Penting untuk diingat bahwa, jika byte ketiga dalam sebuah paket tidak dikodekan, kode terakhir harus diisi dengan angka nol di sebelah kanan. Base64 diperoleh.
Untuk menggeneralisasi, rotasi kanan dari ekspresi yang menghitung kode masuk Base64 dapat direpresentasikan sebagai 2+(numero_byte%3)*2
sehingga bagian dalam tanda kurung akan berputar dari nol menjadi dua, menghasilkan 2, 4 dan 6 pada setiap langkah. Tentu saja ini bukan satu-satunya cara untuk menggeneralisasi, tetapi saya memilih cara ini karena fungsinya dan yang terpenting untuk kejelasan. Karena mask (AND) hanya diperlukan pada kode keempat dan sudah terlihat bahwa tidak perlu menghitungnya (semuanya adalah sisa), maka tidak disertakan dalam ekspresi akhir untuk menyederhanakannya, meskipun kita harus ingat bahwa jenis data yang digunakan (byte) hanya diambil 6 bit paling tidak signifikan.
Rotasi kiri sisanya dapat digeneralisasikan dengan cara yang analog dengan yang sebelumnya. Terlihat juga bahwa mask yang diterapkan (AND) mengalami putaran bit yang sama tetapi berlawanan arah. Itulah alasan untuk menghitung perpindahan dengan 4-(numero_valor%3)*2
sebelum menerapkannya dalam arti yang sesuai dengan setiap bagian ekspresi.
Contoh berikut menunjukkan cara menggunakan perpustakaan untuk mengkodekan string teks (ingat itu Base64 dapat digunakan untuk kumpulan data apa pun, seperti gambar, misalnya). Pada kode berikut ada beberapa detail yang menarik untuk diklarifikasi. Pertama, simbol khusus (simbol ~) telah digunakan untuk menunjukkan akhir teks, sebagai pengganti sinyal perangkat keras atau menunjukkan panjang teks. Logikanya, simbol tersebut tidak bisa menjadi bagian dari data yang dikodekan.
Persoalan kedua yang harus dipertimbangkan, yang penting dan jelas, adalah bahwa decoder di tujuan harus mengetahui bagaimana informasi yang sampai ke tujuan direpresentasikan. Teks menyertakan karakter yang bukan milik himpunan ASCII dapat dicetak (dari 32 hingga 126), huruf dengan aksen, misalnya. Arduino akan menggunakan dua byte (UTF-8) untuk mewakili karakter ini. Yang biasa tidak bisa digunakan begitu saja \0
sebagai terminator teks karena, dalam banyak kasus, byte pertama yang mewakili karakter akan sama dengan nol.
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()
{
}
|
Baris 26 dari contoh sebelumnya menunjukkan penggunaan perpustakaan untuk Arduino untuk dikodekan di Base64. Anda hanya perlu menunjukkan metodenya convertir
setiap byte yang ingin Anda enkode dan secara opsional apakah itu byte terakhir atau, jika tidak, hentikan konversi dengan metode ini terminar
ketika Anda mencapai akhir.
Seperti terlihat pada screenshot di bawah ini, contoh program dari perpustakaan untuk Arduino untuk dikodekan di Base64 pertama-tama menampilkan teks yang akan dikodekan Base64, dalam hal ini, awal dari nyanyian para raksasa yang terkenal Les Luthiers, dan selanjutnya hasil pengkodean Base64 menggunakan format panjang garis PANTOMIM.
Posting