Merge pull request #11680 from Snuffleupagus/hasBlendModes-fetch-errors
Prevent lookup errors in `PartialEvaluator.hasBlendModes` from breaking all parsing/rendering of a page (issue 11678)
This commit is contained in:
		
						commit
						af8d0b9597
					
				| @ -61,6 +61,7 @@ import { | |||||||
|   WinAnsiEncoding, |   WinAnsiEncoding, | ||||||
|   ZapfDingbatsEncoding, |   ZapfDingbatsEncoding, | ||||||
| } from "./encodings.js"; | } from "./encodings.js"; | ||||||
|  | import { getLookupTableFactory, MissingDataException } from "./core_utils.js"; | ||||||
| import { | import { | ||||||
|   getNormalizedUnicodes, |   getNormalizedUnicodes, | ||||||
|   getUnicodeForGlyph, |   getUnicodeForGlyph, | ||||||
| @ -77,7 +78,6 @@ import { bidi } from "./bidi.js"; | |||||||
| import { ColorSpace } from "./colorspace.js"; | import { ColorSpace } from "./colorspace.js"; | ||||||
| import { DecodeStream } from "./stream.js"; | import { DecodeStream } from "./stream.js"; | ||||||
| import { getGlyphsUnicode } from "./glyphlist.js"; | import { getGlyphsUnicode } from "./glyphlist.js"; | ||||||
| import { getLookupTableFactory } from "./core_utils.js"; |  | ||||||
| import { getMetrics } from "./metrics.js"; | import { getMetrics } from "./metrics.js"; | ||||||
| import { isPDFFunction } from "./function.js"; | import { isPDFFunction } from "./function.js"; | ||||||
| import { JpegStream } from "./jpeg_stream.js"; | import { JpegStream } from "./jpeg_stream.js"; | ||||||
| @ -266,7 +266,27 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { | |||||||
|               if (processed[graphicState.toString()]) { |               if (processed[graphicState.toString()]) { | ||||||
|                 continue; // The ExtGState has already been processed.
 |                 continue; // The ExtGState has already been processed.
 | ||||||
|               } |               } | ||||||
|  |               try { | ||||||
|                 graphicState = xref.fetch(graphicState); |                 graphicState = xref.fetch(graphicState); | ||||||
|  |               } catch (ex) { | ||||||
|  |                 if (ex instanceof MissingDataException) { | ||||||
|  |                   throw ex; | ||||||
|  |                 } | ||||||
|  |                 if (this.options.ignoreErrors) { | ||||||
|  |                   if (graphicState instanceof Ref) { | ||||||
|  |                     // Avoid parsing a corrupt ExtGState more than once.
 | ||||||
|  |                     processed[graphicState.toString()] = true; | ||||||
|  |                   } | ||||||
|  |                   // Error(s) in the ExtGState -- sending unsupported feature
 | ||||||
|  |                   // notification and allow parsing/rendering to continue.
 | ||||||
|  |                   this.handler.send("UnsupportedFeature", { | ||||||
|  |                     featureId: UNSUPPORTED_FEATURES.unknown, | ||||||
|  |                   }); | ||||||
|  |                   warn(`hasBlendModes - ignoring ExtGState: "${ex}".`); | ||||||
|  |                   continue; | ||||||
|  |                 } | ||||||
|  |                 throw ex; | ||||||
|  |               } | ||||||
|             } |             } | ||||||
|             if (!(graphicState instanceof Dict)) { |             if (!(graphicState instanceof Dict)) { | ||||||
|               continue; |               continue; | ||||||
| @ -308,7 +328,27 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { | |||||||
|               // time for badly generated PDF files (fixes issue6961.pdf).
 |               // time for badly generated PDF files (fixes issue6961.pdf).
 | ||||||
|               continue; |               continue; | ||||||
|             } |             } | ||||||
|  |             try { | ||||||
|               xObject = xref.fetch(xObject); |               xObject = xref.fetch(xObject); | ||||||
|  |             } catch (ex) { | ||||||
|  |               if (ex instanceof MissingDataException) { | ||||||
|  |                 throw ex; | ||||||
|  |               } | ||||||
|  |               if (this.options.ignoreErrors) { | ||||||
|  |                 if (xObject instanceof Ref) { | ||||||
|  |                   // Avoid parsing a corrupt XObject more than once.
 | ||||||
|  |                   processed[xObject.toString()] = true; | ||||||
|  |                 } | ||||||
|  |                 // Error(s) in the XObject -- sending unsupported feature
 | ||||||
|  |                 // notification and allow parsing/rendering to continue.
 | ||||||
|  |                 this.handler.send("UnsupportedFeature", { | ||||||
|  |                   featureId: UNSUPPORTED_FEATURES.unknown, | ||||||
|  |                 }); | ||||||
|  |                 warn(`hasBlendModes - ignoring XObject: "${ex}".`); | ||||||
|  |                 continue; | ||||||
|  |               } | ||||||
|  |               throw ex; | ||||||
|  |             } | ||||||
|           } |           } | ||||||
|           if (!isStream(xObject)) { |           if (!isStream(xObject)) { | ||||||
|             continue; |             continue; | ||||||
|  | |||||||
| @ -842,6 +842,7 @@ class Lexer { | |||||||
|     // other commands or literals as a prefix. The knowCommands is optional.
 |     // other commands or literals as a prefix. The knowCommands is optional.
 | ||||||
|     this.knownCommands = knownCommands; |     this.knownCommands = knownCommands; | ||||||
| 
 | 
 | ||||||
|  |     this._hexStringNumWarn = 0; | ||||||
|     this.beginInlineImagePos = -1; |     this.beginInlineImagePos = -1; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -1099,12 +1100,32 @@ class Lexer { | |||||||
|     return Name.get(strBuf.join("")); |     return Name.get(strBuf.join("")); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   /** | ||||||
|  |    * @private | ||||||
|  |    */ | ||||||
|  |   _hexStringWarn(ch) { | ||||||
|  |     const MAX_HEX_STRING_NUM_WARN = 5; | ||||||
|  | 
 | ||||||
|  |     if (this._hexStringNumWarn++ === MAX_HEX_STRING_NUM_WARN) { | ||||||
|  |       warn("getHexString - ignoring additional invalid characters."); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if (this._hexStringNumWarn > MAX_HEX_STRING_NUM_WARN) { | ||||||
|  |       // Limit the number of warning messages printed for a `this.getHexString`
 | ||||||
|  |       // invocation, since corrupt PDF documents may otherwise spam the console
 | ||||||
|  |       // enough to affect general performance negatively.
 | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     warn(`getHexString - ignoring invalid character: ${ch}`); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   getHexString() { |   getHexString() { | ||||||
|     const strBuf = this.strBuf; |     const strBuf = this.strBuf; | ||||||
|     strBuf.length = 0; |     strBuf.length = 0; | ||||||
|     let ch = this.currentChar; |     let ch = this.currentChar; | ||||||
|     let isFirstHex = true; |     let isFirstHex = true; | ||||||
|     let firstDigit, secondDigit; |     let firstDigit, secondDigit; | ||||||
|  |     this._hexStringNumWarn = 0; | ||||||
| 
 | 
 | ||||||
|     while (true) { |     while (true) { | ||||||
|       if (ch < 0) { |       if (ch < 0) { | ||||||
| @ -1120,14 +1141,14 @@ class Lexer { | |||||||
|         if (isFirstHex) { |         if (isFirstHex) { | ||||||
|           firstDigit = toHexDigit(ch); |           firstDigit = toHexDigit(ch); | ||||||
|           if (firstDigit === -1) { |           if (firstDigit === -1) { | ||||||
|             warn(`Ignoring invalid character "${ch}" in hex string`); |             this._hexStringWarn(ch); | ||||||
|             ch = this.nextChar(); |             ch = this.nextChar(); | ||||||
|             continue; |             continue; | ||||||
|           } |           } | ||||||
|         } else { |         } else { | ||||||
|           secondDigit = toHexDigit(ch); |           secondDigit = toHexDigit(ch); | ||||||
|           if (secondDigit === -1) { |           if (secondDigit === -1) { | ||||||
|             warn(`Ignoring invalid character "${ch}" in hex string`); |             this._hexStringWarn(ch); | ||||||
|             ch = this.nextChar(); |             ch = this.nextChar(); | ||||||
|             continue; |             continue; | ||||||
|           } |           } | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								test/pdfs/issue11678.pdf.link
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/pdfs/issue11678.pdf.link
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | https://github.com/mozilla/pdf.js/files/4304559/default.pdf | ||||||
| @ -3064,6 +3064,15 @@ | |||||||
|        "link": false, |        "link": false, | ||||||
|        "type": "eq" |        "type": "eq" | ||||||
|     }, |     }, | ||||||
|  |     {  "id": "issue11678", | ||||||
|  |        "file": "pdfs/issue11678.pdf", | ||||||
|  |        "md5": "e2efadeb91932f4c21e4fc682cce7de9", | ||||||
|  |        "rounds": 1, | ||||||
|  |        "link": true, | ||||||
|  |        "firstPage": 2, | ||||||
|  |        "lastPage": 2, | ||||||
|  |        "type": "eq" | ||||||
|  |     }, | ||||||
|     {  "id": "issue4890", |     {  "id": "issue4890", | ||||||
|        "file": "pdfs/issue4890.pdf", |        "file": "pdfs/issue4890.pdf", | ||||||
|        "md5": "1666feb4cd26318c2bdbea6a175dce87", |        "md5": "1666feb4cd26318c2bdbea6a175dce87", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user