martedì 14 gennaio 2014

Compressione SMS in Android

Per la solita applicazione su cui sto lavorando adesso, sarebbe utile effettuare la compressione dei dati di un SMS per trasportare la maggiore quantita' di informazioni. Ho fatto un paio di prove, la prima e' questa basata semplicemente sulla compressione dei caratteri

Fonte Wikipedia


I dati previsti sono numerici con alcuni segni di interpunzione per cui l'intero set di caratteri puo' essere descritto con un set di 16 caratteri (4 bit). I dati trasportati sono coordinate geografiche, informazioni sul tempo, dati di antenne e stato della batteria
Considerando che la tavola dei caratteri piu' semplice per gli SMS racchiude 7 bit c'e' un discreto guadagno (un fattore di 1.75)

Attualmente gli SMS permettono di inviare 1120 bit, ovvero 160 caratteri con la tabella a 7 bit e 140 con la tabella ad 8 bit.(le tabelle dei codici SMS non sono confrontabili con quelle ASCII)

Usando il codice riportato dopo il salto e' stata effettuata una prova codificando

---------------------------------------------
Messaggio : 12.3455;43.123123;22;-45;13:23:21 12/03/2013
Lungh. messaggio 44
Valore numerici convertiti a 7 bit 72 22 11 85 39 120 34 98 72 120 17 58 45 116 33 30 68 7 97 71 84 0 23 2 72 127 127 
Messaggio compresso a 7 Bit tabella GSM : HΠØU'x"bHx_:-t!ßDìaGT@Ψ$Hàà
Lungh.Mess.Compresso 27
Messaggio Decompresso :12.3455;43.123123;22;-45;13:23:21 12/03/2013   
---------------------------------------------

Come si osserva che il messaggio e' compresso con un fatto di circa 1.7 (il limite teorico di 1.75 non e' raggiunto per una serie di aggiustamenti nel passare da 4 a 7 bit)


Il codice che segue non e' certo elegante (abbiate pazienza)

---------------------------------------------
package sms_compression;

/**
 *
 * @author l.innocenti
 */
public class Sms_compression {

    static String[] tabella = new String[16];
    static char[] sms = new char[128];
  
    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        tabella[0] = "0000"; // 0
        tabella[1] = "0001"; // 1
        tabella[2] = "0010"; // 2
        tabella[3] = "0011"; // 3
        tabella[4] = "0100"; // 4
        tabella[5] = "0101"; // 5
        tabella[6] = "0110"; // 6
        tabella[7] = "0111"; // 7
        tabella[8] = "1000"; // 8
        tabella[9] = "1001"; // 9
        tabella[10] = "1010"; // /
        tabella[11] = "1011"; // -
        tabella[12] = "1100"; // :
        tabella[13] = "1101"; // .
        tabella[14] = "1110"; // ;
        tabella[15] = "1111"; // spazio
        
