Remove CPDF_CrossRefTable::ObjectType::kObjStream

There's really no such type. There is, however, a normal object
which we've flagged as being an object stream. Make this an attribute
of all types of ObjectInfo to steal byte otherwise used as padding.

Change-Id: I5caa5e2c3b3890c7c571a38b7de32fbf63f4da69
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/114770
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_cross_ref_table.cpp b/core/fpdfapi/parser/cpdf_cross_ref_table.cpp
index 0d9c14f..c0dc754 100644
--- a/core/fpdfapi/parser/cpdf_cross_ref_table.cpp
+++ b/core/fpdfapi/parser/cpdf_cross_ref_table.cpp
@@ -44,19 +44,22 @@
   if (info.gennum > 0)
     return;
 
-  if (info.type == ObjectType::kObjStream)
+  // Don't add known object streams to object streams.
+  if (info.is_object_stream_flag) {
     return;
+  }
 
   info.type = ObjectType::kCompressed;
   info.archive.obj_num = archive_obj_num;
   info.archive.obj_index = archive_obj_index;
   info.gennum = 0;
 
-  objects_info_[archive_obj_num].type = ObjectType::kObjStream;
+  objects_info_[archive_obj_num].is_object_stream_flag = true;
 }
 
 void CPDF_CrossRefTable::AddNormal(uint32_t obj_num,
                                    uint16_t gen_num,
+                                   bool is_object_stream,
                                    FX_FILESIZE pos) {
   CHECK_LT(obj_num, CPDF_Parser::kMaxObjectNumber);
 
@@ -67,9 +70,8 @@
   if (info.type == ObjectType::kCompressed && gen_num == 0)
     return;
 
-  if (info.type != ObjectType::kObjStream)
-    info.type = ObjectType::kNormal;
-
+  info.type = ObjectType::kNormal;
+  info.is_object_stream_flag |= is_object_stream;
   info.gennum = gen_num;
   info.pos = pos;
 }
