import assert from "assert" ; /**
 * BufferReader class is used to simplify reading information from a Buffer
 */ export class BufferReader { /**
     * Returns the number of bytes that will be used to encode
     * a BigSize number. BigSize is defined in Lightning Network BOLT 07
     */ public static bigSizeBytes ( num ) { if ( num < BigInt ( 0xfd ) ) return 1 ; if ( num < BigInt ( 0x10000 ) ) return 3 ; if ( num < BigInt ( 0x100000000 ) ) return 5 ; else return 9 ; } private _buffer : Buffer ; private _position : number ; private _lastReadBytes : number ; /**
     * Constructs a reader from the supplied Buffer
     */ constructor ( buffer ) { assert ( Buffer . isBuffer ( buffer ) , "Requires a buffer" ) ; this . _buffer = buffer ; this . _position = 0 ; this . _lastReadBytes = 0 ; } /**
     * Gets or sets the current position of the cursor in the buffer
     */ public get position ( ) : number { return this . _position ; } public set position ( val ) { this . _position = val ; } /**
     * Gets if the cursor is at the end of file.
     */ public get eof ( ) : boolean { return this . _position === this . _buffer . length ; } /**
     * Gets the underlying buffer that the cursor
     * is reading from.
     */ public get buffer ( ) : Buffer { return this . _buffer ; } /**
     * Number of bytes read in last operation executed on the cursor.
     * Especially useful for operations that return variable length of
     * results such as readBytes or readVarUint.
     */ public get lastReadBytes ( ) : number { return this . _lastReadBytes ; } /**
     * Read a UInt8 number
     */ public readUInt8 ( ) { return this . _readStandard ( this . readUInt8 . name , 1 ) ; } /**
     * Read a UInt16 number as little-endian
     */ public readUInt16LE ( ) { return this . _readStandard ( this . readUInt16LE . name , 2 ) ; } /**
     * Read a UInt16 number as big-endian
     */ public readUInt16BE ( ) { return this . _readStandard ( this . readUInt16BE . name , 2 ) ; } /**
     * Read a UInt32 number as little-endian
     */ public readUInt32LE ( ) { return this . _readStandard ( this . readUInt32LE . name , 4 ) ; } /**
     * Read a UInt32 number as big-endian
     */ public readUInt32BE ( ) { return this . _readStandard ( this . readUInt32BE . name , 4 ) ; } /**
     * Read a UInt64 number as big-endian
     */ public readUInt64BE ( ) { return BigInt ( "0x" + this . readBytes ( 8 ) . toString ( "hex" ) ) ; } /**
     * Read a UInt64 number as little-endian
     */ public readUInt64LE ( ) { return BigInt ( "0x" + this . readBytes ( 8 ) . reverse ( ) . toString ( "hex" ) ) ; } remarks public readVarUint ( ) { const size = this . readUInt8 ( ) ; if ( size < 0xfd ) { this . _lastReadBytes = 1 ; return BigInt ( size ) ; } switch ( size ) { case 0xfd : this . _lastReadBytes = 3 ; return BigInt ( this . readUInt16LE ( ) ) ; case 0xfe : this . _lastReadBytes = 5 ; return BigInt ( this . readUInt32LE ( ) ) ; case 0xff : this . _lastReadBytes = 9 ; return this . readUInt64LE ( ) ; } } remarks public readBigSize ( ) { const size = this . readUInt8 ( ) ; if ( size < 0xfd ) { this . _lastReadBytes = 1 ; return BigInt ( size ) ; } switch ( size ) { case 0xfd : { this . _lastReadBytes = 3 ; const val = this . readUInt16BE ( ) ; if ( val < 0xfd ) throw new Error ( "decoded varint is not canonical" ) ; return BigInt ( val ) ; } case 0xfe : { this . _lastReadBytes = 5 ; const val = this . readUInt32BE ( ) ; if ( val < 0x10000 ) throw new Error ( "decoded varint is not canonical" ) ; return BigInt ( val ) ; } case 0xff : { this . _lastReadBytes = 9 ; const val = this . readUInt64BE ( ) ; if ( val < BigInt ( 0x100000000 ) ) throw new Error ( "decoded varint is not canonical" ) ; return val ; } } } param len public readBytes ( len ? ) { if ( len === 0 ) { this . _lastReadBytes = 0 ; return Buffer . alloc ( 0 ) ; } else if ( len > 0 ) { if ( this . _position + len > this . _buffer . length ) { throw new RangeError ( "Index out of range" ) ; } const slice = this . _buffer . slice ( this . _position , this . _position + len ) ; const result = Buffer . alloc ( slice . length , slice ) ; this . _position += len ; this . _lastReadBytes = len ; return result ; } else { if ( this . _position === this . _buffer . length ) { this . _lastReadBytes = 0 ; return Buffer . alloc ( 0 ) ; } const slice = this . _buffer . slice ( this . _position ) ; const result = Buffer . alloc ( slice . length , slice ) ; this . _position = this . _buffer . length ; this . _lastReadBytes = result . length ; return result ; } } param len public peakBytes ( len ? ) { if ( len === 0 ) { return Buffer . alloc ( 0 ) ; } else if ( len > 0 ) { if ( this . _position + len > this . _buffer . length ) { throw new RangeError ( "Index out of range" ) ; } const slice = this . _buffer . slice ( this . _position , this . _position + len ) ; const result = Buffer . alloc ( slice . length , slice ) ; return result ; } else { if ( this . _position === this . _buffer . length ) throw new RangeError ( "Index out of range" ) ; const slice = this . _buffer . slice ( this . _position ) ; const result = Buffer . alloc ( slice . length , slice ) ; return result ; } } /**
     * TLV 0 to 2 byte unsigned integer encoded in big-endian.
     */ public readTUInt16 ( ) { const size = Math . min ( 2 , this . _buffer . length - this . _position ) ; if ( size === 0 ) return 0 ; const val = this . _buffer . readUIntBE ( this . _position , size ) ; this . _assertMinimalTUInt ( BigInt ( val ) , size ) ; this . _position += size ; return val ; } /**
     * TLV 0 to 4 byte unsigned integer encoded in big-endian.
     */ public readTUInt32 ( ) { const size = Math . min ( 4 , this . _buffer . length - this . _position ) ; if ( size === 0 ) return 0 ; const val = this . _buffer . readUIntBE ( this . _position , size ) ; this . _assertMinimalTUInt ( BigInt ( val ) , size ) ; this . _position += size ; return val ; } /**
     * TLV 0 to 8 byte unsigned integer encoded in big-endian.
     */ public readTUInt64 ( ) { const size = Math . min ( 8 , this . _buffer . length - this . _position ) ; if ( size === 0 ) return BigInt ( 0 ) ; const hex = this . _buffer . slice ( this . _position , this . _position + size ) . toString ( "hex" ) || "0" ; const val = BigInt ( "0x" + hex ) ; this . _assertMinimalTUInt ( val , size ) ; this . _position += size ; return val ; } param fn param len private _readStandard ( fn , len ) { if ( this . _position + len > this . _buffer . length ) { throw new RangeError ( "Index out of range" ) ; } const result = this . _buffer [ fn ] ( this . _position ) ; this . _position += len ; this . _lastReadBytes = len ; return result ; } param num param bytes private _assertMinimalTUInt ( num , bytes ) { const msg = "TUInt not minimal" ; for ( let i = 0 ; i < 9 ; i ++ ) { if ( num < BigInt ( "0x1" + "" . padStart ( i * 2 , "0" ) ) ) { return assert . equal ( bytes , i , msg ) ; } } } }