blob: abda2c5e371a5c223f974b561a8700d572c32823 [file] [log] [blame]
// Copyright 2016 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#ifndef CORE_FPDFAPI_PARSER_CPDF_PARSER_H_
#define CORE_FPDFAPI_PARSER_CPDF_PARSER_H_
#include <stddef.h>
#include <stdint.h>
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "core/fpdfapi/parser/cpdf_cross_ref_table.h"
#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h"
#include "core/fxcrt/bytestring.h"
#include "core/fxcrt/fx_types.h"
#include "core/fxcrt/retain_ptr.h"
#include "core/fxcrt/unowned_ptr.h"
class CPDF_Array;
class CPDF_Dictionary;
class CPDF_LinearizedHeader;
class CPDF_Object;
class CPDF_ObjectStream;
class CPDF_ReadValidator;
class CPDF_SecurityHandler;
class CPDF_SyntaxParser;
class IFX_ArchiveStream;
class IFX_SeekableReadStream;
class CPDF_Parser {
public:
using ObjectType = CPDF_CrossRefTable::ObjectType;
using ObjectInfo = CPDF_CrossRefTable::ObjectInfo;
class ParsedObjectsHolder : public CPDF_IndirectObjectHolder {
public:
virtual bool TryInit() = 0;
};
enum Error {
SUCCESS = 0,
FILE_ERROR,
FORMAT_ERROR,
PASSWORD_ERROR,
HANDLER_ERROR
};
// A limit on the maximum object number in the xref table. Theoretical limits
// are higher, but this may be large enough in practice.
// Note: This was 1M, but https://crbug.com/910009 encountered a PDF with
// object numbers in the 1.7M range. The PDF only has 10K objects, but they
// are non-consecutive.
static constexpr uint32_t kMaxObjectNumber = 4 * 1024 * 1024;
static constexpr size_t kInvalidPos = std::numeric_limits<size_t>::max();
explicit CPDF_Parser(ParsedObjectsHolder* holder);
CPDF_Parser();
~CPDF_Parser();
Error StartParse(RetainPtr<IFX_SeekableReadStream> pFile,
const ByteString& password);
Error StartLinearizedParse(RetainPtr<CPDF_ReadValidator> validator,
const ByteString& password);
void SetPassword(const ByteString& password) { m_Password = password; }
ByteString GetPassword() const { return m_Password; }
// Take the GetPassword() value and encode it, if necessary, based on the
// password encoding conversion.
ByteString GetEncodedPassword() const;
const CPDF_Dictionary* GetTrailer() const;
CPDF_Dictionary* GetMutableTrailerForTesting();
uint32_t GetTrailerObjectNumber() const;
// Returns a new trailer which combines the last read trailer with the /Root
// and /Info from previous ones.
RetainPtr<CPDF_Dictionary> GetCombinedTrailer() const;
FX_FILESIZE GetLastXRefOffset() const { return m_LastXRefOffset; }
uint32_t GetPermissions(bool get_owner_perms) const;
uint32_t GetRootObjNum() const;
uint32_t GetInfoObjNum() const;
RetainPtr<const CPDF_Array> GetIDArray() const;
RetainPtr<const CPDF_Dictionary> GetRoot() const;
RetainPtr<const CPDF_Dictionary> GetEncryptDict() const;
RetainPtr<CPDF_Object> ParseIndirectObject(uint32_t objnum);
uint32_t GetLastObjNum() const;
bool IsValidObjectNumber(uint32_t objnum) const;
FX_FILESIZE GetObjectPositionOrZero(uint32_t objnum) const;
bool IsObjectFreeOrNull(uint32_t objnum) const;
const RetainPtr<CPDF_SecurityHandler>& GetSecurityHandler() const {
return m_pSecurityHandler;
}
bool IsObjectFree(uint32_t objnum) const;
int GetFileVersion() const { return m_FileVersion; }
bool IsXRefStream() const { return m_bXRefStream; }
RetainPtr<CPDF_Object> ParseIndirectObjectAt(FX_FILESIZE pos,
uint32_t objnum);
FX_FILESIZE GetDocumentSize() const;
uint32_t GetFirstPageNo() const;
const CPDF_LinearizedHeader* GetLinearizedHeader() const {
return m_pLinearized.get();
}
const CPDF_CrossRefTable* GetCrossRefTable() const {
return m_CrossRefTable.get();
}
bool xref_table_rebuilt() const { return m_bXRefTableRebuilt; }
std::vector<unsigned int> GetTrailerEnds();
bool WriteToArchive(IFX_ArchiveStream* archive, FX_FILESIZE src_size);
void SetLinearizedHeaderForTesting(
std::unique_ptr<CPDF_LinearizedHeader> pLinearized);
protected:
bool LoadCrossRefV4(FX_FILESIZE pos, bool bSkip);
bool RebuildCrossRef();
Error StartParseInternal();
FX_FILESIZE ParseStartXRef();
std::unique_ptr<CPDF_LinearizedHeader> ParseLinearizedHeader();
void SetSyntaxParserForTesting(std::unique_ptr<CPDF_SyntaxParser> parser);
private:
friend class CPDF_DataAvail;
struct CrossRefObjData {
uint32_t obj_num = 0;
ObjectInfo info;
};
bool LoadAllCrossRefV4(FX_FILESIZE xref_offset);
bool LoadAllCrossRefV5(FX_FILESIZE xref_offset);
bool LoadCrossRefV5(FX_FILESIZE* pos,
bool is_main_xref,
bool overwrite_existing);
void ProcessCrossRefV5Entry(pdfium::span<const uint8_t> entry_span,
pdfium::span<const uint32_t> field_widths,
uint32_t obj_num,
bool overwrite_existing);
RetainPtr<CPDF_Dictionary> LoadTrailerV4();
Error SetEncryptHandler();
void ReleaseEncryptHandler();
bool LoadLinearizedAllCrossRefV4(FX_FILESIZE main_xref_offset);
bool LoadLinearizedAllCrossRefV5(FX_FILESIZE main_xref_offset);
Error LoadLinearizedMainXRefTable();
const CPDF_ObjectStream* GetObjectStream(uint32_t object_number);
// A simple check whether the cross reference table matches with
// the objects.
bool VerifyCrossRefV4();
// If out_objects is null, the parser position will be moved to end subsection
// without additional validation.
bool ParseAndAppendCrossRefSubsectionData(
uint32_t start_objnum,
uint32_t count,
std::vector<CrossRefObjData>* out_objects);
bool ParseCrossRefV4(std::vector<CrossRefObjData>* out_objects);
void MergeCrossRefObjectsData(const std::vector<CrossRefObjData>& objects);
bool InitSyntaxParser(RetainPtr<CPDF_ReadValidator> validator);
bool ParseFileVersion();
ObjectType GetObjectType(uint32_t objnum) const;
std::unique_ptr<CPDF_SyntaxParser> m_pSyntax;
std::unique_ptr<ParsedObjectsHolder> m_pOwnedObjectsHolder;
UnownedPtr<ParsedObjectsHolder> m_pObjectsHolder;
bool m_bHasParsed = false;
bool m_bXRefStream = false;
bool m_bXRefTableRebuilt = false;
int m_FileVersion = 0;
uint32_t m_MetadataObjnum = 0;
// m_CrossRefTable must be destroyed after m_pSecurityHandler due to the
// ownership of the ID array data.
std::unique_ptr<CPDF_CrossRefTable> m_CrossRefTable;
FX_FILESIZE m_LastXRefOffset = 0;
ByteString m_Password;
std::unique_ptr<CPDF_LinearizedHeader> m_pLinearized;
// A map of object numbers to indirect streams.
std::map<uint32_t, std::unique_ptr<CPDF_ObjectStream>> m_ObjectStreamMap;
// All indirect object numbers that are being parsed.
std::set<uint32_t> m_ParsingObjNums;
RetainPtr<CPDF_SecurityHandler> m_pSecurityHandler;
};
#endif // CORE_FPDFAPI_PARSER_CPDF_PARSER_H_