import PDFObject from 'src/core/objects/PDFObject' ; import CharCodes from 'src/core/syntax/CharCodes' ; import { copyStringIntoBuffer , padStart , utf16Decode , pdfDocEncodingDecode , toCharCode , parseDate , hasUtf16BOM , } from 'src/utils' ; import { InvalidPDFDateStringError } from 'src/core/errors' ; class PDFString extends PDFObject { static of = ( value ) => new PDFString ( value ) ; static fromDate = ( date ) => { const year = padStart ( String ( date . getUTCFullYear ( ) ) , 4 , '0' ) ; const month = padStart ( String ( date . getUTCMonth ( ) + 1 ) , 2 , '0' ) ; const day = padStart ( String ( date . getUTCDate ( ) ) , 2 , '0' ) ; const hours = padStart ( String ( date . getUTCHours ( ) ) , 2 , '0' ) ; const mins = padStart ( String ( date . getUTCMinutes ( ) ) , 2 , '0' ) ; const secs = padStart ( String ( date . getUTCSeconds ( ) ) , 2 , '0' ) ; return new PDFString ( `D:${ year }${ month }${ day }${ hours }${ mins }${ secs }Z` ) ; } ; private readonly value : string ; private constructor ( value ) { super ( ) ; this . value = value ; } asBytes ( ) { const bytes = [ ] ; let octal = '' ; let escaped = false ; const pushByte = ( byte ? ) => { if ( byte !== undefined ) bytes . push ( byte ) ; escaped = false ; } ; for ( let idx = 0 , len = this . value . length ; idx < len ; idx ++ ) { const char = this . value [ idx ] ; const byte = toCharCode ( char ) ; const nextChar = this . value [ idx + 1 ] ; if ( ! escaped ) { if ( byte === CharCodes . BackSlash ) escaped = true ; else pushByte ( byte ) ; } else { if ( byte === CharCodes . Newline ) pushByte ( ) ; else if ( byte === CharCodes . CarriageReturn ) pushByte ( ) ; else if ( byte === CharCodes . n ) pushByte ( CharCodes . Newline ) ; else if ( byte === CharCodes . r ) pushByte ( CharCodes . CarriageReturn ) ; else if ( byte === CharCodes . t ) pushByte ( CharCodes . Tab ) ; else if ( byte === CharCodes . b ) pushByte ( CharCodes . Backspace ) ; else if ( byte === CharCodes . f ) pushByte ( CharCodes . FormFeed ) ; else if ( byte === CharCodes . LeftParen ) pushByte ( CharCodes . LeftParen ) ; else if ( byte === CharCodes . RightParen ) pushByte ( CharCodes . RightParen ) ; else if ( byte === CharCodes . Backspace ) pushByte ( CharCodes . BackSlash ) ; else if ( byte >= CharCodes . Zero && byte <= CharCodes . Seven ) { octal += char ; if ( octal . length === 3 || ! ( nextChar >= '0' && nextChar <= '7' ) ) { pushByte ( parseInt ( octal , 8 ) ) ; octal = '' ; } } else { pushByte ( byte ) ; } } } return new Uint8Array ( bytes ) ; } decodeText ( ) { const bytes = this . asBytes ( ) ; if ( hasUtf16BOM ( bytes ) ) return utf16Decode ( bytes ) ; return pdfDocEncodingDecode ( bytes ) ; } decodeDate ( ) { const text = this . decodeText ( ) ; const date = parseDate ( text ) ; if ( ! date ) throw new InvalidPDFDateStringError ( text ) ; return date ; } asString ( ) { return this . value ; } clone ( ) { return PDFString . of ( this . value ) ; } toString ( ) { return `(${ this . value })` ; } sizeInBytes ( ) { return this . value . length + 2 ; } copyBytesInto ( buffer , offset ) { buffer [ offset ++ ] = CharCodes . LeftParen ; offset += copyStringIntoBuffer ( this . value , buffer , offset ) ; buffer [ offset ++ ] = CharCodes . RightParen ; return this . value . length + 2 ; } } export default PDFString ;