| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 PDFium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| 6 | |
| 7 #include "core/src/fpdfapi/fpdf_parser/cpdf_hint_tables.h" | |
| 8 | |
| 9 #include "core/include/fxcrt/fx_safe_types.h" | |
| 10 #include "core/include/fpdfapi/cpdf_array.h" | |
| 11 #include "core/include/fpdfapi/cpdf_dictionary.h" | |
| 12 #include "core/include/fpdfapi/cpdf_stream.h" | |
| 13 #include "core/src/fpdfapi/fpdf_parser/cpdf_data_avail.h" | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 bool CanReadFromBitStream(const CFX_BitStream* hStream, | |
| 18 const FX_SAFE_DWORD& num_bits) { | |
| 19 return num_bits.IsValid() && | |
| 20 hStream->BitsRemaining() >= num_bits.ValueOrDie(); | |
| 21 } | |
| 22 | |
| 23 } // namespace | |
| 24 | |
| 25 CPDF_HintTables::~CPDF_HintTables() { | |
| 26 m_dwDeltaNObjsArray.RemoveAll(); | |
| 27 m_dwNSharedObjsArray.RemoveAll(); | |
| 28 m_dwSharedObjNumArray.RemoveAll(); | |
| 29 m_dwIdentifierArray.RemoveAll(); | |
| 30 } | |
| 31 | |
| 32 FX_DWORD CPDF_HintTables::GetItemLength( | |
| 33 int index, | |
| 34 const std::vector<FX_FILESIZE>& szArray) { | |
| 35 if (index < 0 || szArray.size() < 2 || | |
| 36 static_cast<size_t>(index) > szArray.size() - 2 || | |
| 37 szArray[index] > szArray[index + 1]) { | |
| 38 return 0; | |
| 39 } | |
| 40 return szArray[index + 1] - szArray[index]; | |
| 41 } | |
| 42 | |
| 43 FX_BOOL CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { | |
| 44 if (!hStream || hStream->IsEOF()) | |
| 45 return FALSE; | |
| 46 | |
| 47 int nStreamOffset = ReadPrimaryHintStreamOffset(); | |
| 48 int nStreamLen = ReadPrimaryHintStreamLength(); | |
| 49 if (nStreamOffset < 0 || nStreamLen < 1) | |
| 50 return FALSE; | |
| 51 | |
| 52 const FX_DWORD kHeaderSize = 288; | |
| 53 if (hStream->BitsRemaining() < kHeaderSize) | |
| 54 return FALSE; | |
| 55 | |
| 56 // Item 1: The least number of objects in a page. | |
| 57 FX_DWORD dwObjLeastNum = hStream->GetBits(32); | |
| 58 | |
| 59 // Item 2: The location of the first page's page object. | |
| 60 FX_DWORD dwFirstObjLoc = hStream->GetBits(32); | |
| 61 if (dwFirstObjLoc > nStreamOffset) { | |
| 62 FX_SAFE_DWORD safeLoc = pdfium::base::checked_cast<FX_DWORD>(nStreamLen); | |
| 63 safeLoc += dwFirstObjLoc; | |
| 64 if (!safeLoc.IsValid()) | |
| 65 return FALSE; | |
| 66 m_szFirstPageObjOffset = | |
| 67 pdfium::base::checked_cast<FX_FILESIZE>(safeLoc.ValueOrDie()); | |
| 68 } else { | |
| 69 m_szFirstPageObjOffset = | |
| 70 pdfium::base::checked_cast<FX_FILESIZE>(dwFirstObjLoc); | |
| 71 } | |
| 72 | |
| 73 // Item 3: The number of bits needed to represent the difference | |
| 74 // between the greatest and least number of objects in a page. | |
| 75 FX_DWORD dwDeltaObjectsBits = hStream->GetBits(16); | |
| 76 | |
| 77 // Item 4: The least length of a page in bytes. | |
| 78 FX_DWORD dwPageLeastLen = hStream->GetBits(32); | |
| 79 | |
| 80 // Item 5: The number of bits needed to represent the difference | |
| 81 // between the greatest and least length of a page, in bytes. | |
| 82 FX_DWORD dwDeltaPageLenBits = hStream->GetBits(16); | |
| 83 | |
| 84 // Skip Item 6, 7, 8, 9 total 96 bits. | |
| 85 hStream->SkipBits(96); | |
| 86 | |
| 87 // Item 10: The number of bits needed to represent the greatest | |
| 88 // number of shared object references. | |
| 89 FX_DWORD dwSharedObjBits = hStream->GetBits(16); | |
| 90 | |
| 91 // Item 11: The number of bits needed to represent the numerically | |
| 92 // greatest shared object identifier used by the pages. | |
| 93 FX_DWORD dwSharedIdBits = hStream->GetBits(16); | |
| 94 | |
| 95 // Item 12: The number of bits needed to represent the numerator of | |
| 96 // the fractional position for each shared object reference. For each | |
| 97 // shared object referenced from a page, there is an indication of | |
| 98 // where in the page's content stream the object is first referenced. | |
| 99 FX_DWORD dwSharedNumeratorBits = hStream->GetBits(16); | |
| 100 | |
| 101 // Item 13: Skip Item 13 which has 16 bits. | |
| 102 hStream->SkipBits(16); | |
| 103 | |
| 104 CPDF_Object* pPageNum = m_pLinearizedDict->GetElementValue("N"); | |
| 105 int nPages = pPageNum ? pPageNum->GetInteger() : 0; | |
| 106 if (nPages < 1) | |
| 107 return FALSE; | |
| 108 | |
| 109 FX_SAFE_DWORD required_bits = dwDeltaObjectsBits; | |
| 110 required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages); | |
| 111 if (!CanReadFromBitStream(hStream, required_bits)) | |
| 112 return FALSE; | |
| 113 | |
| 114 for (int i = 0; i < nPages; ++i) { | |
| 115 FX_SAFE_DWORD safeDeltaObj = hStream->GetBits(dwDeltaObjectsBits); | |
| 116 safeDeltaObj += dwObjLeastNum; | |
| 117 if (!safeDeltaObj.IsValid()) | |
| 118 return FALSE; | |
| 119 m_dwDeltaNObjsArray.Add(safeDeltaObj.ValueOrDie()); | |
| 120 } | |
| 121 hStream->ByteAlign(); | |
| 122 | |
| 123 required_bits = dwDeltaPageLenBits; | |
| 124 required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages); | |
| 125 if (!CanReadFromBitStream(hStream, required_bits)) | |
| 126 return FALSE; | |
| 127 | |
| 128 CFX_DWordArray dwPageLenArray; | |
| 129 for (int i = 0; i < nPages; ++i) { | |
| 130 FX_SAFE_DWORD safePageLen = hStream->GetBits(dwDeltaPageLenBits); | |
| 131 safePageLen += dwPageLeastLen; | |
| 132 if (!safePageLen.IsValid()) | |
| 133 return FALSE; | |
| 134 dwPageLenArray.Add(safePageLen.ValueOrDie()); | |
| 135 } | |
| 136 | |
| 137 CPDF_Object* pOffsetE = m_pLinearizedDict->GetElementValue("E"); | |
| 138 int nOffsetE = pOffsetE ? pOffsetE->GetInteger() : -1; | |
| 139 if (nOffsetE < 0) | |
| 140 return FALSE; | |
| 141 | |
| 142 CPDF_Object* pFirstPageNum = m_pLinearizedDict->GetElementValue("P"); | |
| 143 int nFirstPageNum = pFirstPageNum ? pFirstPageNum->GetInteger() : 0; | |
| 144 for (int i = 0; i < nPages; ++i) { | |
| 145 if (i == nFirstPageNum) { | |
| 146 m_szPageOffsetArray.push_back(m_szFirstPageObjOffset); | |
| 147 } else if (i == nFirstPageNum + 1) { | |
| 148 if (i == 1) { | |
| 149 m_szPageOffsetArray.push_back(nOffsetE); | |
| 150 } else { | |
| 151 m_szPageOffsetArray.push_back(m_szPageOffsetArray[i - 2] + | |
| 152 dwPageLenArray[i - 2]); | |
| 153 } | |
| 154 } else { | |
| 155 if (i == 0) { | |
| 156 m_szPageOffsetArray.push_back(nOffsetE); | |
| 157 } else { | |
| 158 m_szPageOffsetArray.push_back(m_szPageOffsetArray[i - 1] + | |
| 159 dwPageLenArray[i - 1]); | |
| 160 } | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 if (nPages > 0) { | |
| 165 m_szPageOffsetArray.push_back(m_szPageOffsetArray[nPages - 1] + | |
| 166 dwPageLenArray[nPages - 1]); | |
| 167 } | |
| 168 hStream->ByteAlign(); | |
| 169 | |
| 170 // Number of shared objects. | |
| 171 required_bits = dwSharedObjBits; | |
| 172 required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages); | |
| 173 if (!CanReadFromBitStream(hStream, required_bits)) | |
| 174 return FALSE; | |
| 175 | |
| 176 for (int i = 0; i < nPages; i++) | |
| 177 m_dwNSharedObjsArray.Add(hStream->GetBits(dwSharedObjBits)); | |
| 178 hStream->ByteAlign(); | |
| 179 | |
| 180 // Array of identifiers, size = nshared_objects. | |
| 181 for (int i = 0; i < nPages; i++) { | |
| 182 required_bits = dwSharedIdBits; | |
| 183 required_bits *= m_dwNSharedObjsArray[i]; | |
| 184 if (!CanReadFromBitStream(hStream, required_bits)) | |
| 185 return FALSE; | |
| 186 | |
| 187 for (int j = 0; j < m_dwNSharedObjsArray[i]; j++) | |
| 188 m_dwIdentifierArray.Add(hStream->GetBits(dwSharedIdBits)); | |
| 189 } | |
| 190 hStream->ByteAlign(); | |
| 191 | |
| 192 for (int i = 0; i < nPages; i++) { | |
| 193 FX_SAFE_DWORD safeSize = m_dwNSharedObjsArray[i]; | |
| 194 safeSize *= dwSharedNumeratorBits; | |
| 195 if (!CanReadFromBitStream(hStream, safeSize)) | |
| 196 return FALSE; | |
| 197 | |
| 198 hStream->SkipBits(safeSize.ValueOrDie()); | |
| 199 } | |
| 200 hStream->ByteAlign(); | |
| 201 | |
| 202 FX_SAFE_DWORD safeTotalPageLen = pdfium::base::checked_cast<FX_DWORD>(nPages); | |
| 203 safeTotalPageLen *= dwDeltaPageLenBits; | |
| 204 if (!CanReadFromBitStream(hStream, safeTotalPageLen)) | |
| 205 return FALSE; | |
| 206 | |
| 207 hStream->SkipBits(safeTotalPageLen.ValueOrDie()); | |
| 208 hStream->ByteAlign(); | |
| 209 return TRUE; | |
| 210 } | |
| 211 | |
| 212 FX_BOOL CPDF_HintTables::ReadSharedObjHintTable(CFX_BitStream* hStream, | |
| 213 FX_DWORD offset) { | |
| 214 if (!hStream || hStream->IsEOF()) | |
| 215 return FALSE; | |
| 216 | |
| 217 int nStreamOffset = ReadPrimaryHintStreamOffset(); | |
| 218 int nStreamLen = ReadPrimaryHintStreamLength(); | |
| 219 if (nStreamOffset < 0 || nStreamLen < 1) | |
| 220 return FALSE; | |
| 221 | |
| 222 FX_SAFE_DWORD bit_offset = offset; | |
| 223 bit_offset *= 8; | |
| 224 if (!bit_offset.IsValid() || hStream->GetPos() > bit_offset.ValueOrDie()) | |
| 225 return FALSE; | |
| 226 hStream->SkipBits(bit_offset.ValueOrDie() - hStream->GetPos()); | |
| 227 | |
| 228 const FX_DWORD kHeaderSize = 192; | |
| 229 if (hStream->BitsRemaining() < kHeaderSize) | |
| 230 return FALSE; | |
| 231 | |
| 232 // Item 1: The object number of the first object in the shared objects | |
| 233 // section. | |
| 234 FX_DWORD dwFirstSharedObjNum = hStream->GetBits(32); | |
| 235 | |
| 236 // Item 2: The location of the first object in the shared objects section. | |
| 237 FX_DWORD dwFirstSharedObjLoc = hStream->GetBits(32); | |
| 238 if (dwFirstSharedObjLoc > nStreamOffset) | |
| 239 dwFirstSharedObjLoc += nStreamLen; | |
| 240 | |
| 241 // Item 3: The number of shared object entries for the first page. | |
| 242 m_nFirstPageSharedObjs = hStream->GetBits(32); | |
| 243 | |
| 244 // Item 4: The number of shared object entries for the shared objects | |
| 245 // section, including the number of shared object entries for the first page. | |
| 246 FX_DWORD dwSharedObjTotal = hStream->GetBits(32); | |
| 247 | |
| 248 // Item 5: The number of bits needed to represent the greatest number of | |
| 249 // objects in a shared object group. Skipped. | |
| 250 hStream->SkipBits(16); | |
| 251 | |
| 252 // Item 6: The least length of a shared object group in bytes. | |
| 253 FX_DWORD dwGroupLeastLen = hStream->GetBits(32); | |
| 254 | |
| 255 // Item 7: The number of bits needed to represent the difference between the | |
| 256 // greatest and least length of a shared object group, in bytes. | |
| 257 FX_DWORD dwDeltaGroupLen = hStream->GetBits(16); | |
| 258 CPDF_Object* pFirstPageObj = m_pLinearizedDict->GetElementValue("O"); | |
| 259 int nFirstPageObjNum = pFirstPageObj ? pFirstPageObj->GetInteger() : -1; | |
| 260 if (nFirstPageObjNum < 0) | |
| 261 return FALSE; | |
| 262 | |
| 263 FX_DWORD dwPrevObjLen = 0; | |
| 264 FX_DWORD dwCurObjLen = 0; | |
| 265 FX_SAFE_DWORD required_bits = dwSharedObjTotal; | |
| 266 required_bits *= dwDeltaGroupLen; | |
| 267 if (!CanReadFromBitStream(hStream, required_bits)) | |
| 268 return FALSE; | |
| 269 | |
| 270 for (FX_DWORD i = 0; i < dwSharedObjTotal; ++i) { | |
| 271 dwPrevObjLen = dwCurObjLen; | |
| 272 FX_SAFE_DWORD safeObjLen = hStream->GetBits(dwDeltaGroupLen); | |
| 273 safeObjLen += dwGroupLeastLen; | |
| 274 if (!safeObjLen.IsValid()) | |
| 275 return FALSE; | |
| 276 | |
| 277 dwCurObjLen = safeObjLen.ValueOrDie(); | |
| 278 if (i < m_nFirstPageSharedObjs) { | |
| 279 m_dwSharedObjNumArray.Add(nFirstPageObjNum + i); | |
| 280 if (i == 0) | |
| 281 m_szSharedObjOffsetArray.push_back(m_szFirstPageObjOffset); | |
| 282 } else { | |
| 283 FX_SAFE_DWORD safeObjNum = dwFirstSharedObjNum; | |
| 284 safeObjNum += i - m_nFirstPageSharedObjs; | |
| 285 if (!safeObjNum.IsValid()) | |
| 286 return FALSE; | |
| 287 | |
| 288 m_dwSharedObjNumArray.Add(safeObjNum.ValueOrDie()); | |
| 289 if (i == m_nFirstPageSharedObjs) { | |
| 290 m_szSharedObjOffsetArray.push_back( | |
| 291 pdfium::base::checked_cast<int32_t>(dwFirstSharedObjLoc)); | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 if (i != 0 && i != m_nFirstPageSharedObjs) { | |
| 296 FX_SAFE_INT32 safeLoc = pdfium::base::checked_cast<int32_t>(dwPrevObjLen); | |
| 297 safeLoc += m_szSharedObjOffsetArray[i - 1]; | |
| 298 if (!safeLoc.IsValid()) | |
| 299 return FALSE; | |
| 300 | |
| 301 m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 if (dwSharedObjTotal > 0) { | |
| 306 FX_SAFE_INT32 safeLoc = pdfium::base::checked_cast<int32_t>(dwCurObjLen); | |
| 307 safeLoc += m_szSharedObjOffsetArray[dwSharedObjTotal - 1]; | |
| 308 if (!safeLoc.IsValid()) | |
| 309 return FALSE; | |
| 310 | |
| 311 m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); | |
| 312 } | |
| 313 | |
| 314 hStream->ByteAlign(); | |
| 315 if (hStream->BitsRemaining() < dwSharedObjTotal) | |
| 316 return FALSE; | |
| 317 | |
| 318 hStream->SkipBits(dwSharedObjTotal); | |
| 319 hStream->ByteAlign(); | |
| 320 return TRUE; | |
| 321 } | |
| 322 | |
| 323 FX_BOOL CPDF_HintTables::GetPagePos(int index, | |
| 324 FX_FILESIZE& szPageStartPos, | |
| 325 FX_FILESIZE& szPageLength, | |
| 326 FX_DWORD& dwObjNum) { | |
| 327 if (!m_pLinearizedDict) | |
| 328 return FALSE; | |
| 329 | |
| 330 szPageStartPos = m_szPageOffsetArray[index]; | |
| 331 szPageLength = GetItemLength(index, m_szPageOffsetArray); | |
| 332 | |
| 333 CPDF_Object* pFirstPageNum = m_pLinearizedDict->GetElementValue("P"); | |
| 334 int nFirstPageNum = pFirstPageNum ? pFirstPageNum->GetInteger() : 0; | |
| 335 | |
| 336 CPDF_Object* pFirstPageObjNum = m_pLinearizedDict->GetElementValue("O"); | |
| 337 if (!pFirstPageObjNum) | |
| 338 return FALSE; | |
| 339 | |
| 340 int nFirstPageObjNum = pFirstPageObjNum->GetInteger(); | |
| 341 if (index == nFirstPageNum) { | |
| 342 dwObjNum = nFirstPageObjNum; | |
| 343 return TRUE; | |
| 344 } | |
| 345 | |
| 346 // The object number of remaining pages starts from 1. | |
| 347 dwObjNum = 1; | |
| 348 for (int i = 0; i < index; ++i) { | |
| 349 if (i == nFirstPageNum) | |
| 350 continue; | |
| 351 dwObjNum += m_dwDeltaNObjsArray[i]; | |
| 352 } | |
| 353 return TRUE; | |
| 354 } | |
| 355 | |
| 356 IPDF_DataAvail::DocAvailStatus CPDF_HintTables::CheckPage( | |
| 357 int index, | |
| 358 IPDF_DataAvail::DownloadHints* pHints) { | |
| 359 if (!m_pLinearizedDict || !pHints) | |
| 360 return IPDF_DataAvail::DataError; | |
| 361 | |
| 362 CPDF_Object* pFirstAvailPage = m_pLinearizedDict->GetElementValue("P"); | |
| 363 int nFirstAvailPage = pFirstAvailPage ? pFirstAvailPage->GetInteger() : 0; | |
| 364 if (index == nFirstAvailPage) | |
| 365 return IPDF_DataAvail::DataAvailable; | |
| 366 | |
| 367 FX_DWORD dwLength = GetItemLength(index, m_szPageOffsetArray); | |
| 368 // If two pages have the same offset, it should be treated as an error. | |
| 369 if (!dwLength) | |
| 370 return IPDF_DataAvail::DataError; | |
| 371 | |
| 372 if (!m_pDataAvail->IsDataAvail(m_szPageOffsetArray[index], dwLength, pHints)) | |
| 373 return IPDF_DataAvail::DataNotAvailable; | |
| 374 | |
| 375 // Download data of shared objects in the page. | |
| 376 FX_DWORD offset = 0; | |
| 377 for (int i = 0; i < index; ++i) | |
| 378 offset += m_dwNSharedObjsArray[i]; | |
| 379 | |
| 380 CPDF_Object* pFirstPageObj = m_pLinearizedDict->GetElementValue("O"); | |
| 381 int nFirstPageObjNum = pFirstPageObj ? pFirstPageObj->GetInteger() : -1; | |
| 382 if (nFirstPageObjNum < 0) | |
| 383 return IPDF_DataAvail::DataError; | |
| 384 | |
| 385 FX_DWORD dwIndex = 0; | |
| 386 FX_DWORD dwObjNum = 0; | |
| 387 for (int j = 0; j < m_dwNSharedObjsArray[index]; ++j) { | |
| 388 dwIndex = m_dwIdentifierArray[offset + j]; | |
| 389 if (dwIndex >= m_dwSharedObjNumArray.GetSize()) | |
| 390 return IPDF_DataAvail::DataNotAvailable; | |
| 391 | |
| 392 dwObjNum = m_dwSharedObjNumArray[dwIndex]; | |
| 393 if (dwObjNum >= nFirstPageObjNum && | |
| 394 dwObjNum < nFirstPageObjNum + m_nFirstPageSharedObjs) { | |
| 395 continue; | |
| 396 } | |
| 397 | |
| 398 dwLength = GetItemLength(dwIndex, m_szSharedObjOffsetArray); | |
| 399 // If two objects have the same offset, it should be treated as an error. | |
| 400 if (!dwLength) | |
| 401 return IPDF_DataAvail::DataError; | |
| 402 | |
| 403 if (!m_pDataAvail->IsDataAvail(m_szSharedObjOffsetArray[dwIndex], dwLength, | |
| 404 pHints)) { | |
| 405 return IPDF_DataAvail::DataNotAvailable; | |
| 406 } | |
| 407 } | |
| 408 return IPDF_DataAvail::DataAvailable; | |
| 409 } | |
| 410 | |
| 411 FX_BOOL CPDF_HintTables::LoadHintStream(CPDF_Stream* pHintStream) { | |
| 412 if (!pHintStream || !m_pLinearizedDict) | |
| 413 return FALSE; | |
| 414 | |
| 415 CPDF_Dictionary* pDict = pHintStream->GetDict(); | |
| 416 CPDF_Object* pOffset = pDict ? pDict->GetElement("S") : nullptr; | |
| 417 if (!pOffset || !pOffset->IsNumber()) | |
| 418 return FALSE; | |
| 419 | |
| 420 int shared_hint_table_offset = pOffset->GetInteger(); | |
| 421 CPDF_StreamAcc acc; | |
| 422 acc.LoadAllData(pHintStream); | |
| 423 | |
| 424 FX_DWORD size = acc.GetSize(); | |
| 425 // The header section of page offset hint table is 36 bytes. | |
| 426 // The header section of shared object hint table is 24 bytes. | |
| 427 // Hint table has at least 60 bytes. | |
| 428 const FX_DWORD MIN_STREAM_LEN = 60; | |
| 429 if (size < MIN_STREAM_LEN || shared_hint_table_offset <= 0 || | |
| 430 size < shared_hint_table_offset) { | |
| 431 return FALSE; | |
| 432 } | |
| 433 | |
| 434 CFX_BitStream bs; | |
| 435 bs.Init(acc.GetData(), size); | |
| 436 return ReadPageHintTable(&bs) && | |
| 437 ReadSharedObjHintTable(&bs, pdfium::base::checked_cast<FX_DWORD>( | |
| 438 shared_hint_table_offset)); | |
| 439 } | |
| 440 | |
| 441 int CPDF_HintTables::ReadPrimaryHintStreamOffset() const { | |
| 442 if (!m_pLinearizedDict) | |
| 443 return -1; | |
| 444 | |
| 445 CPDF_Array* pRange = m_pLinearizedDict->GetArrayBy("H"); | |
| 446 if (!pRange) | |
| 447 return -1; | |
| 448 | |
| 449 CPDF_Object* pStreamOffset = pRange->GetElementValue(0); | |
| 450 if (!pStreamOffset) | |
| 451 return -1; | |
| 452 | |
| 453 return pStreamOffset->GetInteger(); | |
| 454 } | |
| 455 | |
| 456 int CPDF_HintTables::ReadPrimaryHintStreamLength() const { | |
| 457 if (!m_pLinearizedDict) | |
| 458 return -1; | |
| 459 | |
| 460 CPDF_Array* pRange = m_pLinearizedDict->GetArrayBy("H"); | |
| 461 if (!pRange) | |
| 462 return -1; | |
| 463 | |
| 464 CPDF_Object* pStreamLen = pRange->GetElementValue(1); | |
| 465 if (!pStreamLen) | |
| 466 return -1; | |
| 467 | |
| 468 return pStreamLen->GetInteger(); | |
| 469 } | |
| OLD | NEW |