@sskmy1024y/react-native-hash
Version:
A hashing library for react-native
134 lines (116 loc) • 3.46 kB
JavaScript
/* eslint linebreak-style: ["error", "windows"] */
/* eslint-disable no-use-before-define */
import Base from './Base.js';
import WordArray from './WordArray.js';
import Utf8 from './Utf8.js';
/**
* 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
*/
export default class BufferedBlockAlgorithm extends Base {
constructor() {
super();
this._minBufferSize = 0;
}
/**
* Resets this block algorithm's data buffer to its initial state.
*
* @example
*
* bufferedBlockAlgorithm.reset();
*/
reset() {
// Initial values
this._data = new WordArray();
this._nDataBytes = 0;
}
/**
* 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(data) {
let m_data = data;
// Convert string to WordArray, else assume WordArray already
if (typeof m_data === 'string') {
m_data = Utf8.parse(m_data);
}
// Append
this._data.concat(m_data);
this._nDataBytes += m_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(doFlush) {
let processedWords;
// Shortcuts
const { _data: data, blockSize } = this;
const dataWords = data.words;
const dataSigBytes = data.sigBytes;
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);
}
// Count words ready
const nWordsReady = nBlocksReady * blockSize;
// Count bytes ready
const nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);
// Process blocks
if (nWordsReady) {
for (let offset = 0; offset < nWordsReady; offset += blockSize) {
// Perform concrete-algorithm logic
this._doProcessBlock(dataWords, offset);
}
// Remove processed words
processedWords = dataWords.splice(0, nWordsReady);
data.sigBytes -= nBytesReady;
}
// Return processed words
return new WordArray(processedWords, nBytesReady);
}
/**
* Creates a copy of this object.
*
* @return {Object} The clone.
*
* @example
*
* var clone = bufferedBlockAlgorithm.clone();
*/
clone() {
const clone = super.clone.call(this);
clone._data = this._data.clone();
return clone;
}
}