// Copyright 2014 PDFium Authors. All rights reserved.
// 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 _FPDF_PARSER_
#define _FPDF_PARSER_
#ifndef _FX_BASIC_H_
#include "../fxcrt/fx_ext.h"
#endif
#ifndef _FPDF_OBJECTS_
#include "fpdf_objects.h"
#endif
class CPDF_Document;
class IPDF_DocParser;
class CPDF_Parser;
class CPDF_SecurityHandler;
class CPDF_StandardSecurityHandler;
class CPDF_CryptoHandler;
class CPDF_Object;
class IFX_FileRead;
class CFDF_Document;
class CFDF_Parser;
class CFX_Font;
class CFX_AffineMatrix;
class CFX_FloatRect;
class CPDF_Point;
class CPDF_DocPageData;
class CPDF_DocRenderData;
class CPDF_ModuleMgr;
class CFX_DIBSource;
class CPDF_Font;
class CPDF_Image;
class CPDF_ColorSpace;
class CPDF_Pattern;
class CPDF_FontEncoding;
class CPDF_IccProfile;
class CFX_PrivateData;
#define FPDFPERM_PRINT			0x0004
#define FPDFPERM_MODIFY			0x0008
#define FPDFPERM_EXTRACT		0x0010
#define FPDFPERM_ANNOT_FORM		0x0020
#define FPDFPERM_FILL_FORM		0x0100
#define FPDFPERM_EXTRACT_ACCESS	0x0200
#define FPDFPERM_ASSEMBLE		0x0400
#define FPDFPERM_PRINT_HIGH		0x0800
#define FPDF_PAGE_MAX_NUM		0xFFFFF
class IPDF_EnumPageHandler
{
public:

    virtual FX_BOOL EnumPage(CPDF_Dictionary* pPageDict) = 0;
};
class CPDF_Document : public CFX_PrivateData, public CPDF_IndirectObjects
{
public:

    CPDF_Document(IPDF_DocParser* pParser);

    CPDF_Document();

    ~CPDF_Document();

    IPDF_DocParser*			GetParser() const
    {
        return m_pParser;
    }

    CPDF_Dictionary*		GetRoot() const
    {
        return m_pRootDict;
    }

    CPDF_Dictionary*		GetInfo() const
    {
        return m_pInfoDict;
    }

    void					GetID(CFX_ByteString& id1, CFX_ByteString& id2) const
    {
        id1 = m_ID1;
        id2 = m_ID2;
    }

    int						GetPageCount() const;

    CPDF_Dictionary*		GetPage(int iPage);

    int						GetPageIndex(FX_DWORD objnum);

    void					EnumPages(IPDF_EnumPageHandler* pHandler);

    FX_DWORD				GetUserPermissions(FX_BOOL bCheckRevision = FALSE) const;

    FX_BOOL					IsOwner() const;



    CPDF_DocPageData*		GetPageData()
    {
        return GetValidatePageData();
    }

    void					ClearPageData();

    void					RemoveColorSpaceFromPageData(CPDF_Object* pObject);


    CPDF_DocRenderData*		GetRenderData()
    {
        return GetValidateRenderData();
    }

    void					ClearRenderData();

    void					ClearRenderFont();


    FX_BOOL					IsFormStream(FX_DWORD objnum, FX_BOOL& bForm) const;




    CPDF_Font*				LoadFont(CPDF_Dictionary* pFontDict);

    CPDF_Font*				FindFont(CPDF_Dictionary* pFontDict);

    CPDF_ColorSpace*		LoadColorSpace(CPDF_Object* pCSObj, CPDF_Dictionary* pResources = NULL);

    CPDF_Pattern*			LoadPattern(CPDF_Object* pObj, FX_BOOL bShading, const CFX_AffineMatrix* matrix = NULL);

    CPDF_Image*				LoadImageF(CPDF_Object* pObj);

    CPDF_StreamAcc*			LoadFontFile(CPDF_Stream* pStream);

    CPDF_IccProfile*		LoadIccProfile(CPDF_Stream* pStream, int nComponents);

#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_

    CPDF_Font*				AddWindowsFont(LOGFONTA* pLogFont, FX_BOOL bVert, FX_BOOL bTranslateName = FALSE);
    CPDF_Font*				AddWindowsFont(LOGFONTW* pLogFont, FX_BOOL bVert, FX_BOOL bTranslateName = FALSE);
#endif
#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
    CPDF_Font*              AddMacFont(CTFontRef pFont, FX_BOOL bVert, FX_BOOL bTranslateName = FALSE);
#endif

    CPDF_Font*				AddStandardFont(const FX_CHAR* font, CPDF_FontEncoding* pEncoding);


    CPDF_Font*				AddFont(CFX_Font* pFont, int charset, FX_BOOL bVert);

    void					CreateNewDoc();

    CPDF_Dictionary*		CreateNewPage(int iPage);

    void					DeletePage(int iPage);

    void					LoadDoc();
    void					LoadAsynDoc(CPDF_Dictionary *pLinearized);
    void					LoadPages();
protected:

    CPDF_Dictionary*		m_pRootDict;

    CPDF_Dictionary*		m_pInfoDict;

    CFX_ByteString			m_ID1;

    CFX_ByteString			m_ID2;


    FX_BOOL					m_bLinearized;

    FX_DWORD				m_dwFirstPageNo;

    FX_DWORD				m_dwFirstPageObjNum;

    CFX_DWordArray			m_PageList;

    int						_GetPageCount() const;
    CPDF_Dictionary*		_FindPDFPage(CPDF_Dictionary* pPages, int iPage, int nPagesToGo, int level);
    int						_FindPageIndex(CPDF_Dictionary* pNode, FX_DWORD& skip_count, FX_DWORD objnum, int& index, int level = 0);
    FX_BOOL					IsContentUsedElsewhere(FX_DWORD objnum, CPDF_Dictionary* pPageDict);
    FX_BOOL					CheckOCGVisible(CPDF_Dictionary* pOCG, FX_BOOL bPrinting);
    CPDF_DocPageData*		GetValidatePageData();
    CPDF_DocRenderData*		GetValidateRenderData();
    friend class			CPDF_Creator;
    friend class			CPDF_Parser;
    friend class			CPDF_DataAvail;
    friend class			CPDF_OCContext;



    CPDF_DocPageData*		m_pDocPage;

    CPDF_DocRenderData*		m_pDocRender;

};

#define PDFWORD_EOF			0
#define PDFWORD_NUMBER		1
#define PDFWORD_TEXT		2
#define PDFWORD_DELIMITER	3
#define PDFWORD_NAME		4
class CPDF_SimpleParser : public CFX_Object
{
public:

    CPDF_SimpleParser(FX_LPCBYTE pData, FX_DWORD dwSize);

    CPDF_SimpleParser(FX_BSTR str);

    CFX_ByteStringC		GetWord();

    FX_BOOL				SearchToken(FX_BSTR token);

    FX_BOOL				SkipWord(FX_BSTR token);

    FX_BOOL				FindTagPair(FX_BSTR start_token, FX_BSTR end_token,
                                    FX_DWORD& start_pos, FX_DWORD& end_pos);

    FX_BOOL				FindTagParam(FX_BSTR token, int nParams);

    FX_DWORD			GetPos()
    {
        return m_dwCurPos;
    }

    void				SetPos(FX_DWORD pos)
    {
        ASSERT(pos <= m_dwSize);
        m_dwCurPos = pos;
    }
private:

    void				ParseWord(FX_LPCBYTE& pStart, FX_DWORD& dwSize, int& type);

    FX_LPCBYTE			m_pData;

    FX_DWORD			m_dwSize;

    FX_DWORD			m_dwCurPos;
};
class CPDF_SyntaxParser : public CFX_Object
{
public:

    CPDF_SyntaxParser();

    ~CPDF_SyntaxParser();

    void				InitParser(IFX_FileRead* pFileAccess, FX_DWORD HeaderOffset);

    FX_FILESIZE			SavePos()
    {
        return m_Pos;
    }

    void				RestorePos(FX_FILESIZE pos)
    {
        m_Pos = pos;
    }

    CPDF_Object*		GetObject(CPDF_IndirectObjects* pObjList, FX_DWORD objnum, FX_DWORD gennum, int level, struct PARSE_CONTEXT* pContext = NULL, FX_BOOL bDecrypt = TRUE);


    CPDF_Object*		GetObjectByStrict(CPDF_IndirectObjects* pObjList, FX_DWORD objnum, FX_DWORD gennum, int level, struct PARSE_CONTEXT* pContext = NULL);

    int					GetDirectNum();

    CFX_ByteString		GetString(FX_DWORD objnum, FX_DWORD gennum);

    CFX_ByteString		GetName();

    CFX_ByteString		GetKeyword();

    void				GetBinary(FX_BYTE* buffer, FX_DWORD size);

    void				ToNextLine();

    void				ToNextWord();

    FX_BOOL				SearchWord(FX_BSTR word, FX_BOOL bWholeWord, FX_BOOL bForward, FX_FILESIZE limit);

    int					SearchMultiWord(FX_BSTR words, FX_BOOL bWholeWord, FX_FILESIZE limit);

    FX_FILESIZE			FindTag(FX_BSTR tag, FX_FILESIZE limit);

    void				SetEncrypt(CPDF_CryptoHandler* pCryptoHandler)
    {
        m_pCryptoHandler = pCryptoHandler;
    }

    FX_BOOL				IsEncrypted()
    {
        return m_pCryptoHandler != NULL;
    }

    FX_BOOL				GetCharAt(FX_FILESIZE pos, FX_BYTE& ch);

    FX_BOOL				ReadBlock(FX_BYTE* pBuf, FX_DWORD size);

    CFX_ByteString		GetNextWord(FX_BOOL& bIsNumber);
protected:

    virtual FX_BOOL				GetNextChar(FX_BYTE& ch);

    FX_BOOL				GetCharAtBackward(FX_FILESIZE pos, FX_BYTE& ch);

    void				GetNextWord();

    FX_BOOL				IsWholeWord(FX_FILESIZE startpos, FX_FILESIZE limit, FX_LPCBYTE tag, FX_DWORD taglen);

    CFX_ByteString		ReadString();

    CFX_ByteString		ReadHexString();

    CPDF_Stream*		ReadStream(CPDF_Dictionary* pDict, PARSE_CONTEXT* pContext, FX_DWORD objnum, FX_DWORD gennum);

    FX_FILESIZE			m_Pos;

    FX_BOOL				m_bFileStream;

    int					m_MetadataObjnum;

    IFX_FileRead*		m_pFileAccess;

    FX_DWORD			m_HeaderOffset;

    FX_FILESIZE			m_FileLen;

    FX_BYTE*			m_pFileBuf;

    FX_DWORD			m_BufSize;

    FX_FILESIZE			m_BufOffset;

    CPDF_CryptoHandler*	m_pCryptoHandler;

    FX_BYTE				m_WordBuffer[257];

    FX_DWORD			m_WordSize;

    FX_BOOL				m_bIsNumber;

    FX_FILESIZE			m_dwWordPos;
    friend class		CPDF_Parser;
    friend class		CPDF_DataAvail;
};

#define PDFPARSE_TYPEONLY	1
#define PDFPARSE_NOSTREAM	2
struct PARSE_CONTEXT {

    FX_BOOL		m_Flags;

    FX_FILESIZE	m_DictStart;

    FX_FILESIZE	m_DictEnd;

    FX_FILESIZE	m_DataStart;

    FX_FILESIZE	m_DataEnd;
};
class IPDF_DocParser : public CFX_Object
{
public:

    virtual FX_DWORD	GetRootObjNum() = 0;

    virtual FX_DWORD	GetInfoObjNum() = 0;

    virtual CPDF_Object*	ParseIndirectObject(CPDF_IndirectObjects* pObjList, FX_DWORD objnum, PARSE_CONTEXT* pContext = NULL) = 0;

    virtual FX_DWORD	GetLastObjNum() = 0;

    virtual CPDF_Array*	GetIDArray() = 0;

    virtual CPDF_Dictionary*	GetEncryptDict() = 0;

    FX_BOOL				IsEncrypted()
    {
        return GetEncryptDict() != NULL;
    }

    virtual FX_DWORD	GetPermissions(FX_BOOL bCheckRevision = FALSE) = 0;

    virtual FX_BOOL		IsOwner() = 0;

    virtual FX_BOOL		IsFormStream(FX_DWORD objnum, FX_BOOL& bForm) = 0;
};

#define PDFPARSE_ERROR_SUCCESS		0
#define PDFPARSE_ERROR_FILE			1
#define PDFPARSE_ERROR_FORMAT		2
#define PDFPARSE_ERROR_PASSWORD		3
#define PDFPARSE_ERROR_HANDLER		4
#define PDFPARSE_ERROR_CERT			5
class CPDF_Parser FX_FINAL : public IPDF_DocParser
{
public:

    CPDF_Parser();

    ~CPDF_Parser();

    FX_DWORD			StartParse(FX_LPCSTR filename, FX_BOOL bReParse = FALSE);

    FX_DWORD			StartParse(FX_LPCWSTR filename, FX_BOOL bReParse = FALSE);

    FX_DWORD			StartParse(IFX_FileRead* pFile, FX_BOOL bReParse = FALSE, FX_BOOL bOwnFileRead = TRUE);

    void				CloseParser(FX_BOOL bReParse = FALSE);

    virtual FX_DWORD	GetPermissions(FX_BOOL bCheckRevision = FALSE);

    virtual FX_BOOL		IsOwner();

    void				SetPassword(const FX_CHAR* password)
    {
        m_Password = password;
    }

    CFX_ByteString		GetPassword()
    {
        return m_Password;
    }

    CPDF_SecurityHandler* GetSecurityHandler()
    {
        return m_pSecurityHandler;
    }

    CPDF_CryptoHandler*	GetCryptoHandler()
    {
        return m_Syntax.m_pCryptoHandler;
    }

    void				SetSecurityHandler(CPDF_SecurityHandler* pSecurityHandler, FX_BOOL bForced = FALSE);

    CFX_ByteString		GetRecipient()
    {
        return m_bsRecipient;
    }

    CPDF_Dictionary*	GetTrailer()
    {
        return m_pTrailer;
    }

    FX_FILESIZE			GetLastXRefOffset()
    {
        return m_LastXRefOffset;
    }

    CPDF_Document*		GetDocument()
    {
        return m_pDocument;
    }
    CFX_ArrayTemplate<CPDF_Dictionary *> * GetOtherTrailers()
    {
        return &m_Trailers;
    }

    virtual FX_DWORD	GetRootObjNum();
    virtual FX_DWORD	GetInfoObjNum();
    virtual CPDF_Array*	GetIDArray();
    virtual CPDF_Dictionary*	GetEncryptDict()
    {
        return m_pEncryptDict;
    }
    virtual CPDF_Object*		ParseIndirectObject(CPDF_IndirectObjects* pObjList, FX_DWORD objnum, PARSE_CONTEXT* pContext = NULL);
    virtual FX_DWORD	GetLastObjNum();
    virtual FX_BOOL		IsFormStream(FX_DWORD objnum, FX_BOOL& bForm);

    FX_FILESIZE			GetObjectOffset(FX_DWORD objnum);

    FX_FILESIZE			GetObjectSize(FX_DWORD objnum);

    int					GetObjectVersion(FX_DWORD objnum)
    {
        return m_ObjVersion[objnum];
    }

    void				GetIndirectBinary(FX_DWORD objnum, FX_BYTE*& pBuffer, FX_DWORD& size);

    FX_BOOL				GetFileStreamOption()
    {
        return m_Syntax.m_bFileStream;
    }

    void				SetFileStreamOption(FX_BOOL b)
    {
        m_Syntax.m_bFileStream = b;
    }

    IFX_FileRead*		GetFileAccess() const
    {
        return m_Syntax.m_pFileAccess;
    }

    int					GetFileVersion() const
    {
        return m_FileVersion;
    }

    FX_BOOL				IsXRefStream() const
    {
        return m_bXRefStream;
    }
    CPDF_Object*		ParseIndirectObjectAt(CPDF_IndirectObjects* pObjList, FX_FILESIZE pos, FX_DWORD objnum,
            struct PARSE_CONTEXT* pContext);

    CPDF_Object*		ParseIndirectObjectAtByStrict(CPDF_IndirectObjects* pObjList, FX_FILESIZE pos, FX_DWORD objnum,
            struct PARSE_CONTEXT* pContext, FX_FILESIZE *pResultPos);

    FX_DWORD			StartAsynParse(IFX_FileRead* pFile, FX_BOOL bReParse = FALSE, FX_BOOL bOwnFileRead = TRUE);

    FX_DWORD			GetFirstPageNo()
    {
        return m_dwFirstPageNo;
    }
protected:

    CPDF_Document*		m_pDocument;

    CPDF_SyntaxParser	m_Syntax;
    FX_BOOL				m_bOwnFileRead;
    CPDF_Object*		ParseDirect(CPDF_Object* pObj);

    FX_BOOL				LoadAllCrossRefV4(FX_FILESIZE pos);

    FX_BOOL				LoadAllCrossRefV5(FX_FILESIZE pos);

    FX_BOOL				LoadCrossRefV4(FX_FILESIZE pos, FX_FILESIZE streampos, FX_BOOL bSkip, FX_BOOL bFirst);

    FX_BOOL				LoadCrossRefV5(FX_FILESIZE pos, FX_FILESIZE& prev, FX_BOOL bMainXRef);

    CPDF_Dictionary*	LoadTrailerV4();

    FX_BOOL				RebuildCrossRef();

    FX_DWORD			SetEncryptHandler();

    void				ReleaseEncryptHandler();

    FX_BOOL				LoadLinearizedAllCrossRefV4(FX_FILESIZE pos, FX_DWORD dwObjCount);

    FX_BOOL				LoadLinearizedCrossRefV4(FX_FILESIZE pos, FX_DWORD dwObjCount);

    FX_BOOL				LoadLinearizedAllCrossRefV5(FX_FILESIZE pos);

    FX_DWORD			LoadLinearizedMainXRefTable();

    CFX_MapPtrToPtr		m_ObjectStreamMap;

    CPDF_StreamAcc*		GetObjectStream(FX_DWORD number);

    FX_BOOL				IsLinearizedFile(IFX_FileRead* pFileAccess, FX_DWORD offset);



    int					m_FileVersion;

    CPDF_Dictionary*	m_pTrailer;

    CPDF_Dictionary*	m_pEncryptDict;
    void SetEncryptDictionary(CPDF_Dictionary* pDict);

    FX_FILESIZE			m_LastXRefOffset;

    FX_BOOL				m_bXRefStream;


    CPDF_SecurityHandler*	m_pSecurityHandler;

    FX_BOOL					m_bForceUseSecurityHandler;

    CFX_ByteString			m_bsRecipient;

    CFX_ByteString		m_FilePath;

    CFX_ByteString		m_Password;

    CFX_FileSizeArray	m_CrossRef;

    CFX_ByteArray		m_V5Type;

    CFX_FileSizeArray	m_SortedOffset;

    CFX_WordArray		m_ObjVersion;
    CFX_ArrayTemplate<CPDF_Dictionary *>	m_Trailers;

    FX_BOOL				m_bVersionUpdated;

    CPDF_Object*		m_pLinearized;

    FX_DWORD			m_dwFirstPageNo;

    FX_DWORD			m_dwXrefStartObjNum;
    friend class		CPDF_Creator;
    friend class		CPDF_DataAvail;
};
#define FXCIPHER_NONE	0
#define FXCIPHER_RC4	1
#define FXCIPHER_AES	2
#define FXCIPHER_AES2   3
class CPDF_SecurityHandler : public CFX_Object
{
public:

    virtual ~CPDF_SecurityHandler() {}

    virtual FX_BOOL		OnInit(CPDF_Parser* pParser, CPDF_Dictionary* pEncryptDict) = 0;

    virtual FX_DWORD	GetPermissions() = 0;

    virtual FX_BOOL		IsOwner() = 0;

    virtual FX_BOOL		GetCryptInfo(int& cipher, FX_LPCBYTE& buffer, int& keylen) = 0;

    virtual FX_BOOL		IsMetadataEncrypted()
    {
        return TRUE;
    }

    virtual CPDF_CryptoHandler*	CreateCryptoHandler() = 0;

    virtual CPDF_StandardSecurityHandler* GetStandardHandler()
    {
        return NULL;
    }
};
#define PDF_ENCRYPT_CONTENT				0
class CPDF_StandardSecurityHandler : public CPDF_SecurityHandler
{
public:
    CPDF_StandardSecurityHandler();

    virtual ~CPDF_StandardSecurityHandler();
    virtual FX_BOOL		OnInit(CPDF_Parser* pParser, CPDF_Dictionary* pEncryptDict);
    virtual FX_DWORD	GetPermissions();
    virtual FX_BOOL		IsOwner()
    {
        return m_bOwner;
    }
    virtual FX_BOOL		GetCryptInfo(int& cipher, FX_LPCBYTE& buffer, int& keylen);
    virtual FX_BOOL		IsMetadataEncrypted();
    virtual CPDF_CryptoHandler*	CreateCryptoHandler();
    virtual CPDF_StandardSecurityHandler* GetStandardHandler()
    {
        return this;
    }

