220 lines
5.5 KiB
JavaScript
220 lines
5.5 KiB
JavaScript
var BinaryBuffer = function() {
|
|
|
|
this.bufferSize = 32;
|
|
this.buffer = new Uint8Array(this.bufferSize);
|
|
this.length = 0;
|
|
|
|
};
|
|
|
|
BinaryBuffer.prototype.append = function(v) {
|
|
if (this.length >= this.bufferSize) {
|
|
this.bufferSize *= 2;
|
|
var newBuffer = new Uint8Array(this.bufferSize);
|
|
newBuffer.set(this.buffer);
|
|
this.buffer = newBuffer;
|
|
}
|
|
this.buffer[this.length] = v;
|
|
this.length++;
|
|
};
|
|
|
|
BinaryBuffer.prototype.compact = function() {
|
|
this.bufferSize = this.length;
|
|
var newBuffer = new Uint8Array(this.bufferSize);
|
|
newBuffer.set(this.buffer, 0, newBuffer.length);
|
|
this.buffer = newBuffer;
|
|
};
|
|
|
|
var Unicode = {};
|
|
|
|
Unicode.toUTF8 = function(s) {
|
|
var index = 0;
|
|
var buffer = new BinaryBuffer();
|
|
|
|
while (index < s.length) {
|
|
var codePoint;
|
|
var code = s.charCodeAt(index);
|
|
index++;
|
|
if (code >= 0xd800 && code < 0xdc00) {
|
|
if (index >= s.length) {
|
|
throw "Bad character";
|
|
}
|
|
var code2 = s.charCodeAt(index);
|
|
index++;
|
|
if (code2 < 0xdc00 || code2 >= 0xe000) {
|
|
throw "Bad character";
|
|
}
|
|
codePoint = (code - 0xd800 << 10) + code2 - 0xdc00 + 0x10000;
|
|
} else {
|
|
codePoint = code;
|
|
}
|
|
|
|
if (codePoint < 0x80) {
|
|
buffer.append(codePoint);
|
|
} else if (codePoint < 0x800) {
|
|
buffer.append(0xc0 | codePoint >>> 6);
|
|
buffer.append(0x80 | (codePoint & 0x3f));
|
|
} else if (codePoint < 0x10000) {
|
|
buffer.append(0xe0 | codePoint >>> 12);
|
|
buffer.append(0x80 | (codePoint >>> 6 & 0x3f));
|
|
buffer.append(0x80 | (codePoint & 0x3f));
|
|
} else if (codePoint < 0x200000) {
|
|
buffer.append(0xf0 | codePoint >>> 18);
|
|
buffer.append(0x80 | (codePoint >>> 12 & 0x3f));
|
|
buffer.append(0x80 | (codePoint >>> 6 & 0x3f));
|
|
buffer.append(0x80 | (codePoint & 0x3f));
|
|
} else {
|
|
throw "Bad code point";
|
|
break;
|
|
}
|
|
}
|
|
|
|
buffer.compact;
|
|
return buffer.buffer;
|
|
};
|
|
|
|
Unicode.fromUTF8 = function(buffer) {
|
|
var s = '';
|
|
var index = 0;
|
|
|
|
while (index < buffer.length) {
|
|
var head = buffer[index];
|
|
var n;
|
|
if ((head & 0x80) == 0x00) {
|
|
n = 1;
|
|
} else if ((head & 0xe0) == 0xc0) {
|
|
n = 2;
|
|
} else if ((head & 0xf0) == 0xe0) {
|
|
n = 3;
|
|
} else if ((head & 0xf8) == 0xf0) {
|
|
n = 4;
|
|
} else if ((head & 0xfc) == 0xf8) {
|
|
n = 5;
|
|
} else if ((head & 0xfe) == 0xfc) {
|
|
n = 6;
|
|
} else {
|
|
break;
|
|
}
|
|
var b = [];
|
|
for (var i = 0; i < n; i++) {
|
|
b[i] = buffer[index];
|
|
index++;
|
|
}
|
|
|
|
var codePoint;
|
|
switch (b.length) {
|
|
case 1:
|
|
codePoint = b[0];
|
|
break;
|
|
case 2:
|
|
codePoint = (b[0] & 0x1f) << 6 | (b[1] & 0x3f);
|
|
break;
|
|
case 3:
|
|
codePoint = (b[0] & 0x0f) << 12 | (b[1] & 0x3f) << 6 | (b[2] & 0x3f);
|
|
break;
|
|
case 4:
|
|
codePoint = (b[0] & 0x07) << 18 | (b[1] & 0x3f) << 12 | (b[2] & 0x3f) << 6 | (b[3] & 0x3f);
|
|
break;
|
|
case 5:
|
|
throw "Parse error";
|
|
case 6:
|
|
throw "Parse error";
|
|
default:
|
|
throw "Unreachable";
|
|
break;
|
|
}
|
|
|
|
if (codePoint < 0x10000) {
|
|
s += String.fromCharCode(codePoint);
|
|
} else {
|
|
s += String.fromCharCode(codePoint - 0x10000 >>> 10 + 0xd800);
|
|
s += String.fromCharCode((codePoint - 0x10000 & 0x3ff) + 0xdc00);
|
|
}
|
|
}
|
|
|
|
return s;
|
|
};
|
|
|
|
var Base64 = {};
|
|
|
|
Base64.encoderMap = [
|
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
|
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
|
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
|
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
|
|
];
|
|
|
|
Base64.decoderMap = {
|
|
'A':0, 'B':1, 'C':2, 'D':3, 'E':4, 'F':5, 'G':6, 'H':7, 'I':8, 'J':9, 'K':10, 'L':11, 'M':12, 'N':13, 'O':14, 'P':15,
|
|
'Q':16, 'R':17, 'S':18, 'T':19, 'U':20, 'V':21, 'W':22, 'X':23, 'Y':24, 'Z':25, 'a':26, 'b':27, 'c':28, 'd':29, 'e':30, 'f':31,
|
|
'g':32, 'h':33, 'i':34, 'j':35, 'k':36, 'l':37, 'm':38, 'n':39, 'o':40, 'p':41, 'q':42, 'r':43, 's':44, 't':45, 'u':46, 'v':47,
|
|
'w':48, 'x':49, 'y':50, 'z':51, '0':52, '1':53, '2':54, '3':55, '4':56, '5':57, '6':58, '7':59, '8':60, '9':61, '+':62, '/':63,
|
|
};
|
|
|
|
Base64.getBase64Index = function(b, i) {
|
|
// 00000011 11112222 22333333
|
|
var j = Math.floor(i / 4) * 3;
|
|
switch (i % 4) {
|
|
case 0:
|
|
return (b[j] & 0xfc) >>> 2;
|
|
case 1:
|
|
if (j + 1 < b.length) {
|
|
return (b[j] & 0x03) << 4 | (b[j + 1] & 0xf0) >>> 4;
|
|
} else {
|
|
return (b[j] & 0x03) << 4;
|
|
}
|
|
case 2:
|
|
if (j + 2 < b.length) {
|
|
return (b[j + 1] & 0x0f) << 2 | (b[j + 2] & 0xc0) >>> 6;
|
|
} else {
|
|
return (b[j + 1] & 0x0f) << 2;
|
|
}
|
|
case 3:
|
|
return b[j + 2] & 0x3f;
|
|
default:
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
Base64.encode = function(b) {
|
|
var meanSize = Math.floor((b.length * 8 + 5) / 6);
|
|
var resultSize = Math.floor((meanSize + 3) / 4) * 4;
|
|
var sb = '';
|
|
for (var i = 0; i < meanSize; i++) {
|
|
sb += this.encoderMap[this.getBase64Index(b, i)];
|
|
}
|
|
for (var i = meanSize; i < resultSize; i++) {
|
|
sb += '=';
|
|
}
|
|
return sb;
|
|
};
|
|
|
|
Base64.getRawByte = function(s, i) {
|
|
// 00000011 11112222 22333333
|
|
var j = Math.floor(i * 8 / 6 / 4) * 4;
|
|
switch (i % 3) {
|
|
case 0:
|
|
return this.decoderMap[s.charAt(j)] << 2 | this.decoderMap[s.charAt(j + 1)] >>> 4;
|
|
case 1:
|
|
return this.decoderMap[s.charAt(j + 1)] << 4 & 0xf0 | this.decoderMap[s.charAt(j + 2)] >>> 2;
|
|
case 2:
|
|
return this.decoderMap[s.charAt(j + 2)] << 6 & 0xc0 | this.decoderMap[s.charAt(j + 3)];
|
|
default:
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
Base64.decode = function(s) {
|
|
var meanSize = s.length;
|
|
for (var i = s.length - 1; i >= 0; i--) {
|
|
if (s.charAt(i) == '=') {
|
|
meanSize--;
|
|
}
|
|
}
|
|
var resultSize = Math.floor(meanSize * 6 / 8);
|
|
var result = new Uint8Array(resultSize);
|
|
for (var i = 0; i < resultSize; i++) {
|
|
result[i] = this.getRawByte(s, i);
|
|
}
|
|
return result;
|
|
};
|