import { NumberParsingError } from 'src/core/errors' ; import ByteStream from 'src/core/parser/ByteStream' ; import CharCodes from 'src/core/syntax/CharCodes' ; import { IsDigit , IsNumeric } from 'src/core/syntax/Numeric' ; import { IsWhitespace } from 'src/core/syntax/Whitespace' ; import { charFromCode } from 'src/utils' ; const { Newline , CarriageReturn } = CharCodes ; class BaseParser { protected readonly bytes : ByteStream ; protected readonly capNumbers : boolean ; constructor ( bytes , capNumbers = false ) { this . bytes = bytes ; this . capNumbers = capNumbers ; } protected parseRawInt ( ) { let value = '' ; while ( ! this . bytes . done ( ) ) { const byte = this . bytes . peek ( ) ; if ( ! IsDigit [ byte ] ) break ; value += charFromCode ( this . bytes . next ( ) ) ; } const numberValue = Number ( value ) ; if ( ! value || ! isFinite ( numberValue ) ) { throw new NumberParsingError ( this . bytes . position ( ) , value ) ; } return numberValue ; } protected parseRawNumber ( ) { let value = '' ; while ( ! this . bytes . done ( ) ) { const byte = this . bytes . peek ( ) ; if ( ! IsNumeric [ byte ] ) break ; value += charFromCode ( this . bytes . next ( ) ) ; if ( byte === CharCodes . Period ) break ; } while ( ! this . bytes . done ( ) ) { const byte = this . bytes . peek ( ) ; if ( ! IsDigit [ byte ] ) break ; value += charFromCode ( this . bytes . next ( ) ) ; } const numberValue = Number ( value ) ; if ( ! value || ! isFinite ( numberValue ) ) { throw new NumberParsingError ( this . bytes . position ( ) , value ) ; } if ( numberValue > Number . MAX_SAFE_INTEGER ) { if ( this . capNumbers ) { const msg = `Parsed number that is too large for some PDF readers: ${ value }, using Number.MAX_SAFE_INTEGER instead.` ; console . warn ( msg ) ; return Number . MAX_SAFE_INTEGER ; } else { const msg = `Parsed number that is too large for some PDF readers: ${ value }, not capping.` ; console . warn ( msg ) ; } } return numberValue ; } protected skipWhitespace ( ) { while ( ! this . bytes . done ( ) && IsWhitespace [ this . bytes . peek ( ) ] ) { this . bytes . next ( ) ; } } protected skipLine ( ) { while ( ! this . bytes . done ( ) ) { const byte = this . bytes . peek ( ) ; if ( byte === Newline || byte === CarriageReturn ) return ; this . bytes . next ( ) ; } } protected skipComment ( ) { if ( this . bytes . peek ( ) !== CharCodes . Percent ) return false ; while ( ! this . bytes . done ( ) ) { const byte = this . bytes . peek ( ) ; if ( byte === Newline || byte === CarriageReturn ) return true ; this . bytes . next ( ) ; } return true ; } protected skipWhitespaceAndComments ( ) { this . skipWhitespace ( ) ; while ( this . skipComment ( ) ) this . skipWhitespace ( ) ; } protected matchKeyword ( keyword ) { const initialOffset = this . bytes . offset ( ) ; for ( let idx = 0 , len = keyword . length ; idx < len ; idx ++ ) { if ( this . bytes . done ( ) || this . bytes . next ( ) !== keyword [ idx ] ) { this . bytes . moveTo ( initialOffset ) ; return false ; } } return true ; } } export default BaseParser ;