diff --git a/src/core/index.js b/src/core/index.js index d24cd4241..b7cf86b47 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -1,4 +1,3 @@ - import * as base from "./2.base"; import * as ob from "./3.ob"; import * as widget from "./4.widget"; @@ -7,10 +6,11 @@ import * as action from "./action"; import * as behavior from "./behavior"; import * as controllers from "./controller"; import * as func from "./func"; -import { StyleLoaderManager } from "./loader/loader.style"; +import * as structure from "./structure"; +import {StyleLoaderManager} from "./loader/loader.style"; import "./h"; -import { ShowListener } from "./listener/listener.show"; -import { shortcut } from "./decorator"; +import {ShowListener} from "./listener/listener.show"; +import {shortcut} from "./decorator"; export * from "./2.base"; export * from "./3.ob"; @@ -20,6 +20,7 @@ export * from "./action"; export * from "./behavior"; export * from "./controller"; export * from "./func"; +export * from "./structure"; // 有了后删掉 export const emptyFn = () => { }; @@ -42,4 +43,5 @@ Object.assign(BI, { ...func, StyleLoaderManager, ShowListener, + ...structure, }); diff --git a/src/core/structure/aes.js b/src/core/structure/aes.js index ec5d6b86a..b21b49aaa 100644 --- a/src/core/structure/aes.js +++ b/src/core/structure/aes.js @@ -1,2346 +1,2342 @@ -!(function () { - /* - CryptoJS v3.1.2 - code.google.com/p/crypto-js - (c) 2009-2013 by Jeff Mott. All rights reserved. - code.google.com/p/crypto-js/wiki/License - */ +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +/** + * CryptoJS core components. + */ +BI.CRYPT_TYPE = BI.CRYPT_TYPE || {}; +BI.CRYPT_TYPE.AES = "aes"; + +const CryptoJS = CryptoJS || (function (Math, undefined) { /** - * CryptoJS core components. + * CryptoJS namespace. */ - BI.CRYPT_TYPE = BI.CRYPT_TYPE || {}; - BI.CRYPT_TYPE.AES = "aes"; + const C = {}; - var CryptoJS = CryptoJS || (function (Math, undefined) { - /** - * CryptoJS namespace. - */ - var C = {}; - - /** - * Library namespace. - */ - var C_lib = C.lib = {}; - - /** - * Base object for prototypal inheritance. - */ - var Base = C_lib.Base = (function () { - function F () { - } - - return { - /** - * Creates a new object that inherits from this object. - * - * @param {Object} overrides Properties to copy into the new object. - * - * @return {Object} The new object. - * - * @static - * - * @example - * - * var MyType = CryptoJS.lib.Base.extend({ - * field: 'value', - * - * method: function () { - * } - * }); - */ - extend: function (overrides) { - // Spawn - F.prototype = this; - var subtype = new F(); - - // Augment - if (overrides) { - subtype.mixIn(overrides); - } - - // Create default initializer - if (!subtype.hasOwnProperty('init')) { - subtype.init = function () { - subtype.$super.init.apply(this, arguments); - }; - } - - // Initializer's prototype is the subtype object - subtype.init.prototype = subtype; - - // Reference supertype - subtype.$super = this; - - return subtype; - }, - - /** - * Extends this object and runs the init method. - * Arguments to create() will be passed to init(). - * - * @return {Object} The new object. - * - * @static - * - * @example - * - * var instance = MyType.create(); - */ - create: function () { - var instance = this.extend(); - instance.init.apply(instance, arguments); - - return instance; - }, - - /** - * Initializes a newly created object. - * Override this method to add some logic when your objects are created. - * - * @example - * - * var MyType = CryptoJS.lib.Base.extend({ - * init: function () { - * // ... - * } - * }); - */ - init: function () { - }, - - /** - * Copies properties into this object. - * - * @param {Object} properties The properties to mix in. - * - * @example - * - * MyType.mixIn({ - * field: 'value' - * }); - */ - mixIn: function (properties) { - for (var propertyName in properties) { - if (properties.hasOwnProperty(propertyName)) { - this[propertyName] = properties[propertyName]; - } - } + /** + * Library namespace. + */ + const C_lib = C.lib = {}; - // IE won't copy toString using the loop above - if (properties.hasOwnProperty('toString')) { - this.toString = properties.toString; - } - }, - - /** - * Creates a copy of this object. - * - * @return {Object} The clone. - * - * @example - * - * var clone = instance.clone(); - */ - clone: function () { - return this.init.prototype.extend(this); - } - }; - }()); + /** + * Base object for prototypal inheritance. + */ + const Base = C_lib.Base = (function () { + function F() { + } - /** - * An array of 32-bit words. - * - * @property {Array} words The array of 32-bit words. - * @property {number} sigBytes The number of significant bytes in this word array. - */ - var WordArray = C_lib.WordArray = Base.extend({ + return { /** - * Initializes a newly created word array. - * - * @param {Array} words (Optional) An array of 32-bit words. - * @param {number} sigBytes (Optional) The number of significant bytes in the words. - * - * @example + * Creates a new object that inherits from this object. * - * var wordArray = CryptoJS.lib.WordArray.create(); - * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); - * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); - */ - init: function (words, sigBytes) { - words = this.words = words || []; - - if (sigBytes != undefined) { - this.sigBytes = sigBytes; - } else { - this.sigBytes = words.length * 4; - } - }, - - /** - * Converts this word array to a string. + * @param {Object} overrides Properties to copy into the new object. * - * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex + * @return {Object} The new object. * - * @return {string} The stringified word array. + * @static * * @example * - * var string = wordArray + ''; - * var string = wordArray.toString(); - * var string = wordArray.toString(CryptoJS.enc.Utf8); - */ - toString: function (encoder) { - return (encoder || Hex).stringify(this); - }, - - /** - * Concatenates a word array to this word array. - * - * @param {WordArray} wordArray The word array to append. - * - * @return {WordArray} This word array. - * - * @example + * var MyType = CryptoJS.lib.Base.extend({ + * field: 'value', * - * wordArray1.concat(wordArray2); + * method: function () { + * } + * }); */ - concat: function (wordArray) { - // Shortcuts - var thisWords = this.words; - var thatWords = wordArray.words; - var thisSigBytes = this.sigBytes; - var thatSigBytes = wordArray.sigBytes; - - // Clamp excess bits - this.clamp(); - - // Concat - if (thisSigBytes % 4) { - // Copy one byte at a time - for (var i = 0; i < thatSigBytes; i++) { - var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); - } - } else if (thatWords.length > 0xffff) { - // Copy one word at a time - for (var i = 0; i < thatSigBytes; i += 4) { - thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; - } - } else { - // Copy all words at once - thisWords.push.apply(thisWords, thatWords); + extend: function (overrides) { + // Spawn + F.prototype = this; + const subtype = new F(); + + // Augment + if (overrides) { + subtype.mixIn(overrides); } - this.sigBytes += thatSigBytes; - - // Chainable - return this; - }, - /** - * Removes insignificant bits. - * - * @example - * - * wordArray.clamp(); - */ - clamp: function () { - // Shortcuts - var words = this.words; - var sigBytes = this.sigBytes; + // Create default initializer + if (!subtype.hasOwnProperty("init")) { + subtype.init = function () { + subtype.$super.init.apply(this, arguments); + }; + } - // Clamp - words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); - words.length = Math.ceil(sigBytes / 4); - }, + // Initializer's prototype is the subtype object + subtype.init.prototype = subtype; - /** - * Creates a copy of this word array. - * - * @return {WordArray} The clone. - * - * @example - * - * var clone = wordArray.clone(); - */ - clone: function () { - var clone = Base.clone.call(this); - clone.words = this.words.slice(0); + // Reference supertype + subtype.$super = this; - return clone; + return subtype; }, /** - * Creates a word array filled with random bytes. + * Extends this object and runs the init method. + * Arguments to create() will be passed to init(). * - * @param {number} nBytes The number of random bytes to generate. - * - * @return {WordArray} The random word array. + * @return {Object} The new object. * * @static * * @example * - * var wordArray = CryptoJS.lib.WordArray.random(16); + * var instance = MyType.create(); */ - random: function (nBytes) { - var words = []; - for (var i = 0; i < nBytes; i += 4) { - words.push((Math.random() * 0x100000000) | 0); - } - - return new WordArray.init(words, nBytes); - } - }); + create: function () { + const instance = this.extend(); + instance.init.apply(instance, arguments); - /** - * Encoder namespace. - */ - var C_enc = C.enc = {}; + return instance; + }, - /** - * Hex encoding strategy. - */ - var Hex = C_enc.Hex = { /** - * Converts a word array to a hex string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The hex string. - * - * @static + * Initializes a newly created object. + * Override this method to add some logic when your objects are created. * * @example * - * var hexString = CryptoJS.enc.Hex.stringify(wordArray); + * var MyType = CryptoJS.lib.Base.extend({ + * init: function () { + * // ... + * } + * }); */ - stringify: function (wordArray) { - // Shortcuts - var words = wordArray.words; - var sigBytes = wordArray.sigBytes; - - // Convert - var hexChars = []; - for (var i = 0; i < sigBytes; i++) { - var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - hexChars.push((bite >>> 4).toString(16)); - hexChars.push((bite & 0x0f).toString(16)); - } - - return hexChars.join(''); + init: function () { }, /** - * Converts a hex string to a word array. - * - * @param {string} hexStr The hex string. - * - * @return {WordArray} The word array. + * Copies properties into this object. * - * @static + * @param {Object} properties The properties to mix in. * * @example * - * var wordArray = CryptoJS.enc.Hex.parse(hexString); + * MyType.mixIn({ + * field: 'value' + * }); */ - parse: function (hexStr) { - // Shortcut - var hexStrLength = hexStr.length; - - // Convert - var words = []; - for (var i = 0; i < hexStrLength; i += 2) { - words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + mixIn: function (properties) { + for (const propertyName in properties) { + if (properties.hasOwnProperty(propertyName)) { + this[propertyName] = properties[propertyName]; + } } - return new WordArray.init(words, hexStrLength / 2); - } - }; - - /** - * Latin1 encoding strategy. - */ - var Latin1 = C_enc.Latin1 = { - /** - * Converts a word array to a Latin1 string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The Latin1 string. - * - * @static - * - * @example - * - * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); - */ - stringify: function (wordArray) { - // Shortcuts - var words = wordArray.words; - var sigBytes = wordArray.sigBytes; - - // Convert - var latin1Chars = []; - for (var i = 0; i < sigBytes; i++) { - var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - latin1Chars.push(String.fromCharCode(bite)); + // IE won't copy toString using the loop above + if (properties.hasOwnProperty("toString")) { + this.toString = properties.toString; } - - return latin1Chars.join(''); }, /** - * Converts a Latin1 string to a word array. - * - * @param {string} latin1Str The Latin1 string. - * - * @return {WordArray} The word array. + * Creates a copy of this object. * - * @static + * @return {Object} The clone. * * @example * - * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); + * var clone = instance.clone(); */ - parse: function (latin1Str) { - // Shortcut - var latin1StrLength = latin1Str.length; - - // Convert - var words = []; - for (var i = 0; i < latin1StrLength; i++) { - words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); - } - - return new WordArray.init(words, latin1StrLength); - } + clone: function () { + return this.init.prototype.extend(this); + }, }; + }()); + /** + * An array of 32-bit words. + * + * @property {Array} words The array of 32-bit words. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var WordArray = C_lib.WordArray = Base.extend({ /** - * UTF-8 encoding strategy. + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of 32-bit words. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.create(); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); */ - var Utf8 = C_enc.Utf8 = { - /** - * Converts a word array to a UTF-8 string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The UTF-8 string. - * - * @static - * - * @example - * - * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); - */ - stringify: function (wordArray) { - try { - return decodeURIComponent(escape(Latin1.stringify(wordArray))); - } catch (e) { - throw new Error('Malformed UTF-8 data'); - } - }, + init: function (words, sigBytes) { + words = this.words = words || []; - /** - * Converts a UTF-8 string to a word array. - * - * @param {string} utf8Str The UTF-8 string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); - */ - parse: function (utf8Str) { - return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 4; } - }; + }, /** - * Abstract buffered block algorithm template. + * Converts this word array to a string. + * + * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex + * + * @return {string} The stringified word array. * - * The property blockSize must be implemented in a concrete subtype. + * @example * - * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 + * var string = wordArray + ''; + * var string = wordArray.toString(); + * var string = wordArray.toString(CryptoJS.enc.Utf8); */ - var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ - /** - * Resets this block algorithm's data buffer to its initial state. - * - * @example - * - * bufferedBlockAlgorithm.reset(); - */ - reset: function () { - // Initial values - this._data = new WordArray.init(); - this._nDataBytes = 0; - }, + toString: function (encoder) { + return (encoder || Hex).stringify(this); + }, - /** - * Adds new data to this block algorithm's buffer. - * - * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. - * - * @example - * - * bufferedBlockAlgorithm._append('data'); - * bufferedBlockAlgorithm._append(wordArray); - */ - _append: function (data) { - // Convert string to WordArray, else assume WordArray already - if (typeof data == 'string') { - data = Utf8.parse(data); + /** + * Concatenates a word array to this word array. + * + * @param {WordArray} wordArray The word array to append. + * + * @return {WordArray} This word array. + * + * @example + * + * wordArray1.concat(wordArray2); + */ + concat: function (wordArray) { + // Shortcuts + const thisWords = this.words; + const thatWords = wordArray.words; + const thisSigBytes = this.sigBytes; + const thatSigBytes = wordArray.sigBytes; + + // Clamp excess bits + this.clamp(); + + // Concat + if (thisSigBytes % 4) { + // Copy one byte at a time + for (var i = 0; i < thatSigBytes; i++) { + const thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); } - - // Append - this._data.concat(data); - this._nDataBytes += data.sigBytes; - }, - - /** - * Processes available data blocks. - * - * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. - * - * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. - * - * @return {WordArray} The processed data. - * - * @example - * - * var processedData = bufferedBlockAlgorithm._process(); - * var processedData = bufferedBlockAlgorithm._process(!!'flush'); - */ - _process: function (doFlush) { - // Shortcuts - var data = this._data; - var dataWords = data.words; - var dataSigBytes = data.sigBytes; - var blockSize = this.blockSize; - var blockSizeBytes = blockSize * 4; - - // Count blocks ready - var nBlocksReady = dataSigBytes / blockSizeBytes; - if (doFlush) { - // Round up to include partial blocks - nBlocksReady = Math.ceil(nBlocksReady); - } else { - // Round down to include only full blocks, - // less the number of blocks that must remain in the buffer - nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } else if (thatWords.length > 0xffff) { + // Copy one word at a time + for (var i = 0; i < thatSigBytes; i += 4) { + thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; } + } else { + // Copy all words at once + thisWords.push.apply(thisWords, thatWords); + } + this.sigBytes += thatSigBytes; - // Count words ready - var nWordsReady = nBlocksReady * blockSize; - - // Count bytes ready - var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); + // Chainable + return this; + }, - // Process blocks - if (nWordsReady) { - for (var offset = 0; offset < nWordsReady; offset += blockSize) { - // Perform concrete-algorithm logic - this._doProcessBlock(dataWords, offset); - } + /** + * Removes insignificant bits. + * + * @example + * + * wordArray.clamp(); + */ + clamp: function () { + // Shortcuts + const words = this.words; + const sigBytes = this.sigBytes; + + // Clamp + words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); + words.length = Math.ceil(sigBytes / 4); + }, - // Remove processed words - var processedWords = dataWords.splice(0, nWordsReady); - data.sigBytes -= nBytesReady; - } + /** + * Creates a copy of this word array. + * + * @return {WordArray} The clone. + * + * @example + * + * var clone = wordArray.clone(); + */ + clone: function () { + const clone = Base.clone.call(this); + clone.words = this.words.slice(0); - // Return processed words - return new WordArray.init(processedWords, nBytesReady); - }, + return clone; + }, - /** - * Creates a copy of this object. - * - * @return {Object} The clone. - * - * @example - * - * var clone = bufferedBlockAlgorithm.clone(); - */ - clone: function () { - var clone = Base.clone.call(this); - clone._data = this._data.clone(); + /** + * Creates a word array filled with random bytes. + * + * @param {number} nBytes The number of random bytes to generate. + * + * @return {WordArray} The random word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.random(16); + */ + random: function (nBytes) { + const words = []; + for (let i = 0; i < nBytes; i += 4) { + words.push((Math.random() * 0x100000000) | 0); + } - return clone; - }, + return new WordArray.init(words, nBytes); + }, + }); - _minBufferSize: 0 - }); + /** + * Encoder namespace. + */ + const C_enc = C.enc = {}; + /** + * Hex encoding strategy. + */ + var Hex = C_enc.Hex = { /** - * Abstract hasher template. + * Converts a word array to a hex string. * - * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) + * @param {WordArray} wordArray The word array. + * + * @return {string} The hex string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.enc.Hex.stringify(wordArray); */ - var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ - /** - * Configuration options. - */ - cfg: Base.extend(), - - /** - * Initializes a newly created hasher. - * - * @param {Object} cfg (Optional) The configuration options to use for this hash computation. - * - * @example - * - * var hasher = CryptoJS.algo.SHA256.create(); - */ - init: function (cfg) { - // Apply config defaults - this.cfg = this.cfg.extend(cfg); - - // Set initial values - this.reset(); - }, + stringify: function (wordArray) { + // Shortcuts + const words = wordArray.words; + const sigBytes = wordArray.sigBytes; + + // Convert + const hexChars = []; + for (let i = 0; i < sigBytes; i++) { + const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + hexChars.push((bite >>> 4).toString(16)); + hexChars.push((bite & 0x0f).toString(16)); + } - /** - * Resets this hasher to its initial state. - * - * @example - * - * hasher.reset(); - */ - reset: function () { - // Reset data buffer - BufferedBlockAlgorithm.reset.call(this); + return hexChars.join(""); + }, - // Perform concrete-hasher logic - this._doReset(); - }, - - /** - * Updates this hasher with a message. - * - * @param {WordArray|string} messageUpdate The message to append. - * - * @return {Hasher} This hasher. - * - * @example - * - * hasher.update('message'); - * hasher.update(wordArray); - */ - update: function (messageUpdate) { - // Append - this._append(messageUpdate); - - // Update the hash - this._process(); - - // Chainable - return this; - }, + /** + * Converts a hex string to a word array. + * + * @param {string} hexStr The hex string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Hex.parse(hexString); + */ + parse: function (hexStr) { + // Shortcut + const hexStrLength = hexStr.length; + + // Convert + const words = []; + for (let i = 0; i < hexStrLength; i += 2) { + words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + } - /** - * Finalizes the hash computation. - * Note that the finalize operation is effectively a destructive, read-once operation. - * - * @param {WordArray|string} messageUpdate (Optional) A final message update. - * - * @return {WordArray} The hash. - * - * @example - * - * var hash = hasher.finalize(); - * var hash = hasher.finalize('message'); - * var hash = hasher.finalize(wordArray); - */ - finalize: function (messageUpdate) { - // Final message update - if (messageUpdate) { - this._append(messageUpdate); - } + return new WordArray.init(words, hexStrLength / 2); + }, + }; - // Perform concrete-hasher logic - var hash = this._doFinalize(); + /** + * Latin1 encoding strategy. + */ + const Latin1 = C_enc.Latin1 = { + /** + * Converts a word array to a Latin1 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Latin1 string. + * + * @static + * + * @example + * + * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + const words = wordArray.words; + const sigBytes = wordArray.sigBytes; + + // Convert + const latin1Chars = []; + for (let i = 0; i < sigBytes; i++) { + const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + latin1Chars.push(String.fromCharCode(bite)); + } - return hash; - }, + return latin1Chars.join(""); + }, - blockSize: 512 / 32, + /** + * Converts a Latin1 string to a word array. + * + * @param {string} latin1Str The Latin1 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); + */ + parse: function (latin1Str) { + // Shortcut + const latin1StrLength = latin1Str.length; + + // Convert + const words = []; + for (let i = 0; i < latin1StrLength; i++) { + words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); + } - /** - * Creates a shortcut function to a hasher's object interface. - * - * @param {Hasher} hasher The hasher to create a helper for. - * - * @return {Function} The shortcut function. - * - * @static - * - * @example - * - * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); - */ - _createHelper: function (hasher) { - return function (message, cfg) { - return new hasher.init(cfg).finalize(message); - }; - }, + return new WordArray.init(words, latin1StrLength); + }, + }; - /** - * Creates a shortcut function to the HMAC's object interface. - * - * @param {Hasher} hasher The hasher to use in this HMAC helper. - * - * @return {Function} The shortcut function. - * - * @static - * - * @example - * - * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); - */ - _createHmacHelper: function (hasher) { - return function (message, key) { - return new C_algo.HMAC.init(hasher, key).finalize(message); - }; + /** + * UTF-8 encoding strategy. + */ + const Utf8 = C_enc.Utf8 = { + /** + * Converts a word array to a UTF-8 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-8 string. + * + * @static + * + * @example + * + * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); + */ + stringify: function (wordArray) { + try { + return decodeURIComponent(escape(Latin1.stringify(wordArray))); + } catch (e) { + throw new Error("Malformed UTF-8 data"); } - }); + }, /** - * Algorithm namespace. + * Converts a UTF-8 string to a word array. + * + * @param {string} utf8Str The UTF-8 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); */ - var C_algo = C.algo = {}; - - return C; - }(Math)); - - /* - CryptoJS v3.1.2 - code.google.com/p/crypto-js - (c) 2009-2013 by Jeff Mott. All rights reserved. - code.google.com/p/crypto-js/wiki/License - */ - (function () { - // Shortcuts - var C = CryptoJS; - var C_lib = C.lib; - var WordArray = C_lib.WordArray; - var C_enc = C.enc; + parse: function (utf8Str) { + return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + }, + }; + /** + * Abstract buffered block algorithm template. + * + * The property blockSize must be implemented in a concrete subtype. + * + * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 + */ + const BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ /** - * Base64 encoding strategy. + * Resets this block algorithm's data buffer to its initial state. + * + * @example + * + * bufferedBlockAlgorithm.reset(); */ - var Base64 = C_enc.Base64 = { - /** - * Converts a word array to a Base64 string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The Base64 string. - * - * @static - * - * @example - * - * var base64String = CryptoJS.enc.Base64.stringify(wordArray); - */ - stringify: function (wordArray) { - // Shortcuts - var words = wordArray.words; - var sigBytes = wordArray.sigBytes; - var map = this._map; - - // Clamp excess bits - wordArray.clamp(); - - // Convert - var base64Chars = []; - for (var i = 0; i < sigBytes; i += 3) { - var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; - var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + reset: function () { + // Initial values + this._data = new WordArray.init(); + this._nDataBytes = 0; + }, - var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + /** + * Adds new data to this block algorithm's buffer. + * + * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. + * + * @example + * + * bufferedBlockAlgorithm._append('data'); + * bufferedBlockAlgorithm._append(wordArray); + */ + _append: function (data) { + // Convert string to WordArray, else assume WordArray already + if (typeof data == "string") { + data = Utf8.parse(data); + } - for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { - base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); - } - } + // Append + this._data.concat(data); + this._nDataBytes += data.sigBytes; + }, - // Add padding - var paddingChar = map.charAt(64); - if (paddingChar) { - while (base64Chars.length % 4) { - base64Chars.push(paddingChar); - } - } + /** + * Processes available data blocks. + * + * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. + * + * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. + * + * @return {WordArray} The processed data. + * + * @example + * + * var processedData = bufferedBlockAlgorithm._process(); + * var processedData = bufferedBlockAlgorithm._process(!!'flush'); + */ + _process: function (doFlush) { + // Shortcuts + const data = this._data; + const dataWords = data.words; + const dataSigBytes = data.sigBytes; + const blockSize = this.blockSize; + const blockSizeBytes = blockSize * 4; + + // Count blocks ready + let nBlocksReady = dataSigBytes / blockSizeBytes; + if (doFlush) { + // Round up to include partial blocks + nBlocksReady = Math.ceil(nBlocksReady); + } else { + // Round down to include only full blocks, + // less the number of blocks that must remain in the buffer + nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } - return base64Chars.join(''); - }, + // Count words ready + const nWordsReady = nBlocksReady * blockSize; - /** - * Converts a Base64 string to a word array. - * - * @param {string} base64Str The Base64 string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Base64.parse(base64String); - */ - parse: function (base64Str) { - // Shortcuts - var base64StrLength = base64Str.length; - var map = this._map; - - // Ignore padding - var paddingChar = map.charAt(64); - if (paddingChar) { - var paddingIndex = base64Str.indexOf(paddingChar); - if (paddingIndex != -1) { - base64StrLength = paddingIndex; - } - } + // Count bytes ready + const nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); - // Convert - var words = []; - var nBytes = 0; - for (var i = 0; i < base64StrLength; i++) { - if (i % 4) { - var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2); - var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2); - words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); - nBytes++; - } + // Process blocks + if (nWordsReady) { + for (let offset = 0; offset < nWordsReady; offset += blockSize) { + // Perform concrete-algorithm logic + this._doProcessBlock(dataWords, offset); } - return WordArray.create(words, nBytes); - }, - - _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' - }; - }()); - - /* - CryptoJS v3.1.2 - code.google.com/p/crypto-js - (c) 2009-2013 by Jeff Mott. All rights reserved. - code.google.com/p/crypto-js/wiki/License - */ - (function (Math) { - // Shortcuts - var C = CryptoJS; - var C_lib = C.lib; - var WordArray = C_lib.WordArray; - var Hasher = C_lib.Hasher; - var C_algo = C.algo; - - // Constants table - var T = []; - - // Compute constants - (function () { - for (var i = 0; i < 64; i++) { - T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0; + // Remove processed words + var processedWords = dataWords.splice(0, nWordsReady); + data.sigBytes -= nBytesReady; } - }()); + + // Return processed words + return new WordArray.init(processedWords, nBytesReady); + }, /** - * MD5 hash algorithm. + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = bufferedBlockAlgorithm.clone(); */ - var MD5 = C_algo.MD5 = Hasher.extend({ - _doReset: function () { - this._hash = new WordArray.init([ - 0x67452301, 0xefcdab89, - 0x98badcfe, 0x10325476 - ]); - }, - - _doProcessBlock: function (M, offset) { - // Swap endian - for (var i = 0; i < 16; i++) { - // Shortcuts - var offset_i = offset + i; - var M_offset_i = M[offset_i]; - - M[offset_i] = ( - (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | - (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) - ); - } + clone: function () { + const clone = Base.clone.call(this); + clone._data = this._data.clone(); - // Shortcuts - var H = this._hash.words; - - var M_offset_0 = M[offset + 0]; - var M_offset_1 = M[offset + 1]; - var M_offset_2 = M[offset + 2]; - var M_offset_3 = M[offset + 3]; - var M_offset_4 = M[offset + 4]; - var M_offset_5 = M[offset + 5]; - var M_offset_6 = M[offset + 6]; - var M_offset_7 = M[offset + 7]; - var M_offset_8 = M[offset + 8]; - var M_offset_9 = M[offset + 9]; - var M_offset_10 = M[offset + 10]; - var M_offset_11 = M[offset + 11]; - var M_offset_12 = M[offset + 12]; - var M_offset_13 = M[offset + 13]; - var M_offset_14 = M[offset + 14]; - var M_offset_15 = M[offset + 15]; - - // Working varialbes - var a = H[0]; - var b = H[1]; - var c = H[2]; - var d = H[3]; - - // Computation - a = FF(a, b, c, d, M_offset_0, 7, T[0]); - d = FF(d, a, b, c, M_offset_1, 12, T[1]); - c = FF(c, d, a, b, M_offset_2, 17, T[2]); - b = FF(b, c, d, a, M_offset_3, 22, T[3]); - a = FF(a, b, c, d, M_offset_4, 7, T[4]); - d = FF(d, a, b, c, M_offset_5, 12, T[5]); - c = FF(c, d, a, b, M_offset_6, 17, T[6]); - b = FF(b, c, d, a, M_offset_7, 22, T[7]); - a = FF(a, b, c, d, M_offset_8, 7, T[8]); - d = FF(d, a, b, c, M_offset_9, 12, T[9]); - c = FF(c, d, a, b, M_offset_10, 17, T[10]); - b = FF(b, c, d, a, M_offset_11, 22, T[11]); - a = FF(a, b, c, d, M_offset_12, 7, T[12]); - d = FF(d, a, b, c, M_offset_13, 12, T[13]); - c = FF(c, d, a, b, M_offset_14, 17, T[14]); - b = FF(b, c, d, a, M_offset_15, 22, T[15]); - - a = GG(a, b, c, d, M_offset_1, 5, T[16]); - d = GG(d, a, b, c, M_offset_6, 9, T[17]); - c = GG(c, d, a, b, M_offset_11, 14, T[18]); - b = GG(b, c, d, a, M_offset_0, 20, T[19]); - a = GG(a, b, c, d, M_offset_5, 5, T[20]); - d = GG(d, a, b, c, M_offset_10, 9, T[21]); - c = GG(c, d, a, b, M_offset_15, 14, T[22]); - b = GG(b, c, d, a, M_offset_4, 20, T[23]); - a = GG(a, b, c, d, M_offset_9, 5, T[24]); - d = GG(d, a, b, c, M_offset_14, 9, T[25]); - c = GG(c, d, a, b, M_offset_3, 14, T[26]); - b = GG(b, c, d, a, M_offset_8, 20, T[27]); - a = GG(a, b, c, d, M_offset_13, 5, T[28]); - d = GG(d, a, b, c, M_offset_2, 9, T[29]); - c = GG(c, d, a, b, M_offset_7, 14, T[30]); - b = GG(b, c, d, a, M_offset_12, 20, T[31]); - - a = HH(a, b, c, d, M_offset_5, 4, T[32]); - d = HH(d, a, b, c, M_offset_8, 11, T[33]); - c = HH(c, d, a, b, M_offset_11, 16, T[34]); - b = HH(b, c, d, a, M_offset_14, 23, T[35]); - a = HH(a, b, c, d, M_offset_1, 4, T[36]); - d = HH(d, a, b, c, M_offset_4, 11, T[37]); - c = HH(c, d, a, b, M_offset_7, 16, T[38]); - b = HH(b, c, d, a, M_offset_10, 23, T[39]); - a = HH(a, b, c, d, M_offset_13, 4, T[40]); - d = HH(d, a, b, c, M_offset_0, 11, T[41]); - c = HH(c, d, a, b, M_offset_3, 16, T[42]); - b = HH(b, c, d, a, M_offset_6, 23, T[43]); - a = HH(a, b, c, d, M_offset_9, 4, T[44]); - d = HH(d, a, b, c, M_offset_12, 11, T[45]); - c = HH(c, d, a, b, M_offset_15, 16, T[46]); - b = HH(b, c, d, a, M_offset_2, 23, T[47]); - - a = II(a, b, c, d, M_offset_0, 6, T[48]); - d = II(d, a, b, c, M_offset_7, 10, T[49]); - c = II(c, d, a, b, M_offset_14, 15, T[50]); - b = II(b, c, d, a, M_offset_5, 21, T[51]); - a = II(a, b, c, d, M_offset_12, 6, T[52]); - d = II(d, a, b, c, M_offset_3, 10, T[53]); - c = II(c, d, a, b, M_offset_10, 15, T[54]); - b = II(b, c, d, a, M_offset_1, 21, T[55]); - a = II(a, b, c, d, M_offset_8, 6, T[56]); - d = II(d, a, b, c, M_offset_15, 10, T[57]); - c = II(c, d, a, b, M_offset_6, 15, T[58]); - b = II(b, c, d, a, M_offset_13, 21, T[59]); - a = II(a, b, c, d, M_offset_4, 6, T[60]); - d = II(d, a, b, c, M_offset_11, 10, T[61]); - c = II(c, d, a, b, M_offset_2, 15, T[62]); - b = II(b, c, d, a, M_offset_9, 21, T[63]); - - // Intermediate hash value - H[0] = (H[0] + a) | 0; - H[1] = (H[1] + b) | 0; - H[2] = (H[2] + c) | 0; - H[3] = (H[3] + d) | 0; - }, - - _doFinalize: function () { - // Shortcuts - var data = this._data; - var dataWords = data.words; - - var nBitsTotal = this._nDataBytes * 8; - var nBitsLeft = data.sigBytes * 8; + return clone; + }, - // Add padding - dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + _minBufferSize: 0, + }); - var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000); - var nBitsTotalL = nBitsTotal; - dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = ( - (((nBitsTotalH << 8) | (nBitsTotalH >>> 24)) & 0x00ff00ff) | - (((nBitsTotalH << 24) | (nBitsTotalH >>> 8)) & 0xff00ff00) - ); - dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( - (((nBitsTotalL << 8) | (nBitsTotalL >>> 24)) & 0x00ff00ff) | - (((nBitsTotalL << 24) | (nBitsTotalL >>> 8)) & 0xff00ff00) - ); + /** + * Abstract hasher template. + * + * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) + */ + const Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + */ + cfg: Base.extend(), - data.sigBytes = (dataWords.length + 1) * 4; + /** + * Initializes a newly created hasher. + * + * @param {Object} cfg (Optional) The configuration options to use for this hash computation. + * + * @example + * + * var hasher = CryptoJS.algo.SHA256.create(); + */ + init: function (cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); - // Hash final blocks - this._process(); + // Set initial values + this.reset(); + }, - // Shortcuts - var hash = this._hash; - var H = hash.words; + /** + * Resets this hasher to its initial state. + * + * @example + * + * hasher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); - // Swap endian - for (var i = 0; i < 4; i++) { - // Shortcut - var H_i = H[i]; + // Perform concrete-hasher logic + this._doReset(); + }, - H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | - (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); - } + /** + * Updates this hasher with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {Hasher} This hasher. + * + * @example + * + * hasher.update('message'); + * hasher.update(wordArray); + */ + update: function (messageUpdate) { + // Append + this._append(messageUpdate); - // Return final computed hash - return hash; - }, + // Update the hash + this._process(); - clone: function () { - var clone = Hasher.clone.call(this); - clone._hash = this._hash.clone(); + // Chainable + return this; + }, - return clone; + /** + * Finalizes the hash computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The hash. + * + * @example + * + * var hash = hasher.finalize(); + * var hash = hasher.finalize('message'); + * var hash = hasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Final message update + if (messageUpdate) { + this._append(messageUpdate); } - }); - - function FF (a, b, c, d, x, s, t) { - var n = a + ((b & c) | (~b & d)) + x + t; - return ((n << s) | (n >>> (32 - s))) + b; - } - function GG (a, b, c, d, x, s, t) { - var n = a + ((b & d) | (c & ~d)) + x + t; - return ((n << s) | (n >>> (32 - s))) + b; - } + // Perform concrete-hasher logic + const hash = this._doFinalize(); - function HH (a, b, c, d, x, s, t) { - var n = a + (b ^ c ^ d) + x + t; - return ((n << s) | (n >>> (32 - s))) + b; - } + return hash; + }, - function II (a, b, c, d, x, s, t) { - var n = a + (c ^ (b | ~d)) + x + t; - return ((n << s) | (n >>> (32 - s))) + b; - } + blockSize: 512 / 32, /** - * Shortcut function to the hasher's object interface. + * Creates a shortcut function to a hasher's object interface. * - * @param {WordArray|string} message The message to hash. + * @param {Hasher} hasher The hasher to create a helper for. * - * @return {WordArray} The hash. + * @return {Function} The shortcut function. * * @static * * @example * - * var hash = CryptoJS.MD5('message'); - * var hash = CryptoJS.MD5(wordArray); + * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); */ - C.MD5 = Hasher._createHelper(MD5); + _createHelper: function (hasher) { + return function (message, cfg) { + return new hasher.init(cfg).finalize(message); + }; + }, /** - * Shortcut function to the HMAC's object interface. + * Creates a shortcut function to the HMAC's object interface. * - * @param {WordArray|string} message The message to hash. - * @param {WordArray|string} key The secret key. + * @param {Hasher} hasher The hasher to use in this HMAC helper. * - * @return {WordArray} The HMAC. + * @return {Function} The shortcut function. * * @static * * @example * - * var hmac = CryptoJS.HmacMD5(message, key); + * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); */ - C.HmacMD5 = Hasher._createHmacHelper(MD5); - }(Math)); - - /* - CryptoJS v3.1.2 - code.google.com/p/crypto-js - (c) 2009-2013 by Jeff Mott. All rights reserved. - code.google.com/p/crypto-js/wiki/License - */ - (function () { - // Shortcuts - var C = CryptoJS; - var C_lib = C.lib; - var Base = C_lib.Base; - var WordArray = C_lib.WordArray; - var C_algo = C.algo; - var MD5 = C_algo.MD5; + _createHmacHelper: function (hasher) { + return function (message, key) { + return new C_algo.HMAC.init(hasher, key).finalize(message); + }; + }, + }); + /** + * Algorithm namespace. + */ + var C_algo = C.algo = {}; + + return C; +}(Math)); + +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +(function () { + // Shortcuts + const C = CryptoJS; + const C_lib = C.lib; + const WordArray = C_lib.WordArray; + const C_enc = C.enc; + + /** + * Base64 encoding strategy. + */ + const Base64 = C_enc.Base64 = { /** - * This key derivation function is meant to conform with EVP_BytesToKey. - * www.openssl.org/docs/crypto/EVP_BytesToKey.html + * Converts a word array to a Base64 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Base64 string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64.stringify(wordArray); */ - var EvpKDF = C_algo.EvpKDF = Base.extend({ - /** - * Configuration options. - * - * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) - * @property {Hasher} hasher The hash algorithm to use. Default: MD5 - * @property {number} iterations The number of iterations to perform. Default: 1 - */ - cfg: Base.extend({ - keySize: 128 / 32, - hasher: MD5, - iterations: 1 - }), - - /** - * Initializes a newly created key derivation function. - * - * @param {Object} cfg (Optional) The configuration options to use for the derivation. - * - * @example - * - * var kdf = CryptoJS.algo.EvpKDF.create(); - * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 }); - * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 }); - */ - init: function (cfg) { - this.cfg = this.cfg.extend(cfg); - }, - - /** - * Derives a key from a password. - * - * @param {WordArray|string} password The password. - * @param {WordArray|string} salt A salt. - * - * @return {WordArray} The derived key. - * - * @example - * - * var key = kdf.compute(password, salt); - */ - compute: function (password, salt) { - // Shortcut - var cfg = this.cfg; - - // Init hasher - var hasher = cfg.hasher.create(); - - // Initial values - var derivedKey = WordArray.create(); - - // Shortcuts - var derivedKeyWords = derivedKey.words; - var keySize = cfg.keySize; - var iterations = cfg.iterations; - - // Generate key - while (derivedKeyWords.length < keySize) { - if (block) { - hasher.update(block); - } - var block = hasher.update(password).finalize(salt); - hasher.reset(); - - // Iterations - for (var i = 1; i < iterations; i++) { - block = hasher.finalize(block); - hasher.reset(); - } - - derivedKey.concat(block); + stringify: function (wordArray) { + // Shortcuts + const words = wordArray.words; + const sigBytes = wordArray.sigBytes; + const map = this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + const base64Chars = []; + for (let i = 0; i < sigBytes; i += 3) { + const byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + const byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + const byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + const triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (let j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); } - derivedKey.sigBytes = keySize * 4; + } - return derivedKey; + // Add padding + const paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } } - }); + + return base64Chars.join(""); + }, /** - * Derives a key from a password. + * Converts a Base64 string to a word array. * - * @param {WordArray|string} password The password. - * @param {WordArray|string} salt A salt. - * @param {Object} cfg (Optional) The configuration options to use for this computation. + * @param {string} base64Str The Base64 string. * - * @return {WordArray} The derived key. + * @return {WordArray} The word array. * * @static * * @example * - * var key = CryptoJS.EvpKDF(password, salt); - * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 }); - * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 }); + * var wordArray = CryptoJS.enc.Base64.parse(base64String); */ - C.EvpKDF = function (password, salt, cfg) { - return EvpKDF.create(cfg).compute(password, salt); - }; - }()); + parse: function (base64Str) { + // Shortcuts + let base64StrLength = base64Str.length; + const map = this._map; + + // Ignore padding + const paddingChar = map.charAt(64); + if (paddingChar) { + const paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex != -1) { + base64StrLength = paddingIndex; + } + } + // Convert + const words = []; + let nBytes = 0; + for (let i = 0; i < base64StrLength; i++) { + if (i % 4) { + const bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2); + const bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2); + words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + + return WordArray.create(words, nBytes); + }, + + _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + }; +}()); + +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +(function (Math) { + // Shortcuts + const C = CryptoJS; + const C_lib = C.lib; + const WordArray = C_lib.WordArray; + const Hasher = C_lib.Hasher; + const C_algo = C.algo; + + // Constants table + const T = []; + + // Compute constants + (function () { + for (let i = 0; i < 64; i++) { + T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0; + } + }()); - /* - CryptoJS v3.1.2 - code.google.com/p/crypto-js - (c) 2009-2013 by Jeff Mott. All rights reserved. - code.google.com/p/crypto-js/wiki/License - */ /** - * Cipher core components. + * MD5 hash algorithm. */ - CryptoJS.lib.Cipher || (function (undefined) { - // Shortcuts - var C = CryptoJS; - var C_lib = C.lib; - var Base = C_lib.Base; - var WordArray = C_lib.WordArray; - var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm; - var C_enc = C.enc; - var Utf8 = C_enc.Utf8; - var Base64 = C_enc.Base64; - var C_algo = C.algo; - var EvpKDF = C_algo.EvpKDF; + const MD5 = C_algo.MD5 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476 + ]); + }, - /** - * Abstract base cipher template. - * - * @property {number} keySize This cipher's key size. Default: 4 (128 bits) - * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits) - * @property {number} _ENC_XFORM_MODE A constant representing encryption mode. - * @property {number} _DEC_XFORM_MODE A constant representing decryption mode. - */ - var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({ - /** - * Configuration options. - * - * @property {WordArray} iv The IV to use for this operation. - */ - cfg: Base.extend(), + _doProcessBlock: function (M, offset) { + // Swap endian + for (let i = 0; i < 16; i++) { + // Shortcuts + const offset_i = offset + i; + const M_offset_i = M[offset_i]; - /** - * Creates this cipher in encryption mode. - * - * @param {WordArray} key The key. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {Cipher} A cipher instance. - * - * @static - * - * @example - * - * var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray }); - */ - createEncryptor: function (key, cfg) { - return this.create(this._ENC_XFORM_MODE, key, cfg); - }, + M[offset_i] = ( + (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | + (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) + ); + } - /** - * Creates this cipher in decryption mode. - * - * @param {WordArray} key The key. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {Cipher} A cipher instance. - * - * @static - * - * @example - * - * var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray }); - */ - createDecryptor: function (key, cfg) { - return this.create(this._DEC_XFORM_MODE, key, cfg); - }, + // Shortcuts + const H = this._hash.words; + + const M_offset_0 = M[offset + 0]; + const M_offset_1 = M[offset + 1]; + const M_offset_2 = M[offset + 2]; + const M_offset_3 = M[offset + 3]; + const M_offset_4 = M[offset + 4]; + const M_offset_5 = M[offset + 5]; + const M_offset_6 = M[offset + 6]; + const M_offset_7 = M[offset + 7]; + const M_offset_8 = M[offset + 8]; + const M_offset_9 = M[offset + 9]; + const M_offset_10 = M[offset + 10]; + const M_offset_11 = M[offset + 11]; + const M_offset_12 = M[offset + 12]; + const M_offset_13 = M[offset + 13]; + const M_offset_14 = M[offset + 14]; + const M_offset_15 = M[offset + 15]; + + // Working varialbes + let a = H[0]; + let b = H[1]; + let c = H[2]; + let d = H[3]; + + // Computation + a = FF(a, b, c, d, M_offset_0, 7, T[0]); + d = FF(d, a, b, c, M_offset_1, 12, T[1]); + c = FF(c, d, a, b, M_offset_2, 17, T[2]); + b = FF(b, c, d, a, M_offset_3, 22, T[3]); + a = FF(a, b, c, d, M_offset_4, 7, T[4]); + d = FF(d, a, b, c, M_offset_5, 12, T[5]); + c = FF(c, d, a, b, M_offset_6, 17, T[6]); + b = FF(b, c, d, a, M_offset_7, 22, T[7]); + a = FF(a, b, c, d, M_offset_8, 7, T[8]); + d = FF(d, a, b, c, M_offset_9, 12, T[9]); + c = FF(c, d, a, b, M_offset_10, 17, T[10]); + b = FF(b, c, d, a, M_offset_11, 22, T[11]); + a = FF(a, b, c, d, M_offset_12, 7, T[12]); + d = FF(d, a, b, c, M_offset_13, 12, T[13]); + c = FF(c, d, a, b, M_offset_14, 17, T[14]); + b = FF(b, c, d, a, M_offset_15, 22, T[15]); + + a = GG(a, b, c, d, M_offset_1, 5, T[16]); + d = GG(d, a, b, c, M_offset_6, 9, T[17]); + c = GG(c, d, a, b, M_offset_11, 14, T[18]); + b = GG(b, c, d, a, M_offset_0, 20, T[19]); + a = GG(a, b, c, d, M_offset_5, 5, T[20]); + d = GG(d, a, b, c, M_offset_10, 9, T[21]); + c = GG(c, d, a, b, M_offset_15, 14, T[22]); + b = GG(b, c, d, a, M_offset_4, 20, T[23]); + a = GG(a, b, c, d, M_offset_9, 5, T[24]); + d = GG(d, a, b, c, M_offset_14, 9, T[25]); + c = GG(c, d, a, b, M_offset_3, 14, T[26]); + b = GG(b, c, d, a, M_offset_8, 20, T[27]); + a = GG(a, b, c, d, M_offset_13, 5, T[28]); + d = GG(d, a, b, c, M_offset_2, 9, T[29]); + c = GG(c, d, a, b, M_offset_7, 14, T[30]); + b = GG(b, c, d, a, M_offset_12, 20, T[31]); + + a = HH(a, b, c, d, M_offset_5, 4, T[32]); + d = HH(d, a, b, c, M_offset_8, 11, T[33]); + c = HH(c, d, a, b, M_offset_11, 16, T[34]); + b = HH(b, c, d, a, M_offset_14, 23, T[35]); + a = HH(a, b, c, d, M_offset_1, 4, T[36]); + d = HH(d, a, b, c, M_offset_4, 11, T[37]); + c = HH(c, d, a, b, M_offset_7, 16, T[38]); + b = HH(b, c, d, a, M_offset_10, 23, T[39]); + a = HH(a, b, c, d, M_offset_13, 4, T[40]); + d = HH(d, a, b, c, M_offset_0, 11, T[41]); + c = HH(c, d, a, b, M_offset_3, 16, T[42]); + b = HH(b, c, d, a, M_offset_6, 23, T[43]); + a = HH(a, b, c, d, M_offset_9, 4, T[44]); + d = HH(d, a, b, c, M_offset_12, 11, T[45]); + c = HH(c, d, a, b, M_offset_15, 16, T[46]); + b = HH(b, c, d, a, M_offset_2, 23, T[47]); + + a = II(a, b, c, d, M_offset_0, 6, T[48]); + d = II(d, a, b, c, M_offset_7, 10, T[49]); + c = II(c, d, a, b, M_offset_14, 15, T[50]); + b = II(b, c, d, a, M_offset_5, 21, T[51]); + a = II(a, b, c, d, M_offset_12, 6, T[52]); + d = II(d, a, b, c, M_offset_3, 10, T[53]); + c = II(c, d, a, b, M_offset_10, 15, T[54]); + b = II(b, c, d, a, M_offset_1, 21, T[55]); + a = II(a, b, c, d, M_offset_8, 6, T[56]); + d = II(d, a, b, c, M_offset_15, 10, T[57]); + c = II(c, d, a, b, M_offset_6, 15, T[58]); + b = II(b, c, d, a, M_offset_13, 21, T[59]); + a = II(a, b, c, d, M_offset_4, 6, T[60]); + d = II(d, a, b, c, M_offset_11, 10, T[61]); + c = II(c, d, a, b, M_offset_2, 15, T[62]); + b = II(b, c, d, a, M_offset_9, 21, T[63]); + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + }, - /** - * Initializes a newly created cipher. - * - * @param {number} xformMode Either the encryption or decryption transormation mode constant. - * @param {WordArray} key The key. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @example - * - * var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }); - */ - init: function (xformMode, key, cfg) { - // Apply config defaults - this.cfg = this.cfg.extend(cfg); + _doFinalize: function () { + // Shortcuts + const data = this._data; + const dataWords = data.words; - // Store transform mode and key - this._xformMode = xformMode; - this._key = key; + const nBitsTotal = this._nDataBytes * 8; + const nBitsLeft = data.sigBytes * 8; - // Set initial values - this.reset(); - }, + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); - /** - * Resets this cipher to its initial state. - * - * @example - * - * cipher.reset(); - */ - reset: function () { - // Reset data buffer - BufferedBlockAlgorithm.reset.call(this); + const nBitsTotalH = Math.floor(nBitsTotal / 0x100000000); + const nBitsTotalL = nBitsTotal; + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = ( + (((nBitsTotalH << 8) | (nBitsTotalH >>> 24)) & 0x00ff00ff) | + (((nBitsTotalH << 24) | (nBitsTotalH >>> 8)) & 0xff00ff00) + ); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( + (((nBitsTotalL << 8) | (nBitsTotalL >>> 24)) & 0x00ff00ff) | + (((nBitsTotalL << 24) | (nBitsTotalL >>> 8)) & 0xff00ff00) + ); - // Perform concrete-cipher logic - this._doReset(); - }, + data.sigBytes = (dataWords.length + 1) * 4; - /** - * Adds data to be encrypted or decrypted. - * - * @param {WordArray|string} dataUpdate The data to encrypt or decrypt. - * - * @return {WordArray} The data after processing. - * - * @example - * - * var encrypted = cipher.process('data'); - * var encrypted = cipher.process(wordArray); - */ - process: function (dataUpdate) { - // Append - this._append(dataUpdate); + // Hash final blocks + this._process(); - // Process available blocks - return this._process(); - }, + // Shortcuts + const hash = this._hash; + const H = hash.words; - /** - * Finalizes the encryption or decryption process. - * Note that the finalize operation is effectively a destructive, read-once operation. - * - * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt. - * - * @return {WordArray} The data after final processing. - * - * @example - * - * var encrypted = cipher.finalize(); - * var encrypted = cipher.finalize('data'); - * var encrypted = cipher.finalize(wordArray); - */ - finalize: function (dataUpdate) { - // Final data update - if (dataUpdate) { - this._append(dataUpdate); - } + // Swap endian + for (let i = 0; i < 4; i++) { + // Shortcut + const H_i = H[i]; - // Perform concrete-cipher logic - var finalProcessedData = this._doFinalize(); + H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | + (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); + } - return finalProcessedData; - }, + // Return final computed hash + return hash; + }, + + clone: function () { + const clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + }, + }); + + function FF(a, b, c, d, x, s, t) { + const n = a + ((b & c) | (~b & d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function GG(a, b, c, d, x, s, t) { + const n = a + ((b & d) | (c & ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function HH(a, b, c, d, x, s, t) { + const n = a + (b ^ c ^ d) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function II(a, b, c, d, x, s, t) { + const n = a + (c ^ (b | ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.MD5('message'); + * var hash = CryptoJS.MD5(wordArray); + */ + C.MD5 = Hasher._createHelper(MD5); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacMD5(message, key); + */ + C.HmacMD5 = Hasher._createHmacHelper(MD5); +}(Math)); + +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +(function () { + // Shortcuts + const C = CryptoJS; + const C_lib = C.lib; + const Base = C_lib.Base; + const WordArray = C_lib.WordArray; + const C_algo = C.algo; + const MD5 = C_algo.MD5; + + /** + * This key derivation function is meant to conform with EVP_BytesToKey. + * www.openssl.org/docs/crypto/EVP_BytesToKey.html + */ + const EvpKDF = C_algo.EvpKDF = Base.extend({ + /** + * Configuration options. + * + * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) + * @property {Hasher} hasher The hash algorithm to use. Default: MD5 + * @property {number} iterations The number of iterations to perform. Default: 1 + */ + cfg: Base.extend({ keySize: 128 / 32, + hasher: MD5, + iterations: 1, + }), + + /** + * Initializes a newly created key derivation function. + * + * @param {Object} cfg (Optional) The configuration options to use for the derivation. + * + * @example + * + * var kdf = CryptoJS.algo.EvpKDF.create(); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 }); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 }); + */ + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + }, - ivSize: 128 / 32, + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * + * @return {WordArray} The derived key. + * + * @example + * + * var key = kdf.compute(password, salt); + */ + compute: function (password, salt) { + // Shortcut + const cfg = this.cfg; - _ENC_XFORM_MODE: 1, + // Init hasher + const hasher = cfg.hasher.create(); - _DEC_XFORM_MODE: 2, + // Initial values + const derivedKey = WordArray.create(); - /** - * Creates shortcut functions to a cipher's object interface. - * - * @param {Cipher} cipher The cipher to create a helper for. - * - * @return {Object} An object with encrypt and decrypt shortcut functions. - * - * @static - * - * @example - * - * var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES); - */ - _createHelper: (function () { - function selectCipherStrategy (key) { - if (typeof key == 'string') { - return PasswordBasedCipher; - } else { - return SerializableCipher; - } + // Shortcuts + const derivedKeyWords = derivedKey.words; + const keySize = cfg.keySize; + const iterations = cfg.iterations; + + // Generate key + while (derivedKeyWords.length < keySize) { + if (block) { + hasher.update(block); + } + var block = hasher.update(password).finalize(salt); + hasher.reset(); + + // Iterations + for (let i = 1; i < iterations; i++) { + block = hasher.finalize(block); + hasher.reset(); } - return function (cipher) { - return { - encrypt: function (message, key, cfg) { - return selectCipherStrategy(key).encrypt(cipher, message, key, cfg); - }, + derivedKey.concat(block); + } + derivedKey.sigBytes = keySize * 4; + + return derivedKey; + }, + }); + + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * @param {Object} cfg (Optional) The configuration options to use for this computation. + * + * @return {WordArray} The derived key. + * + * @static + * + * @example + * + * var key = CryptoJS.EvpKDF(password, salt); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 }); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 }); + */ + C.EvpKDF = function (password, salt, cfg) { + return EvpKDF.create(cfg).compute(password, salt); + }; +}()); + + +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +/** + * Cipher core components. + */ +CryptoJS.lib.Cipher || (function (undefined) { + // Shortcuts + const C = CryptoJS; + const C_lib = C.lib; + const Base = C_lib.Base; + const WordArray = C_lib.WordArray; + const BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm; + const C_enc = C.enc; + const Utf8 = C_enc.Utf8; + const Base64 = C_enc.Base64; + const C_algo = C.algo; + const EvpKDF = C_algo.EvpKDF; + + /** + * Abstract base cipher template. + * + * @property {number} keySize This cipher's key size. Default: 4 (128 bits) + * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits) + * @property {number} _ENC_XFORM_MODE A constant representing encryption mode. + * @property {number} _DEC_XFORM_MODE A constant representing decryption mode. + */ + const Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + * + * @property {WordArray} iv The IV to use for this operation. + */ + cfg: Base.extend(), + + /** + * Creates this cipher in encryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray }); + */ + createEncryptor: function (key, cfg) { + return this.create(this._ENC_XFORM_MODE, key, cfg); + }, - decrypt: function (ciphertext, key, cfg) { - return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg); - } - }; - }; - }()) - }); + /** + * Creates this cipher in decryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray }); + */ + createDecryptor: function (key, cfg) { + return this.create(this._DEC_XFORM_MODE, key, cfg); + }, /** - * Abstract base stream cipher template. + * Initializes a newly created cipher. + * + * @param {number} xformMode Either the encryption or decryption transormation mode constant. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @example * - * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits) + * var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }); */ - var StreamCipher = C_lib.StreamCipher = Cipher.extend({ - _doFinalize: function () { - // Process partial blocks - var finalProcessedBlocks = this._process(!!'flush'); + init: function (xformMode, key, cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); - return finalProcessedBlocks; - }, + // Store transform mode and key + this._xformMode = xformMode; + this._key = key; - blockSize: 1 - }); + // Set initial values + this.reset(); + }, /** - * Mode namespace. + * Resets this cipher to its initial state. + * + * @example + * + * cipher.reset(); */ - var C_mode = C.mode = {}; + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-cipher logic + this._doReset(); + }, /** - * Abstract base block cipher mode template. + * Adds data to be encrypted or decrypted. + * + * @param {WordArray|string} dataUpdate The data to encrypt or decrypt. + * + * @return {WordArray} The data after processing. + * + * @example + * + * var encrypted = cipher.process('data'); + * var encrypted = cipher.process(wordArray); */ - var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({ - /** - * Creates this mode for encryption. - * - * @param {Cipher} cipher A block cipher instance. - * @param {Array} iv The IV words. - * - * @static - * - * @example - * - * var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words); - */ - createEncryptor: function (cipher, iv) { - return this.Encryptor.create(cipher, iv); - }, - - /** - * Creates this mode for decryption. - * - * @param {Cipher} cipher A block cipher instance. - * @param {Array} iv The IV words. - * - * @static - * - * @example - * - * var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words); - */ - createDecryptor: function (cipher, iv) { - return this.Decryptor.create(cipher, iv); - }, + process: function (dataUpdate) { + // Append + this._append(dataUpdate); - /** - * Initializes a newly created mode. - * - * @param {Cipher} cipher A block cipher instance. - * @param {Array} iv The IV words. - * - * @example - * - * var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words); - */ - init: function (cipher, iv) { - this._cipher = cipher; - this._iv = iv; - } - }); + // Process available blocks + return this._process(); + }, /** - * Cipher Block Chaining mode. + * Finalizes the encryption or decryption process. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt. + * + * @return {WordArray} The data after final processing. + * + * @example + * + * var encrypted = cipher.finalize(); + * var encrypted = cipher.finalize('data'); + * var encrypted = cipher.finalize(wordArray); */ - var CBC = C_mode.CBC = (function () { - /** - * Abstract base CBC mode. - */ - var CBC = BlockCipherMode.extend(); + finalize: function (dataUpdate) { + // Final data update + if (dataUpdate) { + this._append(dataUpdate); + } - /** - * CBC encryptor. - */ - CBC.Encryptor = CBC.extend({ - /** - * Processes the data block at offset. - * - * @param {Array} words The data words to operate on. - * @param {number} offset The offset where the block starts. - * - * @example - * - * mode.processBlock(data.words, offset); - */ - processBlock: function (words, offset) { - // Shortcuts - var cipher = this._cipher; - var blockSize = cipher.blockSize; - - // XOR and encrypt - xorBlock.call(this, words, offset, blockSize); - cipher.encryptBlock(words, offset); - - // Remember this block to use with next block - this._prevBlock = words.slice(offset, offset + blockSize); - } - }); + // Perform concrete-cipher logic + const finalProcessedData = this._doFinalize(); - /** - * CBC decryptor. - */ - CBC.Decryptor = CBC.extend({ - /** - * Processes the data block at offset. - * - * @param {Array} words The data words to operate on. - * @param {number} offset The offset where the block starts. - * - * @example - * - * mode.processBlock(data.words, offset); - */ - processBlock: function (words, offset) { - // Shortcuts - var cipher = this._cipher; - var blockSize = cipher.blockSize; - - // Remember this block to use with next block - var thisBlock = words.slice(offset, offset + blockSize); - - // Decrypt and XOR - cipher.decryptBlock(words, offset); - xorBlock.call(this, words, offset, blockSize); - - // This block becomes the previous block - this._prevBlock = thisBlock; - } - }); + return finalProcessedData; + }, - function xorBlock (words, offset, blockSize) { - // Shortcut - var iv = this._iv; + keySize: 128 / 32, - // Choose mixing block - if (iv) { - var block = iv; + ivSize: 128 / 32, - // Remove IV for subsequent blocks - this._iv = undefined; - } else { - var block = this._prevBlock; - } + _ENC_XFORM_MODE: 1, + + _DEC_XFORM_MODE: 2, - // XOR blocks - for (var i = 0; i < blockSize; i++) { - words[offset + i] ^= block[i]; + /** + * Creates shortcut functions to a cipher's object interface. + * + * @param {Cipher} cipher The cipher to create a helper for. + * + * @return {Object} An object with encrypt and decrypt shortcut functions. + * + * @static + * + * @example + * + * var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES); + */ + _createHelper: (function () { + function selectCipherStrategy(key) { + if (typeof key == "string") { + return PasswordBasedCipher; + } else { + return SerializableCipher; } } - return CBC; - }()); + return function (cipher) { + return { + encrypt: function (message, key, cfg) { + return selectCipherStrategy(key).encrypt(cipher, message, key, cfg); + }, + + decrypt: function (ciphertext, key, cfg) { + return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg); + }, + }; + }; + }()), + }); + + /** + * Abstract base stream cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits) + */ + const StreamCipher = C_lib.StreamCipher = Cipher.extend({ + _doFinalize: function () { + // Process partial blocks + const finalProcessedBlocks = this._process(!!"flush"); + + return finalProcessedBlocks; + }, + + blockSize: 1, + }); + + /** + * Mode namespace. + */ + const C_mode = C.mode = {}; + /** + * Abstract base block cipher mode template. + */ + const BlockCipherMode = C_lib.BlockCipherMode = Base.extend({ /** - * Padding namespace. + * Creates this mode for encryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words); */ - var C_pad = C.pad = {}; + createEncryptor: function (cipher, iv) { + return this.Encryptor.create(cipher, iv); + }, /** - * PKCS #5/7 padding strategy. + * Creates this mode for decryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words); */ - var Pkcs7 = C_pad.Pkcs7 = { - /** - * Pads data using the algorithm defined in PKCS #5/7. - * - * @param {WordArray} data The data to pad. - * @param {number} blockSize The multiple that the data should be padded to. - * - * @static - * - * @example - * - * CryptoJS.pad.Pkcs7.pad(wordArray, 4); - */ - pad: function (data, blockSize) { - // Shortcut - var blockSizeBytes = blockSize * 4; - - // Count padding bytes - var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; - - // Create padding word - var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes; + createDecryptor: function (cipher, iv) { + return this.Decryptor.create(cipher, iv); + }, - // Create padding - var paddingWords = []; - for (var i = 0; i < nPaddingBytes; i += 4) { - paddingWords.push(paddingWord); - } - var padding = WordArray.create(paddingWords, nPaddingBytes); + /** + * Initializes a newly created mode. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @example + * + * var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words); + */ + init: function (cipher, iv) { + this._cipher = cipher; + this._iv = iv; + }, + }); - // Add padding - data.concat(padding); - }, + /** + * Cipher Block Chaining mode. + */ + const CBC = C_mode.CBC = (function () { + /** + * Abstract base CBC mode. + */ + const CBC = BlockCipherMode.extend(); + /** + * CBC encryptor. + */ + CBC.Encryptor = CBC.extend({ /** - * Unpads data that had been padded using the algorithm defined in PKCS #5/7. - * - * @param {WordArray} data The data to unpad. + * Processes the data block at offset. * - * @static + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. * * @example * - * CryptoJS.pad.Pkcs7.unpad(wordArray); + * mode.processBlock(data.words, offset); */ - unpad: function (data) { - // Get number of padding bytes from last byte - var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + processBlock: function (words, offset) { + // Shortcuts + const cipher = this._cipher; + const blockSize = cipher.blockSize; - // Remove padding - data.sigBytes -= nPaddingBytes; - } - }; + // XOR and encrypt + xorBlock.call(this, words, offset, blockSize); + cipher.encryptBlock(words, offset); + + // Remember this block to use with next block + this._prevBlock = words.slice(offset, offset + blockSize); + }, + }); /** - * Abstract base block cipher template. - * - * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits) + * CBC decryptor. */ - var BlockCipher = C_lib.BlockCipher = Cipher.extend({ + CBC.Decryptor = CBC.extend({ /** - * Configuration options. + * Processes the data block at offset. + * + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. + * + * @example * - * @property {Mode} mode The block mode to use. Default: CBC - * @property {Padding} padding The padding strategy to use. Default: Pkcs7 + * mode.processBlock(data.words, offset); */ - cfg: Cipher.cfg.extend({ - mode: CBC, - padding: Pkcs7 - }), + processBlock: function (words, offset) { + // Shortcuts + const cipher = this._cipher; + const blockSize = cipher.blockSize; - reset: function () { - // Reset cipher - Cipher.reset.call(this); + // Remember this block to use with next block + const thisBlock = words.slice(offset, offset + blockSize); - // Shortcuts - var cfg = this.cfg; - var iv = cfg.iv; - var mode = cfg.mode; - - // Reset block mode - if (this._xformMode == this._ENC_XFORM_MODE) { - var modeCreator = mode.createEncryptor; - } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { - var modeCreator = mode.createDecryptor; - - // Keep at least one block in the buffer for unpadding - this._minBufferSize = 1; - } - this._mode = modeCreator.call(mode, this, iv && iv.words); - }, + // Decrypt and XOR + cipher.decryptBlock(words, offset); + xorBlock.call(this, words, offset, blockSize); - _doProcessBlock: function (words, offset) { - this._mode.processBlock(words, offset); + // This block becomes the previous block + this._prevBlock = thisBlock; }, + }); - _doFinalize: function () { - // Shortcut - var padding = this.cfg.padding; + function xorBlock(words, offset, blockSize) { + // Shortcut + const iv = this._iv; - // Finalize - if (this._xformMode == this._ENC_XFORM_MODE) { - // Pad data - padding.pad(this._data, this.blockSize); + // Choose mixing block + if (iv) { + var block = iv; - // Process final blocks - var finalProcessedBlocks = this._process(!!'flush'); - } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { - // Process final blocks - var finalProcessedBlocks = this._process(!!'flush'); + // Remove IV for subsequent blocks + this._iv = undefined; + } else { + var block = this._prevBlock; + } - // Unpad data - padding.unpad(finalProcessedBlocks); - } + // XOR blocks + for (let i = 0; i < blockSize; i++) { + words[offset + i] ^= block[i]; + } + } - return finalProcessedBlocks; - }, + return CBC; + }()); - blockSize: 128 / 32 - }); + /** + * Padding namespace. + */ + const C_pad = C.pad = {}; + /** + * PKCS #5/7 padding strategy. + */ + const Pkcs7 = C_pad.Pkcs7 = { /** - * A collection of cipher parameters. - * - * @property {WordArray} ciphertext The raw ciphertext. - * @property {WordArray} key The key to this ciphertext. - * @property {WordArray} iv The IV used in the ciphering operation. - * @property {WordArray} salt The salt used with a key derivation function. - * @property {Cipher} algorithm The cipher algorithm. - * @property {Mode} mode The block mode used in the ciphering operation. - * @property {Padding} padding The padding scheme used in the ciphering operation. - * @property {number} blockSize The block size of the cipher. - * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string. + * Pads data using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to pad. + * @param {number} blockSize The multiple that the data should be padded to. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.pad(wordArray, 4); */ - var CipherParams = C_lib.CipherParams = Base.extend({ - /** - * Initializes a newly created cipher params object. - * - * @param {Object} cipherParams An object with any of the possible cipher parameters. - * - * @example - * - * var cipherParams = CryptoJS.lib.CipherParams.create({ - * ciphertext: ciphertextWordArray, - * key: keyWordArray, - * iv: ivWordArray, - * salt: saltWordArray, - * algorithm: CryptoJS.algo.AES, - * mode: CryptoJS.mode.CBC, - * padding: CryptoJS.pad.PKCS7, - * blockSize: 4, - * formatter: CryptoJS.format.OpenSSL - * }); - */ - init: function (cipherParams) { - this.mixIn(cipherParams); - }, + pad: function (data, blockSize) { + // Shortcut + const blockSizeBytes = blockSize * 4; - /** - * Converts this cipher params object to a string. - * - * @param {Format} formatter (Optional) The formatting strategy to use. - * - * @return {string} The stringified cipher params. - * - * @throws Error If neither the formatter nor the default formatter is set. - * - * @example - * - * var string = cipherParams + ''; - * var string = cipherParams.toString(); - * var string = cipherParams.toString(CryptoJS.format.OpenSSL); - */ - toString: function (formatter) { - return (formatter || this.formatter).stringify(this); + // Count padding bytes + const nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Create padding word + const paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes; + + // Create padding + const paddingWords = []; + for (let i = 0; i < nPaddingBytes; i += 4) { + paddingWords.push(paddingWord); } - }); + const padding = WordArray.create(paddingWords, nPaddingBytes); + + // Add padding + data.concat(padding); + }, /** - * Format namespace. + * Unpads data that had been padded using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to unpad. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.unpad(wordArray); */ - var C_format = C.format = {}; + unpad: function (data) { + // Get number of padding bytes from last byte + const nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + }, + }; + /** + * Abstract base block cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits) + */ + const BlockCipher = C_lib.BlockCipher = Cipher.extend({ /** - * OpenSSL formatting strategy. + * Configuration options. + * + * @property {Mode} mode The block mode to use. Default: CBC + * @property {Padding} padding The padding strategy to use. Default: Pkcs7 */ - var OpenSSLFormatter = C_format.OpenSSL = { - /** - * Converts a cipher params object to an OpenSSL-compatible string. - * - * @param {CipherParams} cipherParams The cipher params object. - * - * @return {string} The OpenSSL-compatible string. - * - * @static - * - * @example - * - * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams); - */ - stringify: function (cipherParams) { - // Shortcuts - var ciphertext = cipherParams.ciphertext; - var salt = cipherParams.salt; + cfg: Cipher.cfg.extend({ + mode: CBC, + padding: Pkcs7, + }), + + reset: function () { + // Reset cipher + Cipher.reset.call(this); + + // Shortcuts + const cfg = this.cfg; + const iv = cfg.iv; + const mode = cfg.mode; + + // Reset block mode + if (this._xformMode == this._ENC_XFORM_MODE) { + var modeCreator = mode.createEncryptor; + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + var modeCreator = mode.createDecryptor; + + // Keep at least one block in the buffer for unpadding + this._minBufferSize = 1; + } + this._mode = modeCreator.call(mode, this, iv && iv.words); + }, - // Format - if (salt) { - var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); - } else { - var wordArray = ciphertext; - } + _doProcessBlock: function (words, offset) { + this._mode.processBlock(words, offset); + }, - return wordArray.toString(Base64); - }, + _doFinalize: function () { + // Shortcut + const padding = this.cfg.padding; - /** - * Converts an OpenSSL-compatible string to a cipher params object. - * - * @param {string} openSSLStr The OpenSSL-compatible string. - * - * @return {CipherParams} The cipher params object. - * - * @static - * - * @example - * - * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); - */ - parse: function (openSSLStr) { - // Parse base64 - var ciphertext = Base64.parse(openSSLStr); + // Finalize + if (this._xformMode == this._ENC_XFORM_MODE) { + // Pad data + padding.pad(this._data, this.blockSize); - // Shortcut - var ciphertextWords = ciphertext.words; + // Process final blocks + var finalProcessedBlocks = this._process(!!"flush"); + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + // Process final blocks + var finalProcessedBlocks = this._process(!!"flush"); - // Test for salt - if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) { - // Extract salt - var salt = WordArray.create(ciphertextWords.slice(2, 4)); + // Unpad data + padding.unpad(finalProcessedBlocks); + } - // Remove salt from ciphertext - ciphertextWords.splice(0, 4); - ciphertext.sigBytes -= 16; - } + return finalProcessedBlocks; + }, - return CipherParams.create({ciphertext: ciphertext, salt: salt}); - } - }; + blockSize: 128 / 32, + }); + + /** + * A collection of cipher parameters. + * + * @property {WordArray} ciphertext The raw ciphertext. + * @property {WordArray} key The key to this ciphertext. + * @property {WordArray} iv The IV used in the ciphering operation. + * @property {WordArray} salt The salt used with a key derivation function. + * @property {Cipher} algorithm The cipher algorithm. + * @property {Mode} mode The block mode used in the ciphering operation. + * @property {Padding} padding The padding scheme used in the ciphering operation. + * @property {number} blockSize The block size of the cipher. + * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string. + */ + const CipherParams = C_lib.CipherParams = Base.extend({ + /** + * Initializes a newly created cipher params object. + * + * @param {Object} cipherParams An object with any of the possible cipher parameters. + * + * @example + * + * var cipherParams = CryptoJS.lib.CipherParams.create({ + * ciphertext: ciphertextWordArray, + * key: keyWordArray, + * iv: ivWordArray, + * salt: saltWordArray, + * algorithm: CryptoJS.algo.AES, + * mode: CryptoJS.mode.CBC, + * padding: CryptoJS.pad.PKCS7, + * blockSize: 4, + * formatter: CryptoJS.format.OpenSSL + * }); + */ + init: function (cipherParams) { + this.mixIn(cipherParams); + }, /** - * A cipher wrapper that returns ciphertext as a serializable cipher params object. + * Converts this cipher params object to a string. + * + * @param {Format} formatter (Optional) The formatting strategy to use. + * + * @return {string} The stringified cipher params. + * + * @throws Error If neither the formatter nor the default formatter is set. + * + * @example + * + * var string = cipherParams + ''; + * var string = cipherParams.toString(); + * var string = cipherParams.toString(CryptoJS.format.OpenSSL); */ - var SerializableCipher = C_lib.SerializableCipher = Base.extend({ - /** - * Configuration options. - * - * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL - */ - cfg: Base.extend({ - format: OpenSSLFormatter - }), - - /** - * Encrypts a message. - * - * @param {Cipher} cipher The cipher algorithm to use. - * @param {WordArray|string} message The message to encrypt. - * @param {WordArray} key The key. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {CipherParams} A cipher params object. - * - * @static - * - * @example - * - * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key); - * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv }); - * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL }); - */ - encrypt: function (cipher, message, key, cfg) { - // Apply config defaults - cfg = this.cfg.extend(cfg); + toString: function (formatter) { + return (formatter || this.formatter).stringify(this); + }, + }); - // Encrypt - var encryptor = cipher.createEncryptor(key, cfg); - var ciphertext = encryptor.finalize(message); + /** + * Format namespace. + */ + const C_format = C.format = {}; - // Shortcut - var cipherCfg = encryptor.cfg; - - // Create and return serializable cipher params - return CipherParams.create({ - ciphertext: ciphertext, - key: key, - iv: cipherCfg.iv, - algorithm: cipher, - mode: cipherCfg.mode, - padding: cipherCfg.padding, - blockSize: cipher.blockSize, - formatter: cfg.format - }); - }, + /** + * OpenSSL formatting strategy. + */ + const OpenSSLFormatter = C_format.OpenSSL = { + /** + * Converts a cipher params object to an OpenSSL-compatible string. + * + * @param {CipherParams} cipherParams The cipher params object. + * + * @return {string} The OpenSSL-compatible string. + * + * @static + * + * @example + * + * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams); + */ + stringify: function (cipherParams) { + // Shortcuts + const ciphertext = cipherParams.ciphertext; + const salt = cipherParams.salt; + + // Format + if (salt) { + var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); + } else { + var wordArray = ciphertext; + } - /** - * Decrypts serialized ciphertext. - * - * @param {Cipher} cipher The cipher algorithm to use. - * @param {CipherParams|string} ciphertext The ciphertext to decrypt. - * @param {WordArray} key The key. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {WordArray} The plaintext. - * - * @static - * - * @example - * - * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL }); - * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL }); - */ - decrypt: function (cipher, ciphertext, key, cfg) { - // Apply config defaults - cfg = this.cfg.extend(cfg); + return wordArray.toString(Base64); + }, - // Convert string to CipherParams - ciphertext = this._parse(ciphertext, cfg.format); + /** + * Converts an OpenSSL-compatible string to a cipher params object. + * + * @param {string} openSSLStr The OpenSSL-compatible string. + * + * @return {CipherParams} The cipher params object. + * + * @static + * + * @example + * + * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); + */ + parse: function (openSSLStr) { + // Parse base64 + const ciphertext = Base64.parse(openSSLStr); - // Decrypt - var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext); + // Shortcut + const ciphertextWords = ciphertext.words; - return plaintext; - }, + // Test for salt + if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) { + // Extract salt + var salt = WordArray.create(ciphertextWords.slice(2, 4)); - /** - * Converts serialized ciphertext to CipherParams, - * else assumed CipherParams already and returns ciphertext unchanged. - * - * @param {CipherParams|string} ciphertext The ciphertext. - * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext. - * - * @return {CipherParams} The unserialized ciphertext. - * - * @static - * - * @example - * - * var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format); - */ - _parse: function (ciphertext, format) { - if (typeof ciphertext == 'string') { - return format.parse(ciphertext, this); - } else { - return ciphertext; - } + // Remove salt from ciphertext + ciphertextWords.splice(0, 4); + ciphertext.sigBytes -= 16; } - }); + return CipherParams.create({ ciphertext: ciphertext, salt: salt }); + }, + }; + + /** + * A cipher wrapper that returns ciphertext as a serializable cipher params object. + */ + var SerializableCipher = C_lib.SerializableCipher = Base.extend({ /** - * Key derivation function namespace. + * Configuration options. + * + * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL */ - var C_kdf = C.kdf = {}; + cfg: Base.extend({ + format: OpenSSLFormatter, + }), /** - * OpenSSL key derivation function. + * Encrypts a message. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv }); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL }); */ - var OpenSSLKdf = C_kdf.OpenSSL = { - /** - * Derives a key and IV from a password. - * - * @param {string} password The password to derive from. - * @param {number} keySize The size in words of the key to generate. - * @param {number} ivSize The size in words of the IV to generate. - * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly. - * - * @return {CipherParams} A cipher params object with the key, IV, and salt. - * - * @static - * - * @example - * - * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32); - * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt'); - */ - execute: function (password, keySize, ivSize, salt) { - // Generate random salt - if (!salt) { - salt = WordArray.random(64 / 8); - } + encrypt: function (cipher, message, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Encrypt + const encryptor = cipher.createEncryptor(key, cfg); + const ciphertext = encryptor.finalize(message); + + // Shortcut + const cipherCfg = encryptor.cfg; + + // Create and return serializable cipher params + return CipherParams.create({ + ciphertext: ciphertext, + key: key, + iv: cipherCfg.iv, + algorithm: cipher, + mode: cipherCfg.mode, + padding: cipherCfg.padding, + blockSize: cipher.blockSize, + formatter: cfg.format, + }); + }, + + /** + * Decrypts serialized ciphertext. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); - // Derive key and IV - var key = EvpKDF.create({keySize: keySize + ivSize}).compute(password, salt); + // Decrypt + const plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext); - // Separate key and IV - var iv = WordArray.create(key.words.slice(keySize), ivSize * 4); - key.sigBytes = keySize * 4; + return plaintext; + }, - // Return params - return CipherParams.create({key: key, iv: iv, salt: salt}); + /** + * Converts serialized ciphertext to CipherParams, + * else assumed CipherParams already and returns ciphertext unchanged. + * + * @param {CipherParams|string} ciphertext The ciphertext. + * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext. + * + * @return {CipherParams} The unserialized ciphertext. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format); + */ + _parse: function (ciphertext, format) { + if (typeof ciphertext == "string") { + return format.parse(ciphertext, this); + } else { + return ciphertext; } - }; + }, + }); + /** + * Key derivation function namespace. + */ + const C_kdf = C.kdf = {}; + + /** + * OpenSSL key derivation function. + */ + const OpenSSLKdf = C_kdf.OpenSSL = { /** - * A serializable cipher wrapper that derives the key from a password, - * and returns ciphertext as a serializable cipher params object. + * Derives a key and IV from a password. + * + * @param {string} password The password to derive from. + * @param {number} keySize The size in words of the key to generate. + * @param {number} ivSize The size in words of the IV to generate. + * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly. + * + * @return {CipherParams} A cipher params object with the key, IV, and salt. + * + * @static + * + * @example + * + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32); + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt'); */ - var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({ - /** - * Configuration options. - * - * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL - */ - cfg: SerializableCipher.cfg.extend({ - kdf: OpenSSLKdf - }), + execute: function (password, keySize, ivSize, salt) { + // Generate random salt + if (!salt) { + salt = WordArray.random(64 / 8); + } - /** - * Encrypts a message using a password. - * - * @param {Cipher} cipher The cipher algorithm to use. - * @param {WordArray|string} message The message to encrypt. - * @param {string} password The password. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {CipherParams} A cipher params object. - * - * @static - * - * @example - * - * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password'); - * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL }); - */ - encrypt: function (cipher, message, password, cfg) { - // Apply config defaults - cfg = this.cfg.extend(cfg); + // Derive key and IV + const key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt); - // Derive key and other params - var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize); + // Separate key and IV + const iv = WordArray.create(key.words.slice(keySize), ivSize * 4); + key.sigBytes = keySize * 4; - // Add IV to config - cfg.iv = derivedParams.iv; + // Return params + return CipherParams.create({ key: key, iv: iv, salt: salt }); + }, + }; - // Encrypt - var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg); + /** + * A serializable cipher wrapper that derives the key from a password, + * and returns ciphertext as a serializable cipher params object. + */ + var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({ + /** + * Configuration options. + * + * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL + */ + cfg: SerializableCipher.cfg.extend({ + kdf: OpenSSLKdf, + }), - // Mix in derived params - ciphertext.mixIn(derivedParams); + /** + * Encrypts a message using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password'); + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL }); + */ + encrypt: function (cipher, message, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); - return ciphertext; - }, + // Derive key and other params + const derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize); - /** - * Decrypts serialized ciphertext using a password. - * - * @param {Cipher} cipher The cipher algorithm to use. - * @param {CipherParams|string} ciphertext The ciphertext to decrypt. - * @param {string} password The password. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {WordArray} The plaintext. - * - * @static - * - * @example - * - * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL }); - * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL }); - */ - decrypt: function (cipher, ciphertext, password, cfg) { - // Apply config defaults - cfg = this.cfg.extend(cfg); + // Add IV to config + cfg.iv = derivedParams.iv; - // Convert string to CipherParams - ciphertext = this._parse(ciphertext, cfg.format); + // Encrypt + const ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg); - // Derive key and other params - var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt); + // Mix in derived params + ciphertext.mixIn(derivedParams); - // Add IV to config - cfg.iv = derivedParams.iv; + return ciphertext; + }, - // Decrypt - var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg); + /** + * Decrypts serialized ciphertext using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); - return plaintext; - } - }); - }()); + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); - /* - CryptoJS v3.1.2 - code.google.com/p/crypto-js - (c) 2009-2013 by Jeff Mott. All rights reserved. - code.google.com/p/crypto-js/wiki/License - */ - /** - * Electronic Codebook block mode. - */ - CryptoJS.mode.ECB = (function () { - var ECB = CryptoJS.lib.BlockCipherMode.extend(); + // Derive key and other params + const derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt); - ECB.Encryptor = ECB.extend({ - processBlock: function (words, offset) { - this._cipher.encryptBlock(words, offset); - } - }); + // Add IV to config + cfg.iv = derivedParams.iv; - ECB.Decryptor = ECB.extend({ - processBlock: function (words, offset) { - this._cipher.decryptBlock(words, offset); - } - }); + // Decrypt + const plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg); - return ECB; - }()); + return plaintext; + }, + }); +}()); + +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +/** + * Electronic Codebook block mode. + */ +CryptoJS.mode.ECB = (function () { + const ECB = CryptoJS.lib.BlockCipherMode.extend(); + + ECB.Encryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.encryptBlock(words, offset); + }, + }); + ECB.Decryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.decryptBlock(words, offset); + }, + }); - /* - CryptoJS v3.1.2 - code.google.com/p/crypto-js - (c) 2009-2013 by Jeff Mott. All rights reserved. - code.google.com/p/crypto-js/wiki/License - */ + return ECB; +}()); + + +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +(function () { + // Shortcuts + const C = CryptoJS; + const C_lib = C.lib; + const BlockCipher = C_lib.BlockCipher; + const C_algo = C.algo; + + // Lookup tables + const SBOX = []; + const INV_SBOX = []; + const SUB_MIX_0 = []; + const SUB_MIX_1 = []; + const SUB_MIX_2 = []; + const SUB_MIX_3 = []; + const INV_SUB_MIX_0 = []; + const INV_SUB_MIX_1 = []; + const INV_SUB_MIX_2 = []; + const INV_SUB_MIX_3 = []; + + // Compute lookup tables (function () { - // Shortcuts - var C = CryptoJS; - var C_lib = C.lib; - var BlockCipher = C_lib.BlockCipher; - var C_algo = C.algo; - - // Lookup tables - var SBOX = []; - var INV_SBOX = []; - var SUB_MIX_0 = []; - var SUB_MIX_1 = []; - var SUB_MIX_2 = []; - var SUB_MIX_3 = []; - var INV_SUB_MIX_0 = []; - var INV_SUB_MIX_1 = []; - var INV_SUB_MIX_2 = []; - var INV_SUB_MIX_3 = []; - - // Compute lookup tables - (function () { - // Compute double table - var d = []; - for (var i = 0; i < 256; i++) { - if (i < 128) { - d[i] = i << 1; - } else { - d[i] = (i << 1) ^ 0x11b; - } + // Compute double table + const d = []; + for (var i = 0; i < 256; i++) { + if (i < 128) { + d[i] = i << 1; + } else { + d[i] = (i << 1) ^ 0x11b; } + } - // Walk GF(2^8) - var x = 0; - var xi = 0; - for (var i = 0; i < 256; i++) { - // Compute sbox - var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4); - sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63; - SBOX[x] = sx; - INV_SBOX[sx] = x; - - // Compute multiplication - var x2 = d[x]; - var x4 = d[x2]; - var x8 = d[x4]; - - // Compute sub bytes, mix columns tables - var t = (d[sx] * 0x101) ^ (sx * 0x1010100); - SUB_MIX_0[x] = (t << 24) | (t >>> 8); - SUB_MIX_1[x] = (t << 16) | (t >>> 16); - SUB_MIX_2[x] = (t << 8) | (t >>> 24); - SUB_MIX_3[x] = t; - - // Compute inv sub bytes, inv mix columns tables - var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100); - INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8); - INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16); - INV_SUB_MIX_2[sx] = (t << 8) | (t >>> 24); - INV_SUB_MIX_3[sx] = t; - - // Compute next counter - if (!x) { - x = xi = 1; - } else { - x = x2 ^ d[d[d[x8 ^ x2]]]; - xi ^= d[d[xi]]; - } + // Walk GF(2^8) + let x = 0; + let xi = 0; + for (var i = 0; i < 256; i++) { + // Compute sbox + let sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4); + sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63; + SBOX[x] = sx; + INV_SBOX[sx] = x; + + // Compute multiplication + const x2 = d[x]; + const x4 = d[x2]; + const x8 = d[x4]; + + // Compute sub bytes, mix columns tables + var t = (d[sx] * 0x101) ^ (sx * 0x1010100); + SUB_MIX_0[x] = (t << 24) | (t >>> 8); + SUB_MIX_1[x] = (t << 16) | (t >>> 16); + SUB_MIX_2[x] = (t << 8) | (t >>> 24); + SUB_MIX_3[x] = t; + + // Compute inv sub bytes, inv mix columns tables + var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100); + INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8); + INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16); + INV_SUB_MIX_2[sx] = (t << 8) | (t >>> 24); + INV_SUB_MIX_3[sx] = t; + + // Compute next counter + if (!x) { + x = xi = 1; + } else { + x = x2 ^ d[d[d[x8 ^ x2]]]; + xi ^= d[d[xi]]; } - }()); + } + }()); - // Precomputed Rcon lookup - var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; + // Precomputed Rcon lookup + const RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; - /** - * AES block cipher algorithm. - */ - var AES = C_algo.AES = BlockCipher.extend({ - _doReset: function () { - // Shortcuts - var key = this._key; - var keyWords = key.words; - var keySize = key.sigBytes / 4; - - // Compute number of rounds - var nRounds = this._nRounds = keySize + 6; - - // Compute number of key schedule rows - var ksRows = (nRounds + 1) * 4; - - // Compute key schedule - var keySchedule = this._keySchedule = []; - for (var ksRow = 0; ksRow < ksRows; ksRow++) { - if (ksRow < keySize) { - keySchedule[ksRow] = keyWords[ksRow]; - } else { - var t = keySchedule[ksRow - 1]; - - if (!(ksRow % keySize)) { - // Rot word - t = (t << 8) | (t >>> 24); - - // Sub word - t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; - - // Mix Rcon - t ^= RCON[(ksRow / keySize) | 0] << 24; - } else if (keySize > 6 && ksRow % keySize == 4) { - // Sub word - t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; - } - - keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t; - } - } + /** + * AES block cipher algorithm. + */ + const AES = C_algo.AES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + const key = this._key; + const keyWords = key.words; + const keySize = key.sigBytes / 4; + + // Compute number of rounds + const nRounds = this._nRounds = keySize + 6; + + // Compute number of key schedule rows + const ksRows = (nRounds + 1) * 4; + + // Compute key schedule + const keySchedule = this._keySchedule = []; + for (var ksRow = 0; ksRow < ksRows; ksRow++) { + if (ksRow < keySize) { + keySchedule[ksRow] = keyWords[ksRow]; + } else { + var t = keySchedule[ksRow - 1]; - // Compute inv key schedule - var invKeySchedule = this._invKeySchedule = []; - for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) { - var ksRow = ksRows - invKsRow; + if (!(ksRow % keySize)) { + // Rot word + t = (t << 8) | (t >>> 24); - if (invKsRow % 4) { - var t = keySchedule[ksRow]; - } else { - var t = keySchedule[ksRow - 4]; - } + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; - if (invKsRow < 4 || ksRow <= 4) { - invKeySchedule[invKsRow] = t; - } else { - invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^ - INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]]; + // Mix Rcon + t ^= RCON[(ksRow / keySize) | 0] << 24; + } else if (keySize > 6 && ksRow % keySize == 4) { + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; } - } - }, - - encryptBlock: function (M, offset) { - this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX); - }, - decryptBlock: function (M, offset) { - // Swap 2nd and 4th rows - var t = M[offset + 1]; - M[offset + 1] = M[offset + 3]; - M[offset + 3] = t; + keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t; + } + } - this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX); + // Compute inv key schedule + const invKeySchedule = this._invKeySchedule = []; + for (let invKsRow = 0; invKsRow < ksRows; invKsRow++) { + var ksRow = ksRows - invKsRow; - // Inv swap 2nd and 4th rows - var t = M[offset + 1]; - M[offset + 1] = M[offset + 3]; - M[offset + 3] = t; - }, + if (invKsRow % 4) { + var t = keySchedule[ksRow]; + } else { + var t = keySchedule[ksRow - 4]; + } - _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) { - // Shortcut - var nRounds = this._nRounds; - - // Get input, add round key - var s0 = M[offset] ^ keySchedule[0]; - var s1 = M[offset + 1] ^ keySchedule[1]; - var s2 = M[offset + 2] ^ keySchedule[2]; - var s3 = M[offset + 3] ^ keySchedule[3]; - - // Key schedule row counter - var ksRow = 4; - - // Rounds - for (var round = 1; round < nRounds; round++) { - // Shift rows, sub bytes, mix columns, add round key - var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++]; - var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++]; - var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++]; - var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++]; - - // Update state - s0 = t0; - s1 = t1; - s2 = t2; - s3 = t3; + if (invKsRow < 4 || ksRow <= 4) { + invKeySchedule[invKsRow] = t; + } else { + invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^ + INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]]; } + } + }, - // Shift rows, sub bytes, add round key - var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++]; - var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++]; - var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++]; - var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++]; - - // Set output - M[offset] = t0; - M[offset + 1] = t1; - M[offset + 2] = t2; - M[offset + 3] = t3; - }, + encryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX); + }, - keySize: 256 / 32 - }); + decryptBlock: function (M, offset) { + // Swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; - /** - * Shortcut functions to the cipher's object interface. - * - * @example - * - * var ciphertext = CryptoJS.AES.encrypt(message, key, cfg); - * var plaintext = CryptoJS.AES.decrypt(ciphertext, key, cfg); - */ - C.AES = BlockCipher._createHelper(AES); - }()); + this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX); + // Inv swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; + }, - BI._.extend(BI, { - /** - * aes加密方法 - * aes-128-ecb - * - * @example - * - * var ciphertext = BI.aesEncrypt(text, key); - */ - aesEncrypt: function (text, key) { - key = CryptoJS.enc.Utf8.parse(key); - var cipher = CryptoJS.AES.encrypt(text, key, { - mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.Pkcs7 - }); + _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) { + // Shortcut + const nRounds = this._nRounds; + + // Get input, add round key + let s0 = M[offset] ^ keySchedule[0]; + let s1 = M[offset + 1] ^ keySchedule[1]; + let s2 = M[offset + 2] ^ keySchedule[2]; + let s3 = M[offset + 3] ^ keySchedule[3]; + + // Key schedule row counter + let ksRow = 4; + + // Rounds + for (let round = 1; round < nRounds; round++) { + // Shift rows, sub bytes, mix columns, add round key + var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++]; + var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++]; + var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++]; + var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++]; + + // Update state + s0 = t0; + s1 = t1; + s2 = t2; + s3 = t3; + } - var base64Cipher = cipher.ciphertext.toString(CryptoJS.enc.Base64); - return base64Cipher; + // Shift rows, sub bytes, add round key + var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++]; + var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++]; + var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++]; + var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++]; + + // Set output + M[offset] = t0; + M[offset + 1] = t1; + M[offset + 2] = t2; + M[offset + 3] = t3; }, - /** - * aes解密方法 - * @param {String} text - * @param {String} key - */ - aesDecrypt: function (text, key) { - key = CryptoJS.enc.Utf8.parse(key); - var decipher = CryptoJS.AES.decrypt(text, key, { - mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.Pkcs7 - }); + keySize: 256 / 32, + }); - return CryptoJS.enc.Utf8.stringify(decipher); - } + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.AES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.AES.decrypt(ciphertext, key, cfg); + */ + C.AES = BlockCipher._createHelper(AES); +}()); + + +/** + * aes加密方法 + * aes-128-ecb + * + * @example + * + * var ciphertext = BI.aesEncrypt(text, key); + */ +export function aesEncrypt(text, key) { + key = CryptoJS.enc.Utf8.parse(key); + const cipher = CryptoJS.AES.encrypt(text, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7, }); -}()); \ No newline at end of file + + return cipher.ciphertext.toString(CryptoJS.enc.Base64); +} + +/** + * aes解密方法 + * @param {String} text + * @param {String} key + */ +export function aesDecrypt(text, key) { + key = CryptoJS.enc.Utf8.parse(key); + const decipher = CryptoJS.AES.decrypt(text, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7, + }); + + return CryptoJS.enc.Utf8.stringify(decipher); +} + diff --git a/src/core/structure/aspect.js b/src/core/structure/aspect.js index a104c12ca..ad47d42ae 100644 --- a/src/core/structure/aspect.js +++ b/src/core/structure/aspect.js @@ -1,63 +1,58 @@ -!(function () { - function aspect (type) { - return function (target, methodName, advice) { - var exist = target[methodName], - dispatcher; - - if (!exist || exist.target != target) { - dispatcher = target[methodName] = function () { - // before methods - var beforeArr = dispatcher.before; - var args = arguments, next; - for (var l = beforeArr.length; l--;) { - next = beforeArr[l].advice.apply(this, args); - if (next === false) { - return false; - } - args = next || args; - } - // target method - var rs = dispatcher.method.apply(this, args); - // after methods - var afterArr = dispatcher.after; - for (var i = 0, ii = afterArr.length; i < ii; i++) { - next = afterArr[i].advice.call(this, rs, args); - if (rs === false) { - return false; - } - args = next || args; +function _aspect(type) { + return function (target, methodName, advice) { + let exist = target[methodName], + dispatcher; + + if (!exist || exist.target != target) { + dispatcher = target[methodName] = function () { + // before methods + let beforeArr = dispatcher.before; + let args = arguments, next; + for (let l = beforeArr.length; l--;) { + next = beforeArr[l].advice.apply(this, args); + if (next === false) { + return false; } - return rs; - }; - - dispatcher.before = []; - dispatcher.after = []; - - if (exist) { - dispatcher.method = exist; + args = next || args; } - dispatcher.target = target; - } - - var aspectArr = (dispatcher || exist)[type]; - var obj = { - advice: advice, - _index: aspectArr.length, - remove: function () { - aspectArr.splice(this._index, 1); + // target method + let rs = dispatcher.method.apply(this, args); + // after methods + let afterArr = dispatcher.after; + for (let i = 0, ii = afterArr.length; i < ii; i++) { + next = afterArr[i].advice.call(this, rs, args); + if (rs === false) { + return false; + } + args = next || args; } + return rs; }; - aspectArr.push(obj); - return obj; + dispatcher.before = []; + dispatcher.after = []; + + if (exist) { + dispatcher.method = exist; + } + dispatcher.target = target; + } + + let aspectArr = (dispatcher || exist)[type]; + let obj = { + advice: advice, + _index: aspectArr.length, + remove: function () { + aspectArr.splice(this._index, 1); + }, }; - } + aspectArr.push(obj); - BI.aspect = { - before: aspect("before"), - after: aspect("after") + return obj; }; +} - return BI.aspect; - -})(); \ No newline at end of file +export const aspect = { + before: _aspect("before"), + after: _aspect("after"), +}; diff --git a/src/core/structure/base64.js b/src/core/structure/base64.js index 976fbab9e..9d3f0f217 100644 --- a/src/core/structure/base64.js +++ b/src/core/structure/base64.js @@ -1,130 +1,132 @@ +const _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; -!(function () { - var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +// private method for UTF-8 encoding +const _utf8_encode = function (string) { + string = string.replace(/\r\n/g, "\n"); + let utftext = ""; + for (let n = 0; n < string.length; n++) { - // private method for UTF-8 encoding - var _utf8_encode = function (string) { - string = string.replace(/\r\n/g, "\n"); - var utftext = ""; - - for (var n = 0; n < string.length; n++) { - - var c = string.charCodeAt(n); - - if (c < 128) { - utftext += String.fromCharCode(c); - } else if ((c > 127) && (c < 2048)) { - utftext += String.fromCharCode((c >> 6) | 192); - utftext += String.fromCharCode((c & 63) | 128); - } else { - utftext += String.fromCharCode((c >> 12) | 224); - utftext += String.fromCharCode(((c >> 6) & 63) | 128); - utftext += String.fromCharCode((c & 63) | 128); - } + const c = string.charCodeAt(n); + if (c < 128) { + utftext += String.fromCharCode(c); + } else if ((c > 127) && (c < 2048)) { + utftext += String.fromCharCode((c >> 6) | 192); + utftext += String.fromCharCode((c & 63) | 128); + } else { + utftext += String.fromCharCode((c >> 12) | 224); + utftext += String.fromCharCode(((c >> 6) & 63) | 128); + utftext += String.fromCharCode((c & 63) | 128); } - return utftext; - }; - - // private method for UTF-8 decoding - var _utf8_decode = function (utftext) { - var string = ""; - var i = 0; - var c = 0, c3 = 0, c2 = 0; - - while (i < utftext.length) { - - c = utftext.charCodeAt(i); - - if (c < 128) { - string += String.fromCharCode(c); - i++; - } else if ((c > 191) && (c < 224)) { - c2 = utftext.charCodeAt(i + 1); - string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); - i += 2; - } else { - c2 = utftext.charCodeAt(i + 1); - c3 = utftext.charCodeAt(i + 2); - string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); - i += 3; - } - + } + + return utftext; +}; + +// private method for UTF-8 decoding +const _utf8_decode = function (utftext) { + let string = ""; + let i = 0; + let c = 0, c3 = 0, c2 = 0; + + while (i < utftext.length) { + + c = utftext.charCodeAt(i); + + if (c < 128) { + string += String.fromCharCode(c); + i++; + } else if ((c > 191) && (c < 224)) { + c2 = utftext.charCodeAt(i + 1); + string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); + i += 2; + } else { + c2 = utftext.charCodeAt(i + 1); + c3 = utftext.charCodeAt(i + 2); + string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; } - return string; - }; - - BI._.extend(BI, { - - encode: function (input) { - var output = ""; - var chr1, chr2, chr3, enc1, enc2, enc3, enc4; - var i = 0; - - input = _utf8_encode(input); - while (i < input.length) { - - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } + } + return string; +}; + +/** + * base64 encode + * @param input + * @returns {string} + */ +export function encode(input) { + let output = ""; + let chr1, chr2, chr3, enc1, enc2, enc3, enc4; + let i = 0; + + input = _utf8_encode(input); + + while (i < input.length) { + + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } - output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4); + output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4); - } + } - return output; - }, + return output; +} - // public method for decoding - decode: function (input) { - var output = ""; - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0; +/** + * base64 decode + * @param input + * @returns {string} + */ +export function decode(input) { + let output = ""; + let chr1, chr2, chr3; + let enc1, enc2, enc3, enc4; + let i = 0; - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - while (i < input.length) { + while (i < input.length) { - enc1 = _keyStr.indexOf(input.charAt(i++)); - enc2 = _keyStr.indexOf(input.charAt(i++)); - enc3 = _keyStr.indexOf(input.charAt(i++)); - enc4 = _keyStr.indexOf(input.charAt(i++)); + enc1 = _keyStr.indexOf(input.charAt(i++)); + enc2 = _keyStr.indexOf(input.charAt(i++)); + enc3 = _keyStr.indexOf(input.charAt(i++)); + enc4 = _keyStr.indexOf(input.charAt(i++)); - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; - output = output + String.fromCharCode(chr1); + output = output + String.fromCharCode(chr1); - if (enc3 != 64) { - output = output + String.fromCharCode(chr2); - } - if (enc4 != 64) { - output = output + String.fromCharCode(chr3); - } + if (enc3 != 64) { + output = output + String.fromCharCode(chr2); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } - } + } - output = _utf8_decode(output); + output = _utf8_decode(output); - return output; + return output; - } - }); -})(); \ No newline at end of file +} diff --git a/src/core/structure/cache.js b/src/core/structure/cache.js index 5f17bd630..38e238f7a 100644 --- a/src/core/structure/cache.js +++ b/src/core/structure/cache.js @@ -1,43 +1,42 @@ - -BI.Cache = { +export const Cache = { _prefix: "bi", setUsername: function (username) { - localStorage.setItem(BI.Cache._prefix + ".username", (username + "" || "").toUpperCase()); + localStorage.setItem(Cache._prefix + ".username", (username + "" || "").toUpperCase()); }, getUsername: function () { - return localStorage.getItem(BI.Cache._prefix + ".username") || ""; + return localStorage.getItem(Cache._prefix + ".username") || ""; }, _getKeyPrefix: function () { - return BI.Cache.getUsername() + "." + BI.Cache._prefix + "."; + return Cache.getUsername() + "." + Cache._prefix + "."; }, _generateKey: function (key) { - return BI.Cache._getKeyPrefix() + (key || ""); + return Cache._getKeyPrefix() + (key || ""); }, getItem: function (key) { - return localStorage.getItem(BI.Cache._generateKey(key)); + return localStorage.getItem(Cache._generateKey(key)); }, setItem: function (key, value) { - localStorage.setItem(BI.Cache._generateKey(key), value); + localStorage.setItem(Cache._generateKey(key), value); }, removeItem: function (key) { - localStorage.removeItem(BI.Cache._generateKey(key)); + localStorage.removeItem(Cache._generateKey(key)); }, clear: function () { - for (var i = localStorage.length; i >= 0; i--) { - var key = localStorage.key(i); + for (let i = localStorage.length; i >= 0; i--) { + const key = localStorage.key(i); if (key) { - if (key.indexOf(BI.Cache._getKeyPrefix()) === 0) { + if (key.indexOf(Cache._getKeyPrefix()) === 0) { localStorage.removeItem(key); } } } }, keys: function () { - var result = []; - for (var i = localStorage.length; i >= 0; i--) { - var key = localStorage.key(i); + const result = []; + for (let i = localStorage.length; i >= 0; i--) { + const key = localStorage.key(i); if (key) { - var prefix = BI.Cache._getKeyPrefix(); + const prefix = Cache._getKeyPrefix(); if (key.indexOf(prefix) === 0) { result[result.length] = key.substring(prefix.length); } @@ -47,10 +46,10 @@ BI.Cache = { }, addCookie: function (name, value, path, expiresHours) { - var cookieString = name + "=" + encodeURI(value); + let cookieString = name + "=" + encodeURI(value); // 判断是否设置过期时间 if (expiresHours && expiresHours > 0) { - var date = new Date(); + const date = new Date(); // expires是标准GMT格式时间,应该使用时间戳作为起始时间 date.setTime(date.getTime() + expiresHours * 3600 * 1000); cookieString = cookieString + "; expires=" + date.toUTCString(); @@ -61,17 +60,19 @@ BI.Cache = { document.cookie = cookieString; }, getCookie: function (name) { - var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)"); - if (arr = document.cookie.match(reg)) {return decodeURI(arr[2]);} + let arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)"); + if (arr = document.cookie.match(reg)) { + return decodeURI(arr[2]); + } return null; }, deleteCookie: function (name, path) { - var date = new Date(); + const date = new Date(); date.setTime(date.getTime() - 10000); - var cookieString = name + "=v; expires=" + date.toUTCString(); + let cookieString = name + "=v; expires=" + date.toUTCString(); if (path) { cookieString = cookieString + "; path=" + path; } document.cookie = cookieString; - } + }, }; diff --git a/src/core/structure/cellSizeAndPositionManager.js b/src/core/structure/cellSizeAndPositionManager.js index 9c30fdfdd..0adc4e22c 100644 --- a/src/core/structure/cellSizeAndPositionManager.js +++ b/src/core/structure/cellSizeAndPositionManager.js @@ -1,40 +1,40 @@ -BI.CellSizeAndPositionManager = function (cellCount, cellSizeGetter, estimatedCellSize) { - this._cellSizeGetter = cellSizeGetter; - this._cellCount = cellCount; - this._estimatedCellSize = estimatedCellSize; - this._cellSizeAndPositionData = {}; - this._lastMeasuredIndex = -1; -}; - -BI.CellSizeAndPositionManager.prototype = { - constructor: BI.CellSizeAndPositionManager, - configure: function (cellCount, estimatedCellSize) { +export class CellSizeAndPositionManager { + + constructor(cellCount, cellSizeGetter, estimatedCellSize) { + this._cellSizeGetter = cellSizeGetter; this._cellCount = cellCount; this._estimatedCellSize = estimatedCellSize; - }, + this._cellSizeAndPositionData = {}; + this._lastMeasuredIndex = -1; + } - getCellCount: function () { + configure(cellCount, estimatedCellSize) { + this._cellCount = cellCount; + this._estimatedCellSize = estimatedCellSize; + } + + getCellCount() { return this._cellCount; - }, + } - getEstimatedCellSize: function () { + getEstimatedCellSize() { return this._estimatedCellSize; - }, + } - getLastMeasuredIndex: function () { + getLastMeasuredIndex() { return this._lastMeasuredIndex; - }, + } - getSizeAndPositionOfCell: function (index) { + getSizeAndPositionOfCell(index) { if (index < 0 || index >= this._cellCount) { return; } if (index > this._lastMeasuredIndex) { - var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); - var offset = lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size; + const lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); + let offset = lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size; - for (var i = this._lastMeasuredIndex + 1; i <= index; i++) { - var size = this._cellSizeGetter(i); + for (let i = this._lastMeasuredIndex + 1; i <= index; i++) { + const size = this._cellSizeGetter(i); if (size == null || isNaN(size)) { continue; @@ -42,7 +42,7 @@ BI.CellSizeAndPositionManager.prototype = { this._cellSizeAndPositionData[i] = { offset: offset, - size: size + size: size, }; offset += size; @@ -51,28 +51,28 @@ BI.CellSizeAndPositionManager.prototype = { this._lastMeasuredIndex = index; } return this._cellSizeAndPositionData[index]; - }, + } - getSizeAndPositionOfLastMeasuredCell: function () { + getSizeAndPositionOfLastMeasuredCell() { return this._lastMeasuredIndex >= 0 ? this._cellSizeAndPositionData[this._lastMeasuredIndex] : { offset: 0, - size: 0 + size: 0, }; - }, + } - getTotalSize: function () { - var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); + getTotalSize() { + const lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); return lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size + (this._cellCount - this._lastMeasuredIndex - 1) * this._estimatedCellSize; - }, + } - getUpdatedOffsetForIndex: function (align, containerSize, currentOffset, targetIndex) { - var datum = this.getSizeAndPositionOfCell(targetIndex); - var maxOffset = datum.offset; - var minOffset = maxOffset - containerSize + datum.size; + getUpdatedOffsetForIndex(align, containerSize, currentOffset, targetIndex) { + const datum = this.getSizeAndPositionOfCell(targetIndex); + const maxOffset = datum.offset; + const minOffset = maxOffset - containerSize + datum.size; - var idealOffset; + let idealOffset; switch (align) { case "start": @@ -89,25 +89,25 @@ BI.CellSizeAndPositionManager.prototype = { break; } - var totalSize = this.getTotalSize(); + const totalSize = this.getTotalSize(); return Math.max(0, Math.min(totalSize - containerSize, idealOffset)); - }, + } - getVisibleCellRange: function (containerSize, offset) { - var totalSize = this.getTotalSize(); + getVisibleCellRange(containerSize, offset) { + const totalSize = this.getTotalSize(); if (totalSize === 0) { return {}; } - var maxOffset = offset + containerSize; - var start = this._findNearestCell(offset); + const maxOffset = offset + containerSize; + const start = this._findNearestCell(offset); - var datum = this.getSizeAndPositionOfCell(start); + const datum = this.getSizeAndPositionOfCell(start); offset = datum.offset + datum.size; - var stop = start; + let stop = start; while (offset < maxOffset && stop < this._cellCount - 1) { stop++; @@ -116,17 +116,17 @@ BI.CellSizeAndPositionManager.prototype = { return { start: start, - stop: stop + stop: stop, }; - }, + } - resetCell: function (index) { + resetCell(index) { this._lastMeasuredIndex = Math.min(this._lastMeasuredIndex, index - 1); - }, + } - _binarySearch: function (high, low, offset) { - var middle; - var currentOffset; + _binarySearch(high, low, offset) { + let middle; + let currentOffset; while (low <= high) { middle = low + Math.floor((high - low) / 2); @@ -144,10 +144,10 @@ BI.CellSizeAndPositionManager.prototype = { if (low > 0) { return low - 1; } - }, + } - _exponentialSearch: function (index, offset) { - var interval = 1; + _exponentialSearch(index, offset) { + let interval = 1; while (index < this._cellCount && this.getSizeAndPositionOfCell(index).offset < offset) { index += interval; @@ -155,117 +155,115 @@ BI.CellSizeAndPositionManager.prototype = { } return this._binarySearch(Math.min(index, this._cellCount - 1), Math.floor(index / 2), offset); - }, + } - _findNearestCell: function (offset) { + _findNearestCell(offset) { if (isNaN(offset)) { return; } offset = Math.max(0, offset); - var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); - var lastMeasuredIndex = Math.max(0, this._lastMeasuredIndex); + const lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); + const lastMeasuredIndex = Math.max(0, this._lastMeasuredIndex); if (lastMeasuredCellSizeAndPosition.offset >= offset) { return this._binarySearch(lastMeasuredIndex, 0, offset); } return this._exponentialSearch(lastMeasuredIndex, offset); - - } -}; -BI.ScalingCellSizeAndPositionManager = function (cellCount, cellSizeGetter, estimatedCellSize, maxScrollSize) { - this._cellSizeAndPositionManager = new BI.CellSizeAndPositionManager(cellCount, cellSizeGetter, estimatedCellSize); - this._maxScrollSize = maxScrollSize || 10000000; -}; + } +} -BI.ScalingCellSizeAndPositionManager.prototype = { - constructor: BI.ScalingCellSizeAndPositionManager, +export class ScalingCellSizeAndPositionManager { + constructor(cellCount, cellSizeGetter, estimatedCellSize, maxScrollSize) { + this._cellSizeAndPositionManager = new CellSizeAndPositionManager(cellCount, cellSizeGetter, estimatedCellSize); + this._maxScrollSize = maxScrollSize || 10000000; + } - configure: function () { + configure() { this._cellSizeAndPositionManager.configure.apply(this._cellSizeAndPositionManager, arguments); - }, + } - getCellCount: function () { + getCellCount() { return this._cellSizeAndPositionManager.getCellCount(); - }, + } - getEstimatedCellSize: function () { + getEstimatedCellSize() { return this._cellSizeAndPositionManager.getEstimatedCellSize(); - }, + } - getLastMeasuredIndex: function () { + getLastMeasuredIndex() { return this._cellSizeAndPositionManager.getLastMeasuredIndex(); - }, + } - getOffsetAdjustment: function (containerSize, offset) { - var totalSize = this._cellSizeAndPositionManager.getTotalSize(); - var safeTotalSize = this.getTotalSize(); - var offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize); + getOffsetAdjustment(containerSize, offset) { + const totalSize = this._cellSizeAndPositionManager.getTotalSize(); + const safeTotalSize = this.getTotalSize(); + const offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize); return Math.round(offsetPercentage * (safeTotalSize - totalSize)); - }, + } - getSizeAndPositionOfCell: function (index) { + getSizeAndPositionOfCell(index) { return this._cellSizeAndPositionManager.getSizeAndPositionOfCell(index); - }, + } - getSizeAndPositionOfLastMeasuredCell: function () { + getSizeAndPositionOfLastMeasuredCell() { return this._cellSizeAndPositionManager.getSizeAndPositionOfLastMeasuredCell(); - }, + } - getTotalSize: function () { + getTotalSize() { return Math.min(this._maxScrollSize, this._cellSizeAndPositionManager.getTotalSize()); - }, + } - getUpdatedOffsetForIndex: function (align, containerSize, currentOffset, targetIndex) { + getUpdatedOffsetForIndex(align, containerSize, currentOffset, targetIndex) { currentOffset = this._safeOffsetToOffset(containerSize, currentOffset); - var offset = this._cellSizeAndPositionManager.getUpdatedOffsetForIndex(align, containerSize, currentOffset, targetIndex); + const offset = this._cellSizeAndPositionManager.getUpdatedOffsetForIndex(align, containerSize, currentOffset, targetIndex); return this._offsetToSafeOffset(containerSize, offset); - }, + } - getVisibleCellRange: function (containerSize, offset) { + getVisibleCellRange(containerSize, offset) { offset = this._safeOffsetToOffset(containerSize, offset); return this._cellSizeAndPositionManager.getVisibleCellRange(containerSize, offset); - }, + } - resetCell: function (index) { + resetCell(index) { this._cellSizeAndPositionManager.resetCell(index); - }, + } - _getOffsetPercentage: function (containerSize, offset, totalSize) { + _getOffsetPercentage(containerSize, offset, totalSize) { return totalSize <= containerSize ? 0 : offset / (totalSize - containerSize); - }, + } - _offsetToSafeOffset: function (containerSize, offset) { - var totalSize = this._cellSizeAndPositionManager.getTotalSize(); - var safeTotalSize = this.getTotalSize(); + _offsetToSafeOffset(containerSize, offset) { + const totalSize = this._cellSizeAndPositionManager.getTotalSize(); + const safeTotalSize = this.getTotalSize(); if (totalSize === safeTotalSize) { return offset; } - var offsetPercentage = this._getOffsetPercentage(containerSize, offset, totalSize); + const offsetPercentage = this._getOffsetPercentage(containerSize, offset, totalSize); return Math.round(offsetPercentage * (safeTotalSize - containerSize)); - - }, - _safeOffsetToOffset: function (containerSize, offset) { - var totalSize = this._cellSizeAndPositionManager.getTotalSize(); - var safeTotalSize = this.getTotalSize(); + } + + _safeOffsetToOffset(containerSize, offset) { + const totalSize = this._cellSizeAndPositionManager.getTotalSize(); + const safeTotalSize = this.getTotalSize(); if (totalSize === safeTotalSize) { return offset; } - var offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize); + const offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize); return Math.round(offsetPercentage * (totalSize - containerSize)); - + } -}; \ No newline at end of file +} diff --git a/src/core/structure/heap.js b/src/core/structure/heap.js index b9ac4f890..ae0aed9c1 100644 --- a/src/core/structure/heap.js +++ b/src/core/structure/heap.js @@ -1,115 +1,111 @@ +function defaultComparator(a, b) { + return a < b; +} -(function () { - function defaultComparator (a, b) { - return a < b; - } - - BI.Heap = function (items, comparator) { +export class Heap { + constructor(items, comparator) { this._items = items || []; this._size = this._items.length; this._comparator = comparator || defaultComparator; this._heapify(); - }; - - BI.Heap.prototype = { - constructor: BI.Heap, - empty: function () { - return this._size === 0; - }, + } - pop: function () { - if (this._size === 0) { - return; - } + empty() { + return this._size === 0; + } - var elt = this._items[0]; + pop() { + if (this._size === 0) { + return; + } - var lastElt = this._items.pop(); - this._size--; + const elt = this._items[0]; - if (this._size > 0) { - this._items[0] = lastElt; - this._sinkDown(0); - } + const lastElt = this._items.pop(); + this._size--; - return elt; - }, + if (this._size > 0) { + this._items[0] = lastElt; + this._sinkDown(0); + } - push: function (item) { - this._items[this._size++] = item; - this._bubbleUp(this._size - 1); - }, + return elt; + } - size: function () { - return this._size; - }, + push(item) { + this._items[this._size++] = item; + this._bubbleUp(this._size - 1); + } - peek: function () { - if (this._size === 0) { - return; - } + size() { + return this._size; + } - return this._items[0]; - }, + peek() { + if (this._size === 0) { + return; + } - _heapify: function () { - for (var index = Math.floor((this._size + 1) / 2); index >= 0; index--) { - this._sinkDown(index); - } - }, + return this._items[0]; + } - _bubbleUp: function (index) { - var elt = this._items[index]; - while (index > 0) { - var parentIndex = Math.floor((index + 1) / 2) - 1; - var parentElt = this._items[parentIndex]; + _heapify() { + for (let index = Math.floor((this._size + 1) / 2); index >= 0; index--) { + this._sinkDown(index); + } + } - // if parentElt < elt, stop - if (this._comparator(parentElt, elt)) { - return; - } + _bubbleUp(index) { + const elt = this._items[index]; + while (index > 0) { + const parentIndex = Math.floor((index + 1) / 2) - 1; + const parentElt = this._items[parentIndex]; - // swap - this._items[parentIndex] = elt; - this._items[index] = parentElt; - index = parentIndex; + // if parentElt < elt, stop + if (this._comparator(parentElt, elt)) { + return; } - }, - _sinkDown: function (index) { - var elt = this._items[index]; + // swap + this._items[parentIndex] = elt; + this._items[index] = parentElt; + index = parentIndex; + } + } - while (true) { - var leftChildIndex = 2 * (index + 1) - 1; - var rightChildIndex = 2 * (index + 1); - var swapIndex = -1; + _sinkDown(index) { + const elt = this._items[index]; - if (leftChildIndex < this._size) { - var leftChild = this._items[leftChildIndex]; - if (this._comparator(leftChild, elt)) { - swapIndex = leftChildIndex; - } - } + while (true) { + const leftChildIndex = 2 * (index + 1) - 1; + const rightChildIndex = 2 * (index + 1); + let swapIndex = -1; - if (rightChildIndex < this._size) { - var rightChild = this._items[rightChildIndex]; - if (this._comparator(rightChild, elt)) { - if (swapIndex === -1 || - this._comparator(rightChild, this._items[swapIndex])) { - swapIndex = rightChildIndex; - } - } + if (leftChildIndex < this._size) { + const leftChild = this._items[leftChildIndex]; + if (this._comparator(leftChild, elt)) { + swapIndex = leftChildIndex; } + } - // if we don't have a swap, stop - if (swapIndex === -1) { - return; + if (rightChildIndex < this._size) { + const rightChild = this._items[rightChildIndex]; + if (this._comparator(rightChild, elt)) { + if (swapIndex === -1 || + this._comparator(rightChild, this._items[swapIndex])) { + swapIndex = rightChildIndex; + } } + } - this._items[index] = this._items[swapIndex]; - this._items[swapIndex] = elt; - index = swapIndex; + // if we don't have a swap, stop + if (swapIndex === -1) { + return; } + + this._items[index] = this._items[swapIndex]; + this._items[swapIndex] = elt; + index = swapIndex; } - }; -})(); + } +} diff --git a/src/core/structure/index.js b/src/core/structure/index.js new file mode 100644 index 000000000..263e41942 --- /dev/null +++ b/src/core/structure/index.js @@ -0,0 +1,13 @@ +export * from "./aes"; +export * from "./aspect"; +export * from "./base64"; +export * from "./cache"; +export * from "./cellSizeAndPositionManager"; +export * from "./heap"; +export * from "./linkedHashMap"; +export * from "./lru"; +export * from "./prefixIntervalTree"; +export * from "./queue"; +export * from "./sectionManager"; +export * from "./tree"; +export * from "./vector"; diff --git a/src/core/structure/linkedHashMap.js b/src/core/structure/linkedHashMap.js index e9328e591..d4a54eafd 100644 --- a/src/core/structure/linkedHashMap.js +++ b/src/core/structure/linkedHashMap.js @@ -1,72 +1,66 @@ - -!(function () { - BI.LinkHashMap = function () { +export class LinkHashMap { + constructor() { this.array = []; this.map = {}; - }; - BI.LinkHashMap.prototype = { - constructor: BI.LinkHashMap, - has: function (key) { - if (key in this.map) { - return true; - } - return false; - }, - - add: function (key, value) { - if (typeof key === "undefined") { - return; - } - if (key in this.map) { - this.map[key] = value; - } else { - this.array.push(key); - this.map[key] = value; - } - }, + } - remove: function (key) { - if (key in this.map) { - delete this.map[key]; - for (var i = 0; i < this.array.length; i++) { - if (this.array[i] == key) { - this.array.splice(i, 1); - break; - } - } - } - }, + has(key) { + return key in this.map; + } - size: function () { - return this.array.length; - }, + add(key, value) { + if (typeof key === "undefined") { + return; + } + if (key in this.map) { + this.map[key] = value; + } else { + this.array.push(key); + this.map[key] = value; + } + } - each: function (fn, scope) { - var scope = scope || window; - var fn = fn || null; - if (fn == null || typeof (fn) !== "function") { - return; - } - for (var i = 0; i < this.array.length; i++) { - var key = this.array[i]; - var value = this.map[key]; - var re = fn.call(scope, key, value, i, this.array, this.map); - if (re == false) { + remove(key) { + if (key in this.map) { + delete this.map[key]; + for (let i = 0; i < this.array.length; i++) { + if (this.array[i] == key) { + this.array.splice(i, 1); break; } } - }, + } + } - get: function (key) { - return this.map[key]; - }, + size() { + return this.array.length; + } - toArray: function () { - var array = []; - this.each(function (key, value) { - array.push(value); - }); - return array; + each(fn, scope) { + scope = scope || window; + fn = fn || null; + if (fn == null || typeof (fn) !== "function") { + return; } - }; -})(); \ No newline at end of file + for (let i = 0; i < this.array.length; i++) { + const key = this.array[i]; + const value = this.map[key]; + const re = fn.call(scope, key, value, i, this.array, this.map); + if (re == false) { + break; + } + } + } + + get(key) { + return this.map[key]; + } + + toArray() { + const array = []; + this.each(function (key, value) { + array.push(value); + }); + return array; + } +} diff --git a/src/core/structure/lru.js b/src/core/structure/lru.js index 5243d75ca..1d1ce30f6 100644 --- a/src/core/structure/lru.js +++ b/src/core/structure/lru.js @@ -1,24 +1,21 @@ - -!(function () { - BI.LRU = function (limit) { +export class LRU { + constructor(limit) { this.size = 0; this.limit = limit; this.head = this.tail = undefined; this._keymap = {}; - }; - - var p = BI.LRU.prototype; + } - p.put = function (key, value) { - var removed; + put(key, value) { + let removed; if (this.size === this.limit) { removed = this.shift(); } - var entry = this.get(key, true); + let entry = this.get(key, true); if (!entry) { entry = { - key: key + key: key, }; this._keymap[key] = entry; if (this.tail) { @@ -33,10 +30,10 @@ entry.value = value; return removed; - }; + } - p.shift = function () { - var entry = this.head; + shift() { + const entry = this.head; if (entry) { this.head = this.head.newer; this.head.older = undefined; @@ -45,11 +42,10 @@ this.size--; } return entry; - }; - + } - p.get = function (key, returnEntry) { - var entry = this._keymap[key]; + get(key, returnEntry) { + const entry = this._keymap[key]; if (entry === undefined) return; if (entry === this.tail) { return returnEntry @@ -78,9 +74,9 @@ return returnEntry ? entry : entry.value; - }; + } - p.has = function (key) { + has(key) { return this._keymap[key] != null; - }; -})(); \ No newline at end of file + } +} diff --git a/src/core/structure/prefixIntervalTree.js b/src/core/structure/prefixIntervalTree.js index 1a180b34d..a1356970f 100644 --- a/src/core/structure/prefixIntervalTree.js +++ b/src/core/structure/prefixIntervalTree.js @@ -1,32 +1,32 @@ // 线段树 -(function () { - var parent = function (node) { - return Math.floor(node / 2); - }; - - var Int32Array = _global.Int32Array || function (size) { - var xs = []; - for (var i = size - 1; i >= 0; --i) { - xs[i] = 0; - } - return xs; - }; - - var ceilLog2 = function (x) { - var y = 1; - while (y < x) { - y *= 2; - } - return y; - }; - - BI.PrefixIntervalTree = function (xs) { +const parent = function (node) { + return Math.floor(node / 2); +}; + +const Int32Array = _global.Int32Array || function (size) { + const xs = []; + for (let i = size - 1; i >= 0; --i) { + xs[i] = 0; + } + return xs; +}; + +const ceilLog2 = function (x) { + let y = 1; + while (y < x) { + y *= 2; + } + return y; +}; + +export class PrefixIntervalTree { + constructor(xs) { this._size = xs.length; this._half = ceilLog2(this._size); // _heap是一个_size两倍以上的堆 this._heap = new Int32Array(2 * this._half); - var i; + let i; // 初始化 >= _size 的堆空间, 即叶子节点 for (i = 0; i < this._size; ++i) { this._heap[this._half + i] = xs[i]; @@ -35,146 +35,143 @@ for (i = this._half - 1; i > 0; --i) { this._heap[i] = this._heap[2 * i] + this._heap[2 * i + 1]; } - }; - - BI.PrefixIntervalTree.prototype = { - constructor: BI.PrefixIntervalTree, - // 往_half之后的空间set值,需要更新其所有祖先节点的值 - set: function (index, value) { - var node = this._half + index; - this._heap[node] = value; - - node = parent(node); - for (; node !== 0; node = parent(node)) { - this._heap[node] = - this._heap[2 * node] + this._heap[2 * node + 1]; - } - }, + } - get: function (index) { - var node = this._half + index; - return this._heap[node]; - }, + static uniform(size, initialValue) { + const xs = []; + for (let i = size - 1; i >= 0; --i) { + xs[i] = initialValue; + } - getSize: function () { - return this._size; - }, - - /** - * get(0) + get(1) + ... + get(end - 1). - */ - sumUntil: function (end) { - if (end === 0) { - return 0; - } + return new PrefixIntervalTree(xs); + } - var node = this._half + end - 1; - var sum = this._heap[node]; - for (; node !== 1; node = parent(node)) { - if (node % 2 === 1) { - sum += this._heap[node - 1]; - } - } + static empty(size) { + return PrefixIntervalTree.uniform(size, 0); + } - return sum; - }, - - /** - * get(0) + get(1) + ... + get(inclusiveEnd). - */ - sumTo: function (inclusiveEnd) { - return this.sumUntil(inclusiveEnd + 1); - }, - - /** - * sum get(begin) + get(begin + 1) + ... + get(end - 1). - */ - sum: function (begin, end) { - return this.sumUntil(end) - this.sumUntil(begin); - }, - - /** - * Returns the smallest i such that 0 <= i <= size and sumUntil(i) <= t, or - * -1 if no such i exists. - */ - greatestLowerBound: function (t) { - if (t < 0) { - return -1; - } + set(index, value) { + let node = this._half + index; + this._heap[node] = value; - var node = 1; - if (this._heap[node] <= t) { - return this._size; - } + node = parent(node); + for (; node !== 0; node = parent(node)) { + this._heap[node] = + this._heap[2 * node] + this._heap[2 * node + 1]; + } + } + + get(index) { + const node = this._half + index; + return this._heap[node]; + } + + getSize() { + return this._size; + } + + /** + * get(0) + get(1) + ... + get(end - 1). + */ + sumUntil(end) { + if (end === 0) { + return 0; + } - while (node < this._half) { - var leftSum = this._heap[2 * node]; - if (t < leftSum) { - node = 2 * node; - } else { - node = 2 * node + 1; - t -= leftSum; - } + let node = this._half + end - 1; + let sum = this._heap[node]; + for (; node !== 1; node = parent(node)) { + if (node % 2 === 1) { + sum += this._heap[node - 1]; } + } - return node - this._half; - }, + return sum; + } + + /** + * get(0) + get(1) + ... + get(inclusiveEnd). + */ + sumTo(inclusiveEnd) { + return this.sumUntil(inclusiveEnd + 1); + } + + /** + * sum get(begin) + get(begin + 1) + ... + get(end - 1). + */ + sum(begin, end) { + return this.sumUntil(end) - this.sumUntil(begin); + } + + /** + * Returns the smallest i such that 0 <= i <= size and sumUntil(i) <= t, or + * -1 if no such i exists. + */ + greatestLowerBound(t) { + if (t < 0) { + return -1; + } - /** - * Returns the smallest i such that 0 <= i <= size and sumUntil(i) < t, or - * -1 if no such i exists. - */ - greatestStrictLowerBound: function (t) { - if (t <= 0) { - return -1; - } + let node = 1; + if (this._heap[node] <= t) { + return this._size; + } - var node = 1; - if (this._heap[node] < t) { - return this._size; + while (node < this._half) { + const leftSum = this._heap[2 * node]; + if (t < leftSum) { + node = 2 * node; + } else { + node = 2 * node + 1; + t -= leftSum; } + } - while (node < this._half) { - var leftSum = this._heap[2 * node]; - if (t <= leftSum) { - node = 2 * node; - } else { - node = 2 * node + 1; - t -= leftSum; - } - } + return node - this._half; + } - return node - this._half; - }, - - /** - * Returns the smallest i such that 0 <= i <= size and t <= sumUntil(i), or - * size + 1 if no such i exists. - */ - leastUpperBound: function (t) { - return this.greatestStrictLowerBound(t) + 1; - }, - - /** - * Returns the smallest i such that 0 <= i <= size and t < sumUntil(i), or - * size + 1 if no such i exists. - */ - leastStrictUpperBound: function (t) { - return this.greatestLowerBound(t) + 1; + /** + * Returns the smallest i such that 0 <= i <= size and sumUntil(i) < t, or + * -1 if no such i exists. + */ + greatestStrictLowerBound(t) { + if (t <= 0) { + return -1; } - }; - BI.PrefixIntervalTree.uniform = function (size, initialValue) { - var xs = []; - for (var i = size - 1; i >= 0; --i) { - xs[i] = initialValue; + let node = 1; + if (this._heap[node] < t) { + return this._size; } - return new BI.PrefixIntervalTree(xs); - }; + while (node < this._half) { + const leftSum = this._heap[2 * node]; + if (t <= leftSum) { + node = 2 * node; + } else { + node = 2 * node + 1; + t -= leftSum; + } + } + + return node - this._half; + } + + /** + * Returns the smallest i such that 0 <= i <= size and t <= sumUntil(i), or + * size + 1 if no such i exists. + */ + leastUpperBound(t) { + return this.greatestStrictLowerBound(t) + 1; + } + + /** + * Returns the smallest i such that 0 <= i <= size and t < sumUntil(i), or + * size + 1 if no such i exists. + */ + leastStrictUpperBound(t) { + return this.greatestLowerBound(t) + 1; + } - BI.PrefixIntervalTree.empty = function (size) { - return BI.PrefixIntervalTree.uniform(size, 0); - }; -})(); +} diff --git a/src/core/structure/queue.js b/src/core/structure/queue.js index 2d8e382e7..9cdf8b596 100644 --- a/src/core/structure/queue.js +++ b/src/core/structure/queue.js @@ -1,89 +1,86 @@ +import {contains, remove} from "../2.base"; -!(function () { - BI.Queue = function (capacity) { +export class Queue { + constructor(capacity) { this.capacity = capacity; this.array = []; - }; - BI.Queue.prototype = { - constructor: BI.Queue, - - contains: function (v) { - return BI.contains(this.array, v); - }, - - indexOf: function (v) { - return BI.contains(this.array, v); - }, - - getElementByIndex: function (index) { - return this.array[index]; - }, - - push: function (v) { - this.array.push(v); - if (this.capacity && this.array.length > this.capacity) { - this.array.shift(); - } - }, + } - pop: function () { - this.array.pop(); - }, + contains(v) { + return contains(this.array, v); + } + + indexOf(v) { + return contains(this.array, v); + } + + getElementByIndex(index) { + return this.array[index]; + } - shift: function () { + push(v) { + this.array.push(v); + if (this.capacity && this.array.length > this.capacity) { this.array.shift(); - }, + } + } - unshift: function (v) { - this.array.unshift(v); - if (this.capacity && this.array.length > this.capacity) { - this.array.pop(); - } - }, + pop() { + this.array.pop(); + } + + shift() { + this.array.shift(); + } + + unshift(v) { + this.array.unshift(v); + if (this.capacity && this.array.length > this.capacity) { + this.array.pop(); + } + } - remove: function (v) { - BI.remove(this.array, v); - }, + remove(v) { + remove(this.array, v); + } - splice: function () { - this.array.splice.apply(this.array, arguments); - }, + splice() { + this.array.splice.apply(this.array, arguments); + } - slice: function () { - this.array.slice.apply(this.array, arguments); - }, + slice() { + this.array.slice.apply(this.array, arguments); + } - size: function () { - return this.array.length; - }, + size() { + return this.array.length; + } - each: function (fn, scope) { - var scope = scope || window; - var fn = fn || null; - if (fn == null || typeof (fn) !== "function") { - return; - } - for (var i = 0; i < this.array.length; i++) { - var re = fn.call(scope, i, this.array[i], this.array); - if (re == false) { - break; - } + each(fn, scope) { + scope = scope || window; + fn = fn || null; + if (fn == null || typeof (fn) !== "function") { + return; + } + for (let i = 0; i < this.array.length; i++) { + const re = fn.call(scope, i, this.array[i], this.array); + if (re === false) { + break; } - }, + } + } - toArray: function () { - return this.array; - }, + toArray() { + return this.array; + } + + fromArray(array) { + array.each(v => this.push(v)); + } + + clear() { + this.array.length = 0; + } +} - fromArray: function (array) { - var self = this; - BI.each(array, function (i, v) { - self.push(v); - }); - }, - clear: function () { - this.array.length = 0; - } - }; -})(); \ No newline at end of file diff --git a/src/core/structure/sectionManager.js b/src/core/structure/sectionManager.js index ee0692072..8eb348253 100644 --- a/src/core/structure/sectionManager.js +++ b/src/core/structure/sectionManager.js @@ -1,5 +1,7 @@ -!(function () { - var Section = function (height, width, x, y) { +import {each, keys, map, size} from "../2.base"; + +class Section { + constructor(height, width, x, y) { this.height = height; this.width = width; this.x = x; @@ -7,82 +9,79 @@ this._indexMap = {}; this._indices = []; - }; - - Section.prototype = { - constructor: Section, - addCellIndex: function (index) { - if (!this._indexMap[index]) { - this._indexMap[index] = true; - this._indices.push(index); - } - }, + } - getCellIndices: function () { - return this._indices; + addCellIndex(index) { + if (!this._indexMap[index]) { + this._indexMap[index] = true; + this._indices.push(index); } - }; + } + + getCellIndices() { + return this._indices; + } +} - var SECTION_SIZE = 100; - BI.SectionManager = function (sectionSize) { - this._sectionSize = sectionSize || SECTION_SIZE; +const SECTION_SIZE = 100; + +export class SectionManager { + constructor(sectionSize = SECTION_SIZE) { + this._sectionSize = sectionSize; this._cellMetadata = []; this._sections = {}; - }; - - BI.SectionManager.prototype = { - constructor: BI.SectionManager, - getCellIndices: function (height, width, x, y) { - var indices = {}; + } - BI.each(this.getSections(height, width, x, y), function (i, section) { - BI.each(section.getCellIndices(), function (j, index) { - indices[index] = index; - }); - }); + getCellIndices(height, width, x, y) { + const indices = {}; - return BI.map(BI.keys(indices), function (i, index) { - return indices[index]; + each(this.getSections(height, width, x, y), function (i, section) { + each(section.getCellIndices(), function (j, index) { + indices[index] = index; }); - }, + }); - getCellMetadata: function (index) { - return this._cellMetadata[index]; - }, + return map(keys(indices), function (i, index) { + return indices[index]; + }); + } - getSections: function (height, width, x, y) { - var sectionXStart = Math.floor(x / this._sectionSize); - var sectionXStop = Math.floor((x + width - 1) / this._sectionSize); - var sectionYStart = Math.floor(y / this._sectionSize); - var sectionYStop = Math.floor((y + height - 1) / this._sectionSize); + getCellMetadata(index) { + return this._cellMetadata[index]; + } - var sections = []; + getSections(height, width, x, y) { + const sectionXStart = Math.floor(x / this._sectionSize); + const sectionXStop = Math.floor((x + width - 1) / this._sectionSize); + const sectionYStart = Math.floor(y / this._sectionSize); + const sectionYStop = Math.floor((y + height - 1) / this._sectionSize); - for (var sectionX = sectionXStart; sectionX <= sectionXStop; sectionX++) { - for (var sectionY = sectionYStart; sectionY <= sectionYStop; sectionY++) { - var key = sectionX + "." + sectionY; + const sections = []; - if (!this._sections[key]) { - this._sections[key] = new Section(this._sectionSize, this._sectionSize, sectionX * this._sectionSize, sectionY * this._sectionSize); - } + for (let sectionX = sectionXStart; sectionX <= sectionXStop; sectionX++) { + for (let sectionY = sectionYStart; sectionY <= sectionYStop; sectionY++) { + const key = sectionX + "." + sectionY; - sections.push(this._sections[key]); + if (!this._sections[key]) { + this._sections[key] = new Section(this._sectionSize, this._sectionSize, sectionX * this._sectionSize, sectionY * this._sectionSize); } + + sections.push(this._sections[key]); } + } - return sections; - }, + return sections; + } - getTotalSectionCount: function () { - return BI.size(this._sections); - }, + getTotalSectionCount() { + return size(this._sections); + } - registerCell: function (cellMetadatum, index) { - this._cellMetadata[index] = cellMetadatum; + registerCell(cellMetadatum, index) { + this._cellMetadata[index] = cellMetadatum; - BI.each(this.getSections(cellMetadatum.height, cellMetadatum.width, cellMetadatum.x, cellMetadatum.y), function (i, section) { - section.addCellIndex(index); - }); - } - }; -})(); \ No newline at end of file + each(this.getSections(cellMetadatum.height, cellMetadatum.width, cellMetadatum.x, cellMetadatum.y), function (i, section) { + section.addCellIndex(index); + }); + } +} diff --git a/src/core/structure/tree.js b/src/core/structure/tree.js index 32e7665b4..a48c17d83 100644 --- a/src/core/structure/tree.js +++ b/src/core/structure/tree.js @@ -1,517 +1,521 @@ -(function () { - BI.Tree = function () { - this.root = new BI.Node(BI.UUID()); - }; - - BI.Tree.prototype = { - constructor: BI.Tree, - addNode: function (node, newNode, index) { - if (BI.isNull(newNode)) { - this.root.addChild(node, index); - } else if (BI.isNull(node)) { - this.root.addChild(newNode, index); - } else { - node.addChild(newNode, index); - } - }, - - isRoot: function (node) { - return node === this.root; - }, - - getRoot: function () { - return this.root; - }, - - clear: function () { - this.root.clear(); - }, - - initTree: function (nodes) { - var self = this; - this.clear(); - var queue = []; - BI.each(nodes, function (i, node) { - var n = new BI.Node(node); - n.set("data", node); - self.addNode(n); - queue.push(n); - }); - while (!BI.isEmpty(queue)) { - var parent = queue.shift(); - var node = parent.get("data"); - BI.each(node.children, function (i, child) { - var n = new BI.Node(child); - n.set("data", child); - queue.push(n); - self.addNode(parent, n); - }); - } - }, +import { + isObject, + UUID, + extend, + isEmpty, + isArray, + first, + last, + findIndex, + isUndefined, + isNull, + each, + deepClone, + isEqual, some, every, clone +} from "../2.base"; + +export class Node { + constructor(id) { + if (isObject(id)) { + extend(this, id); + } else { + this.id = id; + } + this.clear(); + } - _toJSON: function (node) { - var self = this; - var children = []; - BI.each(node.getChildren(), function (i, child) { - children.push(self._toJSON(child)); - }); - return BI.extend({ - id: node.id - }, BI.deepClone(node.get("data")), (children.length > 0 ? { - children: children - } : {})); - }, - - toJSON: function (node) { - var self = this, result = []; - BI.each((node || this.root).getChildren(), function (i, child) { - result.push(self._toJSON(child)); - }); - return result; - }, - - _toJSONWithNode: function (node) { - var self = this; - var children = []; - BI.each(node.getChildren(), function (i, child) { - children.push(self._toJSONWithNode(child)); - }); - return BI.extend({ - id: node.id - }, BI.deepClone(node.get("data")), { - node: node - }, (children.length > 0 ? { - children: children - } : {})); - }, - - toJSONWithNode: function (node) { - var self = this, result = []; - BI.each((node || this.root).getChildren(), function (i, child) { - result.push(self._toJSONWithNode(child)); + set(key, value) { + if (isObject(key)) { + extend(this, key); + return; + } + this[key] = value; + } + + get(key) { + return this[key]; + } + + isLeaf() { + return isEmpty(this.children); + } + + getChildren() { + return this.children; + } + + getChildrenLength() { + return this.children.length; + } + + getFirstChild() { + return first(this.children); + } + + getLastChild() { + return last(this.children); + } + + setLeft(left) { + this.left = left; + } + + getLeft() { + return this.left; + } + + setRight(right) { + this.right = right; + } + + getRight() { + return this.right; + } + + setParent(parent) { + this.parent = parent; + } + + getParent() { + return this.parent; + } + + getChild(index) { + return this.children[index]; + } + + getChildIndex(id) { + return findIndex(this.children, function (i, ch) { + return ch.get("id") === id; + }); + } + + removeChild(id) { + this.removeChildByIndex(this.getChildIndex(id)); + } + + removeChildByIndex(index) { + const before = this.getChild(index - 1); + const behind = this.getChild(index + 1); + if (before != null) { + before.setRight(behind || null); + } + if (behind != null) { + behind.setLeft(before || null); + } + this.children.splice(index, 1); + } + + removeAllChilds() { + this.children = []; + } + + addChild(child, index) { + let cur = null; + if (isUndefined(index)) { + cur = this.children.length - 1; + } else { + cur = index - 1; + } + child.setParent(this); + if (cur >= 0) { + this.getChild(cur) && this.getChild(cur).setRight(child); + child.setLeft(this.getChild(cur)); + } + if (isUndefined(index)) { + this.children.push(child); + } else { + this.children.splice(index, 0, child); + } + } + + equals(obj) { + return this === obj || this.id === obj.id; + } + + clear() { + this.parent = null; + this.left = null; + this.right = null; + this.children = []; + } +} + +export class Tree { + constructor() { + this.root = new Node(UUID()); + } + + addNode(node, newNode, index) { + if (isNull(newNode)) { + this.root.addChild(node, index); + } else if (isNull(node)) { + this.root.addChild(newNode, index); + } else { + node.addChild(newNode, index); + } + } + + isRoot(node) { + return node === this.root; + } + + getRoot() { + return this.root; + } + + clear() { + this.root.clear(); + } + + initTree(nodes) { + this.clear(); + const queue = []; + each(nodes, (i, node) => { + const n = new Node(node); + n.set("data", node); + this.addNode(n); + queue.push(n); + }); + while (!isEmpty(queue)) { + const parent = queue.shift(); + const node = parent.get("data"); + each(node.children, (i, child) => { + const n = new Node(child); + n.set("data", child); + queue.push(n); + this.addNode(parent, n); }); - return result; - }, + } + } + + _toJSON(node) { + const children = []; + each(node.getChildren(), (i, child) => { + children.push(this._toJSON(child)); + }); + return extend({ + id: node.id, + }, deepClone(node.get("data")), (children.length > 0 ? { + children: children, + } : {})); + } + + toJSON(node) { + const result = []; + each((node || this.root).getChildren(), (i, child) => { + result.push(this._toJSON(child)); + }); + return result; + } + + _toJSONWithNode(node) { + const children = []; + each(node.getChildren(), (i, child) => { + children.push(this._toJSONWithNode(child)); + }); + return extend({ + id: node.id, + }, deepClone(node.get("data")), { + node: node, + }, (children.length > 0 ? { + children: children, + } : {})); + } + + toJSONWithNode(node) { + const result = []; + each((node || this.root).getChildren(), (i, child) => { + result.push(this._toJSONWithNode(child)); + }); + return result; + } + + search(root, target, param) { + if (!(root instanceof Node)) { + return this.search(this.root, root, target); + } + let next = null; - search: function (root, target, param) { - if (!(root instanceof BI.Node)) { - return arguments.callee.apply(this, [this.root, root, target]); + if (isNull(target)) { + return null; + } + if (isEqual(root[param || "id"], target)) { + return root; + } + some(root.getChildren(), (i, child) => { + next = this.search(child, target, param); + if (null !== next) { + return true; } - var self = this, next = null; - - if (BI.isNull(target)) { - return null; + }); + return next; + } + + _traverse(node, callback) { + let queue = []; + queue.push(node); + while (!isEmpty(queue)) { + const temp = queue.shift(); + const b = callback && callback(temp); + if (b === false) { + break; } - if (BI.isEqual(root[param || "id"], target)) { - return root; + if (b === true) { + continue; } - BI.any(root.getChildren(), function (i, child) { - next = self.search(child, target, param); - if (null !== next) { - return true; - } - }); - return next; - }, - - _traverse: function (node, callback) { - var queue = []; - queue.push(node); - while (!BI.isEmpty(queue)) { - var temp = queue.shift(); - var b = callback && callback(temp); - if (b === false) { - break; - } - if (b === true) { - continue; - } - if (temp != null) { - queue = queue.concat(temp.getChildren()); - } + if (temp != null) { + queue = queue.concat(temp.getChildren()); } - }, - - traverse: function (callback) { - this._traverse(this.root, callback); - }, - - _recursion: function (node, route, callback) { - var self = this; - return BI.every(node.getChildren(), function (i, child) { - var next = BI.clone(route); - next.push(child.id); - var b = callback && callback(child, next); - if (b === false) { - return false; - } - if (b === true) { - return true; - } - return self._recursion(child, next, callback); - }); - }, - - recursion: function (callback) { - this._recursion(this.root, [], callback); - }, - - inOrderTraverse: function (callback) { - this._inOrderTraverse(this.root, callback); - }, - - // 中序遍历(递归) - _inOrderTraverse: function (node, callback) { - if (node != null) { - this._inOrderTraverse(node.getLeft()); - callback && callback(node); - this._inOrderTraverse(node.getRight()); + } + } + + traverse(callback) { + this._traverse(this.root, callback); + } + + _recursion(node, route, callback) { + return every(node.getChildren(), (i, child) => { + const next = clone(route); + next.push(child.id); + const b = callback && callback(child, next); + if (b === false) { + return false; } - }, - - // 中序遍历(非递归) - nrInOrderTraverse: function (callback) { - - var stack = []; - var node = this.root; - while (node != null || !BI.isEmpty(stack)) { - while (node != null) { - stack.push(node); - node = node.getLeft(); - } - node = stack.pop(); - callback && callback(node); - node = node.getRight(); + if (b === true) { + return true; } - }, + return this._recursion(child, next, callback); + }); + } + + recursion(callback) { + this._recursion(this.root, [], callback); + } + + inOrderTraverse(callback) { + this._inOrderTraverse(this.root, callback); + } + + // 中序遍历(递归) + _inOrderTraverse(node, callback) { + if (node != null) { + this._inOrderTraverse(node.getLeft()); + callback && callback(node); + this._inOrderTraverse(node.getRight()); + } + } - preOrderTraverse: function (callback) { - this._preOrderTraverse(this.root, callback); - }, + // 中序遍历(非递归) + nrInOrderTraverse(callback) { - // 先序遍历(递归) - _preOrderTraverse: function (node, callback) { - if (node != null) { - callback && callback(node); - this._preOrderTraverse(node.getLeft()); - this._preOrderTraverse(node.getRight()); + const stack = []; + let node = this.root; + while (node != null || !isEmpty(stack)) { + while (node != null) { + stack.push(node); + node = node.getLeft(); } - }, - - // 先序遍历(非递归) - nrPreOrderTraverse: function (callback) { - - var stack = []; - var node = this.root; + node = stack.pop(); + callback && callback(node); + node = node.getRight(); + } + } + + preOrderTraverse(callback) { + this._preOrderTraverse(this.root, callback); + } + + // 先序遍历(递归) + _preOrderTraverse(node, callback) { + if (node != null) { + callback && callback(node); + this._preOrderTraverse(node.getLeft()); + this._preOrderTraverse(node.getRight()); + } + } - while (node != null || !BI.isEmpty(stack)) { + // 先序遍历(非递归) + nrPreOrderTraverse(callback) { - while (node != null) { - callback && callback(node); - stack.push(node); - node = node.getLeft(); - } - node = stack.pop(); - node = node.getRight(); - } - }, + const stack = []; + let node = this.root; - postOrderTraverse: function (callback) { - this._postOrderTraverse(this.root, callback); - }, + while (node != null || !isEmpty(stack)) { - // 后序遍历(递归) - _postOrderTraverse: function (node, callback) { - if (node != null) { - this._postOrderTraverse(node.getLeft()); - this._postOrderTraverse(node.getRight()); + while (node != null) { callback && callback(node); + stack.push(node); + node = node.getLeft(); } - }, - - // 后续遍历(非递归) - nrPostOrderTraverse: function (callback) { - - var stack = []; - var node = this.root; - var preNode = null;// 表示最近一次访问的节点 - - while (node != null || !BI.isEmpty(stack)) { - - while (node != null) { - stack.push(node); - node = node.getLeft(); - } - - node = BI.last(stack); - - if (node.getRight() == null || node.getRight() == preNode) { - callback && callback(node); - node = stack.pop(); - preNode = node; - node = null; - } else { - node = node.getRight(); - } - } + node = stack.pop(); + node = node.getRight(); } - }; - - BI.Node = function (id) { - if (BI.isObject(id)) { - BI.extend(this, id); - } else { - this.id = id; + } + + postOrderTraverse(callback) { + this._postOrderTraverse(this.root, callback); + } + + // 后序遍历(递归) + _postOrderTraverse(node, callback) { + if (node != null) { + this._postOrderTraverse(node.getLeft()); + this._postOrderTraverse(node.getRight()); + callback && callback(node); } - this.clear.apply(this, arguments); - }; - - BI.Node.prototype = { - constructor: BI.Node, - - set: function (key, value) { - if (BI.isObject(key)) { - BI.extend(this, key); - return; - } - this[key] = value; - }, - - get: function (key) { - return this[key]; - }, - - isLeaf: function () { - return BI.isEmpty(this.children); - }, - - getChildren: function () { - return this.children; - }, - - getChildrenLength: function () { - return this.children.length; - }, - - getFirstChild: function () { - return BI.first(this.children); - }, - - getLastChild: function () { - return BI.last(this.children); - }, + } - setLeft: function (left) { - this.left = left; - }, + // 后续遍历(非递归) + nrPostOrderTraverse(callback) { - getLeft: function () { - return this.left; - }, + const stack = []; + let node = this.root; + let preNode = null;// 表示最近一次访问的节点 - setRight: function (right) { - this.right = right; - }, + while (node != null || !isEmpty(stack)) { - getRight: function () { - return this.right; - }, - - setParent: function (parent) { - this.parent = parent; - }, - - getParent: function () { - return this.parent; - }, - - getChild: function (index) { - return this.children[index]; - }, - - getChildIndex: function (id) { - return BI.findIndex(this.children, function (i, ch) { - return ch.get("id") === id; - }); - }, - - removeChild: function (id) { - this.removeChildByIndex(this.getChildIndex(id)); - }, - - removeChildByIndex: function (index) { - var before = this.getChild(index - 1); - var behind = this.getChild(index + 1); - if (before != null) { - before.setRight(behind || null); - } - if (behind != null) { - behind.setLeft(before || null); + while (node != null) { + stack.push(node); + node = node.getLeft(); } - this.children.splice(index, 1); - }, - removeAllChilds: function () { - this.children = []; - }, + node = last(stack); - addChild: function (child, index) { - var cur = null; - if (BI.isUndefined(index)) { - cur = this.children.length - 1; + if (node.getRight() == null || node.getRight() === preNode) { + callback && callback(node); + node = stack.pop(); + preNode = node; + node = null; } else { - cur = index - 1; + node = node.getRight(); } - child.setParent(this); - if (cur >= 0) { - this.getChild(cur) && this.getChild(cur).setRight(child); - child.setLeft(this.getChild(cur)); + } + } + + static transformToArrayFormat(nodes, pId, childKey) { + if (!nodes) return []; + let r = []; + childKey = childKey || "children"; + if (isArray(nodes)) { + for (let i = 0, l = nodes.length; i < l; i++) { + const node = clone(nodes[i]); + node.pId = node.pId == null ? pId : node.pId; + delete node.children; + r.push(node); + if (nodes[i][childKey]) { + r = r.concat(Tree.transformToArrayFormat(nodes[i][childKey], node.id)); + } } - if (BI.isUndefined(index)) { - this.children.push(child); - } else { - this.children.splice(index, 0, child); + } else { + const newNodes = clone(nodes); + newNodes.pId = newNodes.pId == null ? pId : newNodes.pId; + delete newNodes.children; + r.push(newNodes); + if (nodes[childKey]) { + r = r.concat(Tree.transformToArrayFormat(nodes[childKey], newNodes.id)); } - }, - - equals: function (obj) { - return this === obj || this.id === obj.id; - }, + } + return r; + } - clear: function () { - this.parent = null; - this.left = null; - this.right = null; - this.children = []; + static arrayFormat(nodes, pId) { + if (!nodes) { + return []; } - }; - - BI.extend(BI.Tree, { - transformToArrayFormat: function (nodes, pId, childKey) { - if (!nodes) return []; - var r = []; - childKey = childKey || "children"; - if (BI.isArray(nodes)) { - for (var i = 0, l = nodes.length; i < l; i++) { - var node = BI.clone(nodes[i]); - node.pId = node.pId == null ? pId : node.pId; - delete node.children; - r.push(node); - if (nodes[i][childKey]) { - r = r.concat(BI.Tree.transformToArrayFormat(nodes[i][childKey], node.id)); - } - } - } else { - var newNodes = BI.clone(nodes); - newNodes.pId = newNodes.pId == null ? pId : newNodes.pId; - delete newNodes.children; - r.push(newNodes); - if (nodes[childKey]) { - r = r.concat(BI.Tree.transformToArrayFormat(nodes[childKey], newNodes.id)); + let r = []; + if (isArray(nodes)) { + for (let i = 0, l = nodes.length; i < l; i++) { + const node = nodes[i]; + node.pId = node.pId == null ? pId : node.pId; + r.push(node); + if (nodes[i]["children"]) { + r = r.concat(Tree.arrayFormat(nodes[i]["children"], node.id)); } } - return r; - }, - - arrayFormat: function (nodes, pId) { - if (!nodes) { - return []; - } - var r = []; - if (BI.isArray(nodes)) { - for (var i = 0, l = nodes.length; i < l; i++) { - var node = nodes[i]; - node.pId = node.pId == null ? pId : node.pId; - r.push(node); - if (nodes[i]["children"]) { - r = r.concat(BI.Tree.arrayFormat(nodes[i]["children"], node.id)); - } - } - } else { - var newNodes = nodes; - newNodes.pId = newNodes.pId == null ? pId : newNodes.pId; - r.push(newNodes); - if (nodes["children"]) { - r = r.concat(BI.Tree.arrayFormat(nodes["children"], newNodes.id)); - } + } else { + const newNodes = nodes; + newNodes.pId = newNodes.pId == null ? pId : newNodes.pId; + r.push(newNodes); + if (nodes["children"]) { + r = r.concat(Tree.arrayFormat(nodes["children"], newNodes.id)); } - return r; - }, + } + return r; + } - transformToTreeFormat: function (sNodes) { - var i, l; - if (!sNodes) { - return []; - } + static transformToTreeFormat(sNodes) { + let i, l; + if (!sNodes) { + return []; + } - if (BI.isArray(sNodes)) { - var r = []; - var tmpMap = {}; - for (i = 0, l = sNodes.length; i < l; i++) { - if (BI.isNull(sNodes[i].id)) { - return sNodes; - } - tmpMap[sNodes[i].id] = BI.clone(sNodes[i]); + if (isArray(sNodes)) { + const r = []; + const tmpMap = {}; + for (i = 0, l = sNodes.length; i < l; i++) { + if (isNull(sNodes[i].id)) { + return sNodes; } - for (i = 0, l = sNodes.length; i < l; i++) { - if (tmpMap[sNodes[i].pId] && sNodes[i].id !== sNodes[i].pId) { - if (!tmpMap[sNodes[i].pId].children) { - tmpMap[sNodes[i].pId].children = []; - } - tmpMap[sNodes[i].pId].children.push(tmpMap[sNodes[i].id]); - } else { - r.push(tmpMap[sNodes[i].id]); + tmpMap[sNodes[i].id] = clone(sNodes[i]); + } + for (i = 0, l = sNodes.length; i < l; i++) { + if (tmpMap[sNodes[i].pId] && sNodes[i].id !== sNodes[i].pId) { + if (!tmpMap[sNodes[i].pId].children) { + tmpMap[sNodes[i].pId].children = []; } - delete tmpMap[sNodes[i].id].pId; + tmpMap[sNodes[i].pId].children.push(tmpMap[sNodes[i].id]); + } else { + r.push(tmpMap[sNodes[i].id]); } - return r; + delete tmpMap[sNodes[i].id].pId; } - return [sNodes]; + return r; + } + return [sNodes]; - }, + } - treeFormat: function (sNodes) { - var i, l; - if (!sNodes) { - return []; - } + static treeFormat(sNodes) { + let i, l; + if (!sNodes) { + return []; + } - if (BI.isArray(sNodes)) { - var r = []; - var tmpMap = {}; - for (i = 0, l = sNodes.length; i < l; i++) { - if (BI.isNull(sNodes[i].id)) { - return sNodes; - } - tmpMap[sNodes[i].id] = sNodes[i]; + if (isArray(sNodes)) { + const r = []; + const tmpMap = {}; + for (i = 0, l = sNodes.length; i < l; i++) { + if (isNull(sNodes[i].id)) { + return sNodes; } - for (i = 0, l = sNodes.length; i < l; i++) { - if (tmpMap[sNodes[i].pId] && sNodes[i].id !== sNodes[i].pId) { - if (!tmpMap[sNodes[i].pId].children) { - tmpMap[sNodes[i].pId].children = []; - } - tmpMap[sNodes[i].pId].children.push(tmpMap[sNodes[i].id]); - } else { - r.push(tmpMap[sNodes[i].id]); + tmpMap[sNodes[i].id] = sNodes[i]; + } + for (i = 0, l = sNodes.length; i < l; i++) { + if (tmpMap[sNodes[i].pId] && sNodes[i].id !== sNodes[i].pId) { + if (!tmpMap[sNodes[i].pId].children) { + tmpMap[sNodes[i].pId].children = []; } + tmpMap[sNodes[i].pId].children.push(tmpMap[sNodes[i].id]); + } else { + r.push(tmpMap[sNodes[i].id]); } - return r; } - return [sNodes]; + return r; + } + return [sNodes]; - }, + } - traversal: function (array, callback, pNode) { - if (BI.isNull(array)) { - return; - } - var self = this; - BI.some(array, function (i, item) { - if (callback(i, item, pNode) === false) { - return true; - } - self.traversal(item.children, callback, item); - }); + static traversal(array, callback, pNode) { + if (isNull(array)) { + return; } - }); -})(); + some(array, (i, item) => { + if (callback(i, item, pNode) === false) { + return true; + } + this.traversal(item.children, callback, item); + }); + } +} diff --git a/src/core/structure/vector.js b/src/core/structure/vector.js index d7ec50e9b..cd52754fd 100644 --- a/src/core/structure/vector.js +++ b/src/core/structure/vector.js @@ -1,27 +1,29 @@ // 向量操作 -BI.Vector = function (x, y) { - this.x = x; - this.y = y; -}; -BI.Vector.prototype = { - constructor: BI.Vector, - cross: function (v) { +export class Vector { + constructor(x, y) { + this.x = x; + this.y = y; + } + + cross(v) { return (this.x * v.y - this.y * v.x); - }, - length: function (v) { + } + + length(v) { return (Math.sqrt(this.x * v.x + this.y * v.y)); } -}; -BI.Region = function (x, y, w, h) { - this.x = x; - this.y = y; - this.w = w; - this.h = h; -}; -BI.Region.prototype = { - constructor: BI.Region, +} + +export class Region { + constructor(x, y, w, h) { + this.x = x; + this.y = y; + this.w = w; + this.h = h; + } + // 判断两个区域是否相交,若相交,则要么顶点互相包含,要么矩形边界(或对角线)相交 - isIntersects: function (obj) { + isIntersects(obj) { if (this.isPointInside(obj.x, obj.y) || this.isPointInside(obj.x + obj.w, obj.y) || this.isPointInside(obj.x, obj.y + obj.h) || @@ -34,17 +36,18 @@ BI.Region.prototype = { return true; } else if (obj.x != null && obj.y != null)// 判断矩形对角线相交 |v1 X v2||v1 X v3| < 0 { - var vector1 = new BI.Vector(this.w, this.h);// 矩形对角线向量 - var vector2 = new BI.Vector(obj.x - this.x, obj.y - this.y); - var vector3 = new BI.Vector(vector2.x + obj.w, vector2.y + obj.h); + const vector1 = new Vector(this.w, this.h);// 矩形对角线向量 + const vector2 = new Vector(obj.x - this.x, obj.y - this.y); + const vector3 = new Vector(vector2.x + obj.w, vector2.y + obj.h); if ((vector1.cross(vector2) * vector1.cross(vector3)) < 0) { return true; } } return false; - }, + } + // 判断一个点是否在这个区域内部 - isPointInside: function (x, y) { + isPointInside(x, y) { if (this.x == null || this.y == null) { return false; } @@ -52,12 +55,14 @@ BI.Region.prototype = { return true; } return false; - }, + } + // 返回区域的重心,因为是矩形所以返回中点 - getPosition: function () { - var pos = []; + getPosition() { + const pos = []; pos.push(this.x + this.w / 2); pos.push(this.y + this.h / 2); return pos; } -}; \ No newline at end of file +} +