| '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 |