You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							154 lines
						
					
					
						
							4.0 KiB
						
					
					
				
			
		
		
	
	
							154 lines
						
					
					
						
							4.0 KiB
						
					
					
				| 'use strict';
 | |
| 
 | |
| const inherits = require('inherits');
 | |
| const Reporter = require('../base/reporter').Reporter;
 | |
| const Buffer = require('safer-buffer').Buffer;
 | |
| 
 | |
| function DecoderBuffer(base, options) {
 | |
|   Reporter.call(this, options);
 | |
|   if (!Buffer.isBuffer(base)) {
 | |
|     this.error('Input not Buffer');
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   this.base = base;
 | |
|   this.offset = 0;
 | |
|   this.length = base.length;
 | |
| }
 | |
| inherits(DecoderBuffer, Reporter);
 | |
| exports.DecoderBuffer = DecoderBuffer;
 | |
| 
 | |
| DecoderBuffer.isDecoderBuffer = function isDecoderBuffer(data) {
 | |
|   if (data instanceof DecoderBuffer) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   // Or accept compatible API
 | |
|   const isCompatible = typeof data === 'object' &&
 | |
|     Buffer.isBuffer(data.base) &&
 | |
|     data.constructor.name === 'DecoderBuffer' &&
 | |
|     typeof data.offset === 'number' &&
 | |
|     typeof data.length === 'number' &&
 | |
|     typeof data.save === 'function' &&
 | |
|     typeof data.restore === 'function' &&
 | |
|     typeof data.isEmpty === 'function' &&
 | |
|     typeof data.readUInt8 === 'function' &&
 | |
|     typeof data.skip === 'function' &&
 | |
|     typeof data.raw === 'function';
 | |
| 
 | |
|   return isCompatible;
 | |
| };
 | |
| 
 | |
| DecoderBuffer.prototype.save = function save() {
 | |
|   return { offset: this.offset, reporter: Reporter.prototype.save.call(this) };
 | |
| };
 | |
| 
 | |
| DecoderBuffer.prototype.restore = function restore(save) {
 | |
|   // Return skipped data
 | |
|   const res = new DecoderBuffer(this.base);
 | |
|   res.offset = save.offset;
 | |
|   res.length = this.offset;
 | |
| 
 | |
|   this.offset = save.offset;
 | |
|   Reporter.prototype.restore.call(this, save.reporter);
 | |
| 
 | |
|   return res;
 | |
| };
 | |
| 
 | |
| DecoderBuffer.prototype.isEmpty = function isEmpty() {
 | |
|   return this.offset === this.length;
 | |
| };
 | |
| 
 | |
| DecoderBuffer.prototype.readUInt8 = function readUInt8(fail) {
 | |
|   if (this.offset + 1 <= this.length)
 | |
|     return this.base.readUInt8(this.offset++, true);
 | |
|   else
 | |
|     return this.error(fail || 'DecoderBuffer overrun');
 | |
| };
 | |
| 
 | |
| DecoderBuffer.prototype.skip = function skip(bytes, fail) {
 | |
|   if (!(this.offset + bytes <= this.length))
 | |
|     return this.error(fail || 'DecoderBuffer overrun');
 | |
| 
 | |
|   const res = new DecoderBuffer(this.base);
 | |
| 
 | |
|   // Share reporter state
 | |
|   res._reporterState = this._reporterState;
 | |
| 
 | |
|   res.offset = this.offset;
 | |
|   res.length = this.offset + bytes;
 | |
|   this.offset += bytes;
 | |
|   return res;
 | |
| };
 | |
| 
 | |
| DecoderBuffer.prototype.raw = function raw(save) {
 | |
|   return this.base.slice(save ? save.offset : this.offset, this.length);
 | |
| };
 | |
| 
 | |
| function EncoderBuffer(value, reporter) {
 | |
|   if (Array.isArray(value)) {
 | |
|     this.length = 0;
 | |
|     this.value = value.map(function(item) {
 | |
|       if (!EncoderBuffer.isEncoderBuffer(item))
 | |
|         item = new EncoderBuffer(item, reporter);
 | |
|       this.length += item.length;
 | |
|       return item;
 | |
|     }, this);
 | |
|   } else if (typeof value === 'number') {
 | |
|     if (!(0 <= value && value <= 0xff))
 | |
|       return reporter.error('non-byte EncoderBuffer value');
 | |
|     this.value = value;
 | |
|     this.length = 1;
 | |
|   } else if (typeof value === 'string') {
 | |
|     this.value = value;
 | |
|     this.length = Buffer.byteLength(value);
 | |
|   } else if (Buffer.isBuffer(value)) {
 | |
|     this.value = value;
 | |
|     this.length = value.length;
 | |
|   } else {
 | |
|     return reporter.error('Unsupported type: ' + typeof value);
 | |
|   }
 | |
| }
 | |
| exports.EncoderBuffer = EncoderBuffer;
 | |
| 
 | |
| EncoderBuffer.isEncoderBuffer = function isEncoderBuffer(data) {
 | |
|   if (data instanceof EncoderBuffer) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   // Or accept compatible API
 | |
|   const isCompatible = typeof data === 'object' &&
 | |
|     data.constructor.name === 'EncoderBuffer' &&
 | |
|     typeof data.length === 'number' &&
 | |
|     typeof data.join === 'function';
 | |
| 
 | |
|   return isCompatible;
 | |
| };
 | |
| 
 | |
| EncoderBuffer.prototype.join = function join(out, offset) {
 | |
|   if (!out)
 | |
|     out = Buffer.alloc(this.length);
 | |
|   if (!offset)
 | |
|     offset = 0;
 | |
| 
 | |
|   if (this.length === 0)
 | |
|     return out;
 | |
| 
 | |
|   if (Array.isArray(this.value)) {
 | |
|     this.value.forEach(function(item) {
 | |
|       item.join(out, offset);
 | |
|       offset += item.length;
 | |
|     });
 | |
|   } else {
 | |
|     if (typeof this.value === 'number')
 | |
|       out[offset] = this.value;
 | |
|     else if (typeof this.value === 'string')
 | |
|       out.write(this.value, offset);
 | |
|     else if (Buffer.isBuffer(this.value))
 | |
|       this.value.copy(out, offset);
 | |
|     offset += this.length;
 | |
|   }
 | |
| 
 | |
|   return out;
 | |
| };
 |