Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Since this seems to be the number one google hit on base64 encoding and iphone, I felt like sharing my experience with the code snippet above.</p> <p>It works, but it is extremely slow. A benchmark on a random image (0.4 mb) took 37 seconds on native iphone. The main reason is probably all the OOP magic - single char NSStrings etc, which are only autoreleased after the encoding is done.</p> <p>Another suggestion posted here (ab)uses the openssl library, which feels like overkill as well.</p> <p>The code below takes 70 ms - that's a 500 times speedup. This only does base64 encoding (decoding will follow as soon as I encounter it)</p> <pre><code>+ (NSString *) base64StringFromData: (NSData *)data length: (int)length { int lentext = [data length]; if (lentext &lt; 1) return @""; char *outbuf = malloc(lentext*4/3+4); // add 4 to be sure if ( !outbuf ) return nil; const unsigned char *raw = [data bytes]; int inp = 0; int outp = 0; int do_now = lentext - (lentext%3); for ( outp = 0, inp = 0; inp &lt; do_now; inp += 3 ) { outbuf[outp++] = base64EncodingTable[(raw[inp] &amp; 0xFC) &gt;&gt; 2]; outbuf[outp++] = base64EncodingTable[((raw[inp] &amp; 0x03) &lt;&lt; 4) | ((raw[inp+1] &amp; 0xF0) &gt;&gt; 4)]; outbuf[outp++] = base64EncodingTable[((raw[inp+1] &amp; 0x0F) &lt;&lt; 2) | ((raw[inp+2] &amp; 0xC0) &gt;&gt; 6)]; outbuf[outp++] = base64EncodingTable[raw[inp+2] &amp; 0x3F]; } if ( do_now &lt; lentext ) { char tmpbuf[2] = {0,0}; int left = lentext%3; for ( int i=0; i &lt; left; i++ ) { tmpbuf[i] = raw[do_now+i]; } raw = tmpbuf; outbuf[outp++] = base64EncodingTable[(raw[inp] &amp; 0xFC) &gt;&gt; 2]; outbuf[outp++] = base64EncodingTable[((raw[inp] &amp; 0x03) &lt;&lt; 4) | ((raw[inp+1] &amp; 0xF0) &gt;&gt; 4)]; if ( left == 2 ) outbuf[outp++] = base64EncodingTable[((raw[inp+1] &amp; 0x0F) &lt;&lt; 2) | ((raw[inp+2] &amp; 0xC0) &gt;&gt; 6)]; } NSString *ret = [[[NSString alloc] initWithBytes:outbuf length:outp encoding:NSASCIIStringEncoding] autorelease]; free(outbuf); return ret; } </code></pre> <p>I left out the line-cutting since I didn't need it, but it's trivial to add.</p> <p>For those who are interested in optimizing: the goal is to minimize what happens in the main loop. Therefore all logic to deal with the last 3 bytes is treated outside the loop.</p> <p>Also, try to work on data in-place, without additional copying to/from buffers. And reduce any arithmetic to the bare minimum.</p> <p>Observe that the bits that are put together to look up an entry in the table, would not overlap when they were to be orred together without shifting. A major improvement could therefore be to use 4 separate 256 byte lookup tables and eliminate the shifts, like this:</p> <pre><code>outbuf[outp++] = base64EncodingTable1[(raw[inp] &amp; 0xFC)]; outbuf[outp++] = base64EncodingTable2[(raw[inp] &amp; 0x03) | (raw[inp+1] &amp; 0xF0)]; outbuf[outp++] = base64EncodingTable3[(raw[inp+1] &amp; 0x0F) | (raw[inp+2] &amp; 0xC0)]; outbuf[outp++] = base64EncodingTable4[raw[inp+2] &amp; 0x3F]; </code></pre> <p>Of course you could take it a whole lot further, but that's beyond the scope here.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload