From 8f952279866afb647b7098c0cbdc25e35e8c0531 Mon Sep 17 00:00:00 2001 From: Wei Li Date: Fri, 29 Jan 2016 18:04:42 -0800 Subject: Merge to XFA: Refactor CPDF_Object and its subclasses. Mainly use virtual functions to replace functions with switch statements. Also remove a few unused functions and make some format changes. BUG=pdfium:63 TBR=thestig@chromium.org Review URL: https://codereview.chromium.org/1634373003 . (cherry picked from commit df1ab41e000069dda7bf21527308f3bf41e126ca) Review URL: https://codereview.chromium.org/1650493003 . --- core/include/fpdfapi/fpdf_objects.h | 440 +++++++-------- core/src/fpdfapi/fpdf_page/fpdf_page_image.cpp | 2 +- .../fpdfapi/fpdf_parser/fpdf_parser_objects.cpp | 594 +++++---------------- .../fpdf_parser/fpdf_parser_objects_unittest.cpp | 263 ++++++++- 4 files changed, 600 insertions(+), 699 deletions(-) diff --git a/core/include/fpdfapi/fpdf_objects.h b/core/include/fpdfapi/fpdf_objects.h index 0478acc3e0..86035a86ad 100644 --- a/core/include/fpdfapi/fpdf_objects.h +++ b/core/include/fpdfapi/fpdf_objects.h @@ -44,65 +44,61 @@ class CPDF_Object { REFERENCE }; - Type GetType() const { return m_Type; } + virtual Type GetType() const = 0; FX_DWORD GetObjNum() const { return m_ObjNum; } FX_DWORD GetGenNum() const { return m_GenNum; } - FX_BOOL IsIdentical(CPDF_Object* pObj) const; - CPDF_Object* Clone(FX_BOOL bDirect = FALSE) const; - CPDF_Object* CloneRef(CPDF_IndirectObjectHolder* pObjs) const; + virtual CPDF_Object* Clone(FX_BOOL bDirect = FALSE) const = 0; + virtual CPDF_Object* GetDirect() const { + return const_cast(this); + } - CPDF_Object* GetDirect() const; FX_BOOL IsModified() const { return FALSE; } - void Release(); - CFX_ByteString GetString() const; - CFX_ByteStringC GetConstString() const; - CFX_WideString GetUnicodeText(CFX_CharMap* pCharMap = NULL) const; - FX_FLOAT GetNumber() const; - FX_FLOAT GetNumber16() const; - int GetInteger() const; - CPDF_Dictionary* GetDict() const; - CPDF_Array* GetArray() const; - - void SetString(const CFX_ByteString& str); - void SetUnicodeText(const FX_WCHAR* pUnicodes, int len = -1); - - bool IsArray() const { return m_Type == ARRAY; } - bool IsBoolean() const { return m_Type == BOOLEAN; } - bool IsDictionary() const { return m_Type == DICTIONARY; } - bool IsName() const { return m_Type == NAME; } - bool IsNumber() const { return m_Type == NUMBER; } - bool IsReference() const { return m_Type == REFERENCE; } - bool IsStream() const { return m_Type == STREAM; } - bool IsString() const { return m_Type == STRING; } - - CPDF_Array* AsArray(); - const CPDF_Array* AsArray() const; - CPDF_Boolean* AsBoolean(); - const CPDF_Boolean* AsBoolean() const; - CPDF_Dictionary* AsDictionary(); - const CPDF_Dictionary* AsDictionary() const; - CPDF_Name* AsName(); - const CPDF_Name* AsName() const; - CPDF_Number* AsNumber(); - const CPDF_Number* AsNumber() const; - CPDF_Reference* AsReference(); - const CPDF_Reference* AsReference() const; - CPDF_Stream* AsStream(); - const CPDF_Stream* AsStream() const; - CPDF_String* AsString(); - const CPDF_String* AsString() const; + virtual CFX_ByteString GetString() const { return CFX_ByteString(); } + virtual CFX_ByteStringC GetConstString() const { return CFX_ByteStringC(); } + virtual CFX_WideString GetUnicodeText(CFX_CharMap* pCharMap = nullptr) const { + return CFX_WideString(); + } + virtual FX_FLOAT GetNumber() const { return 0; } + virtual int GetInteger() const { return 0; } + virtual CPDF_Dictionary* GetDict() const { return nullptr; } + virtual CPDF_Array* GetArray() const { return nullptr; } + + virtual void SetString(const CFX_ByteString& str) { ASSERT(FALSE); } + + virtual bool IsArray() const { return false; } + virtual bool IsBoolean() const { return false; } + virtual bool IsDictionary() const { return false; } + virtual bool IsName() const { return false; } + virtual bool IsNumber() const { return false; } + virtual bool IsReference() const { return false; } + virtual bool IsStream() const { return false; } + virtual bool IsString() const { return false; } + + virtual CPDF_Array* AsArray() { return nullptr; } + virtual const CPDF_Array* AsArray() const { return nullptr; } + virtual CPDF_Boolean* AsBoolean() { return nullptr; } + virtual const CPDF_Boolean* AsBoolean() const { return nullptr; } + virtual CPDF_Dictionary* AsDictionary() { return nullptr; } + virtual const CPDF_Dictionary* AsDictionary() const { return nullptr; } + virtual CPDF_Name* AsName() { return nullptr; } + virtual const CPDF_Name* AsName() const { return nullptr; } + virtual CPDF_Number* AsNumber() { return nullptr; } + virtual const CPDF_Number* AsNumber() const { return nullptr; } + virtual CPDF_Reference* AsReference() { return nullptr; } + virtual const CPDF_Reference* AsReference() const { return nullptr; } + virtual CPDF_Stream* AsStream() { return nullptr; } + virtual const CPDF_Stream* AsStream() const { return nullptr; } + virtual CPDF_String* AsString() { return nullptr; } + virtual const CPDF_String* AsString() const { return nullptr; } protected: - explicit CPDF_Object(Type type) : m_Type(type), m_ObjNum(0), m_GenNum(0) {} - ~CPDF_Object() {} - void Destroy(); + CPDF_Object() : m_ObjNum(0), m_GenNum(0) {} + virtual ~CPDF_Object() {} + void Destroy() { delete this; } - const CPDF_Object* GetBasicObject() const; - - const Type m_Type; FX_DWORD m_ObjNum; FX_DWORD m_GenNum; @@ -111,66 +107,73 @@ class CPDF_Object { friend class CPDF_SyntaxParser; private: - CPDF_Object* CloneInternal(FX_BOOL bDirect, - std::set* visited) const; + CPDF_Object(const CPDF_Object& src) {} }; + class CPDF_Boolean : public CPDF_Object { public: - CPDF_Boolean() : CPDF_Object(BOOLEAN), m_bValue(false) {} - explicit CPDF_Boolean(FX_BOOL value) - : CPDF_Object(BOOLEAN), m_bValue(value) {} + CPDF_Boolean() : m_bValue(false) {} + explicit CPDF_Boolean(FX_BOOL value) : m_bValue(value) {} - FX_BOOL Identical(CPDF_Boolean* pOther) const { - return m_bValue == pOther->m_bValue; + // CPDF_Object. + Type GetType() const override { return BOOLEAN; } + CPDF_Object* Clone(FX_BOOL bDirect = FALSE) const override { + return new CPDF_Boolean(m_bValue); } - - CFX_ByteString GetString() const { return m_bValue ? "true" : "false"; } - FX_BOOL GetValue() const { return m_bValue; } + CFX_ByteString GetString() const override { + return m_bValue ? "true" : "false"; + } + int GetInteger() const override { return m_bValue; } + void SetString(const CFX_ByteString& str) override { + m_bValue = (str == "true"); + } + bool IsBoolean() const override { return true; } + CPDF_Boolean* AsBoolean() override { return this; } + const CPDF_Boolean* AsBoolean() const override { return this; } protected: + ~CPDF_Boolean() {} + FX_BOOL m_bValue; - friend class CPDF_Object; }; + inline CPDF_Boolean* ToBoolean(CPDF_Object* obj) { return obj ? obj->AsBoolean() : nullptr; } + inline const CPDF_Boolean* ToBoolean(const CPDF_Object* obj) { return obj ? obj->AsBoolean() : nullptr; } class CPDF_Number : public CPDF_Object { public: - CPDF_Number() : CPDF_Object(NUMBER), m_bInteger(TRUE), m_Integer(0) {} - - explicit CPDF_Number(int value); - - explicit CPDF_Number(FX_FLOAT value); - + CPDF_Number() : m_bInteger(TRUE), m_Integer(0) {} + explicit CPDF_Number(int value) : m_bInteger(TRUE), m_Integer(value) {} + explicit CPDF_Number(FX_FLOAT value) : m_bInteger(FALSE), m_Float(value) {} explicit CPDF_Number(const CFX_ByteStringC& str); - FX_BOOL Identical(CPDF_Number* pOther) const; - - CFX_ByteString GetString() const; - - void SetString(const CFX_ByteStringC& str); - - FX_BOOL IsInteger() const { return m_bInteger; } - - int GetInteger() const { return m_bInteger ? m_Integer : (int)m_Float; } - - FX_FLOAT GetNumber() const { - return m_bInteger ? (FX_FLOAT)m_Integer : m_Float; + // CPDF_Object. + Type GetType() const override { return NUMBER; } + CPDF_Object* Clone(FX_BOOL bDirect = FALSE) const override { + return m_bInteger ? new CPDF_Number(m_Integer) : new CPDF_Number(m_Float); } - - void SetNumber(FX_FLOAT value); - - FX_FLOAT GetNumber16() const { return GetNumber(); } - - FX_FLOAT GetFloat() const { - return m_bInteger ? (FX_FLOAT)m_Integer : m_Float; + CFX_ByteString GetString() const override; + FX_FLOAT GetNumber() const override { + return m_bInteger ? static_cast(m_Integer) : m_Float; } + int GetInteger() const override { + return m_bInteger ? m_Integer : static_cast(m_Float); + } + void SetString(const CFX_ByteString& str) override; + bool IsNumber() const override { return true; } + CPDF_Number* AsNumber() override { return this; } + const CPDF_Number* AsNumber() const override { return this; } + + FX_BOOL IsInteger() { return m_bInteger; } protected: + ~CPDF_Number() {} + FX_BOOL m_bInteger; union { @@ -178,141 +181,149 @@ class CPDF_Number : public CPDF_Object { FX_FLOAT m_Float; }; - friend class CPDF_Object; }; + inline CPDF_Number* ToNumber(CPDF_Object* obj) { return obj ? obj->AsNumber() : nullptr; } + inline const CPDF_Number* ToNumber(const CPDF_Object* obj) { return obj ? obj->AsNumber() : nullptr; } class CPDF_String : public CPDF_Object { public: - CPDF_String() : CPDF_Object(STRING), m_bHex(FALSE) {} - + CPDF_String() : m_bHex(FALSE) {} CPDF_String(const CFX_ByteString& str, FX_BOOL bHex) - : CPDF_Object(STRING), m_String(str), m_bHex(bHex) {} - + : m_String(str), m_bHex(bHex) {} explicit CPDF_String(const CFX_WideString& str); - CFX_ByteString GetString() const { return m_String; } - - FX_BOOL Identical(CPDF_String* pOther) const { - return m_String == pOther->m_String; + // CPDF_Object. + Type GetType() const override { return STRING; } + CPDF_Object* Clone(FX_BOOL bDirect = FALSE) const override { + return new CPDF_String(m_String, m_bHex); + } + CFX_ByteString GetString() const override { return m_String; } + CFX_ByteStringC GetConstString() const override { + return CFX_ByteStringC(m_String); } + CFX_WideString GetUnicodeText(CFX_CharMap* pCharMap = nullptr) const override; + void SetString(const CFX_ByteString& str) override { m_String = str; } + bool IsString() const override { return true; } + CPDF_String* AsString() override { return this; } + const CPDF_String* AsString() const override { return this; } FX_BOOL IsHex() const { return m_bHex; } protected: - CFX_ByteString m_String; + ~CPDF_String() {} + CFX_ByteString m_String; FX_BOOL m_bHex; - friend class CPDF_Object; }; + inline CPDF_String* ToString(CPDF_Object* obj) { return obj ? obj->AsString() : nullptr; } + inline const CPDF_String* ToString(const CPDF_Object* obj) { return obj ? obj->AsString() : nullptr; } class CPDF_Name : public CPDF_Object { public: - explicit CPDF_Name(const CFX_ByteString& str) - : CPDF_Object(NAME), m_Name(str) {} - explicit CPDF_Name(const CFX_ByteStringC& str) - : CPDF_Object(NAME), m_Name(str) {} - explicit CPDF_Name(const FX_CHAR* str) : CPDF_Object(NAME), m_Name(str) {} - - CFX_ByteString GetString() const { return m_Name; } - - FX_BOOL Identical(CPDF_Name* pOther) const { - return m_Name == pOther->m_Name; + explicit CPDF_Name(const CFX_ByteString& str) : m_Name(str) {} + explicit CPDF_Name(const CFX_ByteStringC& str) : m_Name(str) {} + explicit CPDF_Name(const FX_CHAR* str) : m_Name(str) {} + + // CPDF_Object. + Type GetType() const override { return NAME; } + CPDF_Object* Clone(FX_BOOL bDirect = FALSE) const override { + return new CPDF_Name(m_Name); } + CFX_ByteString GetString() const override { return m_Name; } + CFX_ByteStringC GetConstString() const override { + return CFX_ByteStringC(m_Name); + } + CFX_WideString GetUnicodeText(CFX_CharMap* pCharMap = nullptr) const override; + void SetString(const CFX_ByteString& str) override { m_Name = str; } + bool IsName() const override { return true; } + CPDF_Name* AsName() override { return this; } + const CPDF_Name* AsName() const override { return this; } protected: + ~CPDF_Name() {} + CFX_ByteString m_Name; - friend class CPDF_Object; }; + inline CPDF_Name* ToName(CPDF_Object* obj) { return obj ? obj->AsName() : nullptr; } + inline const CPDF_Name* ToName(const CPDF_Object* obj) { return obj ? obj->AsName() : nullptr; } class CPDF_Array : public CPDF_Object { public: - CPDF_Array() : CPDF_Object(ARRAY) {} + CPDF_Array() {} + + // CPDF_Object. + Type GetType() const override { return ARRAY; } + CPDF_Object* Clone(FX_BOOL bDirect = FALSE) const override; + CPDF_Array* GetArray() const override { + // The method should be made non-const if we want to not be const. + // See bug #234. + return const_cast(this); + } + bool IsArray() const override { return true; } + CPDF_Array* AsArray() override { return this; } + const CPDF_Array* AsArray() const override { return this; } FX_DWORD GetCount() const { return m_Objects.GetSize(); } - CPDF_Object* GetElement(FX_DWORD index) const; - CPDF_Object* GetElementValue(FX_DWORD index) const; - CFX_Matrix GetMatrix(); - CFX_FloatRect GetRect(); - CFX_ByteString GetStringAt(FX_DWORD index) const; - CFX_ByteStringC GetConstStringAt(FX_DWORD index) const; - int GetIntegerAt(FX_DWORD index) const; - FX_FLOAT GetNumberAt(FX_DWORD index) const; - CPDF_Dictionary* GetDictAt(FX_DWORD index) const; - CPDF_Stream* GetStreamAt(FX_DWORD index) const; - CPDF_Array* GetArrayAt(FX_DWORD index) const; - FX_FLOAT GetFloatAt(FX_DWORD index) const { return GetNumberAt(index); } void SetAt(FX_DWORD index, CPDF_Object* pObj, - CPDF_IndirectObjectHolder* pObjs = NULL); - + CPDF_IndirectObjectHolder* pObjs = nullptr); void InsertAt(FX_DWORD index, CPDF_Object* pObj, - CPDF_IndirectObjectHolder* pObjs = NULL); - + CPDF_IndirectObjectHolder* pObjs = nullptr); void RemoveAt(FX_DWORD index, int nCount = 1); - void Add(CPDF_Object* pObj, CPDF_IndirectObjectHolder* pObjs = NULL); - + void Add(CPDF_Object* pObj, CPDF_IndirectObjectHolder* pObjs = nullptr); void AddNumber(FX_FLOAT f); - void AddInteger(int i); - void AddString(const CFX_ByteString& str); - void AddName(const CFX_ByteString& str); - void AddReference(CPDF_IndirectObjectHolder* pDoc, FX_DWORD objnum); - void AddReference(CPDF_IndirectObjectHolder* pDoc, CPDF_Object* obj) { AddReference(pDoc, obj->GetObjNum()); } - - FX_FLOAT GetNumber16(FX_DWORD index) const { return GetNumberAt(index); } - void AddNumber16(FX_FLOAT value) { AddNumber(value); } - FX_BOOL Identical(CPDF_Array* pOther) const; - protected: ~CPDF_Array(); CFX_ArrayTemplate m_Objects; - friend class CPDF_Object; }; + inline CPDF_Array* ToArray(CPDF_Object* obj) { return obj ? obj->AsArray() : nullptr; } + inline const CPDF_Array* ToArray(const CPDF_Object* obj) { return obj ? obj->AsArray() : nullptr; } @@ -322,44 +333,41 @@ class CPDF_Dictionary : public CPDF_Object { using iterator = std::map::iterator; using const_iterator = std::map::const_iterator; - CPDF_Dictionary() : CPDF_Object(DICTIONARY) {} + CPDF_Dictionary() {} - CPDF_Object* GetElement(const CFX_ByteStringC& key) const; + // CPDF_Object. + Type GetType() const override { return DICTIONARY; } + CPDF_Object* Clone(FX_BOOL bDirect = FALSE) const override; + CPDF_Dictionary* GetDict() const override { + // The method should be made non-const if we want to not be const. + // See bug #234. + return const_cast(this); + } + bool IsDictionary() const override { return true; } + CPDF_Dictionary* AsDictionary() override { return this; } + const CPDF_Dictionary* AsDictionary() const override { return this; } + size_t GetCount() const { return m_Map.size(); } + CPDF_Object* GetElement(const CFX_ByteStringC& key) const; CPDF_Object* GetElementValue(const CFX_ByteStringC& key) const; - CFX_ByteString GetStringBy(const CFX_ByteStringC& key) const; - CFX_ByteStringC GetConstStringBy(const CFX_ByteStringC& key) const; - CFX_ByteString GetStringBy(const CFX_ByteStringC& key, const CFX_ByteStringC& default_str) const; - CFX_ByteStringC GetConstStringBy(const CFX_ByteStringC& key, const CFX_ByteStringC& default_str) const; - CFX_WideString GetUnicodeTextBy(const CFX_ByteStringC& key, CFX_CharMap* pCharMap = NULL) const; - int GetIntegerBy(const CFX_ByteStringC& key) const; - int GetIntegerBy(const CFX_ByteStringC& key, int default_int) const; - FX_BOOL GetBooleanBy(const CFX_ByteStringC& key, FX_BOOL bDefault = FALSE) const; - FX_FLOAT GetNumberBy(const CFX_ByteStringC& key) const; - CPDF_Dictionary* GetDictBy(const CFX_ByteStringC& key) const; - CPDF_Stream* GetStreamBy(const CFX_ByteStringC& key) const; - CPDF_Array* GetArrayBy(const CFX_ByteStringC& key) const; - CFX_FloatRect GetRectBy(const CFX_ByteStringC& key) const; - CFX_Matrix GetMatrixBy(const CFX_ByteStringC& key) const; - FX_FLOAT GetFloatBy(const CFX_ByteStringC& key) const { return GetNumberBy(key); } @@ -368,63 +376,47 @@ class CPDF_Dictionary : public CPDF_Object { // Set* functions invalidate iterators for the element with the key |key|. void SetAt(const CFX_ByteStringC& key, CPDF_Object* pObj); - void SetAtName(const CFX_ByteStringC& key, const CFX_ByteString& name); - void SetAtString(const CFX_ByteStringC& key, const CFX_ByteString& string); - void SetAtInteger(const CFX_ByteStringC& key, int i); - void SetAtNumber(const CFX_ByteStringC& key, FX_FLOAT f); - void SetAtReference(const CFX_ByteStringC& key, CPDF_IndirectObjectHolder* pDoc, FX_DWORD objnum); - void SetAtReference(const CFX_ByteStringC& key, CPDF_IndirectObjectHolder* pDoc, CPDF_Object* obj) { SetAtReference(key, pDoc, obj->GetObjNum()); } + void SetAtRect(const CFX_ByteStringC& key, const CFX_FloatRect& rect); + void SetAtMatrix(const CFX_ByteStringC& key, const CFX_Matrix& matrix); + void SetAtBoolean(const CFX_ByteStringC& key, FX_BOOL bValue); void AddReference(const CFX_ByteStringC& key, CPDF_IndirectObjectHolder* pDoc, FX_DWORD objnum); - void SetAtRect(const CFX_ByteStringC& key, const CFX_FloatRect& rect); - - void SetAtMatrix(const CFX_ByteStringC& key, const CFX_Matrix& matrix); - - void SetAtBoolean(const CFX_ByteStringC& key, FX_BOOL bValue); - // Invalidates iterators for the element with the key |key|. void RemoveAt(const CFX_ByteStringC& key); // Invalidates iterators for the element with the key |oldkey|. void ReplaceKey(const CFX_ByteStringC& oldkey, const CFX_ByteStringC& newkey); - FX_BOOL Identical(CPDF_Dictionary* pDict) const; - - size_t GetCount() const { return m_Map.size(); } - iterator begin() { return m_Map.begin(); } - iterator end() { return m_Map.end(); } - const_iterator begin() const { return m_Map.begin(); } - const_iterator end() const { return m_Map.end(); } protected: ~CPDF_Dictionary(); std::map m_Map; - - friend class CPDF_Object; }; + inline CPDF_Dictionary* ToDictionary(CPDF_Object* obj) { return obj ? obj->AsDictionary() : nullptr; } + inline const CPDF_Dictionary* ToDictionary(const CPDF_Object* obj) { return obj ? obj->AsDictionary() : nullptr; } @@ -433,7 +425,17 @@ class CPDF_Stream : public CPDF_Object { public: CPDF_Stream(uint8_t* pData, FX_DWORD size, CPDF_Dictionary* pDict); - CPDF_Dictionary* GetDict() const { return m_pDict; } + // CPDF_Object. + Type GetType() const override { return STREAM; } + CPDF_Object* Clone(FX_BOOL bDirect = FALSE) const override; + CPDF_Dictionary* GetDict() const override { return m_pDict; } + CFX_WideString GetUnicodeText(CFX_CharMap* pCharMap = nullptr) const override; + bool IsStream() const override { return true; } + CPDF_Stream* AsStream() override { return this; } + const CPDF_Stream* AsStream() const override { return this; } + + FX_DWORD GetRawSize() const { return m_dwSize; } + uint8_t* GetRawData() const { return m_pDataBuf; } void SetData(const uint8_t* pData, FX_DWORD size, @@ -441,13 +443,8 @@ class CPDF_Stream : public CPDF_Object { FX_BOOL bKeepBuf); void InitStream(uint8_t* pData, FX_DWORD size, CPDF_Dictionary* pDict); - void InitStreamFromFile(IFX_FileRead* pFile, CPDF_Dictionary* pDict); - FX_BOOL Identical(CPDF_Stream* pOther) const; - - FX_DWORD GetRawSize() const { return m_dwSize; } - FX_BOOL ReadRawData(FX_FILESIZE start_pos, uint8_t* pBuf, FX_DWORD buf_size) const; @@ -455,29 +452,26 @@ class CPDF_Stream : public CPDF_Object { FX_BOOL IsMemoryBased() const { return m_GenNum == kMemoryBasedGenNum; } protected: - friend class CPDF_Object; - friend class CPDF_StreamAcc; - static const FX_DWORD kMemoryBasedGenNum = (FX_DWORD)-1; + ~CPDF_Stream(); void InitStreamInternal(CPDF_Dictionary* pDict); CPDF_Dictionary* m_pDict; - FX_DWORD m_dwSize; - FX_DWORD m_GenNum; union { uint8_t* m_pDataBuf; - IFX_FileRead* m_pFile; }; }; + inline CPDF_Stream* ToStream(CPDF_Object* obj) { return obj ? obj->AsStream() : nullptr; } + inline const CPDF_Stream* ToStream(const CPDF_Object* obj) { return obj ? obj->AsStream() : nullptr; } @@ -485,7 +479,6 @@ inline const CPDF_Stream* ToStream(const CPDF_Object* obj) { class CPDF_StreamAcc { public: CPDF_StreamAcc(); - ~CPDF_StreamAcc(); void LoadAllData(const CPDF_Stream* pStream, @@ -494,66 +487,93 @@ class CPDF_StreamAcc { FX_BOOL bImageAcc = FALSE); const CPDF_Stream* GetStream() const { return m_pStream; } - CPDF_Dictionary* GetDict() const { return m_pStream ? m_pStream->GetDict() : nullptr; } - const uint8_t* GetData() const; - FX_DWORD GetSize() const; + const CFX_ByteString& GetImageDecoder() const { return m_ImageDecoder; } + const CPDF_Dictionary* GetImageParam() const { return m_pImageParam; } uint8_t* DetachData(); - const CFX_ByteString& GetImageDecoder() { return m_ImageDecoder; } - - const CPDF_Dictionary* GetImageParam() { return m_pImageParam; } - protected: uint8_t* m_pData; - FX_DWORD m_dwSize; - FX_BOOL m_bNewBuf; - CFX_ByteString m_ImageDecoder; - CPDF_Dictionary* m_pImageParam; - const CPDF_Stream* m_pStream; - uint8_t* m_pSrcData; }; class CPDF_Null : public CPDF_Object { public: - CPDF_Null() : CPDF_Object(NULLOBJ) {} + CPDF_Null() {} + + // CPDF_Object. + Type GetType() const override { return NULLOBJ; } + CPDF_Object* Clone(FX_BOOL bDirect = FALSE) const override { + return new CPDF_Null; + } }; class CPDF_Reference : public CPDF_Object { public: CPDF_Reference(CPDF_IndirectObjectHolder* pDoc, int objnum) - : CPDF_Object(REFERENCE), m_pObjList(pDoc), m_RefObjNum(objnum) {} + : m_pObjList(pDoc), m_RefObjNum(objnum) {} + + // CPDF_Object. + Type GetType() const override { return REFERENCE; } + CPDF_Object* Clone(FX_BOOL bDirect = FALSE) const override; + CPDF_Object* GetDirect() const override; + CFX_ByteString GetString() const override { + CPDF_Object* obj = SafeGetDirect(); + return obj ? obj->GetString() : CFX_ByteString(); + } + CFX_ByteStringC GetConstString() const override { + CPDF_Object* obj = SafeGetDirect(); + return obj ? obj->GetConstString() : CFX_ByteStringC(); + } + FX_FLOAT GetNumber() const override { + CPDF_Object* obj = SafeGetDirect(); + return obj ? obj->GetNumber() : 0; + } + int GetInteger() const override { + CPDF_Object* obj = SafeGetDirect(); + return obj ? obj->GetInteger() : 0; + } + CPDF_Dictionary* GetDict() const override { + CPDF_Object* obj = SafeGetDirect(); + return obj ? obj->GetDict() : nullptr; + } + // TODO(weili): check whether GetUnicodeText() and GetArray() are needed. + bool IsReference() const override { return true; } + CPDF_Reference* AsReference() override { return this; } + const CPDF_Reference* AsReference() const override { return this; } CPDF_IndirectObjectHolder* GetObjList() const { return m_pObjList; } - FX_DWORD GetRefObjNum() const { return m_RefObjNum; } void SetRef(CPDF_IndirectObjectHolder* pDoc, FX_DWORD objnum); - FX_BOOL Identical(CPDF_Reference* pOther) const { - return m_RefObjNum == pOther->m_RefObjNum; + protected: + ~CPDF_Reference() {} + CPDF_Object* SafeGetDirect() const { + CPDF_Object* obj = GetDirect(); + if (!obj || obj->IsReference()) + return nullptr; + return obj; } - protected: CPDF_IndirectObjectHolder* m_pObjList; - FX_DWORD m_RefObjNum; - friend class CPDF_Object; }; + inline CPDF_Reference* ToReference(CPDF_Object* obj) { return obj ? obj->AsReference() : nullptr; } + inline const CPDF_Reference* ToReference(const CPDF_Object* obj) { return obj ? obj->AsReference() : nullptr; } @@ -575,7 +595,7 @@ class CPDF_IndirectObjectHolder { FX_DWORD GetLastObjNum() const { return m_LastObjNum; } iterator begin() { return m_IndirectObjs.begin(); } - const_iterator begin() const { return m_IndirectObjs.cbegin(); } + const_iterator begin() const { return m_IndirectObjs.begin(); } iterator end() { return m_IndirectObjs.end(); } const_iterator end() const { return m_IndirectObjs.end(); } diff --git a/core/src/fpdfapi/fpdf_page/fpdf_page_image.cpp b/core/src/fpdfapi/fpdf_page/fpdf_page_image.cpp index 9296cd6158..3791f5fec0 100644 --- a/core/src/fpdfapi/fpdf_page/fpdf_page_image.cpp +++ b/core/src/fpdfapi/fpdf_page/fpdf_page_image.cpp @@ -49,7 +49,7 @@ CPDF_Image* CPDF_Image::Clone() { return m_pDocument->GetPageData()->GetImage(m_pStream); CPDF_Image* pImage = new CPDF_Image(m_pDocument); - pImage->LoadImageF(ToStream(m_pStream->CPDF_Object::Clone()), m_bInline); + pImage->LoadImageF(ToStream(m_pStream->Clone()), m_bInline); if (m_bInline) pImage->SetInlineDict(ToDictionary(m_pInlineDict->Clone(TRUE))); diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_objects.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_objects.cpp index 6b512949ae..813c18a4c5 100644 --- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_objects.cpp +++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_objects.cpp @@ -12,382 +12,38 @@ #include "core/include/fxcrt/fx_string.h" #include "third_party/base/stl_util.h" -namespace { - -const FX_DWORD kBlockSize = 1024; - -} // namespace - void CPDF_Object::Release() { if (m_ObjNum) { return; } Destroy(); } -void CPDF_Object::Destroy() { - switch (m_Type) { - case STRING: - delete AsString(); - break; - case NAME: - delete AsName(); - break; - case ARRAY: - delete AsArray(); - break; - case DICTIONARY: - delete AsDictionary(); - break; - case STREAM: - delete AsStream(); - break; - default: - delete this; - } -} - -const CPDF_Object* CPDF_Object::GetBasicObject() const { - const CPDF_Reference* pRef = AsReference(); - if (!pRef) { - // This is not an indirect reference. - return this; - } - if (!pRef->m_pObjList) - return nullptr; - return pRef->m_pObjList->GetIndirectObject(pRef->GetRefObjNum()); -} - -CFX_ByteString CPDF_Object::GetString() const { - const CPDF_Object* obj = GetBasicObject(); - if (obj) { - switch (obj->GetType()) { - case BOOLEAN: - return obj->AsBoolean()->GetString(); - case NUMBER: - return obj->AsNumber()->GetString(); - case STRING: - return obj->AsString()->GetString(); - case NAME: - return obj->AsName()->GetString(); - default: - break; - } - } - return CFX_ByteString(); -} - -CFX_ByteStringC CPDF_Object::GetConstString() const { - const CPDF_Object* obj = GetBasicObject(); - if (obj) { - FX_DWORD type = obj->GetType(); - if (type == STRING) { - CFX_ByteString str = obj->AsString()->GetString(); - return CFX_ByteStringC(str); - } - if (type == NAME) { - CFX_ByteString name = obj->AsName()->GetString(); - return CFX_ByteStringC(name); - } - } - return CFX_ByteStringC(); -} - -FX_FLOAT CPDF_Object::GetNumber() const { - const CPDF_Object* obj = GetBasicObject(); - if (obj && obj->GetType() == NUMBER) - return obj->AsNumber()->GetNumber(); - return 0; -} - -FX_FLOAT CPDF_Object::GetNumber16() const { - return GetNumber(); -} - -int CPDF_Object::GetInteger() const { - const CPDF_Object* obj = GetBasicObject(); - if (obj) { - FX_DWORD type = obj->GetType(); - if (type == BOOLEAN) - return obj->AsBoolean()->GetValue(); - if (type == NUMBER) - return obj->AsNumber()->GetInteger(); - } - return 0; -} - -CPDF_Dictionary* CPDF_Object::GetDict() const { - const CPDF_Object* obj = GetBasicObject(); - if (obj) { - FX_DWORD type = obj->GetType(); - if (type == DICTIONARY) { - // The method should be made non-const if we want to not be const. - // See bug #234. - return const_cast(obj->AsDictionary()); - } - if (type == STREAM) - return obj->AsStream()->GetDict(); - } - return nullptr; -} - -CPDF_Array* CPDF_Object::GetArray() const { - // The method should be made non-const if we want to not be const. - // See bug #234. - return const_cast(AsArray()); -} - -void CPDF_Object::SetString(const CFX_ByteString& str) { - switch (m_Type) { - case BOOLEAN: - AsBoolean()->m_bValue = (str == "true"); - return; - case NUMBER: - AsNumber()->SetString(str); - return; - case STRING: - AsString()->m_String = str; - return; - case NAME: - AsName()->m_Name = str; - return; - default: - break; - } - ASSERT(FALSE); -} -FX_BOOL CPDF_Object::IsIdentical(CPDF_Object* pOther) const { - if (this == pOther) - return TRUE; - if (!pOther) - return FALSE; - if (pOther->m_Type != m_Type) { - if (IsReference() && GetDirect()) - return GetDirect()->IsIdentical(pOther); - if (pOther->IsReference()) - return IsIdentical(pOther->GetDirect()); - return FALSE; - } - switch (m_Type) { - case BOOLEAN: - return AsBoolean()->Identical(pOther->AsBoolean()); - case NUMBER: - return AsNumber()->Identical(pOther->AsNumber()); - case STRING: - return AsString()->Identical(pOther->AsString()); - case NAME: - return AsName()->Identical(pOther->AsName()); - case ARRAY: - return AsArray()->Identical(pOther->AsArray()); - case DICTIONARY: - return AsDictionary()->Identical(pOther->AsDictionary()); - case NULLOBJ: - return TRUE; - case STREAM: - return AsStream()->Identical(pOther->AsStream()); - case REFERENCE: - return AsReference()->Identical(pOther->AsReference()); - } - return FALSE; -} - -CPDF_Object* CPDF_Object::GetDirect() const { - const CPDF_Reference* pRef = AsReference(); - if (!pRef) - return const_cast(this); - if (!pRef->m_pObjList) - return nullptr; - return pRef->m_pObjList->GetIndirectObject(pRef->GetRefObjNum()); -} - -CPDF_Object* CPDF_Object::Clone(FX_BOOL bDirect) const { - std::set visited; - return CloneInternal(bDirect, &visited); -} -CPDF_Object* CPDF_Object::CloneInternal(FX_BOOL bDirect, - std::set* visited) const { - switch (m_Type) { - case BOOLEAN: - return new CPDF_Boolean(AsBoolean()->m_bValue); - case NUMBER: { - const CPDF_Number* pThis = AsNumber(); - return new CPDF_Number(pThis->m_bInteger ? pThis->m_Integer - : pThis->m_Float); - } - case STRING: { - const CPDF_String* pString = AsString(); - return new CPDF_String(pString->m_String, pString->IsHex()); - } - case NAME: - return new CPDF_Name(AsName()->m_Name); - case ARRAY: { - CPDF_Array* pCopy = new CPDF_Array(); - const CPDF_Array* pThis = AsArray(); - int n = pThis->GetCount(); - for (int i = 0; i < n; i++) { - CPDF_Object* value = pThis->m_Objects.GetAt(i); - pCopy->m_Objects.Add(value->CloneInternal(bDirect, visited)); - } - return pCopy; - } - case DICTIONARY: { - CPDF_Dictionary* pCopy = new CPDF_Dictionary(); - const CPDF_Dictionary* pThis = AsDictionary(); - for (const auto& it : *pThis) { - pCopy->m_Map.insert(std::make_pair( - it.first, it.second->CloneInternal(bDirect, visited))); - } - return pCopy; - } - case NULLOBJ: { - return new CPDF_Null; - } - case STREAM: { - const CPDF_Stream* pThis = AsStream(); - CPDF_StreamAcc acc; - acc.LoadAllData(pThis, TRUE); - FX_DWORD streamSize = acc.GetSize(); - CPDF_Dictionary* pDict = pThis->GetDict(); - if (pDict) { - pDict = ToDictionary(pDict->CloneInternal(bDirect, visited)); - } - return new CPDF_Stream(acc.DetachData(), streamSize, pDict); - } - case REFERENCE: { - const CPDF_Reference* pRef = AsReference(); - FX_DWORD obj_num = pRef->GetRefObjNum(); - if (bDirect && !pdfium::ContainsKey(*visited, obj_num)) { - visited->insert(obj_num); - auto* pDirect = pRef->GetDirect(); - return pDirect ? pDirect->CloneInternal(TRUE, visited) : nullptr; - } - return new CPDF_Reference(pRef->m_pObjList, obj_num); - } - } - return NULL; -} -CPDF_Object* CPDF_Object::CloneRef(CPDF_IndirectObjectHolder* pDoc) const { - if (m_ObjNum) { - return new CPDF_Reference(pDoc, m_ObjNum); - } - return Clone(); -} -CFX_WideString CPDF_Object::GetUnicodeText(CFX_CharMap* pCharMap) const { - if (const CPDF_String* pString = AsString()) - return PDF_DecodeText(pString->m_String, pCharMap); - - if (const CPDF_Stream* pStream = AsStream()) { - CPDF_StreamAcc stream; - stream.LoadAllData(pStream, FALSE); - CFX_WideString result = - PDF_DecodeText(stream.GetData(), stream.GetSize(), pCharMap); - return result; - } - if (const CPDF_Name* pName = AsName()) - return PDF_DecodeText(pName->m_Name, pCharMap); - return CFX_WideString(); -} -void CPDF_Object::SetUnicodeText(const FX_WCHAR* pUnicodes, int len) { - if (CPDF_String* pString = AsString()) { - pString->m_String = PDF_EncodeText(pUnicodes, len); - } else if (CPDF_Stream* pStream = AsStream()) { - CFX_ByteString result = PDF_EncodeText(pUnicodes, len); - pStream->SetData((uint8_t*)result.c_str(), result.GetLength(), FALSE, - FALSE); - } -} - -CPDF_Array* CPDF_Object::AsArray() { - return IsArray() ? static_cast(this) : nullptr; -} - -const CPDF_Array* CPDF_Object::AsArray() const { - return IsArray() ? static_cast(this) : nullptr; -} -CPDF_Boolean* CPDF_Object::AsBoolean() { - return IsBoolean() ? static_cast(this) : nullptr; -} - -const CPDF_Boolean* CPDF_Object::AsBoolean() const { - return IsBoolean() ? static_cast(this) : nullptr; -} - -CPDF_Dictionary* CPDF_Object::AsDictionary() { - return IsDictionary() ? static_cast(this) : nullptr; -} - -const CPDF_Dictionary* CPDF_Object::AsDictionary() const { - return IsDictionary() ? static_cast(this) : nullptr; -} - -CPDF_Name* CPDF_Object::AsName() { - return IsName() ? static_cast(this) : nullptr; -} - -const CPDF_Name* CPDF_Object::AsName() const { - return IsName() ? static_cast(this) : nullptr; -} - -CPDF_Number* CPDF_Object::AsNumber() { - return IsNumber() ? static_cast(this) : nullptr; -} - -const CPDF_Number* CPDF_Object::AsNumber() const { - return IsNumber() ? static_cast(this) : nullptr; -} - -CPDF_Reference* CPDF_Object::AsReference() { - return IsReference() ? static_cast(this) : nullptr; -} - -const CPDF_Reference* CPDF_Object::AsReference() const { - return IsReference() ? static_cast(this) : nullptr; +CPDF_Number::CPDF_Number(const CFX_ByteStringC& str) { + FX_atonum(str, m_bInteger, &m_Integer); } -CPDF_Stream* CPDF_Object::AsStream() { - return IsStream() ? static_cast(this) : nullptr; +void CPDF_Number::SetString(const CFX_ByteString& str) { + FX_atonum(str, m_bInteger, &m_Integer); } -const CPDF_Stream* CPDF_Object::AsStream() const { - return IsStream() ? static_cast(this) : nullptr; +CFX_ByteString CPDF_Number::GetString() const { + return m_bInteger ? CFX_ByteString::FormatInteger(m_Integer, FXFORMAT_SIGNED) + : CFX_ByteString::FormatFloat(m_Float); } -CPDF_String* CPDF_Object::AsString() { - return IsString() ? static_cast(this) : nullptr; +CPDF_String::CPDF_String(const CFX_WideString& str) : m_bHex(FALSE) { + m_String = PDF_EncodeText(str); } -const CPDF_String* CPDF_Object::AsString() const { - return IsString() ? static_cast(this) : nullptr; +CFX_WideString CPDF_String::GetUnicodeText(CFX_CharMap* pCharMap) const { + return PDF_DecodeText(m_String, pCharMap); } -CPDF_Number::CPDF_Number(int value) - : CPDF_Object(NUMBER), m_bInteger(TRUE), m_Integer(value) {} - -CPDF_Number::CPDF_Number(FX_FLOAT value) - : CPDF_Object(NUMBER), m_bInteger(FALSE), m_Float(value) {} - -CPDF_Number::CPDF_Number(const CFX_ByteStringC& str) : CPDF_Object(NUMBER) { - FX_atonum(str, m_bInteger, &m_Integer); +CFX_WideString CPDF_Name::GetUnicodeText(CFX_CharMap* pCharMap) const { + return PDF_DecodeText(m_Name, pCharMap); } -void CPDF_Number::SetString(const CFX_ByteStringC& str) { - FX_atonum(str, m_bInteger, &m_Integer); -} -FX_BOOL CPDF_Number::Identical(CPDF_Number* pOther) const { - return m_bInteger == pOther->m_bInteger && m_Integer == pOther->m_Integer; -} -CFX_ByteString CPDF_Number::GetString() const { - return m_bInteger ? CFX_ByteString::FormatInteger(m_Integer, FXFORMAT_SIGNED) - : CFX_ByteString::FormatFloat(m_Float); -} -void CPDF_Number::SetNumber(FX_FLOAT value) { - m_bInteger = FALSE; - m_Float = value; -} -CPDF_String::CPDF_String(const CFX_WideString& str) - : CPDF_Object(STRING), m_bHex(FALSE) { - m_String = PDF_EncodeText(str); -} CPDF_Array::~CPDF_Array() { int size = m_Objects.GetSize(); CPDF_Object** pList = m_Objects.GetData(); @@ -396,6 +52,16 @@ CPDF_Array::~CPDF_Array() { pList[i]->Release(); } } + +CPDF_Object* CPDF_Array::Clone(FX_BOOL bDirect) const { + CPDF_Array* pCopy = new CPDF_Array(); + for (int i = 0; i < GetCount(); i++) { + CPDF_Object* value = m_Objects.GetAt(i); + pCopy->m_Objects.Add(value->Clone(bDirect)); + } + return pCopy; +} + CFX_FloatRect CPDF_Array::GetRect() { CFX_FloatRect rect; if (!IsArray() || m_Objects.GetSize() != 4) @@ -407,6 +73,7 @@ CFX_FloatRect CPDF_Array::GetRect() { rect.top = GetNumberAt(3); return rect; } + CFX_Matrix CPDF_Array::GetMatrix() { CFX_Matrix matrix; if (!IsArray() || m_Objects.GetSize() != 6) @@ -416,36 +83,43 @@ CFX_Matrix CPDF_Array::GetMatrix() { GetNumberAt(4), GetNumberAt(5)); return matrix; } + CPDF_Object* CPDF_Array::GetElement(FX_DWORD i) const { if (i >= (FX_DWORD)m_Objects.GetSize()) return nullptr; return m_Objects.GetAt(i); } + CPDF_Object* CPDF_Array::GetElementValue(FX_DWORD i) const { if (i >= (FX_DWORD)m_Objects.GetSize()) return nullptr; return m_Objects.GetAt(i)->GetDirect(); } + CFX_ByteString CPDF_Array::GetStringAt(FX_DWORD i) const { if (i >= (FX_DWORD)m_Objects.GetSize()) return CFX_ByteString(); return m_Objects.GetAt(i)->GetString(); } + CFX_ByteStringC CPDF_Array::GetConstStringAt(FX_DWORD i) const { if (i >= (FX_DWORD)m_Objects.GetSize()) return CFX_ByteStringC(); return m_Objects.GetAt(i)->GetConstString(); } + int CPDF_Array::GetIntegerAt(FX_DWORD i) const { if (i >= (FX_DWORD)m_Objects.GetSize()) return 0; return m_Objects.GetAt(i)->GetInteger(); } + FX_FLOAT CPDF_Array::GetNumberAt(FX_DWORD i) const { if (i >= (FX_DWORD)m_Objects.GetSize()) return 0; return m_Objects.GetAt(i)->GetNumber(); } + CPDF_Dictionary* CPDF_Array::GetDictAt(FX_DWORD i) const { CPDF_Object* p = GetElementValue(i); if (!p) @@ -456,12 +130,15 @@ CPDF_Dictionary* CPDF_Array::GetDictAt(FX_DWORD i) const { return pStream->GetDict(); return NULL; } + CPDF_Stream* CPDF_Array::GetStreamAt(FX_DWORD i) const { return ToStream(GetElementValue(i)); } + CPDF_Array* CPDF_Array::GetArrayAt(FX_DWORD i) const { return ToArray(GetElementValue(i)); } + void CPDF_Array::RemoveAt(FX_DWORD i, int nCount) { if (i >= (FX_DWORD)m_Objects.GetSize()) return; @@ -475,6 +152,7 @@ void CPDF_Array::RemoveAt(FX_DWORD i, int nCount) { } m_Objects.RemoveAt(i, nCount); } + void CPDF_Array::SetAt(FX_DWORD i, CPDF_Object* pObj, CPDF_IndirectObjectHolder* pObjs) { @@ -490,6 +168,7 @@ void CPDF_Array::SetAt(FX_DWORD i, } m_Objects.SetAt(i, pObj); } + void CPDF_Array::InsertAt(FX_DWORD index, CPDF_Object* pObj, CPDF_IndirectObjectHolder* pObjs) { @@ -499,6 +178,7 @@ void CPDF_Array::InsertAt(FX_DWORD index, } m_Objects.InsertAt(index, pObj); } + void CPDF_Array::Add(CPDF_Object* pObj, CPDF_IndirectObjectHolder* pObjs) { if (pObj->GetObjNum()) { ASSERT(pObjs); @@ -506,44 +186,47 @@ void CPDF_Array::Add(CPDF_Object* pObj, CPDF_IndirectObjectHolder* pObjs) { } m_Objects.Add(pObj); } + void CPDF_Array::AddName(const CFX_ByteString& str) { ASSERT(IsArray()); Add(new CPDF_Name(str)); } + void CPDF_Array::AddString(const CFX_ByteString& str) { ASSERT(IsArray()); Add(new CPDF_String(str, FALSE)); } + void CPDF_Array::AddInteger(int i) { ASSERT(IsArray()); Add(new CPDF_Number(i)); } + void CPDF_Array::AddNumber(FX_FLOAT f) { ASSERT(IsArray()); - CPDF_Number* pNumber = new CPDF_Number; - pNumber->SetNumber(f); + CPDF_Number* pNumber = new CPDF_Number(f); Add(pNumber); } + void CPDF_Array::AddReference(CPDF_IndirectObjectHolder* pDoc, FX_DWORD objnum) { ASSERT(IsArray()); Add(new CPDF_Reference(pDoc, objnum)); } -FX_BOOL CPDF_Array::Identical(CPDF_Array* pOther) const { - if (m_Objects.GetSize() != pOther->m_Objects.GetSize()) { - return FALSE; - } - for (int i = 0; i < m_Objects.GetSize(); i++) { - if (!m_Objects[i]->IsIdentical(pOther->m_Objects[i])) - return FALSE; - } - return TRUE; -} + CPDF_Dictionary::~CPDF_Dictionary() { for (const auto& it : m_Map) { it.second->Release(); } } + +CPDF_Object* CPDF_Dictionary::Clone(FX_BOOL bDirect) const { + CPDF_Dictionary* pCopy = new CPDF_Dictionary(); + for (const auto& it : *this) + pCopy->m_Map.insert(std::make_pair(it.first, it.second->Clone(bDirect))); + return pCopy; +} + CPDF_Object* CPDF_Dictionary::GetElement(const CFX_ByteStringC& key) const { auto it = m_Map.find(key); if (it == m_Map.end()) @@ -555,6 +238,7 @@ CPDF_Object* CPDF_Dictionary::GetElementValue( CPDF_Object* p = GetElement(key); return p ? p->GetDirect() : nullptr; } + CFX_ByteString CPDF_Dictionary::GetStringBy(const CFX_ByteStringC& key) const { CPDF_Object* p = GetElement(key); if (p) { @@ -562,6 +246,7 @@ CFX_ByteString CPDF_Dictionary::GetStringBy(const CFX_ByteStringC& key) const { } return CFX_ByteString(); } + CFX_ByteStringC CPDF_Dictionary::GetConstStringBy( const CFX_ByteStringC& key) const { CPDF_Object* p = GetElement(key); @@ -570,6 +255,7 @@ CFX_ByteStringC CPDF_Dictionary::GetConstStringBy( } return CFX_ByteStringC(); } + CFX_WideString CPDF_Dictionary::GetUnicodeTextBy(const CFX_ByteStringC& key, CFX_CharMap* pCharMap) const { CPDF_Object* p = GetElement(key); @@ -577,6 +263,7 @@ CFX_WideString CPDF_Dictionary::GetUnicodeTextBy(const CFX_ByteStringC& key, p = pRef->GetDirect(); return p ? p->GetUnicodeText(pCharMap) : CFX_WideString(); } + CFX_ByteString CPDF_Dictionary::GetStringBy(const CFX_ByteStringC& key, const CFX_ByteStringC& def) const { CPDF_Object* p = GetElement(key); @@ -585,6 +272,7 @@ CFX_ByteString CPDF_Dictionary::GetStringBy(const CFX_ByteStringC& key, } return CFX_ByteString(def); } + CFX_ByteStringC CPDF_Dictionary::GetConstStringBy( const CFX_ByteStringC& key, const CFX_ByteStringC& def) const { @@ -594,6 +282,7 @@ CFX_ByteStringC CPDF_Dictionary::GetConstStringBy( } return CFX_ByteStringC(def); } + int CPDF_Dictionary::GetIntegerBy(const CFX_ByteStringC& key) const { CPDF_Object* p = GetElement(key); if (p) { @@ -601,6 +290,7 @@ int CPDF_Dictionary::GetIntegerBy(const CFX_ByteStringC& key) const { } return 0; } + int CPDF_Dictionary::GetIntegerBy(const CFX_ByteStringC& key, int def) const { CPDF_Object* p = GetElement(key); if (p) { @@ -608,6 +298,7 @@ int CPDF_Dictionary::GetIntegerBy(const CFX_ByteStringC& key, int def) const { } return def; } + FX_FLOAT CPDF_Dictionary::GetNumberBy(const CFX_ByteStringC& key) const { CPDF_Object* p = GetElement(key); if (p) { @@ -615,6 +306,7 @@ FX_FLOAT CPDF_Dictionary::GetNumberBy(const CFX_ByteStringC& key) const { } return 0; } + FX_BOOL CPDF_Dictionary::GetBooleanBy(const CFX_ByteStringC& key, FX_BOOL bDefault) const { CPDF_Object* p = GetElement(key); @@ -622,6 +314,7 @@ FX_BOOL CPDF_Dictionary::GetBooleanBy(const CFX_ByteStringC& key, return p->GetInteger(); return bDefault; } + CPDF_Dictionary* CPDF_Dictionary::GetDictBy(const CFX_ByteStringC& key) const { CPDF_Object* p = GetElementValue(key); if (!p) @@ -632,12 +325,15 @@ CPDF_Dictionary* CPDF_Dictionary::GetDictBy(const CFX_ByteStringC& key) const { return pStream->GetDict(); return nullptr; } + CPDF_Array* CPDF_Dictionary::GetArrayBy(const CFX_ByteStringC& key) const { return ToArray(GetElementValue(key)); } + CPDF_Stream* CPDF_Dictionary::GetStreamBy(const CFX_ByteStringC& key) const { return ToStream(GetElementValue(key)); } + CFX_FloatRect CPDF_Dictionary::GetRectBy(const CFX_ByteStringC& key) const { CFX_FloatRect rect; CPDF_Array* pArray = GetArrayBy(key); @@ -645,6 +341,7 @@ CFX_FloatRect CPDF_Dictionary::GetRectBy(const CFX_ByteStringC& key) const { rect = pArray->GetRect(); return rect; } + CFX_Matrix CPDF_Dictionary::GetMatrixBy(const CFX_ByteStringC& key) const { CFX_Matrix matrix; CPDF_Array* pArray = GetArrayBy(key); @@ -652,6 +349,7 @@ CFX_Matrix CPDF_Dictionary::GetMatrixBy(const CFX_ByteStringC& key) const { matrix = pArray->GetMatrix(); return matrix; } + FX_BOOL CPDF_Dictionary::KeyExist(const CFX_ByteStringC& key) const { return pdfium::ContainsKey(m_Map, key); } @@ -677,8 +375,8 @@ void CPDF_Dictionary::SetAt(const CFX_ByteStringC& key, CPDF_Object* pObj) { else m_Map.erase(it); } + void CPDF_Dictionary::RemoveAt(const CFX_ByteStringC& key) { - ASSERT(m_Type == DICTIONARY); auto it = m_Map.find(key); if (it == m_Map.end()) return; @@ -686,9 +384,9 @@ void CPDF_Dictionary::RemoveAt(const CFX_ByteStringC& key) { it->second->Release(); m_Map.erase(it); } + void CPDF_Dictionary::ReplaceKey(const CFX_ByteStringC& oldkey, const CFX_ByteStringC& newkey) { - ASSERT(m_Type == DICTIONARY); auto old_it = m_Map.find(oldkey); if (old_it == m_Map.end()) return; @@ -707,49 +405,42 @@ void CPDF_Dictionary::ReplaceKey(const CFX_ByteStringC& oldkey, } m_Map.erase(old_it); } -FX_BOOL CPDF_Dictionary::Identical(CPDF_Dictionary* pOther) const { - if (!pOther) { - return FALSE; - } - if (m_Map.size() != pOther->m_Map.size()) { - return FALSE; - } - for (const auto& it : m_Map) { - const CFX_ByteString& key = it.first; - if (!it.second->IsIdentical(pOther->GetElement(key))) - return FALSE; - } - return TRUE; -} + void CPDF_Dictionary::SetAtInteger(const CFX_ByteStringC& key, int i) { SetAt(key, new CPDF_Number(i)); } + void CPDF_Dictionary::SetAtName(const CFX_ByteStringC& key, const CFX_ByteString& name) { SetAt(key, new CPDF_Name(name)); } + void CPDF_Dictionary::SetAtString(const CFX_ByteStringC& key, const CFX_ByteString& str) { SetAt(key, new CPDF_String(str, FALSE)); } + void CPDF_Dictionary::SetAtReference(const CFX_ByteStringC& key, CPDF_IndirectObjectHolder* pDoc, FX_DWORD objnum) { SetAt(key, new CPDF_Reference(pDoc, objnum)); } + void CPDF_Dictionary::AddReference(const CFX_ByteStringC& key, CPDF_IndirectObjectHolder* pDoc, FX_DWORD objnum) { SetAt(key, new CPDF_Reference(pDoc, objnum)); } + void CPDF_Dictionary::SetAtNumber(const CFX_ByteStringC& key, FX_FLOAT f) { - CPDF_Number* pNumber = new CPDF_Number; - pNumber->SetNumber(f); + CPDF_Number* pNumber = new CPDF_Number(f); SetAt(key, pNumber); } + void CPDF_Dictionary::SetAtBoolean(const CFX_ByteStringC& key, FX_BOOL bValue) { SetAt(key, new CPDF_Boolean(bValue)); } + void CPDF_Dictionary::SetAtRect(const CFX_ByteStringC& key, const CFX_FloatRect& rect) { CPDF_Array* pArray = new CPDF_Array; @@ -759,6 +450,7 @@ void CPDF_Dictionary::SetAtRect(const CFX_ByteStringC& key, pArray->AddNumber(rect.top); SetAt(key, pArray); } + void CPDF_Dictionary::SetAtMatrix(const CFX_ByteStringC& key, const CFX_Matrix& matrix) { CPDF_Array* pArray = new CPDF_Array; @@ -770,9 +462,9 @@ void CPDF_Dictionary::SetAtMatrix(const CFX_ByteStringC& key, pArray->AddNumber(matrix.f); SetAt(key, pArray); } + CPDF_Stream::CPDF_Stream(uint8_t* pData, FX_DWORD size, CPDF_Dictionary* pDict) - : CPDF_Object(STREAM), - m_pDict(pDict), + : m_pDict(pDict), m_dwSize(size), m_GenNum(kMemoryBasedGenNum), m_pDataBuf(pData) {} @@ -812,6 +504,18 @@ void CPDF_Stream::InitStream(uint8_t* pData, m_pDict->SetAtInteger("Length", size); } } + +CPDF_Object* CPDF_Stream::Clone(FX_BOOL bDirect) const { + CPDF_StreamAcc acc; + acc.LoadAllData(this, TRUE); + FX_DWORD streamSize = acc.GetSize(); + CPDF_Dictionary* pDict = GetDict(); + if (pDict) { + pDict = ToDictionary(pDict->Clone(bDirect)); + } + return new CPDF_Stream(acc.DetachData(), streamSize, pDict); +} + void CPDF_Stream::SetData(const uint8_t* pData, FX_DWORD size, FX_BOOL bCompressed, @@ -821,7 +525,7 @@ void CPDF_Stream::SetData(const uint8_t* pData, m_GenNum = kMemoryBasedGenNum; if (bKeepBuf) { - m_pDataBuf = (uint8_t*)pData; + m_pDataBuf = const_cast(pData); } else { m_pDataBuf = FX_Alloc(uint8_t, size); if (pData) { @@ -837,6 +541,7 @@ void CPDF_Stream::SetData(const uint8_t* pData, m_pDict->RemoveAt("DecodeParms"); } } + FX_BOOL CPDF_Stream::ReadRawData(FX_FILESIZE offset, uint8_t* buf, FX_DWORD size) const { @@ -857,72 +562,10 @@ void CPDF_Stream::InitStreamFromFile(IFX_FileRead* pFile, } } -FX_BOOL CPDF_Stream::Identical(CPDF_Stream* pOther) const { - if (!m_pDict) - return !pOther->m_pDict; - - if (!m_pDict->Identical(pOther->m_pDict)) - return FALSE; - - if (m_dwSize != pOther->m_dwSize) - return FALSE; - - if (!IsMemoryBased() && !pOther->IsMemoryBased()) { - if (m_pFile == pOther->m_pFile && !m_pFile) - return TRUE; - - if (!m_pFile || !pOther->m_pFile) - return FALSE; - - uint8_t srcBuf[kBlockSize]; - uint8_t destBuf[kBlockSize]; - FX_DWORD size = m_dwSize; - if (m_pFile == pOther->m_pFile) - return TRUE; - - FX_DWORD offset = 0; - while (size > 0) { - FX_DWORD actualSize = std::min(size, kBlockSize); - m_pFile->ReadBlock(srcBuf, offset, actualSize); - pOther->m_pFile->ReadBlock(destBuf, offset, actualSize); - if (FXSYS_memcmp(srcBuf, destBuf, actualSize) != 0) - return FALSE; - - size -= actualSize; - offset += actualSize; - } - return TRUE; - } - - if (!IsMemoryBased() || !pOther->IsMemoryBased()) { - IFX_FileRead* pFile = nullptr; - uint8_t* pBuf = nullptr; - if (!pOther->IsMemoryBased()) { - pFile = pOther->m_pFile; - pBuf = m_pDataBuf; - } else if (!IsMemoryBased()) { - pFile = m_pFile; - pBuf = pOther->m_pDataBuf; - } - if (!pBuf) - return FALSE; - - uint8_t srcBuf[kBlockSize]; - FX_DWORD size = m_dwSize; - FX_DWORD offset = 0; - while (size > 0) { - FX_DWORD actualSize = std::min(size, kBlockSize); - pFile->ReadBlock(srcBuf, offset, actualSize); - if (FXSYS_memcmp(srcBuf, pBuf, actualSize) != 0) - return FALSE; - - pBuf += actualSize; - size -= actualSize; - offset += actualSize; - } - return TRUE; - } - return FXSYS_memcmp(m_pDataBuf, pOther->m_pDataBuf, m_dwSize) == 0; +CFX_WideString CPDF_Stream::GetUnicodeText(CFX_CharMap* pCharMap) const { + CPDF_StreamAcc stream; + stream.LoadAllData(this, FALSE); + return PDF_DecodeText(stream.GetData(), stream.GetSize(), pCharMap); } CPDF_StreamAcc::CPDF_StreamAcc() { @@ -943,12 +586,12 @@ void CPDF_StreamAcc::LoadAllData(const CPDF_Stream* pStream, m_pStream = pStream; if (pStream->IsMemoryBased() && (!pStream->GetDict()->KeyExist("Filter") || bRawAccess)) { - m_dwSize = pStream->m_dwSize; - m_pData = (uint8_t*)pStream->m_pDataBuf; + m_dwSize = pStream->GetRawSize(); + m_pData = pStream->GetRawData(); return; } uint8_t* pSrcData; - FX_DWORD dwSrcSize = pStream->m_dwSize; + FX_DWORD dwSrcSize = pStream->GetRawSize(); if (dwSrcSize == 0) return; @@ -957,7 +600,7 @@ void CPDF_StreamAcc::LoadAllData(const CPDF_Stream* pStream, if (!pStream->ReadRawData(0, pSrcData, dwSrcSize)) return; } else { - pSrcData = pStream->m_pDataBuf; + pSrcData = pStream->GetRawData(); } uint8_t* pDecryptedData = pSrcData; FX_DWORD dwDecryptedSize = dwSrcSize; @@ -973,21 +616,23 @@ void CPDF_StreamAcc::LoadAllData(const CPDF_Stream* pStream, m_dwSize = dwDecryptedSize; } } - if (pSrcData != pStream->m_pDataBuf && pSrcData != m_pData) { + if (pSrcData != pStream->GetRawData() && pSrcData != m_pData) { FX_Free(pSrcData); } if (pDecryptedData != pSrcData && pDecryptedData != m_pData) { FX_Free(pDecryptedData); } m_pSrcData = NULL; - m_bNewBuf = m_pData != pStream->m_pDataBuf; + m_bNewBuf = m_pData != pStream->GetRawData(); } + CPDF_StreamAcc::~CPDF_StreamAcc() { if (m_bNewBuf) { FX_Free(m_pData); } FX_Free(m_pSrcData); } + const uint8_t* CPDF_StreamAcc::GetData() const { if (m_bNewBuf) { return m_pData; @@ -995,8 +640,9 @@ const uint8_t* CPDF_StreamAcc::GetData() const { if (!m_pStream) { return NULL; } - return m_pStream->m_pDataBuf; + return m_pStream->GetRawData(); } + FX_DWORD CPDF_StreamAcc::GetSize() const { if (m_bNewBuf) { return m_dwSize; @@ -1004,8 +650,9 @@ FX_DWORD CPDF_StreamAcc::GetSize() const { if (!m_pStream) { return 0; } - return m_pStream->m_dwSize; + return m_pStream->GetRawSize(); } + uint8_t* CPDF_StreamAcc::DetachData() { if (m_bNewBuf) { uint8_t* p = m_pData; @@ -1017,20 +664,36 @@ uint8_t* CPDF_StreamAcc::DetachData() { FXSYS_memcpy(p, m_pData, m_dwSize); return p; } + +CPDF_Object* CPDF_Reference::Clone(FX_BOOL bDirect) const { + if (bDirect) { + auto* pDirect = GetDirect(); + return pDirect ? pDirect->Clone(TRUE) : nullptr; + } + return new CPDF_Reference(m_pObjList, m_RefObjNum); +} + void CPDF_Reference::SetRef(CPDF_IndirectObjectHolder* pDoc, FX_DWORD objnum) { m_pObjList = pDoc; m_RefObjNum = objnum; } + +CPDF_Object* CPDF_Reference::GetDirect() const { + return m_pObjList ? m_pObjList->GetIndirectObject(m_RefObjNum) : nullptr; +} + CPDF_IndirectObjectHolder::CPDF_IndirectObjectHolder(CPDF_Parser* pParser) : m_pParser(pParser), m_LastObjNum(0) { if (pParser) m_LastObjNum = m_pParser->GetLastObjNum(); } + CPDF_IndirectObjectHolder::~CPDF_IndirectObjectHolder() { for (const auto& pair : m_IndirectObjs) { pair.second->Destroy(); } } + CPDF_Object* CPDF_IndirectObjectHolder::GetIndirectObject(FX_DWORD objnum) { if (objnum == 0) return nullptr; @@ -1054,6 +717,7 @@ CPDF_Object* CPDF_IndirectObjectHolder::GetIndirectObject(FX_DWORD objnum) { m_IndirectObjs[objnum] = pObj; return pObj; } + FX_DWORD CPDF_IndirectObjectHolder::AddIndirectObject(CPDF_Object* pObj) { if (pObj->m_ObjNum) { return pObj->m_ObjNum; @@ -1063,6 +727,7 @@ FX_DWORD CPDF_IndirectObjectHolder::AddIndirectObject(CPDF_Object* pObj) { pObj->m_ObjNum = m_LastObjNum; return m_LastObjNum; } + void CPDF_IndirectObjectHolder::ReleaseIndirectObject(FX_DWORD objnum) { auto it = m_IndirectObjs.find(objnum); if (it == m_IndirectObjs.end() || it->second->GetObjNum() == -1) @@ -1070,6 +735,7 @@ void CPDF_IndirectObjectHolder::ReleaseIndirectObject(FX_DWORD objnum) { it->second->Destroy(); m_IndirectObjs.erase(it); } + FX_BOOL CPDF_IndirectObjectHolder::InsertIndirectObject(FX_DWORD objnum, CPDF_Object* pObj) { if (!objnum || !pObj) diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_objects_unittest.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_objects_unittest.cpp index 3965399254..9de31c8673 100644 --- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_objects_unittest.cpp +++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_objects_unittest.cpp @@ -26,9 +26,9 @@ class PDFObjectsTest : public testing::Test { // Name object. CPDF_Name* name_obj = new CPDF_Name("space"); // Array object. - CPDF_Array* array_obj = new CPDF_Array; - array_obj->InsertAt(0, new CPDF_Number(8902)); - array_obj->InsertAt(1, new CPDF_Name("address")); + m_ArrayObj = new CPDF_Array; + m_ArrayObj->InsertAt(0, new CPDF_Number(8902)); + m_ArrayObj->InsertAt(1, new CPDF_Name("address")); // Dictionary object. m_DictObj = new CPDF_Dictionary; m_DictObj->SetAt("bool", new CPDF_Boolean(false)); @@ -47,23 +47,92 @@ class PDFObjectsTest : public testing::Test { // All direct objects. CPDF_Object* objs[] = {boolean_false_obj, boolean_true_obj, number_int_obj, number_float_obj, str_reg_obj, str_spec_obj, - name_obj, array_obj, m_DictObj, + name_obj, m_ArrayObj, m_DictObj, stream_obj, null_obj}; - for (int i = 0; i < FX_ArraySize(objs); ++i) + m_DirectObjTypes = { + CPDF_Object::BOOLEAN, CPDF_Object::BOOLEAN, CPDF_Object::NUMBER, + CPDF_Object::NUMBER, CPDF_Object::STRING, CPDF_Object::STRING, + CPDF_Object::NAME, CPDF_Object::ARRAY, CPDF_Object::DICTIONARY, + CPDF_Object::STREAM, CPDF_Object::NULLOBJ}; + for (size_t i = 0; i < FX_ArraySize(objs); ++i) m_DirectObjs.emplace_back(objs[i]); // Indirect references to indirect objects. m_ObjHolder.reset(new CPDF_IndirectObjectHolder(nullptr)); - CPDF_Object* referred_objs[] = { - boolean_true_obj, number_int_obj, str_spec_obj, name_obj, - array_obj, m_DictObj, stream_obj}; - for (int i = 0; i < FX_ArraySize(referred_objs); ++i) { - m_ObjHolder->AddIndirectObject(referred_objs[i]); - m_RefObjs.emplace_back( - new CPDF_Reference(m_ObjHolder.get(), referred_objs[i]->GetObjNum())); + m_IndirectObjs = {boolean_true_obj, number_int_obj, str_spec_obj, name_obj, + m_ArrayObj, m_DictObj, stream_obj}; + for (size_t i = 0; i < m_IndirectObjs.size(); ++i) { + m_ObjHolder->AddIndirectObject(m_IndirectObjs[i]); + m_RefObjs.emplace_back(new CPDF_Reference( + m_ObjHolder.get(), m_IndirectObjs[i]->GetObjNum())); } } + bool Equal(CPDF_Object* obj1, CPDF_Object* obj2) { + if (obj1 == obj2) + return true; + if (!obj1 || !obj2 || obj1->GetType() != obj2->GetType()) + return false; + switch (obj1->GetType()) { + case CPDF_Object::BOOLEAN: + return obj1->GetInteger() == obj2->GetInteger(); + case CPDF_Object::NUMBER: + return obj1->AsNumber()->IsInteger() == obj2->AsNumber()->IsInteger() && + obj1->GetInteger() == obj2->GetInteger(); + case CPDF_Object::STRING: + case CPDF_Object::NAME: + return obj1->GetString() == obj2->GetString(); + case CPDF_Object::ARRAY: { + const CPDF_Array* array1 = obj1->AsArray(); + const CPDF_Array* array2 = obj2->AsArray(); + if (array1->GetCount() != array2->GetCount()) + return false; + for (size_t i = 0; i < array1->GetCount(); ++i) { + if (!Equal(array1->GetElement(i), array2->GetElement(i))) + return false; + } + return true; + } + case CPDF_Object::DICTIONARY: { + const CPDF_Dictionary* dict1 = obj1->AsDictionary(); + const CPDF_Dictionary* dict2 = obj2->AsDictionary(); + if (dict1->GetCount() != dict2->GetCount()) + return false; + for (CPDF_Dictionary::const_iterator it = dict1->begin(); + it != dict1->end(); ++it) { + if (!Equal(it->second, dict2->GetElement(it->first))) + return false; + } + return true; + } + case CPDF_Object::NULLOBJ: + return true; + case CPDF_Object::STREAM: { + const CPDF_Stream* stream1 = obj1->AsStream(); + const CPDF_Stream* stream2 = obj2->AsStream(); + if (!stream1->GetDict() && !stream2->GetDict()) + return true; + // Compare dictionaries. + if (!Equal(stream1->GetDict(), stream2->GetDict())) + return false; + // Compare sizes. + if (stream1->GetRawSize() != stream2->GetRawSize()) + return false; + // Compare contents. + // Since this function is used for testing Clone(), only memory based + // streams need to be handled. + if (!stream1->IsMemoryBased() || !stream2->IsMemoryBased()) + return false; + return FXSYS_memcmp(stream1->GetRawData(), stream2->GetRawData(), + stream1->GetRawSize()) == 0; + } + case CPDF_Object::REFERENCE: + return obj1->AsReference()->GetRefObjNum() == + obj2->AsReference()->GetRefObjNum(); + } + return false; + } + protected: using ScopedObj = std::unique_ptr>; @@ -71,9 +140,12 @@ class PDFObjectsTest : public testing::Test { // refers to some objects in m_DirectObjs. std::unique_ptr m_ObjHolder; std::vector m_DirectObjs; + std::vector m_DirectObjTypes; std::vector m_RefObjs; CPDF_Dictionary* m_DictObj; CPDF_Dictionary* m_StreamDictObj; + CPDF_Array* m_ArrayObj; + std::vector m_IndirectObjs; }; TEST_F(PDFObjectsTest, GetString) { @@ -81,13 +153,13 @@ TEST_F(PDFObjectsTest, GetString) { "false", "true", "1245", "9.00345", "A simple test", "\t\n", "space", "", "", "", ""}; // Check for direct objects. - for (int i = 0; i < m_DirectObjs.size(); ++i) + for (size_t i = 0; i < m_DirectObjs.size(); ++i) EXPECT_STREQ(m_DirectObjs[i]->GetString().c_str(), direct_obj_results[i]); // Check indirect references. const char* indirect_obj_results[] = {"true", "1245", "\t\n", "space", "", "", ""}; - for (int i = 0; i < m_RefObjs.size(); ++i) { + for (size_t i = 0; i < m_RefObjs.size(); ++i) { EXPECT_STREQ(m_RefObjs[i]->GetString().c_str(), indirect_obj_results[i]); } } @@ -97,7 +169,7 @@ TEST_F(PDFObjectsTest, GetConstString) { nullptr, nullptr, nullptr, nullptr, "A simple test", "\t\n", "space", nullptr, nullptr, nullptr, nullptr}; // Check for direct objects. - for (int i = 0; i < m_DirectObjs.size(); ++i) { + for (size_t i = 0; i < m_DirectObjs.size(); ++i) { if (!direct_obj_results[i]) { EXPECT_EQ(m_DirectObjs[i]->GetConstString().GetCStr(), direct_obj_results[i]); @@ -109,38 +181,53 @@ TEST_F(PDFObjectsTest, GetConstString) { // Check indirect references. const char* indirect_obj_results[] = {nullptr, nullptr, "\t\n", "space", nullptr, nullptr, nullptr}; - for (int i = 0; i < m_RefObjs.size(); ++i) { - if (!indirect_obj_results[i]) + for (size_t i = 0; i < m_RefObjs.size(); ++i) { + if (!indirect_obj_results[i]) { EXPECT_EQ(m_RefObjs[i]->GetConstString().GetCStr(), nullptr); - else { + } else { EXPECT_STREQ(m_RefObjs[i]->GetConstString().GetCStr(), indirect_obj_results[i]); } } } +TEST_F(PDFObjectsTest, GetUnicodeText) { + const wchar_t* direct_obj_results[] = { + L"", L"", L"", L"", L"A simple test", + L"\t\n", L"space", L"", L"", L"abcdefghijklmnopqrstuvwxyz", + L""}; + // Check for direct objects. + for (size_t i = 0; i < m_DirectObjs.size(); ++i) + EXPECT_STREQ(m_DirectObjs[i]->GetUnicodeText().c_str(), + direct_obj_results[i]); + + // Check indirect references. + for (const auto& it : m_RefObjs) + EXPECT_STREQ(it->GetUnicodeText().c_str(), L""); +} + TEST_F(PDFObjectsTest, GetNumber) { const FX_FLOAT direct_obj_results[] = {0, 0, 1245, 9.00345f, 0, 0, 0, 0, 0, 0, 0}; // Check for direct objects. - for (int i = 0; i < m_DirectObjs.size(); ++i) + for (size_t i = 0; i < m_DirectObjs.size(); ++i) EXPECT_EQ(m_DirectObjs[i]->GetNumber(), direct_obj_results[i]); // Check indirect references. const FX_FLOAT indirect_obj_results[] = {0, 1245, 0, 0, 0, 0, 0}; - for (int i = 0; i < m_RefObjs.size(); ++i) + for (size_t i = 0; i < m_RefObjs.size(); ++i) EXPECT_EQ(m_RefObjs[i]->GetNumber(), indirect_obj_results[i]); } TEST_F(PDFObjectsTest, GetInteger) { const int direct_obj_results[] = {0, 1, 1245, 9, 0, 0, 0, 0, 0, 0, 0}; // Check for direct objects. - for (int i = 0; i < m_DirectObjs.size(); ++i) + for (size_t i = 0; i < m_DirectObjs.size(); ++i) EXPECT_EQ(m_DirectObjs[i]->GetInteger(), direct_obj_results[i]); // Check indirect references. const int indirect_obj_results[] = {1, 1245, 0, 0, 0, 0, 0}; - for (int i = 0; i < m_RefObjs.size(); ++i) + for (size_t i = 0; i < m_RefObjs.size(); ++i) EXPECT_EQ(m_RefObjs[i]->GetInteger(), indirect_obj_results[i]); } @@ -149,12 +236,140 @@ TEST_F(PDFObjectsTest, GetDict) { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, m_DictObj, m_StreamDictObj, nullptr}; // Check for direct objects. - for (int i = 0; i < m_DirectObjs.size(); ++i) + for (size_t i = 0; i < m_DirectObjs.size(); ++i) EXPECT_EQ(m_DirectObjs[i]->GetDict(), direct_obj_results[i]); // Check indirect references. const CPDF_Dictionary* indirect_obj_results[] = { nullptr, nullptr, nullptr, nullptr, nullptr, m_DictObj, m_StreamDictObj}; - for (int i = 0; i < m_RefObjs.size(); ++i) + for (size_t i = 0; i < m_RefObjs.size(); ++i) EXPECT_EQ(m_RefObjs[i]->GetDict(), indirect_obj_results[i]); } + +TEST_F(PDFObjectsTest, GetArray) { + const CPDF_Array* direct_obj_results[] = { + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, m_ArrayObj, nullptr, nullptr, nullptr}; + // Check for direct objects. + for (size_t i = 0; i < m_DirectObjs.size(); ++i) + EXPECT_EQ(m_DirectObjs[i]->GetArray(), direct_obj_results[i]); + + // Check indirect references. + for (const auto& it : m_RefObjs) + EXPECT_EQ(it->GetArray(), nullptr); +} + +TEST_F(PDFObjectsTest, Clone) { + // Check for direct objects. + for (size_t i = 0; i < m_DirectObjs.size(); ++i) { + ScopedObj obj(m_DirectObjs[i]->Clone()); + EXPECT_TRUE(Equal(m_DirectObjs[i].get(), obj.get())); + } + + // Check indirect references. + for (const auto& it : m_RefObjs) { + ScopedObj obj(it->Clone()); + EXPECT_TRUE(Equal(it.get(), obj.get())); + } +} + +TEST_F(PDFObjectsTest, GetType) { + // Check for direct objects. + for (size_t i = 0; i < m_DirectObjs.size(); ++i) + EXPECT_EQ(m_DirectObjs[i]->GetType(), m_DirectObjTypes[i]); + + // Check indirect references. + for (const auto& it : m_RefObjs) + EXPECT_EQ(it->GetType(), CPDF_Object::REFERENCE); +} + +TEST_F(PDFObjectsTest, GetDirect) { + // Check for direct objects. + for (size_t i = 0; i < m_DirectObjs.size(); ++i) + EXPECT_EQ(m_DirectObjs[i]->GetDirect(), m_DirectObjs[i].get()); + + // Check indirect references. + for (size_t i = 0; i < m_RefObjs.size(); ++i) + EXPECT_EQ(m_RefObjs[i]->GetDirect(), m_IndirectObjs[i]); +} + +TEST_F(PDFObjectsTest, SetString) { + // Check for direct objects. + const char* const set_values[] = {"true", "fake", "3.125f", "097", + "changed", "", "NewName"}; + const char* expected[] = {"true", "false", "3.125", "97", + "changed", "", "NewName"}; + for (size_t i = 0; i < FX_ArraySize(set_values); ++i) { + m_DirectObjs[i]->SetString(set_values[i]); + EXPECT_STREQ(m_DirectObjs[i]->GetString().c_str(), expected[i]); + } +} + +TEST_F(PDFObjectsTest, IsTypeAndAsType) { + // Check for direct objects. + for (size_t i = 0; i < m_DirectObjs.size(); ++i) { + if (m_DirectObjTypes[i] == CPDF_Object::ARRAY) { + EXPECT_TRUE(m_DirectObjs[i]->IsArray()); + EXPECT_EQ(m_DirectObjs[i]->AsArray(), m_DirectObjs[i].get()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsArray()); + EXPECT_EQ(m_DirectObjs[i]->AsArray(), nullptr); + } + + if (m_DirectObjTypes[i] == CPDF_Object::BOOLEAN) { + EXPECT_TRUE(m_DirectObjs[i]->IsBoolean()); + EXPECT_EQ(m_DirectObjs[i]->AsBoolean(), m_DirectObjs[i].get()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsBoolean()); + EXPECT_EQ(m_DirectObjs[i]->AsBoolean(), nullptr); + } + + if (m_DirectObjTypes[i] == CPDF_Object::NAME) { + EXPECT_TRUE(m_DirectObjs[i]->IsName()); + EXPECT_EQ(m_DirectObjs[i]->AsName(), m_DirectObjs[i].get()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsName()); + EXPECT_EQ(m_DirectObjs[i]->AsName(), nullptr); + } + + if (m_DirectObjTypes[i] == CPDF_Object::NUMBER) { + EXPECT_TRUE(m_DirectObjs[i]->IsNumber()); + EXPECT_EQ(m_DirectObjs[i]->AsNumber(), m_DirectObjs[i].get()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsNumber()); + EXPECT_EQ(m_DirectObjs[i]->AsNumber(), nullptr); + } + + if (m_DirectObjTypes[i] == CPDF_Object::STRING) { + EXPECT_TRUE(m_DirectObjs[i]->IsString()); + EXPECT_EQ(m_DirectObjs[i]->AsString(), m_DirectObjs[i].get()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsString()); + EXPECT_EQ(m_DirectObjs[i]->AsString(), nullptr); + } + + if (m_DirectObjTypes[i] == CPDF_Object::DICTIONARY) { + EXPECT_TRUE(m_DirectObjs[i]->IsDictionary()); + EXPECT_EQ(m_DirectObjs[i]->AsDictionary(), m_DirectObjs[i].get()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsDictionary()); + EXPECT_EQ(m_DirectObjs[i]->AsDictionary(), nullptr); + } + + if (m_DirectObjTypes[i] == CPDF_Object::STREAM) { + EXPECT_TRUE(m_DirectObjs[i]->IsStream()); + EXPECT_EQ(m_DirectObjs[i]->AsStream(), m_DirectObjs[i].get()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsStream()); + EXPECT_EQ(m_DirectObjs[i]->AsStream(), nullptr); + } + + EXPECT_FALSE(m_DirectObjs[i]->IsReference()); + EXPECT_EQ(m_DirectObjs[i]->AsReference(), nullptr); + } + // Check indirect references. + for (size_t i = 0; i < m_RefObjs.size(); ++i) { + EXPECT_TRUE(m_RefObjs[i]->IsReference()); + EXPECT_EQ(m_RefObjs[i]->AsReference(), m_RefObjs[i].get()); + } +} -- cgit v1.2.3