Remove out parameter from CPDF_SyntaxParser::GetNextWord().

Change the return value to a struct to hold both the ByteString and the
bool.

Change-Id: Id7520989cdb378352456ff4e40f3bd56bfd049e4
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/85977
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/parser/cfdf_document.cpp b/core/fpdfapi/parser/cfdf_document.cpp
index b9dc188..8e5c9d9 100644
--- a/core/fpdfapi/parser/cfdf_document.cpp
+++ b/core/fpdfapi/parser/cfdf_document.cpp
@@ -38,19 +38,18 @@
   m_pFile = std::move(pFile);
   CPDF_SyntaxParser parser(m_pFile);
   while (1) {
-    bool bNumber;
-    ByteString word = parser.GetNextWord(&bNumber);
-    if (bNumber) {
-      uint32_t objnum = FXSYS_atoui(word.c_str());
+    CPDF_SyntaxParser::WordResult word_result = parser.GetNextWord();
+    if (word_result.is_number) {
+      uint32_t objnum = FXSYS_atoui(word_result.word.c_str());
       if (!objnum)
         break;
 
-      word = parser.GetNextWord(&bNumber);
-      if (!bNumber)
+      word_result = parser.GetNextWord();
+      if (!word_result.is_number)
         break;
 
-      word = parser.GetNextWord(nullptr);
-      if (word != "obj")
+      word_result = parser.GetNextWord();
+      if (word_result.word != "obj")
         break;
 
       RetainPtr<CPDF_Object> pObj = parser.GetObjectBody(this);
@@ -58,11 +57,11 @@
         break;
 
       ReplaceIndirectObjectIfHigherGeneration(objnum, std::move(pObj));
-      word = parser.GetNextWord(nullptr);
-      if (word != "endobj")
+      word_result = parser.GetNextWord();
+      if (word_result.word != "endobj")
         break;
     } else {
-      if (word != "trailer")
+      if (word_result.word != "trailer")
         break;
 
       RetainPtr<CPDF_Dictionary> pMainDict =
diff --git a/core/fpdfapi/parser/cpdf_linearized_header.cpp b/core/fpdfapi/parser/cpdf_linearized_header.cpp
index 256c2cc..2c927c7 100644
--- a/core/fpdfapi/parser/cpdf_linearized_header.cpp
+++ b/core/fpdfapi/parser/cpdf_linearized_header.cpp
@@ -72,7 +72,7 @@
   }
   // Move parser to the start of the xref table for the documents first page.
   // (skpping endobj keyword)
-  if (parser->GetNextWord(nullptr) != "endobj")
+  if (parser->GetNextWord().word != "endobj")
     return nullptr;
 
   auto result = pdfium::WrapUnique(
diff --git a/core/fpdfapi/parser/cpdf_parser.cpp b/core/fpdfapi/parser/cpdf_parser.cpp
index 7ef9ed2..11e1cad 100644
--- a/core/fpdfapi/parser/cpdf_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_parser.cpp
@@ -228,12 +228,12 @@
   m_pSyntax->GetKeyword();
 
   // Read XRef offset.
-  bool bNumber;
-  const ByteString xref_offset_str = m_pSyntax->GetNextWord(&bNumber);
-  if (!bNumber || xref_offset_str.IsEmpty())
+  const CPDF_SyntaxParser::WordResult xref_offset_result =
+      m_pSyntax->GetNextWord();
+  if (!xref_offset_result.is_number || xref_offset_result.word.IsEmpty())
     return 0;
 
-  const FX_SAFE_FILESIZE result = FXSYS_atoi64(xref_offset_str.c_str());
+  const FX_SAFE_FILESIZE result = FXSYS_atoi64(xref_offset_result.word.c_str());
   if (!result.IsValid() || result.ValueOrDie() >= m_pSyntax->GetDocumentSize())
     return 0;
 
@@ -275,11 +275,10 @@
     // Find the first non-zero position.
     FX_FILESIZE SavedPos = m_pSyntax->GetPos();
     m_pSyntax->SetPos(it.second.pos);
-    bool is_num = false;
-    ByteString num_str = m_pSyntax->GetNextWord(&is_num);
+    CPDF_SyntaxParser::WordResult word_result = m_pSyntax->GetNextWord();
     m_pSyntax->SetPos(SavedPos);
-    if (!is_num || num_str.IsEmpty() ||
-        FXSYS_atoui(num_str.c_str()) != it.first) {
+    if (!word_result.is_number || word_result.word.IsEmpty() ||
+        FXSYS_atoui(word_result.word.c_str()) != it.first) {
       // If the object number read doesn't match the one stored,
       // something is wrong with the cross reference table.
       return false;
@@ -511,12 +510,12 @@
   std::vector<CrossRefObjData> result_objects;
   while (1) {
     FX_FILESIZE saved_pos = m_pSyntax->GetPos();
-    bool bIsNumber;
-    ByteString word = m_pSyntax->GetNextWord(&bIsNumber);
+    CPDF_SyntaxParser::WordResult word_result = m_pSyntax->GetNextWord();
+    const ByteString& word = word_result.word;
     if (word.IsEmpty())
       return false;
 
-    if (!bIsNumber) {
+    if (!word_result.is_number) {
       m_pSyntax->SetPos(saved_pos);
       break;
     }
@@ -595,11 +594,11 @@
   m_pSyntax->SetReadBufferSize(kBufferSize);
   m_pSyntax->SetPos(0);
 
-  bool bIsNumber;
   std::vector<std::pair<uint32_t, FX_FILESIZE>> numbers;
-  for (ByteString word = m_pSyntax->GetNextWord(&bIsNumber); !word.IsEmpty();
-       word = m_pSyntax->GetNextWord(&bIsNumber)) {
-    if (bIsNumber) {
+  for (CPDF_SyntaxParser::WordResult result = m_pSyntax->GetNextWord();
+       !result.word.IsEmpty(); result = m_pSyntax->GetNextWord()) {
+    const ByteString& word = result.word;
+    if (result.is_number) {
       numbers.emplace_back(FXSYS_atoui(word.c_str()),
                            m_pSyntax->GetPos() - word.GetLength());
       if (numbers.size() > 2u)
diff --git a/core/fpdfapi/parser/cpdf_syntax_parser.cpp b/core/fpdfapi/parser/cpdf_syntax_parser.cpp
index 3b65133..00c8746 100644
--- a/core/fpdfapi/parser/cpdf_syntax_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_syntax_parser.cpp
@@ -464,24 +464,22 @@
   m_Pos--;
 }
 
-ByteString CPDF_SyntaxParser::GetNextWord(bool* bIsNumber) {
+CPDF_SyntaxParser::WordResult CPDF_SyntaxParser::GetNextWord() {
   CPDF_ReadValidator::ScopedSession read_session(GetValidator());
   WordType word_type = GetNextWordInternal();
-  if (bIsNumber)
-    *bIsNumber = word_type == WordType::kNumber;
-  ByteString ret;
+  ByteString word;
   if (!GetValidator()->has_read_problems())
-    ret = ByteString(m_WordBuffer, m_WordSize);
-  return ret;
+    word = ByteString(m_WordBuffer, m_WordSize);
+  return {word, word_type == WordType::kNumber};
 }
 
 ByteString CPDF_SyntaxParser::PeekNextWord() {
   AutoRestorer<FX_FILESIZE> save_pos(&m_Pos);
-  return GetNextWord(nullptr);
+  return GetNextWord().word;
 }
 
 ByteString CPDF_SyntaxParser::GetKeyword() {
-  return GetNextWord(nullptr);
+  return GetNextWord().word;
 }
 
 void CPDF_SyntaxParser::SetPos(FX_FILESIZE pos) {
@@ -505,19 +503,19 @@
     return nullptr;
 
   FX_FILESIZE SavedObjPos = m_Pos;
-  bool bIsNumber;
-  ByteString word = GetNextWord(&bIsNumber);
+  WordResult word_result = GetNextWord();
+  const ByteString& word = word_result.word;
   if (word.IsEmpty())
     return nullptr;
 
-  if (bIsNumber) {
+  if (word_result.is_number) {
     AutoRestorer<FX_FILESIZE> pos_restorer(&m_Pos);
-    ByteString nextword = GetNextWord(&bIsNumber);
-    if (!bIsNumber)
+    WordResult nextword = GetNextWord();
+    if (!nextword.is_number)
       return pdfium::MakeRetain<CPDF_Number>(word.AsStringView());
 
-    ByteString nextword2 = GetNextWord(nullptr);
-    if (nextword2 != "R")
+    WordResult nextword2 = GetNextWord();
+    if (nextword2.word != "R")
       return pdfium::MakeRetain<CPDF_Number>(word.AsStringView());
 
     pos_restorer.AbandonRestoration();
@@ -561,7 +559,8 @@
     RetainPtr<CPDF_Dictionary> pDict =
         pdfium::MakeRetain<CPDF_Dictionary>(m_pPool);
     while (1) {
-      ByteString inner_word = GetNextWord(nullptr);
+      WordResult inner_word_result = GetNextWord();
+      const ByteString& inner_word = inner_word_result.word;
       if (inner_word.IsEmpty())
         return nullptr;
 
@@ -599,7 +598,7 @@
     }
 
     AutoRestorer<FX_FILESIZE> pos_restorer(&m_Pos);
-    if (GetNextWord(nullptr) != "stream")
+    if (GetNextWord().word != "stream")
       return pDict;
     pos_restorer.AbandonRestoration();
     return ReadStream(std::move(pDict));
@@ -615,20 +614,21 @@
     ParseType parse_type) {
   CPDF_ReadValidator::ScopedSession read_session(GetValidator());
   const FX_FILESIZE saved_pos = GetPos();
-  bool is_number = false;
-  ByteString word = GetNextWord(&is_number);
-  if (!is_number || word.IsEmpty()) {
-    SetPos(saved_pos);
-    return nullptr;
-  }
-  const uint32_t parser_objnum = FXSYS_atoui(word.c_str());
 
-  word = GetNextWord(&is_number);
-  if (!is_number || word.IsEmpty()) {
+  WordResult objnum_word_result = GetNextWord();
+  if (!objnum_word_result.is_number || objnum_word_result.word.IsEmpty()) {
     SetPos(saved_pos);
     return nullptr;
   }
-  const uint32_t parser_gennum = FXSYS_atoui(word.c_str());
+  const uint32_t parser_objnum = FXSYS_atoui(objnum_word_result.word.c_str());
+
+  WordResult gennum_word_result = GetNextWord();
+  const ByteString& gennum_word = gennum_word_result.word;
+  if (!gennum_word_result.is_number || gennum_word.IsEmpty()) {
+    SetPos(saved_pos);
+    return nullptr;
+  }
+  const uint32_t parser_gennum = FXSYS_atoui(gennum_word.c_str());
 
   if (GetKeyword() != "obj") {
     SetPos(saved_pos);
diff --git a/core/fpdfapi/parser/cpdf_syntax_parser.h b/core/fpdfapi/parser/cpdf_syntax_parser.h
index 3d474fa..f8425f6 100644
--- a/core/fpdfapi/parser/cpdf_syntax_parser.h
+++ b/core/fpdfapi/parser/cpdf_syntax_parser.h
@@ -31,6 +31,11 @@
  public:
   enum class ParseType { kStrict, kLoose };
 
+  struct WordResult {
+    ByteString word;
+    bool is_number;
+  };
+
   static std::unique_ptr<CPDF_SyntaxParser> CreateForTesting(
       const RetainPtr<IFX_SeekableReadStream>& pFileAccess,
       FX_FILESIZE HeaderOffset);
@@ -61,7 +66,7 @@
   FX_FILESIZE FindTag(ByteStringView tag);
   bool ReadBlock(uint8_t* pBuf, uint32_t size);
   bool GetCharAt(FX_FILESIZE pos, uint8_t& ch);
-  ByteString GetNextWord(bool* bIsNumber);
+  WordResult GetNextWord();
   ByteString PeekNextWord();
 
   const RetainPtr<CPDF_ReadValidator>& GetValidator() const {
diff --git a/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp
index 47cec95..9c2bfa6 100644
--- a/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp
@@ -157,5 +157,5 @@
   static const uint8_t data[] = "    WORD ";
   CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(data));
   EXPECT_EQ("WORD", parser.PeekNextWord());
-  EXPECT_EQ("WORD", parser.GetNextWord(nullptr));
+  EXPECT_EQ("WORD", parser.GetNextWord().word);
 }
diff --git a/fpdfsdk/fpdf_view.cpp b/fpdfsdk/fpdf_view.cpp
index c061b76..86bfa7f 100644
--- a/fpdfsdk/fpdf_view.cpp
+++ b/fpdfsdk/fpdf_view.cpp
@@ -1262,34 +1262,33 @@
   // Traverse the document.
   syntax->SetPos(0);
   while (1) {
-    bool number;
-    ByteString word = syntax->GetNextWord(&number);
-    if (number) {
+    CPDF_SyntaxParser::WordResult word_result = syntax->GetNextWord();
+    if (word_result.is_number) {
       // The object number was read. Read the generation number.
-      word = syntax->GetNextWord(&number);
-      if (!number)
+      word_result = syntax->GetNextWord();
+      if (!word_result.is_number)
         break;
 
-      word = syntax->GetNextWord(nullptr);
-      if (word != "obj")
+      word_result = syntax->GetNextWord();
+      if (word_result.word != "obj")
         break;
 
       syntax->GetObjectBody(nullptr);
 
-      word = syntax->GetNextWord(nullptr);
-      if (word != "endobj")
+      word_result = syntax->GetNextWord();
+      if (word_result.word != "endobj")
         break;
-    } else if (word == "trailer") {
+    } else if (word_result.word == "trailer") {
       syntax->GetObjectBody(nullptr);
-    } else if (word == "startxref") {
-      syntax->GetNextWord(nullptr);
-    } else if (word == "xref") {
+    } else if (word_result.word == "startxref") {
+      syntax->GetNextWord();
+    } else if (word_result.word == "xref") {
       while (1) {
-        word = syntax->GetNextWord(nullptr);
-        if (word.IsEmpty() || word == "startxref")
+        word_result = syntax->GetNextWord();
+        if (word_result.word.IsEmpty() || word_result.word == "startxref")
           break;
       }
-      syntax->GetNextWord(nullptr);
+      syntax->GetNextWord();
     } else {
       break;
     }