M74: Avoid premature decoding completion in CJBig2_ArithDecoder.

BUG=chromium:947622
TBR=npm@chromium.org

Change-Id: Iec70a876fa6a00fab424807dd8118b8eb512dda6
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/52712
Reviewed-by: Nicolás Peña Moreno <npm@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
(cherry picked from commit fe699e74488ff5ccbc0bf6fa15230ae27116d3fa)
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/52770
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp b/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp
index 45cca11..8d3fc5a 100644
--- a/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp
+++ b/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp
@@ -52,7 +52,7 @@
 }
 
 CJBig2_ArithDecoder::CJBig2_ArithDecoder(CJBig2_BitStream* pStream)
-    : m_Complete(false), m_FinishedStream(false), m_pStream(pStream) {
+    : m_pStream(pStream) {
   m_B = m_pStream->getCurByte_arith();
   m_C = (m_B ^ 0xff) << 16;
   BYTEIN();
@@ -86,17 +86,26 @@
 }
 
 void CJBig2_ArithDecoder::BYTEIN() {
-  unsigned char B1;
   if (m_B == 0xff) {
-    B1 = m_pStream->getNextByte_arith();
+    unsigned char B1 = m_pStream->getNextByte_arith();
     if (B1 > 0x8f) {
       m_CT = 8;
-      // If we are here, it means that we have finished decoding data (see JBIG2
-      // spec, Section E.3.4). If we arrive here a second time, we're looping,
-      // so complete decoding.
-      if (m_FinishedStream)
-        m_Complete = true;
-      m_FinishedStream = true;
+
+      switch (m_State) {
+        case StreamState::kDataAvailable:
+          // Finished decoding data (see JBIG2 spec, Section E.3.4).
+          m_State = StreamState::kDecodingFinished;
+          break;
+        case StreamState::kDecodingFinished:
+          // Allow one more call in the finished state. https://crbug.com/947622
+          m_State = StreamState::kLooping;
+          break;
+        case StreamState::kLooping:
+          // Looping state detected. Mark decoding as complete to bail out.
+          // https://crbug.com/767156
+          m_Complete = true;
+          break;
+      }
     } else {
       m_pStream->incByteIdx();
       m_B = B1;
diff --git a/core/fxcodec/jbig2/JBig2_ArithDecoder.h b/core/fxcodec/jbig2/JBig2_ArithDecoder.h
index c2fed50..9731ac6 100644
--- a/core/fxcodec/jbig2/JBig2_ArithDecoder.h
+++ b/core/fxcodec/jbig2/JBig2_ArithDecoder.h
@@ -46,11 +46,17 @@
   bool IsComplete() const { return m_Complete; }
 
  private:
+  enum class StreamState : uint8_t {
+    kDataAvailable,
+    kDecodingFinished,
+    kLooping,
+  };
+
   void BYTEIN();
   void ReadValueA();
 
-  bool m_Complete;
-  bool m_FinishedStream;
+  bool m_Complete = false;
+  StreamState m_State = StreamState::kDataAvailable;
   uint8_t m_B;
   unsigned int m_C;
   unsigned int m_A;