Created
May 6, 2016 02:59
-
-
Save davisford/b75066db218e42a3f71a402f35ac5d2a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
/*\ | |
|*| | |
|*| :: Number.isInteger() polyfill :: | |
|*| | |
|*| https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger | |
|*| | |
\*/ | |
if (!Number.isInteger) { | |
Number.isInteger = function isInteger (nVal) { | |
return typeof nVal === "number" && isFinite(nVal) && nVal > -9007199254740992 && nVal < 9007199254740992 && Math.floor(nVal) === nVal; | |
}; | |
} | |
/*\ | |
|*| | |
|*| StringView - Mozilla Developer Network | |
|*| | |
|*| Revision #8, October 6, 2014 | |
|*| | |
|*| https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays/StringView | |
|*| https://developer.mozilla.org/en-US/docs/User:fusionchess | |
|*| | |
|*| This framework is released under the GNU Lesser General Public License, version 3 or later. | |
|*| http://www.gnu.org/licenses/lgpl-3.0.html | |
|*| | |
\*/ | |
function StringView (vInput, sEncoding /* optional (default: UTF-8) */, nOffset /* optional */, nLength /* optional */) { | |
var fTAView, aWhole, aRaw, fPutOutptCode, fGetOutptChrSize, nInptLen, nStartIdx = isFinite(nOffset) ? nOffset : 0, nTranscrType = 15; | |
if (sEncoding) { this.encoding = sEncoding.toString(); } | |
encSwitch: switch (this.encoding) { | |
case "UTF-8": | |
fPutOutptCode = StringView.putUTF8CharCode; | |
fGetOutptChrSize = StringView.getUTF8CharLength; | |
fTAView = Uint8Array; | |
break encSwitch; | |
case "UTF-16": | |
fPutOutptCode = StringView.putUTF16CharCode; | |
fGetOutptChrSize = StringView.getUTF16CharLength; | |
fTAView = Uint16Array; | |
break encSwitch; | |
case "UTF-32": | |
fTAView = Uint32Array; | |
nTranscrType &= 14; | |
break encSwitch; | |
default: | |
/* case "ASCII", or case "BinaryString" or unknown cases */ | |
fTAView = Uint8Array; | |
nTranscrType &= 14; | |
} | |
typeSwitch: switch (typeof vInput) { | |
case "string": | |
/* the input argument is a primitive string: a new buffer will be created. */ | |
nTranscrType &= 7; | |
break typeSwitch; | |
case "object": | |
classSwitch: switch (vInput.constructor) { | |
case StringView: | |
/* the input argument is a stringView: a new buffer will be created. */ | |
nTranscrType &= 3; | |
break typeSwitch; | |
case String: | |
/* the input argument is an objectified string: a new buffer will be created. */ | |
nTranscrType &= 7; | |
break typeSwitch; | |
case ArrayBuffer: | |
/* the input argument is an arrayBuffer: the buffer will be shared. */ | |
aWhole = new fTAView(vInput); | |
nInptLen = this.encoding === "UTF-32" ? | |
vInput.byteLength >>> 2 | |
: this.encoding === "UTF-16" ? | |
vInput.byteLength >>> 1 | |
: | |
vInput.byteLength; | |
aRaw = nStartIdx === 0 && (!isFinite(nLength) || nLength === nInptLen) ? | |
aWhole | |
: new fTAView(vInput, nStartIdx, !isFinite(nLength) ? nInptLen - nStartIdx : nLength); | |
break typeSwitch; | |
case Uint32Array: | |
case Uint16Array: | |
case Uint8Array: | |
/* the input argument is a typedArray: the buffer, and possibly the array itself, will be shared. */ | |
fTAView = vInput.constructor; | |
nInptLen = vInput.length; | |
aWhole = vInput.byteOffset === 0 && vInput.length === ( | |
fTAView === Uint32Array ? | |
vInput.buffer.byteLength >>> 2 | |
: fTAView === Uint16Array ? | |
vInput.buffer.byteLength >>> 1 | |
: | |
vInput.buffer.byteLength | |
) ? vInput : new fTAView(vInput.buffer); | |
aRaw = nStartIdx === 0 && (!isFinite(nLength) || nLength === nInptLen) ? | |
vInput | |
: vInput.subarray(nStartIdx, isFinite(nLength) ? nStartIdx + nLength : nInptLen); | |
break typeSwitch; | |
default: | |
/* the input argument is an array or another serializable object: a new typedArray will be created. */ | |
aWhole = new fTAView(vInput); | |
nInptLen = aWhole.length; | |
aRaw = nStartIdx === 0 && (!isFinite(nLength) || nLength === nInptLen) ? | |
aWhole | |
: aWhole.subarray(nStartIdx, isFinite(nLength) ? nStartIdx + nLength : nInptLen); | |
} | |
break typeSwitch; | |
default: | |
/* the input argument is a number, a boolean or a function: a new typedArray will be created. */ | |
aWhole = aRaw = new fTAView(Number(vInput) || 0); | |
} | |
if (nTranscrType < 8) { | |
var vSource, nOutptLen, nCharStart, nCharEnd, nEndIdx, fGetInptChrSize, fGetInptChrCode; | |
if (nTranscrType & 4) { /* input is string */ | |
vSource = vInput; | |
nOutptLen = nInptLen = vSource.length; | |
nTranscrType ^= this.encoding === "UTF-32" ? 0 : 2; | |
/* ...or...: nTranscrType ^= Number(this.encoding !== "UTF-32") << 1; */ | |
nStartIdx = nCharStart = nOffset ? Math.max((nOutptLen + nOffset) % nOutptLen, 0) : 0; | |
nEndIdx = nCharEnd = (Number.isInteger(nLength) ? Math.min(Math.max(nLength, 0) + nStartIdx, nOutptLen) : nOutptLen) - 1; | |
} else { /* input is stringView */ | |
vSource = vInput.rawData; | |
nInptLen = vInput.makeIndex(); | |
nStartIdx = nCharStart = nOffset ? Math.max((nInptLen + nOffset) % nInptLen, 0) : 0; | |
nOutptLen = Number.isInteger(nLength) ? Math.min(Math.max(nLength, 0), nInptLen - nCharStart) : nInptLen; | |
nEndIdx = nCharEnd = nOutptLen + nCharStart; | |
if (vInput.encoding === "UTF-8") { | |
fGetInptChrSize = StringView.getUTF8CharLength; | |
fGetInptChrCode = StringView.loadUTF8CharCode; | |
} else if (vInput.encoding === "UTF-16") { | |
fGetInptChrSize = StringView.getUTF16CharLength; | |
fGetInptChrCode = StringView.loadUTF16CharCode; | |
} else { | |
nTranscrType &= 1; | |
} | |
} | |
if (nOutptLen === 0 || nTranscrType < 4 && vSource.encoding === this.encoding && nCharStart === 0 && nOutptLen === nInptLen) { | |
/* the encoding is the same, the length too and the offset is 0... or the input is empty! */ | |
nTranscrType = 7; | |
} | |
conversionSwitch: switch (nTranscrType) { | |
case 0: | |
/* both the source and the new StringView have a fixed-length encoding... */ | |
aWhole = new fTAView(nOutptLen); | |
for (var nOutptIdx = 0; nOutptIdx < nOutptLen; aWhole[nOutptIdx] = vSource[nStartIdx + nOutptIdx++]); | |
break conversionSwitch; | |
case 1: | |
/* the source has a fixed-length encoding but the new StringView has a variable-length encoding... */ | |
/* mapping... */ | |
nOutptLen = 0; | |
for (var nInptIdx = nStartIdx; nInptIdx < nEndIdx; nInptIdx++) { | |
nOutptLen += fGetOutptChrSize(vSource[nInptIdx]); | |
} | |
aWhole = new fTAView(nOutptLen); | |
/* transcription of the source... */ | |
for (var nInptIdx = nStartIdx, nOutptIdx = 0; nOutptIdx < nOutptLen; nInptIdx++) { | |
nOutptIdx = fPutOutptCode(aWhole, vSource[nInptIdx], nOutptIdx); | |
} | |
break conversionSwitch; | |
case 2: | |
/* the source has a variable-length encoding but the new StringView has a fixed-length encoding... */ | |
/* mapping... */ | |
nStartIdx = 0; | |
var nChrCode; | |
for (nChrIdx = 0; nChrIdx < nCharStart; nChrIdx++) { | |
nChrCode = fGetInptChrCode(vSource, nStartIdx); | |
nStartIdx += fGetInptChrSize(nChrCode); | |
} | |
aWhole = new fTAView(nOutptLen); | |
/* transcription of the source... */ | |
for (var nInptIdx = nStartIdx, nOutptIdx = 0; nOutptIdx < nOutptLen; nInptIdx += fGetInptChrSize(nChrCode), nOutptIdx++) { | |
nChrCode = fGetInptChrCode(vSource, nInptIdx); | |
aWhole[nOutptIdx] = nChrCode; | |
} | |
break conversionSwitch; | |
case 3: | |
/* both the source and the new StringView have a variable-length encoding... */ | |
/* mapping... */ | |
nOutptLen = 0; | |
var nChrCode; | |
for (var nChrIdx = 0, nInptIdx = 0; nChrIdx < nCharEnd; nInptIdx += fGetInptChrSize(nChrCode)) { | |
nChrCode = fGetInptChrCode(vSource, nInptIdx); | |
if (nChrIdx === nCharStart) { nStartIdx = nInptIdx; } | |
if (++nChrIdx > nCharStart) { nOutptLen += fGetOutptChrSize(nChrCode); } | |
} | |
aWhole = new fTAView(nOutptLen); | |
/* transcription... */ | |
for (var nInptIdx = nStartIdx, nOutptIdx = 0; nOutptIdx < nOutptLen; nInptIdx += fGetInptChrSize(nChrCode)) { | |
nChrCode = fGetInptChrCode(vSource, nInptIdx); | |
nOutptIdx = fPutOutptCode(aWhole, nChrCode, nOutptIdx); | |
} | |
break conversionSwitch; | |
case 4: | |
/* DOMString to ASCII or BinaryString or other unknown encodings */ | |
aWhole = new fTAView(nOutptLen); | |
/* transcription... */ | |
for (var nIdx = 0; nIdx < nOutptLen; nIdx++) { | |
aWhole[nIdx] = vSource.charCodeAt(nIdx) & 0xff; | |
} | |
break conversionSwitch; | |
case 5: | |
/* DOMString to UTF-8 or to UTF-16 */ | |
/* mapping... */ | |
nOutptLen = 0; | |
for (var nMapIdx = 0; nMapIdx < nInptLen; nMapIdx++) { | |
if (nMapIdx === nCharStart) { nStartIdx = nOutptLen; } | |
nOutptLen += fGetOutptChrSize(vSource.charCodeAt(nMapIdx)); | |
if (nMapIdx === nCharEnd) { nEndIdx = nOutptLen; } | |
} | |
aWhole = new fTAView(nOutptLen); | |
/* transcription... */ | |
for (var nOutptIdx = 0, nChrIdx = 0; nOutptIdx < nOutptLen; nChrIdx++) { | |
nOutptIdx = fPutOutptCode(aWhole, vSource.charCodeAt(nChrIdx), nOutptIdx); | |
} | |
break conversionSwitch; | |
case 6: | |
/* DOMString to UTF-32 */ | |
aWhole = new fTAView(nOutptLen); | |
/* transcription... */ | |
for (var nIdx = 0; nIdx < nOutptLen; nIdx++) { | |
aWhole[nIdx] = vSource.charCodeAt(nIdx); | |
} | |
break conversionSwitch; | |
case 7: | |
aWhole = new fTAView(nOutptLen ? vSource : 0); | |
break conversionSwitch; | |
} | |
aRaw = nTranscrType > 3 && (nStartIdx > 0 || nEndIdx < aWhole.length - 1) ? aWhole.subarray(nStartIdx, nEndIdx) : aWhole; | |
} | |
this.buffer = aWhole.buffer; | |
this.bufferView = aWhole; | |
this.rawData = aRaw; | |
Object.freeze(this); | |
} | |
/* CONSTRUCTOR'S METHODS */ | |
StringView.loadUTF8CharCode = function (aChars, nIdx) { | |
var nLen = aChars.length, nPart = aChars[nIdx]; | |
return nPart > 251 && nPart < 254 && nIdx + 5 < nLen ? | |
/* (nPart - 252 << 30) may be not safe in ECMAScript! So...: */ | |
/* six bytes */ (nPart - 252) * 1073741824 + (aChars[nIdx + 1] - 128 << 24) + (aChars[nIdx + 2] - 128 << 18) + (aChars[nIdx + 3] - 128 << 12) + (aChars[nIdx + 4] - 128 << 6) + aChars[nIdx + 5] - 128 | |
: nPart > 247 && nPart < 252 && nIdx + 4 < nLen ? | |
/* five bytes */ (nPart - 248 << 24) + (aChars[nIdx + 1] - 128 << 18) + (aChars[nIdx + 2] - 128 << 12) + (aChars[nIdx + 3] - 128 << 6) + aChars[nIdx + 4] - 128 | |
: nPart > 239 && nPart < 248 && nIdx + 3 < nLen ? | |
/* four bytes */(nPart - 240 << 18) + (aChars[nIdx + 1] - 128 << 12) + (aChars[nIdx + 2] - 128 << 6) + aChars[nIdx + 3] - 128 | |
: nPart > 223 && nPart < 240 && nIdx + 2 < nLen ? | |
/* three bytes */ (nPart - 224 << 12) + (aChars[nIdx + 1] - 128 << 6) + aChars[nIdx + 2] - 128 | |
: nPart > 191 && nPart < 224 && nIdx + 1 < nLen ? | |
/* two bytes */ (nPart - 192 << 6) + aChars[nIdx + 1] - 128 | |
: | |
/* one byte */ nPart; | |
}; | |
StringView.putUTF8CharCode = function (aTarget, nChar, nPutAt) { | |
var nIdx = nPutAt; | |
if (nChar < 0x80 /* 128 */) { | |
/* one byte */ | |
aTarget[nIdx++] = nChar; | |
} else if (nChar < 0x800 /* 2048 */) { | |
/* two bytes */ | |
aTarget[nIdx++] = 0xc0 /* 192 */ + (nChar >>> 6); | |
aTarget[nIdx++] = 0x80 /* 128 */ + (nChar & 0x3f /* 63 */); | |
} else if (nChar < 0x10000 /* 65536 */) { | |
/* three bytes */ | |
aTarget[nIdx++] = 0xe0 /* 224 */ + (nChar >>> 12); | |
aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 6) & 0x3f /* 63 */); | |
aTarget[nIdx++] = 0x80 /* 128 */ + (nChar & 0x3f /* 63 */); | |
} else if (nChar < 0x200000 /* 2097152 */) { | |
/* four bytes */ | |
aTarget[nIdx++] = 0xf0 /* 240 */ + (nChar >>> 18); | |
aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 12) & 0x3f /* 63 */); | |
aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 6) & 0x3f /* 63 */); | |
aTarget[nIdx++] = 0x80 /* 128 */ + (nChar & 0x3f /* 63 */); | |
} else if (nChar < 0x4000000 /* 67108864 */) { | |
/* five bytes */ | |
aTarget[nIdx++] = 0xf8 /* 248 */ + (nChar >>> 24); | |
aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 18) & 0x3f /* 63 */); | |
aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 12) & 0x3f /* 63 */); | |
aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 6) & 0x3f /* 63 */); | |
aTarget[nIdx++] = 0x80 /* 128 */ + (nChar & 0x3f /* 63 */); | |
} else /* if (nChar <= 0x7fffffff) */ { /* 2147483647 */ | |
/* six bytes */ | |
aTarget[nIdx++] = 0xfc /* 252 */ + /* (nChar >>> 30) may be not safe in ECMAScript! So...: */ (nChar / 1073741824); | |
aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 24) & 0x3f /* 63 */); | |
aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 18) & 0x3f /* 63 */); | |
aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 12) & 0x3f /* 63 */); | |
aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 6) & 0x3f /* 63 */); | |
aTarget[nIdx++] = 0x80 /* 128 */ + (nChar & 0x3f /* 63 */); | |
} | |
return nIdx; | |
}; | |
StringView.getUTF8CharLength = function (nChar) { | |
return nChar < 0x80 ? 1 : nChar < 0x800 ? 2 : nChar < 0x10000 ? 3 : nChar < 0x200000 ? 4 : nChar < 0x4000000 ? 5 : 6; | |
}; | |
StringView.loadUTF16CharCode = function (aChars, nIdx) { | |
/* UTF-16 to DOMString decoding algorithm */ | |
var nFrstChr = aChars[nIdx]; | |
return nFrstChr > 0xD7BF /* 55231 */ && nIdx + 1 < aChars.length ? | |
(nFrstChr - 0xD800 /* 55296 */ << 10) + aChars[nIdx + 1] + 0x2400 /* 9216 */ | |
: nFrstChr; | |
}; | |
StringView.putUTF16CharCode = function (aTarget, nChar, nPutAt) { | |
var nIdx = nPutAt; | |
if (nChar < 0x10000 /* 65536 */) { | |
/* one element */ | |
aTarget[nIdx++] = nChar; | |
} else { | |
/* two elements */ | |
aTarget[nIdx++] = 0xD7C0 /* 55232 */ + (nChar >>> 10); | |
aTarget[nIdx++] = 0xDC00 /* 56320 */ + (nChar & 0x3FF /* 1023 */); | |
} | |
return nIdx; | |
}; | |
StringView.getUTF16CharLength = function (nChar) { | |
return nChar < 0x10000 ? 1 : 2; | |
}; | |
/* Array of bytes to base64 string decoding */ | |
StringView.b64ToUint6 = function (nChr) { | |
return nChr > 64 && nChr < 91 ? | |
nChr - 65 | |
: nChr > 96 && nChr < 123 ? | |
nChr - 71 | |
: nChr > 47 && nChr < 58 ? | |
nChr + 4 | |
: nChr === 43 ? | |
62 | |
: nChr === 47 ? | |
63 | |
: | |
0; | |
}; | |
StringView.uint6ToB64 = function (nUint6) { | |
return nUint6 < 26 ? | |
nUint6 + 65 | |
: nUint6 < 52 ? | |
nUint6 + 71 | |
: nUint6 < 62 ? | |
nUint6 - 4 | |
: nUint6 === 62 ? | |
43 | |
: nUint6 === 63 ? | |
47 | |
: | |
65; | |
}; | |
/* Base64 string to array encoding */ | |
StringView.bytesToBase64 = function (aBytes) { | |
var sB64Enc = ""; | |
for (var nMod3, nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) { | |
nMod3 = nIdx % 3; | |
if (nIdx > 0 && (nIdx * 4 / 3) % 76 === 0) { sB64Enc += "\r\n"; } | |
nUint24 |= aBytes[nIdx] << (16 >>> nMod3 & 24); | |
if (nMod3 === 2 || aBytes.length - nIdx === 1) { | |
sB64Enc += String.fromCharCode(StringView.uint6ToB64(nUint24 >>> 18 & 63), StringView.uint6ToB64(nUint24 >>> 12 & 63), StringView.uint6ToB64(nUint24 >>> 6 & 63), StringView.uint6ToB64(nUint24 & 63)); | |
nUint24 = 0; | |
} | |
} | |
return sB64Enc.replace(/A(?=A$|$)/g, "="); | |
}; | |
StringView.base64ToBytes = function (sBase64, nBlockBytes) { | |
var | |
sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length, | |
nOutLen = nBlockBytes ? Math.ceil((nInLen * 3 + 1 >>> 2) / nBlockBytes) * nBlockBytes : nInLen * 3 + 1 >>> 2, aBytes = new Uint8Array(nOutLen); | |
for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) { | |
nMod4 = nInIdx & 3; | |
nUint24 |= StringView.b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4; | |
if (nMod4 === 3 || nInLen - nInIdx === 1) { | |
for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) { | |
aBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255; | |
} | |
nUint24 = 0; | |
} | |
} | |
return aBytes; | |
}; | |
StringView.makeFromBase64 = function (sB64Inpt, sEncoding, nByteOffset, nLength) { | |
return new StringView(sEncoding === "UTF-16" || sEncoding === "UTF-32" ? StringView.base64ToBytes(sB64Inpt, sEncoding === "UTF-16" ? 2 : 4).buffer : StringView.base64ToBytes(sB64Inpt), sEncoding, nByteOffset, nLength); | |
}; | |
/* DEFAULT VALUES */ | |
StringView.prototype.encoding = "UTF-8"; /* Default encoding... */ | |
/* INSTANCES' METHODS */ | |
StringView.prototype.makeIndex = function (nChrLength, nStartFrom) { | |
var | |
aTarget = this.rawData, nChrEnd, nRawLength = aTarget.length, | |
nStartIdx = nStartFrom || 0, nIdxEnd = nStartIdx, nStopAtChr = isNaN(nChrLength) ? Infinity : nChrLength; | |
if (nChrLength + 1 > aTarget.length) { throw new RangeError("StringView.prototype.makeIndex - The offset can\'t be major than the length of the array - 1."); } | |
switch (this.encoding) { | |
case "UTF-8": | |
var nPart; | |
for (nChrEnd = 0; nIdxEnd < nRawLength && nChrEnd < nStopAtChr; nChrEnd++) { | |
nPart = aTarget[nIdxEnd]; | |
nIdxEnd += nPart > 251 && nPart < 254 && nIdxEnd + 5 < nRawLength ? 6 | |
: nPart > 247 && nPart < 252 && nIdxEnd + 4 < nRawLength ? 5 | |
: nPart > 239 && nPart < 248 && nIdxEnd + 3 < nRawLength ? 4 | |
: nPart > 223 && nPart < 240 && nIdxEnd + 2 < nRawLength ? 3 | |
: nPart > 191 && nPart < 224 && nIdxEnd + 1 < nRawLength ? 2 | |
: 1; | |
} | |
break; | |
case "UTF-16": | |
for (nChrEnd = nStartIdx; nIdxEnd < nRawLength && nChrEnd < nStopAtChr; nChrEnd++) { | |
nIdxEnd += aTarget[nIdxEnd] > 0xD7BF /* 55231 */ && nIdxEnd + 1 < aTarget.length ? 2 : 1; | |
} | |
break; | |
default: | |
nIdxEnd = nChrEnd = isFinite(nChrLength) ? nChrLength : nRawLength - 1; | |
} | |
if (nChrLength) { return nIdxEnd; } | |
return nChrEnd; | |
}; | |
StringView.prototype.toBase64 = function (bWholeBuffer) { | |
return StringView.bytesToBase64( | |
bWholeBuffer ? | |
( | |
this.bufferView.constructor === Uint8Array ? | |
this.bufferView | |
: | |
new Uint8Array(this.buffer) | |
) | |
: this.rawData.constructor === Uint8Array ? | |
this.rawData | |
: | |
new Uint8Array(this.buffer, this.rawData.byteOffset, this.rawData.length << (this.rawData.constructor === Uint16Array ? 1 : 2)) | |
); | |
}; | |
StringView.prototype.subview = function (nCharOffset /* optional */, nCharLength /* optional */) { | |
var | |
nChrLen, nCharStart, nStrLen, bVariableLen = this.encoding === "UTF-8" || this.encoding === "UTF-16", | |
nStartOffset = nCharOffset, nStringLength, nRawLen = this.rawData.length; | |
if (nRawLen === 0) { | |
return new StringView(this.buffer, this.encoding); | |
} | |
nStringLength = bVariableLen ? this.makeIndex() : nRawLen; | |
nCharStart = nCharOffset ? Math.max((nStringLength + nCharOffset) % nStringLength, 0) : 0; | |
nStrLen = Number.isInteger(nCharLength) ? Math.max(nCharLength, 0) + nCharStart > nStringLength ? nStringLength - nCharStart : nCharLength : nStringLength; | |
if (nCharStart === 0 && nStrLen === nStringLength) { return this; } | |
if (bVariableLen) { | |
nStartOffset = this.makeIndex(nCharStart); | |
nChrLen = this.makeIndex(nStrLen, nStartOffset) - nStartOffset; | |
} else { | |
nStartOffset = nCharStart; | |
//nChrLen = nStrLen - nCharStart; // this can generate a negative length which blows up StringView ctor with Array index out of bounds error | |
nChrLen = nCharLength - nCharStart; | |
} | |
if (this.encoding === "UTF-16") { | |
nStartOffset <<= 1; | |
} else if (this.encoding === "UTF-32") { | |
nStartOffset <<= 2; | |
} | |
return new StringView(this.buffer, this.encoding, nStartOffset, nChrLen); | |
}; | |
StringView.prototype.forEachChar = function (fCallback, oThat, nChrOffset, nChrLen) { | |
var aSource = this.rawData, nRawEnd, nRawIdx; | |
if (this.encoding === "UTF-8" || this.encoding === "UTF-16") { | |
var fGetInptChrSize, fGetInptChrCode; | |
if (this.encoding === "UTF-8") { | |
fGetInptChrSize = StringView.getUTF8CharLength; | |
fGetInptChrCode = StringView.loadUTF8CharCode; | |
} else if (this.encoding === "UTF-16") { | |
fGetInptChrSize = StringView.getUTF16CharLength; | |
fGetInptChrCode = StringView.loadUTF16CharCode; | |
} | |
nRawIdx = isFinite(nChrOffset) ? this.makeIndex(nChrOffset) : 0; | |
nRawEnd = isFinite(nChrLen) ? this.makeIndex(nChrLen, nRawIdx) : aSource.length; | |
for (var nChrCode, nChrIdx = 0; nRawIdx < nRawEnd; nChrIdx++) { | |
nChrCode = fGetInptChrCode(aSource, nRawIdx); | |
fCallback.call(oThat || null, nChrCode, nChrIdx, nRawIdx, aSource); | |
nRawIdx += fGetInptChrSize(nChrCode); | |
} | |
} else { | |
nRawIdx = isFinite(nChrOffset) ? nChrOffset : 0; | |
nRawEnd = isFinite(nChrLen) ? nChrLen + nRawIdx : aSource.length; | |
for (nRawIdx; nRawIdx < nRawEnd; nRawIdx++) { | |
fCallback.call(oThat || null, aSource[nRawIdx], nRawIdx, nRawIdx, aSource); | |
} | |
} | |
}; | |
StringView.prototype.valueOf = StringView.prototype.toString = function () { | |
if (this.encoding !== "UTF-8" && this.encoding !== "UTF-16") { | |
/* ASCII, UTF-32 or BinaryString to DOMString */ | |
return String.fromCharCode.apply(null, this.rawData); | |
} | |
var fGetCode, fGetIncr, sView = ""; | |
if (this.encoding === "UTF-8") { | |
fGetIncr = StringView.getUTF8CharLength; | |
fGetCode = StringView.loadUTF8CharCode; | |
} else if (this.encoding === "UTF-16") { | |
fGetIncr = StringView.getUTF16CharLength; | |
fGetCode = StringView.loadUTF16CharCode; | |
} | |
for (var nChr, nLen = this.rawData.length, nIdx = 0; nIdx < nLen; nIdx += fGetIncr(nChr)) { | |
nChr = fGetCode(this.rawData, nIdx); | |
sView += String.fromCharCode(nChr); | |
} | |
return sView; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment