Parse obj nums range within Hint tables for shared groups.

Change-Id: Ib22db6c57d2066ef70c0ef12e44d1e5eee6611a5
Reviewed-on: https://pdfium-review.googlesource.com/36410
Commit-Queue: Art Snake <art-snake@yandex-team.ru>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_hint_tables.cpp b/core/fpdfapi/parser/cpdf_hint_tables.cpp
index 04e673b..8d8aa32 100644
--- a/core/fpdfapi/parser/cpdf_hint_tables.cpp
+++ b/core/fpdfapi/parser/cpdf_hint_tables.cpp
@@ -233,6 +233,8 @@
   // Item 1: The object number of the first object in the shared objects
   // section.
   uint32_t dwFirstSharedObjNum = hStream->GetBits(32);
+  if (!dwFirstSharedObjNum)
+    return false;
 
   // Item 2: The location of the first object in the shared objects section.
   const FX_FILESIZE szFirstSharedObjLoc =
@@ -248,8 +250,8 @@
   uint32_t dwSharedObjTotal = hStream->GetBits(32);
 
   // Item 5: The number of bits needed to represent the greatest number of
-  // objects in a shared object group. Skipped.
-  hStream->SkipBits(16);
+  // objects in a shared object group.
+  uint32_t dwSharedObjNumBits = hStream->GetBits(16);
 
   // Item 6: The least length of a shared object group in bytes.
   uint32_t dwGroupLeastLen = hStream->GetBits(32);
@@ -285,6 +287,9 @@
   }
 
   m_SharedObjGroupInfos.resize(dwSharedObjTotal);
+  // Table F.6 –  Shared object hint table, shared object group entries:
+  // Item 1: A number that, when added to the least shared object
+  // group length.
   FX_SAFE_FILESIZE prev_shared_group_end_offset = m_szFirstPageObjOffset;
   for (uint32_t i = 0; i < dwSharedObjTotal; ++i) {
     if (i == m_nFirstPageSharedObjs)
@@ -304,10 +309,48 @@
   }
 
   hStream->ByteAlign();
-  if (hStream->BitsRemaining() < dwSharedObjTotal)
-    return false;
+  {
+    // Item 2: A flag indicating whether the shared object signature (item 3) is
+    // present.
+    uint32_t signature_count = 0;
+    for (uint32_t i = 0; i < dwSharedObjTotal; ++i) {
+      signature_count += hStream->GetBits(1);
+    }
+    hStream->ByteAlign();
+    // Item 3: (Only if item 2 is 1) The shared object signature, a 16-byte MD5
+    // hash that uniquely identifies the resource that the group of objects
+    // represents.
+    if (signature_count) {
+      required_bits = signature_count;
+      required_bits *= 128;
+      if (!CanReadFromBitStream(hStream, required_bits))
+        return false;
 
-  hStream->SkipBits(dwSharedObjTotal);
+      hStream->SkipBits(required_bits.ValueOrDie());
+      hStream->ByteAlign();
+    }
+  }
+  // Item 4: A number equal to 1 less than the number of objects in the group.
+  FX_SAFE_UINT32 cur_obj_num = m_pLinearized->GetFirstPageObjNum();
+  for (uint32_t i = 0; i < dwSharedObjTotal; ++i) {
+    if (i == m_nFirstPageSharedObjs)
+      cur_obj_num = dwFirstSharedObjNum;
+
+    FX_SAFE_UINT32 obj_count =
+        dwSharedObjNumBits ? hStream->GetBits(dwSharedObjNumBits) : 0;
+    obj_count += 1;
+    if (!obj_count.IsValid())
+      return false;
+
+    uint32_t obj_num = cur_obj_num.ValueOrDie();
+    cur_obj_num += obj_count.ValueOrDie();
+    if (!cur_obj_num.IsValid())
+      return false;
+
+    m_SharedObjGroupInfos[i].m_dwStartObjNum = obj_num;
+    m_SharedObjGroupInfos[i].m_dwObjectsCount = obj_count.ValueOrDie();
+  }
+
   hStream->ByteAlign();
   return true;
 }
