import { fastPathLookup , IPublicSuffix , ISuffixLookupOptions , } from 'tldts-core' ; import packed from './data/hashes' ; /**
 * Find `elt` in `arr` between indices `start` (included) and `end` (excluded)
 * using a binary search algorithm.
 */ function binSearch ( arr , elt , start , end ) { if ( start >= end ) { return false ; } let low = start ; let high = end - 1 ; while ( low <= high ) { const mid = ( low + high ) >>> 1 ; const midVal = arr [ mid ] ; if ( midVal < elt ) { low = mid + 1 ; } else if ( midVal > elt ) { high = mid - 1 ; } else { return true ; } } return false ; } const BUFFER = new Uint32Array ( 20 ) ; /**
 * Iterate on hashes of labels from `hostname` backward (from last label to
 * first label), stopping after `maximumNumberOfLabels` have been extracted and
 * calling `cb` on each of them.
 *
 * The `maximumNumberOfLabels` argument is typically used to specify the number
 * of labels seen in the longest public suffix. We do not need to check further
 * in very long hostnames.
 */ function hashHostnameLabelsBackward ( hostname , maximumNumberOfLabels ) { let hash = 5381 ; let index = 0 ; for ( let i = hostname . length - 1 ; i >= 0 ; i -= 1 ) { const code = hostname . charCodeAt ( i ) ; if ( code === 46 ) { BUFFER [ index << 1 ] = hash >>> 0 ; BUFFER [ ( index << 1 ) + 1 ] = i + 1 ; index += 1 ; if ( index === maximumNumberOfLabels ) { return index ; } } hash = ( hash * 33 ) ^ code ; } BUFFER [ index << 1 ] = hash >>> 0 ; BUFFER [ ( index << 1 ) + 1 ] = 0 ; index += 1 ; return index ; } const enum Result { NO_MATCH = 0 , ICANN_MATCH = 1 , PRIVATE_MATCH = 2 , EXCEPTION_MATCH = 4 , NORMAL_MATCH = 8 , WILDCARD_MATCH = 16 } /**
 * Perform a public suffix lookup for `hostname` using the packed hashes
 * data-structure. The `options` allows to specify if ICANN/PRIVATE sections
 * should be considered. By default, both are.
 *
 */ export default function suffixLookup ( hostname , options , out ) { if ( fastPathLookup ( hostname , options , out ) === true ) { return ; } const { allowIcannDomains , allowPrivateDomains } = options ; let matchIndex = - 1 ; let matchKind = Result . NO_MATCH ; let matchLabels = 0 ; let index = 1 ; const numberOfHashes = hashHostnameLabelsBackward ( hostname , packed [ 0 ] ) ; for ( let label = 0 ; label < numberOfHashes ; label += 1 ) { const hash = BUFFER [ label << 1 ] ; const labelStart = BUFFER [ ( label << 1 ) + 1 ] ; let match = Result . NO_MATCH ; if ( allowIcannDomains === true ) { match = binSearch ( packed , hash , index + 1 , index + packed [ index ] + 1 ) ? Result . ICANN_MATCH | Result . EXCEPTION_MATCH : Result . NO_MATCH ; } index += packed [ index ] + 1 ; if ( allowPrivateDomains === true && match === Result . NO_MATCH ) { match = binSearch ( packed , hash , index + 1 , index + packed [ index ] + 1 ) ? Result . PRIVATE_MATCH | Result . EXCEPTION_MATCH : Result . NO_MATCH ; } index += packed [ index ] + 1 ; if ( allowIcannDomains === true && match === Result . NO_MATCH && ( matchKind & Result . EXCEPTION_MATCH ) === 0 ) { match = binSearch ( packed , hash , index + 1 , index + packed [ index ] + 1 ) ? Result . WILDCARD_MATCH | Result . ICANN_MATCH : Result . NO_MATCH ; } index += packed [ index ] + 1 ; if ( allowPrivateDomains === true && match === Result . NO_MATCH && ( matchKind & Result . EXCEPTION_MATCH ) === 0 ) { match = binSearch ( packed , hash , index + 1 , index + packed [ index ] + 1 ) ? Result . WILDCARD_MATCH | Result . PRIVATE_MATCH : Result . NO_MATCH ; } index += packed [ index ] + 1 ; if ( allowIcannDomains === true && match === Result . NO_MATCH && ( matchKind & Result . EXCEPTION_MATCH ) === 0 && matchLabels <= label ) { match = binSearch ( packed , hash , index + 1 , index + packed [ index ] + 1 ) ? Result . NORMAL_MATCH | Result . ICANN_MATCH : Result . NO_MATCH ; } index += packed [ index ] + 1 ; if ( allowPrivateDomains === true && match === Result . NO_MATCH && ( matchKind & Result . EXCEPTION_MATCH ) === 0 && matchLabels <= label ) { match = binSearch ( packed , hash , index + 1 , index + packed [ index ] + 1 ) ? Result . NORMAL_MATCH | Result . PRIVATE_MATCH : Result . NO_MATCH ; } index += packed [ index ] + 1 ; if ( match !== Result . NO_MATCH ) { matchKind = match ; matchLabels = label + ( ( match & Result . WILDCARD_MATCH ) !== 0 ? 2 : 1 ) ; matchIndex = labelStart ; } } out . isIcann = ( matchKind & Result . ICANN_MATCH ) !== 0 ; out . isPrivate = ( matchKind & Result . PRIVATE_MATCH ) !== 0 ; if ( matchIndex === - 1 ) { out . publicSuffix = numberOfHashes === 1 ? hostname : hostname . slice ( BUFFER [ 1 ] ) ; return ; } if ( ( matchKind & Result . EXCEPTION_MATCH ) !== 0 ) { out . publicSuffix = hostname . slice ( BUFFER [ ( ( matchLabels - 2 ) << 1 ) + 1 ] ) ; return ; } if ( ( matchKind & Result . WILDCARD_MATCH ) !== 0 ) { out . publicSuffix = matchLabels >= numberOfHashes ? hostname : hostname . slice ( BUFFER [ ( ( matchLabels - 1 ) << 1 ) + 1 ] ) ; return ; } out . publicSuffix = hostname . slice ( matchIndex ) ; }