const POW_2_32 = 4294967296 ; const POW_2_53 = 9007199254740992 ; export function encode ( value ) { let data = new ArrayBuffer ( 256 ) ; let dataView = new DataView ( data ) ; let lastLength ; let offset = 0 ; function prepareWrite ( length ) { let newByteLength = data . byteLength ; let requiredLength = offset + length ; while ( newByteLength < requiredLength ) newByteLength <<= 1 ; if ( newByteLength !== data . byteLength ) { let oldDataView = dataView ; data = new ArrayBuffer ( newByteLength ) ; dataView = new DataView ( data ) ; let uint32count = ( offset + 3 ) >> 2 ; for ( let i = 0 ; i < uint32count ; ++ i ) dataView . setUint32 ( i << 2 , oldDataView . getUint32 ( i << 2 ) ) ; } lastLength = length ; return dataView ; } const commitWrite = ( ) => ( offset += lastLength ) ; function writeUint8 ( value ) { prepareWrite ( 1 ) . setUint8 ( offset , value ) ; commitWrite ( ) ; } function writeUint8Array ( value ) { let dataView = prepareWrite ( value . length ) ; for ( let i = 0 ; i < value . length ; ++ i ) dataView . setUint8 ( offset + i , value [ i ] ) ; commitWrite ( ) ; } function writeUint16 ( value ) { prepareWrite ( 2 ) . setUint16 ( offset , value ) ; commitWrite ( ) ; } function writeUint64 ( value ) { let low = value % POW_2_32 ; let high = ( value - low ) / POW_2_32 ; let dataView = prepareWrite ( 8 ) ; dataView . setUint32 ( offset , high ) ; dataView . setUint32 ( offset + 4 , low ) ; commitWrite ( ) ; } function writeTypeAndLength ( type , length ) { if ( length < 24 ) { writeUint8 ( ( type << 5 ) | length ) ; } else if ( length < 0x100 ) { writeUint8 ( ( type << 5 ) | 24 ) ; writeUint8 ( length ) ; } else if ( length < 0x10000 ) { writeUint8 ( ( type << 5 ) | 25 ) ; writeUint16 ( length ) ; } else { writeUint8 ( ( type << 5 ) | 27 ) ; writeUint64 ( length ) ; } } function encodeItem ( value ) { let i ; if ( value === false ) return writeUint8 ( 0xf4 ) ; if ( value === true ) return writeUint8 ( 0xf5 ) ; if ( value === null ) return writeUint8 ( 0xf6 ) ; if ( value === undefined ) return writeUint8 ( 0xf7 ) ; switch ( typeof value ) { case "number" : return writeTypeAndLength ( 0 , value ) ; default : let length ; if ( Array . isArray ( value ) ) { length = value . length ; writeTypeAndLength ( 4 , length ) ; for ( i = 0 ; i < length ; ++ i ) encodeItem ( value [ i ] ) ; } else if ( value instanceof Uint8Array ) { writeTypeAndLength ( 2 , value . length ) ; writeUint8Array ( value ) ; } else { let keys = Object . keys ( value ) ; length = keys . length ; writeTypeAndLength ( 5 , length ) ; for ( i = 0 ; i < length ; ++ i ) { let key = keys [ i ] ; encodeItem ( key ) ; encodeItem ( value [ key ] ) ; } } } } encodeItem ( value ) ; if ( "slice" in data ) return data . slice ( 0 , offset ) ; let ret = new ArrayBuffer ( offset ) ; let retView = new DataView ( ret ) ; for ( let i = 0 ; i < offset ; ++ i ) retView . setUint8 ( i , dataView . getUint8 ( i ) ) ; return ret ; } export function decode ( data ) { let dataView = new DataView ( data ) ; let offset = 0 ; const commitRead = ( length , value ) => { offset += length ; return value ; } ; const readArrayBuffer = ( length ) => commitRead ( length , new Uint8Array ( data , offset , length ) ) ; const readUint8 = ( ) => commitRead ( 1 , dataView . getUint8 ( offset ) ) ; const readUint16 = ( ) => commitRead ( 2 , dataView . getUint16 ( offset ) ) ; const readBreak = ( ) => { if ( dataView . getUint8 ( offset ) !== 0xff ) return false ; offset += 1 ; return true ; } ; function readLength ( additionalInformation ) { if ( additionalInformation < 24 ) return additionalInformation ; if ( additionalInformation === 24 ) return readUint8 ( ) ; if ( additionalInformation === 25 ) return readUint16 ( ) ; if ( additionalInformation === 31 ) return - 1 ; } function readIndefiniteStringLength ( ) { let initialByte = readUint8 ( ) ; if ( initialByte === 0xff ) return - 1 ; return readLength ( initialByte & 0x1f ) ; } const decodeItem = ( ) : any => { let initialByte = readUint8 ( ) ; let majorType = initialByte >> 5 ; let additionalInformation = initialByte & 0x1f ; let i ; let length ; length = readLength ( additionalInformation ) ; if ( length < 0 && ( majorType < 2 || 6 < majorType ) ) throw "Invalid length" ; switch ( majorType ) { case 0 : return length ; case 1 : return - 1 - length ; case 2 : if ( length < 0 ) { let elements = [ ] ; let fullArrayLength = 0 ; while ( ( length = readIndefiniteStringLength ( ) ) >= 0 ) { fullArrayLength += length ; elements . push ( readArrayBuffer ( length ) ) ; } let fullArray = new Uint8Array ( fullArrayLength ) ; let fullArrayOffset = 0 ; for ( i = 0 ; i < elements . length ; ++ i ) { fullArray . set ( elements [ i ] , fullArrayOffset ) ; fullArrayOffset += elements [ i ] . length ; } return fullArray ; } return readArrayBuffer ( length ) ; case 4 : let retArray ; if ( length < 0 ) { retArray = [ ] ; while ( ! readBreak ( ) ) retArray . push ( decodeItem ( ) ) ; } else { retArray = new Array ( length ) ; for ( i = 0 ; i < length ; ++ i ) retArray [ i ] = decodeItem ( ) ; } return retArray ; } } ; let ret = decodeItem ( ) ; if ( offset !== data . byteLength ) throw "Remaining bytes" ; return ret ; }