var assert=require("assert"),Buffer=require("safer-buffer").Buffer,ASN1=require("./types"),errors=require("./errors"),newInvalidAsn1Error=errors.newInvalidAsn1Error;function Reader(e){if(!e||!Buffer.isBuffer(e))throw new TypeError("data must be a node Buffer");this._buf=e,this._size=e.length,this._len=0,this._offset=0}Object.defineProperty(Reader.prototype,"length",{enumerable:!0,get:function(){return this._len}}),Object.defineProperty(Reader.prototype,"offset",{enumerable:!0,get:function(){return this._offset}}),Object.defineProperty(Reader.prototype,"remain",{get:function(){return this._size-this._offset}}),Object.defineProperty(Reader.prototype,"buffer",{get:function(){return this._buf.slice(this._offset)}}),Reader.prototype.readByte=function(e){if(this._size-this._offset<1)return null;var t=255&this._buf[this._offset];return e||(this._offset+=1),t},Reader.prototype.peek=function(){return this.readByte(!0)},Reader.prototype.readLength=function(e){if(void 0===e&&(e=this._offset),e>=this._size)return null;var t=255&this._buf[e++];if(null===t)return null;if(128==(128&t)){if(0===(t&=127))throw newInvalidAsn1Error("Indefinite length not supported");if(t>4)throw newInvalidAsn1Error("encoding too long");if(this._size-e<t)return null;this._len=0;for(var r=0;r<t;r++)this._len=(this._len<<8)+(255&this._buf[e++])}else this._len=t;return e},Reader.prototype.readSequence=function(e){var t=this.peek();if(null===t)return null;if(void 0!==e&&e!==t)throw newInvalidAsn1Error("Expected 0x"+e.toString(16)+": got 0x"+t.toString(16));var r=this.readLength(this._offset+1);return null===r?null:(this._offset=r,t)},Reader.prototype.readInt=function(){return this._readTag(ASN1.Integer)},Reader.prototype.readBoolean=function(){return 0!==this._readTag(ASN1.Boolean)},Reader.prototype.readEnumeration=function(){return this._readTag(ASN1.Enumeration)},Reader.prototype.readString=function(e,t){e||(e=ASN1.OctetString);var r=this.peek();if(null===r)return null;if(r!==e)throw newInvalidAsn1Error("Expected 0x"+e.toString(16)+": got 0x"+r.toString(16));var n=this.readLength(this._offset+1);if(null===n)return null;if(this.length>this._size-n)return null;if(this._offset=n,0===this.length)return t?Buffer.alloc(0):"";var i=this._buf.slice(this._offset,this._offset+this.length);return this._offset+=this.length,t?i:i.toString("utf8")},Reader.prototype.readOID=function(e){e||(e=ASN1.OID);var t=this.readString(e,!0);if(null===t)return null;for(var r=[],n=0,i=0;i<t.length;i++){var o=255&t[i];n<<=7,n+=127&o,0==(128&o)&&(r.push(n),n=0)}return n=r.shift(),r.unshift(n%40),r.unshift(n/40>>0),r.join(".")},Reader.prototype._readTag=function(e){assert.ok(void 0!==e);var t=this.peek();if(null===t)return null;if(t!==e)throw newInvalidAsn1Error("Expected 0x"+e.toString(16)+": got 0x"+t.toString(16));var r=this.readLength(this._offset+1);if(null===r)return null;if(this.length>4)throw newInvalidAsn1Error("Integer too long: "+this.length);if(this.length>this._size-r)return null;this._offset=r;for(var n=this._buf[this._offset],i=0,o=0;o<this.length;o++)i<<=8,i|=255&this._buf[this._offset++];return 128==(128&n)&&4!==o&&(i-=1<<8*o),i>>0},module.exports=Reader;