    void				OnCreate(CPDF_Dictionary* pEncryptDict, CPDF_Array* pIdArray,
                                 FX_LPCBYTE user_pass, FX_DWORD user_size,
                                 FX_LPCBYTE owner_pass, FX_DWORD owner_size, FX_DWORD type = PDF_ENCRYPT_CONTENT);

    void				OnCreate(CPDF_Dictionary* pEncryptDict, CPDF_Array* pIdArray,
                                 FX_LPCBYTE user_pass, FX_DWORD user_size, FX_DWORD type = PDF_ENCRYPT_CONTENT);

    CFX_ByteString		GetUserPassword(FX_LPCBYTE owner_pass, FX_DWORD pass_size);
    CFX_ByteString		GetUserPassword(FX_LPCBYTE owner_pass, FX_DWORD pass_size, FX_INT32 key_len);
    int					GetVersion()
    {
        return m_Version;
    }
    int					GetRevision()
    {
        return m_Revision;
    }

    int					CheckPassword(FX_LPCBYTE password, FX_DWORD pass_size, FX_BOOL bOwner, FX_LPBYTE key);
    int					CheckPassword(FX_LPCBYTE password, FX_DWORD pass_size, FX_BOOL bOwner, FX_LPBYTE key, int key_len);
private:

    int					m_Version;

    int					m_Revision;

    CPDF_Parser*		m_pParser;

    CPDF_Dictionary*	m_pEncryptDict;

    FX_BOOL				LoadDict(CPDF_Dictionary* pEncryptDict);
    FX_BOOL				LoadDict(CPDF_Dictionary* pEncryptDict, FX_DWORD type, int& cipher, int& key_len);

    FX_BOOL				CheckUserPassword(FX_LPCBYTE password, FX_DWORD pass_size,
                                          FX_BOOL bIgnoreEncryptMeta, FX_LPBYTE key, FX_INT32 key_len);

    FX_BOOL				CheckOwnerPassword(FX_LPCBYTE password, FX_DWORD pass_size, FX_LPBYTE key, FX_INT32 key_len);
    FX_BOOL				AES256_CheckPassword(FX_LPCBYTE password, FX_DWORD size, FX_BOOL bOwner, FX_LPBYTE key);
    void				AES256_SetPassword(CPDF_Dictionary* pEncryptDict, FX_LPCBYTE password, FX_DWORD size, FX_BOOL bOwner, FX_LPCBYTE key);
    void				AES256_SetPerms(CPDF_Dictionary* pEncryptDict, FX_DWORD permission, FX_BOOL bEncryptMetadata, FX_LPCBYTE key);
    void				OnCreate(CPDF_Dictionary* pEncryptDict, CPDF_Array* pIdArray,
                                 FX_LPCBYTE user_pass, FX_DWORD user_size,
                                 FX_LPCBYTE owner_pass, FX_DWORD owner_size, FX_BOOL bDefault, FX_DWORD type);
    FX_BOOL				CheckSecurity(FX_INT32 key_len);

    FX_BOOL				m_bOwner;

    FX_DWORD			m_Permissions;

    int					m_Cipher;

    FX_BYTE				m_EncryptKey[32];

    int					m_KeyLen;
};
class CPDF_CryptoHandler : public CFX_Object
{
public:

    virtual ~CPDF_CryptoHandler() {}

    virtual FX_BOOL		Init(CPDF_Dictionary* pEncryptDict, CPDF_SecurityHandler* pSecurityHandler) = 0;

    virtual FX_DWORD	DecryptGetSize(FX_DWORD src_size) = 0;

    virtual FX_LPVOID	DecryptStart(FX_DWORD objnum, FX_DWORD gennum) = 0;

    virtual FX_BOOL		DecryptStream(FX_LPVOID context, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf) = 0;

    virtual FX_BOOL		DecryptFinish(FX_LPVOID context, CFX_BinaryBuf& dest_buf) = 0;


    virtual FX_DWORD	EncryptGetSize(FX_DWORD objnum, FX_DWORD version, FX_LPCBYTE src_buf, FX_DWORD src_size) = 0;

    virtual FX_BOOL		EncryptContent(FX_DWORD objnum, FX_DWORD version, FX_LPCBYTE src_buf, FX_DWORD src_size,
                                       FX_LPBYTE dest_buf, FX_DWORD& dest_size) = 0;

    void				Decrypt(FX_DWORD objnum, FX_DWORD version, CFX_ByteString& str);
};
class CPDF_StandardCryptoHandler : public CPDF_CryptoHandler
{
public:

    CPDF_StandardCryptoHandler();

    virtual ~CPDF_StandardCryptoHandler();

    FX_BOOL				Init(int cipher, FX_LPCBYTE key, int keylen);
    virtual FX_BOOL		Init(CPDF_Dictionary* pEncryptDict, CPDF_SecurityHandler* pSecurityHandler);
    virtual FX_DWORD	DecryptGetSize(FX_DWORD src_size);
    virtual FX_LPVOID	DecryptStart(FX_DWORD objnum, FX_DWORD gennum);
    virtual FX_BOOL		DecryptStream(FX_LPVOID context, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf);
    virtual FX_BOOL		DecryptFinish(FX_LPVOID context, CFX_BinaryBuf& dest_buf);
    virtual FX_DWORD	EncryptGetSize(FX_DWORD objnum, FX_DWORD version, FX_LPCBYTE src_buf, FX_DWORD src_size);
    virtual FX_BOOL		EncryptContent(FX_DWORD objnum, FX_DWORD version, FX_LPCBYTE src_buf, FX_DWORD src_size,
                                       FX_LPBYTE dest_buf, FX_DWORD& dest_size);
protected:

    virtual void		CryptBlock(FX_BOOL bEncrypt, FX_DWORD objnum, FX_DWORD gennum, FX_LPCBYTE src_buf, FX_DWORD src_size,
                                   FX_LPBYTE dest_buf, FX_DWORD& dest_size);
    virtual FX_LPVOID	CryptStart(FX_DWORD objnum, FX_DWORD gennum, FX_BOOL bEncrypt);
    virtual FX_BOOL		CryptStream(FX_LPVOID context, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf, FX_BOOL bEncrypt);
    virtual FX_BOOL		CryptFinish(FX_LPVOID context, CFX_BinaryBuf& dest_buf, FX_BOOL bEncrypt);

    FX_BYTE				m_EncryptKey[32];

    int					m_KeyLen;

    int					m_Cipher;

    FX_LPBYTE			m_pAESContext;
};
class CPDF_Point : public CFX_Object
{
public:

    CPDF_Point(FX_FLOAT xx, FX_FLOAT yy)
    {
        x = xx;
        y = yy;
    }

    FX_FLOAT			x;

    FX_FLOAT			y;
};

#define CPDF_Rect		CFX_FloatRect
#define CPDF_Matrix		CFX_AffineMatrix
CFX_ByteString PDF_NameDecode(FX_BSTR orig);
CFX_ByteString PDF_NameDecode(const CFX_ByteString& orig);
CFX_ByteString PDF_NameEncode(const CFX_ByteString& orig);
CFX_ByteString PDF_EncodeString(const CFX_ByteString& src, FX_BOOL bHex = FALSE);
CFX_WideString PDF_DecodeText(const CFX_ByteString& str, CFX_CharMap* pCharMap = NULL);
CFX_WideString PDF_DecodeText(FX_LPCBYTE pData, FX_DWORD size, CFX_CharMap* pCharMap = NULL);
CFX_ByteString PDF_EncodeText(FX_LPCWSTR pString, int len = -1, CFX_CharMap* pCharMap = NULL);
FX_FLOAT PDF_ClipFloat(FX_FLOAT f);
class CFDF_Document : public CPDF_IndirectObjects
{
public:

    static CFDF_Document*	CreateNewDoc();

    static CFDF_Document*	ParseFile(FX_LPCSTR file_path);

    static CFDF_Document*	ParseFile(FX_LPCWSTR file_path);

    static CFDF_Document*	ParseFile(IFX_FileRead *pFile, FX_BOOL bOwnFile = FALSE);

    static CFDF_Document*	ParseMemory(FX_LPCBYTE pData, FX_DWORD size);

    ~CFDF_Document();

    FX_BOOL					WriteFile(FX_LPCSTR file_path) const;

    FX_BOOL					WriteFile(FX_LPCWSTR file_path) const;

    FX_BOOL					WriteFile(IFX_FileWrite *pFile) const;

    FX_BOOL					WriteBuf(CFX_ByteTextBuf& buf) const;

    CPDF_Dictionary*		GetRoot() const
    {
        return m_pRootDict;
    }

    CFX_WideString			GetWin32Path() const;
protected:

    CFDF_Document();
    void	ParseStream(IFX_FileRead *pFile, FX_BOOL bOwnFile);
    CPDF_Dictionary*		m_pRootDict;
    IFX_FileRead*			m_pFile;
    FX_BOOL					m_bOwnFile;
};

CFX_WideString	FPDF_FileSpec_GetWin32Path(const CPDF_Object* pFileSpec);
void			FPDF_FileSpec_SetWin32Path(CPDF_Object* pFileSpec, const CFX_WideString& fullpath);

void FlateEncode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size);
FX_DWORD FlateDecode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size);
FX_DWORD RunLengthDecode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size);
class CPDF_NumberTree : public CFX_Object
{
public:

    CPDF_NumberTree(CPDF_Dictionary* pRoot)
    {
        m_pRoot = pRoot;
    }

    CPDF_Object*		LookupValue(int num);
protected:

    CPDF_Dictionary*	m_pRoot;
};

class IFX_FileAvail
{
public:

    virtual FX_BOOL			IsDataAvail( FX_FILESIZE offset, FX_DWORD size) = 0;
};
class IFX_DownloadHints
{
public:

    virtual void			AddSegment(FX_FILESIZE offset, FX_DWORD size) = 0;
};
#define PDF_IS_LINEARIZED			1
#define PDF_NOT_LINEARIZED			0
#define PDF_UNKNOW_LINEARIZED		-1
#define PDFFORM_NOTAVAIL		0
#define PDFFORM_AVAIL			1
#define PDFFORM_NOTEXIST		2
class IPDF_DataAvail
{
public:

    virtual FX_BOOL			IsDocAvail(IFX_DownloadHints* pHints) = 0;


    virtual void			SetDocument(CPDF_Document* pDoc) = 0;


    virtual FX_BOOL			IsPageAvail(int iPage, IFX_DownloadHints* pHints) = 0;

    virtual FX_BOOL			IsLinearized() = 0;

    virtual FX_INT32		IsFormAvail(IFX_DownloadHints *pHints) = 0;

    virtual FX_INT32		IsLinearizedPDF() = 0;

    virtual void				GetLinearizedMainXRefInfo(FX_FILESIZE *pPos, FX_DWORD *pSize) = 0;
};
class CPDF_SortObjNumArray : public CFX_Object
{
public:

    void AddObjNum(FX_DWORD dwObjNum);

    FX_BOOL Find(FX_DWORD dwObjNum);

    void RemoveAll()
    {
        m_number_array.RemoveAll();
    }
protected:

    FX_BOOL BinarySearch(FX_DWORD value, int &iNext);
protected:

    CFX_DWordArray			m_number_array;
};
enum PDF_PAGENODE_TYPE {
    PDF_PAGENODE_UNKOWN = 0,
    PDF_PAGENODE_PAGE,
    PDF_PAGENODE_PAGES,
    PDF_PAGENODE_ARRAY,
};
class CPDF_PageNode : public CFX_Object
{
public:
    CPDF_PageNode() : m_type(PDF_PAGENODE_UNKOWN) {}
    ~CPDF_PageNode();
    PDF_PAGENODE_TYPE	m_type;
    FX_DWORD			m_dwPageNo;
    CFX_PtrArray		m_childNode;
};
enum PDF_DATAAVAIL_STATUS {
    PDF_DATAAVAIL_HEADER = 0,
    PDF_DATAAVAIL_FIRSTPAGE,
    PDF_DATAAVAIL_FIRSTPAGE_PREPARE,
    PDF_DATAAVAIL_END,
    PDF_DATAAVAIL_CROSSREF,
    PDF_DATAAVAIL_CROSSREF_ITEM,
    PDF_DATAAVAIL_CROSSREF_STREAM,
    PDF_DATAAVAIL_TRAILER,
    PDF_DATAAVAIL_LOADALLCRSOSSREF,
    PDF_DATAAVAIL_ROOT,
    PDF_DATAAVAIL_INFO,
    PDF_DATAAVAIL_ACROFORM,
    PDF_DATAAVAIL_ACROFORM_SUBOBJECT,
    PDF_DATAAVAIL_PAGETREE,
    PDF_DATAAVAIL_PAGE,
    PDF_DATAAVAIL_PAGE_LATERLOAD,
    PDF_DATAAVAIL_RESOURCES,
    PDF_DATAAVAIL_DONE,
    PDF_DATAAVAIL_ERROR,
    PDF_DATAAVAIL_LOADALLFILE,
    PDF_DATAAVAIL_TRAILER_APPEND
};
class CPDF_DataAvail FX_FINAL : public CFX_Object, public IPDF_DataAvail
{
public:

    CPDF_DataAvail(IFX_FileAvail* pFileAvail, IFX_FileRead* pFileRead);
    ~CPDF_DataAvail();

    virtual FX_BOOL				IsDocAvail(IFX_DownloadHints* pHints);


    virtual void				SetDocument(CPDF_Document* pDoc);


    virtual FX_BOOL				IsPageAvail(int iPage, IFX_DownloadHints* pHints);

    virtual FX_INT32			IsFormAvail(IFX_DownloadHints *pHints);

    virtual FX_INT32			IsLinearizedPDF();

    virtual FX_BOOL				IsLinearized()
    {
        return m_bLinearized;
    }

