When I’m Sixty-Four ovvero quando avro' 64 anni

Dal titolo si capisce che sono andato a vedere “yesterday”? il film che i Beatles non sono mai esistiti?
Io non ho 64 anni, ma il numerello mi ha girato per la testa, fino a farmi venire in mente un problemino che dovrò risolvere la prossima volta che metto mano al maggiordomo

La codifica base64
Brr che paura…

ho cercato e trovato una comoda libreria che codifica e de-codifica da e per base64, ma per come la vedo io fa “brutta cosa”, lavora su array di byte già formati
e se devo lavorare su oggetti lunghi la memoria mi fa difetto, voi lo sapete che mi piace lavorare on the fly (libera traduzione: a cavallo della mosca, non credo che sia proprio proprio corretta…)
ecco quindi che ho pensato a una funzione che accetta in ingresso un singolo byte
e che restituisce un int, ogni volta che riceve 8 bit utili restituisce un byte corretto, altrimenti restituisce -1
e così posso de-codificare al volo una stringa in ingresso base64, senza dover stivare (a me stoccare non piace, sembra brutto)
senza dover stivare dicevo, sia l’intera stringa in ingresso che l’intera stringa di uscita
come funziona?
semplice: riceve un byte, lo converte, una variabile locale statica tiene conto dei bit utili ricevuti,
sulla base dei bit utili ricevuti calcolo i bitshift che servono per costruire la variabile da ritornare, se i bit ricevuti sono meno di 8 restituisce -1, se più di otto ne avanza per la prossima chiamata
eccola:

int base64decode(byte input)
{
  // riceve in ingresso un byte di una stringa base64
  // restituisce -1 se non ha nulla da decodificare
  // restituisce da 0 a 255 se ha decodificato qualcosa
    int ritorno = -1;
    typedef union assemblato
    {
        byte a[2];
        unsigned int b;
    };
    // restituisce un byte de-codificato da base 64
    // oppure -1 se non ha ancora ricevuto abbastanza byte in ingresso
    // per prima cosa de-codifico il byte in ingresso
    char c = (char)input;
    byte d = 0;
    static assemblato h;
    bool valido = 0;
    static byte resto = 0;

    // richiamata, ricevo un carattere
    // lo decodifico
    if (c >= 'A' and c <= 'Z')
    {
        d = c - 'A';
        valido = 1;
    }

    if (c >= 'a' and c <= 'z')
    {
        d = c - 'a' + 26;
        valido = 1;
    }

    if (c >= '0' and c <= '9')
    {
        d = c - '0' + 52;
        valido = 1;
    }

    if (c == '+')
    {
        d = 62;
        valido = 1;
    }

    if (c == '/')
    {
        d = 63;
        valido = 1;
    }

    //se valido
    if (valido)
    {
        valido = 0;
        // metto il suo codice nel primo byte
        h.a[0] = d;
        h.a[0] <<= 2;
        // lo spingo nel secondo byte (il secondo byte ha 0,2,4,6 byte)
        byte posizioni = 8 - resto;

        if (posizioni > 6)
        {
            posizioni = 6;
        }

        h.b <<= posizioni;
        resto = resto + 6;

        // se ho piu' di 7 bit;
        if (resto > 7)
        {
            resto = resto - 8;
            ritorno = h.a[1];
            h.a[1] = 0;
            h.b <<= resto;
        }
    }

    return ritorno;
}

come vedete il grosso è una pura enumerazione di casi per la conversione
poi abbiamo il check che si tratti di un valore valido
poi il giochino di bitshift
col trucco che scrivo in una union, un array di due byte unito con un unsigned int
shifto prima di due bit il byte in ingresso e lo scrivo nel primo dei due byte dello array
poi calcolo lo shift dell’intero gruppo di bit (16)
poi se ne ho 8 utili leggo il “secondo” byte dello array , lo azzero e finisco lo shift
un bell’esempio di uso:

char prova[] = "V2hlbiBJIGdldCBvbGRlciBsb3NpbmcgbXkgaGFpcgpNYW55IHllYXJzIGZyb20gbm93CldpbGwgeW91IHN0aWxsIGJlIHNlbmRpbmcgbWUgYSB2YWxlbnRpbmUKQmlydGhkYXkgZ3JlZXRpbmdzLCBib3R0bGUgb2Ygd2luZT8KCklmIEnigJlkIGJlZW4gb3V0IHRpbGwgcXVhcnRlciB0byB0aHJlZQpXb3VsZCB5b3UgbG9jayB0aGUgZG9vcgpXaWxsIHlvdSBzdGlsbCBuZWVkIG1lLCB3aWxsIHlvdSBzdGlsbCBmZWVkIG1lCldoZW4gSeKAmW0gc2l4dHktZm91cj8=";
char * puntatore = prova;

