nxkit
Version:
This is a collection of tools, independent of any other libraries
368 lines (367 loc) • 11.7 kB
JavaScript
"use strict";
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2015, xuewen.chu
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, self list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, self list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of xuewen.chu nor the
* names of its contributors may be used to endorse or promote products
* derived from self software without specific prior written permission.
*
* self SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL xuewen.chu BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF self
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = require("./util");
const errno_1 = require("./errno");
var b64pad = '=';
var hex_tab = '0123456789abcdef';
var base64_tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var hex_keys = new Map();
var base64_keys = new Map([['=', 65]]);
hex_tab.split('').forEach((e, i) => (hex_keys.set(e, i), hex_keys.set(e.toUpperCase(), i)));
base64_tab.split('').forEach((e, i) => base64_keys.set(e, i));
// string => bytes
// convert unicode to utf-8 codeing
function encodeUTF8Word(unicode) {
var bytes = [];
if (unicode < 0x7F + 1) { // 单字节编码
bytes.push(unicode);
}
else {
var len = 1;
if (unicode < 0x7FF + 1) { // 两字节编码
len = 2;
bytes.push(0b11000000);
}
else if (unicode < 0xFFFF + 1) { // 三字节编码
len = 3;
bytes.push(0b11100000);
}
else if (unicode < 0x10FFFF + 1) { // 四字节编码
len = 4;
bytes.push(0b11110000);
}
else if (unicode < 0x3FFFFFF + 1) { // 五字节编码
if (unicode > 0x200000 - 1) {
len = 5;
bytes.push(0b11111000);
}
else { // 这个区间没有编码
return bytes;
}
}
else { //六字节编码
len = 6;
bytes.push(0b11111100);
}
for (var i = len - 1; i > 0; i--) {
bytes[i] = 0b10000000 | (unicode & 0b00111111);
unicode >>= 6;
}
bytes[0] |= unicode;
}
return bytes;
}
function encodeUTF8WordLength(unicode) {
if (unicode < 0x7F + 1) { // 单字节编码
return 1;
}
else {
if (unicode < 0x7FF + 1) { // 两字节编码
return 2;
}
else if (unicode < 0xFFFF + 1) { // 三字节编码
return 3;
}
else if (unicode < 0x10FFFF + 1) { // 四字节编码
return 4;
}
else if (unicode < 0x3FFFFFF + 1) { // 五字节编码
if (unicode > 0x200000 - 1) {
return 5;
}
else { // 这个区间没有编码
return 1;
}
}
else { //六字节编码
return 6;
}
}
}
function encodeUTF8Length(str) {
var r = 0;
for (var i = 0, l = str.length; i < l; i++) {
r += encodeUTF8WordLength(str.charCodeAt(i));
}
return r;
}
// string => bytes
// Convert str to utf8 to a bytes
function encodeUTF8(str) {
var bytes = [];
for (var i = 0, l = str.length; i < l; i++) {
bytes.push(...encodeUTF8Word(str.charCodeAt(i)));
}
return bytes;
}
// string => bytes
function encodeLatin1From(str) {
var bytes = [];
for (var i = 0, l = str.length; i < l; i++)
bytes.push(str.charCodeAt(i) % 256);
return bytes;
}
// string => bytes
function encodeAsciiFrom(str) {
var bytes = [];
for (var i = 0, l = str.length; i < l; i++)
bytes.push(str.charCodeAt(i) % 128);
return bytes;
}
// bytes => string
function encodeHexFrom(bytes, start, end) {
checkOffset(bytes, start, end);
var str = '';
for (var i = start; i < end; i++) {
str += hex_tab.charAt(bytes[i] >> 4) + hex_tab.charAt(bytes[i] & 0xF);
}
return str;
}
// bytes => string
function encodeBase64From(bytes, start, end) {
checkOffset(bytes, start, end);
var size = end - start;
var str = '';
for (var i = start; i < end; i += 3) {
var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
for (var j = 0; j < 4; j++) {
if (i * 8 + j * 6 > size * 8)
str += b64pad;
else
str += base64_tab.charAt((triplet >> 6 * (3 - j)) & 0x3F);
}
}
return str;
}
// decode
function checkOffset(bytes, start, end) {
util_1.default.assert(start >= 0, errno_1.default.ERR_BAD_ARGUMENT);
util_1.default.assert(end >= start, errno_1.default.ERR_BAD_ARGUMENT);
util_1.default.assert(end <= bytes.length, errno_1.default.ERR_BAD_ARGUMENT);
util_1.default.assert(start <= end, errno_1.default.ERR_BAD_ARGUMENT);
}
// convert utf8 bytes to unicode
function decodeUTF8Word(bytes, offset) {
var str = offset;
var c = bytes[str];
str++;
if ((c & 0x80) == 0) { // 小于 128 (c & 10000000) == 00000000
//uft8单字节编码 0xxxxxxx
return [1, c];
}
else if ((c & 0xe0) == 0xc0) { // (c & 11100000) == 11000000
//uft8双字节编码 110xxxxx 10xxxxxx
var r_c = 0;
var c2 = bytes[str];
str++;
r_c |= (c2 & ~0xc0);
r_c |= ((c & ~0xe0) << 6);
return [2, r_c];
}
else if ((c & 0xf0) == 0xe0) { //(c & 11110000) == 11100000
//uft8三字节编码 1110xxxx 10xxxxxx 10xxxxxx
var r_c = 0;
var c2 = bytes[str];
str++;
var c3 = bytes[str];
str++;
r_c |= (c3 & ~0xc0);
r_c |= ((c2 & ~0xc0) << 6);
r_c |= ((c & ~0xf0) << 12);
return [3, r_c];
}
else if ((c & 0xf8) == 0xf0) { // (c & 11111000) == 11110000
//uft8四字节编码 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
var r_c = 0;
var c2 = bytes[str];
str++;
var c3 = bytes[str];
str++;
var c4 = bytes[str];
str++;
r_c |= (c4 & ~0xc0);
r_c |= ((c3 & ~0xc0) << 6);
r_c |= ((c2 & ~0xc0) << 12);
r_c |= ((c & ~0xf8) << 18);
return [4, r_c];
}
else if ((c & 0xfc) == 0xf8) { // (c & 11111100) == 11111000
//uft8五字节编码 , utf8最多可用6个字节表示31位二进制
var r_c = 0;
var c2 = bytes[str];
str++;
var c3 = bytes[str];
str++;
var c4 = bytes[str];
str++;
var c5 = bytes[str];
str++;
r_c |= (c5 & ~0xc0);
r_c |= ((c4 & ~0xc0) << 6);
r_c |= ((c3 & ~0xc0) << 12);
r_c |= ((c2 & ~0xc0) << 18);
r_c |= ((c & ~0xfc) << 24);
return [5, r_c];
}
else if ((c & 0xfe) == 0xfc) { // (c & 11111110) == 11111100
//uft8六字节编码
var r_c = 0;
var c2 = bytes[str];
str++;
var c3 = bytes[str];
str++;
var c4 = bytes[str];
str++;
var c5 = bytes[str];
str++;
var c6 = bytes[str];
str++;
r_c |= (c6 & ~0xc0);
r_c |= ((c5 & ~0xc0) << 6);
r_c |= ((c4 & ~0xc0) << 12);
r_c |= ((c3 & ~0xc0) << 18);
r_c |= ((c2 & ~0xc0) << 24);
r_c |= ((c & ~0xfe) << 30);
return [6, r_c];
}
return [1, 0]; // skip char
}
// convert utf8 bytes to a str
function decodeUTF8From(bytes, start, end) {
checkOffset(bytes, start, end);
var str = [];
for (var i = start; i < end;) {
var [len, unicode] = decodeUTF8Word(bytes, i);
str.push(String.fromCharCode(unicode));
i += len;
}
return str.join('');
}
// bytes => string
function decodeUTF8(bytes) {
return decodeUTF8From(bytes, 0, bytes.length);
}
// bytes => string
function decodeLatin1From(bytes, start, end) {
checkOffset(bytes, start, end);
var str = '';
for (var i = start; i < end; i++)
str += String.fromCharCode(bytes[i]);
return str;
}
// bytes => string
function decodeAsciiFrom(bytes, start, end) {
checkOffset(bytes, start, end);
var str = '';
for (var i = start; i < end; i++)
str += String.fromCharCode(bytes[i] % 128);
return str;
}
// hex string => bytes
function decodeHex(str) {
var ERR_BAD_ARGUMENT = errno_1.default.ERR_BAD_ARGUMENT;
util_1.default.assert(str.length % 2 === 0, ERR_BAD_ARGUMENT);
var bytes = [];
for (var i = 0, l = str.length; i < l; i += 2) {
var a = hex_keys.get(str[i]);
var b = hex_keys.get(str[i + 1]);
// utils.assert(a !== undefined, ERR_BAD_ARGUMENT);
// utils.assert(b !== undefined, ERR_BAD_ARGUMENT);
bytes.push(a << 4 | b);
}
return bytes;
}
// base64 string => bytes
function decodeBase64(str) {
var ERR_BAD_ARGUMENT = errno_1.default.ERR_BAD_ARGUMENT;
util_1.default.assert(str.length % 4 === 0, ERR_BAD_ARGUMENT);
var bytes = [];
for (var i = 0, l = str.length; i < l; i += 4) {
var a = base64_keys.get(str[i]);
var b = base64_keys.get(str[i + 1]);
var c = base64_keys.get(str[i + 2]);
var d = base64_keys.get(str[i + 3]);
// utils.assert(a !== undefined, ERR_BAD_ARGUMENT);
// utils.assert(b !== undefined, ERR_BAD_ARGUMENT);
// utils.assert(c !== undefined, ERR_BAD_ARGUMENT);
// utils.assert(d !== undefined, ERR_BAD_ARGUMENT);
// console.log(str[i],str[i+1],str[i+2],str[i+3])
// console.log(a,b,c,d)
var triplet;
triplet = (a << 18) | (b << 12);
bytes.push((triplet >> 16) & 0xff); // 1 bytes
if (c == 65)
continue;
triplet |= (c << 6);
bytes.push((triplet >> 8) & 0xff); // 2 bytes
if (d == 65)
continue;
triplet |= d;
bytes.push(triplet & 0xff); // 3 bytes
}
return bytes;
}
/*
* Convert an array of bytes to a hex string.
*/
function convertHexString(bytes) {
return encodeHexFrom(bytes, 0, bytes.length);
}
/*
* Convert an array of bytes to a base64 string.
*/
function convertBase64String(bytes) {
return encodeBase64From(bytes, 0, bytes.length);
}
exports.default = {
// encode
encodeUTF8Word,
encodeUTF8,
encodeLatin1From,
encodeAsciiFrom,
encodeHexFrom,
encodeBase64From,
// decode
decodeUTF8Word,
decodeUTF8From,
decodeUTF8,
decodeLatin1From,
decodeAsciiFrom,
decodeHex,
decodeBase64,
// ext
convertHexString,
convertBase64String,
// length
encodeUTF8WordLength,
encodeUTF8Length,
};