Βιβλιοθήκη κωδικοποίησης Base64 με Arduino
Βάση64 είναι ένα σύστημα κωδικοποίησης που χρησιμοποιεί 64 σύμβολα ομαδοποιημένα σε μηνύματα που έχουν μήκος πολλαπλάσιο των τεσσάρων. Αυτά τα μηνύματα (πακέτα δεδομένων) συμπληρώνονται, εάν χρειάζεται, με ένα σύμβολο συν (άρα χρησιμοποιούνται 65), συχνά το σύμβολο ίσου (=), εάν οι χρήσιμες πληροφορίες που κωδικοποιούνται έχουν ως αποτέλεσμα μικρότερο μήκος.
Χρησιμοποιώντας 64 σημάδια μπορείτε να δουλέψετε με τους 10 αριθμούς και τα κεφαλαία και πεζά γράμματα (26+26) του κωδικού ASCII, το πρόβλημα είναι ότι υπάρχουν 62, ας πούμε, μονοσήμαντα σύμβολα συν δύο που διαφέρουν σε διαφορετικές υλοποιήσεις. Αν και μερικές φορές αναφέρεται με την έκφραση «χαρακτήρες ASCII εκτυπώσιμα», στην πραγματικότητα είναι αυτά που κυμαίνονται από αυτό που αντιπροσωπεύεται από τον κωδικό 32 (κενό) έως 126 (~) το 95 πραγματικά εκτυπώσιμο.
Η εφαρμογή της κωδικοποίησης Βάση64 πιο χρησιμοποιημένος, αυτός του PEM, το οποίο χρησιμοποιείται επίσης από ΜΊΜΟΣ, εργαστείτε με τα πρόσθετα σημάδια "+" και "/" και το σύμβολο "=" στο pad, έτσι ώστε τα πακέτα να έχουν μήκος πολλαπλάσιο του τεσσάρου. Τα γράμματα AZ καταλαμβάνουν τις θέσεις 0-25, τα γράμματα az καταλαμβάνουν τις θέσεις 26-51, οι αριθμοί 0-9 καταλαμβάνουν τις θέσεις 52-61, το σύμβολο συν (+) τις θέσεις 62 και η θέση 63 καταλαμβάνεται από την κάθετο (/ ).
Ο τρόπος αναπαράστασης δεδομένων σε μορφή Βάση64 αποτελείται από τη λήψη, από τα αρχικά δεδομένα, ομάδων των 6 bit που αντιπροσωπεύονται με τον αντίστοιχο κωδικό. Εάν περισσεύουν bits, γεμίζονται με μηδενικά προς τα δεξιά. Εάν ο αριθμός των κωδικών που προκύπτει δεν είναι πολλαπλάσιο των τεσσάρων, συμπληρώνεται με ίσα προς τα δεξιά.
Η παρακάτω εικόνα δείχνει την κωδικοποίηση ASCII ενός κειμένου ("ohm") και τον τρόπο με τον οποίο μετατρέπεται σε Βάση64. Δεδομένου ότι υπάρχουν 7 σύμβολα, το τελικό μήνυμα θα πρέπει να συμπληρωθεί με ένα σύμβολο ίσου στο τέλος. Θα μπορούσε να ειπωθεί ότι το κείμενο "ohm" σε ASCII ισοδυναμεί με «b2htaW8=" σε Βάση64.
Ειδικές χρήσεις κωδικοποίησης Βάση64 Επίσης συνήθως επιβάλλουν ένα μέγιστο μήκος γραμμής. Η εφαρμογή ΜΊΜΟΣ Περιορίζει κάθε γραμμή σε 76 χαρακτήρες. Κανονικά οι γραμμές θα διαχωρίζονται από έναν κωδικό τέλους γραμμής (CR, που αντιπροσωπεύεται από την τιμή 0x0D στο ASCII) και μια άλλη νέα γραμμή (NL, που αντιστοιχεί στον κωδικό ASCII 0x0A).
Η ταλαιπωρία που προστίθεται κατά την εφαρμογή κωδικοποίησης Βάση64 σε μια συσκευή με λίγους πόρους, όπως συμβαίνει συχνά με το a μικροελεγκτής είναι ότι πρέπει να κωδικοποιήσετε καθώς φτάνουν οι πληροφορίες ή με α ρυθμιστικό ελάχιστο, το οποίο απαιτεί επίσης την παροχή ενός συστήματος που υποδεικνύει ότι έχει φτάσει το τέλος του αρχικού μηνύματος, για παράδειγμα, προσθέτοντας έναν ειδικό κωδικό ή χρησιμοποιώντας μια καρφίτσα της οποίας το επίπεδο (συγχρονισμένο με τη λήψη) υποδεικνύει την κατάσταση του μηνύματος.
Το παράδειγμα κώδικα παρακάτω είναι α βιβλιοθήκη για κωδικοποίηση Arduino στο Base64 που υλοποιείται και με τα δύο κριτήρια: κωδικοποίηση των πληροφοριών που φθάνουν (χωρίς α ρυθμιστικό) και περιμένετε να τελειώσει ένα προειδοποιητικό σήμα.
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”
}
}
|
Το θεμελιώδες μέρος του υπολογισμού του κώδικα Βάση64 Γίνεται με την έκφραση:
(valor_original>>(2+(numero_valor%3)*2))|resto_base64
και τον υπολογισμό του υπολοίπου με την έκφραση:
(valor_original&(MASCARA_B64>>desplazamiento))<<desplazamiento
,
ύπαρξη desplazamiento
μια τιμή που υπολογίζεται με την έκφραση:
4-(numero_valor%3)*2
Η διαδικασία που ακολουθείται για να ληφθούν αυτές οι εκφράσεις συνίσταται στη γενίκευση του υπολογισμού καθενός από τους τέσσερις κωδικούς Βάση64 που προκύπτουν από την αναπαράσταση τριών byte της αρχικής τιμής.
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 |
Με το κείμενο Base64
Ο ψευδοκώδικας παραπάνω αναφέρεται στον κωδικό στο Βάση64 που υπολογίζεται. Η έκφραση έχει χρησιμοποιηθεί byte_n
να αναφέρεται στο nο byte που κωδικοποιείται. Το κείμενο resto
αντιπροσωπεύει τα εναπομείναντα bit του byte που κωδικοποιείται. Στην αρχή του υπολογισμού θεωρείται ότι το υπόλοιπο είναι μηδέν
Για λόγους σαφήνειας, στον προηγούμενο ψευδοκώδικα η μάσκα των 6 bit έχει συμπεριληφθεί στον υπολογισμό όλων των κωδικών, αν και είναι απαραίτητο να προσδιοριστεί μόνο ο τελευταίος από αυτούς, αφού τα άλλα περιστρέφονται έτσι ώστε τα δύο περισσότερα bit να χάνονται πάντα. σημαντικός.
Όπως φαίνεται, ο τέταρτος κωδικός είναι όλο το υπόλοιπο και δεν χρειάζεται να υπολογιστεί ένα υπόλοιπο μετά. Επομένως, είναι απαραίτητο να εκτελέσετε μόνο τρία βήματα, ένα ανά κωδικοποιημένο byte. Είναι σημαντικό να θυμάστε ότι, εάν ένα τρίτο byte σε ένα πακέτο δεν ήταν κωδικοποιημένο, ο τελευταίος κωδικός θα έπρεπε να συμπληρωθεί με μηδενικά στα δεξιά. Βάση64 αποκτηθεί.
Για να γενικεύσουμε, η σωστή περιστροφή της έκφρασης που υπολογίζει τον κώδικα σε Βάση64 μπορεί να αναπαρασταθεί ως 2+(numero_byte%3)*2
έτσι ώστε το τμήμα μέσα στις παρενθέσεις να περιστρέφεται από το μηδέν στο δύο, με αποτέλεσμα 2, 4 και 6 σε κάθε βήμα. Φυσικά δεν είναι ο μόνος τρόπος γενίκευσης, αλλά έχω επιλέξει αυτόν για λειτουργικότητα και κυρίως για λόγους σαφήνειας. Δεδομένου ότι η μάσκα (ΚΑΙ) ήταν απαραίτητη μόνο στον τέταρτο κώδικα και έχει ήδη φανεί ότι δεν είναι απαραίτητο να υπολογιστεί (είναι όλο υπόλοιπο), δεν περιλαμβάνεται στην τελική έκφραση για να την απλοποιήσουμε, αν και πρέπει να θυμόμαστε ότι ο τύπος των δεδομένων που χρησιμοποιείται (byte ) λαμβάνονται μόνο τα 6 λιγότερο σημαντικά bit.
Η αριστερή περιστροφή των υπολοίπων μπορεί να γενικευτεί με τρόπο ανάλογο με τον προηγούμενο. Μπορεί επίσης να φανεί ότι η μάσκα που εφαρμόζεται (AND) υφίσταται την ίδια περιστροφή bit αλλά προς την αντίθετη κατεύθυνση. Αυτός είναι ο λόγος για τον υπολογισμό της μετατόπισης με 4-(numero_valor%3)*2
πριν το εφαρμόσουμε με την έννοια που αντιστοιχεί σε κάθε μέρος της έκφρασης.
Το παρακάτω παράδειγμα δείχνει πώς να χρησιμοποιήσετε τη βιβλιοθήκη για να κωδικοποιήσετε μια συμβολοσειρά κειμένου (θυμηθείτε ότι Βάση64 μπορεί να χρησιμοποιηθεί για οποιοδήποτε σύνολο δεδομένων, όπως μια εικόνα, για παράδειγμα). Στον παρακάτω κώδικα υπάρχουν μερικές λεπτομέρειες που είναι ενδιαφέρον να διευκρινιστούν. Πρώτον, ένα ειδικό σύμβολο (το σύμβολο ~) έχει χρησιμοποιηθεί για να υποδείξει το τέλος του κειμένου, αντί για σήμα υλικού ή που υποδεικνύει το μήκος του κειμένου. Λογικά, αυτό το σύμβολο δεν μπορεί να είναι μέρος των δεδομένων που είναι κωδικοποιημένα.
Το δεύτερο θέμα που πρέπει να ληφθεί υπόψη, τόσο σημαντικό όσο είναι προφανές, είναι ότι ο αποκωδικοποιητής στον προορισμό πρέπει να γνωρίζει πώς αναπαρίσταται η πληροφορία που φθάνει σε αυτόν. Το κείμενο περιλαμβάνει χαρακτήρες που δεν ανήκουν στο σύνολο ASCII εκτυπώσιμα (από 32 έως 126), γράμματα με έμφαση, για παράδειγμα. Arduino θα χρησιμοποιήσει δύο byte (UTF-8) για να αναπαραστήσουν αυτούς τους χαρακτήρες. Το συνηθισμένο δεν μπορεί απλά να χρησιμοποιηθεί \0
ως τερματιστής κειμένου αφού, σε πολλές περιπτώσεις, το πρώτο byte με το οποίο αναπαρίσταται ένας χαρακτήρας θα είναι ακριβώς μηδέν.
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()
{
}
|
Η γραμμή 26 του προηγούμενου παραδείγματος δείχνει τη χρήση του βιβλιοθήκη για κωδικοποίηση Arduino στο Base64. Είναι απαραίτητο μόνο να υποδείξετε τη μέθοδο convertir
κάθε byte που θέλετε να κωδικοποιήσετε και προαιρετικά εάν είναι το τελευταίο ή, αν όχι, σταματήστε τη μετατροπή με τη μέθοδο terminar
όταν φτάσεις στο τέλος.
Όπως φαίνεται στο στιγμιότυπο οθόνης παρακάτω, το παράδειγμα προγράμματος του βιβλιοθήκη για κωδικοποίηση Arduino στο Base64 εμφανίζει πρώτα το κείμενο στο οποίο θα κωδικοποιηθεί Βάση64, εν προκειμένω, η αρχή του διάσημου τραγουδιού των γιγάντων Οι Λούθιερ, και στη συνέχεια το αποτέλεσμα της κωδικοποίησης σε Βάση64 χρησιμοποιώντας μήκος γραμμής μορφής ΜΊΜΟΣ.
Δημοσίευση σχολίου