import { _ } from "streamline-runtime" ; import { Reader as BaseReader } from "../reader" ; import { Writer as BaseWriter } from "../writer" ; const NUMBERS = [ [ 'Int8' , 1 ] , [ 'UInt8' , 1 ] , [ 'Int16' , 2 ] , [ 'UInt16' , 2 ] , [ 'Int32' , 4 ] , [ 'UInt32' , 4 ] , [ 'Float' , 4 ] , [ 'Double' , 8 ] ] ; export interface ReaderOptions { endian ? : 'big' | 'little' ; } export class Reader extends BaseReader < Buffer > { reader : BaseReader < Buffer > ; options : ReaderOptions ; pos : number ; buf : Buffer | undefined ; constructor ( reader , options ) { super ( ( _ ) => { return this . readData ( _ ) ; } ) ; this . reader = reader ; this . options = options ; this . pos = 0 ; this . buf = Buffer . alloc ( 0 ) ; this . read = this . readData ; } readData ( _ , len ? , peekOnly ? ) { if ( this . buf === undefined ) return undefined ; if ( len === undefined ) { if ( this . pos < this . buf . length ) return this . readData ( _ , this . buf . length - this . pos ) ; else { this . buf = this . reader . read ( _ ) ; this . pos = this . buf && ! peekOnly ? this . buf . length : 0 ; return this . buf ; } } const l = this . ensure ( _ , len ) ; if ( l === 0 && len > 0 ) return undefined ; const result = this . buf . slice ( this . pos , this . pos + l ) ; if ( ! peekOnly ) this . pos += l ; return result ; } ensure ( _ , len ) { if ( this . buf === undefined ) return 0 ; if ( this . pos + len <= this . buf . length ) return len ; var got = this . buf . length - this . pos ; const bufs = got ? [ this . buf . slice ( this . pos ) ] : [ ] ; this . pos = 0 ; while ( got < len ) { var buf = this . reader . read ( _ ) ; if ( buf === undefined ) { if ( bufs . length === 0 ) return 0 ; else break ; } bufs . push ( buf ) ; got += buf . length ; } this . buf = Buffer . concat ( bufs ) ; return Math . min ( this . buf . length , len ) ; } peek ( _ , len ) { return this . readData ( _ , len , true ) ; } unread ( len ) { if ( ! ( len <= this . pos ) ) throw new Error ( "invalid unread: expected <= " + this . pos + ", got " + len ) ; this . pos -= len ; } } function numberReader ( name , len , peekOnly ? ) { return function ( this , _ ) { const got = this . ensure ( _ , len ) ; if ( got === 0 ) return undefined ; if ( got < len ) throw new Error ( "unexpected EOF: expected " + len + ", got " + got ) ; const result = ( this . buf as any ) [ name ] ( this . pos ) ; if ( ! peekOnly ) this . pos += len ; return result ; } ; } function numberUnreader ( len ) { return function ( this ) { return this . unread ( len ) ; } ; } export interface WriterOptions { endian ? : 'big' | 'little' ; bufSize ? : number ; } export class Writer extends BaseWriter < Buffer > { writer : BaseWriter < Buffer > ; options : WriterOptions ; pos : number ; buf : Buffer ; constructor ( writer , options ? ) { super ( ( _ , buf ) => { this . writeDate ( _ , buf ) ; return this ; } ) ; options = options || { } ; this . writer = writer ; this . options = options ; this . pos = 0 ; this . buf = Buffer . alloc ( options . bufSize && options . bufSize > 0 ? options . bufSize : 16384 ) ; } flush ( _ ) { if ( this . pos > 0 ) this . writer . write ( _ , this . buf . slice ( 0 , this . pos ) ) ; this . buf = Buffer . alloc ( this . buf . length ) ; this . pos = 0 ; } ensure ( _ , len ) { if ( this . pos + len > this . buf . length ) { this . flush ( _ ) ; if ( len > this . buf . length ) this . buf = Buffer . alloc ( len ) ; } } writeDate ( _ , buf ) { if ( buf === undefined || buf . length > this . buf . length ) { this . flush ( _ ) ; this . writer . write ( _ , buf ) ; } else { this . ensure ( _ , buf . length ) ; buf . copy ( this . buf , this . pos ) ; this . pos += buf . length ; } } } function numberWriter ( name , len ) { return function ( this , _ , val ) { this . ensure ( _ , len ) ; ( this . buf as any ) [ name ] ( val , this . pos ) ; this . pos += len ; } ; } NUMBERS . forEach ( function ( pair ) { const len = pair [ 1 ] ; const names = len > 1 ? [ pair [ 0 ] + 'BE' , pair [ 0 ] + 'LE' ] : [ pair [ 0 ] ] ; const readerProto = Reader . prototype ; const writerProto = Writer . prototype ; names . forEach ( function ( name ) { readerProto [ 'read' + name ] = numberReader ( 'read' + name , len , false ) ; readerProto [ 'peek' + name ] = numberReader ( 'read' + name , len , true ) ; readerProto [ 'unread' + name ] = numberUnreader ( len ) ; writerProto [ 'write' + name ] = numberWriter ( 'write' + name , len ) ; } ) ; } ) ; function makeEndian ( base , verbs , suffix ) { const construct = function ( this ) { base . apply ( this , arguments ) ; } ; construct . prototype = Object . create ( base . prototype ) ; NUMBERS . slice ( 1 ) . forEach ( function ( pair ) { verbs . forEach ( function ( verb ) { construct . prototype [ verb + pair [ 0 ] ] = base . prototype [ verb + pair [ 0 ] + suffix ] ; } ) ; } ) ; return construct ; } require ( '../reader' ) . decorate ( Reader . prototype ) ; require ( '../writer' ) . decorate ( Writer . prototype ) ; const ReaderLE = makeEndian ( Reader , [ 'read' , 'peek' , 'unread' ] , 'LE' ) ; const ReaderBE = makeEndian ( Reader , [ 'read' , 'peek' , 'unread' ] , 'BE' ) ; const WriterLE = makeEndian ( Writer , [ 'write' ] , 'LE' ) ; const WriterBE = makeEndian ( Writer , [ 'write' ] , 'BE' ) ; export interface BinaryReader extends Reader { read ( _ , len ? ) : Buffer | undefined ; readInt8 ( _ ) : number ; peekInt8 ( _ ) : number ; unreadInt8 ( ) : void ; readInt16 ( _ ) : number ; peekInt16 ( _ ) : number ; unreadInt16 ( ) : void ; readUInt16 ( _ ) : number ; peekUInt16 ( _ ) : number ; unreadUInt16 ( ) : void ; readInt32 ( _ ) : number ; peekInt32 ( _ ) : number ; unreadInt32 ( ) : void ; readUInt32 ( _ ) : number ; peekUInt32 ( _ ) : number ; unreadUInt32 ( ) : void ; readFloat ( _ ) : number ; peekFloat ( _ ) : number ; unreadFloat ( ) : void ; readDouble ( _ ) : number ; peekDouble ( _ ) : number ; unreadDouble ( ) : void ; } export interface BinaryWriter extends Writer { writeInt8 ( _ , val ) : void ; writeInt16 ( _ , val ) : void ; writeUInt16 ( _ , val ) : void ; writeInt32 ( _ , val ) : void ; writeUInt32 ( _ , val ) : void ; writeFloat ( _ , val ) : void ; writeDouble ( _ , val ) : void ; } export function reader ( reader , options ? ) { options = options || { } ; const constr = options . endian === 'little' ? ReaderLE : ReaderBE ; return new constr ( reader , options ) ; } export function writer ( writer , options ? ) { options = options || { } ; const constr = options . endian === 'little' ? WriterLE : WriterBE ; return new constr ( writer , options ) ; }