Ignore inline images without EI operators

If content stream parsing is handling the BI operator and it does not
find an EI operator before reaching the end of the stream, then the
inline image is invalid and should not be displayed.

- Add a pixel test for this to demonstrate this corner case.
- Fix bug_1591.in so it has enough image data. The existing file did not
  take the image pitch into account and was reading "\nEI" as part of
  the image data.
- Temporarily suppress bug_1236805.in pixel test, which uses inline
  images and is very sensitive to these changes.

Bug: 412524377
Change-Id: Icaa7089fb14f0e74c613f7f1461f0d1ead19d656
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/130930
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.cpp b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
index 6403baf..fdd3ac9 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
@@ -683,14 +683,11 @@
   while (true) {
     CPDF_StreamParser::ElementType type = syntax_->ParseNextElement();
     if (type == CPDF_StreamParser::ElementType::kEndOfData) {
-      break;
+      return;
     }
 
-    if (type != CPDF_StreamParser::ElementType::kKeyword) {
-      continue;
-    }
-
-    if (syntax_->GetWord() == "EI") {
+    if (type == CPDF_StreamParser::ElementType::kKeyword &&
+        syntax_->GetWord() == "EI") {
       break;
     }
   }
diff --git a/core/fpdfapi/page/cpdf_streamparser.cpp b/core/fpdfapi/page/cpdf_streamparser.cpp
index c07dbec..96e5db8 100644
--- a/core/fpdfapi/page/cpdf_streamparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamparser.cpp
@@ -210,8 +210,11 @@
       while (true) {
         uint32_t saved_iteration_position = pos_;
         ElementType type = ParseNextElement();
-        if (type == ElementType::kEndOfData ||
-            (type == ElementType::kKeyword && GetWord() == "EI")) {
+        if (type == ElementType::kEndOfData) {
+          return nullptr;
+        }
+
+        if (type == ElementType::kKeyword && GetWord() == "EI") {
           break;
         }
 
diff --git a/testing/SUPPRESSIONS b/testing/SUPPRESSIONS
index aa1db92..ae5308a 100644
--- a/testing/SUPPRESSIONS
+++ b/testing/SUPPRESSIONS
@@ -622,6 +622,9 @@
 # TODO(chromium:1131694): Remove after associated bug is fixed
 bug_1131694.in * * * *
 
+# TODO(thestig): Remove after fixing inline image parsing.
+bug_1236805.in * * * *
+
 # TODO(pdfium:1747): Remove after associated bug is fixed
 bug_1258634.in * * * *
 
diff --git a/testing/resources/bug_1591.in b/testing/resources/bug_1591.in
index 7632e13..95d04ab 100644
--- a/testing/resources/bug_1591.in
+++ b/testing/resources/bug_1591.in
@@ -95,7 +95,7 @@
 /BPC 1
 /IM true
 ID
-xx
+xxxx
 EI
 Q
 endstream
diff --git a/testing/resources/bug_1591.pdf b/testing/resources/bug_1591.pdf
index 3ec0a13..98f8ab8 100644
--- a/testing/resources/bug_1591.pdf
+++ b/testing/resources/bug_1591.pdf
@@ -25,7 +25,7 @@
 >>
 endobj
 4 0 obj <<
-  /Length 102
+  /Length 101
 >>
 stream
 0 0 0 rg
@@ -69,7 +69,7 @@
 >>
 endobj
 8 0 obj <<
-  /Length 105
+  /Length 104
 >>
 stream
 q
@@ -86,7 +86,7 @@
 endstream
 endobj
 9 0 obj <<
-  /Length 42
+  /Length 43
 >>
 stream
 q
@@ -96,7 +96,7 @@
 /BPC 1
 /IM true
 ID
-xx
+xxxx
 EI
 Q
 endstream
@@ -118,5 +118,5 @@
   /Size 10
 >>
 startxref
-1106
+1108
 %%EOF
diff --git a/testing/resources/pixel/bug_412524377.in b/testing/resources/pixel/bug_412524377.in
new file mode 100644
index 0000000..488af5d
--- /dev/null
+++ b/testing/resources/pixel/bug_412524377.in
@@ -0,0 +1,87 @@
+{{header}}
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+>>
+endobj
+{{object 2 0}} <<
+  /Type /Pages
+  /Count 2
+  /Kids [3 0 R 5 0 R]
+  /MediaBox [0 0 200 200]
+  /Resources <<
+    /ColorSpace <<
+      /CS0 /DeviceGray % Needed to make Acrobat happy.
+    >>
+  >>
+>>
+endobj
+{{object 3 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /Contents 4 0 R
+>>
+endobj
+{{object 4 0}} <<
+  {{streamlen}}
+>>
+stream
+% This page renders correctly.
+q
+0 0 1 rg
+0 0 200 200 re f
+Q
+q
+100 0 0 100 0 0 cm
+BI
+/W 2
+/H 2
+/BPC 8
+/CS /G
+/F /AHx
+ID
+0066CCFF >
+EI
+Q
+q
+0 1 0 rg
+100 0 100 100 re f
+Q
+endstream
+endobj
+{{object 5 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /Contents 6 0 R
+>>
+endobj
+{{object 6 0}} <<
+  {{streamlen}}
+>>
+stream
+% This page only renders as blue due to the missing EI operator.
+q
+0 0 1 rg
+0 0 200 200 re f
+Q
+q
+100 0 0 100 0 0 cm
+BI
+/W 2
+/H 2
+/BPC 8
+/CS /G
+/F /AHx
+ID
+0066CCFF >
+Q
+q
+0 1 0 rg
+100 0 100 100 re f
+Q
+endstream
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_412524377_expected.pdf.0.png b/testing/resources/pixel/bug_412524377_expected.pdf.0.png
new file mode 100644
index 0000000..3e59940
--- /dev/null
+++ b/testing/resources/pixel/bug_412524377_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_412524377_expected.pdf.1.png b/testing/resources/pixel/bug_412524377_expected.pdf.1.png
new file mode 100644
index 0000000..7b62530
--- /dev/null
+++ b/testing/resources/pixel/bug_412524377_expected.pdf.1.png
Binary files differ