|
@@ -21,8 +21,8 @@ if (typeof PDFJS === 'undefined') {
|
|
typeof global !== 'undefined' ? global : this).PDFJS = {};
|
|
typeof global !== 'undefined' ? global : this).PDFJS = {};
|
|
}
|
|
}
|
|
|
|
|
|
-PDFJS.version = '1.3.148';
|
|
|
|
-PDFJS.build = '4e9ea35';
|
|
|
|
|
|
+PDFJS.version = '1.3.150';
|
|
|
|
+PDFJS.build = '62ade3e';
|
|
|
|
|
|
(function pdfjsWrapper() {
|
|
(function pdfjsWrapper() {
|
|
// Use strict in our context only - users might not want it
|
|
// Use strict in our context only - users might not want it
|
|
@@ -32414,6 +32414,9 @@ var HINTING_ENABLED = false;
|
|
// to control analysis of seac charstrings.
|
|
// to control analysis of seac charstrings.
|
|
var SEAC_ANALYSIS_ENABLED = false;
|
|
var SEAC_ANALYSIS_ENABLED = false;
|
|
|
|
|
|
|
|
+// Maximum subroutine call depth of type 2 chartrings. Matches OTS.
|
|
|
|
+var MAX_SUBR_NESTING = 10;
|
|
|
|
+
|
|
var FontFlags = {
|
|
var FontFlags = {
|
|
FixedPitch: 1,
|
|
FixedPitch: 1,
|
|
Serif: 2,
|
|
Serif: 2,
|
|
@@ -38443,10 +38446,7 @@ var CFFParser = (function CFFParserClosure() {
|
|
cff.isCIDFont = topDict.hasName('ROS');
|
|
cff.isCIDFont = topDict.hasName('ROS');
|
|
|
|
|
|
var charStringOffset = topDict.getByName('CharStrings');
|
|
var charStringOffset = topDict.getByName('CharStrings');
|
|
- var charStringsAndSeacs = this.parseCharStrings(charStringOffset);
|
|
|
|
- cff.charStrings = charStringsAndSeacs.charStrings;
|
|
|
|
- cff.seacs = charStringsAndSeacs.seacs;
|
|
|
|
- cff.widths = charStringsAndSeacs.widths;
|
|
|
|
|
|
+ var charStringIndex = this.parseIndex(charStringOffset).obj;
|
|
|
|
|
|
var fontMatrix = topDict.getByName('FontMatrix');
|
|
var fontMatrix = topDict.getByName('FontMatrix');
|
|
if (fontMatrix) {
|
|
if (fontMatrix) {
|
|
@@ -38474,19 +38474,30 @@ var CFFParser = (function CFFParserClosure() {
|
|
// cid fonts don't have an encoding
|
|
// cid fonts don't have an encoding
|
|
encoding = null;
|
|
encoding = null;
|
|
charset = this.parseCharsets(topDict.getByName('charset'),
|
|
charset = this.parseCharsets(topDict.getByName('charset'),
|
|
- cff.charStrings.count, cff.strings, true);
|
|
|
|
|
|
+ charStringIndex.count, cff.strings, true);
|
|
cff.fdSelect = this.parseFDSelect(topDict.getByName('FDSelect'),
|
|
cff.fdSelect = this.parseFDSelect(topDict.getByName('FDSelect'),
|
|
- cff.charStrings.count);
|
|
|
|
|
|
+ charStringIndex.count);
|
|
} else {
|
|
} else {
|
|
charset = this.parseCharsets(topDict.getByName('charset'),
|
|
charset = this.parseCharsets(topDict.getByName('charset'),
|
|
- cff.charStrings.count, cff.strings, false);
|
|
|
|
|
|
+ charStringIndex.count, cff.strings, false);
|
|
encoding = this.parseEncoding(topDict.getByName('Encoding'),
|
|
encoding = this.parseEncoding(topDict.getByName('Encoding'),
|
|
properties,
|
|
properties,
|
|
cff.strings, charset.charset);
|
|
cff.strings, charset.charset);
|
|
}
|
|
}
|
|
|
|
+
|
|
cff.charset = charset;
|
|
cff.charset = charset;
|
|
cff.encoding = encoding;
|
|
cff.encoding = encoding;
|
|
|
|
|
|
|
|
+ var charStringsAndSeacs = this.parseCharStrings(
|
|
|
|
+ charStringIndex,
|
|
|
|
+ topDict.privateDict.subrsIndex,
|
|
|
|
+ globalSubrIndex.obj,
|
|
|
|
+ cff.fdSelect,
|
|
|
|
+ cff.fdArray);
|
|
|
|
+ cff.charStrings = charStringsAndSeacs.charStrings;
|
|
|
|
+ cff.seacs = charStringsAndSeacs.seacs;
|
|
|
|
+ cff.widths = charStringsAndSeacs.widths;
|
|
|
|
+
|
|
return cff;
|
|
return cff;
|
|
},
|
|
},
|
|
parseHeader: function CFFParser_parseHeader() {
|
|
parseHeader: function CFFParser_parseHeader() {
|
|
@@ -38661,118 +38672,201 @@ var CFFParser = (function CFFParserClosure() {
|
|
}
|
|
}
|
|
return cffDict;
|
|
return cffDict;
|
|
},
|
|
},
|
|
- parseCharStrings: function CFFParser_parseCharStrings(charStringOffset) {
|
|
|
|
- var charStrings = this.parseIndex(charStringOffset).obj;
|
|
|
|
- var seacs = [];
|
|
|
|
- var widths = [];
|
|
|
|
- var count = charStrings.count;
|
|
|
|
- for (var i = 0; i < count; i++) {
|
|
|
|
- var charstring = charStrings.get(i);
|
|
|
|
-
|
|
|
|
- var stackSize = 0;
|
|
|
|
- var stack = [];
|
|
|
|
- var undefStack = true;
|
|
|
|
- var hints = 0;
|
|
|
|
- var valid = true;
|
|
|
|
- var data = charstring;
|
|
|
|
- var length = data.length;
|
|
|
|
- var firstStackClearing = true;
|
|
|
|
- for (var j = 0; j < length;) {
|
|
|
|
- var value = data[j++];
|
|
|
|
- var validationCommand = null;
|
|
|
|
- if (value === 12) {
|
|
|
|
- var q = data[j++];
|
|
|
|
- if (q === 0) {
|
|
|
|
- // The CFF specification state that the 'dotsection' command
|
|
|
|
- // (12, 0) is deprecated and treated as a no-op, but all Type2
|
|
|
|
- // charstrings processors should support them. Unfortunately
|
|
|
|
- // the font sanitizer don't. As a workaround the sequence (12, 0)
|
|
|
|
- // is replaced by a useless (0, hmoveto).
|
|
|
|
- data[j - 2] = 139;
|
|
|
|
- data[j - 1] = 22;
|
|
|
|
- stackSize = 0;
|
|
|
|
- } else {
|
|
|
|
- validationCommand = CharstringValidationData12[q];
|
|
|
|
- }
|
|
|
|
- } else if (value === 28) { // number (16 bit)
|
|
|
|
- stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16)) >> 16;
|
|
|
|
- j += 2;
|
|
|
|
- stackSize++;
|
|
|
|
- } else if (value === 14) {
|
|
|
|
- if (stackSize >= 4) {
|
|
|
|
- stackSize -= 4;
|
|
|
|
- if (SEAC_ANALYSIS_ENABLED) {
|
|
|
|
- seacs[i] = stack.slice(stackSize, stackSize + 4);
|
|
|
|
- valid = false;
|
|
|
|
- }
|
|
|
|
|
|
+ parseCharString: function CFFParser_parseCharString(state, data,
|
|
|
|
+ localSubrIndex,
|
|
|
|
+ globalSubrIndex) {
|
|
|
|
+ if (state.callDepth > MAX_SUBR_NESTING) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ var stackSize = state.stackSize;
|
|
|
|
+ var stack = state.stack;
|
|
|
|
+
|
|
|
|
+ var length = data.length;
|
|
|
|
+
|
|
|
|
+ for (var j = 0; j < length;) {
|
|
|
|
+ var value = data[j++];
|
|
|
|
+ var validationCommand = null;
|
|
|
|
+ if (value === 12) {
|
|
|
|
+ var q = data[j++];
|
|
|
|
+ if (q === 0) {
|
|
|
|
+ // The CFF specification state that the 'dotsection' command
|
|
|
|
+ // (12, 0) is deprecated and treated as a no-op, but all Type2
|
|
|
|
+ // charstrings processors should support them. Unfortunately
|
|
|
|
+ // the font sanitizer don't. As a workaround the sequence (12, 0)
|
|
|
|
+ // is replaced by a useless (0, hmoveto).
|
|
|
|
+ data[j - 2] = 139;
|
|
|
|
+ data[j - 1] = 22;
|
|
|
|
+ stackSize = 0;
|
|
|
|
+ } else {
|
|
|
|
+ validationCommand = CharstringValidationData12[q];
|
|
|
|
+ }
|
|
|
|
+ } else if (value === 28) { // number (16 bit)
|
|
|
|
+ stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16)) >> 16;
|
|
|
|
+ j += 2;
|
|
|
|
+ stackSize++;
|
|
|
|
+ } else if (value === 14) {
|
|
|
|
+ if (stackSize >= 4) {
|
|
|
|
+ stackSize -= 4;
|
|
|
|
+ if (SEAC_ANALYSIS_ENABLED) {
|
|
|
|
+ state.seac = stack.slice(stackSize, stackSize + 4);
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
- validationCommand = CharstringValidationData[value];
|
|
|
|
- } else if (value >= 32 && value <= 246) { // number
|
|
|
|
- stack[stackSize] = value - 139;
|
|
|
|
- stackSize++;
|
|
|
|
- } else if (value >= 247 && value <= 254) { // number (+1 bytes)
|
|
|
|
- stack[stackSize] = (value < 251 ?
|
|
|
|
- ((value - 247) << 8) + data[j] + 108 :
|
|
|
|
- -((value - 251) << 8) - data[j] - 108);
|
|
|
|
- j++;
|
|
|
|
- stackSize++;
|
|
|
|
- } else if (value === 255) { // number (32 bit)
|
|
|
|
- stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16) |
|
|
|
|
- (data[j + 2] << 8) | data[j + 3]) / 65536;
|
|
|
|
- j += 4;
|
|
|
|
- stackSize++;
|
|
|
|
- } else if (value === 19 || value === 20) {
|
|
|
|
- hints += stackSize >> 1;
|
|
|
|
- j += (hints + 7) >> 3; // skipping right amount of hints flag data
|
|
|
|
- stackSize %= 2;
|
|
|
|
- validationCommand = CharstringValidationData[value];
|
|
|
|
|
|
+ }
|
|
|
|
+ validationCommand = CharstringValidationData[value];
|
|
|
|
+ } else if (value >= 32 && value <= 246) { // number
|
|
|
|
+ stack[stackSize] = value - 139;
|
|
|
|
+ stackSize++;
|
|
|
|
+ } else if (value >= 247 && value <= 254) { // number (+1 bytes)
|
|
|
|
+ stack[stackSize] = (value < 251 ?
|
|
|
|
+ ((value - 247) << 8) + data[j] + 108 :
|
|
|
|
+ -((value - 251) << 8) - data[j] - 108);
|
|
|
|
+ j++;
|
|
|
|
+ stackSize++;
|
|
|
|
+ } else if (value === 255) { // number (32 bit)
|
|
|
|
+ stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16) |
|
|
|
|
+ (data[j + 2] << 8) | data[j + 3]) / 65536;
|
|
|
|
+ j += 4;
|
|
|
|
+ stackSize++;
|
|
|
|
+ } else if (value === 19 || value === 20) {
|
|
|
|
+ state.hints += stackSize >> 1;
|
|
|
|
+ // skipping right amount of hints flag data
|
|
|
|
+ j += (state.hints + 7) >> 3;
|
|
|
|
+ stackSize %= 2;
|
|
|
|
+ validationCommand = CharstringValidationData[value];
|
|
|
|
+ } else if (value === 10 || value === 29) {
|
|
|
|
+ var subrsIndex;
|
|
|
|
+ if (value === 10) {
|
|
|
|
+ subrsIndex = localSubrIndex;
|
|
} else {
|
|
} else {
|
|
|
|
+ subrsIndex = globalSubrIndex;
|
|
|
|
+ }
|
|
|
|
+ if (!subrsIndex) {
|
|
validationCommand = CharstringValidationData[value];
|
|
validationCommand = CharstringValidationData[value];
|
|
|
|
+ warn('Missing subrsIndex for ' + validationCommand.id);
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
- if (validationCommand) {
|
|
|
|
- if (validationCommand.stem) {
|
|
|
|
- hints += stackSize >> 1;
|
|
|
|
|
|
+ var bias = 32768;
|
|
|
|
+ if (subrsIndex.count < 1240) {
|
|
|
|
+ bias = 107;
|
|
|
|
+ } else if (subrsIndex.count < 33900) {
|
|
|
|
+ bias = 1131;
|
|
|
|
+ }
|
|
|
|
+ var subrNumber = stack[--stackSize] + bias;
|
|
|
|
+ if (subrNumber < 0 || subrNumber >= subrsIndex.count) {
|
|
|
|
+ validationCommand = CharstringValidationData[value];
|
|
|
|
+ warn('Out of bounds subrIndex for ' + validationCommand.id);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ state.stackSize = stackSize;
|
|
|
|
+ state.callDepth++;
|
|
|
|
+ var valid = this.parseCharString(state, subrsIndex.get(subrNumber),
|
|
|
|
+ localSubrIndex, globalSubrIndex);
|
|
|
|
+ if (!valid) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ state.callDepth--;
|
|
|
|
+ stackSize = state.stackSize;
|
|
|
|
+ continue;
|
|
|
|
+ } else if (value === 11) {
|
|
|
|
+ state.stackSize = stackSize;
|
|
|
|
+ return true;
|
|
|
|
+ } else {
|
|
|
|
+ validationCommand = CharstringValidationData[value];
|
|
|
|
+ }
|
|
|
|
+ if (validationCommand) {
|
|
|
|
+ if (validationCommand.stem) {
|
|
|
|
+ state.hints += stackSize >> 1;
|
|
|
|
+ }
|
|
|
|
+ if ('min' in validationCommand) {
|
|
|
|
+ if (!state.undefStack && stackSize < validationCommand.min) {
|
|
|
|
+ warn('Not enough parameters for ' + validationCommand.id +
|
|
|
|
+ '; actual: ' + stackSize +
|
|
|
|
+ ', expected: ' + validationCommand.min);
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
- if ('min' in validationCommand) {
|
|
|
|
- if (!undefStack && stackSize < validationCommand.min) {
|
|
|
|
- warn('Not enough parameters for ' + validationCommand.id +
|
|
|
|
- '; actual: ' + stackSize +
|
|
|
|
- ', expected: ' + validationCommand.min);
|
|
|
|
- valid = false;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
+ if (state.firstStackClearing && validationCommand.stackClearing) {
|
|
|
|
+ state.firstStackClearing = false;
|
|
|
|
+ // the optional character width can be found before the first
|
|
|
|
+ // stack-clearing command arguments
|
|
|
|
+ stackSize -= validationCommand.min;
|
|
|
|
+ if (stackSize >= 2 && validationCommand.stem) {
|
|
|
|
+ // there are even amount of arguments for stem commands
|
|
|
|
+ stackSize %= 2;
|
|
|
|
+ } else if (stackSize > 1) {
|
|
|
|
+ warn('Found too many parameters for stack-clearing command');
|
|
}
|
|
}
|
|
- if (firstStackClearing && validationCommand.stackClearing) {
|
|
|
|
- firstStackClearing = false;
|
|
|
|
- // the optional character width can be found before the first
|
|
|
|
- // stack-clearing command arguments
|
|
|
|
- stackSize -= validationCommand.min;
|
|
|
|
- if (stackSize >= 2 && validationCommand.stem) {
|
|
|
|
- // there are even amount of arguments for stem commands
|
|
|
|
- stackSize %= 2;
|
|
|
|
- } else if (stackSize > 1) {
|
|
|
|
- warn('Found too many parameters for stack-clearing command');
|
|
|
|
- }
|
|
|
|
- if (stackSize > 0 && stack[stackSize - 1] >= 0) {
|
|
|
|
- widths[i] = stack[stackSize - 1];
|
|
|
|
- }
|
|
|
|
|
|
+ if (stackSize > 0 && stack[stackSize - 1] >= 0) {
|
|
|
|
+ state.width = stack[stackSize - 1];
|
|
}
|
|
}
|
|
- if ('stackDelta' in validationCommand) {
|
|
|
|
- if ('stackFn' in validationCommand) {
|
|
|
|
- validationCommand.stackFn(stack, stackSize);
|
|
|
|
- }
|
|
|
|
- stackSize += validationCommand.stackDelta;
|
|
|
|
- } else if (validationCommand.stackClearing) {
|
|
|
|
- stackSize = 0;
|
|
|
|
- } else if (validationCommand.resetStack) {
|
|
|
|
- stackSize = 0;
|
|
|
|
- undefStack = false;
|
|
|
|
- } else if (validationCommand.undefStack) {
|
|
|
|
- stackSize = 0;
|
|
|
|
- undefStack = true;
|
|
|
|
- firstStackClearing = false;
|
|
|
|
|
|
+ }
|
|
|
|
+ if ('stackDelta' in validationCommand) {
|
|
|
|
+ if ('stackFn' in validationCommand) {
|
|
|
|
+ validationCommand.stackFn(stack, stackSize);
|
|
}
|
|
}
|
|
|
|
+ stackSize += validationCommand.stackDelta;
|
|
|
|
+ } else if (validationCommand.stackClearing) {
|
|
|
|
+ stackSize = 0;
|
|
|
|
+ } else if (validationCommand.resetStack) {
|
|
|
|
+ stackSize = 0;
|
|
|
|
+ state.undefStack = false;
|
|
|
|
+ } else if (validationCommand.undefStack) {
|
|
|
|
+ stackSize = 0;
|
|
|
|
+ state.undefStack = true;
|
|
|
|
+ state.firstStackClearing = false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ state.stackSize = stackSize;
|
|
|
|
+ return true;
|
|
|
|
+ },
|
|
|
|
+ parseCharStrings: function CFFParser_parseCharStrings(charStrings,
|
|
|
|
+ localSubrIndex,
|
|
|
|
+ globalSubrIndex,
|
|
|
|
+ fdSelect,
|
|
|
|
+ fdArray) {
|
|
|
|
+ var seacs = [];
|
|
|
|
+ var widths = [];
|
|
|
|
+ var count = charStrings.count;
|
|
|
|
+ for (var i = 0; i < count; i++) {
|
|
|
|
+ var charstring = charStrings.get(i);
|
|
|
|
+ var state = {
|
|
|
|
+ callDepth: 0,
|
|
|
|
+ stackSize: 0,
|
|
|
|
+ stack: [],
|
|
|
|
+ undefStack: true,
|
|
|
|
+ hints: 0,
|
|
|
|
+ firstStackClearing: true,
|
|
|
|
+ seac: null,
|
|
|
|
+ width: null
|
|
|
|
+ };
|
|
|
|
+ var valid = true;
|
|
|
|
+ var localSubrToUse = null;
|
|
|
|
+ if (fdSelect && fdArray.length) {
|
|
|
|
+ var fdIndex = fdSelect.getFDIndex(i);
|
|
|
|
+ if (fdIndex === -1) {
|
|
|
|
+ warn('Glyph index is not in fd select.');
|
|
|
|
+ valid = false;
|
|
}
|
|
}
|
|
|
|
+ if (fdIndex >= fdArray.length) {
|
|
|
|
+ warn('Invalid fd index for glyph index.');
|
|
|
|
+ valid = false;
|
|
|
|
+ }
|
|
|
|
+ if (valid) {
|
|
|
|
+ localSubrToUse = fdArray[fdIndex].privateDict.subrsIndex;
|
|
|
|
+ }
|
|
|
|
+ } else if (localSubrIndex) {
|
|
|
|
+ localSubrToUse = localSubrIndex;
|
|
|
|
+ }
|
|
|
|
+ if (valid) {
|
|
|
|
+ valid = this.parseCharString(state, charstring, localSubrToUse,
|
|
|
|
+ globalSubrIndex);
|
|
|
|
+ }
|
|
|
|
+ if (state.width !== null) {
|
|
|
|
+ widths[i] = state.width;
|
|
|
|
+ }
|
|
|
|
+ if (state.seac !== null) {
|
|
|
|
+ seacs[i] = state.seac;
|
|
}
|
|
}
|
|
if (!valid) {
|
|
if (!valid) {
|
|
// resetting invalid charstring to single 'endchar'
|
|
// resetting invalid charstring to single 'endchar'
|
|
@@ -39267,6 +39361,14 @@ var CFFFDSelect = (function CFFFDSelectClosure() {
|
|
this.fdSelect = fdSelect;
|
|
this.fdSelect = fdSelect;
|
|
this.raw = raw;
|
|
this.raw = raw;
|
|
}
|
|
}
|
|
|
|
+ CFFFDSelect.prototype = {
|
|
|
|
+ getFDIndex: function CFFFDSelect_get(glyphIndex) {
|
|
|
|
+ if (glyphIndex < 0 || glyphIndex >= this.fdSelect.length) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ return this.fdSelect[glyphIndex];
|
|
|
|
+ }
|
|
|
|
+ };
|
|
return CFFFDSelect;
|
|
return CFFFDSelect;
|
|
})();
|
|
})();
|
|
|
|
|