/* Copyright 2012 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import './compatibility'; import { ReadableStream } from './streams_polyfill'; import { URL } from './url_polyfill'; const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; const NativeImageDecoding = { NONE: 'none', DECODE: 'decode', DISPLAY: 'display', }; // Permission flags from Table 22, Section 7.6.3.2 of the PDF specification. const PermissionFlag = { PRINT: 0x04, MODIFY_CONTENTS: 0x08, COPY: 0x10, MODIFY_ANNOTATIONS: 0x20, FILL_INTERACTIVE_FORMS: 0x100, COPY_FOR_ACCESSIBILITY: 0x200, ASSEMBLE: 0x400, PRINT_HIGH_QUALITY: 0x800, }; const TextRenderingMode = { FILL: 0, STROKE: 1, FILL_STROKE: 2, INVISIBLE: 3, FILL_ADD_TO_PATH: 4, STROKE_ADD_TO_PATH: 5, FILL_STROKE_ADD_TO_PATH: 6, ADD_TO_PATH: 7, FILL_STROKE_MASK: 3, ADD_TO_PATH_FLAG: 4, }; const ImageKind = { GRAYSCALE_1BPP: 1, RGB_24BPP: 2, RGBA_32BPP: 3, }; const AnnotationType = { TEXT: 1, LINK: 2, FREETEXT: 3, LINE: 4, SQUARE: 5, CIRCLE: 6, POLYGON: 7, POLYLINE: 8, HIGHLIGHT: 9, UNDERLINE: 10, SQUIGGLY: 11, STRIKEOUT: 12, STAMP: 13, CARET: 14, INK: 15, POPUP: 16, FILEATTACHMENT: 17, SOUND: 18, MOVIE: 19, WIDGET: 20, SCREEN: 21, PRINTERMARK: 22, TRAPNET: 23, WATERMARK: 24, THREED: 25, REDACT: 26, }; const AnnotationFlag = { INVISIBLE: 0x01, HIDDEN: 0x02, PRINT: 0x04, NOZOOM: 0x08, NOROTATE: 0x10, NOVIEW: 0x20, READONLY: 0x40, LOCKED: 0x80, TOGGLENOVIEW: 0x100, LOCKEDCONTENTS: 0x200, }; const AnnotationFieldFlag = { READONLY: 0x0000001, REQUIRED: 0x0000002, NOEXPORT: 0x0000004, MULTILINE: 0x0001000, PASSWORD: 0x0002000, NOTOGGLETOOFF: 0x0004000, RADIO: 0x0008000, PUSHBUTTON: 0x0010000, COMBO: 0x0020000, EDIT: 0x0040000, SORT: 0x0080000, FILESELECT: 0x0100000, MULTISELECT: 0x0200000, DONOTSPELLCHECK: 0x0400000, DONOTSCROLL: 0x0800000, COMB: 0x1000000, RICHTEXT: 0x2000000, RADIOSINUNISON: 0x2000000, COMMITONSELCHANGE: 0x4000000, }; const AnnotationBorderStyleType = { SOLID: 1, DASHED: 2, BEVELED: 3, INSET: 4, UNDERLINE: 5, }; const StreamType = { UNKNOWN: 0, FLATE: 1, LZW: 2, DCT: 3, JPX: 4, JBIG: 5, A85: 6, AHX: 7, CCF: 8, RL: 9, }; const FontType = { UNKNOWN: 0, TYPE1: 1, TYPE1C: 2, CIDFONTTYPE0: 3, CIDFONTTYPE0C: 4, TRUETYPE: 5, CIDFONTTYPE2: 6, TYPE3: 7, OPENTYPE: 8, TYPE0: 9, MMTYPE1: 10, }; const VerbosityLevel = { ERRORS: 0, WARNINGS: 1, INFOS: 5, }; const CMapCompressionType = { NONE: 0, BINARY: 1, STREAM: 2, }; // All the possible operations for an operator list. const OPS = { // Intentionally start from 1 so it is easy to spot bad operators that will be // 0's. dependency: 1, setLineWidth: 2, setLineCap: 3, setLineJoin: 4, setMiterLimit: 5, setDash: 6, setRenderingIntent: 7, setFlatness: 8, setGState: 9, save: 10, restore: 11, transform: 12, moveTo: 13, lineTo: 14, curveTo: 15, curveTo2: 16, curveTo3: 17, closePath: 18, rectangle: 19, stroke: 20, closeStroke: 21, fill: 22, eoFill: 23, fillStroke: 24, eoFillStroke: 25, closeFillStroke: 26, closeEOFillStroke: 27, endPath: 28, clip: 29, eoClip: 30, beginText: 31, endText: 32, setCharSpacing: 33, setWordSpacing: 34, setHScale: 35, setLeading: 36, setFont: 37, setTextRenderingMode: 38, setTextRise: 39, moveText: 40, setLeadingMoveText: 41, setTextMatrix: 42, nextLine: 43, showText: 44, showSpacedText: 45, nextLineShowText: 46, nextLineSetSpacingShowText: 47, setCharWidth: 48, setCharWidthAndBounds: 49, setStrokeColorSpace: 50, setFillColorSpace: 51, setStrokeColor: 52, setStrokeColorN: 53, setFillColor: 54, setFillColorN: 55, setStrokeGray: 56, setFillGray: 57, setStrokeRGBColor: 58, setFillRGBColor: 59, setStrokeCMYKColor: 60, setFillCMYKColor: 61, shadingFill: 62, beginInlineImage: 63, beginImageData: 64, endInlineImage: 65, paintXObject: 66, markPoint: 67, markPointProps: 68, beginMarkedContent: 69, beginMarkedContentProps: 70, endMarkedContent: 71, beginCompat: 72, endCompat: 73, paintFormXObjectBegin: 74, paintFormXObjectEnd: 75, beginGroup: 76, endGroup: 77, beginAnnotations: 78, endAnnotations: 79, beginAnnotation: 80, endAnnotation: 81, paintJpegXObject: 82, paintImageMaskXObject: 83, paintImageMaskXObjectGroup: 84, paintImageXObject: 85, paintInlineImageXObject: 86, paintInlineImageXObjectGroup: 87, paintImageXObjectRepeat: 88, paintImageMaskXObjectRepeat: 89, paintSolidColorImageMask: 90, constructPath: 91, }; const UNSUPPORTED_FEATURES = { unknown: 'unknown', forms: 'forms', javaScript: 'javaScript', smask: 'smask', shadingPattern: 'shadingPattern', font: 'font', }; const PasswordResponses = { NEED_PASSWORD: 1, INCORRECT_PASSWORD: 2, }; let verbosity = VerbosityLevel.WARNINGS; function setVerbosityLevel(level) { if (Number.isInteger(level)) { verbosity = level; } } function getVerbosityLevel() { return verbosity; } // A notice for devs. These are good for things that are helpful to devs, such // as warning that Workers were disabled, which is important to devs but not // end users. function info(msg) { if (verbosity >= VerbosityLevel.INFOS) { console.log('Info: ' + msg); } } // Non-fatal warnings. function warn(msg) { if (verbosity >= VerbosityLevel.WARNINGS) { console.log('Warning: ' + msg); } } // Deprecated API function -- display regardless of the `verbosity` setting. function deprecated(details) { console.log('Deprecated API usage: ' + details); } function unreachable(msg) { throw new Error(msg); } function assert(cond, msg) { if (!cond) { unreachable(msg); } } // Checks if URLs have the same origin. For non-HTTP based URLs, returns false. function isSameOrigin(baseUrl, otherUrl) { try { var base = new URL(baseUrl); if (!base.origin || base.origin === 'null') { return false; // non-HTTP url } } catch (e) { return false; } var other = new URL(otherUrl, base); return base.origin === other.origin; } // Checks if URLs use one of the whitelisted protocols, e.g. to avoid XSS. function _isValidProtocol(url) { if (!url) { return false; } switch (url.protocol) { case 'http:': case 'https:': case 'ftp:': case 'mailto:': case 'tel:': return true; default: return false; } } /** * Attempts to create a valid absolute URL. * * @param {URL|string} url - An absolute, or relative, URL. * @param {URL|string} baseUrl - An absolute URL. * @returns Either a valid {URL}, or `null` otherwise. */ function createValidAbsoluteUrl(url, baseUrl) { if (!url) { return null; } try { var absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url); if (_isValidProtocol(absoluteUrl)) { return absoluteUrl; } } catch (ex) { /* `new URL()` will throw on incorrect data. */ } return null; } function shadow(obj, prop, value) { Object.defineProperty(obj, prop, { value, enumerable: true, configurable: true, writable: false, }); return value; } function getLookupTableFactory(initializer) { var lookup; return function () { if (initializer) { lookup = Object.create(null); initializer(lookup); initializer = null; } return lookup; }; } var PasswordException = (function PasswordExceptionClosure() { function PasswordException(msg, code) { this.name = 'PasswordException'; this.message = msg; this.code = code; } PasswordException.prototype = new Error(); PasswordException.constructor = PasswordException; return PasswordException; })(); var UnknownErrorException = (function UnknownErrorExceptionClosure() { function UnknownErrorException(msg, details) { this.name = 'UnknownErrorException'; this.message = msg; this.details = details; } UnknownErrorException.prototype = new Error(); UnknownErrorException.constructor = UnknownErrorException; return UnknownErrorException; })(); var InvalidPDFException = (function InvalidPDFExceptionClosure() { function InvalidPDFException(msg) { this.name = 'InvalidPDFException'; this.message = msg; } InvalidPDFException.prototype = new Error(); InvalidPDFException.constructor = InvalidPDFException; return InvalidPDFException; })(); var MissingPDFException = (function MissingPDFExceptionClosure() { function MissingPDFException(msg) { this.name = 'MissingPDFException'; this.message = msg; } MissingPDFException.prototype = new Error(); MissingPDFException.constructor = MissingPDFException; return MissingPDFException; })(); var UnexpectedResponseException = (function UnexpectedResponseExceptionClosure() { function UnexpectedResponseException(msg, status) { this.name = 'UnexpectedResponseException'; this.message = msg; this.status = status; } UnexpectedResponseException.prototype = new Error(); UnexpectedResponseException.constructor = UnexpectedResponseException; return UnexpectedResponseException; })(); var MissingDataException = (function MissingDataExceptionClosure() { function MissingDataException(begin, end) { this.begin = begin; this.end = end; this.message = 'Missing data [' + begin + ', ' + end + ')'; } MissingDataException.prototype = new Error(); MissingDataException.prototype.name = 'MissingDataException'; MissingDataException.constructor = MissingDataException; return MissingDataException; })(); var XRefParseException = (function XRefParseExceptionClosure() { function XRefParseException(msg) { this.message = msg; } XRefParseException.prototype = new Error(); XRefParseException.prototype.name = 'XRefParseException'; XRefParseException.constructor = XRefParseException; return XRefParseException; })(); /** * Error caused during parsing PDF data. */ let FormatError = (function FormatErrorClosure() { function FormatError(msg) { this.message = msg; } FormatError.prototype = new Error(); FormatError.prototype.name = 'FormatError'; FormatError.constructor = FormatError; return FormatError; })(); /** * Error used to indicate task cancellation. */ let AbortException = (function AbortExceptionClosure() { function AbortException(msg) { this.name = 'AbortException'; this.message = msg; } AbortException.prototype = new Error(); AbortException.constructor = AbortException; return AbortException; })(); var NullCharactersRegExp = /\x00/g; function removeNullCharacters(str) { if (typeof str !== 'string') { warn('The argument for removeNullCharacters must be a string.'); return str; } return str.replace(NullCharactersRegExp, ''); } function bytesToString(bytes) { assert(bytes !== null && typeof bytes === 'object' && bytes.length !== undefined, 'Invalid argument for bytesToString'); var length = bytes.length; var MAX_ARGUMENT_COUNT = 8192; if (length < MAX_ARGUMENT_COUNT) { return String.fromCharCode.apply(null, bytes); } var strBuf = []; for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) { var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length); var chunk = bytes.subarray(i, chunkEnd); strBuf.push(String.fromCharCode.apply(null, chunk)); } return strBuf.join(''); } function stringToBytes(str) { assert(typeof str === 'string', 'Invalid argument for stringToBytes'); var length = str.length; var bytes = new Uint8Array(length); for (var i = 0; i < length; ++i) { bytes[i] = str.charCodeAt(i) & 0xFF; } return bytes; } /** * Gets length of the array (Array, Uint8Array, or string) in bytes. * @param {Array|Uint8Array|string} arr * @returns {number} */ function arrayByteLength(arr) { if (arr.length !== undefined) { return arr.length; } assert(arr.byteLength !== undefined); return arr.byteLength; } /** * Combines array items (arrays) into single Uint8Array object. * @param {Array} arr - the array of the arrays (Array, Uint8Array, or string). * @returns {Uint8Array} */ function arraysToBytes(arr) { // Shortcut: if first and only item is Uint8Array, return it. if (arr.length === 1 && (arr[0] instanceof Uint8Array)) { return arr[0]; } var resultLength = 0; var i, ii = arr.length; var item, itemLength; for (i = 0; i < ii; i++) { item = arr[i]; itemLength = arrayByteLength(item); resultLength += itemLength; } var pos = 0; var data = new Uint8Array(resultLength); for (i = 0; i < ii; i++) { item = arr[i]; if (!(item instanceof Uint8Array)) { if (typeof item === 'string') { item = stringToBytes(item); } else { item = new Uint8Array(item); } } itemLength = item.byteLength; data.set(item, pos); pos += itemLength; } return data; } function string32(value) { return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff, (value >> 8) & 0xff, value & 0xff); } // Calculate the base 2 logarithm of the number `x`. This differs from the // native function in the sense that it returns the ceiling value and that it // returns 0 instead of `Infinity`/`NaN` for `x` values smaller than/equal to 0. function log2(x) { if (x <= 0) { return 0; } return Math.ceil(Math.log2(x)); } function readInt8(data, start) { return (data[start] << 24) >> 24; } function readUint16(data, offset) { return (data[offset] << 8) | data[offset + 1]; } function readUint32(data, offset) { return ((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]) >>> 0; } // Lazy test the endianness of the platform // NOTE: This will be 'true' for simulated TypedArrays function isLittleEndian() { var buffer8 = new Uint8Array(4); buffer8[0] = 1; var view32 = new Uint32Array(buffer8.buffer, 0, 1); return (view32[0] === 1); } // Checks if it's possible to eval JS expressions. function isEvalSupported() { try { new Function(''); // eslint-disable-line no-new, no-new-func return true; } catch (e) { return false; } } /** * Get the value of an inheritable property. * * If the PDF specification explicitly lists a property in a dictionary as * inheritable, then the value of the property may be present in the dictionary * itself or in one or more parents of the dictionary. * * If the key is not found in the tree, `undefined` is returned. Otherwise, * the value for the key is returned or, if `stopWhenFound` is `false`, a list * of values is returned. To avoid infinite loops, the traversal is stopped when * the loop limit is reached. * * @param {Dict} dict - Dictionary from where to start the traversal. * @param {string} key - The key of the property to find the value for. * @param {boolean} getArray - Whether or not the value should be fetched as an * array. The default value is `false`. * @param {boolean} stopWhenFound - Whether or not to stop the traversal when * the key is found. If set to `false`, we always walk up the entire parent * chain, for example to be able to find `\Resources` placed on multiple * levels of the tree. The default value is `true`. */ function getInheritableProperty({ dict, key, getArray = false, stopWhenFound = true, }) { const LOOP_LIMIT = 100; let loopCount = 0; let values; while (dict) { const value = getArray ? dict.getArray(key) : dict.get(key); if (value !== undefined) { if (stopWhenFound) { return value; } if (!values) { values = []; } values.push(value); } if (++loopCount > LOOP_LIMIT) { warn(`getInheritableProperty: maximum loop count exceeded for "${key}"`); break; } dict = dict.get('Parent'); } return values; } var Util = (function UtilClosure() { function Util() {} var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')']; // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids // creating many intermediate strings. Util.makeCssRgb = function Util_makeCssRgb(r, g, b) { rgbBuf[1] = r; rgbBuf[3] = g; rgbBuf[5] = b; return rgbBuf.join(''); }; // Concatenates two transformation matrices together and returns the result. Util.transform = function Util_transform(m1, m2) { return [ m1[0] * m2[0] + m1[2] * m2[1], m1[1] * m2[0] + m1[3] * m2[1], m1[0] * m2[2] + m1[2] * m2[3], m1[1] * m2[2] + m1[3] * m2[3], m1[0] * m2[4] + m1[2] * m2[5] + m1[4], m1[1] * m2[4] + m1[3] * m2[5] + m1[5] ]; }; // For 2d affine transforms Util.applyTransform = function Util_applyTransform(p, m) { var xt = p[0] * m[0] + p[1] * m[2] + m[4]; var yt = p[0] * m[1] + p[1] * m[3] + m[5]; return [xt, yt]; }; Util.applyInverseTransform = function Util_applyInverseTransform(p, m) { var d = m[0] * m[3] - m[1] * m[2]; var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d; var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d; return [xt, yt]; }; // Applies the transform to the rectangle and finds the minimum axially // aligned bounding box. Util.getAxialAlignedBoundingBox = function Util_getAxialAlignedBoundingBox(r, m) { var p1 = Util.applyTransform(r, m); var p2 = Util.applyTransform(r.slice(2, 4), m); var p3 = Util.applyTransform([r[0], r[3]], m); var p4 = Util.applyTransform([r[2], r[1]], m); return [ Math.min(p1[0], p2[0], p3[0], p4[0]), Math.min(p1[1], p2[1], p3[1], p4[1]), Math.max(p1[0], p2[0], p3[0], p4[0]), Math.max(p1[1], p2[1], p3[1], p4[1]) ]; }; Util.inverseTransform = function Util_inverseTransform(m) { var d = m[0] * m[3] - m[1] * m[2]; return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d, (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d]; }; // Apply a generic 3d matrix M on a 3-vector v: // | a b c | | X | // | d e f | x | Y | // | g h i | | Z | // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i], // with v as [X,Y,Z] Util.apply3dTransform = function Util_apply3dTransform(m, v) { return [ m[0] * v[0] + m[1] * v[1] + m[2] * v[2], m[3] * v[0] + m[4] * v[1] + m[5] * v[2], m[6] * v[0] + m[7] * v[1] + m[8] * v[2] ]; }; // This calculation uses Singular Value Decomposition. // The SVD can be represented with formula A = USV. We are interested in the // matrix S here because it represents the scale values. Util.singularValueDecompose2dScale = function Util_singularValueDecompose2dScale(m) { var transpose = [m[0], m[2], m[1], m[3]]; // Multiply matrix m with its transpose. var a = m[0] * transpose[0] + m[1] * transpose[2]; var b = m[0] * transpose[1] + m[1] * transpose[3]; var c = m[2] * transpose[0] + m[3] * transpose[2]; var d = m[2] * transpose[1] + m[3] * transpose[3]; // Solve the second degree polynomial to get roots. var first = (a + d) / 2; var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2; var sx = first + second || 1; var sy = first - second || 1; // Scale values are the square roots of the eigenvalues. return [Math.sqrt(sx), Math.sqrt(sy)]; }; // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2) // For coordinate systems whose origin lies in the bottom-left, this // means normalization to (BL,TR) ordering. For systems with origin in the // top-left, this means (TL,BR) ordering. Util.normalizeRect = function Util_normalizeRect(rect) { var r = rect.slice(0); // clone rect if (rect[0] > rect[2]) { r[0] = rect[2]; r[2] = rect[0]; } if (rect[1] > rect[3]) { r[1] = rect[3]; r[3] = rect[1]; } return r; }; // Returns a rectangle [x1, y1, x2, y2] corresponding to the // intersection of rect1 and rect2. If no intersection, returns 'false' // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2] Util.intersect = function Util_intersect(rect1, rect2) { function compare(a, b) { return a - b; } // Order points along the axes var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare), orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare), result = []; rect1 = Util.normalizeRect(rect1); rect2 = Util.normalizeRect(rect2); // X: first and second points belong to different rectangles? if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) || (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) { // Intersection must be between second and third points result[0] = orderedX[1]; result[2] = orderedX[2]; } else { return false; } // Y: first and second points belong to different rectangles? if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) || (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) { // Intersection must be between second and third points result[1] = orderedY[1]; result[3] = orderedY[2]; } else { return false; } return result; }; return Util; })(); const ROMAN_NUMBER_MAP = [ '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX' ]; /** * Converts positive integers to (upper case) Roman numerals. * @param {integer} number - The number that should be converted. * @param {boolean} lowerCase - Indicates if the result should be converted * to lower case letters. The default value is `false`. * @return {string} The resulting Roman number. */ function toRomanNumerals(number, lowerCase = false) { assert(Number.isInteger(number) && number > 0, 'The number should be a positive integer.'); let pos, romanBuf = []; // Thousands while (number >= 1000) { number -= 1000; romanBuf.push('M'); } // Hundreds pos = (number / 100) | 0; number %= 100; romanBuf.push(ROMAN_NUMBER_MAP[pos]); // Tens pos = (number / 10) | 0; number %= 10; romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]); // Ones romanBuf.push(ROMAN_NUMBER_MAP[20 + number]); const romanStr = romanBuf.join(''); return (lowerCase ? romanStr.toLowerCase() : romanStr); } const PDFStringTranslateTable = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160, 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC ]; function stringToPDFString(str) { var i, n = str.length, strBuf = []; if (str[0] === '\xFE' && str[1] === '\xFF') { // UTF16BE BOM for (i = 2; i < n; i += 2) { strBuf.push(String.fromCharCode( (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1))); } } else { for (i = 0; i < n; ++i) { var code = PDFStringTranslateTable[str.charCodeAt(i)]; strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); } } return strBuf.join(''); } function stringToUTF8String(str) { return decodeURIComponent(escape(str)); } function utf8StringToString(str) { return unescape(encodeURIComponent(str)); } function isEmptyObj(obj) { for (var key in obj) { return false; } return true; } function isBool(v) { return typeof v === 'boolean'; } function isNum(v) { return typeof v === 'number'; } function isString(v) { return typeof v === 'string'; } function isArrayBuffer(v) { return typeof v === 'object' && v !== null && v.byteLength !== undefined; } // Checks if ch is one of the following characters: SPACE, TAB, CR or LF. function isSpace(ch) { return (ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A); } /** * Promise Capability object. * * @typedef {Object} PromiseCapability * @property {Promise} promise - A promise object. * @property {function} resolve - Fulfills the promise. * @property {function} reject - Rejects the promise. */ /** * Creates a promise capability object. * @alias createPromiseCapability * * @return {PromiseCapability} A capability object contains: * - a Promise, resolve and reject methods. */ function createPromiseCapability() { var capability = {}; capability.promise = new Promise(function (resolve, reject) { capability.resolve = resolve; capability.reject = reject; }); return capability; } var createObjectURL = (function createObjectURLClosure() { // Blob/createObjectURL is not available, falling back to data schema. var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; return function createObjectURL(data, contentType, forceDataSchema = false) { if (!forceDataSchema && URL.createObjectURL) { const blob = new Blob([data], { type: contentType, }); return URL.createObjectURL(blob); } var buffer = 'data:' + contentType + ';base64,'; for (var i = 0, ii = data.length; i < ii; i += 3) { var b1 = data[i] & 0xFF; var b2 = data[i + 1] & 0xFF; var b3 = data[i + 2] & 0xFF; var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4); var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64; var d4 = i + 2 < ii ? (b3 & 0x3F) : 64; buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; } return buffer; }; })(); export { FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, OPS, VerbosityLevel, UNSUPPORTED_FEATURES, AnnotationBorderStyleType, AnnotationFieldFlag, AnnotationFlag, AnnotationType, FontType, ImageKind, CMapCompressionType, AbortException, InvalidPDFException, MissingDataException, MissingPDFException, NativeImageDecoding, PasswordException, PasswordResponses, PermissionFlag, StreamType, TextRenderingMode, UnexpectedResponseException, UnknownErrorException, Util, toRomanNumerals, XRefParseException, FormatError, arrayByteLength, arraysToBytes, assert, bytesToString, createPromiseCapability, createObjectURL, deprecated, getInheritableProperty, getLookupTableFactory, getVerbosityLevel, info, isArrayBuffer, isBool, isEmptyObj, isNum, isString, isSpace, isSameOrigin, createValidAbsoluteUrl, isLittleEndian, isEvalSupported, log2, readInt8, readUint16, readUint32, removeNullCharacters, ReadableStream, URL, setVerbosityLevel, shadow, string32, stringToBytes, stringToPDFString, stringToUTF8String, utf8StringToString, warn, unreachable, };