public void parse(InputStream stream, ContentHandler handler, Metadata metadata,
                      ParseContext context) throws IOException, SAXException, TikaException {

        PDFParserConfig localConfig = defaultConfig;
        PDFParserConfig userConfig = context.get(PDFParserConfig.class);
        if (userConfig != null) {
            localConfig = defaultConfig.cloneAndUpdate(userConfig);
        }
        if (localConfig.isSetKCMS()) {
            System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider");
        }
        IncrementalUpdateRecord incomingIncrementalUpdateRecord = context.get(IncrementalUpdateRecord.class);
        context.set(IncrementalUpdateRecord.class, null);
        initRenderer(localConfig, context);
        PDDocument pdfDocument = null;

        String password = "";
        PDFRenderingState incomingRenderingState = context.get(PDFRenderingState.class);
        TikaInputStream tstream = null;
        boolean shouldClose = false;
        OCRPageCounter prevOCRCounter = context.get(OCRPageCounter.class);
        context.set(OCRPageCounter.class, new OCRPageCounter());
        try {
            if (shouldSpool(localConfig)) {
                if (stream instanceof TikaInputStream) {
                    tstream = (TikaInputStream) stream;
                } else {
                    tstream = TikaInputStream.get(CloseShieldInputStream.wrap(stream));
                    shouldClose = true;
                }
                context.set(PDFRenderingState.class, new PDFRenderingState(tstream));
            } else {
                tstream = TikaInputStream.cast(stream);
            }


            scanXRefOffsets(localConfig, tstream, metadata, context);

            password = getPassword(metadata, context);
            MemoryUsageSetting memoryUsageSetting = null;

            if (localConfig.getMaxMainMemoryBytes() >= 0) {
                memoryUsageSetting =
                        MemoryUsageSetting.setupMixed(localConfig.getMaxMainMemoryBytes());
            } else {
                memoryUsageSetting = MemoryUsageSetting.setupMainMemoryOnly();
            }

            pdfDocument = getPDDocument(stream, tstream, password,
                    memoryUsageSetting.streamCache, metadata, context);


            boolean hasCollection = hasCollection(pdfDocument, metadata);

            checkEncryptedPayload(pdfDocument, hasCollection, localConfig);

            boolean hasXFA = hasXFA(pdfDocument, metadata);
            boolean hasMarkedContent = hasMarkedContent(pdfDocument, metadata);
            extractMetadata(pdfDocument, metadata, context);
            extractSignatures(pdfDocument, metadata);
            checkIllustrator(pdfDocument, metadata);
            AccessChecker checker = localConfig.getAccessChecker();
            checker.check(metadata);
            renderPagesBeforeParse(tstream, handler, metadata, context, localConfig);
            if (handler != null) {
                if (shouldHandleXFAOnly(hasXFA, localConfig)) {
                    handleXFAOnly(pdfDocument, handler, metadata, context);
                } else if (localConfig.getOcrStrategy()
                        .equals(PDFParserConfig.OCR_STRATEGY.OCR_ONLY)) {
                    OCR2XHTML.process(pdfDocument, handler, context, metadata,
                            localConfig);
                } else if (hasMarkedContent && localConfig.isExtractMarkedContent()) {
                    PDFMarkedContent2XHTML
                            .process(pdfDocument, handler, context, metadata,
                                    localConfig);
                } else {
                    PDF2XHTML.process(pdfDocument, handler, context, metadata,
                            localConfig);
                }
            }
        } catch (InvalidPasswordException e) {
            metadata.set(PDF.IS_ENCRYPTED, "true");
            throw new EncryptedDocumentException(e);
        } finally {
            metadata.set(OCR_PAGE_COUNT, context.get(OCRPageCounter.class).getCount());
            context.set(OCRPageCounter.class, prevOCRCounter);
            //reset the incrementalUpdateRecord even if null
            context.set(IncrementalUpdateRecord.class, incomingIncrementalUpdateRecord);
            PDFRenderingState currState = context.get(PDFRenderingState.class);
            try {
                if (currState != null && currState.getRenderResults() != null) {
                    currState.getRenderResults().close();
                }
                if (pdfDocument != null) {
                    pdfDocument.close();
                }
            } finally {
                //replace the one that was here
                context.set(PDFRenderingState.class, incomingRenderingState);
                if (shouldClose && tstream != null) {
                    tstream.close();
                }
            }

        }
    }
@Test
    public void testSkipBadPage() throws Exception {
        //test file comes from govdocs1
        //can't use TikaTest shortcuts because of exception
        ContentHandler handler = new BodyContentHandler(-1);
        Metadata m = new Metadata();
        ParseContext context = new ParseContext();
        try (InputStream is = getResourceAsStream("/test-documents/testPDF_bad_page_303226.pdf")) {
            AUTO_DETECT_PARSER.parse(is, handler, m, context);
        }
        //as of PDFBox 2.0.28, exceptions are no longer thrown for this problem
        String content = handler.toString();
        assertEquals(0, m.getValues(TikaCoreProperties.TIKA_META_EXCEPTION_WARNING).length);
        //assertContains("Unknown dir", m.get(TikaCoreProperties.TIKA_META_EXCEPTION_WARNING));
        assertContains("1309.61", content);

        //now try throwing exception immediately
        PDFParserConfig config = new PDFParserConfig();
        config.setCatchIntermediateIOExceptions(false);
        context.set(PDFParserConfig.class, config);

        handler = new BodyContentHandler(-1);
        m = new Metadata();
        try (InputStream is = getResourceAsStream("/test-documents/testPDF_bad_page_303226.pdf")) {
            AUTO_DETECT_PARSER.parse(is, handler, m, context);
        }
        content = handler.toString();
        assertEquals(0, m.getValues(TikaCoreProperties.TIKA_META_EXCEPTION_WARNING).length);
        assertContains("1309.61", content);
    }