    virtual void				GetLinearizedMainXRefInfo(FX_FILESIZE *pPos, FX_DWORD *pSize);
    IFX_FileRead*				GetFileRead() const
    {
        return m_pFileRead;
    }
    IFX_FileAvail*				GetFileAvail() const
    {
        return m_pFileAvail;
    }
protected:
    FX_DWORD					GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset);
    FX_BOOL						IsObjectsAvail(CFX_PtrArray& obj_array, FX_BOOL bParsePage, IFX_DownloadHints* pHints, CFX_PtrArray &ret_array);
    FX_BOOL						CheckDocStatus(IFX_DownloadHints *pHints);
    FX_BOOL						CheckHeader(IFX_DownloadHints* pHints);
    FX_BOOL						CheckFirstPage(IFX_DownloadHints *pHints);
    FX_BOOL						CheckEnd(IFX_DownloadHints *pHints);
    FX_BOOL						CheckCrossRef(IFX_DownloadHints* pHints);
    FX_BOOL						CheckCrossRefItem(IFX_DownloadHints *pHints);
    FX_BOOL						CheckTrailer(IFX_DownloadHints* pHints);
    FX_BOOL						CheckRoot(IFX_DownloadHints* pHints);
    FX_BOOL						CheckInfo(IFX_DownloadHints* pHints);
    FX_BOOL						CheckPages(IFX_DownloadHints* pHints);
    FX_BOOL						CheckPage(IFX_DownloadHints* pHints);
    FX_BOOL						CheckResources(IFX_DownloadHints* pHints);
    FX_BOOL						CheckAnnots(IFX_DownloadHints* pHints);
    FX_BOOL						CheckAcroForm(IFX_DownloadHints* pHints);
    FX_BOOL						CheckAcroFormSubObject(IFX_DownloadHints* pHints);
    FX_BOOL						CheckTrailerAppend(IFX_DownloadHints* pHints);
    FX_BOOL						CheckPageStatus(IFX_DownloadHints* pHints);
    FX_BOOL						CheckAllCrossRefStream(IFX_DownloadHints *pHints);

    FX_DWORD					CheckCrossRefStream(IFX_DownloadHints *pHints, FX_FILESIZE &xref_offset);
    FX_BOOL						IsLinearizedFile(FX_LPBYTE pData, FX_DWORD dwLen);
    void						SetStartOffset(FX_FILESIZE dwOffset);
    FX_BOOL						GetNextToken(CFX_ByteString &token);
    FX_BOOL						GetNextChar(FX_BYTE &ch);
    CPDF_Object	*				ParseIndirectObjectAt(FX_FILESIZE pos, FX_DWORD objnum);
    CPDF_Object	*				GetObject(FX_DWORD objnum, IFX_DownloadHints* pHints, FX_BOOL *pExistInFile);
    FX_BOOL						GetPageKids(CPDF_Parser *pParser, CPDF_Object *pPages);
    FX_BOOL						PreparePageItem();
    FX_BOOL						LoadPages(IFX_DownloadHints* pHints);
    FX_BOOL						LoadAllXref(IFX_DownloadHints* pHints);
    FX_BOOL						LoadAllFile(IFX_DownloadHints* pHints);
    FX_BOOL						CheckLinearizedData(IFX_DownloadHints* pHints);
    FX_BOOL						CheckFileResources(IFX_DownloadHints* pHints);
    FX_BOOL						CheckPageAnnots(int iPage, IFX_DownloadHints* pHints);

    FX_BOOL						CheckLinearizedFirstPage(int iPage, IFX_DownloadHints* pHints);
    FX_BOOL						HaveResourceAncestor(CPDF_Dictionary *pDict);
    FX_BOOL						CheckPage(FX_INT32 iPage, IFX_DownloadHints* pHints);
    FX_BOOL						LoadDocPages(IFX_DownloadHints* pHints);
    FX_BOOL						LoadDocPage(FX_INT32 iPage, IFX_DownloadHints* pHints);
    FX_BOOL						CheckPageNode(CPDF_PageNode &pageNodes, FX_INT32 iPage, FX_INT32 &iCount, IFX_DownloadHints* pHints);
    FX_BOOL						CheckUnkownPageNode(FX_DWORD dwPageNo, CPDF_PageNode *pPageNode, IFX_DownloadHints* pHints);
    FX_BOOL						CheckArrayPageNode(FX_DWORD dwPageNo, CPDF_PageNode *pPageNode, IFX_DownloadHints* pHints);
    FX_BOOL                     CheckPageCount(IFX_DownloadHints* pHints);
    FX_BOOL						IsFirstCheck(int iPage);
    void						ResetFirstCheck(int iPage);

    CPDF_Parser				m_parser;

    CPDF_SyntaxParser		m_syntaxParser;

    CPDF_Object				*m_pRoot;

    FX_DWORD				m_dwRootObjNum;

    FX_DWORD				m_dwInfoObjNum;

    CPDF_Object				*m_pLinearized;

    CPDF_Object				*m_pTrailer;

    FX_BOOL					m_bDocAvail;

    FX_FILESIZE				m_dwHeaderOffset;

    FX_FILESIZE				m_dwLastXRefOffset;

    FX_FILESIZE				m_dwXRefOffset;

    FX_FILESIZE				m_dwTrailerOffset;

    FX_FILESIZE				m_dwCurrentOffset;

    PDF_DATAAVAIL_STATUS	m_docStatus;

    IFX_FileAvail*			m_pFileAvail;

    IFX_FileRead*			m_pFileRead;

    FX_FILESIZE				m_dwFileLen;

    CPDF_Document*			m_pDocument;

    CPDF_SortObjNumArray	m_objnum_array;

    CFX_PtrArray			m_objs_array;

    FX_FILESIZE				m_Pos;

    FX_FILESIZE				m_bufferOffset;

    FX_DWORD				m_bufferSize;

    CFX_ByteString			m_WordBuf;

    FX_BYTE					m_WordBuffer[257];

    FX_DWORD				m_WordSize;

    FX_BYTE					m_bufferData[512];

    CFX_FileSizeArray		m_CrossOffset;

    CFX_DWordArray			m_XRefStreamList;

    CFX_DWordArray			m_PageObjList;

    FX_DWORD				m_PagesObjNum;

    FX_BOOL					m_bLinearized;

    FX_DWORD				m_dwFirstPageNo;

    FX_BOOL					m_bLinearedDataOK;

    FX_BOOL					m_bMainXRefLoad;

    FX_BOOL					m_bMainXRefLoadedOK;

    FX_BOOL					m_bPagesTreeLoad;

    FX_BOOL					m_bPagesLoad;

    CPDF_Parser *			m_pCurrentParser;

    FX_FILESIZE				m_dwCurrentXRefSteam;

    FX_BOOL					m_bAnnotsLoad;

    FX_BOOL					m_bHaveAcroForm;

    FX_DWORD				m_dwAcroFormObjNum;

    FX_BOOL					m_bAcroFormLoad;

    CPDF_Object	*			m_pAcroForm;

    CFX_PtrArray			m_arrayAcroforms;

    CPDF_Dictionary *		m_pPageDict;

    CPDF_Object *			m_pPageResource;

    FX_BOOL					m_bNeedDownLoadResource;

    FX_BOOL					m_bPageLoadedOK;

    FX_BOOL					m_bLinearizedFormParamLoad;

    CFX_PtrArray			m_PagesArray;

    FX_DWORD				m_dwEncryptObjNum;

    FX_FILESIZE				m_dwPrevXRefOffset;

    FX_BOOL					m_bTotalLoadPageTree;

    FX_BOOL					m_bCurPageDictLoadOK;

    CPDF_PageNode			m_pageNodes;

    CFX_CMapDWordToDWord *	m_pageMapCheckState;

    CFX_CMapDWordToDWord *	m_pagesLoadState;
};
#endif