void setup(void)
{
    Serial.begin(9600);

    while (*puntatore)
    {
        int i = base64decode(*puntatore++);

        if (i > 0)
        {
            Serial.print((char)i);
        }
    }

    Serial.println();
}

dove vi ho messo anche una stringa base64 che dimostra il buon funzionamento della cosa
come dicevo una volta?
sono graditi gli applausi


 clap clap clap

C’era un thread che raccomandava titoli che descrivano con chiarezza il contenuto del post ... comunque “When I’m sixty four” significa “Quando avro’ 64 anni” e non “Quando avevo 64 anni”.

Marco

Sì: forse sarebbe più appropriato "Panegirico con auspicio di elogi" :) Beh... Basta, lasciamo perdere.

Sulimarco:
“When I’m sixty four” significa “Quando avro’ 64 anni” e non “Quando avevo 64 anni”.

Marco

ho corretto il titolo, chiedo scusa
per intanto ho fatto alcune aggiunte:
primo, trattandosi di funzioni che hanno delle variabili static ho dovuto prevedere un azzeramento, se mi capita di dover trascodificare una stringa successiva alla prima
ho usato il semplice trucco di usare come argomento un intero, -1 signfica "azzera i vari resti per ripartire da capo)
inoltre ho introdotto una nuova funzione: la codifica in base 64, sempre a cavallo della mosca (on the fly)
eccola:

unsigned int base64encode(int input)
{
    // la tabella di conversione
    static char tabella[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    // riceve in input un byte in chiaro
    // e restituisce 1 o 2 byte codificati base64
    // sotto forma di un unsigned int che verrà letto come 2 byte consecutivi
    typedef union assemblato
    {
        byte a[2];
        unsigned int b;
    };
    static assemblato h;
    static byte resto = 0;

    if (input < 0)
    {
        h.b = 0;
        resto = 0;
        return 0;
    }

    assemblato ritorno;
    ritorno.b = 0;
    // mi assicuro di svuotarlo
    // inizio carico il byte in ingresso nella prima posizione
    h.a[0] = input;
    //Serial.print((int)h.a[0]);
    //Serial.print("\t");
    // ne prendo tanti bit da fare 6 con quelli avanzati
    byte posizioni = 6 - resto;
    h.b <<= posizioni;
    // è garantito che bastano, ne sono entrati otto
    // ne avanzano:
    resto = resto + 2;
    // prelevo il secondo byte convertendolo al volo nell'uscita
    ritorno.a[0] = tabella[h.a[1]];
    // e lo azzero
    h.a[1] = 0;
    // possono avanzare 2 4 o 6  byte
    // li metto nel secondo byte
    h.b <<= resto;

    // ma se ne avanzano 6, posso scrivere un secondo byte
    if (resto == 6)
    {
        ritorno.a[1] = tabella[h.a[1]];
        h.a[1] = 0;
        resto = 0;
    }

    return ritorno.b;
}

attenzione che 3 byte in ingresso codificano in 4 byte in uscita
quindi occorre prevedere che la funzione restituisca a volte 1 a volte 2 byte
di nuovo, faccio restituire un unsigned int, che leggo come array di due byte (in realtà gioco di puntatori), se il secondo byte è vuoto lo ignoro
una cosa così:

        int i = base64encode((byte)'carattere da codificare');
        char * punta = (char *) &i;
        int j = base64decode(* punta);

        if (j > 0)
        {
            uso -> ((char)j);
        }

        punta++;

        if (* punta)
        {
            int k = base64decode(* punta);

            if (k > 0)
            {
                uso -> ((char)k);
            }
        }

il carattere da codificare va castato a byte perchè nel set esteso di caratteri ASCII i caratteri estesi sono negativi, serve di castare a byte, dato che valori negativi servono per il reset della funzione
il tutto è caricato in una piccola libreria personale, che potete scaricare e mettere nel percorso di ricerca
io la ho chiamata mybase64.h (puntoc non lo accetta, chissa’ perché)
e lo ho messa dentro in “… arduino-1.8.5/portable/sketchbook/libraries/Nelson”
file mybase64.c, e se ci mettete li dentro anche il file keyword.txt vi mette a colori anche le due parole chiave
ecco comunque il file.ino:

// Nelson StandardOil
// per non dimenticare i gravi disastri petroliferi
// progetto "Santa Barbara"
// Santa Barbara - California - 21 maggio 2015 - 65 tonnellate
// de-codifica on-fly di messaggi base64

#include "mybase64.h"

char codificato[] = "V2hlbiBJIGdldCBvbGRlciBsb3NpbmcgbXkgaGFpcgpNYW55IHllYXJzIGZyb20gbm93CldpbGwgeW91IHN0aWxsIGJlIHNlbmRpbmcgbWUgYSB2YWxlbnRpbmUKQmlydGhkYXkgZ3JlZXRpbmdzLCBib3R0bGUgb2Ygd2luZT8KCklmIEnigJlkIGJlZW4gb3V0IHRpbGwgcXVhcnRlciB0byB0aHJlZQpXb3VsZCB5b3UgbG9jayB0aGUgZG9vcgpXaWxsIHlvdSBzdGlsbCBuZWVkIG1lLCB3aWxsIHlvdSBzdGlsbCBmZWVkIG1lCldoZW4gSeKAmW0gc2l4dHktZm91cj8=";
char chiaro[] = "the quick brown fox jump over the lazy dog, THE QUICK BROWN FOX JUMP OVER THE LAZY DOG 0123456789+-";
void setup(void)
{
    // per pulire le static di codifica e decodifica:
    base64decode(-1);
    base64encode(-1);
    Serial.begin(9600);
    Serial.println();
    Serial.println("Due versi di una canzone dei Beatles, de-codificati a partire da una stringa pre codificata:");
    Serial.println();

    for (int j = 0; j < strlen(codificato); j++)
    {
        int i = base64decode(codificato[j]);

        if (i > 0)
        {
            Serial.print((char)i);
        }
    }

    Serial.println();
    Serial.println("Fine decodifica");
    base64decode(-1);
    base64encode(-1);
    Serial.println("Inizio co-de-codifica da una stringa in chiaro co - de codificata di nuovo in chiaro");
    Serial.println("Stringa in chiaro:");
    Serial.println(chiaro);
    Serial.println();
    Serial.println("Stringa codificata e ri-decodificata al volo:");

    for (int w = 0; w < strlen(chiaro); w++)
    {
        int i = base64encode((byte)chiaro[w]);
        char * punta = (char *) &i;

        int j = base64decode(* punta);

        if (j > 0)
        {
            Serial.print((char)j);
        }

        punta++;

        if (* punta)
        {
            // Serial.print(* punta);
            int k = base64decode(* punta);

            if (k > 0)
            {
                Serial.print((char)k);
            }
        }
    }

    Serial.println();
    Serial.println("Fine decodifica di una codifica al volo");
}

void loop(void)
{
}

appare evidente che le stringhe da codificare devono avere lunghezza multipla di 3, a dare stringhe codificate con lunghezza multipla di 4
viceversa per le stringhe da de-codificare

come vedete proseguo a nominare i miei progetti con nomi di incidenti petroliferi
per le prove disastri petroliferi senza petroliere
per i progetti definitivi petroliere affondate

santabarbara.ino (2.13 KB)

mybase64.h (3.08 KB)

keywords.txt (487 Bytes)

Sulimarco:
C’era un thread che raccomandava titoli che descrivano con chiarezza il contenuto del post …

questo?

mi sa che se lo è scritto ancora lui…

Salvorhardin: questo? https://forum.arduino.cc/index.php?topic=617572.msg4191852#msg4191852 mi sa che se lo è scritto ancora lui...........

>Standardoil: In effetti protesti riperndere i tuoi vari thread e mettere dei titoli che abbiano un "senso" Arduinesco ... ... anche perché chi fa ricerche sul forum per risolvere un problema, cerca delle parole chiavi e non dei titoli di fantasia che NON descrivono di cosa si parla. In questo modo si aiuta chi viene qui a cercare degli articoli che risolvano il suo problema ... Grazie.

Guglielmo

sono tutti linkati in "aiutateci ad aiutarvi" che invece ha un titolo molto preciso e molto adeguato ma che sembra venga ignorato lo stesso magari invece facendo il "buffone" un po' di attenzione la si ottiene...

Bah, secondo me un titolo chiaro invoglia molto di più ... poi, fai come ti pare ...

Guglielmo

Standardoil: magari invece facendo il "buffone" un po' di attenzione la si ottiene...

...ma come vieni considerato, poi, da chi non ti conosce?...