        sms[0] = '@';
        sms[1] = '£';
        sms[2] = '$';
        sms[3] = '¥';
        sms[4] = 'è';
        sms[5] = 'é';
        sms[6] = 'ù';
        sms[7] = 'ì';
        sms[8] = 'ò';
        sms[9] = 'Ç';
        sms[10] = '\n';
        sms[11] = 'Ø';
        sms[12] = 'ø';
        sms[13] = '\r';
        sms[14] = 'Å';
        sms[15] = 'å';
        sms[16] = 'Δ';
        sms[17] = '_';
        sms[18] = 'Φ';
        sms[19] = 'Γ';
        sms[20] = 'Λ';
        sms[21] = 'Ω';
        sms[22] = 'Π';
        sms[23] = 'Ψ';
        sms[24] = 'Σ';
        sms[25] = 'Θ';
        sms[26] = 'Ξ';
        //sms[27] = '';
        sms[28] = 'Æ';
        sms[29] = 'æ';
        sms[30] = 'ß';
        sms[31] = 'É';
        sms[32] = ' ';
        sms[33] = '!';
        sms[34] = '"';
        sms[35] = '#';
        sms[36] = '¤';
        sms[37] = '%';
        sms[38] = '&';
        sms[39] = '\'';
        sms[40] = '(';
        sms[41] = ')';
        sms[42] = '*';
        sms[43] = '+';
        sms[44] = ',';
        sms[45] = '-';
        sms[46] = '.';
        sms[47] = '/';
        sms[48] = '0';
        sms[49] = '1';
        sms[50] = '2';
        sms[51] = '3';
        sms[52] = '4';
        sms[53] = '5';
        sms[54] = '6';
        sms[55] = '7';
        sms[56] = '8';
        sms[57] = '9';
        sms[58] = ':';
        sms[59] = ';';
        sms[60] = '<';
        sms[61] = '=';
        sms[62] = '>';
        sms[63] = '?';
        sms[64] = '¡';
        sms[65] = 'A';
        sms[66] = 'B';
        sms[67] = 'C';
        sms[68] = 'D';
        sms[69] = 'E';
        sms[70] = 'F';
        sms[71] = 'G';
        sms[72] = 'H';
        sms[73] = 'I';
        sms[74] = 'J';
        sms[75] = 'K';
        sms[76] = 'L';
        sms[77] = 'M';
        sms[78] = 'N';
        sms[79] = 'O';
        sms[80] = 'P';
        sms[81] = 'Q';
        sms[82] = 'R';
        sms[83] = 'S';
        sms[84] = 'T';
        sms[85] = 'U';
        sms[86] = 'V';
        sms[87] = 'W';
        sms[88] = 'X';
        sms[89] = 'Y';
        sms[90] = 'Z';
        sms[91] = 'Ä';
        sms[92] = 'Ö';
        sms[93] = 'Ñ';
        sms[94] = 'Ü';
        sms[95] = '§';
        sms[96] = '¿';
        sms[97] = 'a';
        sms[98] = 'b';
        sms[99] = 'c';
        sms[100] = 'd';
        sms[101] = 'e';
        sms[102] = 'f';
        sms[103] = 'g';
        sms[104] = 'h';
        sms[105] = 'i';
        sms[106] = 'j';
        sms[107] = 'k';
        sms[108] = 'l';
        sms[109] = 'm';
        sms[110] = 'n';
        sms[111] = 'o';
        sms[112] = 'p';
        sms[113] = 'q';
        sms[114] = 'r';
        sms[115] = 's';
        sms[116] = 't';
        sms[117] = 'u';
        sms[118] = 'v';
        sms[119] = 'w';
        sms[120] = 'x';
        sms[121] = 'y';
        sms[122] = 'z';
        sms[123] = 'ä';
        sms[124] = 'ö';
        sms[125] = 'ñ';
        sms[126] = 'ü';
        sms[127] = 'à';
        
        
        String messaggio = "12.3455;43.123123;22;-45;13:23:21 12/03/2013";
        String compressa = "";
        String passaggio = "";
        
        System.out.println("Messaggio : "+messaggio);
        System.out.println("Lungh. messaggio " +messaggio.length());
        for (int t=0;t<messaggio.length();t++)
        {
            switch (messaggio.charAt(t))
            {
                case '0': passaggio = passaggio + tabella[0];
                          break;
                case '1': passaggio = passaggio + tabella[1];
                          break;
                case '2': passaggio = passaggio + tabella[2];
                          break;
                case '3': passaggio = passaggio + tabella[3];
                          break;
                case '4': passaggio = passaggio + tabella[4];
                          break;
                case '5': passaggio = passaggio + tabella[5];
                          break;
                case '6': passaggio = passaggio + tabella[6];
                          break;
                case '7': passaggio = passaggio + tabella[7];
                          break;
                case '8': passaggio = passaggio + tabella[8];
                          break;
                case '9': passaggio = passaggio + tabella[9];
                          break;
                case '/': passaggio = passaggio + tabella[10];
                          break;
                case '-': passaggio = passaggio + tabella[11];
                          break;
                case ':': passaggio = passaggio + tabella[12];
                          break;
                case '.': passaggio = passaggio + tabella[13];
                          break;
                case ';': passaggio = passaggio + tabella[14];
                          break;    
                case ' ': passaggio = passaggio + tabella[15];
                          break;    

                default: break;
            }
        }
        //System.out.println(passaggio);
        