@@ -129,9 +131,10 @@
   auto new_it = new_objects_info.begin();
   while (cur_it != objects_info_.end() && new_it != new_objects_info.end()) {
     if (cur_it->first == new_it->first) {
-      if (cur_it->second.type == ObjectType::kObjStream &&
-          new_it->second.type == ObjectType::kNormal) {
-        new_it->second.type = ObjectType::kObjStream;
+      if (new_it->second.type == ObjectType::kNormal &&
+          cur_it->second.type == ObjectType::kNormal &&
+          cur_it->second.is_object_stream_flag) {
+        new_it->second.is_object_stream_flag = true;
       }
       ++cur_it;
       ++new_it;
diff --git a/core/fpdfapi/parser/cpdf_cross_ref_table.h b/core/fpdfapi/parser/cpdf_cross_ref_table.h
index 5fdc415..725d407 100644
--- a/core/fpdfapi/parser/cpdf_cross_ref_table.h
+++ b/core/fpdfapi/parser/cpdf_cross_ref_table.h
@@ -17,16 +17,17 @@
 
 class CPDF_CrossRefTable {
  public:
+  // See ISO 32000-1:2008 table 18.
   enum class ObjectType : uint8_t {
-    kFree = 0x00,
-    kNormal = 0x01,
-    kCompressed = 0x02,
-    kObjStream = 0xFF,
-    kNull = kObjStream,
+    kFree = 0,
+    kNormal = 1,
+    kCompressed = 2,
+    kNull = 3,  // Higher values reserved, treat all as the null object.
   };
 
   struct ObjectInfo {
     ObjectType type = ObjectType::kFree;
+    bool is_object_stream_flag = false;
     uint16_t gennum = 0;
     // If `type` is `ObjectType::kCompressed`, `archive` should be used.
     // If `type` is `ObjectType::kNormal`, `pos` should be used.
@@ -53,7 +54,10 @@
   void AddCompressed(uint32_t obj_num,
                      uint32_t archive_obj_num,
                      uint32_t archive_obj_index);
-  void AddNormal(uint32_t obj_num, uint16_t gen_num, FX_FILESIZE pos);
+  void AddNormal(uint32_t obj_num,
+                 uint16_t gen_num,
+                 bool is_object_stream,
+                 FX_FILESIZE pos);
   void SetFree(uint32_t obj_num);
 
   void SetTrailer(RetainPtr<CPDF_Dictionary> trailer,
diff --git a/core/fpdfapi/parser/cpdf_parser.cpp b/core/fpdfapi/parser/cpdf_parser.cpp
index c8136e7..f1d9cbc 100644
--- a/core/fpdfapi/parser/cpdf_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_parser.cpp
@@ -652,13 +652,17 @@
           m_CrossRefTable->SetFree(obj.obj_num);
         break;
       case ObjectType::kNormal:
-      case ObjectType::kObjStream:
-        m_CrossRefTable->AddNormal(obj.obj_num, obj.info.gennum, obj.info.pos);
+        m_CrossRefTable->AddNormal(obj.obj_num, obj.info.gennum,
+                                   obj.info.is_object_stream_flag,
+                                   obj.info.pos);
         break;
       case ObjectType::kCompressed:
         m_CrossRefTable->AddCompressed(obj.obj_num, obj.info.archive.obj_num,
                                        obj.info.archive.obj_index);
         break;
+      case ObjectType::kNull:
+        // Ignored.
+        break;
     }
   }
 }
@@ -745,7 +749,8 @@
       }
 
       if (obj_num < kMaxObjectNumber) {
-        cross_ref_table->AddNormal(obj_num, gen_num, obj_pos);
+        cross_ref_table->AddNormal(obj_num, gen_num, /*is_object_stream=*/false,
+                                   obj_pos);
         const auto object_stream =
             CPDF_ObjectStream::Create(std::move(pStream));
         if (object_stream) {
@@ -891,7 +896,8 @@
   if (existing_type == ObjectType::kNull) {
     const uint32_t offset = GetSecondXRefStreamEntry(entry_span, field_widths);
     if (pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(offset))
-      m_CrossRefTable->AddNormal(obj_num, 0, offset);
+      m_CrossRefTable->AddNormal(obj_num, 0, /*is_object_stream=*/false,
+                                 offset);
     return;
   }
 
@@ -907,7 +913,8 @@
   if (type == ObjectType::kNormal) {
     const uint32_t offset = GetSecondXRefStreamEntry(entry_span, field_widths);
     if (pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(offset))
-      m_CrossRefTable->AddNormal(obj_num, 0, offset);
+      m_CrossRefTable->AddNormal(obj_num, 0, /*is_object_stream=*/false,
+                                 offset);
     return;
   }
 
@@ -1028,7 +1035,7 @@
     return it->second.get();
 
   const auto* info = m_CrossRefTable->GetObjectInfo(object_number);
-  if (!info || info->type != ObjectType::kObjStream) {
+  if (!info || !info->is_object_stream_flag) {
     return nullptr;
   }
 
diff --git a/core/fpdfapi/parser/cpdf_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_parser_unittest.cpp
index 801217f..114fb29 100644
--- a/core/fpdfapi/parser/cpdf_parser_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_parser_unittest.cpp
@@ -66,7 +66,7 @@
     case CPDF_CrossRefTable::ObjectType::kCompressed:
       return lhs.archive.obj_num == rhs.archive.obj_num &&
              lhs.archive.obj_index == rhs.archive.obj_index;
-    case CPDF_CrossRefTable::ObjectType::kObjStream:
+    case CPDF_CrossRefTable::ObjectType::kNull:
       return false;
   }
 }
@@ -81,14 +81,15 @@
       os << "Free object";
       break;
     case CPDF_CrossRefTable::ObjectType::kNormal:
-      os << "Normal object, pos: " << info.pos;
+      os << "Normal object, pos: " << info.pos
+         << ", obj_stream=" << info.is_object_stream_flag;
       break;
     case CPDF_CrossRefTable::ObjectType::kCompressed:
       os << "Compressed object, archive obj_num: " << info.archive.obj_num
          << ", archive obj_index: " << info.archive.obj_index;
       break;
-    case CPDF_CrossRefTable::ObjectType::kObjStream:
-      os << "ObjectStream object";
+    case CPDF_CrossRefTable::ObjectType::kNull:
+      os << "Null object";
       break;
   }
   os << ", gennum: " << info.gennum << ")";