зеркало из https://github.com/mozilla/pluotsorbet.git
707 строки
16 KiB
JavaScript
707 строки
16 KiB
JavaScript
/**
|
|
* Utility functions for web applications.
|
|
*
|
|
* @author Dave Longley
|
|
*
|
|
* Copyright (c) 2010-2014 Digital Bazaar, Inc.
|
|
*/
|
|
(function() {
|
|
/* ########## Begin module implementation ########## */
|
|
function initModule(forge) {
|
|
|
|
/* Utilities API */
|
|
var util = forge.util = forge.util || {};
|
|
|
|
// define isArrayBuffer
|
|
util.isArrayBuffer = function(x) {
|
|
return typeof ArrayBuffer !== 'undefined' && x instanceof ArrayBuffer;
|
|
};
|
|
|
|
// define isArrayBufferView
|
|
var _arrayBufferViews = [];
|
|
if(typeof DataView !== 'undefined') {
|
|
_arrayBufferViews.push(DataView);
|
|
}
|
|
if(typeof Int8Array !== 'undefined') {
|
|
_arrayBufferViews.push(Int8Array);
|
|
}
|
|
if(typeof Uint8Array !== 'undefined') {
|
|
_arrayBufferViews.push(Uint8Array);
|
|
}
|
|
if(typeof Uint8ClampedArray !== 'undefined') {
|
|
_arrayBufferViews.push(Uint8ClampedArray);
|
|
}
|
|
if(typeof Int16Array !== 'undefined') {
|
|
_arrayBufferViews.push(Int16Array);
|
|
}
|
|
if(typeof Uint16Array !== 'undefined') {
|
|
_arrayBufferViews.push(Uint16Array);
|
|
}
|
|
if(typeof Int32Array !== 'undefined') {
|
|
_arrayBufferViews.push(Int32Array);
|
|
}
|
|
if(typeof Uint32Array !== 'undefined') {
|
|
_arrayBufferViews.push(Uint32Array);
|
|
}
|
|
if(typeof Float32Array !== 'undefined') {
|
|
_arrayBufferViews.push(Float32Array);
|
|
}
|
|
if(typeof Float64Array !== 'undefined') {
|
|
_arrayBufferViews.push(Float64Array);
|
|
}
|
|
util.isArrayBufferView = function(x) {
|
|
for(var i = 0; i < _arrayBufferViews.length; ++i) {
|
|
if(x instanceof _arrayBufferViews[i]) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// TODO: set ByteBuffer to best available backing
|
|
util.ByteBuffer = ByteStringBuffer;
|
|
|
|
/** Buffer w/BinaryString backing */
|
|
|
|
/**
|
|
* Constructor for a binary string backed byte buffer.
|
|
*
|
|
* @param [b] the bytes to wrap (either encoded as string, one byte per
|
|
* character, or as an ArrayBuffer or Typed Array).
|
|
*/
|
|
function ByteStringBuffer(b) {
|
|
// TODO: update to match DataBuffer API
|
|
|
|
// the data in this buffer
|
|
this.data = '';
|
|
// the pointer for reading from this buffer
|
|
this.read = 0;
|
|
|
|
if(typeof b === 'string') {
|
|
this.data = b;
|
|
} else if(util.isArrayBuffer(b) || util.isArrayBufferView(b)) {
|
|
// convert native buffer to forge buffer
|
|
// FIXME: support native buffers internally instead
|
|
var arr = new Uint8Array(b);
|
|
try {
|
|
this.data = String.fromCharCode.apply(null, arr);
|
|
} catch(e) {
|
|
for(var i = 0; i < arr.length; ++i) {
|
|
this.putByte(arr[i]);
|
|
}
|
|
}
|
|
} else if(b instanceof ByteStringBuffer ||
|
|
(typeof b === 'object' && typeof b.data === 'string' &&
|
|
typeof b.read === 'number')) {
|
|
// copy existing buffer
|
|
this.data = b.data;
|
|
this.read = b.read;
|
|
}
|
|
}
|
|
util.ByteStringBuffer = ByteStringBuffer;
|
|
|
|
/**
|
|
* Gets the number of bytes in this buffer.
|
|
*
|
|
* @return the number of bytes in this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.length = function() {
|
|
return this.data.length - this.read;
|
|
};
|
|
|
|
/**
|
|
* Gets whether or not this buffer is empty.
|
|
*
|
|
* @return true if this buffer is empty, false if not.
|
|
*/
|
|
util.ByteStringBuffer.prototype.isEmpty = function() {
|
|
return this.length() <= 0;
|
|
};
|
|
|
|
/**
|
|
* Puts a byte in this buffer.
|
|
*
|
|
* @param b the byte to put.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putByte = function(b) {
|
|
this.data += String.fromCharCode(b);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Puts a byte in this buffer N times.
|
|
*
|
|
* @param b the byte to put.
|
|
* @param n the number of bytes of value b to put.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.fillWithByte = function(b, n) {
|
|
b = String.fromCharCode(b);
|
|
var d = this.data;
|
|
while(n > 0) {
|
|
if(n & 1) {
|
|
d += b;
|
|
}
|
|
n >>>= 1;
|
|
if(n > 0) {
|
|
b += b;
|
|
}
|
|
}
|
|
this.data = d;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Puts bytes in this buffer.
|
|
*
|
|
* @param bytes the bytes (as a UTF-8 encoded string) to put.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putBytes = function(bytes) {
|
|
// TODO: update to match DataBuffer API
|
|
this.data += bytes;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Puts a UTF-16 encoded string into this buffer.
|
|
*
|
|
* @param str the string to put.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putString = function(str) {
|
|
this.data += util.encodeUtf8(str);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Puts a 16-bit integer in this buffer in big-endian order.
|
|
*
|
|
* @param i the 16-bit integer.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putInt16 = function(i) {
|
|
this.data +=
|
|
String.fromCharCode(i >> 8 & 0xFF) +
|
|
String.fromCharCode(i & 0xFF);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Puts a 24-bit integer in this buffer in big-endian order.
|
|
*
|
|
* @param i the 24-bit integer.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putInt24 = function(i) {
|
|
this.data +=
|
|
String.fromCharCode(i >> 16 & 0xFF) +
|
|
String.fromCharCode(i >> 8 & 0xFF) +
|
|
String.fromCharCode(i & 0xFF);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Puts a 32-bit integer in this buffer in big-endian order.
|
|
*
|
|
* @param i the 32-bit integer.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putInt32 = function(i) {
|
|
this.data +=
|
|
String.fromCharCode(i >> 24 & 0xFF) +
|
|
String.fromCharCode(i >> 16 & 0xFF) +
|
|
String.fromCharCode(i >> 8 & 0xFF) +
|
|
String.fromCharCode(i & 0xFF);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Puts a 16-bit integer in this buffer in little-endian order.
|
|
*
|
|
* @param i the 16-bit integer.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putInt16Le = function(i) {
|
|
this.data +=
|
|
String.fromCharCode(i & 0xFF) +
|
|
String.fromCharCode(i >> 8 & 0xFF);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Puts a 24-bit integer in this buffer in little-endian order.
|
|
*
|
|
* @param i the 24-bit integer.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putInt24Le = function(i) {
|
|
this.data +=
|
|
String.fromCharCode(i & 0xFF) +
|
|
String.fromCharCode(i >> 8 & 0xFF) +
|
|
String.fromCharCode(i >> 16 & 0xFF);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Puts a 32-bit integer in this buffer in little-endian order.
|
|
*
|
|
* @param i the 32-bit integer.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putInt32Le = function(i) {
|
|
this.data +=
|
|
String.fromCharCode(i & 0xFF) +
|
|
String.fromCharCode(i >> 8 & 0xFF) +
|
|
String.fromCharCode(i >> 16 & 0xFF) +
|
|
String.fromCharCode(i >> 24 & 0xFF);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Puts an n-bit integer in this buffer in big-endian order.
|
|
*
|
|
* @param i the n-bit integer.
|
|
* @param n the number of bits in the integer.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putInt = function(i, n) {
|
|
do {
|
|
n -= 8;
|
|
this.data += String.fromCharCode((i >> n) & 0xFF);
|
|
} while(n > 0);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Puts a signed n-bit integer in this buffer in big-endian order. Two's
|
|
* complement representation is used.
|
|
*
|
|
* @param i the n-bit integer.
|
|
* @param n the number of bits in the integer.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putSignedInt = function(i, n) {
|
|
if(i < 0) {
|
|
i += 2 << (n - 1);
|
|
}
|
|
return this.putInt(i, n);
|
|
};
|
|
|
|
/**
|
|
* Puts the given buffer into this buffer.
|
|
*
|
|
* @param buffer the buffer to put into this one.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.putBuffer = function(buffer) {
|
|
this.data += buffer.getBytes();
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Gets a byte from this buffer and advances the read pointer by 1.
|
|
*
|
|
* @return the byte.
|
|
*/
|
|
util.ByteStringBuffer.prototype.getByte = function() {
|
|
return this.data.charCodeAt(this.read++);
|
|
};
|
|
|
|
/**
|
|
* Gets a uint16 from this buffer in big-endian order and advances the read
|
|
* pointer by 2.
|
|
*
|
|
* @return the uint16.
|
|
*/
|
|
util.ByteStringBuffer.prototype.getInt16 = function() {
|
|
var rval = (
|
|
this.data.charCodeAt(this.read) << 8 ^
|
|
this.data.charCodeAt(this.read + 1));
|
|
this.read += 2;
|
|
return rval;
|
|
};
|
|
|
|
/**
|
|
* Gets a uint24 from this buffer in big-endian order and advances the read
|
|
* pointer by 3.
|
|
*
|
|
* @return the uint24.
|
|
*/
|
|
util.ByteStringBuffer.prototype.getInt24 = function() {
|
|
var rval = (
|
|
this.data.charCodeAt(this.read) << 16 ^
|
|
this.data.charCodeAt(this.read + 1) << 8 ^
|
|
this.data.charCodeAt(this.read + 2));
|
|
this.read += 3;
|
|
return rval;
|
|
};
|
|
|
|
/**
|
|
* Gets a uint32 from this buffer in big-endian order and advances the read
|
|
* pointer by 4.
|
|
*
|
|
* @return the word.
|
|
*/
|
|
util.ByteStringBuffer.prototype.getInt32 = function() {
|
|
var rval = (
|
|
this.data.charCodeAt(this.read) << 24 ^
|
|
this.data.charCodeAt(this.read + 1) << 16 ^
|
|
this.data.charCodeAt(this.read + 2) << 8 ^
|
|
this.data.charCodeAt(this.read + 3));
|
|
this.read += 4;
|
|
return rval;
|
|
};
|
|
|
|
/**
|
|
* Gets a uint16 from this buffer in little-endian order and advances the read
|
|
* pointer by 2.
|
|
*
|
|
* @return the uint16.
|
|
*/
|
|
util.ByteStringBuffer.prototype.getInt16Le = function() {
|
|
var rval = (
|
|
this.data.charCodeAt(this.read) ^
|
|
this.data.charCodeAt(this.read + 1) << 8);
|
|
this.read += 2;
|
|
return rval;
|
|
};
|
|
|
|
/**
|
|
* Gets a uint24 from this buffer in little-endian order and advances the read
|
|
* pointer by 3.
|
|
*
|
|
* @return the uint24.
|
|
*/
|
|
util.ByteStringBuffer.prototype.getInt24Le = function() {
|
|
var rval = (
|
|
this.data.charCodeAt(this.read) ^
|
|
this.data.charCodeAt(this.read + 1) << 8 ^
|
|
this.data.charCodeAt(this.read + 2) << 16);
|
|
this.read += 3;
|
|
return rval;
|
|
};
|
|
|
|
/**
|
|
* Gets a uint32 from this buffer in little-endian order and advances the read
|
|
* pointer by 4.
|
|
*
|
|
* @return the word.
|
|
*/
|
|
util.ByteStringBuffer.prototype.getInt32Le = function() {
|
|
var rval = (
|
|
this.data.charCodeAt(this.read) ^
|
|
this.data.charCodeAt(this.read + 1) << 8 ^
|
|
this.data.charCodeAt(this.read + 2) << 16 ^
|
|
this.data.charCodeAt(this.read + 3) << 24);
|
|
this.read += 4;
|
|
return rval;
|
|
};
|
|
|
|
/**
|
|
* Gets an n-bit integer from this buffer in big-endian order and advances the
|
|
* read pointer by n/8.
|
|
*
|
|
* @param n the number of bits in the integer.
|
|
*
|
|
* @return the integer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.getInt = function(n) {
|
|
var rval = 0;
|
|
do {
|
|
rval = (rval << 8) + this.data.charCodeAt(this.read++);
|
|
n -= 8;
|
|
} while(n > 0);
|
|
return rval;
|
|
};
|
|
|
|
/**
|
|
* Gets a signed n-bit integer from this buffer in big-endian order, using
|
|
* two's complement, and advances the read pointer by n/8.
|
|
*
|
|
* @param n the number of bits in the integer.
|
|
*
|
|
* @return the integer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.getSignedInt = function(n) {
|
|
var x = this.getInt(n);
|
|
var max = 2 << (n - 2);
|
|
if(x >= max) {
|
|
x -= max << 1;
|
|
}
|
|
return x;
|
|
};
|
|
|
|
/**
|
|
* Reads bytes out into a UTF-8 string and clears them from the buffer.
|
|
*
|
|
* @param count the number of bytes to read, undefined or null for all.
|
|
*
|
|
* @return a UTF-8 string of bytes.
|
|
*/
|
|
util.ByteStringBuffer.prototype.getBytes = function(count) {
|
|
var rval;
|
|
if(count) {
|
|
// read count bytes
|
|
count = Math.min(this.length(), count);
|
|
rval = this.data.slice(this.read, this.read + count);
|
|
this.read += count;
|
|
} else if(count === 0) {
|
|
rval = '';
|
|
} else {
|
|
// read all bytes, optimize to only copy when needed
|
|
rval = (this.read === 0) ? this.data : this.data.slice(this.read);
|
|
this.clear();
|
|
}
|
|
return rval;
|
|
};
|
|
|
|
/**
|
|
* Gets a UTF-8 encoded string of the bytes from this buffer without modifying
|
|
* the read pointer.
|
|
*
|
|
* @param count the number of bytes to get, omit to get all.
|
|
*
|
|
* @return a string full of UTF-8 encoded characters.
|
|
*/
|
|
util.ByteStringBuffer.prototype.bytes = function(count) {
|
|
return (typeof(count) === 'undefined' ?
|
|
this.data.slice(this.read) :
|
|
this.data.slice(this.read, this.read + count));
|
|
};
|
|
|
|
/**
|
|
* Gets a byte at the given index without modifying the read pointer.
|
|
*
|
|
* @param i the byte index.
|
|
*
|
|
* @return the byte.
|
|
*/
|
|
util.ByteStringBuffer.prototype.at = function(i) {
|
|
return this.data.charCodeAt(this.read + i);
|
|
};
|
|
|
|
/**
|
|
* Puts a byte at the given index without modifying the read pointer.
|
|
*
|
|
* @param i the byte index.
|
|
* @param b the byte to put.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.setAt = function(i, b) {
|
|
this.data = this.data.substr(0, this.read + i) +
|
|
String.fromCharCode(b) +
|
|
this.data.substr(this.read + i + 1);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Gets the last byte without modifying the read pointer.
|
|
*
|
|
* @return the last byte.
|
|
*/
|
|
util.ByteStringBuffer.prototype.last = function() {
|
|
return this.data.charCodeAt(this.data.length - 1);
|
|
};
|
|
|
|
/**
|
|
* Creates a copy of this buffer.
|
|
*
|
|
* @return the copy.
|
|
*/
|
|
util.ByteStringBuffer.prototype.copy = function() {
|
|
var c = util.createBuffer(this.data);
|
|
c.read = this.read;
|
|
return c;
|
|
};
|
|
|
|
/**
|
|
* Compacts this buffer.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.compact = function() {
|
|
if(this.read > 0) {
|
|
this.data = this.data.slice(this.read);
|
|
this.read = 0;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Clears this buffer.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.clear = function() {
|
|
this.data = '';
|
|
this.read = 0;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Shortens this buffer by triming bytes off of the end of this buffer.
|
|
*
|
|
* @param count the number of bytes to trim off.
|
|
*
|
|
* @return this buffer.
|
|
*/
|
|
util.ByteStringBuffer.prototype.truncate = function(count) {
|
|
var len = Math.max(0, this.length() - count);
|
|
this.data = this.data.substr(this.read, len);
|
|
this.read = 0;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Converts this buffer to a hexadecimal string.
|
|
*
|
|
* @return a hexadecimal string.
|
|
*/
|
|
util.ByteStringBuffer.prototype.toHex = function() {
|
|
var rval = '';
|
|
for(var i = this.read; i < this.data.length; ++i) {
|
|
var b = this.data.charCodeAt(i);
|
|
if(b < 16) {
|
|
rval += '0';
|
|
}
|
|
rval += b.toString(16);
|
|
}
|
|
return rval;
|
|
};
|
|
|
|
/**
|
|
* Converts this buffer to a UTF-16 string (standard JavaScript string).
|
|
*
|
|
* @return a UTF-16 string.
|
|
*/
|
|
util.ByteStringBuffer.prototype.toString = function() {
|
|
return util.decodeUtf8(this.bytes());
|
|
};
|
|
|
|
/** End Buffer w/BinaryString backing */
|
|
|
|
/**
|
|
* Creates a buffer that stores bytes. A value may be given to put into the
|
|
* buffer that is either a string of bytes or a UTF-16 string that will
|
|
* be encoded using UTF-8 (to do the latter, specify 'utf8' as the encoding).
|
|
*
|
|
* @param [input] the bytes to wrap (as a string) or a UTF-16 string to encode
|
|
* as UTF-8.
|
|
* @param [encoding] (default: 'raw', other: 'utf8').
|
|
*/
|
|
util.createBuffer = function(input, encoding) {
|
|
// TODO: deprecate, use new ByteBuffer() instead
|
|
encoding = encoding || 'raw';
|
|
if(input !== undefined && encoding === 'utf8') {
|
|
input = util.encodeUtf8(input);
|
|
}
|
|
return new util.ByteBuffer(input);
|
|
};
|
|
|
|
/**
|
|
* Fills a string with a particular value. If you want the string to be a byte
|
|
* string, pass in String.fromCharCode(theByte).
|
|
*
|
|
* @param c the character to fill the string with, use String.fromCharCode
|
|
* to fill the string with a byte value.
|
|
* @param n the number of characters of value c to fill with.
|
|
*
|
|
* @return the filled string.
|
|
*/
|
|
util.fillString = function(c, n) {
|
|
var s = '';
|
|
while(n > 0) {
|
|
if(n & 1) {
|
|
s += c;
|
|
}
|
|
n >>>= 1;
|
|
if(n > 0) {
|
|
c += c;
|
|
}
|
|
}
|
|
return s;
|
|
};
|
|
|
|
/**
|
|
* UTF-8 encodes the given UTF-16 encoded string (a standard JavaScript
|
|
* string). Non-ASCII characters will be encoded as multiple bytes according
|
|
* to UTF-8.
|
|
*
|
|
* @param str the string to encode.
|
|
*
|
|
* @return the UTF-8 encoded string.
|
|
*/
|
|
util.encodeUtf8 = function(str) {
|
|
return unescape(encodeURIComponent(str));
|
|
};
|
|
|
|
} // end module implementation
|
|
|
|
/* ########## Begin module wrapper ########## */
|
|
var name = 'util';
|
|
if(typeof define !== 'function') {
|
|
// NodeJS -> AMD
|
|
if(typeof module === 'object' && module.exports) {
|
|
var nodeJS = true;
|
|
define = function(ids, factory) {
|
|
factory(require, module);
|
|
};
|
|
} else {
|
|
// <script>
|
|
if(typeof forge === 'undefined') {
|
|
forge = {};
|
|
}
|
|
return initModule(forge);
|
|
}
|
|
}
|
|
// AMD
|
|
var deps;
|
|
var defineFunc = function(require, module) {
|
|
module.exports = function(forge) {
|
|
var mods = deps.map(function(dep) {
|
|
return require(dep);
|
|
}).concat(initModule);
|
|
// handle circular dependencies
|
|
forge = forge || {};
|
|
forge.defined = forge.defined || {};
|
|
if(forge.defined[name]) {
|
|
return forge[name];
|
|
}
|
|
forge.defined[name] = true;
|
|
for(var i = 0; i < mods.length; ++i) {
|
|
mods[i](forge);
|
|
}
|
|
return forge[name];
|
|
};
|
|
};
|
|
var tmpDefine = define;
|
|
define = function(ids, factory) {
|
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
|
if(nodeJS) {
|
|
delete define;
|
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
|
}
|
|
define = tmpDefine;
|
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
|
};
|
|
define(['require', 'module'], function() {
|
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
|
});
|
|
})();
|