96 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict'
 | |
| var Buffer = require('safe-buffer').Buffer
 | |
| var Transform = require('readable-stream').Transform
 | |
| var inherits = require('inherits')
 | |
| 
 | |
| function throwIfNotStringOrBuffer (val, prefix) {
 | |
|   if (!Buffer.isBuffer(val) && typeof val !== 'string') {
 | |
|     throw new TypeError(prefix + ' must be a string or a buffer')
 | |
|   }
 | |
| }
 | |
| 
 | |
| function HashBase (blockSize) {
 | |
|   Transform.call(this)
 | |
| 
 | |
|   this._block = Buffer.allocUnsafe(blockSize)
 | |
|   this._blockSize = blockSize
 | |
|   this._blockOffset = 0
 | |
|   this._length = [0, 0, 0, 0]
 | |
| 
 | |
|   this._finalized = false
 | |
| }
 | |
| 
 | |
| inherits(HashBase, Transform)
 | |
| 
 | |
| HashBase.prototype._transform = function (chunk, encoding, callback) {
 | |
|   var error = null
 | |
|   try {
 | |
|     this.update(chunk, encoding)
 | |
|   } catch (err) {
 | |
|     error = err
 | |
|   }
 | |
| 
 | |
|   callback(error)
 | |
| }
 | |
| 
 | |
| HashBase.prototype._flush = function (callback) {
 | |
|   var error = null
 | |
|   try {
 | |
|     this.push(this.digest())
 | |
|   } catch (err) {
 | |
|     error = err
 | |
|   }
 | |
| 
 | |
|   callback(error)
 | |
| }
 | |
| 
 | |
| HashBase.prototype.update = function (data, encoding) {
 | |
|   throwIfNotStringOrBuffer(data, 'Data')
 | |
|   if (this._finalized) throw new Error('Digest already called')
 | |
|   if (!Buffer.isBuffer(data)) data = Buffer.from(data, encoding)
 | |
| 
 | |
|   // consume data
 | |
|   var block = this._block
 | |
|   var offset = 0
 | |
|   while (this._blockOffset + data.length - offset >= this._blockSize) {
 | |
|     for (var i = this._blockOffset; i < this._blockSize;) block[i++] = data[offset++]
 | |
|     this._update()
 | |
|     this._blockOffset = 0
 | |
|   }
 | |
|   while (offset < data.length) block[this._blockOffset++] = data[offset++]
 | |
| 
 | |
|   // update length
 | |
|   for (var j = 0, carry = data.length * 8; carry > 0; ++j) {
 | |
|     this._length[j] += carry
 | |
|     carry = (this._length[j] / 0x0100000000) | 0
 | |
|     if (carry > 0) this._length[j] -= 0x0100000000 * carry
 | |
|   }
 | |
| 
 | |
|   return this
 | |
| }
 | |
| 
 | |
| HashBase.prototype._update = function () {
 | |
|   throw new Error('_update is not implemented')
 | |
| }
 | |
| 
 | |
| HashBase.prototype.digest = function (encoding) {
 | |
|   if (this._finalized) throw new Error('Digest already called')
 | |
|   this._finalized = true
 | |
| 
 | |
|   var digest = this._digest()
 | |
|   if (encoding !== undefined) digest = digest.toString(encoding)
 | |
| 
 | |
|   // reset state
 | |
|   this._block.fill(0)
 | |
|   this._blockOffset = 0
 | |
|   for (var i = 0; i < 4; ++i) this._length[i] = 0
 | |
| 
 | |
|   return digest
 | |
| }
 | |
| 
 | |
| HashBase.prototype._digest = function () {
 | |
|   throw new Error('_digest is not implemented')
 | |
| }
 | |
| 
 | |
| module.exports = HashBase
 |