ADAMKDEAN

base64 decode explained

Published Monday, 2 May 2016

This is part 2 of a series on base64 encoding/decoding, based on a kata I recently completed at codewars. I've used base64 a lot but never have I delved into it enough to understand exactly what goes on. So I took the time to explain via inline comments. I hope you enjoy reading it as much as I enjoyed writing it. Part 1 - base64 encode explained.

String.prototype.fromBase64 = function () {
  const base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef' +
                      'ghijklmnopqrstuvwxyz0123456789+/';
  let result = '',
      encoded = '';

  // step 1. convert base64chars into reverse lookup object
  const base64inv = {};
  for (let i = 0; i < base64chars.length; i++)
    base64inv[base64chars[i]] = i;

  // step 2. remove any characters that are not base64 or padding
  const base64regex = new RegExp(`[^${base64chars}=]`, 'g');
  encoded = this.replace(base64regex, '');

  // step 3. replace padding at the end with A (remember, A equals zero)
  const onePadding = encoded.charAt(encoded.length - 1) === '=';
  const twoPadding = encoded.charAt(encoded.length - 2) === '=';  
  const padding = onePadding ? twoPadding ? 'AA' : 'A' : '';
  encoded = encoded.substring(0, encoded.length - padding.length) + padding;

  // step 4. iterate over the encoded string, four characters at a time
  for (let i = 0; i < encoded.length; i += 4) {

    // step 5. convert the four base64 characters into 6-bit numbers using
    //         the base64 character -> 6-bit number map above
    const dn = base64inv[encoded.charAt(i)];
    const en = base64inv[encoded.charAt(i + 1)];
    const fn = base64inv[encoded.charAt(i + 2)];
    const gn = base64inv[encoded.charAt(i + 3)];

    // step 6. convert these four 6-bit numbers into  one 24-bit number
    //
    // if you remember from before, we split a 24-bit number into four 6-bit numbers:
    //
    // e.g.   00001111 00000101 00001010
    // to     |----||- ---||--- -||----|
    //         d     e      f      g
    //
    // d =    00000000 00000000 00000011
    // e =    00000000 00000000 00110000
    // f =    00000000 00000000 00010100
    // g =    00000000 00000000 00001010
    //
    //
    // we need to left shift them (<<) so that they all line up
    // 
    // 00000000 00000000 00XXXXXX (we have four of these)
    // DDDDDDEE EEEEFFFF FFGGGGGG (we want one of these)        
    const d = dn << 18;      // DDDDDD00 00000000 00000000
    const e = en << 12;      // 000000EE EEEE0000 00000000
    const f = fn << 6;       // 00000000 0000FFFF FF000000
    const g = gn;            // 00000000 00000000 00GGGGGG
    const n = d + e + f + g; // DDDDDDEE EEEEFFFF FFGGGGGG (yay!)

    // step 7. split this 24-bit number into three 8-bit (ASCII) characters
    //
    // if you remember, we had three of these (8-bit): 00000000
    // and we actually wanted one of these (24-bit): 00000000 00000000 00000000
    //
    // to get this, we shift the first number 16 bits left, and the second, 8 bits left:
    //
    // 00000000 <------- -------- first char << 16
    //          00000000 <------- second char << 8
    //                   00000000 third char (no shift)
    //
    // so now we want to reverse this and reclaim our three 8-bit (ASCII) characters,
    // we can do this by shifting the numbers back over to the right, and applying a
    // 255 value logical AND (&) bit mask to ignore anything in the 16 bits on the left
    //
    // e.g.   00001111 00000101 00001010
    // to     |------| |------| |------|
    //         a        b        c
    //
    // >>> 16 00000000 00000000 00001111
    // & 255  00000000 00000000 11111111
    // a =    00000000 00000000 00001111
    //                            
    // >>> 8  00000000 00001111 00000101
    // & 255  00000000 00000000 11111111
    // b =    00000000 00000000 00000101
    //
    // noop   00001111 00000101 00001010
    // & 255  00000000 00000000 11111111
    // c =    00000000 00000000 00001010
    const a = (n >>> 16) & 255;
    const b = (n >>> 8) & 255;
    const c = n & 255;

    // step 8. turn these three 8-bit numbers into ASCII characters, and append to result
    result += String.fromCharCode(a, b, c);
  }

  // step 8. finally, remove any padding that was previously added to make this a multiple of 3
  return result.substring(0, result.length - padding.length);
};

base64 encode explained

Published Monday, 2 May 2016

This is from a kata I recently completed at codewars. I've used base64 a lot but never have I delved into it enough to understand exactly what goes on. So I took the time to explain via inline comments. I hope you enjoy reading it as much as I enjoyed writing it. Part 2 - base64 decode explained.

String.prototype.toBase64 = function () {  
  const base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef' +
                      'ghijklmnopqrstuvwxyz0123456789+/';

  let plaintext = this,
      result = '',
      padding = '';

  // step 1. ensure that the string is a multiple of three chars
  if (plaintext.length % 3 > 0) {
    for(let count = 0; count < 3; count++) {
      padding += '=';
      plaintext += '\0';
    }
  }

  // step 2. iterate over the input string, three chars at a time
  for (let i = 0; i < plaintext.length; i += 3) {
    // step 3. take three 8-bit (ASCII) chars, and store
    //         them as one single 24-bit number
    //
    // 00000000 8-bit (1 byte)
    // 00000000 00000000 00000000 24-bit (3 bytes)
    //
    // we'll bitshift the first number two bytes (16 bits)
    // we'll bitshift the second number one byte (8 bits)
    // and we'll pop the other number into the third byte
    //
    // 00000000 <------- -------- first char << 16
    //          00000000 <------- second char << 8
    //                   00000000 third char (no shift)    
    const a = plaintext.charCodeAt(i) << 16;
    const b = plaintext.charCodeAt(i + 1) << 8;
    const c = plaintext.charCodeAt(i + 2);
    const n = a + b + c;

    // step 4. separate this 24-bit number into four 6-bit numbers
    //
    // we'll do this by shifting to the right (with zero pad >>>)
    // and then doing a logical AND (&) to strip everything after 
    // the first (right most) six bits
    //
    // e.g.   00001111 00000101 00001010
    // to     |----||- ---||--- -||----|
    //         d     e      f      g
    //
    // >>> 18 00000000 00000000 00000011
    // & 63   00000000 00000000 00111111
    // d =    00000000 00000000 00000011
    //                            
    // >>> 12 00000000 00000000 11110000 
    // & 63   00000000 00000000 00111111
    // e =    00000000 00000000 00110000
    //
    // >>> 6  00000000 00111100 00010100 
    // & 63   00000000 00000000 00111111
    // f =    00000000 00000000 00010100
    //
    // noop   00001111 00000101 00001010
    // & 63   00000000 00000000 00111111
    // g =    00000000 00000000 00001010
    const d = (n >>> 18) & 63;
    const e = (n >>> 12) & 63;
    const f = (n >>> 6) & 63;
    const g = n & 63;

    // step 5. use the four 6-bit numbers as indices to pluck
    //         chars from our char array above, and add to the
    //         result string, before continuing with the loop
    //
    // this works because a 6-bit number is 0-63, and we have
    // 64 characters above. Therefore, we can pluck out chars
    result += base64chars[d];
    result += base64chars[e];
    result += base64chars[f];
    result += base64chars[g];
  }

  // step 6. finally, we'll remove the zero pad we added above
  //         and add the actual padding, then return this string
  return result.substring(0, result.length - padding.length) + padding;
};

List all files changed in last commit

Published Monday, 8 February 2016

List all files changed in the last commit by using git diff-tree on HEAD.

git diff-tree --no-commit-id --name-only -r HEAD

For example, if you changed README.md in your last commit:

adam@macbook:project (master) $ git diff-tree --no-commit-id --name-only -r HEAD
README.md

Clutter free Unity/VSCode

Published Sunday, 24 January 2016

So, it's 2016. It's been over two months since my last post. I've just been so busy recently, with work being emotionally tiring and with a baby on the way, I've just been busy with real life and not really had much chance to do much else. I've decided that I need to enjoy programming. I need to use my ability for good. So I'm going to make games.

I've dabbled in game development before but it's always been unchannelled, uncontrolled, and that isn't a good thing. The first step to being able to enjoy something is to enjoy your environment, and for us devs, that means our development environment. I'm using OS X, so things are sometimes different to 90% of the internet. Unity ships with MonoDevelop, which fair enough, does it's job, but it's pretty shit. Luckily, VSCode works on OS X and though I'm now a convert, I have always like Visual Studio ever since I started using it 16 years ago with VB6.

A chap named @reapazor wrote a VSCode integration script for Unity which works really well, but my OCD goes wild at all the miscellaneous files which show up in the treeview. It just doesn't look good. Note: I had to install VSCode from the asset store for it to work properly.

Cluttered treeview

This can be fixed by exlcuding a few files/directories in your user settings.json file (which you can access with cmd + ,). If you ever need to access these files, just remove them from the exclusion list.

Update I've realised just now (25/01/16 14:39) that the VSCode plugin actually has an option to do this for you, in the preferences, "Write Workspace Settings". I guess it didn't jump out at me at the time but this also works. All you need to do is append two lines to the .vscode/settings.json file to clear up a few other files you may not want to see:

"**/*.csproj":true,
"**/*.sln":true

The full list is at the end of this post. It will result in lower blood pressure:

Lower blood pressure with Unity + VSCode

Well, hopefully I'll be posting some interesting posts this year. I'll be using C# for game dev, ES6 at work, and with a baby on the way, there will be lots of non-computer related discoveries too I'm sure.

Here is to a great 2016, and here is your complete settings.json file:

{
    "files.exclude":
    {
        "**/.DS_Store":true,
        "**/.git":true,
        "**/.gitignore":true,
        "**/.gitmodules":true,
        "**/*.booproj":true,
        "**/*.pidb":true,
        "**/*.suo":true,
        "**/*.user":true,
        "**/*.userprefs":true,
        "**/*.unityproj":true,
        "**/*.dll":true,
        "**/*.exe":true,
        "**/*.pdf":true,
        "**/*.mid":true,
        "**/*.midi":true,
        "**/*.wav":true,
        "**/*.gif":true,
        "**/*.ico":true,
        "**/*.jpg":true,
        "**/*.jpeg":true,
        "**/*.png":true,
        "**/*.psd":true,
        "**/*.tga":true,
        "**/*.tif":true,
        "**/*.tiff":true,
        "**/*.3ds":true,
        "**/*.3DS":true,
        "**/*.fbx":true,
        "**/*.FBX":true,
        "**/*.lxo":true,
        "**/*.LXO":true,
        "**/*.ma":true,
        "**/*.MA":true,
        "**/*.obj":true,
        "**/*.OBJ":true,
        "**/*.asset":true,
        "**/*.cubemap":true,
        "**/*.flare":true,
        "**/*.mat":true,
        "**/*.meta":true,
        "**/*.prefab":true,
        "**/*.unity":true,
        "build/":true,
        "Build/":true,
        "Library/":true,
        "library/":true,
        "obj/":true,
        "Obj/":true,
        "ProjectSettings/":true,
        "temp/":true,
        "Temp/":true,
        "**/*.csproj":true,
        "**/*.sln":true
    }
}

Change keyboard layout on Ubuntu + Xrdp

Published Monday, 30 November 2015

If you're using Ubuntu with Xrdp, and you find the keyboard to be infuriatingly inaccurate, you should probably change it. To do this, you need to have the ability to open the System Settings window, which you can't always do over RDP. In there, go to Text Entry, and click the little plus at the bottom. Now select the keyboard layout that applies to you, and test it works.

Now, finally, to make these settings apply to Xrdp, run the following command:

sudo xrdp-genkeymap /etc/xrdp/km-0409.ini

Logout, log back in with Xrdp and it should now work.

 
Showing posts 1-5 of 180