Skip to content

Instantly share code, notes, and snippets.

@jcoglan
Created December 16, 2013 14:22
Show Gist options
  • Save jcoglan/7987659 to your computer and use it in GitHub Desktop.
Save jcoglan/7987659 to your computer and use it in GitHub Desktop.
(function() {
'use strict';
var indexOf = function(list, needle) {
if (list.indexOf) return list.indexOf(needle);
for (var i = 0, n = list.length; i < n; i++) {
if (list[i] === needle) return i;
}
return -1;
};
var pad = function(n, b, k) {
n = n.toString(b);
return Array(k + 1 - n.length).join('0') + n;
};
var Base64 = {
CHARS: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''),
decode: function(string) {
var data = [],
chars = Base64.CHARS,
n = string.length,
i, c, offset, chunk, padding;
for (offset = 0; offset < n; offset += 4) {
chunk = [];
padding = 0;
for (i = 0; i < 4; i++) {
c = string[offset + i];
if (c === '=')
padding += 1;
else
chunk[i] = pad(indexOf(chars, c), 2, 6);
}
chunk = chunk.join('').match(/.{8}/g);
for (i = 0; i < 3 - padding; i++) {
data[data.length] = parseInt(chunk[i], 2);
}
}
return data;
},
encode: function(data) {
var string = '',
chars = Base64.CHARS,
n = data.length,
i, c, offset, chunk, padding;
for (offset = 0; offset < n; offset += 3) {
chunk = [];
padding = 0;
for (i = 0; i < 3; i++) {
c = data[offset + i];
if (c === undefined)
padding += 1;
else
chunk[i] = pad(c, 2, 8);
}
for (i = 0; i < padding; i++) chunk.push('00000000');
chunk = chunk.join('').match(/.{6}/g);
for (i = 0; i < 4 - padding; i++) {
string += chars[parseInt(chunk[i], 2)];
}
while (padding--) string += '=';
}
return string;
}
};
var Hex = {
decode: function(string) {
var data = [];
for (var i = 0, n = string.length; i < n; i += 2) {
data[i / 2] = parseInt(string.substr(i, 2), 16);
}
return data;
},
encode: function(data) {
var string = '';
for (var i = 0, n = data.length; i < n; i++) {
string += pad(data[i], 16, 2);
}
return string;
}
};
var UTF8 = {
decode: function(string) {
var data = [],
n = string.length,
c, b;
for (var i = 0; i < string.length; i++) {
c = string.charCodeAt(i);
if (c >= 0xd800 && c <= 0xdbff) {
c = 0x10000 + (c - 0xd800) * 0x400 + (string.charCodeAt(i + 1) - 0xdc00);
i += 1;
}
if (c <= 0x7f) {
data[data.length] = c;
} else if (c <= 0x7ff) {
b = pad(c, 2, 11);
data.push(parseInt('110' + b.substr(0,5), 2), parseInt('10' + b.substr(5,6), 2));
} else if (c <= 0xffff) {
b = pad(c, 2, 16);
data.push(parseInt('1110' + b.substr(0,4), 2), parseInt('10' + b.substr(4,6), 2), parseInt('10' + b.substr(10,6), 2));
} else if (c <= 0x1fffff) {
b = pad(c, 2, 21);
data.push(parseInt('11110' + b.substr(0,3), 2), parseInt('10' + b.substr(3,6), 2), parseInt('10' + b.substr(9,6), 2), parseInt('10' + b.substr(15,6), 2));
} else if (c <= 0x3ffffff) {
b = pad(c, 2, 26);
data.push(parseInt('111110' + b.substr(0,2), 2), parseInt('10' + b.substr(2,6), 2), parseInt('10' + b.substr(8,6), 2), parseInt('10' + b.substr(14,6), 2), parseInt('10' + b.substr(20,6), 2));
} else if (c <= 0x7fffffff) {
b = pad(c, 2, 31);
data.push(parseInt('1111110' + b.substr(0,1), 2), parseInt('10' + b.substr(1,6), 2), parseInt('10' + b.substr(7,6), 2), parseInt('10' + b.substr(13,6), 2), parseInt('10' + b.substr(19,6), 2), parseInt('10' + b.substr(25,6), 2));
}
}
return data;
},
encode: function(data) {
var codepoints = [],
offset = 0,
n = data.length,
i, c, binary, match;
while (offset < n) {
c = data[offset];
binary = '';
if (c <= 127) {
match = pad(c, 2, 7).match(/^(.*)$/);
offset += 1;
} else if (c <= 223) {
match = (pad(data[offset], 2, 8) + pad(data[offset + 1], 2, 8)).match(/^110(.{5})10(.{6})$/);
offset += 2;
} else if (c <= 239) {
for (i = 0; i < 3; i++) binary += pad(data[offset + i], 2, 8);
match = binary.match(/^1110(.{4})10(.{6})10(.{6})$/);
offset += 3;
} else if (c <= 247) {
for (i = 0; i < 4; i++) binary += pad(data[offset + i], 2, 8);
match = binary.match(/^11110(.{3})10(.{6})10(.{6})10(.{6})$/);
offset += 4;
} else if (c <= 251) {
for (i = 0; i < 5; i++) binary += pad(data[offset + i], 2, 8);
match = binary.match(/^111110(.{2})10(.{6})10(.{6})10(.{6})10(.{6})$/);
offset += 5;
} else if (c <= 253) {
for (i = 0; i < 6; i++) binary += pad(data[offset + i], 2, 8);
match = binary.match(/^1111110(.)10(.{6})10(.{6})10(.{6})10(.{6})10(.{6})$/);
offset += 6;
}
if (!match) throw new Error('UTF-8 encoding error');
binary = '';
for (i = 1; i < match.length; i++) binary += match[i];
c = parseInt(binary, 2);
if (c <= 0xffff) {
codepoints[codepoints.length] = c;
} else {
c -= 0x10000;
codepoints[codepoints.length] = 0xd800 + (Math.floor(c / 0x400) & 0x3ff);
codepoints[codepoints.length] = 0xdc00 + (c & 0x3ff);
}
}
return String.fromCharCode.apply(String, codepoints);
}
};
var Buffer = function(data, encoding) {
if (typeof data === 'string') {
encoding = encoding || 'utf8';
data = Buffer.ENCODERS[encoding].decode(data);
}
this._data = data;
this.length = data.length;
};
Buffer.ENCODERS = {
base64: Base64,
hex: Hex,
utf8: UTF8
};
Buffer.prototype.toString = function(encoding) {
encoding = encoding || 'utf8';
if (encoding === 'binary') return this;
return Buffer.ENCODERS[encoding].encode(this._data);
};
Buffer.prototype.inspect = function() {
return '<Buffer ' + this.toString('hex').match(/../g).join(' ') + '>';
};
if (typeof module !== 'undefined')
module.exports = Buffer;
else if (typeof window !== 'undefined')
window.Buffer = Buffer;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment