1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-22 16:18:08 +02:00

Skip commands that have too few arguments

- Commands that have too few args will be skipped
- Commands that have too many args will generate an info, but still
execute
This commit is contained in:
mduan 2013-01-10 18:00:44 -08:00
parent 4fa82683fa
commit 5ab3bb1e03
5 changed files with 297 additions and 91 deletions

View file

@ -30,101 +30,104 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
this.fontIdCounter = 0;
}
// Specifies properties for each command
//
// If variableArgs === true: [0, `numArgs`] expected
// If variableArgs === false: exactly `numArgs` expected
var OP_MAP = {
// Graphics state
w: 'setLineWidth',
J: 'setLineCap',
j: 'setLineJoin',
M: 'setMiterLimit',
d: 'setDash',
ri: 'setRenderingIntent',
i: 'setFlatness',
gs: 'setGState',
q: 'save',
Q: 'restore',
cm: 'transform',
// Graphic state
w: { fnName: 'setLineWidth', numArgs: 1, variableArgs: false },
J: { fnName: 'setLineCap', numArgs: 1, variableArgs: false },
j: { fnName: 'setLineJoin', numArgs: 1, variableArgs: false },
M: { fnName: 'setMiterLimit', numArgs: 1, variableArgs: false },
d: { fnName: 'setDash', numArgs: 2, variableArgs: false },
ri: { fnName: 'setRenderingIntent', numArgs: 1, variableArgs: false },
i: { fnName: 'setFlatness', numArgs: 1, variableArgs: false },
gs: { fnName: 'setGState', numArgs: 1, variableArgs: false },
q: { fnName: 'save', numArgs: 0, variableArgs: false },
Q: { fnName: 'restore', numArgs: 0, variableArgs: false },
cm: { fnName: 'transform', numArgs: 6, variableArgs: false },
// Path
m: 'moveTo',
l: 'lineTo',
c: 'curveTo',
v: 'curveTo2',
y: 'curveTo3',
h: 'closePath',
re: 'rectangle',
S: 'stroke',
s: 'closeStroke',
f: 'fill',
F: 'fill',
'f*': 'eoFill',
B: 'fillStroke',
'B*': 'eoFillStroke',
b: 'closeFillStroke',
'b*': 'closeEOFillStroke',
n: 'endPath',
m: { fnName: 'moveTo', numArgs: 2, variableArgs: false },
l: { fnName: 'lineTo', numArgs: 2, variableArgs: false },
c: { fnName: 'curveTo', numArgs: 6, variableArgs: false },
v: { fnName: 'curveTo2', numArgs: 4, variableArgs: false },
y: { fnName: 'curveTo3', numArgs: 4, variableArgs: false },
h: { fnName: 'closePath', numArgs: 0, variableArgs: false },
re: { fnName: 'rectangle', numArgs: 4, variableArgs: false },
S: { fnName: 'stroke', numArgs: 0, variableArgs: false },
s: { fnName: 'closeStroke', numArgs: 0, variableArgs: false },
f: { fnName: 'fill', numArgs: 0, variableArgs: false },
F: { fnName: 'fill', numArgs: 0, variableArgs: false },
'f*': { fnName: 'eoFill', numArgs: 0, variableArgs: false },
B: { fnName: 'fillStroke', numArgs: 0, variableArgs: false },
'B*': { fnName: 'eoFillStroke', numArgs: 0, variableArgs: false },
b: { fnName: 'closeFillStroke', numArgs: 0, variableArgs: false },
'b*': { fnName: 'closeEOFillStroke', numArgs: 0, variableArgs: false },
n: { fnName: 'endPath', numArgs: 0, variableArgs: false },
// Clipping
W: 'clip',
'W*': 'eoClip',
W: { fnName: 'clip', numArgs: 0, variableArgs: false },
'W*': { fnName: 'eoClip', numArgs: 0, variableArgs: false },
// Text
BT: 'beginText',
ET: 'endText',
Tc: 'setCharSpacing',
Tw: 'setWordSpacing',
Tz: 'setHScale',
TL: 'setLeading',
Tf: 'setFont',
Tr: 'setTextRenderingMode',
Ts: 'setTextRise',
Td: 'moveText',
TD: 'setLeadingMoveText',
Tm: 'setTextMatrix',
'T*': 'nextLine',
Tj: 'showText',
TJ: 'showSpacedText',
"'": 'nextLineShowText',
'"': 'nextLineSetSpacingShowText',
BT: { fnName: 'beginText', numArgs: 0, variableArgs: false },
ET: { fnName: 'endText', numArgs: 0, variableArgs: false },
Tc: { fnName: 'setCharSpacing', numArgs: 1, variableArgs: false },
Tw: { fnName: 'setWordSpacing', numArgs: 1, variableArgs: false },
Tz: { fnName: 'setHScale', numArgs: 1, variableArgs: false },
TL: { fnName: 'setLeading', numArgs: 1, variableArgs: false },
Tf: { fnName: 'setFont', numArgs: 2, variableArgs: false },
Tr: { fnName: 'setTextRenderingMode', numArgs: 1, variableArgs: false },
Ts: { fnName: 'setTextRise', numArgs: 1, variableArgs: false },
Td: { fnName: 'moveText', numArgs: 2, variableArgs: false },
TD: { fnName: 'setLeadingMoveText', numArgs: 2, variableArgs: false },
Tm: { fnName: 'setTextMatrix', numArgs: 6, variableArgs: false },
'T*': { fnName: 'nextLine', numArgs: 0, variableArgs: false },
Tj: { fnName: 'showText', numArgs: 1, variableArgs: false },
TJ: { fnName: 'showSpacedText', numArgs: 1, variableArgs: false },
'\'': { fnName: 'nextLineShowText', numArgs: 1, variableArgs: false },
'"': { fnName: 'nextLineSetSpacingShowText', numArgs: 3,
variableArgs: false },
// Type3 fonts
d0: 'setCharWidth',
d1: 'setCharWidthAndBounds',
d0: { fnName: 'setCharWidth', numArgs: 2, variableArgs: false },
d1: { fnName: 'setCharWidthAndBounds', numArgs: 6, variableArgs: false },
// Color
CS: 'setStrokeColorSpace',
cs: 'setFillColorSpace',
SC: 'setStrokeColor',
SCN: 'setStrokeColorN',
sc: 'setFillColor',
scn: 'setFillColorN',
G: 'setStrokeGray',
g: 'setFillGray',
RG: 'setStrokeRGBColor',
rg: 'setFillRGBColor',
K: 'setStrokeCMYKColor',
k: 'setFillCMYKColor',
CS: { fnName: 'setStrokeColorSpace', numArgs: 1, variableArgs: false },
cs: { fnName: 'setFillColorSpace', numArgs: 1, variableArgs: false },
SC: { fnName: 'setStrokeColor', numArgs: 4, variableArgs: true },
SCN: { fnName: 'setStrokeColorN', numArgs: 33, variableArgs: true },
sc: { fnName: 'setFillColor', numArgs: 4, variableArgs: true },
scn: { fnName: 'setFillColorN', numArgs: 33, variableArgs: true },
G: { fnName: 'setStrokeGray', numArgs: 1, variableArgs: false },
g: { fnName: 'setFillGray', numArgs: 1, variableArgs: false },
RG: { fnName: 'setStrokeRGBColor', numArgs: 3, variableArgs: false },
rg: { fnName: 'setFillRGBColor', numArgs: 3, variableArgs: false },
K: { fnName: 'setStrokeCMYKColor', numArgs: 4, variableArgs: false },
k: { fnName: 'setFillCMYKColor', numArgs: 4, variableArgs: false },
// Shading
sh: 'shadingFill',
sh: { fnName: 'shadingFill', numArgs: 1, variableArgs: false },
// Images
BI: 'beginInlineImage',
ID: 'beginImageData',
EI: 'endInlineImage',
BI: { fnName: 'beginInlineImage', numArgs: 0, variableArgs: false },
ID: { fnName: 'beginImageData', numArgs: 0, variableArgs: false },
EI: { fnName: 'endInlineImage', numArgs: 0, variableArgs: false },
// XObjects
Do: 'paintXObject',
// Marked content
MP: 'markPoint',
DP: 'markPointProps',
BMC: 'beginMarkedContent',
BDC: 'beginMarkedContentProps',
EMC: 'endMarkedContent',
Do: { fnName: 'paintXObject', numArgs: 1, variableArgs: false },
MP: { fnName: 'markPoint', numArgs: 1, variableArgs: false },
DP: { fnName: 'markPointProps', numArgs: 2, variableArgs: false },
BMC: { fnName: 'beginMarkedContent', numArgs: 1, variableArgs: false },
BDC: { fnName: 'beginMarkedContentProps', numArgs: 2, variableArgs: false },
EMC: { fnName: 'endMarkedContent', numArgs: 0, variableArgs: false },
// Compatibility
BX: 'beginCompat',
EX: 'endCompat',
BX: { fnName: 'beginCompat', numArgs: 0, variableArgs: false },
EX: { fnName: 'endCompat', numArgs: 0, variableArgs: false },
// (reserved partial commands for the lexer)
BM: null,
@ -314,6 +317,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
resources = resources || new Dict();
var xobjs = resources.get('XObject') || new Dict();
var patterns = resources.get('Pattern') || new Dict();
// TODO(mduan): pass array of knownCommands rather than OP_MAP
// dictionary
var parser = new Parser(new Lexer(stream, OP_MAP), false, xref);
var res = resources;
var args = [], obj;
@ -321,13 +326,42 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
while (true) {
obj = parser.getObj();
if (isEOF(obj))
if (isEOF(obj)) {
break;
}
if (isCmd(obj)) {
var cmd = obj.cmd;
var fn = OP_MAP[cmd];
assertWellFormed(fn, 'Unknown command "' + cmd + '"');
// Check that the command is valid
var opSpec = OP_MAP[cmd];
if (!opSpec) {
warn('Unknown command "' + cmd + '"');
continue;
}
var fn = opSpec.fnName;
// Validate the number of arguments for the command
if (opSpec.variableArgs) {
if (args.length > opSpec.numArgs) {
info('Command ' + fn + ': expected [0,' + opSpec.numArgs +
'] args, but received ' + args.length + ' args');
}
} else {
if (args.length < opSpec.numArgs) {
// If we receive too few args, it's not possible to possible
// to execute the command, so skip the command
info('Command ' + fn + ': because expected ' + opSpec.numArgs +
' args, but received ' + args.length + ' args; skipping');
args = [];
continue;
} else if (args.length > opSpec.numArgs) {
info('Command ' + fn + ': expected ' + opSpec.numArgs +
' args, but received ' + args.length + ' args');
}
}
// TODO figure out how to type-check vararg functions
if ((cmd == 'SCN' || cmd == 'scn') && !args[args.length - 1].code) {
@ -509,8 +543,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
argsArray.push(args);
args = [];
} else if (obj != null) {
assertWellFormed(args.length <= 33, 'Too many arguments');
args.push(obj instanceof Dict ? obj.getAll() : obj);
assertWellFormed(args.length <= 33, 'Too many arguments');
}
}