Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Class Members | File Members

Base32.cxx

Go to the documentation of this file.
00001 
00024 #include <libzrtpcpp/Base32.h>
00025 
00026 int divceil(int a, int b) {
00027     int c;
00028     if (a>0) {
00029         if (b>0) c=a+b-1;
00030         else c=a;
00031     } else {
00032         if (b>0) c=a;
00033         else c=a+b+1;
00034     }
00035     return c/b;
00036 }
00037 
00038 //                                         1         2         3
00039 //                               01234567890123456789012345678901
00040 static const char* const chars= "ybndrfg8ejkmcpqxot1uwisza345h769";
00041 
00042 /*
00043  * revchars: index into this table with the ASCII value of the char.
00044  * The result is the value of that quintet.
00045  */
00046 static const unsigned char revchars[]= {
00047     255, 255, 255, 255, 255, 255, 255, 255,
00048     255, 255, 255, 255, 255, 255, 255, 255,
00049     255, 255, 255, 255, 255, 255, 255, 255,
00050     255, 255, 255, 255, 255, 255, 255, 255,
00051     255, 255, 255, 255, 255, 255, 255, 255,
00052     255, 255, 255, 255, 255, 255, 255, 255,
00053     255,  18, 255,  25,  26,  27,  30,  29,
00054       7,  31, 255, 255, 255, 255, 255, 255,
00055     255, 255, 255, 255, 255, 255, 255, 255,
00056     255, 255, 255, 255, 255, 255, 255, 255,
00057     255, 255, 255, 255, 255, 255, 255, 255,
00058     255, 255, 255, 255, 255, 255, 255, 255,
00059     255,  24,   1,  12,   3,   8,   5,   6,
00060     28,   21,   9,  10, 255,  11,   2,  16,
00061     13,   14,   4,  22,  17,  19, 255,  20,
00062     15,    0,  23, 255, 255, 255, 255, 255,
00063     255, 255, 255, 255, 255, 255, 255, 255,
00064     255, 255, 255, 255, 255, 255, 255, 255,
00065     255, 255, 255, 255, 255, 255, 255, 255,
00066     255, 255, 255, 255, 255, 255, 255, 255,
00067     255, 255, 255, 255, 255, 255, 255, 255,
00068     255, 255, 255, 255, 255, 255, 255, 255,
00069     255, 255, 255, 255, 255, 255, 255, 255,
00070     255, 255, 255, 255, 255, 255, 255, 255,
00071     255, 255, 255, 255, 255, 255, 255, 255,
00072     255, 255, 255, 255, 255, 255, 255, 255,
00073     255, 255, 255, 255, 255, 255, 255, 255,
00074     255, 255, 255, 255, 255, 255, 255, 255,
00075     255, 255, 255, 255, 255, 255, 255, 255,
00076     255, 255, 255, 255, 255, 255, 255, 255,
00077     255, 255, 255, 255, 255, 255, 255, 255,
00078     255, 255, 255, 255, 255, 255, 255, 255
00079 };
00080 
00081 
00082 Base32::Base32(const string encoded):
00083     binaryResult(NULL), resultLength(0) {
00084 
00085     a2b_l(encoded, encoded.size(), (encoded.size()*5/8)*8);
00086 }
00087 
00088 Base32::Base32(const string encoded, int noOfBits):
00089     binaryResult(NULL), resultLength(0) {
00090 
00091     a2b_l(encoded, divceil(noOfBits, 5), noOfBits);
00092 }
00093 
00094 Base32::Base32(const unsigned char* data, int noOfBits):
00095     binaryResult(NULL), resultLength(0) {
00096 
00097     b2a_l(data, (noOfBits+7)/8, noOfBits);
00098 }
00099 
00100 Base32::~Base32() {
00101     if (binaryResult != NULL && binaryResult != smallBuffer) {
00102         delete [] binaryResult;
00103     }
00104     binaryResult = NULL;
00105 }
00106 
00107 const unsigned char* Base32::getDecoded(int &length) {
00108     length = resultLength;
00109     return binaryResult;
00110 }
00111 
00112 void Base32::b2a_l(const unsigned char* os, int len,
00113                    const size_t lengthinbits) {
00114 
00115     /* if lengthinbits is not a multiple of 8 then this is allocating
00116      * space for 0, 1, or 2 extra quintets that will be truncated at the
00117      * end of this function if they are not needed
00118      */
00119     string result(divceil(len*8, 5), ' ');
00120 
00121     /* index into the result buffer, initially pointing to the
00122      * "one-past-the-end" quintet
00123      */
00124     int resp = result.size();
00125 
00126     /* pointer into the os buffer, initially pointing to the
00127      * "one-past-the-end" octet
00128      */
00129     const unsigned char* osp = os + len;
00130 
00131     /* Now this is a real live Duff's device.  You gotta love it. */
00132 
00133     unsigned long x = 0;        // to hold up to 32 bits worth of the input
00134     switch ((osp - os) % 5) {
00135 
00136         case 0:
00137             do {
00138                 x = *--osp;
00139                 result[--resp] = chars[x % 32]; /* The least sig 5 bits go into the final quintet. */
00140                 x /= 32;        /* ... now we have 3 bits worth in x... */
00141                 case 4:
00142                     x |= ((unsigned long)(*--osp)) << 3; /* ... now we have 11 bits worth in x... */
00143                     result[--resp] = chars[x % 32];
00144                     x /= 32; /* ... now we have 6 bits worth in x... */
00145                     result[--resp] = chars[x % 32];
00146                     x /= 32; /* ... now we have 1 bits worth in x... */
00147                 case 3:
00148                     x |= ((unsigned long)(*--osp)) << 1; /* The 8 bits from the 2-indexed octet.
00149                                                             So now we have 9 bits worth in x... */
00150                     result[--resp] = chars[x % 32];
00151                     x /= 32; /* ... now we have 4 bits worth in x... */
00152                 case 2:
00153                     x |= ((unsigned long)(*--osp)) << 4; /* The 8 bits from the 1-indexed octet.
00154                                                             So now we have 12 bits worth in x... */
00155                     result[--resp] = chars[x%32];
00156                     x /= 32; /* ... now we have 7 bits worth in x... */
00157                     result[--resp] = chars[x%32];
00158                     x /= 32; /* ... now we have 2 bits worth in x... */
00159                 case 1:
00160                     x |= ((unsigned long)(*--osp)) << 2; /* The 8 bits from the 0-indexed octet.
00161                                                             So now we have 10 bits worth in x... */
00162                     result[--resp] = chars[x%32];
00163                     x /= 32; /* ... now we have 5 bits worth in x... */
00164                     result[--resp] = chars[x];
00165             } while (osp > os);
00166     } /* switch ((osp - os.buf) % 5) */
00167 
00168     /* truncate any unused trailing zero quintets */
00169     encoded = result.substr(0, divceil(lengthinbits, 5));
00170     return;
00171 }
00172 
00173 void Base32::a2b_l(const string cs, size_t size, const size_t lengthinbits ) {
00174     unsigned long x = 0;        // to hold up to 32 bits worth of the input
00175 
00176     int len = divceil(size*5, 8);
00177 
00178     /* if lengthinbits is not a multiple of 5 then this is
00179      * allocating space for 0 or 1 extra octets that will be
00180      * truncated at the end of this function if they are
00181      * not needed
00182      */
00183 
00184     if (len < 128) {
00185         binaryResult = smallBuffer;
00186     }
00187     else {
00188         binaryResult = new unsigned char[len];
00189     }
00190 
00191     /* pointer into the result buffer, initially pointing to
00192      * the "one-past-the-end" octet
00193      */
00194     unsigned char* resp = binaryResult + len;
00195 
00196     /* index into the input buffer, initially pointing to the
00197      * "one-past-the-end" character
00198      */
00199     int csp = size;
00200 
00201     /* Now this is a real live Duff's device.  You gotta love it. */
00202     switch (csp % 8) {
00203         case 0:
00204             do {
00205                 x = revchars[cs[--csp]]; /* 5 bits... */
00206                 case 7:
00207                     x |= revchars[cs[--csp]] << 5; /* 10 bits... */
00208                     *--resp = x % 256;
00209                     x /= 256; /* 2 bits... */
00210                 case 6:
00211                     x |= revchars[cs[--csp]] << 2; /* 7 bits... */
00212                 case 5:
00213                     x |= revchars[cs[--csp]] << 7; /* 12 bits... */
00214                     *--resp = x % 256;
00215                     x /= 256; /* 4 bits... */
00216                 case 4:
00217                     x |= revchars[cs[--csp]] << 4; /* 9 bits... */
00218                     *--resp = x % 256;
00219                     x /= 256; /* 1 bit... */
00220                 case 3:
00221                     x |= revchars[cs[--csp]] << 1; /* 6 bits... */
00222                 case 2:
00223                     x |= revchars[cs[--csp]] << 6; /* 11 bits... */
00224                     *--resp = x % 256;
00225                     x /= 256; /* 3 bits... */
00226                 case 1:
00227                     x |= revchars[cs[--csp]] << 3; /* 8 bits... */
00228                     *--resp = x % 256;
00229             } while (csp);
00230     } /* switch ((csp - cs.buf) % 8) */
00231 
00232     /* truncate any unused trailing zero octets */
00233     resultLength = divceil(lengthinbits, 8);
00234     return;
00235 }
00236 
00237 #ifdef UNIT_TEST
00238 #include <math.h>
00239 
00240 
00241 uint8* randz(const size_t len)
00242 {
00243     uint8* result = (uint8*)malloc(len);
00244     size_t i;
00245     for (i=0; i<len; i++) {
00246         result[i] = rand() % 256;
00247     }
00248     return result;
00249 }
00250 
00251 int main(int argc, char *argv[]) {
00252 
00253     int32 resLen;
00254     string a;
00255     const uint8* zrecovered;
00256     uint8 ones[] = {1, 1, 1, 1, 1};
00257 
00258     // Encode all bits of the 5 one bytes (= 40 bits)
00259     a = Base32(ones, 5*8).getEncoded();
00260 
00261     // The string should be: "yryonyeb"
00262     cout << "Encoded 5 ones: '" << a << "', Expected: 'yryonyeb'" << endl;
00263 
00264     // Now decode all bits and check
00265     Base32 *y = new Base32(a);
00266     zrecovered = y->getDecoded(resLen);
00267     if (resLen != 5 && memcmp(ones, zrecovered, 5)) {
00268         printf("Failed basic 5 ones recovery test.\n");
00269         return -1;
00270     }
00271     delete y;
00272 
00273     a = Base32(ones, 15).getEncoded();
00274     cout << "Encoded 5 ones, 15 bits only: '" << a << "', Expected: 'yry'" << endl;
00275     // now decode 15 bits (out of 40 possible)
00276     y = new Base32(a, 15);
00277     zrecovered = y->getDecoded(resLen);
00278     printf("Decoded 15 bits, result length: %d (should be 2)\n", resLen);
00279     printf("Decoded bytes: %x %x (should be 1 0)\n", zrecovered[0], zrecovered[1]);
00280     delete y;
00281 
00282     for (int i = 0; i < 2; i++) {
00283         uint8* z = randz(16);
00284         a = Base32(z, 16*8).getEncoded();
00285 //        cout << "Result: " << a << endl;
00286         assert (a.size() == Base32::b2alen(16*8));
00287         Base32 *x = new Base32(a);
00288         zrecovered = x->getDecoded(resLen);
00289         if (resLen != 16 && memcmp(z, zrecovered, 16)) {
00290             printf("Failed basic recovery test.\n");
00291             return -1;
00292         }
00293         delete x;
00294         free((void*)z);
00295     }
00296 }
00297 #endif

© sourcejam.com 2005-2008