        //questo per rendere la stringa divisibile per 7 bit
        //int resto = passaggio.length()%7;
        //System.out.println("Resto prima "+Double.toString(resto));

        while ((passaggio.length() %7) != 0)
        {
                passaggio = passaggio + "1111";
        }
        //System.out.println("Lungh. binaria " +passaggio.length());

        
        //System.out.println("Resto dopo "+Double.toString(passaggio.length()%7));
        //effettua la conversione in codifica a 7 bit
        int indice = 0;
        int  valore = 0;
        double p = 0;
        for (int t=0;t<passaggio.length()-1;t++)
        {
            valore = passaggio.charAt(t)-48;
            p = p + (valore*Math.pow(2, indice));
            indice++;
            if (indice == 7)
            {
                indice = 0;
                int te = (int) p;
                System.out.print(te+" ");
                compressa = compressa + sms[te];
                p=0;
            }
        }
    System.out.println();
    System.out.println("Messaggio compresso " +compressa);
    System.out.println("Lungh.Mess.Compresso " +compressa.length());
    passaggio = "";
    String reverse = "";
    String decodifica ="";
    String risultato = "";
    //System.exit(0);
    
    for (int t=0; t<compressa.length();t++)
    {
        //valore = (int)compressa.charAt(t);
        valore = converti_sms(compressa.charAt(t));
        String v = Integer.toBinaryString(valore);
        reverse = new StringBuffer(v).reverse().toString();
        
        while ((reverse.length() %7) != 0)
        {
                reverse = reverse + "0";
        }
     
        passaggio = passaggio + reverse;
        
    }
    for (int t=0;t<passaggio.length()-1;t+=4)
    {
        decodifica = passaggio.substring(t, t+4);
        switch (decodifica)
            {
               case "0000": risultato = risultato + "0";
                          break;
               case "0001": risultato = risultato + "1";
                          break;                    
               case "0010": risultato = risultato + '2';
                          break;                    
               case "0011": risultato = risultato + "3";
                          break;                    
               case "0100": risultato = risultato + "4";
                          break;                    
               case "0101": risultato = risultato + "5";
                          break;                    
               case "0110": risultato = risultato + "6";
                          break;                    
               case "0111": risultato = risultato + "7";
                          break;                    
               case "1000": risultato = risultato + "8";
                          break;                    
               case "1001": risultato = risultato + "9";
                          break;                    
               case "1010": risultato = risultato + "/";
                          break;                    
               case "1011": risultato = risultato + "-";
                          break;                    
               case "1100": risultato = risultato + ":";
                          break;                    
               case "1101": risultato = risultato + ".";
                          break;                    
               case "1110": risultato = risultato + ";";
                          break;                    
               case "1111": risultato = risultato + " ";
                          break;                    

               default: break;
            }
        }
     System.out.println("Messaggio Decompresso :"+risultato);
    }
    
    static private int converti_sms(char carattere)
    {
       int codice=0;
       switch (carattere)
            {
             case '@': codice=0;break;
             case '£': codice=1;break;
             case '$': codice=2;break;
             case '¥': codice=3;break;
             case 'è': codice=4;break;
             case 'é': codice=5;break;
             case 'ù': codice=6;break;
             case 'ì': codice=7;break;
             case 'ò': codice=8;break;
             case 'Ç': codice=9;break;
             case '\n': codice=10;break;
             case 'Ø': codice=11;break;
             case 'ø': codice=12;break;
             case '\r': codice=13;break;
             case 'Å': codice=14;break;
             case 'å': codice=15;break;
             case 'Δ': codice=16;break;
             case '_': codice=17;break;
             case 'Φ': codice=18;break;
             case 'Γ': codice=19;break;
             case 'Λ': codice=20;break;
             case 'Ω': codice=21;break;
             case 'Π': codice=22;break;
             case 'Ψ': codice=23;break;
             case 'Σ': codice=24;break;
             case 'Θ': codice=25;break;
             case 'Ξ': codice=26;break;
             //case '': codice=27;break;
             case 'Æ': codice=28;break;
             case 'æ': codice=29;break;
             case 'ß': codice=30;break;
             case 'É': codice=31;break;
             case ' ': codice=32;break;
             case '!': codice=33;break;
             case '"': codice=34;break;
             case '#': codice=35;break;
             case '¤': codice=36;break;
             case '%': codice=37;break;
             case '&': codice=38;break;
             case '\'': codice=39;break;
             case '(': codice=40;break;
             case ')': codice=41;break;
             case '*': codice=42;break;
             case '+': codice=43;break;
             case ',': codice=44;break;
             case '-': codice=45;break;
             case '.': codice=46;break;
             case '/': codice=47;break;
             case '0': codice=48;break;
             case '1': codice=49;break;
             case '2': codice=50;break;
             case '3': codice=51;break;
             case '4': codice=52;break;
             case '5': codice=53;break;
             case '6': codice=54;break;
             case '7': codice=55;break;
             case '8': codice=56;break;
             case '9': codice=57;break;
             case ':': codice=58;break;
             case ';': codice=59;break;
             case '<': codice=60;break;
             case '=': codice=61;break;
             case '>': codice=62;break;
             case '?': codice=63;break;
             case '¡': codice=64;break;
             case 'A': codice=65;break;
             case 'B': codice=66;break;
             case 'C': codice=67;break;
             case 'D': codice=68;break;
             case 'E': codice=69;break;
             case 'F': codice=70;break;
             case 'G': codice=71;break;
             case 'H': codice=72;break;
             case 'I': codice=73;break;
             case 'J': codice=74;break;
             case 'K': codice=75;break;
             case 'L': codice=76;break;
             case 'M': codice=77;break;
             case 'N': codice=78;break;
             case 'O': codice=79;break;
             case 'P': codice=80;break;
             case 'Q': codice=81;break;
             case 'R': codice=82;break;
             case 'S': codice=83;break;
             case 'T': codice=84;break;
             case 'U': codice=85;break;
             case 'V': codice=86;break;
             case 'W': codice=87;break;
             case 'X': codice=88;break;
             case 'Y': codice=89;break;
             case 'Z': codice=90;break;
             case 'Ä': codice=91;break;
             case 'Ö': codice=92;break;
             case 'Ñ': codice=93;break;
             case 'Ü': codice=94;break;
             case '§': codice=95;break;
             case '¿': codice=96;break;
             case 'a': codice=97;break;
             case 'b': codice=98;break;
             case 'c': codice=99;break;
             case 'd': codice=100;break;
             case 'e': codice=101;break;
             case 'f': codice=102;break;
             case 'g': codice=103;break;
             case 'h': codice=104;break;
             case 'i': codice=105;break;
             case 'j': codice=106;break;
             case 'k': codice=107;break;
             case 'l': codice=108;break;
             case 'm': codice=109;break;
             case 'n': codice=110;break;
             case 'o': codice=111;break;
             case 'p': codice=112;break;
             case 'q': codice=113;break;
             case 'r': codice=114;break;
             case 's': codice=115;break;
             case 't': codice=116;break;
             case 'u': codice=117;break;
             case 'v': codice=118;break;
             case 'w': codice=119;break;
             case 'x': codice=120;break;
             case 'y': codice=121;break;
             case 'z': codice=122;break;
             case 'ä': codice=123;break;
             case 'ö': codice=124;break;
             case 'ñ': codice=125;break;
             case 'ü': codice=126;break;
             case 'à': codice=127;break;
       }
       return codice;
       
    }
    
}