summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/include/fpdfapi/fpdf_parser.h3
-rw-r--r--core/src/fpdfapi/fpdf_page/fpdf_page_parser.cpp2
-rw-r--r--core/src/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp34
-rw-r--r--core/src/fpdfapi/fpdf_page/pageint.h2
-rw-r--r--core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp56
-rw-r--r--testing/resources/pixel/bug_524043_1.in61
-rw-r--r--testing/resources/pixel/bug_524043_1_expected.pdf.0.pngbin0 -> 5433 bytes
-rw-r--r--testing/resources/pixel/bug_524043_2.in62
-rw-r--r--testing/resources/pixel/bug_524043_2_expected.pdf.0.pngbin0 -> 2237 bytes
-rw-r--r--testing/resources/pixel/bug_524043_3.in62
-rw-r--r--testing/resources/pixel/bug_524043_3_expected.pdf.0.pngbin0 -> 5433 bytes
-rw-r--r--testing/resources/pixel/bug_524043_4.in61
-rw-r--r--testing/resources/pixel/bug_524043_4_expected.pdf.0.pngbin0 -> 5433 bytes
-rw-r--r--testing/resources/pixel/bug_524043_5.in61
-rw-r--r--testing/resources/pixel/bug_524043_5_expected.pdf.0.pngbin0 -> 5433 bytes
-rw-r--r--testing/resources/pixel/bug_524043_6.in60
-rw-r--r--testing/resources/pixel/bug_524043_6_expected.pdf.0.pngbin0 -> 590 bytes
-rw-r--r--testing/resources/pixel/bug_524043_7.in61
-rw-r--r--testing/resources/pixel/bug_524043_7_expected.pdf.0.pngbin0 -> 2237 bytes
19 files changed, 455 insertions, 70 deletions
diff --git a/core/include/fpdfapi/fpdf_parser.h b/core/include/fpdfapi/fpdf_parser.h
index 03ae4cf570..6194247568 100644
--- a/core/include/fpdfapi/fpdf_parser.h
+++ b/core/include/fpdfapi/fpdf_parser.h
@@ -294,7 +294,8 @@ class CPDF_SyntaxParser {
FX_BOOL IsWholeWord(FX_FILESIZE startpos,
FX_FILESIZE limit,
const uint8_t* tag,
- FX_DWORD taglen);
+ FX_DWORD taglen,
+ FX_BOOL checkKeyword);
CFX_ByteString ReadString();
diff --git a/core/src/fpdfapi/fpdf_page/fpdf_page_parser.cpp b/core/src/fpdfapi/fpdf_page/fpdf_page_parser.cpp
index 059dd4c2a6..4e5ef1c898 100644
--- a/core/src/fpdfapi/fpdf_page/fpdf_page_parser.cpp
+++ b/core/src/fpdfapi/fpdf_page/fpdf_page_parser.cpp
@@ -11,7 +11,6 @@
#define REQUIRE_PARAMS(count) \
if (m_ParamCount != count) { \
- m_bAbort = TRUE; \
return; \
}
@@ -34,7 +33,6 @@ CPDF_StreamContentParser::CPDF_StreamContentParser(
m_Level(level),
m_ParamStartPos(0),
m_ParamCount(0),
- m_bAbort(FALSE),
m_pCurStates(new CPDF_AllStates),
m_pLastTextObject(nullptr),
m_DefFontSize(0),
diff --git a/core/src/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp b/core/src/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp
index 48e9b98d3a..c9bcff6db6 100644
--- a/core/src/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp
+++ b/core/src/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp
@@ -9,27 +9,7 @@
#include "../../../include/fxcodec/fx_codec.h"
#include "pageint.h"
#include <limits.h>
-const FX_CHAR* const _PDF_OpCharType =
- "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII"
- "IIVIIIIVIIVIIIIIVVIIIIIIIIIIIIII"
- "IIVVVVVVIVVVVVVIVVVVVIIVVIIIIIII"
- "IIVVVVVVVVVVVVVVIVVVIIVVIVVIIIII"
- "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII"
- "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII"
- "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII"
- "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII";
-FX_BOOL _PDF_HasInvalidOpChar(const FX_CHAR* op) {
- if (!op) {
- return FALSE;
- }
- uint8_t ch;
- while ((ch = *op++)) {
- if (_PDF_OpCharType[ch] == 'I') {
- return TRUE;
- }
- }
- return FALSE;
-}
+
class CPDF_StreamParserAutoClearer {
public:
CPDF_StreamParserAutoClearer(CPDF_StreamParser** scoped_variable,
@@ -61,13 +41,7 @@ FX_DWORD CPDF_StreamContentParser::Parse(const uint8_t* pData,
case CPDF_StreamParser::EndOfData:
return m_pSyntax->GetPos();
case CPDF_StreamParser::Keyword:
- if (!OnOperator((char*)syntax.GetWordBuf()) &&
- _PDF_HasInvalidOpChar((char*)syntax.GetWordBuf())) {
- m_bAbort = TRUE;
- }
- if (m_bAbort) {
- return m_pSyntax->GetPos();
- }
+ OnOperator((char*)syntax.GetWordBuf());
ClearAllParams();
break;
case CPDF_StreamParser::Number:
@@ -1126,10 +1100,6 @@ void CPDF_ContentParser::Continue(IFX_Pause* pPause) {
m_CurrentOffset +=
m_pParser->Parse(m_pData + m_CurrentOffset,
m_Size - m_CurrentOffset, PARSE_STEP_LIMIT);
- if (m_pParser->ShouldAbort()) {
- m_InternalStage = PAGEPARSE_STAGE_CHECKCLIP;
- continue;
- }
}
}
if (m_InternalStage == PAGEPARSE_STAGE_CHECKCLIP) {
diff --git a/core/src/fpdfapi/fpdf_page/pageint.h b/core/src/fpdfapi/fpdf_page/pageint.h
index 6bec07268c..c85523b833 100644
--- a/core/src/fpdfapi/fpdf_page/pageint.h
+++ b/core/src/fpdfapi/fpdf_page/pageint.h
@@ -162,7 +162,6 @@ class CPDF_StreamContentParser {
int level);
~CPDF_StreamContentParser();
- FX_BOOL ShouldAbort() const { return m_bAbort; }
CPDF_PageObjects* GetObjectList() const { return m_pObjectList; }
CPDF_AllStates* GetCurStates() const { return m_pCurStates.get(); }
FX_BOOL IsColored() const { return m_bColored; }
@@ -305,7 +304,6 @@ class CPDF_StreamContentParser {
_ContentParam m_ParamBuf1[PARAM_BUF_SIZE];
FX_DWORD m_ParamStartPos;
FX_DWORD m_ParamCount;
- FX_BOOL m_bAbort;
CPDF_StreamParser* m_pSyntax;
nonstd::unique_ptr<CPDF_AllStates> m_pCurStates;
CPDF_ContentMark m_CurContentMark;
diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp
index 7482f0b8e4..cd923f3e22 100644
--- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp
+++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp
@@ -2455,8 +2455,8 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
len = pLenObj->GetInteger();
}
// Check whether end of line markers follow the keyword 'stream'.
- unsigned int numMarkers = ReadEOLMarkers(m_Pos);
- m_Pos += numMarkers;
+ // The stream starts after end of line markers.
+ m_Pos += ReadEOLMarkers(m_Pos);
FX_FILESIZE streamStartPos = m_Pos;
if (pContext) {
pContext->m_DataStart = streamStartPos;
@@ -2467,19 +2467,18 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
objnum == (FX_DWORD)m_MetadataObjnum ? nullptr : m_pCryptoHandler;
if (!pCryptoHandler) {
FX_BOOL bSearchForKeyword = TRUE;
- unsigned int prevMarkers = 0;
- unsigned int nextMarkers = 0;
if (len >= 0) {
pdfium::base::CheckedNumeric<FX_FILESIZE> pos = m_Pos;
pos += len;
if (pos.IsValid() && pos.ValueOrDie() < m_FileLen) {
m_Pos = pos.ValueOrDie();
}
- prevMarkers = ReadEOLMarkers(m_Pos);
+ m_Pos += ReadEOLMarkers(m_Pos);
+ FXSYS_memset(m_WordBuffer, 0, ENDSTREAM_LEN + 1);
GetNextWord();
- nextMarkers = ReadEOLMarkers(m_Pos);
- if (m_WordSize == ENDSTREAM_LEN && prevMarkers != 0 && nextMarkers != 0 &&
- FXSYS_memcmp(m_WordBuffer, "endstream", ENDSTREAM_LEN) == 0) {
+ if (FXSYS_memcmp(m_WordBuffer, "endstream", ENDSTREAM_LEN) == 0 &&
+ IsWholeWord(m_Pos - ENDSTREAM_LEN, m_FileLen,
+ FX_BSTRC("endstream").GetPtr(), ENDSTREAM_LEN, TRUE)) {
bSearchForKeyword = FALSE;
}
}
@@ -2494,22 +2493,12 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
// Can't find any "endstream".
break;
}
- prevMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 1);
- nextMarkers =
- ReadEOLMarkers(streamStartPos + endStreamOffset + ENDSTREAM_LEN);
- if (prevMarkers != 0 && nextMarkers != 0) {
+ if (IsWholeWord(m_Pos - ENDSTREAM_LEN, m_FileLen,
+ FX_BSTRC("endstream").GetPtr(), ENDSTREAM_LEN, TRUE)) {
// Stop searching when the keyword "endstream" is found.
+ endStreamOffset = m_Pos - streamStartPos - ENDSTREAM_LEN;
break;
- } else {
- unsigned char ch = 0x00;
- GetCharAt(streamStartPos + endStreamOffset + ENDSTREAM_LEN, ch);
- if (ch == 0x09 || ch == 0x20) {
- //"endstream" is treated as a keyword
- // when it is followed by a tab or whitespace
- break;
- }
}
- m_Pos += ENDSTREAM_LEN;
}
m_Pos = streamStartPos;
FX_FILESIZE endObjOffset = 0;
@@ -2519,14 +2508,12 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
// Can't find any "endobj".
break;
}
- prevMarkers = ReadEOLMarkers(streamStartPos + endObjOffset - 1);
- nextMarkers =
- ReadEOLMarkers(streamStartPos + endObjOffset + ENDOBJ_LEN);
- if (prevMarkers != 0 && nextMarkers != 0) {
+ if (IsWholeWord(m_Pos - ENDOBJ_LEN, m_FileLen,
+ FX_BSTRC("endobj").GetPtr(), ENDOBJ_LEN, TRUE)) {
// Stop searching when the keyword "endobj" is found.
+ endObjOffset = m_Pos - streamStartPos - ENDOBJ_LEN;
break;
}
- m_Pos += ENDOBJ_LEN;
}
if (endStreamOffset < 0 && endObjOffset < 0) {
// Can't find "endstream" or "endobj".
@@ -2542,7 +2529,7 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
endStreamOffset = endObjOffset;
}
len = endStreamOffset;
- numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 2);
+ int numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 2);
if (numMarkers == 2) {
len -= 2;
} else {
@@ -2579,8 +2566,9 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
pContext->m_DataEnd = pContext->m_DataStart + len;
}
streamStartPos = m_Pos;
+ FXSYS_memset(m_WordBuffer, 0, ENDOBJ_LEN + 1);
GetNextWord();
- numMarkers = ReadEOLMarkers(m_Pos);
+ int numMarkers = ReadEOLMarkers(m_Pos);
if (m_WordSize == ENDOBJ_LEN && numMarkers != 0 &&
FXSYS_memcmp(m_WordBuffer, "endobj", ENDOBJ_LEN) == 0) {
m_Pos = streamStartPos;
@@ -2611,7 +2599,8 @@ int32_t CPDF_SyntaxParser::GetDirectNum() {
FX_BOOL CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos,
FX_FILESIZE limit,
const uint8_t* tag,
- FX_DWORD taglen) {
+ FX_DWORD taglen,
+ FX_BOOL checkKeyword) {
uint8_t type = PDF_CharType[tag[0]];
FX_BOOL bCheckLeft = type != 'D' && type != 'W';
type = PDF_CharType[tag[taglen - 1]];
@@ -2620,13 +2609,13 @@ FX_BOOL CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos,
if (bCheckRight && startpos + (int32_t)taglen <= limit &&
GetCharAt(startpos + (int32_t)taglen, ch)) {
uint8_t type = PDF_CharType[ch];
- if (type == 'N' || type == 'R') {
+ if (type == 'N' || type == 'R' || (checkKeyword && type == 'D')) {
return FALSE;
}
}
if (bCheckLeft && startpos > 0 && GetCharAt(startpos - 1, ch)) {
uint8_t type = PDF_CharType[ch];
- if (type == 'N' || type == 'R') {
+ if (type == 'N' || type == 'R' || (checkKeyword && type == 'D')) {
return FALSE;
}
}
@@ -2682,7 +2671,8 @@ FX_BOOL CPDF_SyntaxParser::SearchWord(const CFX_ByteStringC& tag,
}
}
FX_FILESIZE startpos = bForward ? pos - taglen + 1 : pos;
- if (!bWholeWord || IsWholeWord(startpos, limit, tag.GetPtr(), taglen)) {
+ if (!bWholeWord ||
+ IsWholeWord(startpos, limit, tag.GetPtr(), taglen, FALSE)) {
m_Pos = startpos;
return TRUE;
}
@@ -2739,7 +2729,7 @@ int32_t CPDF_SyntaxParser::SearchMultiWord(const CFX_ByteStringC& tags,
if (pPatterns[i].m_Offset == pPatterns[i].m_Len) {
if (!bWholeWord ||
IsWholeWord(pos - pPatterns[i].m_Len, limit, pPatterns[i].m_pTag,
- pPatterns[i].m_Len)) {
+ pPatterns[i].m_Len, FALSE)) {
found = i;
goto end;
} else {
diff --git a/testing/resources/pixel/bug_524043_1.in b/testing/resources/pixel/bug_524043_1.in
new file mode 100644
index 0000000000..61ac6f4bb2
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_1.in
@@ -0,0 +1,61 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+{{object 2 0}} <<
+ /Type /Pages
+ /MediaBox [ 0 0 200 200 ]
+ /Count 1
+ /Kids [ 3 0 R ]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 4 0 R
+ /F2 5 0 R
+ >>
+ >>
+ /Contents 6 0 R
+>>
+endobj
+{{object 4 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Times-Roman
+>>
+endobj
+{{object 5 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Helvetica
+>>
+endobj
+% Case 1:
+% /Length identifies intended end of stream, despite embedded keywords.
+% Both should render as text.
+{{object 6 0}} <<
+ /Length 107
+>>
+stream
+BT
+20 50 Td
+/F1 12 Tf
+(endobj is text) Tj
+endstream
+0 50 Td
+/F2 13 Tf
+(endstream is text per /Length) Tj
+ET
+endstream
+endobj
+{{xref}}
+trailer <<
+ /Size 6
+ /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_524043_1_expected.pdf.0.png b/testing/resources/pixel/bug_524043_1_expected.pdf.0.png
new file mode 100644
index 0000000000..a044bb0c37
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_1_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_524043_2.in b/testing/resources/pixel/bug_524043_2.in
new file mode 100644
index 0000000000..0ee43da106
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_2.in
@@ -0,0 +1,62 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+{{object 2 0}} <<
+ /Type /Pages
+ /MediaBox [ 0 0 200 200 ]
+ /Count 1
+ /Kids [ 3 0 R ]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 4 0 R
+ /F2 5 0 R
+ >>
+ >>
+ /Contents 6 0 R
+>>
+endobj
+{{object 4 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Times-Roman
+>>
+endobj
+{{object 5 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Helvetica
+>>
+endobj
+% Case 2:
+% /Length incorrectly identifies middle of stream.
+% The stream is blocked by the keyword "endstream"
+% Only the text before the keyword can be rendered.
+{{object 6 0}} <<
+ /Length 87
+>>
+stream
+BT
+20 50 Td
+/F1 12 Tf
+(endobj is text) Tj
+endstream
+0 50 Td
+/F2 13 Tf
+(It's wrong when you see the text!) Tj
+ET
+endstream
+endobj
+{{xref}}
+trailer <<
+ /Size 6
+ /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_524043_2_expected.pdf.0.png b/testing/resources/pixel/bug_524043_2_expected.pdf.0.png
new file mode 100644
index 0000000000..19de52a360
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_2_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_524043_3.in b/testing/resources/pixel/bug_524043_3.in
new file mode 100644
index 0000000000..716345ede1
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_3.in
@@ -0,0 +1,62 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+{{object 2 0}} <<
+ /Type /Pages
+ /MediaBox [ 0 0 200 200 ]
+ /Count 1
+ /Kids [ 3 0 R ]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 4 0 R
+ /F2 5 0 R
+ >>
+ >>
+ /Contents 6 0 R
+>>
+endobj
+{{object 4 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Times-Roman
+>>
+endobj
+{{object 5 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Helvetica
+>>
+endobj
+% Case 3:
+% /Length incorrectly identifies middle of stream.
+% "eendstream" shouldn't block the stream.
+% Both should render as text.
+{{object 6 0}} <<
+ /Length 87
+>>
+stream
+BT
+20 50 Td
+/F1 12 Tf
+(endobj is text) Tj
+eendstream
+0 50 Td
+/F2 13 Tf
+(endstream is text per /Length) Tj
+ET
+endstream
+endobj
+{{xref}}
+trailer <<
+ /Size 6
+ /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_524043_3_expected.pdf.0.png b/testing/resources/pixel/bug_524043_3_expected.pdf.0.png
new file mode 100644
index 0000000000..a044bb0c37
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_3_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_524043_4.in b/testing/resources/pixel/bug_524043_4.in
new file mode 100644
index 0000000000..6cdb3d18a7
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_4.in
@@ -0,0 +1,61 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+{{object 2 0}} <<
+ /Type /Pages
+ /MediaBox [ 0 0 200 200 ]
+ /Count 1
+ /Kids [ 3 0 R ]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 4 0 R
+ /F2 5 0 R
+ >>
+ >>
+ /Contents 6 0 R
+>>
+endobj
+{{object 4 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Times-Roman
+>>
+endobj
+{{object 5 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Helvetica
+>>
+endobj
+% Case 4:
+% /Length incorrectly identifies middle of stream.
+% "endstream." shouldn't block the stream.
+% Both should render as text even "endstream" is missing.
+{{object 6 0}} <<
+ /Length 87
+>>
+stream
+BT
+20 50 Td
+/F1 12 Tf
+(endobj is text) Tj
+endstream.
+0 50 Td
+/F2 13 Tf
+(endstream is text per /Length) Tj
+ET
+endobj
+{{xref}}
+trailer <<
+ /Size 6
+ /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_524043_4_expected.pdf.0.png b/testing/resources/pixel/bug_524043_4_expected.pdf.0.png
new file mode 100644
index 0000000000..a044bb0c37
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_4_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_524043_5.in b/testing/resources/pixel/bug_524043_5.in
new file mode 100644
index 0000000000..799674628d
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_5.in
@@ -0,0 +1,61 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+{{object 2 0}} <<
+ /Type /Pages
+ /MediaBox [ 0 0 200 200 ]
+ /Count 1
+ /Kids [ 3 0 R ]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 4 0 R
+ /F2 5 0 R
+ >>
+ >>
+ /Contents 6 0 R
+>>
+endobj
+{{object 4 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Times-Roman
+>>
+endobj
+{{object 5 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Helvetica
+>>
+endobj
+% Case 5:
+% /Length incorrectly identifies middle of stream.
+% "endstream%" shouldn't block the stream.
+% Both should render as text even "endobj" is missing.
+{{object 6 0}} <<
+ /Length 87
+>>
+stream
+BT
+20 50 Td
+/F1 12 Tf
+(endobj is text) Tj
+endstream%
+0 50 Td
+/F2 13 Tf
+(endstream is text per /Length) Tj
+ET
+endstream
+{{xref}}
+trailer <<
+ /Size 6
+ /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_524043_5_expected.pdf.0.png b/testing/resources/pixel/bug_524043_5_expected.pdf.0.png
new file mode 100644
index 0000000000..a044bb0c37
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_5_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_524043_6.in b/testing/resources/pixel/bug_524043_6.in
new file mode 100644
index 0000000000..318b20750d
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_6.in
@@ -0,0 +1,60 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+{{object 2 0}} <<
+ /Type /Pages
+ /MediaBox [ 0 0 200 200 ]
+ /Count 1
+ /Kids [ 3 0 R ]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 4 0 R
+ /F2 5 0 R
+ >>
+ >>
+ /Contents 6 0 R
+>>
+endobj
+{{object 4 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Times-Roman
+>>
+endobj
+{{object 5 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Helvetica
+>>
+endobj
+% Case 6:
+% /Length incorrectly identifies middle of stream.
+% "endstream+" shouldn't block the stream.
+% Nothing will be rendered when both "endstream" and "endobj" are missing.
+{{object 6 0}} <<
+ /Length 87
+>>
+stream
+BT
+20 50 Td
+/F1 12 Tf
+(endobj is text) Tj
+endstream+
+0 50 Td
+/F2 13 Tf
+(endstream is text per /Length) Tj
+ET
+{{xref}}
+trailer <<
+ /Size 6
+ /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_524043_6_expected.pdf.0.png b/testing/resources/pixel/bug_524043_6_expected.pdf.0.png
new file mode 100644
index 0000000000..3edcc2db89
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_6_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_524043_7.in b/testing/resources/pixel/bug_524043_7.in
new file mode 100644
index 0000000000..c95f2d94e1
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_7.in
@@ -0,0 +1,61 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+{{object 2 0}} <<
+ /Type /Pages
+ /MediaBox [ 0 0 200 200 ]
+ /Count 1
+ /Kids [ 3 0 R ]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 4 0 R
+ /F2 5 0 R
+ >>
+ >>
+ /Contents 6 0 R
+>>
+endobj
+{{object 4 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Times-Roman
+>>
+endobj
+{{object 5 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Helvetica
+>>
+endobj
+% Case 7:
+% /Length incorrectly identifies middle of stream.
+% "endstream" will block the stream.
+% The text before the keyword "endstream" can be rendered although
+% both "endstream" and "endobj" are missing at the end of stream.
+{{object 6 0}} <<
+ /Length 87
+>>
+stream
+BT
+20 50 Td
+/F1 12 Tf
+(endobj is text) Tj
+endstream
+0 50 Td
+/F2 13 Tf
+(endstream is text per /Length) Tj
+ET
+{{xref}}
+trailer <<
+ /Size 6
+ /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_524043_7_expected.pdf.0.png b/testing/resources/pixel/bug_524043_7_expected.pdf.0.png
new file mode 100644
index 0000000000..19de52a360
--- /dev/null
+++ b/testing/resources/pixel/bug_524043_7_expected.pdf.0.png
Binary files differ