diff --git a/core/fpdfapi/parser/cpdf_hint_tables.h b/core/fpdfapi/parser/cpdf_hint_tables.h
index 5b978f9..20ba9be 100644
--- a/core/fpdfapi/parser/cpdf_hint_tables.h
+++ b/core/fpdfapi/parser/cpdf_hint_tables.h
@@ -23,6 +23,8 @@
   struct SharedObjGroupInfo {
     FX_FILESIZE m_szOffset = 0;
     uint32_t m_dwLength = 0;
+    uint32_t m_dwObjectsCount = 0;
+    uint32_t m_dwStartObjNum = 0;
   };
 
   class PageInfo {
@@ -31,9 +33,9 @@
     ~PageInfo();
 
     void set_objects_count(uint32_t objects_count) {
-      m_nObjectsCount = objects_count;
+      m_dwObjectsCount = objects_count;
     }
-    uint32_t objects_count() const { return m_nObjectsCount; }
+    uint32_t objects_count() const { return m_dwObjectsCount; }
 
     void set_page_offset(FX_FILESIZE offset) { m_szOffset = offset; }
     FX_FILESIZE page_offset() const { return m_szOffset; }
@@ -55,7 +57,7 @@
     }
 
    private:
-    uint32_t m_nObjectsCount = 0;
+    uint32_t m_dwObjectsCount = 0;
     FX_FILESIZE m_szOffset = 0;
     uint32_t m_dwLength = 0;
     uint32_t m_dwStartObjNum = 0;
diff --git a/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp b/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp
index dba39f5..97ba434 100644
--- a/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp
@@ -130,21 +130,33 @@
 
   EXPECT_EQ(777, hint_tables->SharedGroupInfos()[0].m_szOffset);
   EXPECT_EQ(254u, hint_tables->SharedGroupInfos()[0].m_dwLength);
+  EXPECT_EQ(39u, hint_tables->SharedGroupInfos()[0].m_dwStartObjNum);
+  EXPECT_EQ(1u, hint_tables->SharedGroupInfos()[0].m_dwObjectsCount);
 
   EXPECT_EQ(1031, hint_tables->SharedGroupInfos()[1].m_szOffset);
   EXPECT_EQ(389u, hint_tables->SharedGroupInfos()[1].m_dwLength);
+  EXPECT_EQ(40u, hint_tables->SharedGroupInfos()[1].m_dwStartObjNum);
+  EXPECT_EQ(1u, hint_tables->SharedGroupInfos()[1].m_dwObjectsCount);
 
   EXPECT_EQ(1420, hint_tables->SharedGroupInfos()[2].m_szOffset);
   EXPECT_EQ(726u, hint_tables->SharedGroupInfos()[2].m_dwLength);
+  EXPECT_EQ(41u, hint_tables->SharedGroupInfos()[2].m_dwStartObjNum);
+  EXPECT_EQ(1u, hint_tables->SharedGroupInfos()[2].m_dwObjectsCount);
 
   EXPECT_EQ(2146, hint_tables->SharedGroupInfos()[3].m_szOffset);
   EXPECT_EQ(290u, hint_tables->SharedGroupInfos()[3].m_dwLength);
+  EXPECT_EQ(42u, hint_tables->SharedGroupInfos()[3].m_dwStartObjNum);
+  EXPECT_EQ(1u, hint_tables->SharedGroupInfos()[3].m_dwObjectsCount);
 
   EXPECT_EQ(2436, hint_tables->SharedGroupInfos()[4].m_szOffset);
   EXPECT_EQ(2669u, hint_tables->SharedGroupInfos()[4].m_dwLength);
+  EXPECT_EQ(43u, hint_tables->SharedGroupInfos()[4].m_dwStartObjNum);
+  EXPECT_EQ(1u, hint_tables->SharedGroupInfos()[4].m_dwObjectsCount);
 
   EXPECT_EQ(10939, hint_tables->SharedGroupInfos()[5].m_szOffset);
   EXPECT_EQ(544u, hint_tables->SharedGroupInfos()[5].m_dwLength);
+  EXPECT_EQ(4u, hint_tables->SharedGroupInfos()[5].m_dwStartObjNum);
+  EXPECT_EQ(1u, hint_tables->SharedGroupInfos()[5].m_dwObjectsCount);
 }
 
 TEST_F(CPDF_HintTablesTest, FirstPageOffset) {