From 488b7ad845d6de212d89cd957303b294ecfa5922 Mon Sep 17 00:00:00 2001 From: dsinclair Date: Tue, 4 Oct 2016 11:55:50 -0700 Subject: Move core/fpdfapi/fpdf_parser to core/fpdfapi/parser BUG=pdfium:603 Review-Url: https://codereview.chromium.org/2392603004 --- BUILD.gn | 110 +- core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp | 12 +- core/fpdfapi/edit/cpdf_pagecontentgenerator.h | 2 +- core/fpdfapi/edit/fpdf_edit_create.cpp | 22 +- core/fpdfapi/font/cpdf_cidfont.cpp | 6 +- core/fpdfapi/font/cpdf_font.cpp | 10 +- core/fpdfapi/font/cpdf_fontencoding.cpp | 10 +- core/fpdfapi/font/cpdf_simplefont.cpp | 4 +- core/fpdfapi/font/cpdf_truetypefont.cpp | 2 +- core/fpdfapi/font/cpdf_type1font.cpp | 2 +- core/fpdfapi/font/cpdf_type3font.cpp | 4 +- core/fpdfapi/font/fpdf_font.cpp | 14 +- core/fpdfapi/font/fpdf_font_cid.cpp | 6 +- core/fpdfapi/fpdf_parser/cfdf_document.cpp | 102 -- core/fpdfapi/fpdf_parser/cfdf_document.h | 42 - core/fpdfapi/fpdf_parser/cpdf_array.cpp | 200 --- core/fpdfapi/fpdf_parser/cpdf_array.h | 72 - core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp | 180 -- core/fpdfapi/fpdf_parser/cpdf_boolean.cpp | 45 - core/fpdfapi/fpdf_parser/cpdf_boolean.h | 35 - core/fpdfapi/fpdf_parser/cpdf_crypto_handler.cpp | 342 ---- core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h | 70 - core/fpdfapi/fpdf_parser/cpdf_data_avail.cpp | 1844 -------------------- core/fpdfapi/fpdf_parser/cpdf_data_avail.h | 253 --- core/fpdfapi/fpdf_parser/cpdf_dictionary.cpp | 275 --- core/fpdfapi/fpdf_parser/cpdf_dictionary.h | 98 -- core/fpdfapi/fpdf_parser/cpdf_document.cpp | 1020 ----------- core/fpdfapi/fpdf_parser/cpdf_document.h | 145 -- core/fpdfapi/fpdf_parser/cpdf_hint_tables.cpp | 524 ------ core/fpdfapi/fpdf_parser/cpdf_hint_tables.h | 71 - .../fpdf_parser/cpdf_indirect_object_holder.cpp | 79 - .../fpdf_parser/cpdf_indirect_object_holder.h | 48 - core/fpdfapi/fpdf_parser/cpdf_name.cpp | 45 - core/fpdfapi/fpdf_parser/cpdf_name.h | 32 - core/fpdfapi/fpdf_parser/cpdf_null.cpp | 17 - core/fpdfapi/fpdf_parser/cpdf_null.h | 21 - core/fpdfapi/fpdf_parser/cpdf_number.cpp | 55 - core/fpdfapi/fpdf_parser/cpdf_number.h | 44 - core/fpdfapi/fpdf_parser/cpdf_object.cpp | 165 -- core/fpdfapi/fpdf_parser/cpdf_object.h | 183 -- core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp | 835 --------- core/fpdfapi/fpdf_parser/cpdf_parser.cpp | 1637 ----------------- core/fpdfapi/fpdf_parser/cpdf_parser.h | 177 -- .../fpdf_parser/cpdf_parser_embeddertest.cpp | 59 - core/fpdfapi/fpdf_parser/cpdf_parser_unittest.cpp | 202 --- core/fpdfapi/fpdf_parser/cpdf_reference.cpp | 83 - core/fpdfapi/fpdf_parser/cpdf_reference.h | 50 - core/fpdfapi/fpdf_parser/cpdf_security_handler.cpp | 699 -------- core/fpdfapi/fpdf_parser/cpdf_security_handler.h | 110 -- .../cpdf_security_handler_embeddertest.cpp | 32 - core/fpdfapi/fpdf_parser/cpdf_simple_parser.cpp | 170 -- core/fpdfapi/fpdf_parser/cpdf_simple_parser.h | 35 - .../fpdf_parser/cpdf_simple_parser_unittest.cpp | 96 - core/fpdfapi/fpdf_parser/cpdf_stream.cpp | 119 -- core/fpdfapi/fpdf_parser/cpdf_stream.h | 61 - core/fpdfapi/fpdf_parser/cpdf_stream_acc.cpp | 91 - core/fpdfapi/fpdf_parser/cpdf_stream_acc.h | 46 - core/fpdfapi/fpdf_parser/cpdf_string.cpp | 52 - core/fpdfapi/fpdf_parser/cpdf_string.h | 39 - core/fpdfapi/fpdf_parser/cpdf_syntax_parser.cpp | 997 ----------- core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h | 101 -- .../fpdf_parser/cpdf_syntax_parser_unittest.cpp | 171 -- core/fpdfapi/fpdf_parser/fpdf_parser_decode.cpp | 575 ------ core/fpdfapi/fpdf_parser/fpdf_parser_decode.h | 77 - .../fpdf_parser_decode_embeddertest.cpp | 117 -- .../fpdf_parser/fpdf_parser_decode_unittest.cpp | 78 - core/fpdfapi/fpdf_parser/fpdf_parser_utility.cpp | 221 --- core/fpdfapi/fpdf_parser/fpdf_parser_utility.h | 39 - core/fpdfapi/fpdf_render/fpdf_render.cpp | 6 +- core/fpdfapi/fpdf_render/fpdf_render_cache.cpp | 2 +- core/fpdfapi/fpdf_render/fpdf_render_image.cpp | 6 +- core/fpdfapi/fpdf_render/fpdf_render_loadimage.cpp | 6 +- core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp | 4 +- core/fpdfapi/fpdf_render/fpdf_render_text.cpp | 4 +- core/fpdfapi/fpdf_render/render_int.h | 2 +- core/fpdfapi/page/cpdf_allstates.cpp | 4 +- core/fpdfapi/page/cpdf_color.cpp | 4 +- core/fpdfapi/page/cpdf_colorspace.cpp | 14 +- core/fpdfapi/page/cpdf_contentmark.cpp | 2 +- core/fpdfapi/page/cpdf_contentmarkitem.cpp | 2 +- core/fpdfapi/page/cpdf_form.cpp | 4 +- core/fpdfapi/page/cpdf_generalstate.cpp | 2 +- core/fpdfapi/page/cpdf_image.cpp | 8 +- core/fpdfapi/page/cpdf_image.h | 2 +- core/fpdfapi/page/cpdf_imageobject.cpp | 2 +- core/fpdfapi/page/cpdf_meshstream.cpp | 2 +- core/fpdfapi/page/cpdf_meshstream.h | 2 +- core/fpdfapi/page/cpdf_page.cpp | 6 +- core/fpdfapi/page/cpdf_pageobjectholder.cpp | 2 +- core/fpdfapi/page/cpdf_shadingobject.cpp | 2 +- core/fpdfapi/page/cpdf_shadingpattern.cpp | 8 +- core/fpdfapi/page/cpdf_textstate.cpp | 2 +- core/fpdfapi/page/cpdf_tilingpattern.cpp | 6 +- core/fpdfapi/page/fpdf_page_colors.cpp | 12 +- core/fpdfapi/page/fpdf_page_doc.cpp | 8 +- core/fpdfapi/page/fpdf_page_func.cpp | 10 +- core/fpdfapi/page/fpdf_page_parser.cpp | 18 +- core/fpdfapi/page/fpdf_page_parser_old.cpp | 24 +- core/fpdfapi/parser/cfdf_document.cpp | 102 ++ core/fpdfapi/parser/cfdf_document.h | 42 + core/fpdfapi/parser/cpdf_array.cpp | 200 +++ core/fpdfapi/parser/cpdf_array.h | 72 + core/fpdfapi/parser/cpdf_array_unittest.cpp | 180 ++ core/fpdfapi/parser/cpdf_boolean.cpp | 45 + core/fpdfapi/parser/cpdf_boolean.h | 35 + core/fpdfapi/parser/cpdf_crypto_handler.cpp | 342 ++++ core/fpdfapi/parser/cpdf_crypto_handler.h | 70 + core/fpdfapi/parser/cpdf_data_avail.cpp | 1844 ++++++++++++++++++++ core/fpdfapi/parser/cpdf_data_avail.h | 253 +++ core/fpdfapi/parser/cpdf_dictionary.cpp | 275 +++ core/fpdfapi/parser/cpdf_dictionary.h | 98 ++ core/fpdfapi/parser/cpdf_document.cpp | 1020 +++++++++++ core/fpdfapi/parser/cpdf_document.h | 145 ++ core/fpdfapi/parser/cpdf_hint_tables.cpp | 524 ++++++ core/fpdfapi/parser/cpdf_hint_tables.h | 71 + .../fpdfapi/parser/cpdf_indirect_object_holder.cpp | 79 + core/fpdfapi/parser/cpdf_indirect_object_holder.h | 48 + core/fpdfapi/parser/cpdf_name.cpp | 45 + core/fpdfapi/parser/cpdf_name.h | 32 + core/fpdfapi/parser/cpdf_null.cpp | 17 + core/fpdfapi/parser/cpdf_null.h | 21 + core/fpdfapi/parser/cpdf_number.cpp | 55 + core/fpdfapi/parser/cpdf_number.h | 44 + core/fpdfapi/parser/cpdf_object.cpp | 165 ++ core/fpdfapi/parser/cpdf_object.h | 183 ++ core/fpdfapi/parser/cpdf_object_unittest.cpp | 835 +++++++++ core/fpdfapi/parser/cpdf_parser.cpp | 1637 +++++++++++++++++ core/fpdfapi/parser/cpdf_parser.h | 177 ++ core/fpdfapi/parser/cpdf_parser_embeddertest.cpp | 59 + core/fpdfapi/parser/cpdf_parser_unittest.cpp | 202 +++ core/fpdfapi/parser/cpdf_reference.cpp | 83 + core/fpdfapi/parser/cpdf_reference.h | 50 + core/fpdfapi/parser/cpdf_security_handler.cpp | 699 ++++++++ core/fpdfapi/parser/cpdf_security_handler.h | 110 ++ .../parser/cpdf_security_handler_embeddertest.cpp | 32 + core/fpdfapi/parser/cpdf_simple_parser.cpp | 170 ++ core/fpdfapi/parser/cpdf_simple_parser.h | 35 + .../fpdfapi/parser/cpdf_simple_parser_unittest.cpp | 96 + core/fpdfapi/parser/cpdf_stream.cpp | 116 ++ core/fpdfapi/parser/cpdf_stream.h | 61 + core/fpdfapi/parser/cpdf_stream_acc.cpp | 91 + core/fpdfapi/parser/cpdf_stream_acc.h | 46 + core/fpdfapi/parser/cpdf_string.cpp | 52 + core/fpdfapi/parser/cpdf_string.h | 39 + core/fpdfapi/parser/cpdf_syntax_parser.cpp | 997 +++++++++++ core/fpdfapi/parser/cpdf_syntax_parser.h | 101 ++ .../fpdfapi/parser/cpdf_syntax_parser_unittest.cpp | 171 ++ core/fpdfapi/parser/fpdf_parser_decode.cpp | 575 ++++++ core/fpdfapi/parser/fpdf_parser_decode.h | 77 + .../parser/fpdf_parser_decode_embeddertest.cpp | 117 ++ .../fpdfapi/parser/fpdf_parser_decode_unittest.cpp | 78 + core/fpdfapi/parser/fpdf_parser_utility.cpp | 221 +++ core/fpdfapi/parser/fpdf_parser_utility.h | 39 + core/fpdfdoc/cpdf_action.cpp | 4 +- core/fpdfdoc/cpdf_action.h | 2 +- core/fpdfdoc/cpdf_actionfields.cpp | 4 +- core/fpdfdoc/cpdf_annot.cpp | 4 +- core/fpdfdoc/cpdf_annotlist.cpp | 4 +- core/fpdfdoc/cpdf_apsettings.cpp | 4 +- core/fpdfdoc/cpdf_bookmark.cpp | 4 +- core/fpdfdoc/cpdf_bookmarktree.cpp | 2 +- core/fpdfdoc/cpdf_defaultappearance.cpp | 4 +- core/fpdfdoc/cpdf_dest.cpp | 4 +- core/fpdfdoc/cpdf_filespec.cpp | 6 +- core/fpdfdoc/cpdf_filespec_unittest.cpp | 6 +- core/fpdfdoc/cpdf_formcontrol.cpp | 8 +- core/fpdfdoc/cpdf_formfield.cpp | 14 +- core/fpdfdoc/cpdf_formfield_unittest.cpp | 4 +- core/fpdfdoc/cpdf_iconfit.cpp | 4 +- core/fpdfdoc/cpdf_interform.cpp | 8 +- core/fpdfdoc/cpdf_interform.h | 2 +- core/fpdfdoc/cpdf_link.cpp | 2 +- core/fpdfdoc/cpdf_linklist.cpp | 2 +- core/fpdfdoc/cpdf_metadata.cpp | 6 +- core/fpdfdoc/cpdf_nametree.cpp | 6 +- core/fpdfdoc/cpdf_numbertree.cpp | 4 +- core/fpdfdoc/cpdf_occontext.cpp | 4 +- core/fpdfdoc/cpdf_pagelabel.cpp | 6 +- core/fpdfdoc/cpdf_viewerpreferences.cpp | 2 +- core/fpdfdoc/cpvt_color.cpp | 2 +- core/fpdfdoc/cpvt_color.h | 2 +- core/fpdfdoc/cpvt_fontmap.cpp | 4 +- core/fpdfdoc/cpvt_generateap.cpp | 10 +- core/fpdfdoc/doc_tagged.cpp | 10 +- core/fpdftext/cpdf_textpage.cpp | 4 +- core/fxcodec/codec/fx_codec_jbig.cpp | 2 +- core/fxcodec/jbig2/JBig2_BitStream.cpp | 4 +- core/fxcodec/jbig2/JBig2_Context.cpp | 4 +- core/fxcodec/jbig2/JBig2_Context.h | 2 +- core/fxge/dib/fx_dib_engine_unittest.cpp | 6 +- core/fxge/ge/cfx_graphstate.cpp | 2 +- core/fxge/skia/fx_skia_device.cpp | 6 +- fpdfsdk/DEPS | 2 +- fpdfsdk/cfx_systemhandler.cpp | 2 +- fpdfsdk/cpdfsdk_baannot.cpp | 10 +- fpdfsdk/cpdfsdk_baannothandler.cpp | 2 +- fpdfsdk/cpdfsdk_document.cpp | 8 +- fpdfsdk/cpdfsdk_document.h | 2 +- fpdfsdk/cpdfsdk_environment.h | 2 +- fpdfsdk/cpdfsdk_interform.cpp | 8 +- fpdfsdk/cpdfsdk_pageview.cpp | 2 +- fpdfsdk/cpdfsdk_widget.cpp | 6 +- fpdfsdk/cpdfsdk_widgethandler.cpp | 2 +- fpdfsdk/formfiller/cba_fontmap.cpp | 8 +- fpdfsdk/formfiller/cffl_interactiveformfiller.cpp | 2 +- fpdfsdk/fpdf_dataavail.cpp | 4 +- fpdfsdk/fpdf_ext.cpp | 4 +- fpdfsdk/fpdf_flatten.cpp | 10 +- fpdfsdk/fpdf_transformpage.cpp | 10 +- fpdfsdk/fpdfdoc.cpp | 4 +- fpdfsdk/fpdfdoc_unittest.cpp | 12 +- fpdfsdk/fpdfeditpage.cpp | 8 +- fpdfsdk/fpdfformfill.cpp | 2 +- fpdfsdk/fpdfppo.cpp | 14 +- fpdfsdk/fpdfsave.cpp | 10 +- fpdfsdk/fpdfview.cpp | 6 +- fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp | 6 +- fpdfsdk/fpdfxfa/fpdfxfa_doc.cpp | 2 +- fpdfsdk/fpdfxfa/fpdfxfa_page.cpp | 2 +- fpdfsdk/fsdk_actionhandler.cpp | 2 +- fpdfsdk/fsdk_define.h | 2 +- fpdfsdk/fxedit/fxet_ap.cpp | 2 +- fpdfsdk/fxedit/fxet_edit.cpp | 2 +- fpdfsdk/javascript/Document.cpp | 6 +- fpdfsdk/javascript/Field.cpp | 2 +- fpdfsdk/pdfwindow/PWL_FontMap.cpp | 4 +- fpdfsdk/pdfwindow/PWL_Icon.cpp | 4 +- xfa/DEPS | 2 +- xfa/fxfa/app/DEPS | 2 +- xfa/fxfa/app/xfa_ffdoc.cpp | 6 +- xfa/fxfa/app/xfa_fontmgr.cpp | 4 +- xfa/fxfa/xfa_ffapp.h | 4 +- 232 files changed, 13348 insertions(+), 13351 deletions(-) delete mode 100644 core/fpdfapi/fpdf_parser/cfdf_document.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cfdf_document.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_array.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_array.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_boolean.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_boolean.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_crypto_handler.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_data_avail.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_data_avail.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_dictionary.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_dictionary.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_document.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_document.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_hint_tables.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_hint_tables.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_name.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_name.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_null.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_null.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_number.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_number.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_object.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_object.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_parser.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_parser.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_parser_embeddertest.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_parser_unittest.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_reference.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_reference.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_security_handler.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_security_handler.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_security_handler_embeddertest.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_simple_parser.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_simple_parser.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_simple_parser_unittest.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_stream.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_stream.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_stream_acc.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_stream_acc.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_string.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_string.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_syntax_parser.cpp delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h delete mode 100644 core/fpdfapi/fpdf_parser/cpdf_syntax_parser_unittest.cpp delete mode 100644 core/fpdfapi/fpdf_parser/fpdf_parser_decode.cpp delete mode 100644 core/fpdfapi/fpdf_parser/fpdf_parser_decode.h delete mode 100644 core/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp delete mode 100644 core/fpdfapi/fpdf_parser/fpdf_parser_decode_unittest.cpp delete mode 100644 core/fpdfapi/fpdf_parser/fpdf_parser_utility.cpp delete mode 100644 core/fpdfapi/fpdf_parser/fpdf_parser_utility.h create mode 100644 core/fpdfapi/parser/cfdf_document.cpp create mode 100644 core/fpdfapi/parser/cfdf_document.h create mode 100644 core/fpdfapi/parser/cpdf_array.cpp create mode 100644 core/fpdfapi/parser/cpdf_array.h create mode 100644 core/fpdfapi/parser/cpdf_array_unittest.cpp create mode 100644 core/fpdfapi/parser/cpdf_boolean.cpp create mode 100644 core/fpdfapi/parser/cpdf_boolean.h create mode 100644 core/fpdfapi/parser/cpdf_crypto_handler.cpp create mode 100644 core/fpdfapi/parser/cpdf_crypto_handler.h create mode 100644 core/fpdfapi/parser/cpdf_data_avail.cpp create mode 100644 core/fpdfapi/parser/cpdf_data_avail.h create mode 100644 core/fpdfapi/parser/cpdf_dictionary.cpp create mode 100644 core/fpdfapi/parser/cpdf_dictionary.h create mode 100644 core/fpdfapi/parser/cpdf_document.cpp create mode 100644 core/fpdfapi/parser/cpdf_document.h create mode 100644 core/fpdfapi/parser/cpdf_hint_tables.cpp create mode 100644 core/fpdfapi/parser/cpdf_hint_tables.h create mode 100644 core/fpdfapi/parser/cpdf_indirect_object_holder.cpp create mode 100644 core/fpdfapi/parser/cpdf_indirect_object_holder.h create mode 100644 core/fpdfapi/parser/cpdf_name.cpp create mode 100644 core/fpdfapi/parser/cpdf_name.h create mode 100644 core/fpdfapi/parser/cpdf_null.cpp create mode 100644 core/fpdfapi/parser/cpdf_null.h create mode 100644 core/fpdfapi/parser/cpdf_number.cpp create mode 100644 core/fpdfapi/parser/cpdf_number.h create mode 100644 core/fpdfapi/parser/cpdf_object.cpp create mode 100644 core/fpdfapi/parser/cpdf_object.h create mode 100644 core/fpdfapi/parser/cpdf_object_unittest.cpp create mode 100644 core/fpdfapi/parser/cpdf_parser.cpp create mode 100644 core/fpdfapi/parser/cpdf_parser.h create mode 100644 core/fpdfapi/parser/cpdf_parser_embeddertest.cpp create mode 100644 core/fpdfapi/parser/cpdf_parser_unittest.cpp create mode 100644 core/fpdfapi/parser/cpdf_reference.cpp create mode 100644 core/fpdfapi/parser/cpdf_reference.h create mode 100644 core/fpdfapi/parser/cpdf_security_handler.cpp create mode 100644 core/fpdfapi/parser/cpdf_security_handler.h create mode 100644 core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp create mode 100644 core/fpdfapi/parser/cpdf_simple_parser.cpp create mode 100644 core/fpdfapi/parser/cpdf_simple_parser.h create mode 100644 core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp create mode 100644 core/fpdfapi/parser/cpdf_stream.cpp create mode 100644 core/fpdfapi/parser/cpdf_stream.h create mode 100644 core/fpdfapi/parser/cpdf_stream_acc.cpp create mode 100644 core/fpdfapi/parser/cpdf_stream_acc.h create mode 100644 core/fpdfapi/parser/cpdf_string.cpp create mode 100644 core/fpdfapi/parser/cpdf_string.h create mode 100644 core/fpdfapi/parser/cpdf_syntax_parser.cpp create mode 100644 core/fpdfapi/parser/cpdf_syntax_parser.h create mode 100644 core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp create mode 100644 core/fpdfapi/parser/fpdf_parser_decode.cpp create mode 100644 core/fpdfapi/parser/fpdf_parser_decode.h create mode 100644 core/fpdfapi/parser/fpdf_parser_decode_embeddertest.cpp create mode 100644 core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp create mode 100644 core/fpdfapi/parser/fpdf_parser_utility.cpp create mode 100644 core/fpdfapi/parser/fpdf_parser_utility.h diff --git a/BUILD.gn b/BUILD.gn index 16ef8e5ecb..4263bf73ca 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -420,52 +420,6 @@ static_library("fpdfapi") { "core/fpdfapi/font/fpdf_font_cid.cpp", "core/fpdfapi/font/ttgsubtable.cpp", "core/fpdfapi/font/ttgsubtable.h", - "core/fpdfapi/fpdf_parser/cfdf_document.cpp", - "core/fpdfapi/fpdf_parser/cfdf_document.h", - "core/fpdfapi/fpdf_parser/cpdf_array.cpp", - "core/fpdfapi/fpdf_parser/cpdf_array.h", - "core/fpdfapi/fpdf_parser/cpdf_boolean.cpp", - "core/fpdfapi/fpdf_parser/cpdf_boolean.h", - "core/fpdfapi/fpdf_parser/cpdf_crypto_handler.cpp", - "core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h", - "core/fpdfapi/fpdf_parser/cpdf_data_avail.cpp", - "core/fpdfapi/fpdf_parser/cpdf_data_avail.h", - "core/fpdfapi/fpdf_parser/cpdf_dictionary.cpp", - "core/fpdfapi/fpdf_parser/cpdf_dictionary.h", - "core/fpdfapi/fpdf_parser/cpdf_document.cpp", - "core/fpdfapi/fpdf_parser/cpdf_document.h", - "core/fpdfapi/fpdf_parser/cpdf_hint_tables.cpp", - "core/fpdfapi/fpdf_parser/cpdf_hint_tables.h", - "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.cpp", - "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h", - "core/fpdfapi/fpdf_parser/cpdf_name.cpp", - "core/fpdfapi/fpdf_parser/cpdf_name.h", - "core/fpdfapi/fpdf_parser/cpdf_null.cpp", - "core/fpdfapi/fpdf_parser/cpdf_null.h", - "core/fpdfapi/fpdf_parser/cpdf_number.cpp", - "core/fpdfapi/fpdf_parser/cpdf_number.h", - "core/fpdfapi/fpdf_parser/cpdf_object.cpp", - "core/fpdfapi/fpdf_parser/cpdf_object.h", - "core/fpdfapi/fpdf_parser/cpdf_parser.cpp", - "core/fpdfapi/fpdf_parser/cpdf_parser.h", - "core/fpdfapi/fpdf_parser/cpdf_reference.cpp", - "core/fpdfapi/fpdf_parser/cpdf_reference.h", - "core/fpdfapi/fpdf_parser/cpdf_security_handler.cpp", - "core/fpdfapi/fpdf_parser/cpdf_security_handler.h", - "core/fpdfapi/fpdf_parser/cpdf_simple_parser.cpp", - "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h", - "core/fpdfapi/fpdf_parser/cpdf_stream.cpp", - "core/fpdfapi/fpdf_parser/cpdf_stream.h", - "core/fpdfapi/fpdf_parser/cpdf_stream_acc.cpp", - "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h", - "core/fpdfapi/fpdf_parser/cpdf_string.cpp", - "core/fpdfapi/fpdf_parser/cpdf_string.h", - "core/fpdfapi/fpdf_parser/cpdf_syntax_parser.cpp", - "core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h", - "core/fpdfapi/fpdf_parser/fpdf_parser_decode.cpp", - "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h", - "core/fpdfapi/fpdf_parser/fpdf_parser_utility.cpp", - "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h", "core/fpdfapi/fpdf_render/cpdf_pagerendercache.h", "core/fpdfapi/fpdf_render/cpdf_progressiverenderer.h", "core/fpdfapi/fpdf_render/cpdf_rendercontext.h", @@ -543,6 +497,52 @@ static_library("fpdfapi") { "core/fpdfapi/page/fpdf_page_parser.cpp", "core/fpdfapi/page/fpdf_page_parser_old.cpp", "core/fpdfapi/page/pageint.h", + "core/fpdfapi/parser/cfdf_document.cpp", + "core/fpdfapi/parser/cfdf_document.h", + "core/fpdfapi/parser/cpdf_array.cpp", + "core/fpdfapi/parser/cpdf_array.h", + "core/fpdfapi/parser/cpdf_boolean.cpp", + "core/fpdfapi/parser/cpdf_boolean.h", + "core/fpdfapi/parser/cpdf_crypto_handler.cpp", + "core/fpdfapi/parser/cpdf_crypto_handler.h", + "core/fpdfapi/parser/cpdf_data_avail.cpp", + "core/fpdfapi/parser/cpdf_data_avail.h", + "core/fpdfapi/parser/cpdf_dictionary.cpp", + "core/fpdfapi/parser/cpdf_dictionary.h", + "core/fpdfapi/parser/cpdf_document.cpp", + "core/fpdfapi/parser/cpdf_document.h", + "core/fpdfapi/parser/cpdf_hint_tables.cpp", + "core/fpdfapi/parser/cpdf_hint_tables.h", + "core/fpdfapi/parser/cpdf_indirect_object_holder.cpp", + "core/fpdfapi/parser/cpdf_indirect_object_holder.h", + "core/fpdfapi/parser/cpdf_name.cpp", + "core/fpdfapi/parser/cpdf_name.h", + "core/fpdfapi/parser/cpdf_null.cpp", + "core/fpdfapi/parser/cpdf_null.h", + "core/fpdfapi/parser/cpdf_number.cpp", + "core/fpdfapi/parser/cpdf_number.h", + "core/fpdfapi/parser/cpdf_object.cpp", + "core/fpdfapi/parser/cpdf_object.h", + "core/fpdfapi/parser/cpdf_parser.cpp", + "core/fpdfapi/parser/cpdf_parser.h", + "core/fpdfapi/parser/cpdf_reference.cpp", + "core/fpdfapi/parser/cpdf_reference.h", + "core/fpdfapi/parser/cpdf_security_handler.cpp", + "core/fpdfapi/parser/cpdf_security_handler.h", + "core/fpdfapi/parser/cpdf_simple_parser.cpp", + "core/fpdfapi/parser/cpdf_simple_parser.h", + "core/fpdfapi/parser/cpdf_stream.cpp", + "core/fpdfapi/parser/cpdf_stream.h", + "core/fpdfapi/parser/cpdf_stream_acc.cpp", + "core/fpdfapi/parser/cpdf_stream_acc.h", + "core/fpdfapi/parser/cpdf_string.cpp", + "core/fpdfapi/parser/cpdf_string.h", + "core/fpdfapi/parser/cpdf_syntax_parser.cpp", + "core/fpdfapi/parser/cpdf_syntax_parser.h", + "core/fpdfapi/parser/fpdf_parser_decode.cpp", + "core/fpdfapi/parser/fpdf_parser_decode.h", + "core/fpdfapi/parser/fpdf_parser_utility.cpp", + "core/fpdfapi/parser/fpdf_parser_utility.h", ] configs += [ ":pdfium_core_config" ] deps = [ @@ -1638,14 +1638,14 @@ test("pdfium_unittests") { sources = [ "core/fpdfapi/font/fpdf_font_cid_unittest.cpp", "core/fpdfapi/font/fpdf_font_unittest.cpp", - "core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp", - "core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp", - "core/fpdfapi/fpdf_parser/cpdf_parser_unittest.cpp", - "core/fpdfapi/fpdf_parser/cpdf_simple_parser_unittest.cpp", - "core/fpdfapi/fpdf_parser/cpdf_syntax_parser_unittest.cpp", - "core/fpdfapi/fpdf_parser/fpdf_parser_decode_unittest.cpp", "core/fpdfapi/page/fpdf_page_parser_old_unittest.cpp", "core/fpdfapi/page/fpdf_page_parser_unittest.cpp", + "core/fpdfapi/parser/cpdf_array_unittest.cpp", + "core/fpdfapi/parser/cpdf_object_unittest.cpp", + "core/fpdfapi/parser/cpdf_parser_unittest.cpp", + "core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp", + "core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp", + "core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp", "core/fpdfdoc/cpdf_filespec_unittest.cpp", "core/fpdfdoc/cpdf_formfield_unittest.cpp", "core/fpdftext/fpdf_text_int_unittest.cpp", @@ -1705,12 +1705,12 @@ test("pdfium_unittests") { test("pdfium_embeddertests") { sources = [ - "core/fpdfapi/fpdf_parser/cpdf_parser_embeddertest.cpp", - "core/fpdfapi/fpdf_parser/cpdf_security_handler_embeddertest.cpp", - "core/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp", "core/fpdfapi/fpdf_render/fpdf_render_loadimage_embeddertest.cpp", "core/fpdfapi/fpdf_render/fpdf_render_pattern_embeddertest.cpp", "core/fpdfapi/page/fpdf_page_func_embeddertest.cpp", + "core/fpdfapi/parser/cpdf_parser_embeddertest.cpp", + "core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp", + "core/fpdfapi/parser/fpdf_parser_decode_embeddertest.cpp", "core/fxcodec/codec/fx_codec_embeddertest.cpp", "core/fxge/ge/fx_ge_text_embeddertest.cpp", "fpdfsdk/fpdf_dataavail_embeddertest.cpp", diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp index 9cfccb3f7c..8697598756 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp @@ -7,17 +7,17 @@ #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h" #include "core/fpdfapi/edit/cpdf_creator.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_imageobject.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" CFX_ByteTextBuf& operator<<(CFX_ByteTextBuf& ar, CFX_Matrix& matrix) { ar << matrix.a << " " << matrix.b << " " << matrix.c << " " << matrix.d << " " diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h index 21b1b74fe9..1470ca8e83 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h @@ -7,7 +7,7 @@ #ifndef CORE_FPDFAPI_EDIT_CPDF_PAGECONTENTGENERATOR_H_ #define CORE_FPDFAPI_EDIT_CPDF_PAGECONTENTGENERATOR_H_ -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fxcrt/fx_basic.h" #include "core/fxcrt/fx_coordinates.h" #include "core/fxcrt/fx_system.h" diff --git a/core/fpdfapi/edit/fpdf_edit_create.cpp b/core/fpdfapi/edit/fpdf_edit_create.cpp index 32395a8728..ac8d709a2e 100644 --- a/core/fpdfapi/edit/fpdf_edit_create.cpp +++ b/core/fpdfapi/edit/fpdf_edit_create.cpp @@ -9,17 +9,17 @@ #include #include "core/fpdfapi/edit/cpdf_creator.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_security_handler.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_crypto_handler.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_security_handler.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fxcrt/fx_ext.h" #include "third_party/base/stl_util.h" diff --git a/core/fpdfapi/font/cpdf_cidfont.cpp b/core/fpdfapi/font/cpdf_cidfont.cpp index 9254294d7b..00c8a3662b 100644 --- a/core/fpdfapi/font/cpdf_cidfont.cpp +++ b/core/fpdfapi/font/cpdf_cidfont.cpp @@ -14,10 +14,10 @@ #include "core/fpdfapi/font/cpdf_fontencoding.h" #include "core/fpdfapi/font/font_int.h" #include "core/fpdfapi/font/ttgsubtable.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" #include "core/fpdfapi/page/cpdf_pagemodule.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "third_party/base/numerics/safe_math.h" namespace { diff --git a/core/fpdfapi/font/cpdf_font.cpp b/core/fpdfapi/font/cpdf_font.cpp index f4f95afd1f..caacc18a97 100644 --- a/core/fpdfapi/font/cpdf_font.cpp +++ b/core/fpdfapi/font/cpdf_font.cpp @@ -15,13 +15,13 @@ #include "core/fpdfapi/font/cpdf_type1font.h" #include "core/fpdfapi/font/cpdf_type3font.h" #include "core/fpdfapi/font/font_int.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" #include "core/fpdfapi/page/cpdf_pagemodule.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fxcrt/fx_memory.h" #include "core/fxge/fx_freetype.h" #include "third_party/base/ptr_util.h" diff --git a/core/fpdfapi/font/cpdf_fontencoding.cpp b/core/fpdfapi/font/cpdf_fontencoding.cpp index f6c5186a63..38cc66411f 100644 --- a/core/fpdfapi/font/cpdf_fontencoding.cpp +++ b/core/fpdfapi/font/cpdf_fontencoding.cpp @@ -6,11 +6,11 @@ #include "core/fpdfapi/font/cpdf_fontencoding.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fxge/fx_freetype.h" namespace { diff --git a/core/fpdfapi/font/cpdf_simplefont.cpp b/core/fpdfapi/font/cpdf_simplefont.cpp index b596cf0036..ed9860970e 100644 --- a/core/fpdfapi/font/cpdf_simplefont.cpp +++ b/core/fpdfapi/font/cpdf_simplefont.cpp @@ -7,8 +7,8 @@ #include "core/fpdfapi/font/cpdf_simplefont.h" #include "core/fpdfapi/font/font_int.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fxge/fx_freetype.h" #include "third_party/base/numerics/safe_math.h" diff --git a/core/fpdfapi/font/cpdf_truetypefont.cpp b/core/fpdfapi/font/cpdf_truetypefont.cpp index f3b5f2507e..d94b3b908e 100644 --- a/core/fpdfapi/font/cpdf_truetypefont.cpp +++ b/core/fpdfapi/font/cpdf_truetypefont.cpp @@ -7,7 +7,7 @@ #include "core/fpdfapi/font/cpdf_truetypefont.h" #include "core/fpdfapi/font/font_int.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fxge/fx_font.h" namespace { diff --git a/core/fpdfapi/font/cpdf_type1font.cpp b/core/fpdfapi/font/cpdf_type1font.cpp index 7848af5dee..b7ee717889 100644 --- a/core/fpdfapi/font/cpdf_type1font.cpp +++ b/core/fpdfapi/font/cpdf_type1font.cpp @@ -7,7 +7,7 @@ #include "core/fpdfapi/font/cpdf_type1font.h" #include "core/fpdfapi/font/font_int.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fxge/cfx_gemodule.h" #include "core/fxge/fx_freetype.h" diff --git a/core/fpdfapi/font/cpdf_type3font.cpp b/core/fpdfapi/font/cpdf_type3font.cpp index f23d4057cf..24ce4e8865 100644 --- a/core/fpdfapi/font/cpdf_type3font.cpp +++ b/core/fpdfapi/font/cpdf_type3font.cpp @@ -9,10 +9,10 @@ #include #include "core/fpdfapi/font/cpdf_type3char.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fxcrt/fx_system.h" #include "third_party/base/stl_util.h" diff --git a/core/fpdfapi/font/fpdf_font.cpp b/core/fpdfapi/font/fpdf_font.cpp index b679b759da..1273ff5f6d 100644 --- a/core/fpdfapi/font/fpdf_font.cpp +++ b/core/fpdfapi/font/fpdf_font.cpp @@ -7,16 +7,16 @@ #include "core/fpdfapi/font/font_int.h" #include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_pagemodule.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_simple_parser.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fxcrt/fx_ext.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxge/fx_freetype.h" diff --git a/core/fpdfapi/font/fpdf_font_cid.cpp b/core/fpdfapi/font/fpdf_font_cid.cpp index 95f4701aa2..02f8f7f058 100644 --- a/core/fpdfapi/font/fpdf_font_cid.cpp +++ b/core/fpdfapi/font/fpdf_font_cid.cpp @@ -9,10 +9,10 @@ #include "core/fpdfapi/cmaps/cmap_int.h" #include "core/fpdfapi/cpdf_modulemgr.h" #include "core/fpdfapi/font/ttgsubtable.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h" #include "core/fpdfapi/page/cpdf_pagemodule.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_simple_parser.h" #include "core/fxcrt/fx_ext.h" #include "core/fxge/fx_freetype.h" diff --git a/core/fpdfapi/fpdf_parser/cfdf_document.cpp b/core/fpdfapi/fpdf_parser/cfdf_document.cpp deleted file mode 100644 index 12d1e7f993..0000000000 --- a/core/fpdfapi/fpdf_parser/cfdf_document.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// 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 - -#include "core/fpdfapi/fpdf_parser/cfdf_document.h" - -#include "core/fpdfapi/edit/cpdf_creator.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h" -#include "third_party/base/ptr_util.h" - -CFDF_Document::CFDF_Document() - : CPDF_IndirectObjectHolder(), - m_pRootDict(nullptr), - m_pFile(nullptr), - m_bOwnFile(FALSE), - m_pByteStringPool(pdfium::MakeUnique()) {} - -CFDF_Document::~CFDF_Document() { - if (m_bOwnFile && m_pFile) - m_pFile->Release(); - m_pByteStringPool.DeleteObject(); // Make weak. -} - -CFDF_Document* CFDF_Document::CreateNewDoc() { - CFDF_Document* pDoc = new CFDF_Document; - pDoc->m_pRootDict = new CPDF_Dictionary(pDoc->GetByteStringPool()); - pDoc->AddIndirectObject(pDoc->m_pRootDict); - pDoc->m_pRootDict->SetFor("FDF", - new CPDF_Dictionary(pDoc->GetByteStringPool())); - return pDoc; -} - -CFDF_Document* CFDF_Document::ParseFile(IFX_FileRead* pFile, FX_BOOL bOwnFile) { - if (!pFile) - return nullptr; - - std::unique_ptr pDoc(new CFDF_Document); - pDoc->ParseStream(pFile, bOwnFile); - return pDoc->m_pRootDict ? pDoc.release() : nullptr; -} - -CFDF_Document* CFDF_Document::ParseMemory(const uint8_t* pData, uint32_t size) { - return CFDF_Document::ParseFile(FX_CreateMemoryStream((uint8_t*)pData, size), - TRUE); -} - -void CFDF_Document::ParseStream(IFX_FileRead* pFile, FX_BOOL bOwnFile) { - m_pFile = pFile; - m_bOwnFile = bOwnFile; - CPDF_SyntaxParser parser; - parser.InitParser(m_pFile, 0); - while (1) { - bool bNumber; - CFX_ByteString word = parser.GetNextWord(&bNumber); - if (bNumber) { - uint32_t objnum = FXSYS_atoui(word.c_str()); - word = parser.GetNextWord(&bNumber); - if (!bNumber) - break; - - word = parser.GetNextWord(nullptr); - if (word != "obj") - break; - - CPDF_Object* pObj = parser.GetObject(this, objnum, 0, true); - if (!pObj) - break; - - ReplaceIndirectObjectIfHigherGeneration(objnum, pObj); - word = parser.GetNextWord(nullptr); - if (word != "endobj") - break; - } else { - if (word != "trailer") - break; - - if (CPDF_Dictionary* pMainDict = - ToDictionary(parser.GetObject(this, 0, 0, true))) { - m_pRootDict = pMainDict->GetDictFor("Root"); - pMainDict->Release(); - } - break; - } - } -} - -FX_BOOL CFDF_Document::WriteBuf(CFX_ByteTextBuf& buf) const { - if (!m_pRootDict) - return FALSE; - - buf << "%FDF-1.2\r\n"; - for (const auto& pair : *this) - buf << pair.first << " 0 obj\r\n" - << pair.second.get() << "\r\nendobj\r\n\r\n"; - - buf << "trailer\r\n<GetObjNum() - << " 0 R>>\r\n%%EOF\r\n"; - return TRUE; -} diff --git a/core/fpdfapi/fpdf_parser/cfdf_document.h b/core/fpdfapi/fpdf_parser/cfdf_document.h deleted file mode 100644 index cd5b5b77bb..0000000000 --- a/core/fpdfapi/fpdf_parser/cfdf_document.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CFDF_DOCUMENT_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CFDF_DOCUMENT_H_ - -#include "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h" -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fxcrt/cfx_string_pool_template.h" -#include "core/fxcrt/cfx_weak_ptr.h" -#include "core/fxcrt/fx_basic.h" - -class CPDF_Dictionary; - -class CFDF_Document : public CPDF_IndirectObjectHolder { - public: - static CFDF_Document* CreateNewDoc(); - static CFDF_Document* ParseFile(IFX_FileRead* pFile, - FX_BOOL bOwnFile = FALSE); - static CFDF_Document* ParseMemory(const uint8_t* pData, uint32_t size); - ~CFDF_Document() override; - - FX_BOOL WriteBuf(CFX_ByteTextBuf& buf) const; - CPDF_Dictionary* GetRoot() const { return m_pRootDict; } - CFX_WeakPtr GetByteStringPool() const { - return m_pByteStringPool; - } - - protected: - CFDF_Document(); - void ParseStream(IFX_FileRead* pFile, FX_BOOL bOwnFile); - - CPDF_Dictionary* m_pRootDict; - IFX_FileRead* m_pFile; - FX_BOOL m_bOwnFile; - CFX_WeakPtr m_pByteStringPool; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CFDF_DOCUMENT_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_array.cpp b/core/fpdfapi/fpdf_parser/cpdf_array.cpp deleted file mode 100644 index 26e65bca34..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_array.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" - -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" -#include "third_party/base/logging.h" -#include "third_party/base/stl_util.h" - -CPDF_Array::CPDF_Array() {} - -CPDF_Array::~CPDF_Array() { - // Mark the object as deleted so that it will not be deleted again - // in case of cyclic references. - m_ObjNum = kInvalidObjNum; - for (auto& it : m_Objects) { - if (it) - it->Release(); - } -} - -CPDF_Object::Type CPDF_Array::GetType() const { - return ARRAY; -} - -bool CPDF_Array::IsArray() const { - return true; -} - -CPDF_Array* CPDF_Array::AsArray() { - return this; -} - -const CPDF_Array* CPDF_Array::AsArray() const { - return this; -} - -CPDF_Object* CPDF_Array::Clone() const { - return CloneObjectNonCyclic(false); -} - -CPDF_Object* CPDF_Array::CloneNonCyclic( - bool bDirect, - std::set* pVisited) const { - pVisited->insert(this); - CPDF_Array* pCopy = new CPDF_Array(); - for (size_t i = 0; i < GetCount(); i++) { - CPDF_Object* value = m_Objects[i]; - if (!pdfium::ContainsKey(*pVisited, value)) - pCopy->m_Objects.push_back(value->CloneNonCyclic(bDirect, pVisited)); - } - return pCopy; -} - -CFX_FloatRect CPDF_Array::GetRect() { - CFX_FloatRect rect; - if (!IsArray() || m_Objects.size() != 4) - return rect; - - rect.left = GetNumberAt(0); - rect.bottom = GetNumberAt(1); - rect.right = GetNumberAt(2); - rect.top = GetNumberAt(3); - return rect; -} - -CFX_Matrix CPDF_Array::GetMatrix() { - CFX_Matrix matrix; - if (!IsArray() || m_Objects.size() != 6) - return matrix; - - matrix.Set(GetNumberAt(0), GetNumberAt(1), GetNumberAt(2), GetNumberAt(3), - GetNumberAt(4), GetNumberAt(5)); - return matrix; -} - -CPDF_Object* CPDF_Array::GetObjectAt(size_t i) const { - if (i >= m_Objects.size()) - return nullptr; - return m_Objects[i]; -} - -CPDF_Object* CPDF_Array::GetDirectObjectAt(size_t i) const { - if (i >= m_Objects.size()) - return nullptr; - return m_Objects[i]->GetDirect(); -} - -CFX_ByteString CPDF_Array::GetStringAt(size_t i) const { - if (i >= m_Objects.size()) - return CFX_ByteString(); - return m_Objects[i]->GetString(); -} - -int CPDF_Array::GetIntegerAt(size_t i) const { - if (i >= m_Objects.size()) - return 0; - return m_Objects[i]->GetInteger(); -} - -FX_FLOAT CPDF_Array::GetNumberAt(size_t i) const { - if (i >= m_Objects.size()) - return 0; - return m_Objects[i]->GetNumber(); -} - -CPDF_Dictionary* CPDF_Array::GetDictAt(size_t i) const { - CPDF_Object* p = GetDirectObjectAt(i); - if (!p) - return nullptr; - if (CPDF_Dictionary* pDict = p->AsDictionary()) - return pDict; - if (CPDF_Stream* pStream = p->AsStream()) - return pStream->GetDict(); - return nullptr; -} - -CPDF_Stream* CPDF_Array::GetStreamAt(size_t i) const { - return ToStream(GetDirectObjectAt(i)); -} - -CPDF_Array* CPDF_Array::GetArrayAt(size_t i) const { - return ToArray(GetDirectObjectAt(i)); -} - -void CPDF_Array::RemoveAt(size_t i, size_t nCount) { - if (i >= m_Objects.size()) - return; - - if (nCount <= 0 || nCount > m_Objects.size() - i) - return; - - for (size_t j = 0; j < nCount; ++j) { - if (CPDF_Object* p = m_Objects[i + j]) - p->Release(); - } - m_Objects.erase(m_Objects.begin() + i, m_Objects.begin() + i + nCount); -} - -void CPDF_Array::SetAt(size_t i, CPDF_Object* pObj) { - ASSERT(IsArray()); - CHECK(!pObj || pObj->GetObjNum() == 0); - if (i >= m_Objects.size()) { - ASSERT(false); - return; - } - if (CPDF_Object* pOld = m_Objects[i]) - pOld->Release(); - - m_Objects[i] = pObj; -} - -void CPDF_Array::InsertAt(size_t index, CPDF_Object* pObj) { - ASSERT(IsArray()); - CHECK(!pObj || pObj->GetObjNum() == 0); - if (index >= m_Objects.size()) { - // Allocate space first. - m_Objects.resize(index + 1, nullptr); - m_Objects[index] = pObj; - } else { - // Directly insert. - m_Objects.insert(m_Objects.begin() + index, pObj); - } -} - -void CPDF_Array::Add(CPDF_Object* pObj) { - ASSERT(IsArray()); - CHECK(!pObj || pObj->GetObjNum() == 0); - m_Objects.push_back(pObj); -} - -void CPDF_Array::AddName(const CFX_ByteString& str) { - Add(new CPDF_Name(str)); -} - -void CPDF_Array::AddString(const CFX_ByteString& str) { - Add(new CPDF_String(str, FALSE)); -} - -void CPDF_Array::AddInteger(int i) { - Add(new CPDF_Number(i)); -} - -void CPDF_Array::AddNumber(FX_FLOAT f) { - Add(new CPDF_Number(f)); -} - -void CPDF_Array::AddReference(CPDF_IndirectObjectHolder* pDoc, - uint32_t objnum) { - Add(new CPDF_Reference(pDoc, objnum)); -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_array.h b/core/fpdfapi/fpdf_parser/cpdf_array.h deleted file mode 100644 index 2d4909d50e..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_array.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_ARRAY_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_ARRAY_H_ - -#include -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h" -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fxcrt/fx_basic.h" -#include "core/fxcrt/fx_coordinates.h" - -class CPDF_Array : public CPDF_Object { - public: - using iterator = std::vector::iterator; - using const_iterator = std::vector::const_iterator; - - CPDF_Array(); - - // CPDF_Object. - Type GetType() const override; - CPDF_Object* Clone() const override; - bool IsArray() const override; - CPDF_Array* AsArray() override; - const CPDF_Array* AsArray() const override; - - bool IsEmpty() const { return m_Objects.empty(); } - size_t GetCount() const { return m_Objects.size(); } - CPDF_Object* GetObjectAt(size_t index) const; - CPDF_Object* GetDirectObjectAt(size_t index) const; - CFX_ByteString GetStringAt(size_t index) const; - int GetIntegerAt(size_t index) const; - FX_FLOAT GetNumberAt(size_t index) const; - CPDF_Dictionary* GetDictAt(size_t index) const; - CPDF_Stream* GetStreamAt(size_t index) const; - CPDF_Array* GetArrayAt(size_t index) const; - FX_FLOAT GetFloatAt(size_t index) const { return GetNumberAt(index); } - CFX_Matrix GetMatrix(); - CFX_FloatRect GetRect(); - - void SetAt(size_t index, CPDF_Object* pObj); - void InsertAt(size_t index, CPDF_Object* pObj); - void RemoveAt(size_t index, size_t nCount = 1); - - void Add(CPDF_Object* pObj); - 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, uint32_t objnum); - - iterator begin() { return m_Objects.begin(); } - iterator end() { return m_Objects.end(); } - const_iterator begin() const { return m_Objects.begin(); } - const_iterator end() const { return m_Objects.end(); } - - protected: - ~CPDF_Array() override; - - CPDF_Object* CloneNonCyclic( - bool bDirect, - std::set* pVisited) const override; - - std::vector m_Objects; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_ARRAY_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp b/core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp deleted file mode 100644 index 110fd59e0a..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2016 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. - -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" - -#include - -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -using ScopedArray = std::unique_ptr>; - -} // namespace - -TEST(cpdf_array, RemoveAt) { - { - int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - arr->AddInteger(elems[i]); - arr->RemoveAt(3, 3); - int expected[] = {1, 2, 3, 7, 8, 9, 10}; - EXPECT_EQ(FX_ArraySize(expected), arr->GetCount()); - for (size_t i = 0; i < FX_ArraySize(expected); ++i) - EXPECT_EQ(expected[i], arr->GetIntegerAt(i)); - arr->RemoveAt(4, 2); - int expected2[] = {1, 2, 3, 7, 10}; - EXPECT_EQ(FX_ArraySize(expected2), arr->GetCount()); - for (size_t i = 0; i < FX_ArraySize(expected2); ++i) - EXPECT_EQ(expected2[i], arr->GetIntegerAt(i)); - } - { - // When the range is out of bound, RemoveAt has no effect. - int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - arr->AddInteger(elems[i]); - arr->RemoveAt(8, 5); - EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); - arr->RemoveAt(0, 12); - EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); - arr->RemoveAt(11, 1); - EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); - } -} - -TEST(cpdf_array, InsertAt) { - { - int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - arr->InsertAt(i, new CPDF_Number(elems[i])); - EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); - arr->InsertAt(3, new CPDF_Number(33)); - arr->InsertAt(6, new CPDF_Number(55)); - arr->InsertAt(12, new CPDF_Number(12)); - int expected[] = {1, 2, 3, 33, 4, 5, 55, 6, 7, 8, 9, 10, 12}; - EXPECT_EQ(FX_ArraySize(expected), arr->GetCount()); - for (size_t i = 0; i < FX_ArraySize(expected); ++i) - EXPECT_EQ(expected[i], arr->GetIntegerAt(i)); - } - { - // When the position to insert is beyond the upper bound, - // an element is inserted at that position while other unfilled - // positions have nullptr. - int elems[] = {1, 2}; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - arr->InsertAt(i, new CPDF_Number(elems[i])); - arr->InsertAt(10, new CPDF_Number(10)); - EXPECT_EQ(11u, arr->GetCount()); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); - for (size_t i = FX_ArraySize(elems); i < 10; ++i) - EXPECT_EQ(nullptr, arr->GetObjectAt(i)); - EXPECT_EQ(10, arr->GetIntegerAt(10)); - } -} - -TEST(cpdf_array, Clone) { - { - // Basic case. - int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - arr->InsertAt(i, new CPDF_Number(elems[i])); - ScopedArray arr2(arr->Clone()->AsArray()); - EXPECT_EQ(arr->GetCount(), arr2->GetCount()); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) { - // Clone() always create new objects. - EXPECT_NE(arr->GetObjectAt(i), arr2->GetObjectAt(i)); - EXPECT_EQ(arr->GetIntegerAt(i), arr2->GetIntegerAt(i)); - } - } - { - // Clone() with and without dereferencing reference objects. - static const size_t kNumOfRows = 3; - static const size_t kNumOfRowElems = 5; - int elems[kNumOfRows][kNumOfRowElems] = { - {1, 2, 3, 4, 5}, {10, 9, 8, 7, 6}, {11, 12, 13, 14, 15}}; - ScopedArray arr(new CPDF_Array); - // Indirect references to indirect objects. - std::unique_ptr obj_holder( - new CPDF_IndirectObjectHolder()); - for (size_t i = 0; i < kNumOfRows; ++i) { - CPDF_Array* arr_elem = new CPDF_Array; - for (size_t j = 0; j < kNumOfRowElems; ++j) { - CPDF_Number* obj = new CPDF_Number(elems[i][j]); - // Starts object number from 1. - int obj_num = i * kNumOfRowElems + j + 1; - obj_holder->ReplaceIndirectObjectIfHigherGeneration(obj_num, obj); - arr_elem->InsertAt(j, new CPDF_Reference(obj_holder.get(), obj_num)); - } - arr->InsertAt(i, arr_elem); - } - ASSERT_EQ(kNumOfRows, arr->GetCount()); - // Not dereferencing reference objects means just creating new references - // instead of new copies of direct objects. - ScopedArray arr1(arr->Clone()->AsArray()); - EXPECT_EQ(arr->GetCount(), arr1->GetCount()); - // Dereferencing reference objects creates new copies of direct objects. - ScopedArray arr2(arr->CloneDirectObject()->AsArray()); - EXPECT_EQ(arr->GetCount(), arr2->GetCount()); - for (size_t i = 0; i < kNumOfRows; ++i) { - CPDF_Array* arr_elem = arr->GetObjectAt(i)->AsArray(); - CPDF_Array* arr1_elem = arr1->GetObjectAt(i)->AsArray(); - CPDF_Array* arr2_elem = arr2->GetObjectAt(i)->AsArray(); - EXPECT_NE(arr_elem, arr1_elem); - EXPECT_NE(arr_elem, arr2_elem); - for (size_t j = 0; j < kNumOfRowElems; ++j) { - auto elem_obj = arr_elem->GetObjectAt(j); - auto elem_obj1 = arr1_elem->GetObjectAt(j); - auto elem_obj2 = arr2_elem->GetObjectAt(j); - // Results from not deferencing reference objects. - EXPECT_NE(elem_obj, elem_obj1); - EXPECT_TRUE(elem_obj1->IsReference()); - EXPECT_EQ(elem_obj->GetDirect(), elem_obj1->GetDirect()); - EXPECT_EQ(elem_obj->GetInteger(), elem_obj1->GetInteger()); - // Results from deferencing reference objects. - EXPECT_NE(elem_obj, elem_obj2); - EXPECT_TRUE(elem_obj2->IsNumber()); - EXPECT_NE(elem_obj->GetDirect(), elem_obj2); - EXPECT_EQ(elem_obj->GetObjNum(), elem_obj2->GetObjNum()); - EXPECT_EQ(elem_obj->GetInteger(), elem_obj2->GetInteger()); - } - } - arr.reset(); - ASSERT_EQ(kNumOfRows, arr1->GetCount()); - for (size_t i = 0; i < kNumOfRows; ++i) { - for (size_t j = 0; j < kNumOfRowElems; ++j) { - // Results from not deferencing reference objects. - auto elem_obj1 = arr1->GetObjectAt(i)->AsArray()->GetObjectAt(j); - EXPECT_TRUE(elem_obj1->IsReference()); - EXPECT_EQ(elems[i][j], elem_obj1->GetInteger()); - // Results from deferencing reference objects. - EXPECT_EQ(elems[i][j], - arr2->GetObjectAt(i)->AsArray()->GetIntegerAt(j)); - } - } - } -} - -TEST(cpdf_array, Iterator) { - int elems[] = {-23, -11, 3, 455, 2345877, - 0, 7895330, -12564334, 10000, -100000}; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - arr->InsertAt(i, new CPDF_Number(elems[i])); - size_t index = 0; - for (const auto& it : *arr) - EXPECT_EQ(elems[index++], it->AsNumber()->GetInteger()); -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_boolean.cpp b/core/fpdfapi/fpdf_parser/cpdf_boolean.cpp deleted file mode 100644 index be0b7e99a3..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_boolean.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" - -CPDF_Boolean::CPDF_Boolean() : m_bValue(false) {} - -CPDF_Boolean::CPDF_Boolean(bool value) : m_bValue(value) {} - -CPDF_Boolean::~CPDF_Boolean() {} - -CPDF_Object::Type CPDF_Boolean::GetType() const { - return BOOLEAN; -} - -CPDF_Object* CPDF_Boolean::Clone() const { - return new CPDF_Boolean(m_bValue); -} - -CFX_ByteString CPDF_Boolean::GetString() const { - return m_bValue ? "true" : "false"; -} - -int CPDF_Boolean::GetInteger() const { - return m_bValue; -} - -void CPDF_Boolean::SetString(const CFX_ByteString& str) { - m_bValue = (str == "true"); -} - -bool CPDF_Boolean::IsBoolean() const { - return true; -} - -CPDF_Boolean* CPDF_Boolean::AsBoolean() { - return this; -} - -const CPDF_Boolean* CPDF_Boolean::AsBoolean() const { - return this; -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_boolean.h b/core/fpdfapi/fpdf_parser/cpdf_boolean.h deleted file mode 100644 index db4a11c312..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_boolean.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_BOOLEAN_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_BOOLEAN_H_ - -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" - -class CPDF_Boolean : public CPDF_Object { - public: - CPDF_Boolean(); - explicit CPDF_Boolean(bool value); - - // CPDF_Object. - Type GetType() const override; - CPDF_Object* Clone() const override; - CFX_ByteString GetString() const override; - int GetInteger() const override; - void SetString(const CFX_ByteString& str) override; - bool IsBoolean() const override; - CPDF_Boolean* AsBoolean() override; - const CPDF_Boolean* AsBoolean() const override; - - protected: - ~CPDF_Boolean() override; - - bool m_bValue; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_BOOLEAN_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_crypto_handler.cpp b/core/fpdfapi/fpdf_parser/cpdf_crypto_handler.cpp deleted file mode 100644 index 36f74cbd32..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_crypto_handler.cpp +++ /dev/null @@ -1,342 +0,0 @@ -// 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h" - -#include - -#include "core/fdrm/crypto/fx_crypt.h" -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_security_handler.h" -#include "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h" - -void CPDF_CryptoHandler::CryptBlock(FX_BOOL bEncrypt, - uint32_t objnum, - uint32_t gennum, - const uint8_t* src_buf, - uint32_t src_size, - uint8_t* dest_buf, - uint32_t& dest_size) { - if (m_Cipher == FXCIPHER_NONE) { - FXSYS_memcpy(dest_buf, src_buf, src_size); - return; - } - uint8_t realkey[16]; - int realkeylen = 16; - if (m_Cipher != FXCIPHER_AES || m_KeyLen != 32) { - uint8_t key1[32]; - PopulateKey(objnum, gennum, key1); - - if (m_Cipher == FXCIPHER_AES) { - FXSYS_memcpy(key1 + m_KeyLen + 5, "sAlT", 4); - } - CRYPT_MD5Generate( - key1, m_Cipher == FXCIPHER_AES ? m_KeyLen + 9 : m_KeyLen + 5, realkey); - realkeylen = m_KeyLen + 5; - if (realkeylen > 16) { - realkeylen = 16; - } - } - if (m_Cipher == FXCIPHER_AES) { - CRYPT_AESSetKey(m_pAESContext, 16, m_KeyLen == 32 ? m_EncryptKey : realkey, - m_KeyLen, bEncrypt); - if (bEncrypt) { - uint8_t iv[16]; - for (int i = 0; i < 16; i++) { - iv[i] = (uint8_t)rand(); - } - CRYPT_AESSetIV(m_pAESContext, iv); - FXSYS_memcpy(dest_buf, iv, 16); - int nblocks = src_size / 16; - CRYPT_AESEncrypt(m_pAESContext, dest_buf + 16, src_buf, nblocks * 16); - uint8_t padding[16]; - FXSYS_memcpy(padding, src_buf + nblocks * 16, src_size % 16); - FXSYS_memset(padding + src_size % 16, 16 - src_size % 16, - 16 - src_size % 16); - CRYPT_AESEncrypt(m_pAESContext, dest_buf + nblocks * 16 + 16, padding, - 16); - dest_size = 32 + nblocks * 16; - } else { - CRYPT_AESSetIV(m_pAESContext, src_buf); - CRYPT_AESDecrypt(m_pAESContext, dest_buf, src_buf + 16, src_size - 16); - dest_size = src_size - 16; - dest_size -= dest_buf[dest_size - 1]; - } - } else { - ASSERT(dest_size == src_size); - if (dest_buf != src_buf) { - FXSYS_memcpy(dest_buf, src_buf, src_size); - } - CRYPT_ArcFourCryptBlock(dest_buf, dest_size, realkey, realkeylen); - } -} - -struct AESCryptContext { - uint8_t m_Context[2048]; - FX_BOOL m_bIV; - uint8_t m_Block[16]; - uint32_t m_BlockOffset; -}; - -void* CPDF_CryptoHandler::CryptStart(uint32_t objnum, - uint32_t gennum, - FX_BOOL bEncrypt) { - if (m_Cipher == FXCIPHER_NONE) { - return this; - } - if (m_Cipher == FXCIPHER_AES && m_KeyLen == 32) { - AESCryptContext* pContext = FX_Alloc(AESCryptContext, 1); - pContext->m_bIV = TRUE; - pContext->m_BlockOffset = 0; - CRYPT_AESSetKey(pContext->m_Context, 16, m_EncryptKey, 32, bEncrypt); - if (bEncrypt) { - for (int i = 0; i < 16; i++) { - pContext->m_Block[i] = (uint8_t)rand(); - } - CRYPT_AESSetIV(pContext->m_Context, pContext->m_Block); - } - return pContext; - } - uint8_t key1[48]; - PopulateKey(objnum, gennum, key1); - - if (m_Cipher == FXCIPHER_AES) { - FXSYS_memcpy(key1 + m_KeyLen + 5, "sAlT", 4); - } - uint8_t realkey[16]; - CRYPT_MD5Generate( - key1, m_Cipher == FXCIPHER_AES ? m_KeyLen + 9 : m_KeyLen + 5, realkey); - int realkeylen = m_KeyLen + 5; - if (realkeylen > 16) { - realkeylen = 16; - } - if (m_Cipher == FXCIPHER_AES) { - AESCryptContext* pContext = FX_Alloc(AESCryptContext, 1); - pContext->m_bIV = TRUE; - pContext->m_BlockOffset = 0; - CRYPT_AESSetKey(pContext->m_Context, 16, realkey, 16, bEncrypt); - if (bEncrypt) { - for (int i = 0; i < 16; i++) { - pContext->m_Block[i] = (uint8_t)rand(); - } - CRYPT_AESSetIV(pContext->m_Context, pContext->m_Block); - } - return pContext; - } - void* pContext = FX_Alloc(uint8_t, 1040); - CRYPT_ArcFourSetup(pContext, realkey, realkeylen); - return pContext; -} - -FX_BOOL CPDF_CryptoHandler::CryptStream(void* context, - const uint8_t* src_buf, - uint32_t src_size, - CFX_BinaryBuf& dest_buf, - FX_BOOL bEncrypt) { - if (!context) { - return FALSE; - } - if (m_Cipher == FXCIPHER_NONE) { - dest_buf.AppendBlock(src_buf, src_size); - return TRUE; - } - if (m_Cipher == FXCIPHER_RC4) { - int old_size = dest_buf.GetSize(); - dest_buf.AppendBlock(src_buf, src_size); - CRYPT_ArcFourCrypt(context, dest_buf.GetBuffer() + old_size, src_size); - return TRUE; - } - AESCryptContext* pContext = (AESCryptContext*)context; - if (pContext->m_bIV && bEncrypt) { - dest_buf.AppendBlock(pContext->m_Block, 16); - pContext->m_bIV = FALSE; - } - uint32_t src_off = 0; - uint32_t src_left = src_size; - while (1) { - uint32_t copy_size = 16 - pContext->m_BlockOffset; - if (copy_size > src_left) { - copy_size = src_left; - } - FXSYS_memcpy(pContext->m_Block + pContext->m_BlockOffset, src_buf + src_off, - copy_size); - src_off += copy_size; - src_left -= copy_size; - pContext->m_BlockOffset += copy_size; - if (pContext->m_BlockOffset == 16) { - if (!bEncrypt && pContext->m_bIV) { - CRYPT_AESSetIV(pContext->m_Context, pContext->m_Block); - pContext->m_bIV = FALSE; - pContext->m_BlockOffset = 0; - } else if (src_off < src_size) { - uint8_t block_buf[16]; - if (bEncrypt) { - CRYPT_AESEncrypt(pContext->m_Context, block_buf, pContext->m_Block, - 16); - } else { - CRYPT_AESDecrypt(pContext->m_Context, block_buf, pContext->m_Block, - 16); - } - dest_buf.AppendBlock(block_buf, 16); - pContext->m_BlockOffset = 0; - } - } - if (!src_left) { - break; - } - } - return TRUE; -} -FX_BOOL CPDF_CryptoHandler::CryptFinish(void* context, - CFX_BinaryBuf& dest_buf, - FX_BOOL bEncrypt) { - if (!context) { - return FALSE; - } - if (m_Cipher == FXCIPHER_NONE) { - return TRUE; - } - if (m_Cipher == FXCIPHER_RC4) { - FX_Free(context); - return TRUE; - } - AESCryptContext* pContext = (AESCryptContext*)context; - if (bEncrypt) { - uint8_t block_buf[16]; - if (pContext->m_BlockOffset == 16) { - CRYPT_AESEncrypt(pContext->m_Context, block_buf, pContext->m_Block, 16); - dest_buf.AppendBlock(block_buf, 16); - pContext->m_BlockOffset = 0; - } - FXSYS_memset(pContext->m_Block + pContext->m_BlockOffset, - (uint8_t)(16 - pContext->m_BlockOffset), - 16 - pContext->m_BlockOffset); - CRYPT_AESEncrypt(pContext->m_Context, block_buf, pContext->m_Block, 16); - dest_buf.AppendBlock(block_buf, 16); - } else if (pContext->m_BlockOffset == 16) { - uint8_t block_buf[16]; - CRYPT_AESDecrypt(pContext->m_Context, block_buf, pContext->m_Block, 16); - if (block_buf[15] <= 16) { - dest_buf.AppendBlock(block_buf, 16 - block_buf[15]); - } - } - FX_Free(pContext); - return TRUE; -} - -void CPDF_CryptoHandler::Decrypt(uint32_t objnum, - uint32_t gennum, - CFX_ByteString& str) { - CFX_BinaryBuf dest_buf; - void* context = DecryptStart(objnum, gennum); - DecryptStream(context, str.raw_str(), str.GetLength(), dest_buf); - DecryptFinish(context, dest_buf); - str = CFX_ByteString(dest_buf.GetBuffer(), dest_buf.GetSize()); -} - -void* CPDF_CryptoHandler::DecryptStart(uint32_t objnum, uint32_t gennum) { - return CryptStart(objnum, gennum, FALSE); -} -uint32_t CPDF_CryptoHandler::DecryptGetSize(uint32_t src_size) { - return m_Cipher == FXCIPHER_AES ? src_size - 16 : src_size; -} - -FX_BOOL CPDF_CryptoHandler::Init(CPDF_Dictionary* pEncryptDict, - CPDF_SecurityHandler* pSecurityHandler) { - const uint8_t* key; - if (!pSecurityHandler->GetCryptInfo(m_Cipher, key, m_KeyLen)) { - return FALSE; - } - if (m_KeyLen > 32 || m_KeyLen < 0) { - return FALSE; - } - if (m_Cipher != FXCIPHER_NONE) { - FXSYS_memcpy(m_EncryptKey, key, m_KeyLen); - } - if (m_Cipher == FXCIPHER_AES) { - m_pAESContext = FX_Alloc(uint8_t, 2048); - } - return TRUE; -} - -FX_BOOL CPDF_CryptoHandler::Init(int cipher, const uint8_t* key, int keylen) { - if (cipher == FXCIPHER_AES) { - switch (keylen) { - case 16: - case 24: - case 32: - break; - default: - return FALSE; - } - } else if (cipher == FXCIPHER_AES2) { - if (keylen != 32) { - return FALSE; - } - } else if (cipher == FXCIPHER_RC4) { - if (keylen < 5 || keylen > 16) { - return FALSE; - } - } else { - if (keylen > 32) { - keylen = 32; - } - } - m_Cipher = cipher; - m_KeyLen = keylen; - FXSYS_memcpy(m_EncryptKey, key, keylen); - if (m_Cipher == FXCIPHER_AES) { - m_pAESContext = FX_Alloc(uint8_t, 2048); - } - return TRUE; -} -FX_BOOL CPDF_CryptoHandler::DecryptStream(void* context, - const uint8_t* src_buf, - uint32_t src_size, - CFX_BinaryBuf& dest_buf) { - return CryptStream(context, src_buf, src_size, dest_buf, FALSE); -} -FX_BOOL CPDF_CryptoHandler::DecryptFinish(void* context, - CFX_BinaryBuf& dest_buf) { - return CryptFinish(context, dest_buf, FALSE); -} -uint32_t CPDF_CryptoHandler::EncryptGetSize(uint32_t objnum, - uint32_t version, - const uint8_t* src_buf, - uint32_t src_size) { - if (m_Cipher == FXCIPHER_AES) { - return src_size + 32; - } - return src_size; -} -FX_BOOL CPDF_CryptoHandler::EncryptContent(uint32_t objnum, - uint32_t gennum, - const uint8_t* src_buf, - uint32_t src_size, - uint8_t* dest_buf, - uint32_t& dest_size) { - CryptBlock(TRUE, objnum, gennum, src_buf, src_size, dest_buf, dest_size); - return TRUE; -} -CPDF_CryptoHandler::CPDF_CryptoHandler() { - m_pAESContext = nullptr; - m_Cipher = FXCIPHER_NONE; - m_KeyLen = 0; -} -CPDF_CryptoHandler::~CPDF_CryptoHandler() { - FX_Free(m_pAESContext); -} - -void CPDF_CryptoHandler::PopulateKey(uint32_t objnum, - uint32_t gennum, - uint8_t* key) { - FXSYS_memcpy(key, m_EncryptKey, m_KeyLen); - key[m_KeyLen + 0] = (uint8_t)objnum; - key[m_KeyLen + 1] = (uint8_t)(objnum >> 8); - key[m_KeyLen + 2] = (uint8_t)(objnum >> 16); - key[m_KeyLen + 3] = (uint8_t)gennum; - key[m_KeyLen + 4] = (uint8_t)(gennum >> 8); -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h b/core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h deleted file mode 100644 index 25ff49b482..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_CRYPTO_HANDLER_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_CRYPTO_HANDLER_H_ - -#include "core/fxcrt/fx_basic.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" - -class CPDF_Dictionary; -class CPDF_SecurityHandler; - -class CPDF_CryptoHandler { - public: - CPDF_CryptoHandler(); - ~CPDF_CryptoHandler(); - - FX_BOOL Init(CPDF_Dictionary* pEncryptDict, - CPDF_SecurityHandler* pSecurityHandler); - uint32_t DecryptGetSize(uint32_t src_size); - void* DecryptStart(uint32_t objnum, uint32_t gennum); - void Decrypt(uint32_t objnum, uint32_t gennum, CFX_ByteString& str); - FX_BOOL DecryptStream(void* context, - const uint8_t* src_buf, - uint32_t src_size, - CFX_BinaryBuf& dest_buf); - FX_BOOL DecryptFinish(void* context, CFX_BinaryBuf& dest_buf); - uint32_t EncryptGetSize(uint32_t objnum, - uint32_t version, - const uint8_t* src_buf, - uint32_t src_size); - FX_BOOL EncryptContent(uint32_t objnum, - uint32_t version, - const uint8_t* src_buf, - uint32_t src_size, - uint8_t* dest_buf, - uint32_t& dest_size); - - FX_BOOL Init(int cipher, const uint8_t* key, int keylen); - - protected: - void CryptBlock(FX_BOOL bEncrypt, - uint32_t objnum, - uint32_t gennum, - const uint8_t* src_buf, - uint32_t src_size, - uint8_t* dest_buf, - uint32_t& dest_size); - void* CryptStart(uint32_t objnum, uint32_t gennum, FX_BOOL bEncrypt); - FX_BOOL CryptStream(void* context, - const uint8_t* src_buf, - uint32_t src_size, - CFX_BinaryBuf& dest_buf, - FX_BOOL bEncrypt); - FX_BOOL CryptFinish(void* context, CFX_BinaryBuf& dest_buf, FX_BOOL bEncrypt); - - uint8_t m_EncryptKey[32]; - int m_KeyLen; - int m_Cipher; - uint8_t* m_pAESContext; - - private: - void PopulateKey(uint32_t objnum, uint32_t gennum, uint8_t* key); -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_CRYPTO_HANDLER_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_data_avail.cpp b/core/fpdfapi/fpdf_parser/cpdf_data_avail.cpp deleted file mode 100644 index 9afe4e5f13..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_data_avail.cpp +++ /dev/null @@ -1,1844 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_data_avail.h" - -#include -#include -#include - -#include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_hint_tables.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h" -#include "core/fxcrt/fx_ext.h" -#include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/stl_util.h" - -CPDF_DataAvail::FileAvail::~FileAvail() {} - -CPDF_DataAvail::DownloadHints::~DownloadHints() {} - -// static -int CPDF_DataAvail::s_CurrentDataAvailRecursionDepth = 0; - -CPDF_DataAvail::CPDF_DataAvail(FileAvail* pFileAvail, - IFX_FileRead* pFileRead, - FX_BOOL bSupportHintTable) - : m_pFileAvail(pFileAvail), m_pFileRead(pFileRead) { - m_Pos = 0; - m_dwFileLen = 0; - if (m_pFileRead) { - m_dwFileLen = (uint32_t)m_pFileRead->GetSize(); - } - m_dwCurrentOffset = 0; - m_dwXRefOffset = 0; - m_bufferOffset = 0; - m_dwFirstPageNo = 0; - m_bufferSize = 0; - m_PagesObjNum = 0; - m_dwCurrentXRefSteam = 0; - m_dwAcroFormObjNum = 0; - m_dwInfoObjNum = 0; - m_pDocument = 0; - m_dwEncryptObjNum = 0; - m_dwPrevXRefOffset = 0; - m_dwLastXRefOffset = 0; - m_bDocAvail = FALSE; - m_bMainXRefLoadTried = FALSE; - m_bDocAvail = FALSE; - m_bLinearized = FALSE; - m_bPagesLoad = FALSE; - m_bPagesTreeLoad = FALSE; - m_bMainXRefLoadedOK = FALSE; - m_bAnnotsLoad = FALSE; - m_bHaveAcroForm = FALSE; - m_bAcroFormLoad = FALSE; - m_bPageLoadedOK = FALSE; - m_bNeedDownLoadResource = FALSE; - m_bLinearizedFormParamLoad = FALSE; - m_pLinearized = nullptr; - m_pRoot = nullptr; - m_pTrailer = nullptr; - m_pCurrentParser = nullptr; - m_pAcroForm = nullptr; - m_pPageDict = nullptr; - m_pPageResource = nullptr; - m_docStatus = PDF_DATAAVAIL_HEADER; - m_parser.m_bOwnFileRead = false; - m_bTotalLoadPageTree = FALSE; - m_bCurPageDictLoadOK = FALSE; - m_bLinearedDataOK = FALSE; - m_bSupportHintTable = bSupportHintTable; -} -CPDF_DataAvail::~CPDF_DataAvail() { - m_pHintTables.reset(); - if (m_pLinearized) - m_pLinearized->Release(); - - if (m_pRoot) - m_pRoot->Release(); - - if (m_pTrailer) - m_pTrailer->Release(); - - int iSize = m_arrayAcroforms.GetSize(); - for (int i = 0; i < iSize; ++i) - m_arrayAcroforms.GetAt(i)->Release(); -} - -void CPDF_DataAvail::SetDocument(CPDF_Document* pDoc) { - m_pDocument = pDoc; -} - -uint32_t CPDF_DataAvail::GetObjectSize(uint32_t objnum, FX_FILESIZE& offset) { - CPDF_Parser* pParser = m_pDocument->GetParser(); - if (!pParser || !pParser->IsValidObjectNumber(objnum)) - return 0; - - if (pParser->GetObjectType(objnum) == 2) - objnum = pParser->GetObjectPositionOrZero(objnum); - - if (pParser->GetObjectType(objnum) != 1 && - pParser->GetObjectType(objnum) != 255) { - return 0; - } - - offset = pParser->GetObjectPositionOrZero(objnum); - if (offset == 0) - return 0; - - auto it = pParser->m_SortedOffset.find(offset); - if (it == pParser->m_SortedOffset.end() || - ++it == pParser->m_SortedOffset.end()) { - return 0; - } - return *it - offset; -} - -FX_BOOL CPDF_DataAvail::IsObjectsAvail( - CFX_ArrayTemplate& obj_array, - FX_BOOL bParsePage, - DownloadHints* pHints, - CFX_ArrayTemplate& ret_array) { - if (!obj_array.GetSize()) - return TRUE; - - uint32_t count = 0; - CFX_ArrayTemplate new_obj_array; - for (int i = 0; i < obj_array.GetSize(); i++) { - CPDF_Object* pObj = obj_array[i]; - if (!pObj) - continue; - - int32_t type = pObj->GetType(); - switch (type) { - case CPDF_Object::ARRAY: { - CPDF_Array* pArray = pObj->AsArray(); - for (size_t k = 0; k < pArray->GetCount(); ++k) - new_obj_array.Add(pArray->GetObjectAt(k)); - } break; - case CPDF_Object::STREAM: - pObj = pObj->GetDict(); - case CPDF_Object::DICTIONARY: { - CPDF_Dictionary* pDict = pObj->GetDict(); - if (pDict && pDict->GetStringFor("Type") == "Page" && !bParsePage) - continue; - - for (const auto& it : *pDict) { - const CFX_ByteString& key = it.first; - CPDF_Object* value = it.second; - if (key != "Parent") - new_obj_array.Add(value); - } - } break; - case CPDF_Object::REFERENCE: { - CPDF_Reference* pRef = pObj->AsReference(); - uint32_t dwNum = pRef->GetRefObjNum(); - - FX_FILESIZE offset; - uint32_t size = GetObjectSize(dwNum, offset); - if (size == 0 || offset < 0 || offset >= m_dwFileLen) - break; - - if (!IsDataAvail(offset, size, pHints)) { - ret_array.Add(pObj); - count++; - } else if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) { - m_ObjectSet.insert(dwNum); - CPDF_Object* pReferred = - m_pDocument->GetOrParseIndirectObject(pRef->GetRefObjNum()); - if (pReferred) - new_obj_array.Add(pReferred); - } - } break; - } - } - - if (count > 0) { - for (int i = 0; i < new_obj_array.GetSize(); ++i) { - CPDF_Object* pObj = new_obj_array[i]; - if (CPDF_Reference* pRef = pObj->AsReference()) { - uint32_t dwNum = pRef->GetRefObjNum(); - if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) - ret_array.Add(pObj); - } else { - ret_array.Add(pObj); - } - } - return FALSE; - } - - obj_array.RemoveAll(); - obj_array.Append(new_obj_array); - return IsObjectsAvail(obj_array, FALSE, pHints, ret_array); -} - -CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsDocAvail( - DownloadHints* pHints) { - if (!m_dwFileLen && m_pFileRead) { - m_dwFileLen = (uint32_t)m_pFileRead->GetSize(); - if (!m_dwFileLen) - return DataError; - } - - while (!m_bDocAvail) { - if (!CheckDocStatus(pHints)) - return DataNotAvailable; - } - - return DataAvailable; -} - -FX_BOOL CPDF_DataAvail::CheckAcroFormSubObject(DownloadHints* pHints) { - if (!m_objs_array.GetSize()) { - m_objs_array.RemoveAll(); - m_ObjectSet.clear(); - CFX_ArrayTemplate obj_array; - obj_array.Append(m_arrayAcroforms); - FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); - if (bRet) - m_objs_array.RemoveAll(); - return bRet; - } - - CFX_ArrayTemplate new_objs_array; - FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); - if (bRet) { - int32_t iSize = m_arrayAcroforms.GetSize(); - for (int32_t i = 0; i < iSize; ++i) { - m_arrayAcroforms.GetAt(i)->Release(); - } - m_arrayAcroforms.RemoveAll(); - } else { - m_objs_array.RemoveAll(); - m_objs_array.Append(new_objs_array); - } - return bRet; -} - -FX_BOOL CPDF_DataAvail::CheckAcroForm(DownloadHints* pHints) { - FX_BOOL bExist = FALSE; - m_pAcroForm = GetObject(m_dwAcroFormObjNum, pHints, &bExist); - if (!bExist) { - m_docStatus = PDF_DATAAVAIL_PAGETREE; - return TRUE; - } - - if (!m_pAcroForm) { - if (m_docStatus == PDF_DATAAVAIL_ERROR) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - return TRUE; - } - return FALSE; - } - - m_arrayAcroforms.Add(m_pAcroForm); - m_docStatus = PDF_DATAAVAIL_PAGETREE; - return TRUE; -} - -FX_BOOL CPDF_DataAvail::CheckDocStatus(DownloadHints* pHints) { - switch (m_docStatus) { - case PDF_DATAAVAIL_HEADER: - return CheckHeader(pHints); - case PDF_DATAAVAIL_FIRSTPAGE: - case PDF_DATAAVAIL_FIRSTPAGE_PREPARE: - return CheckFirstPage(pHints); - case PDF_DATAAVAIL_HINTTABLE: - return CheckHintTables(pHints); - case PDF_DATAAVAIL_END: - return CheckEnd(pHints); - case PDF_DATAAVAIL_CROSSREF: - return CheckCrossRef(pHints); - case PDF_DATAAVAIL_CROSSREF_ITEM: - return CheckCrossRefItem(pHints); - case PDF_DATAAVAIL_CROSSREF_STREAM: - return CheckAllCrossRefStream(pHints); - case PDF_DATAAVAIL_TRAILER: - return CheckTrailer(pHints); - case PDF_DATAAVAIL_TRAILER_APPEND: - return CheckTrailerAppend(pHints); - case PDF_DATAAVAIL_LOADALLCROSSREF: - return LoadAllXref(pHints); - case PDF_DATAAVAIL_LOADALLFILE: - return LoadAllFile(pHints); - case PDF_DATAAVAIL_ROOT: - return CheckRoot(pHints); - case PDF_DATAAVAIL_INFO: - return CheckInfo(pHints); - case PDF_DATAAVAIL_ACROFORM: - return CheckAcroForm(pHints); - case PDF_DATAAVAIL_PAGETREE: - if (m_bTotalLoadPageTree) - return CheckPages(pHints); - return LoadDocPages(pHints); - case PDF_DATAAVAIL_PAGE: - if (m_bTotalLoadPageTree) - return CheckPage(pHints); - m_docStatus = PDF_DATAAVAIL_PAGE_LATERLOAD; - return TRUE; - case PDF_DATAAVAIL_ERROR: - return LoadAllFile(pHints); - case PDF_DATAAVAIL_PAGE_LATERLOAD: - m_docStatus = PDF_DATAAVAIL_PAGE; - default: - m_bDocAvail = TRUE; - return TRUE; - } -} - -FX_BOOL CPDF_DataAvail::CheckPageStatus(DownloadHints* pHints) { - switch (m_docStatus) { - case PDF_DATAAVAIL_PAGETREE: - return CheckPages(pHints); - case PDF_DATAAVAIL_PAGE: - return CheckPage(pHints); - case PDF_DATAAVAIL_ERROR: - return LoadAllFile(pHints); - default: - m_bPagesTreeLoad = TRUE; - m_bPagesLoad = TRUE; - return TRUE; - } -} - -FX_BOOL CPDF_DataAvail::LoadAllFile(DownloadHints* pHints) { - if (m_pFileAvail->IsDataAvail(0, (uint32_t)m_dwFileLen)) { - m_docStatus = PDF_DATAAVAIL_DONE; - return TRUE; - } - - pHints->AddSegment(0, (uint32_t)m_dwFileLen); - return FALSE; -} - -FX_BOOL CPDF_DataAvail::LoadAllXref(DownloadHints* pHints) { - m_parser.m_pSyntax->InitParser(m_pFileRead, (uint32_t)m_dwHeaderOffset); - m_parser.m_bOwnFileRead = false; - if (!m_parser.LoadAllCrossRefV4(m_dwLastXRefOffset) && - !m_parser.LoadAllCrossRefV5(m_dwLastXRefOffset)) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - return FALSE; - } - - m_dwRootObjNum = m_parser.GetRootObjNum(); - m_dwInfoObjNum = m_parser.GetInfoObjNum(); - m_pCurrentParser = &m_parser; - m_docStatus = PDF_DATAAVAIL_ROOT; - return TRUE; -} - -CPDF_Object* CPDF_DataAvail::GetObject(uint32_t objnum, - DownloadHints* pHints, - FX_BOOL* pExistInFile) { - CPDF_Object* pRet = nullptr; - uint32_t size = 0; - FX_FILESIZE offset = 0; - CPDF_Parser* pParser = nullptr; - - if (pExistInFile) - *pExistInFile = TRUE; - - if (m_pDocument) { - size = GetObjectSize(objnum, offset); - pParser = m_pDocument->GetParser(); - } else { - size = (uint32_t)m_parser.GetObjectSize(objnum); - offset = m_parser.GetObjectOffset(objnum); - pParser = &m_parser; - } - - if (!IsDataAvail(offset, size, pHints)) - return nullptr; - - if (pParser) - pRet = pParser->ParseIndirectObject(nullptr, objnum); - - if (!pRet && pExistInFile) - *pExistInFile = FALSE; - - return pRet; -} - -FX_BOOL CPDF_DataAvail::CheckInfo(DownloadHints* pHints) { - FX_BOOL bExist = FALSE; - CPDF_Object* pInfo = GetObject(m_dwInfoObjNum, pHints, &bExist); - if (!bExist) { - m_docStatus = - (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); - return TRUE; - } - - if (!pInfo) { - if (m_docStatus == PDF_DATAAVAIL_ERROR) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - return TRUE; - } - - if (m_Pos == m_dwFileLen) - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - if (pInfo) - pInfo->Release(); - - m_docStatus = - (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); - - return TRUE; -} - -FX_BOOL CPDF_DataAvail::CheckRoot(DownloadHints* pHints) { - FX_BOOL bExist = FALSE; - m_pRoot = GetObject(m_dwRootObjNum, pHints, &bExist); - if (!bExist) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - return TRUE; - } - - if (!m_pRoot) { - if (m_docStatus == PDF_DATAAVAIL_ERROR) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - return TRUE; - } - return FALSE; - } - - CPDF_Dictionary* pDict = m_pRoot->GetDict(); - if (!pDict) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - CPDF_Reference* pRef = ToReference(pDict->GetObjectFor("Pages")); - if (!pRef) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - m_PagesObjNum = pRef->GetRefObjNum(); - CPDF_Reference* pAcroFormRef = - ToReference(m_pRoot->GetDict()->GetObjectFor("AcroForm")); - if (pAcroFormRef) { - m_bHaveAcroForm = TRUE; - m_dwAcroFormObjNum = pAcroFormRef->GetRefObjNum(); - } - - if (m_dwInfoObjNum) { - m_docStatus = PDF_DATAAVAIL_INFO; - } else { - m_docStatus = - m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE; - } - return TRUE; -} - -FX_BOOL CPDF_DataAvail::PreparePageItem() { - CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); - CPDF_Reference* pRef = - ToReference(pRoot ? pRoot->GetObjectFor("Pages") : nullptr); - if (!pRef) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - m_PagesObjNum = pRef->GetRefObjNum(); - m_pCurrentParser = m_pDocument->GetParser(); - m_docStatus = PDF_DATAAVAIL_PAGETREE; - return TRUE; -} - -bool CPDF_DataAvail::IsFirstCheck(uint32_t dwPage) { - return m_pageMapCheckState.insert(dwPage).second; -} - -void CPDF_DataAvail::ResetFirstCheck(uint32_t dwPage) { - m_pageMapCheckState.erase(dwPage); -} - -FX_BOOL CPDF_DataAvail::CheckPage(DownloadHints* pHints) { - uint32_t iPageObjs = m_PageObjList.GetSize(); - CFX_ArrayTemplate UnavailObjList; - for (uint32_t i = 0; i < iPageObjs; ++i) { - uint32_t dwPageObjNum = m_PageObjList.GetAt(i); - FX_BOOL bExist = FALSE; - CPDF_Object* pObj = GetObject(dwPageObjNum, pHints, &bExist); - if (!pObj) { - if (bExist) - UnavailObjList.Add(dwPageObjNum); - continue; - } - - CPDF_Array* pArray = ToArray(pObj); - if (pArray) { - for (CPDF_Object* pArrayObj : *pArray) { - if (CPDF_Reference* pRef = ToReference(pArrayObj)) - UnavailObjList.Add(pRef->GetRefObjNum()); - } - } - - if (!pObj->IsDictionary()) { - pObj->Release(); - continue; - } - - CFX_ByteString type = pObj->GetDict()->GetStringFor("Type"); - if (type == "Pages") { - m_PagesArray.Add(pObj); - continue; - } - pObj->Release(); - } - - m_PageObjList.RemoveAll(); - if (UnavailObjList.GetSize()) { - m_PageObjList.Append(UnavailObjList); - return FALSE; - } - - uint32_t iPages = m_PagesArray.GetSize(); - for (uint32_t i = 0; i < iPages; i++) { - CPDF_Object* pPages = m_PagesArray.GetAt(i); - if (!pPages) - continue; - - if (!GetPageKids(m_pCurrentParser, pPages)) { - pPages->Release(); - while (++i < iPages) { - pPages = m_PagesArray.GetAt(i); - pPages->Release(); - } - m_PagesArray.RemoveAll(); - - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - pPages->Release(); - } - - m_PagesArray.RemoveAll(); - if (!m_PageObjList.GetSize()) - m_docStatus = PDF_DATAAVAIL_DONE; - return TRUE; -} - -FX_BOOL CPDF_DataAvail::GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages) { - if (!pParser) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - CPDF_Dictionary* pDict = pPages->GetDict(); - CPDF_Object* pKids = pDict ? pDict->GetObjectFor("Kids") : nullptr; - if (!pKids) - return TRUE; - - switch (pKids->GetType()) { - case CPDF_Object::REFERENCE: - m_PageObjList.Add(pKids->AsReference()->GetRefObjNum()); - break; - case CPDF_Object::ARRAY: { - CPDF_Array* pKidsArray = pKids->AsArray(); - for (size_t i = 0; i < pKidsArray->GetCount(); ++i) { - if (CPDF_Reference* pRef = ToReference(pKidsArray->GetObjectAt(i))) - m_PageObjList.Add(pRef->GetRefObjNum()); - } - } break; - default: - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - return TRUE; -} - -FX_BOOL CPDF_DataAvail::CheckPages(DownloadHints* pHints) { - FX_BOOL bExist = FALSE; - CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); - if (!bExist) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - return TRUE; - } - - if (!pPages) { - if (m_docStatus == PDF_DATAAVAIL_ERROR) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - return TRUE; - } - return FALSE; - } - - if (!GetPageKids(m_pCurrentParser, pPages)) { - pPages->Release(); - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - pPages->Release(); - m_docStatus = PDF_DATAAVAIL_PAGE; - return TRUE; -} - -FX_BOOL CPDF_DataAvail::CheckHeader(DownloadHints* pHints) { - ASSERT(m_dwFileLen >= 0); - const uint32_t kReqSize = std::min(static_cast(m_dwFileLen), 1024U); - - if (m_pFileAvail->IsDataAvail(0, kReqSize)) { - uint8_t buffer[1024]; - m_pFileRead->ReadBlock(buffer, 0, kReqSize); - - if (IsLinearizedFile(buffer, kReqSize)) { - m_docStatus = PDF_DATAAVAIL_FIRSTPAGE; - } else { - if (m_docStatus == PDF_DATAAVAIL_ERROR) - return FALSE; - m_docStatus = PDF_DATAAVAIL_END; - } - return TRUE; - } - - pHints->AddSegment(0, kReqSize); - return FALSE; -} - -FX_BOOL CPDF_DataAvail::CheckFirstPage(DownloadHints* pHints) { - CPDF_Dictionary* pDict = m_pLinearized->GetDict(); - CPDF_Object* pEndOffSet = pDict ? pDict->GetObjectFor("E") : nullptr; - if (!pEndOffSet) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - CPDF_Object* pXRefOffset = pDict ? pDict->GetObjectFor("T") : nullptr; - if (!pXRefOffset) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - CPDF_Object* pFileLen = pDict ? pDict->GetObjectFor("L") : nullptr; - if (!pFileLen) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - FX_BOOL bNeedDownLoad = FALSE; - if (pEndOffSet->IsNumber()) { - uint32_t dwEnd = pEndOffSet->GetInteger(); - dwEnd += 512; - if ((FX_FILESIZE)dwEnd > m_dwFileLen) - dwEnd = (uint32_t)m_dwFileLen; - - int32_t iStartPos = (int32_t)(m_dwFileLen > 1024 ? 1024 : m_dwFileLen); - int32_t iSize = dwEnd > 1024 ? dwEnd - 1024 : 0; - if (!m_pFileAvail->IsDataAvail(iStartPos, iSize)) { - pHints->AddSegment(iStartPos, iSize); - bNeedDownLoad = TRUE; - } - } - - m_dwLastXRefOffset = 0; - FX_FILESIZE dwFileLen = 0; - if (pXRefOffset->IsNumber()) - m_dwLastXRefOffset = pXRefOffset->GetInteger(); - - if (pFileLen->IsNumber()) - dwFileLen = pFileLen->GetInteger(); - - if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, - (uint32_t)(dwFileLen - m_dwLastXRefOffset))) { - if (m_docStatus == PDF_DATAAVAIL_FIRSTPAGE) { - uint32_t dwSize = (uint32_t)(dwFileLen - m_dwLastXRefOffset); - FX_FILESIZE offset = m_dwLastXRefOffset; - if (dwSize < 512 && dwFileLen > 512) { - dwSize = 512; - offset = dwFileLen - 512; - } - pHints->AddSegment(offset, dwSize); - } - } else { - m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; - } - - if (bNeedDownLoad || m_docStatus != PDF_DATAAVAIL_FIRSTPAGE_PREPARE) { - m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; - return FALSE; - } - - m_docStatus = - m_bSupportHintTable ? PDF_DATAAVAIL_HINTTABLE : PDF_DATAAVAIL_DONE; - return TRUE; -} - -FX_BOOL CPDF_DataAvail::IsDataAvail(FX_FILESIZE offset, - uint32_t size, - DownloadHints* pHints) { - if (offset < 0 || offset > m_dwFileLen) - return TRUE; - - FX_SAFE_FILESIZE safeSize = offset; - safeSize += size; - safeSize += 512; - if (!safeSize.IsValid() || safeSize.ValueOrDie() > m_dwFileLen) - size = m_dwFileLen - offset; - else - size += 512; - - if (!m_pFileAvail->IsDataAvail(offset, size)) { - pHints->AddSegment(offset, size); - return FALSE; - } - return TRUE; -} - -FX_BOOL CPDF_DataAvail::CheckHintTables(DownloadHints* pHints) { - CPDF_Dictionary* pDict = m_pLinearized->GetDict(); - if (!pDict) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - // The actual value is not required here, but validate its existence and type. - CPDF_Number* pFirstPage = ToNumber(pDict->GetDirectObjectFor("O")); - if (!pFirstPage || !pFirstPage->IsInteger()) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - CPDF_Number* pPageCount = ToNumber(pDict->GetDirectObjectFor("N")); - if (!pPageCount || !pPageCount->IsInteger()) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - int nPageCount = pPageCount->GetInteger(); - if (nPageCount <= 1) { - m_docStatus = PDF_DATAAVAIL_DONE; - return TRUE; - } - - CPDF_Array* pHintStreamRange = pDict->GetArrayFor("H"); - size_t nHintStreamSize = pHintStreamRange ? pHintStreamRange->GetCount() : 0; - if (nHintStreamSize != 2 && nHintStreamSize != 4) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - for (const CPDF_Object* pArrayObject : *pHintStreamRange) { - const CPDF_Number* pNumber = ToNumber(pArrayObject->GetDirect()); - if (!pNumber || !pNumber->IsInteger()) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - } - - FX_FILESIZE szHintStart = pHintStreamRange->GetIntegerAt(0); - FX_FILESIZE szHintLength = pHintStreamRange->GetIntegerAt(1); - if (szHintStart < 0 || szHintLength <= 0) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - if (!IsDataAvail(szHintStart, szHintLength, pHints)) - return FALSE; - - m_syntaxParser.InitParser(m_pFileRead, m_dwHeaderOffset); - - std::unique_ptr pHintTables( - new CPDF_HintTables(this, pDict)); - std::unique_ptr> pHintStream( - ParseIndirectObjectAt(szHintStart, 0)); - CPDF_Stream* pStream = ToStream(pHintStream.get()); - if (pStream && pHintTables->LoadHintStream(pStream)) - m_pHintTables = std::move(pHintTables); - - m_docStatus = PDF_DATAAVAIL_DONE; - return TRUE; -} - -CPDF_Object* CPDF_DataAvail::ParseIndirectObjectAt( - FX_FILESIZE pos, - uint32_t objnum, - CPDF_IndirectObjectHolder* pObjList) { - FX_FILESIZE SavedPos = m_syntaxParser.SavePos(); - m_syntaxParser.RestorePos(pos); - - bool bIsNumber; - CFX_ByteString word = m_syntaxParser.GetNextWord(&bIsNumber); - if (!bIsNumber) - return nullptr; - - uint32_t parser_objnum = FXSYS_atoui(word.c_str()); - if (objnum && parser_objnum != objnum) - return nullptr; - - word = m_syntaxParser.GetNextWord(&bIsNumber); - if (!bIsNumber) - return nullptr; - - uint32_t gennum = FXSYS_atoui(word.c_str()); - if (m_syntaxParser.GetKeyword() != "obj") { - m_syntaxParser.RestorePos(SavedPos); - return nullptr; - } - - CPDF_Object* pObj = - m_syntaxParser.GetObject(pObjList, parser_objnum, gennum, true); - m_syntaxParser.RestorePos(SavedPos); - return pObj; -} - -CPDF_DataAvail::DocLinearizationStatus CPDF_DataAvail::IsLinearizedPDF() { - const uint32_t kReqSize = 1024; - if (!m_pFileAvail->IsDataAvail(0, kReqSize)) - return LinearizationUnknown; - - if (!m_pFileRead) - return NotLinearized; - - FX_FILESIZE dwSize = m_pFileRead->GetSize(); - if (dwSize < (FX_FILESIZE)kReqSize) - return LinearizationUnknown; - - uint8_t buffer[1024]; - m_pFileRead->ReadBlock(buffer, 0, kReqSize); - if (IsLinearizedFile(buffer, kReqSize)) - return Linearized; - - return NotLinearized; -} - -FX_BOOL CPDF_DataAvail::IsLinearized() { - return m_bLinearized; -} - -FX_BOOL CPDF_DataAvail::IsLinearizedFile(uint8_t* pData, uint32_t dwLen) { - if (m_pLinearized) - return m_bLinearized; - - ScopedFileStream file(FX_CreateMemoryStream(pData, (size_t)dwLen, FALSE)); - - int32_t offset = GetHeaderOffset(file.get()); - if (offset == -1) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - m_dwHeaderOffset = offset; - m_syntaxParser.InitParser(file.get(), offset); - m_syntaxParser.RestorePos(m_syntaxParser.m_HeaderOffset + 9); - - bool bNumber; - CFX_ByteString wordObjNum = m_syntaxParser.GetNextWord(&bNumber); - if (!bNumber) - return FALSE; - - uint32_t objnum = FXSYS_atoui(wordObjNum.c_str()); - m_pLinearized = - ParseIndirectObjectAt(m_syntaxParser.m_HeaderOffset + 9, objnum); - if (!m_pLinearized) - return FALSE; - - CPDF_Dictionary* pDict = m_pLinearized->GetDict(); - if (!pDict || !pDict->GetObjectFor("Linearized")) - return FALSE; - - CPDF_Object* pLen = pDict->GetObjectFor("L"); - if (!pLen) - return FALSE; - - if ((FX_FILESIZE)pLen->GetInteger() != m_pFileRead->GetSize()) - return FALSE; - - m_bLinearized = TRUE; - - if (CPDF_Number* pNo = ToNumber(pDict->GetObjectFor("P"))) - m_dwFirstPageNo = pNo->GetInteger(); - - return TRUE; -} - -FX_BOOL CPDF_DataAvail::CheckEnd(DownloadHints* pHints) { - uint32_t req_pos = (uint32_t)(m_dwFileLen > 1024 ? m_dwFileLen - 1024 : 0); - uint32_t dwSize = (uint32_t)(m_dwFileLen - req_pos); - - if (m_pFileAvail->IsDataAvail(req_pos, dwSize)) { - uint8_t buffer[1024]; - m_pFileRead->ReadBlock(buffer, req_pos, dwSize); - - ScopedFileStream file(FX_CreateMemoryStream(buffer, (size_t)dwSize, FALSE)); - m_syntaxParser.InitParser(file.get(), 0); - m_syntaxParser.RestorePos(dwSize - 1); - - if (m_syntaxParser.SearchWord("startxref", TRUE, FALSE, dwSize)) { - m_syntaxParser.GetNextWord(nullptr); - - bool bNumber; - CFX_ByteString xrefpos_str = m_syntaxParser.GetNextWord(&bNumber); - if (!bNumber) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - m_dwXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str.c_str()); - if (!m_dwXRefOffset || m_dwXRefOffset > m_dwFileLen) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - return TRUE; - } - - m_dwLastXRefOffset = m_dwXRefOffset; - SetStartOffset(m_dwXRefOffset); - m_docStatus = PDF_DATAAVAIL_CROSSREF; - return TRUE; - } - - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - return TRUE; - } - - pHints->AddSegment(req_pos, dwSize); - return FALSE; -} - -int32_t CPDF_DataAvail::CheckCrossRefStream(DownloadHints* pHints, - FX_FILESIZE& xref_offset) { - xref_offset = 0; - uint32_t req_size = - (uint32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); - - if (m_pFileAvail->IsDataAvail(m_Pos, req_size)) { - int32_t iSize = (int32_t)(m_Pos + req_size - m_dwCurrentXRefSteam); - CFX_BinaryBuf buf(iSize); - uint8_t* pBuf = buf.GetBuffer(); - - m_pFileRead->ReadBlock(pBuf, m_dwCurrentXRefSteam, iSize); - - ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); - m_parser.m_pSyntax->InitParser(file.get(), 0); - - bool bNumber; - CFX_ByteString objnum = m_parser.m_pSyntax->GetNextWord(&bNumber); - if (!bNumber) - return -1; - - uint32_t objNum = FXSYS_atoui(objnum.c_str()); - CPDF_Object* pObj = m_parser.ParseIndirectObjectAt(nullptr, 0, objNum); - if (!pObj) { - m_Pos += m_parser.m_pSyntax->SavePos(); - return 0; - } - - CPDF_Dictionary* pDict = pObj->GetDict(); - CPDF_Name* pName = ToName(pDict ? pDict->GetObjectFor("Type") : nullptr); - if (pName) { - if (pName->GetString() == "XRef") { - m_Pos += m_parser.m_pSyntax->SavePos(); - xref_offset = pObj->GetDict()->GetIntegerFor("Prev"); - pObj->Release(); - return 1; - } - } - pObj->Release(); - return -1; - } - pHints->AddSegment(m_Pos, req_size); - return 0; -} - -void CPDF_DataAvail::SetStartOffset(FX_FILESIZE dwOffset) { - m_Pos = dwOffset; -} - -FX_BOOL CPDF_DataAvail::GetNextToken(CFX_ByteString& token) { - uint8_t ch; - if (!GetNextChar(ch)) - return FALSE; - - while (1) { - while (PDFCharIsWhitespace(ch)) { - if (!GetNextChar(ch)) - return FALSE; - } - - if (ch != '%') - break; - - while (1) { - if (!GetNextChar(ch)) - return FALSE; - if (PDFCharIsLineEnding(ch)) - break; - } - } - - uint8_t buffer[256]; - uint32_t index = 0; - if (PDFCharIsDelimiter(ch)) { - buffer[index++] = ch; - if (ch == '/') { - while (1) { - if (!GetNextChar(ch)) - return FALSE; - - if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { - m_Pos--; - CFX_ByteString ret(buffer, index); - token = ret; - return TRUE; - } - - if (index < sizeof(buffer)) - buffer[index++] = ch; - } - } else if (ch == '<') { - if (!GetNextChar(ch)) - return FALSE; - - if (ch == '<') - buffer[index++] = ch; - else - m_Pos--; - } else if (ch == '>') { - if (!GetNextChar(ch)) - return FALSE; - - if (ch == '>') - buffer[index++] = ch; - else - m_Pos--; - } - - CFX_ByteString ret(buffer, index); - token = ret; - return TRUE; - } - - while (1) { - if (index < sizeof(buffer)) - buffer[index++] = ch; - - if (!GetNextChar(ch)) - return FALSE; - - if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { - m_Pos--; - break; - } - } - - token = CFX_ByteString(buffer, index); - return TRUE; -} - -FX_BOOL CPDF_DataAvail::GetNextChar(uint8_t& ch) { - FX_FILESIZE pos = m_Pos; - if (pos >= m_dwFileLen) - return FALSE; - - if (m_bufferOffset >= pos || - (FX_FILESIZE)(m_bufferOffset + m_bufferSize) <= pos) { - FX_FILESIZE read_pos = pos; - uint32_t read_size = 512; - if ((FX_FILESIZE)read_size > m_dwFileLen) - read_size = (uint32_t)m_dwFileLen; - - if ((FX_FILESIZE)(read_pos + read_size) > m_dwFileLen) - read_pos = m_dwFileLen - read_size; - - if (!m_pFileRead->ReadBlock(m_bufferData, read_pos, read_size)) - return FALSE; - - m_bufferOffset = read_pos; - m_bufferSize = read_size; - } - ch = m_bufferData[pos - m_bufferOffset]; - m_Pos++; - return TRUE; -} - -FX_BOOL CPDF_DataAvail::CheckCrossRefItem(DownloadHints* pHints) { - int32_t iSize = 0; - CFX_ByteString token; - while (1) { - if (!GetNextToken(token)) { - iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); - pHints->AddSegment(m_Pos, iSize); - return FALSE; - } - - if (token == "trailer") { - m_dwTrailerOffset = m_Pos; - m_docStatus = PDF_DATAAVAIL_TRAILER; - return TRUE; - } - } -} - -FX_BOOL CPDF_DataAvail::CheckAllCrossRefStream(DownloadHints* pHints) { - FX_FILESIZE xref_offset = 0; - - int32_t nRet = CheckCrossRefStream(pHints, xref_offset); - if (nRet == 1) { - if (!xref_offset) { - m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; - } else { - m_dwCurrentXRefSteam = xref_offset; - m_Pos = xref_offset; - } - return TRUE; - } - - if (nRet == -1) - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; -} - -FX_BOOL CPDF_DataAvail::CheckCrossRef(DownloadHints* pHints) { - int32_t iSize = 0; - CFX_ByteString token; - if (!GetNextToken(token)) { - iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); - pHints->AddSegment(m_Pos, iSize); - return FALSE; - } - - if (token == "xref") { - while (1) { - if (!GetNextToken(token)) { - iSize = - (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); - pHints->AddSegment(m_Pos, iSize); - m_docStatus = PDF_DATAAVAIL_CROSSREF_ITEM; - return FALSE; - } - - if (token == "trailer") { - m_dwTrailerOffset = m_Pos; - m_docStatus = PDF_DATAAVAIL_TRAILER; - return TRUE; - } - } - } else { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - return TRUE; - } - return FALSE; -} - -FX_BOOL CPDF_DataAvail::CheckTrailerAppend(DownloadHints* pHints) { - if (m_Pos < m_dwFileLen) { - FX_FILESIZE dwAppendPos = m_Pos + m_syntaxParser.SavePos(); - int32_t iSize = (int32_t)( - dwAppendPos + 512 > m_dwFileLen ? m_dwFileLen - dwAppendPos : 512); - - if (!m_pFileAvail->IsDataAvail(dwAppendPos, iSize)) { - pHints->AddSegment(dwAppendPos, iSize); - return FALSE; - } - } - - if (m_dwPrevXRefOffset) { - SetStartOffset(m_dwPrevXRefOffset); - m_docStatus = PDF_DATAAVAIL_CROSSREF; - } else { - m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; - } - return TRUE; -} - -FX_BOOL CPDF_DataAvail::CheckTrailer(DownloadHints* pHints) { - int32_t iTrailerSize = - (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); - if (m_pFileAvail->IsDataAvail(m_Pos, iTrailerSize)) { - int32_t iSize = (int32_t)(m_Pos + iTrailerSize - m_dwTrailerOffset); - CFX_BinaryBuf buf(iSize); - uint8_t* pBuf = buf.GetBuffer(); - if (!pBuf) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - if (!m_pFileRead->ReadBlock(pBuf, m_dwTrailerOffset, iSize)) - return FALSE; - - ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); - m_syntaxParser.InitParser(file.get(), 0); - - std::unique_ptr> pTrailer( - m_syntaxParser.GetObject(nullptr, 0, 0, true)); - if (!pTrailer) { - m_Pos += m_syntaxParser.SavePos(); - pHints->AddSegment(m_Pos, iTrailerSize); - return FALSE; - } - - if (!pTrailer->IsDictionary()) - return FALSE; - - CPDF_Dictionary* pTrailerDict = pTrailer->GetDict(); - CPDF_Object* pEncrypt = pTrailerDict->GetObjectFor("Encrypt"); - if (ToReference(pEncrypt)) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - return TRUE; - } - - uint32_t xrefpos = GetDirectInteger(pTrailerDict, "Prev"); - if (xrefpos) { - m_dwPrevXRefOffset = GetDirectInteger(pTrailerDict, "XRefStm"); - if (m_dwPrevXRefOffset) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - } else { - m_dwPrevXRefOffset = xrefpos; - if (m_dwPrevXRefOffset >= m_dwFileLen) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; - } else { - SetStartOffset(m_dwPrevXRefOffset); - m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; - } - } - return TRUE; - } - m_dwPrevXRefOffset = 0; - m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; - return TRUE; - } - pHints->AddSegment(m_Pos, iTrailerSize); - return FALSE; -} - -FX_BOOL CPDF_DataAvail::CheckPage(uint32_t dwPage, DownloadHints* pHints) { - while (TRUE) { - switch (m_docStatus) { - case PDF_DATAAVAIL_PAGETREE: - if (!LoadDocPages(pHints)) - return FALSE; - break; - case PDF_DATAAVAIL_PAGE: - if (!LoadDocPage(dwPage, pHints)) - return FALSE; - break; - case PDF_DATAAVAIL_ERROR: - return LoadAllFile(pHints); - default: - m_bPagesTreeLoad = TRUE; - m_bPagesLoad = TRUE; - m_bCurPageDictLoadOK = TRUE; - m_docStatus = PDF_DATAAVAIL_PAGE; - return TRUE; - } - } -} - -FX_BOOL CPDF_DataAvail::CheckArrayPageNode(uint32_t dwPageNo, - PageNode* pPageNode, - DownloadHints* pHints) { - FX_BOOL bExist = FALSE; - CPDF_Object* pPages = GetObject(dwPageNo, pHints, &bExist); - if (!bExist) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - if (!pPages) { - if (m_docStatus == PDF_DATAAVAIL_ERROR) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - return FALSE; - } - - CPDF_Array* pArray = pPages->AsArray(); - if (!pArray) { - pPages->Release(); - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - pPageNode->m_type = PDF_PAGENODE_PAGES; - for (size_t i = 0; i < pArray->GetCount(); ++i) { - CPDF_Reference* pKid = ToReference(pArray->GetObjectAt(i)); - if (!pKid) - continue; - - PageNode* pNode = new PageNode(); - pPageNode->m_childNode.Add(pNode); - pNode->m_dwPageNo = pKid->GetRefObjNum(); - } - pPages->Release(); - return TRUE; -} - -FX_BOOL CPDF_DataAvail::CheckUnkownPageNode(uint32_t dwPageNo, - PageNode* pPageNode, - DownloadHints* pHints) { - FX_BOOL bExist = FALSE; - CPDF_Object* pPage = GetObject(dwPageNo, pHints, &bExist); - if (!bExist) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - if (!pPage) { - if (m_docStatus == PDF_DATAAVAIL_ERROR) - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - if (pPage->IsArray()) { - pPageNode->m_dwPageNo = dwPageNo; - pPageNode->m_type = PDF_PAGENODE_ARRAY; - pPage->Release(); - return TRUE; - } - - if (!pPage->IsDictionary()) { - pPage->Release(); - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - pPageNode->m_dwPageNo = dwPageNo; - CPDF_Dictionary* pDict = pPage->GetDict(); - CFX_ByteString type = pDict->GetStringFor("Type"); - if (type == "Pages") { - pPageNode->m_type = PDF_PAGENODE_PAGES; - CPDF_Object* pKids = pDict->GetObjectFor("Kids"); - if (!pKids) { - m_docStatus = PDF_DATAAVAIL_PAGE; - return TRUE; - } - - switch (pKids->GetType()) { - case CPDF_Object::REFERENCE: { - CPDF_Reference* pKid = pKids->AsReference(); - PageNode* pNode = new PageNode(); - pPageNode->m_childNode.Add(pNode); - pNode->m_dwPageNo = pKid->GetRefObjNum(); - } break; - case CPDF_Object::ARRAY: { - CPDF_Array* pKidsArray = pKids->AsArray(); - for (size_t i = 0; i < pKidsArray->GetCount(); ++i) { - CPDF_Reference* pKid = ToReference(pKidsArray->GetObjectAt(i)); - if (!pKid) - continue; - - PageNode* pNode = new PageNode(); - pPageNode->m_childNode.Add(pNode); - pNode->m_dwPageNo = pKid->GetRefObjNum(); - } - } break; - default: - break; - } - } else if (type == "Page") { - pPageNode->m_type = PDF_PAGENODE_PAGE; - } else { - pPage->Release(); - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - pPage->Release(); - return TRUE; -} - -FX_BOOL CPDF_DataAvail::CheckPageNode(CPDF_DataAvail::PageNode& pageNodes, - int32_t iPage, - int32_t& iCount, - DownloadHints* pHints, - int level) { - if (level >= kMaxPageRecursionDepth) - return FALSE; - - int32_t iSize = pageNodes.m_childNode.GetSize(); - if (iSize <= 0 || iPage >= iSize) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - for (int32_t i = 0; i < iSize; ++i) { - PageNode* pNode = pageNodes.m_childNode.GetAt(i); - if (!pNode) - continue; - - switch (pNode->m_type) { - case PDF_PAGENODE_UNKNOWN: - if (!CheckUnkownPageNode(pNode->m_dwPageNo, pNode, pHints)) { - return FALSE; - } - --i; - break; - case PDF_PAGENODE_PAGE: - iCount++; - if (iPage == iCount && m_pDocument) - m_pDocument->SetPageObjNum(iPage, pNode->m_dwPageNo); - break; - case PDF_PAGENODE_PAGES: - if (!CheckPageNode(*pNode, iPage, iCount, pHints, level + 1)) - return FALSE; - break; - case PDF_PAGENODE_ARRAY: - if (!CheckArrayPageNode(pNode->m_dwPageNo, pNode, pHints)) - return FALSE; - --i; - break; - } - - if (iPage == iCount) { - m_docStatus = PDF_DATAAVAIL_DONE; - return TRUE; - } - } - return TRUE; -} - -FX_BOOL CPDF_DataAvail::LoadDocPage(uint32_t dwPage, DownloadHints* pHints) { - FX_SAFE_INT32 safePage = pdfium::base::checked_cast(dwPage); - int32_t iPage = safePage.ValueOrDie(); - if (m_pDocument->GetPageCount() <= iPage || - m_pDocument->IsPageLoaded(iPage)) { - m_docStatus = PDF_DATAAVAIL_DONE; - return TRUE; - } - - if (m_pageNodes.m_type == PDF_PAGENODE_PAGE) { - if (iPage == 0) { - m_docStatus = PDF_DATAAVAIL_DONE; - return TRUE; - } - m_docStatus = PDF_DATAAVAIL_ERROR; - return TRUE; - } - int32_t iCount = -1; - return CheckPageNode(m_pageNodes, iPage, iCount, pHints, 0); -} - -FX_BOOL CPDF_DataAvail::CheckPageCount(DownloadHints* pHints) { - FX_BOOL bExist = FALSE; - CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); - if (!bExist) { - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - if (!pPages) - return FALSE; - - CPDF_Dictionary* pPagesDict = pPages->GetDict(); - if (!pPagesDict) { - pPages->Release(); - m_docStatus = PDF_DATAAVAIL_ERROR; - return FALSE; - } - - if (!pPagesDict->KeyExist("Kids")) { - pPages->Release(); - return TRUE; - } - - int count = pPagesDict->GetIntegerFor("Count"); - if (count > 0) { - pPages->Release(); - return TRUE; - } - - pPages->Release(); - return FALSE; -} - -FX_BOOL CPDF_DataAvail::LoadDocPages(DownloadHints* pHints) { - if (!CheckUnkownPageNode(m_PagesObjNum, &m_pageNodes, pHints)) - return FALSE; - - if (CheckPageCount(pHints)) { - m_docStatus = PDF_DATAAVAIL_PAGE; - return TRUE; - } - - m_bTotalLoadPageTree = TRUE; - return FALSE; -} - -FX_BOOL CPDF_DataAvail::LoadPages(DownloadHints* pHints) { - while (!m_bPagesTreeLoad) { - if (!CheckPageStatus(pHints)) - return FALSE; - } - - if (m_bPagesLoad) - return TRUE; - - m_pDocument->LoadPages(); - return FALSE; -} - -CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedData( - DownloadHints* pHints) { - if (m_bLinearedDataOK) - return DataAvailable; - - if (!m_bMainXRefLoadTried) { - FX_SAFE_UINT32 data_size = m_dwFileLen; - data_size -= m_dwLastXRefOffset; - if (!data_size.IsValid()) - return DataError; - - if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, - data_size.ValueOrDie())) { - pHints->AddSegment(m_dwLastXRefOffset, data_size.ValueOrDie()); - return DataNotAvailable; - } - - CPDF_Parser::Error eRet = - m_pDocument->GetParser()->LoadLinearizedMainXRefTable(); - m_bMainXRefLoadTried = TRUE; - if (eRet != CPDF_Parser::SUCCESS) - return DataError; - - if (!PreparePageItem()) - return DataNotAvailable; - - m_bMainXRefLoadedOK = TRUE; - m_bLinearedDataOK = TRUE; - } - - return m_bLinearedDataOK ? DataAvailable : DataNotAvailable; -} - -FX_BOOL CPDF_DataAvail::CheckPageAnnots(uint32_t dwPage, - DownloadHints* pHints) { - if (!m_objs_array.GetSize()) { - m_objs_array.RemoveAll(); - m_ObjectSet.clear(); - - FX_SAFE_INT32 safePage = pdfium::base::checked_cast(dwPage); - CPDF_Dictionary* pPageDict = m_pDocument->GetPage(safePage.ValueOrDie()); - if (!pPageDict) - return TRUE; - - CPDF_Object* pAnnots = pPageDict->GetObjectFor("Annots"); - if (!pAnnots) - return TRUE; - - CFX_ArrayTemplate obj_array; - obj_array.Add(pAnnots); - - FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); - if (bRet) - m_objs_array.RemoveAll(); - - return bRet; - } - - CFX_ArrayTemplate new_objs_array; - FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); - m_objs_array.RemoveAll(); - if (!bRet) - m_objs_array.Append(new_objs_array); - - return bRet; -} - -CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedFirstPage( - uint32_t dwPage, - DownloadHints* pHints) { - if (!m_bAnnotsLoad) { - if (!CheckPageAnnots(dwPage, pHints)) - return DataNotAvailable; - m_bAnnotsLoad = TRUE; - } - - DocAvailStatus nRet = CheckLinearizedData(pHints); - if (nRet == DataAvailable) - m_bPageLoadedOK = FALSE; - return nRet; -} - -FX_BOOL CPDF_DataAvail::HaveResourceAncestor(CPDF_Dictionary* pDict) { - CFX_AutoRestorer restorer(&s_CurrentDataAvailRecursionDepth); - if (++s_CurrentDataAvailRecursionDepth > kMaxDataAvailRecursionDepth) - return FALSE; - - CPDF_Object* pParent = pDict->GetObjectFor("Parent"); - if (!pParent) - return FALSE; - - CPDF_Dictionary* pParentDict = pParent->GetDict(); - if (!pParentDict) - return FALSE; - - CPDF_Object* pRet = pParentDict->GetObjectFor("Resources"); - if (pRet) { - m_pPageResource = pRet; - return TRUE; - } - - return HaveResourceAncestor(pParentDict); -} - -CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsPageAvail( - uint32_t dwPage, - DownloadHints* pHints) { - if (!m_pDocument) - return DataError; - - if (IsFirstCheck(dwPage)) { - m_bCurPageDictLoadOK = FALSE; - m_bPageLoadedOK = FALSE; - m_bAnnotsLoad = FALSE; - m_bNeedDownLoadResource = FALSE; - m_objs_array.RemoveAll(); - m_ObjectSet.clear(); - } - - if (pdfium::ContainsKey(m_pagesLoadState, dwPage)) - return DataAvailable; - - if (m_bLinearized) { - if (dwPage == m_dwFirstPageNo) { - DocAvailStatus nRet = CheckLinearizedFirstPage(dwPage, pHints); - if (nRet == DataAvailable) - m_pagesLoadState.insert(dwPage); - return nRet; - } - - DocAvailStatus nResult = CheckLinearizedData(pHints); - if (nResult != DataAvailable) - return nResult; - - if (m_pHintTables) { - nResult = m_pHintTables->CheckPage(dwPage, pHints); - if (nResult != DataAvailable) - return nResult; - m_pagesLoadState.insert(dwPage); - return DataAvailable; - } - - if (m_bMainXRefLoadedOK) { - if (m_bTotalLoadPageTree) { - if (!LoadPages(pHints)) - return DataNotAvailable; - } else { - if (!m_bCurPageDictLoadOK && !CheckPage(dwPage, pHints)) - return DataNotAvailable; - } - } else { - if (!LoadAllFile(pHints)) - return DataNotAvailable; - m_pDocument->GetParser()->RebuildCrossRef(); - ResetFirstCheck(dwPage); - return DataAvailable; - } - } else { - if (!m_bTotalLoadPageTree && !m_bCurPageDictLoadOK && - !CheckPage(dwPage, pHints)) { - return DataNotAvailable; - } - } - - if (m_bHaveAcroForm && !m_bAcroFormLoad) { - if (!CheckAcroFormSubObject(pHints)) - return DataNotAvailable; - m_bAcroFormLoad = TRUE; - } - - if (!m_bPageLoadedOK) { - if (!m_objs_array.GetSize()) { - m_objs_array.RemoveAll(); - m_ObjectSet.clear(); - - FX_SAFE_INT32 safePage = pdfium::base::checked_cast(dwPage); - m_pPageDict = m_pDocument->GetPage(safePage.ValueOrDie()); - if (!m_pPageDict) { - ResetFirstCheck(dwPage); - return DataAvailable; - } - - CFX_ArrayTemplate obj_array; - obj_array.Add(m_pPageDict); - FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); - if (!bRet) - return DataNotAvailable; - - m_objs_array.RemoveAll(); - } else { - CFX_ArrayTemplate new_objs_array; - FX_BOOL bRet = - IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); - - m_objs_array.RemoveAll(); - if (!bRet) { - m_objs_array.Append(new_objs_array); - return DataNotAvailable; - } - } - m_bPageLoadedOK = TRUE; - } - - if (!m_bAnnotsLoad) { - if (!CheckPageAnnots(dwPage, pHints)) - return DataNotAvailable; - m_bAnnotsLoad = TRUE; - } - - if (m_pPageDict && !m_bNeedDownLoadResource) { - m_pPageResource = m_pPageDict->GetObjectFor("Resources"); - m_bNeedDownLoadResource = - m_pPageResource || HaveResourceAncestor(m_pPageDict); - } - - if (m_bNeedDownLoadResource) { - if (!CheckResources(pHints)) - return DataNotAvailable; - m_bNeedDownLoadResource = FALSE; - } - - m_bPageLoadedOK = FALSE; - m_bAnnotsLoad = FALSE; - m_bCurPageDictLoadOK = FALSE; - - ResetFirstCheck(dwPage); - m_pagesLoadState.insert(dwPage); - return DataAvailable; -} - -FX_BOOL CPDF_DataAvail::CheckResources(DownloadHints* pHints) { - if (!m_objs_array.GetSize()) { - m_objs_array.RemoveAll(); - CFX_ArrayTemplate obj_array; - obj_array.Add(m_pPageResource); - - FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); - if (bRet) - m_objs_array.RemoveAll(); - return bRet; - } - - CFX_ArrayTemplate new_objs_array; - FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); - m_objs_array.RemoveAll(); - if (!bRet) - m_objs_array.Append(new_objs_array); - return bRet; -} - -void CPDF_DataAvail::GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, - uint32_t* pSize) { - if (pPos) - *pPos = m_dwLastXRefOffset; - if (pSize) - *pSize = (uint32_t)(m_dwFileLen - m_dwLastXRefOffset); -} - -int CPDF_DataAvail::GetPageCount() const { - if (m_pLinearized) { - CPDF_Dictionary* pDict = m_pLinearized->GetDict(); - CPDF_Object* pObj = pDict ? pDict->GetDirectObjectFor("N") : nullptr; - return pObj ? pObj->GetInteger() : 0; - } - return m_pDocument ? m_pDocument->GetPageCount() : 0; -} - -CPDF_Dictionary* CPDF_DataAvail::GetPage(int index) { - if (!m_pDocument || index < 0 || index >= GetPageCount()) - return nullptr; - - if (m_pLinearized) { - CPDF_Dictionary* pDict = m_pLinearized->GetDict(); - CPDF_Object* pObj = pDict ? pDict->GetDirectObjectFor("P") : nullptr; - - int pageNum = pObj ? pObj->GetInteger() : 0; - if (m_pHintTables && index != pageNum) { - FX_FILESIZE szPageStartPos = 0; - FX_FILESIZE szPageLength = 0; - uint32_t dwObjNum = 0; - bool bPagePosGot = m_pHintTables->GetPagePos(index, &szPageStartPos, - &szPageLength, &dwObjNum); - if (!bPagePosGot) - return nullptr; - - m_syntaxParser.InitParser(m_pFileRead, (uint32_t)szPageStartPos); - CPDF_Object* pPageDict = ParseIndirectObjectAt(0, dwObjNum, m_pDocument); - if (!pPageDict) - return nullptr; - - if (!m_pDocument->ReplaceIndirectObjectIfHigherGeneration(dwObjNum, - pPageDict)) { - return nullptr; - } - return pPageDict->GetDict(); - } - } - return m_pDocument->GetPage(index); -} - -CPDF_DataAvail::DocFormStatus CPDF_DataAvail::IsFormAvail( - DownloadHints* pHints) { - if (!m_pDocument) - return FormAvailable; - - if (!m_bLinearizedFormParamLoad) { - CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); - if (!pRoot) - return FormAvailable; - - CPDF_Object* pAcroForm = pRoot->GetObjectFor("AcroForm"); - if (!pAcroForm) - return FormNotExist; - - DocAvailStatus nDocStatus = CheckLinearizedData(pHints); - if (nDocStatus == DataError) - return FormError; - if (nDocStatus == DataNotAvailable) - return FormNotAvailable; - - if (!m_objs_array.GetSize()) - m_objs_array.Add(pAcroForm->GetDict()); - m_bLinearizedFormParamLoad = TRUE; - } - - CFX_ArrayTemplate new_objs_array; - FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); - m_objs_array.RemoveAll(); - if (!bRet) { - m_objs_array.Append(new_objs_array); - return FormNotAvailable; - } - return FormAvailable; -} - -CPDF_DataAvail::PageNode::PageNode() : m_type(PDF_PAGENODE_UNKNOWN) {} - -CPDF_DataAvail::PageNode::~PageNode() { - for (int32_t i = 0; i < m_childNode.GetSize(); ++i) - delete m_childNode[i]; - m_childNode.RemoveAll(); -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_data_avail.h b/core/fpdfapi/fpdf_parser/cpdf_data_avail.h deleted file mode 100644 index 4f8f45b4ed..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_data_avail.h +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_DATA_AVAIL_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_DATA_AVAIL_H_ - -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h" -#include "core/fxcrt/fx_basic.h" - -class CPDF_Dictionary; -class CPDF_HintTables; -class CPDF_IndirectObjectHolder; -class CPDF_Parser; - -enum PDF_DATAAVAIL_STATUS { - PDF_DATAAVAIL_HEADER = 0, - PDF_DATAAVAIL_FIRSTPAGE, - PDF_DATAAVAIL_FIRSTPAGE_PREPARE, - PDF_DATAAVAIL_HINTTABLE, - PDF_DATAAVAIL_END, - PDF_DATAAVAIL_CROSSREF, - PDF_DATAAVAIL_CROSSREF_ITEM, - PDF_DATAAVAIL_CROSSREF_STREAM, - PDF_DATAAVAIL_TRAILER, - PDF_DATAAVAIL_LOADALLCROSSREF, - 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 -}; - -enum PDF_PAGENODE_TYPE { - PDF_PAGENODE_UNKNOWN = 0, - PDF_PAGENODE_PAGE, - PDF_PAGENODE_PAGES, - PDF_PAGENODE_ARRAY, -}; - -class CPDF_DataAvail final { - public: - // Must match PDF_DATA_* definitions in public/fpdf_dataavail.h, but cannot - // #include that header. fpdfsdk/fpdf_dataavail.cpp has static_asserts - // to make sure the two sets of values match. - enum DocAvailStatus { - DataError = -1, // PDF_DATA_ERROR - DataNotAvailable = 0, // PDF_DATA_NOTAVAIL - DataAvailable = 1, // PDF_DATA_AVAIL - }; - - // Must match PDF_*LINEAR* definitions in public/fpdf_dataavail.h, but cannot - // #include that header. fpdfsdk/fpdf_dataavail.cpp has static_asserts - // to make sure the two sets of values match. - enum DocLinearizationStatus { - LinearizationUnknown = -1, // PDF_LINEARIZATION_UNKNOWN - NotLinearized = 0, // PDF_NOT_LINEARIZED - Linearized = 1, // PDF_LINEARIZED - }; - - // Must match PDF_FORM_* definitions in public/fpdf_dataavail.h, but cannot - // #include that header. fpdfsdk/fpdf_dataavail.cpp has static_asserts - // to make sure the two sets of values match. - enum DocFormStatus { - FormError = -1, // PDF_FORM_ERROR - FormNotAvailable = 0, // PDF_FORM_NOTAVAIL - FormAvailable = 1, // PDF_FORM_AVAIL - FormNotExist = 2, // PDF_FORM_NOTEXIST - }; - - class FileAvail { - public: - virtual ~FileAvail(); - virtual FX_BOOL IsDataAvail(FX_FILESIZE offset, uint32_t size) = 0; - }; - - class DownloadHints { - public: - virtual ~DownloadHints(); - virtual void AddSegment(FX_FILESIZE offset, uint32_t size) = 0; - }; - - CPDF_DataAvail(FileAvail* pFileAvail, - IFX_FileRead* pFileRead, - FX_BOOL bSupportHintTable); - ~CPDF_DataAvail(); - - DocAvailStatus IsDocAvail(DownloadHints* pHints); - void SetDocument(CPDF_Document* pDoc); - DocAvailStatus IsPageAvail(uint32_t dwPage, DownloadHints* pHints); - DocFormStatus IsFormAvail(DownloadHints* pHints); - DocLinearizationStatus IsLinearizedPDF(); - FX_BOOL IsLinearized(); - void GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, uint32_t* pSize); - IFX_FileRead* GetFileRead() const { return m_pFileRead; } - int GetPageCount() const; - CPDF_Dictionary* GetPage(int index); - - friend class CPDF_HintTables; - - protected: - class PageNode { - public: - PageNode(); - ~PageNode(); - - PDF_PAGENODE_TYPE m_type; - uint32_t m_dwPageNo; - CFX_ArrayTemplate m_childNode; - }; - - static const int kMaxDataAvailRecursionDepth = 64; - static int s_CurrentDataAvailRecursionDepth; - static const int kMaxPageRecursionDepth = 1024; - - uint32_t GetObjectSize(uint32_t objnum, FX_FILESIZE& offset); - FX_BOOL IsObjectsAvail(CFX_ArrayTemplate& obj_array, - FX_BOOL bParsePage, - DownloadHints* pHints, - CFX_ArrayTemplate& ret_array); - FX_BOOL CheckDocStatus(DownloadHints* pHints); - FX_BOOL CheckHeader(DownloadHints* pHints); - FX_BOOL CheckFirstPage(DownloadHints* pHints); - FX_BOOL CheckHintTables(DownloadHints* pHints); - FX_BOOL CheckEnd(DownloadHints* pHints); - FX_BOOL CheckCrossRef(DownloadHints* pHints); - FX_BOOL CheckCrossRefItem(DownloadHints* pHints); - FX_BOOL CheckTrailer(DownloadHints* pHints); - FX_BOOL CheckRoot(DownloadHints* pHints); - FX_BOOL CheckInfo(DownloadHints* pHints); - FX_BOOL CheckPages(DownloadHints* pHints); - FX_BOOL CheckPage(DownloadHints* pHints); - FX_BOOL CheckResources(DownloadHints* pHints); - FX_BOOL CheckAnnots(DownloadHints* pHints); - FX_BOOL CheckAcroForm(DownloadHints* pHints); - FX_BOOL CheckAcroFormSubObject(DownloadHints* pHints); - FX_BOOL CheckTrailerAppend(DownloadHints* pHints); - FX_BOOL CheckPageStatus(DownloadHints* pHints); - FX_BOOL CheckAllCrossRefStream(DownloadHints* pHints); - - int32_t CheckCrossRefStream(DownloadHints* pHints, FX_FILESIZE& xref_offset); - FX_BOOL IsLinearizedFile(uint8_t* pData, uint32_t dwLen); - void SetStartOffset(FX_FILESIZE dwOffset); - FX_BOOL GetNextToken(CFX_ByteString& token); - FX_BOOL GetNextChar(uint8_t& ch); - CPDF_Object* ParseIndirectObjectAt( - FX_FILESIZE pos, - uint32_t objnum, - CPDF_IndirectObjectHolder* pObjList = nullptr); - CPDF_Object* GetObject(uint32_t objnum, - DownloadHints* pHints, - FX_BOOL* pExistInFile); - FX_BOOL GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages); - FX_BOOL PreparePageItem(); - FX_BOOL LoadPages(DownloadHints* pHints); - FX_BOOL LoadAllXref(DownloadHints* pHints); - FX_BOOL LoadAllFile(DownloadHints* pHints); - DocAvailStatus CheckLinearizedData(DownloadHints* pHints); - FX_BOOL CheckPageAnnots(uint32_t dwPage, DownloadHints* pHints); - - DocAvailStatus CheckLinearizedFirstPage(uint32_t dwPage, - DownloadHints* pHints); - FX_BOOL HaveResourceAncestor(CPDF_Dictionary* pDict); - FX_BOOL CheckPage(uint32_t dwPage, DownloadHints* pHints); - FX_BOOL LoadDocPages(DownloadHints* pHints); - FX_BOOL LoadDocPage(uint32_t dwPage, DownloadHints* pHints); - FX_BOOL CheckPageNode(PageNode& pageNodes, - int32_t iPage, - int32_t& iCount, - DownloadHints* pHints, - int level); - FX_BOOL CheckUnkownPageNode(uint32_t dwPageNo, - PageNode* pPageNode, - DownloadHints* pHints); - FX_BOOL CheckArrayPageNode(uint32_t dwPageNo, - PageNode* pPageNode, - DownloadHints* pHints); - FX_BOOL CheckPageCount(DownloadHints* pHints); - bool IsFirstCheck(uint32_t dwPage); - void ResetFirstCheck(uint32_t dwPage); - FX_BOOL IsDataAvail(FX_FILESIZE offset, uint32_t size, DownloadHints* pHints); - - FileAvail* const m_pFileAvail; - IFX_FileRead* const m_pFileRead; - CPDF_Parser m_parser; - CPDF_SyntaxParser m_syntaxParser; - CPDF_Object* m_pRoot; - uint32_t m_dwRootObjNum; - uint32_t 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; - FX_FILESIZE m_dwFileLen; - CPDF_Document* m_pDocument; - std::set m_ObjectSet; - CFX_ArrayTemplate m_objs_array; - FX_FILESIZE m_Pos; - FX_FILESIZE m_bufferOffset; - uint32_t m_bufferSize; - CFX_ByteString m_WordBuf; - uint8_t m_bufferData[512]; - CFX_ArrayTemplate m_XRefStreamList; - CFX_ArrayTemplate m_PageObjList; - uint32_t m_PagesObjNum; - FX_BOOL m_bLinearized; - uint32_t m_dwFirstPageNo; - FX_BOOL m_bLinearedDataOK; - FX_BOOL m_bMainXRefLoadTried; - 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; - uint32_t m_dwAcroFormObjNum; - FX_BOOL m_bAcroFormLoad; - CPDF_Object* m_pAcroForm; - CFX_ArrayTemplate m_arrayAcroforms; - CPDF_Dictionary* m_pPageDict; - CPDF_Object* m_pPageResource; - FX_BOOL m_bNeedDownLoadResource; - FX_BOOL m_bPageLoadedOK; - FX_BOOL m_bLinearizedFormParamLoad; - CFX_ArrayTemplate m_PagesArray; - uint32_t m_dwEncryptObjNum; - FX_FILESIZE m_dwPrevXRefOffset; - FX_BOOL m_bTotalLoadPageTree; - FX_BOOL m_bCurPageDictLoadOK; - PageNode m_pageNodes; - std::set m_pageMapCheckState; - std::set m_pagesLoadState; - std::unique_ptr m_pHintTables; - FX_BOOL m_bSupportHintTable; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_DATA_AVAIL_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_dictionary.cpp b/core/fpdfapi/fpdf_parser/cpdf_dictionary.cpp deleted file mode 100644 index 5696fc0c8d..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_dictionary.cpp +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" - -#include -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" -#include "third_party/base/logging.h" -#include "third_party/base/stl_util.h" - -CPDF_Dictionary::CPDF_Dictionary() - : CPDF_Dictionary(CFX_WeakPtr()) {} - -CPDF_Dictionary::CPDF_Dictionary(const CFX_WeakPtr& pPool) - : m_pPool(pPool) {} - -CPDF_Dictionary::~CPDF_Dictionary() { - // Mark the object as deleted so that it will not be deleted again - // in case of cyclic references. - m_ObjNum = kInvalidObjNum; - for (const auto& it : m_Map) { - if (it.second) - it.second->Release(); - } -} - -CPDF_Object::Type CPDF_Dictionary::GetType() const { - return DICTIONARY; -} - -CPDF_Dictionary* CPDF_Dictionary::GetDict() const { - // The method should be made non-const if we want to not be const. - // See bug #234. - return const_cast(this); -} - -bool CPDF_Dictionary::IsDictionary() const { - return true; -} - -CPDF_Dictionary* CPDF_Dictionary::AsDictionary() { - return this; -} - -const CPDF_Dictionary* CPDF_Dictionary::AsDictionary() const { - return this; -} - -CPDF_Object* CPDF_Dictionary::Clone() const { - return CloneObjectNonCyclic(false); -} - -CPDF_Object* CPDF_Dictionary::CloneNonCyclic( - bool bDirect, - std::set* pVisited) const { - pVisited->insert(this); - CPDF_Dictionary* pCopy = new CPDF_Dictionary(m_pPool); - for (const auto& it : *this) { - CPDF_Object* value = it.second; - if (!pdfium::ContainsKey(*pVisited, value)) { - pCopy->m_Map.insert( - std::make_pair(it.first, value->CloneNonCyclic(bDirect, pVisited))); - } - } - return pCopy; -} - -CPDF_Object* CPDF_Dictionary::GetObjectFor(const CFX_ByteString& key) const { - auto it = m_Map.find(key); - return it != m_Map.end() ? it->second : nullptr; -} - -CPDF_Object* CPDF_Dictionary::GetDirectObjectFor( - const CFX_ByteString& key) const { - CPDF_Object* p = GetObjectFor(key); - return p ? p->GetDirect() : nullptr; -} - -CFX_ByteString CPDF_Dictionary::GetStringFor(const CFX_ByteString& key) const { - CPDF_Object* p = GetObjectFor(key); - return p ? p->GetString() : CFX_ByteString(); -} - -CFX_WideString CPDF_Dictionary::GetUnicodeTextFor( - const CFX_ByteString& key) const { - CPDF_Object* p = GetObjectFor(key); - if (CPDF_Reference* pRef = ToReference(p)) - p = pRef->GetDirect(); - return p ? p->GetUnicodeText() : CFX_WideString(); -} - -CFX_ByteString CPDF_Dictionary::GetStringFor(const CFX_ByteString& key, - const CFX_ByteString& def) const { - CPDF_Object* p = GetObjectFor(key); - return p ? p->GetString() : CFX_ByteString(def); -} - -int CPDF_Dictionary::GetIntegerFor(const CFX_ByteString& key) const { - CPDF_Object* p = GetObjectFor(key); - return p ? p->GetInteger() : 0; -} - -int CPDF_Dictionary::GetIntegerFor(const CFX_ByteString& key, int def) const { - CPDF_Object* p = GetObjectFor(key); - return p ? p->GetInteger() : def; -} - -FX_FLOAT CPDF_Dictionary::GetNumberFor(const CFX_ByteString& key) const { - CPDF_Object* p = GetObjectFor(key); - return p ? p->GetNumber() : 0; -} - -bool CPDF_Dictionary::GetBooleanFor(const CFX_ByteString& key, - bool bDefault) const { - CPDF_Object* p = GetObjectFor(key); - return ToBoolean(p) ? p->GetInteger() != 0 : bDefault; -} - -CPDF_Dictionary* CPDF_Dictionary::GetDictFor(const CFX_ByteString& key) const { - CPDF_Object* p = GetDirectObjectFor(key); - if (!p) - return nullptr; - if (CPDF_Dictionary* pDict = p->AsDictionary()) - return pDict; - if (CPDF_Stream* pStream = p->AsStream()) - return pStream->GetDict(); - return nullptr; -} - -CPDF_Array* CPDF_Dictionary::GetArrayFor(const CFX_ByteString& key) const { - return ToArray(GetDirectObjectFor(key)); -} - -CPDF_Stream* CPDF_Dictionary::GetStreamFor(const CFX_ByteString& key) const { - return ToStream(GetDirectObjectFor(key)); -} - -CFX_FloatRect CPDF_Dictionary::GetRectFor(const CFX_ByteString& key) const { - CFX_FloatRect rect; - CPDF_Array* pArray = GetArrayFor(key); - if (pArray) - rect = pArray->GetRect(); - return rect; -} - -CFX_Matrix CPDF_Dictionary::GetMatrixFor(const CFX_ByteString& key) const { - CFX_Matrix matrix; - CPDF_Array* pArray = GetArrayFor(key); - if (pArray) - matrix = pArray->GetMatrix(); - return matrix; -} - -FX_BOOL CPDF_Dictionary::KeyExist(const CFX_ByteString& key) const { - return pdfium::ContainsKey(m_Map, key); -} - -bool CPDF_Dictionary::IsSignatureDict() const { - CPDF_Object* pType = GetDirectObjectFor("Type"); - if (!pType) - pType = GetDirectObjectFor("FT"); - return pType && pType->GetString() == "Sig"; -} - -void CPDF_Dictionary::SetFor(const CFX_ByteString& key, CPDF_Object* pObj) { - CHECK(!pObj || pObj->GetObjNum() == 0); - auto it = m_Map.find(key); - if (it == m_Map.end()) { - if (pObj) - m_Map.insert(std::make_pair(MaybeIntern(key), pObj)); - return; - } - - if (it->second == pObj) - return; - it->second->Release(); - - if (pObj) - it->second = pObj; - else - m_Map.erase(it); -} - -void CPDF_Dictionary::RemoveFor(const CFX_ByteString& key) { - auto it = m_Map.find(key); - if (it == m_Map.end()) - return; - - it->second->Release(); - m_Map.erase(it); -} - -void CPDF_Dictionary::ReplaceKey(const CFX_ByteString& oldkey, - const CFX_ByteString& newkey) { - auto old_it = m_Map.find(oldkey); - if (old_it == m_Map.end()) - return; - - auto new_it = m_Map.find(newkey); - if (new_it == old_it) - return; - - if (new_it != m_Map.end()) { - new_it->second->Release(); - new_it->second = old_it->second; - } else { - m_Map.insert(std::make_pair(MaybeIntern(newkey), old_it->second)); - } - m_Map.erase(old_it); -} - -void CPDF_Dictionary::SetIntegerFor(const CFX_ByteString& key, int i) { - SetFor(key, new CPDF_Number(i)); -} - -void CPDF_Dictionary::SetNameFor(const CFX_ByteString& key, - const CFX_ByteString& name) { - SetFor(key, new CPDF_Name(MaybeIntern(name))); -} - -void CPDF_Dictionary::SetStringFor(const CFX_ByteString& key, - const CFX_ByteString& str) { - SetFor(key, new CPDF_String(MaybeIntern(str), FALSE)); -} - -void CPDF_Dictionary::SetReferenceFor(const CFX_ByteString& key, - CPDF_IndirectObjectHolder* pDoc, - uint32_t objnum) { - SetFor(key, new CPDF_Reference(pDoc, objnum)); -} - -void CPDF_Dictionary::SetNumberFor(const CFX_ByteString& key, FX_FLOAT f) { - SetFor(key, new CPDF_Number(f)); -} - -void CPDF_Dictionary::SetBooleanFor(const CFX_ByteString& key, bool bValue) { - SetFor(key, new CPDF_Boolean(bValue)); -} - -void CPDF_Dictionary::SetRectFor(const CFX_ByteString& key, - const CFX_FloatRect& rect) { - CPDF_Array* pArray = new CPDF_Array; - pArray->AddNumber(rect.left); - pArray->AddNumber(rect.bottom); - pArray->AddNumber(rect.right); - pArray->AddNumber(rect.top); - SetFor(key, pArray); -} - -void CPDF_Dictionary::SetMatrixFor(const CFX_ByteString& key, - const CFX_Matrix& matrix) { - CPDF_Array* pArray = new CPDF_Array; - pArray->AddNumber(matrix.a); - pArray->AddNumber(matrix.b); - pArray->AddNumber(matrix.c); - pArray->AddNumber(matrix.d); - pArray->AddNumber(matrix.e); - pArray->AddNumber(matrix.f); - SetFor(key, pArray); -} - -CFX_ByteString CPDF_Dictionary::MaybeIntern(const CFX_ByteString& str) { - return m_pPool ? m_pPool->Intern(str) : str; -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_dictionary.h b/core/fpdfapi/fpdf_parser/cpdf_dictionary.h deleted file mode 100644 index e3fd594575..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_dictionary.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_DICTIONARY_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_DICTIONARY_H_ - -#include -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fxcrt/cfx_string_pool_template.h" -#include "core/fxcrt/cfx_weak_ptr.h" -#include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_string.h" - -class CPDF_IndirectObjectHolder; - -class CPDF_Dictionary : public CPDF_Object { - public: - using iterator = std::map::iterator; - using const_iterator = std::map::const_iterator; - - CPDF_Dictionary(); - explicit CPDF_Dictionary(const CFX_WeakPtr& pPool); - - // CPDF_Object. - Type GetType() const override; - CPDF_Object* Clone() const override; - CPDF_Dictionary* GetDict() const override; - bool IsDictionary() const override; - CPDF_Dictionary* AsDictionary() override; - const CPDF_Dictionary* AsDictionary() const override; - - size_t GetCount() const { return m_Map.size(); } - CPDF_Object* GetObjectFor(const CFX_ByteString& key) const; - CPDF_Object* GetDirectObjectFor(const CFX_ByteString& key) const; - CFX_ByteString GetStringFor(const CFX_ByteString& key) const; - CFX_ByteString GetStringFor(const CFX_ByteString& key, - const CFX_ByteString& default_str) const; - CFX_WideString GetUnicodeTextFor(const CFX_ByteString& key) const; - int GetIntegerFor(const CFX_ByteString& key) const; - int GetIntegerFor(const CFX_ByteString& key, int default_int) const; - bool GetBooleanFor(const CFX_ByteString& key, bool bDefault = false) const; - FX_FLOAT GetNumberFor(const CFX_ByteString& key) const; - CPDF_Dictionary* GetDictFor(const CFX_ByteString& key) const; - CPDF_Stream* GetStreamFor(const CFX_ByteString& key) const; - CPDF_Array* GetArrayFor(const CFX_ByteString& key) const; - CFX_FloatRect GetRectFor(const CFX_ByteString& key) const; - CFX_Matrix GetMatrixFor(const CFX_ByteString& key) const; - FX_FLOAT GetFloatFor(const CFX_ByteString& key) const { - return GetNumberFor(key); - } - - FX_BOOL KeyExist(const CFX_ByteString& key) const; - bool IsSignatureDict() const; - - // Set* functions invalidate iterators for the element with the key |key|. - void SetFor(const CFX_ByteString& key, CPDF_Object* pObj); - void SetNameFor(const CFX_ByteString& key, const CFX_ByteString& name); - void SetStringFor(const CFX_ByteString& key, const CFX_ByteString& str); - void SetIntegerFor(const CFX_ByteString& key, int i); - void SetNumberFor(const CFX_ByteString& key, FX_FLOAT f); - void SetReferenceFor(const CFX_ByteString& key, - CPDF_IndirectObjectHolder* pDoc, - uint32_t objnum); - void SetRectFor(const CFX_ByteString& key, const CFX_FloatRect& rect); - void SetMatrixFor(const CFX_ByteString& key, const CFX_Matrix& matrix); - void SetBooleanFor(const CFX_ByteString& key, bool bValue); - - // Invalidates iterators for the element with the key |key|. - void RemoveFor(const CFX_ByteString& key); - - // Invalidates iterators for the element with the key |oldkey|. - void ReplaceKey(const CFX_ByteString& oldkey, const CFX_ByteString& newkey); - - 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(); } - - CFX_WeakPtr GetByteStringPool() const { return m_pPool; } - - protected: - ~CPDF_Dictionary() override; - - CFX_ByteString MaybeIntern(const CFX_ByteString& str); - CPDF_Object* CloneNonCyclic( - bool bDirect, - std::set* visited) const override; - - CFX_WeakPtr m_pPool; - std::map m_Map; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_DICTIONARY_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_document.cpp b/core/fpdfapi/fpdf_parser/cpdf_document.cpp deleted file mode 100644 index 21469af179..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_document.cpp +++ /dev/null @@ -1,1020 +0,0 @@ -// 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" - -#include -#include -#include - -#include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/font/cpdf_fontencoding.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_render/render_int.h" -#include "core/fpdfapi/page/cpdf_pagemodule.h" -#include "core/fpdfapi/page/pageint.h" -#include "core/fxcodec/JBig2_DocumentContext.h" -#include "core/fxge/cfx_unicodeencoding.h" -#include "core/fxge/fx_font.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" - -namespace { - -const int FX_MAX_PAGE_LEVEL = 1024; - -const uint16_t g_FX_CP874Unicodes[128] = { - 0x20AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x2026, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2018, - 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00A0, 0x0E01, 0x0E02, 0x0E03, - 0x0E04, 0x0E05, 0x0E06, 0x0E07, 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, - 0x0E0D, 0x0E0E, 0x0E0F, 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, - 0x0E16, 0x0E17, 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, - 0x0E1F, 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, - 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, 0x0E30, - 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, 0x0E38, 0x0E39, - 0x0E3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E3F, 0x0E40, 0x0E41, 0x0E42, - 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, - 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, - 0x0E55, 0x0E56, 0x0E57, 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0000, 0x0000, - 0x0000, 0x0000, -}; -const uint16_t g_FX_CP1250Unicodes[128] = { - 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, 0x0000, - 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, 0x0000, 0x2018, - 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0161, - 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, 0x00A0, 0x02C7, 0x02D8, 0x0141, - 0x00A4, 0x0104, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, - 0x00AD, 0x00AE, 0x017B, 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, - 0x00B6, 0x00B7, 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, - 0x017C, 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, - 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, 0x0110, - 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, 0x0158, 0x016E, - 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, 0x0155, 0x00E1, 0x00E2, - 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, 0x010D, 0x00E9, 0x0119, 0x00EB, - 0x011B, 0x00ED, 0x00EE, 0x010F, 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, - 0x0151, 0x00F6, 0x00F7, 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, - 0x0163, 0x02D9, -}; -const uint16_t g_FX_CP1251Unicodes[128] = { - 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, 0x20AC, - 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, 0x0452, 0x2018, - 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0459, - 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, 0x00A0, 0x040E, 0x045E, 0x0408, - 0x00A4, 0x0490, 0x00A6, 0x00A7, 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, - 0x00AD, 0x00AE, 0x0407, 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, - 0x00B6, 0x00B7, 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, - 0x0457, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, - 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, - 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, - 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, - 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, - 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, - 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, - 0x044E, 0x044F, -}; -const uint16_t g_FX_CP1253Unicodes[128] = { - 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x0000, - 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2018, - 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0000, - 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, 0x00A0, 0x0385, 0x0386, 0x00A3, - 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, - 0x00AD, 0x00AE, 0x2015, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, - 0x00B6, 0x00B7, 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, - 0x038F, 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, - 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, - 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, - 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, 0x03B0, 0x03B1, 0x03B2, - 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, - 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, - 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, - 0x03CE, 0x0000, -}; -const uint16_t g_FX_CP1254Unicodes[128] = { - 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, - 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000, 0x0000, 0x2018, - 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, - 0x203A, 0x0153, 0x0000, 0x0000, 0x0178, 0x00A0, 0x00A1, 0x00A2, 0x00A3, - 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, - 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, - 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, - 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x011E, - 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, - 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, 0x00E0, 0x00E1, 0x00E2, - 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, - 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, - 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, - 0x015F, 0x00FF, -}; -const uint16_t g_FX_CP1255Unicodes[128] = { - 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, - 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2018, - 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0000, - 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, 0x00A0, 0x00A1, 0x00A2, 0x00A3, - 0x20AA, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, - 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, - 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, - 0x00BF, 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, - 0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, 0x05C0, - 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x05D0, 0x05D1, 0x05D2, - 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, - 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, - 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, - 0x200F, 0x0000, -}; -const uint16_t g_FX_CP1256Unicodes[128] = { - 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, - 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, 0x06AF, 0x2018, - 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x06A9, 0x2122, 0x0691, - 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, 0x00A0, 0x060C, 0x00A2, 0x00A3, - 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, - 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, - 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, - 0x061F, 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, - 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, - 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, 0x0637, 0x0638, - 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643, 0x00E0, 0x0644, 0x00E2, - 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, - 0x0649, 0x064A, 0x00EE, 0x00EF, 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, - 0x064F, 0x0650, 0x00F7, 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, - 0x200F, 0x06D2, -}; -const uint16_t g_FX_CP1257Unicodes[128] = { - 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, 0x0000, - 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8, 0x0000, 0x2018, - 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0000, - 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000, 0x00A0, 0x0000, 0x00A2, 0x00A3, - 0x00A4, 0x0000, 0x00A6, 0x00A7, 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, - 0x00AD, 0x00AE, 0x00C6, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, - 0x00B6, 0x00B7, 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, - 0x00E6, 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, - 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, 0x0160, - 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, 0x0172, 0x0141, - 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, 0x0105, 0x012F, 0x0101, - 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, 0x010D, 0x00E9, 0x017A, 0x0117, - 0x0123, 0x0137, 0x012B, 0x013C, 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, - 0x00F5, 0x00F6, 0x00F7, 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, - 0x017E, 0x02D9, -}; - -struct FX_CharsetUnicodes { - uint8_t m_Charset; - const uint16_t* m_pUnicodes; -}; - -const FX_CharsetUnicodes g_FX_CharsetUnicodes[] = { - {FXFONT_THAI_CHARSET, g_FX_CP874Unicodes}, - {FXFONT_EASTEUROPE_CHARSET, g_FX_CP1250Unicodes}, - {FXFONT_RUSSIAN_CHARSET, g_FX_CP1251Unicodes}, - {FXFONT_GREEK_CHARSET, g_FX_CP1253Unicodes}, - {FXFONT_TURKISH_CHARSET, g_FX_CP1254Unicodes}, - {FXFONT_HEBREW_CHARSET, g_FX_CP1255Unicodes}, - {FXFONT_ARABIC_CHARSET, g_FX_CP1256Unicodes}, - {FXFONT_BALTIC_CHARSET, g_FX_CP1257Unicodes}, -}; - -void InsertWidthArrayImpl(int* widths, int size, CPDF_Array* pWidthArray) { - int i; - for (i = 1; i < size; i++) { - if (widths[i] != *widths) - break; - } - if (i == size) { - int first = pWidthArray->GetIntegerAt(pWidthArray->GetCount() - 1); - pWidthArray->AddInteger(first + size - 1); - pWidthArray->AddInteger(*widths); - } else { - CPDF_Array* pWidthArray1 = new CPDF_Array; - pWidthArray->Add(pWidthArray1); - for (i = 0; i < size; i++) - pWidthArray1->AddInteger(widths[i]); - } - FX_Free(widths); -} - -#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ -void InsertWidthArray(HDC hDC, int start, int end, CPDF_Array* pWidthArray) { - int size = end - start + 1; - int* widths = FX_Alloc(int, size); - GetCharWidth(hDC, start, end, widths); - InsertWidthArrayImpl(widths, size, pWidthArray); -} - -CFX_ByteString FPDF_GetPSNameFromTT(HDC hDC) { - CFX_ByteString result; - DWORD size = ::GetFontData(hDC, 'eman', 0, nullptr, 0); - if (size != GDI_ERROR) { - LPBYTE buffer = FX_Alloc(BYTE, size); - ::GetFontData(hDC, 'eman', 0, buffer, size); - result = GetNameFromTT(buffer, size, 6); - FX_Free(buffer); - } - return result; -} -#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ - -void InsertWidthArray1(CFX_Font* pFont, - CFX_UnicodeEncoding* pEncoding, - FX_WCHAR start, - FX_WCHAR end, - CPDF_Array* pWidthArray) { - int size = end - start + 1; - int* widths = FX_Alloc(int, size); - int i; - for (i = 0; i < size; i++) { - int glyph_index = pEncoding->GlyphFromCharCode(start + i); - widths[i] = pFont->GetGlyphWidth(glyph_index); - } - InsertWidthArrayImpl(widths, size, pWidthArray); -} - -int InsertDeletePDFPage(CPDF_Document* pDoc, - CPDF_Dictionary* pPages, - int nPagesToGo, - CPDF_Dictionary* pPage, - FX_BOOL bInsert, - std::set* pVisited) { - CPDF_Array* pKidList = pPages->GetArrayFor("Kids"); - if (!pKidList) - return -1; - - for (size_t i = 0; i < pKidList->GetCount(); i++) { - CPDF_Dictionary* pKid = pKidList->GetDictAt(i); - if (pKid->GetStringFor("Type") == "Page") { - if (nPagesToGo == 0) { - if (bInsert) { - pKidList->InsertAt(i, new CPDF_Reference(pDoc, pPage->GetObjNum())); - pPage->SetReferenceFor("Parent", pDoc, pPages->GetObjNum()); - } else { - pKidList->RemoveAt(i); - } - pPages->SetIntegerFor( - "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1)); - return 1; - } - nPagesToGo--; - } else { - int nPages = pKid->GetIntegerFor("Count"); - if (nPagesToGo < nPages) { - if (pdfium::ContainsKey(*pVisited, pKid)) - return -1; - - pdfium::ScopedSetInsertion insertion(pVisited, pKid); - if (InsertDeletePDFPage(pDoc, pKid, nPagesToGo, pPage, bInsert, - pVisited) < 0) { - return -1; - } - pPages->SetIntegerFor( - "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1)); - return 1; - } - nPagesToGo -= nPages; - } - } - return 0; -} - -int InsertNewPage(CPDF_Document* pDoc, - int iPage, - CPDF_Dictionary* pPageDict, - CFX_ArrayTemplate& pageList) { - CPDF_Dictionary* pRoot = pDoc->GetRoot(); - CPDF_Dictionary* pPages = pRoot ? pRoot->GetDictFor("Pages") : nullptr; - if (!pPages) - return -1; - - int nPages = pDoc->GetPageCount(); - if (iPage < 0 || iPage > nPages) - return -1; - - if (iPage == nPages) { - CPDF_Array* pPagesList = pPages->GetArrayFor("Kids"); - if (!pPagesList) { - pPagesList = new CPDF_Array; - pPages->SetFor("Kids", pPagesList); - } - pPagesList->Add(new CPDF_Reference(pDoc, pPageDict->GetObjNum())); - pPages->SetIntegerFor("Count", nPages + 1); - pPageDict->SetReferenceFor("Parent", pDoc, pPages->GetObjNum()); - } else { - std::set stack = {pPages}; - if (InsertDeletePDFPage(pDoc, pPages, iPage, pPageDict, TRUE, &stack) < 0) - return -1; - } - pageList.InsertAt(iPage, pPageDict->GetObjNum()); - return iPage; -} - -int CountPages(CPDF_Dictionary* pPages, - std::set* visited_pages) { - int count = pPages->GetIntegerFor("Count"); - if (count > 0 && count < FPDF_PAGE_MAX_NUM) - return count; - CPDF_Array* pKidList = pPages->GetArrayFor("Kids"); - if (!pKidList) - return 0; - count = 0; - for (size_t i = 0; i < pKidList->GetCount(); i++) { - CPDF_Dictionary* pKid = pKidList->GetDictAt(i); - if (!pKid || pdfium::ContainsKey(*visited_pages, pKid)) - continue; - if (pKid->KeyExist("Kids")) { - // Use |visited_pages| to help detect circular references of pages. - pdfium::ScopedSetInsertion local_add(visited_pages, - pKid); - count += CountPages(pKid, visited_pages); - } else { - // This page is a leaf node. - count++; - } - } - pPages->SetIntegerFor("Count", count); - return count; -} - -int CalculateFlags(bool bold, - bool italic, - bool fixedPitch, - bool serif, - bool script, - bool symbolic) { - int flags = 0; - if (bold) - flags |= PDFFONT_FORCEBOLD; - if (italic) - flags |= PDFFONT_ITALIC; - if (fixedPitch) - flags |= PDFFONT_FIXEDPITCH; - if (serif) - flags |= PDFFONT_SERIF; - if (script) - flags |= PDFFONT_SCRIPT; - if (symbolic) - flags |= PDFFONT_SYMBOLIC; - else - flags |= PDFFONT_NONSYMBOLIC; - return flags; -} - -void ProcessNonbCJK(CPDF_Dictionary* pBaseDict, - bool bold, - bool italic, - CFX_ByteString basefont, - CPDF_Array* pWidths) { - if (bold && italic) - basefont += ",BoldItalic"; - else if (bold) - basefont += ",Bold"; - else if (italic) - basefont += ",Italic"; - pBaseDict->SetNameFor("Subtype", "TrueType"); - pBaseDict->SetNameFor("BaseFont", basefont); - pBaseDict->SetNumberFor("FirstChar", 32); - pBaseDict->SetNumberFor("LastChar", 255); - pBaseDict->SetFor("Widths", pWidths); -} - -CPDF_Dictionary* CalculateFontDesc(CPDF_Document* pDoc, - CFX_ByteString basefont, - int flags, - int italicangle, - int ascend, - int descend, - CPDF_Array* bbox, - int32_t stemV) { - CPDF_Dictionary* pFontDesc = new CPDF_Dictionary(pDoc->GetByteStringPool()); - pFontDesc->SetNameFor("Type", "FontDescriptor"); - pFontDesc->SetNameFor("FontName", basefont); - pFontDesc->SetIntegerFor("Flags", flags); - pFontDesc->SetFor("FontBBox", bbox); - pFontDesc->SetIntegerFor("ItalicAngle", italicangle); - pFontDesc->SetIntegerFor("Ascent", ascend); - pFontDesc->SetIntegerFor("Descent", descend); - pFontDesc->SetIntegerFor("StemV", stemV); - return pFontDesc; -} - -} // namespace - -CPDF_Document::CPDF_Document(std::unique_ptr pParser) - : CPDF_IndirectObjectHolder(), - m_pParser(std::move(pParser)), - m_pRootDict(nullptr), - m_pInfoDict(nullptr), - m_bLinearized(false), - m_iFirstPageNo(0), - m_dwFirstPageObjNum(0), - m_pDocPage(new CPDF_DocPageData(this)), - m_pDocRender(new CPDF_DocRenderData(this)), - m_pByteStringPool(pdfium::MakeUnique()) { - if (pParser) - SetLastObjNum(m_pParser->GetLastObjNum()); -} - -CPDF_Document::~CPDF_Document() { - delete m_pDocPage; - CPDF_ModuleMgr::Get()->GetPageModule()->ClearStockFont(this); - m_pByteStringPool.DeleteObject(); // Make weak. -} - -CPDF_Object* CPDF_Document::ParseIndirectObject(uint32_t objnum) { - return m_pParser ? m_pParser->ParseIndirectObject(this, objnum) : nullptr; -} - -void CPDF_Document::LoadDocInternal() { - SetLastObjNum(m_pParser->GetLastObjNum()); - - CPDF_Object* pRootObj = GetOrParseIndirectObject(m_pParser->GetRootObjNum()); - if (!pRootObj) - return; - - m_pRootDict = pRootObj->GetDict(); - if (!m_pRootDict) - return; - - CPDF_Object* pInfoObj = GetOrParseIndirectObject(m_pParser->GetInfoObjNum()); - if (pInfoObj) - m_pInfoDict = pInfoObj->GetDict(); -} - -void CPDF_Document::LoadDoc() { - LoadDocInternal(); - m_PageList.SetSize(RetrievePageCount()); -} - -void CPDF_Document::LoadLinearizedDoc(CPDF_Dictionary* pLinearizationParams) { - m_bLinearized = true; - LoadDocInternal(); - - uint32_t dwPageCount = 0; - CPDF_Object* pCount = pLinearizationParams->GetObjectFor("N"); - if (ToNumber(pCount)) - dwPageCount = pCount->GetInteger(); - m_PageList.SetSize(dwPageCount); - - CPDF_Object* pNo = pLinearizationParams->GetObjectFor("P"); - if (ToNumber(pNo)) - m_iFirstPageNo = pNo->GetInteger(); - - CPDF_Object* pObjNum = pLinearizationParams->GetObjectFor("O"); - if (ToNumber(pObjNum)) - m_dwFirstPageObjNum = pObjNum->GetInteger(); -} - -void CPDF_Document::LoadPages() { - m_PageList.SetSize(RetrievePageCount()); -} - -CPDF_Dictionary* CPDF_Document::FindPDFPage(CPDF_Dictionary* pPages, - int iPage, - int nPagesToGo, - int level) { - CPDF_Array* pKidList = pPages->GetArrayFor("Kids"); - if (!pKidList) - return nPagesToGo == 0 ? pPages : nullptr; - - if (level >= FX_MAX_PAGE_LEVEL) - return nullptr; - - for (size_t i = 0; i < pKidList->GetCount(); i++) { - CPDF_Dictionary* pKid = pKidList->GetDictAt(i); - if (!pKid) { - nPagesToGo--; - continue; - } - if (pKid == pPages) - continue; - if (!pKid->KeyExist("Kids")) { - if (nPagesToGo == 0) - return pKid; - - m_PageList.SetAt(iPage - nPagesToGo, pKid->GetObjNum()); - nPagesToGo--; - } else { - int nPages = pKid->GetIntegerFor("Count"); - if (nPagesToGo < nPages) - return FindPDFPage(pKid, iPage, nPagesToGo, level + 1); - - nPagesToGo -= nPages; - } - } - return nullptr; -} - -CPDF_Dictionary* CPDF_Document::GetPagesDict() const { - CPDF_Dictionary* pRoot = GetRoot(); - return pRoot ? pRoot->GetDictFor("Pages") : nullptr; -} - -bool CPDF_Document::IsPageLoaded(int iPage) const { - return !!m_PageList.GetAt(iPage); -} - -CPDF_Dictionary* CPDF_Document::GetPage(int iPage) { - if (iPage < 0 || iPage >= m_PageList.GetSize()) - return nullptr; - - if (m_bLinearized && (iPage == m_iFirstPageNo)) { - if (CPDF_Dictionary* pDict = - ToDictionary(GetOrParseIndirectObject(m_dwFirstPageObjNum))) { - return pDict; - } - } - - int objnum = m_PageList.GetAt(iPage); - if (objnum) { - if (CPDF_Dictionary* pDict = ToDictionary(GetOrParseIndirectObject(objnum))) - return pDict; - } - - CPDF_Dictionary* pPages = GetPagesDict(); - if (!pPages) - return nullptr; - - CPDF_Dictionary* pPage = FindPDFPage(pPages, iPage, iPage, 0); - if (!pPage) - return nullptr; - - m_PageList.SetAt(iPage, pPage->GetObjNum()); - return pPage; -} - -void CPDF_Document::SetPageObjNum(int iPage, uint32_t objNum) { - m_PageList.SetAt(iPage, objNum); -} - -int CPDF_Document::FindPageIndex(CPDF_Dictionary* pNode, - uint32_t& skip_count, - uint32_t objnum, - int& index, - int level) { - if (!pNode->KeyExist("Kids")) { - if (objnum == pNode->GetObjNum()) - return index; - - if (skip_count) - skip_count--; - - index++; - return -1; - } - - CPDF_Array* pKidList = pNode->GetArrayFor("Kids"); - if (!pKidList) - return -1; - - if (level >= FX_MAX_PAGE_LEVEL) - return -1; - - size_t count = pNode->GetIntegerFor("Count"); - if (count <= skip_count) { - skip_count -= count; - index += count; - return -1; - } - - if (count && count == pKidList->GetCount()) { - for (size_t i = 0; i < count; i++) { - if (CPDF_Reference* pKid = ToReference(pKidList->GetObjectAt(i))) { - if (pKid->GetRefObjNum() == objnum) { - m_PageList.SetAt(index + i, objnum); - return static_cast(index + i); - } - } - } - } - - for (size_t i = 0; i < pKidList->GetCount(); i++) { - CPDF_Dictionary* pKid = pKidList->GetDictAt(i); - if (!pKid || pKid == pNode) - continue; - - int found_index = FindPageIndex(pKid, skip_count, objnum, index, level + 1); - if (found_index >= 0) - return found_index; - } - return -1; -} - -int CPDF_Document::GetPageIndex(uint32_t objnum) { - uint32_t nPages = m_PageList.GetSize(); - uint32_t skip_count = 0; - bool bSkipped = false; - for (uint32_t i = 0; i < nPages; i++) { - uint32_t objnum1 = m_PageList.GetAt(i); - if (objnum1 == objnum) - return i; - - if (!bSkipped && objnum1 == 0) { - skip_count = i; - bSkipped = true; - } - } - CPDF_Dictionary* pPages = GetPagesDict(); - if (!pPages) - return -1; - - int index = 0; - return FindPageIndex(pPages, skip_count, objnum, index); -} - -int CPDF_Document::GetPageCount() const { - return m_PageList.GetSize(); -} - -int CPDF_Document::RetrievePageCount() const { - CPDF_Dictionary* pPages = GetPagesDict(); - if (!pPages) - return 0; - - if (!pPages->KeyExist("Kids")) - return 1; - - std::set visited_pages; - visited_pages.insert(pPages); - return CountPages(pPages, &visited_pages); -} - -uint32_t CPDF_Document::GetUserPermissions() const { - // https://bugs.chromium.org/p/pdfium/issues/detail?id=499 - if (!m_pParser) { -#ifndef PDF_ENABLE_XFA - return 0; -#else // PDF_ENABLE_XFA - return 0xFFFFFFFF; -#endif - } - return m_pParser->GetPermissions(); -} - -CPDF_Font* CPDF_Document::LoadFont(CPDF_Dictionary* pFontDict) { - ASSERT(pFontDict); - return m_pDocPage->GetFont(pFontDict, FALSE); -} - -CPDF_StreamAcc* CPDF_Document::LoadFontFile(CPDF_Stream* pStream) { - return m_pDocPage->GetFontFileStreamAcc(pStream); -} - -CPDF_ColorSpace* CPDF_Document::LoadColorSpace(CPDF_Object* pCSObj, - CPDF_Dictionary* pResources) { - return m_pDocPage->GetColorSpace(pCSObj, pResources); -} - -CPDF_Pattern* CPDF_Document::LoadPattern(CPDF_Object* pPatternObj, - FX_BOOL bShading, - const CFX_Matrix& matrix) { - return m_pDocPage->GetPattern(pPatternObj, bShading, matrix); -} - -CPDF_IccProfile* CPDF_Document::LoadIccProfile(CPDF_Stream* pStream) { - return m_pDocPage->GetIccProfile(pStream); -} - -CPDF_Image* CPDF_Document::LoadImageF(CPDF_Object* pObj) { - if (!pObj) - return nullptr; - - ASSERT(pObj->GetObjNum()); - return m_pDocPage->GetImage(pObj); -} - -void CPDF_Document::CreateNewDoc() { - ASSERT(!m_pRootDict && !m_pInfoDict); - m_pRootDict = new CPDF_Dictionary(m_pByteStringPool); - m_pRootDict->SetNameFor("Type", "Catalog"); - AddIndirectObject(m_pRootDict); - - CPDF_Dictionary* pPages = new CPDF_Dictionary(m_pByteStringPool); - pPages->SetNameFor("Type", "Pages"); - pPages->SetNumberFor("Count", 0); - pPages->SetFor("Kids", new CPDF_Array); - m_pRootDict->SetReferenceFor("Pages", this, AddIndirectObject(pPages)); - m_pInfoDict = new CPDF_Dictionary(m_pByteStringPool); - AddIndirectObject(m_pInfoDict); -} - -CPDF_Dictionary* CPDF_Document::CreateNewPage(int iPage) { - CPDF_Dictionary* pDict = new CPDF_Dictionary(m_pByteStringPool); - pDict->SetNameFor("Type", "Page"); - uint32_t dwObjNum = AddIndirectObject(pDict); - if (InsertNewPage(this, iPage, pDict, m_PageList) < 0) { - ReleaseIndirectObject(dwObjNum); - return nullptr; - } - return pDict; -} - -void CPDF_Document::DeletePage(int iPage) { - CPDF_Dictionary* pPages = GetPagesDict(); - if (!pPages) - return; - - int nPages = pPages->GetIntegerFor("Count"); - if (iPage < 0 || iPage >= nPages) - return; - - std::set stack = {pPages}; - if (InsertDeletePDFPage(this, pPages, iPage, nullptr, FALSE, &stack) < 0) - return; - - m_PageList.RemoveAt(iPage); -} - -CPDF_Font* CPDF_Document::AddStandardFont(const FX_CHAR* font, - CPDF_FontEncoding* pEncoding) { - CFX_ByteString name(font); - if (PDF_GetStandardFontName(&name) < 0) - return nullptr; - return GetPageData()->GetStandardFont(name, pEncoding); -} - -size_t CPDF_Document::CalculateEncodingDict(int charset, - CPDF_Dictionary* pBaseDict) { - size_t i; - for (i = 0; i < FX_ArraySize(g_FX_CharsetUnicodes); ++i) { - if (g_FX_CharsetUnicodes[i].m_Charset == charset) - break; - } - if (i == FX_ArraySize(g_FX_CharsetUnicodes)) - return i; - CPDF_Dictionary* pEncodingDict = new CPDF_Dictionary(m_pByteStringPool); - pEncodingDict->SetNameFor("BaseEncoding", "WinAnsiEncoding"); - CPDF_Array* pArray = new CPDF_Array; - pArray->AddInteger(128); - const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes; - for (int j = 0; j < 128; j++) { - CFX_ByteString name = PDF_AdobeNameFromUnicode(pUnicodes[j]); - pArray->AddName(name.IsEmpty() ? ".notdef" : name); - } - pEncodingDict->SetFor("Differences", pArray); - pBaseDict->SetReferenceFor("Encoding", this, - AddIndirectObject(pEncodingDict)); - - return i; -} - -CPDF_Dictionary* CPDF_Document::ProcessbCJK( - CPDF_Dictionary* pBaseDict, - int charset, - FX_BOOL bVert, - CFX_ByteString basefont, - std::function Insert) { - CPDF_Dictionary* pFontDict = new CPDF_Dictionary(m_pByteStringPool); - CFX_ByteString cmap; - CFX_ByteString ordering; - int supplement = 0; - CPDF_Array* pWidthArray = new CPDF_Array; - switch (charset) { - case FXFONT_CHINESEBIG5_CHARSET: - cmap = bVert ? "ETenms-B5-V" : "ETenms-B5-H"; - ordering = "CNS1"; - supplement = 4; - pWidthArray->AddInteger(1); - Insert(0x20, 0x7e, pWidthArray); - break; - case FXFONT_GB2312_CHARSET: - cmap = bVert ? "GBK-EUC-V" : "GBK-EUC-H"; - ordering = "GB1"; - supplement = 2; - pWidthArray->AddInteger(7716); - Insert(0x20, 0x20, pWidthArray); - pWidthArray->AddInteger(814); - Insert(0x21, 0x7e, pWidthArray); - break; - case FXFONT_HANGUL_CHARSET: - cmap = bVert ? "KSCms-UHC-V" : "KSCms-UHC-H"; - ordering = "Korea1"; - supplement = 2; - pWidthArray->AddInteger(1); - Insert(0x20, 0x7e, pWidthArray); - break; - case FXFONT_SHIFTJIS_CHARSET: - cmap = bVert ? "90ms-RKSJ-V" : "90ms-RKSJ-H"; - ordering = "Japan1"; - supplement = 5; - pWidthArray->AddInteger(231); - Insert(0x20, 0x7d, pWidthArray); - pWidthArray->AddInteger(326); - Insert(0xa0, 0xa0, pWidthArray); - pWidthArray->AddInteger(327); - Insert(0xa1, 0xdf, pWidthArray); - pWidthArray->AddInteger(631); - Insert(0x7e, 0x7e, pWidthArray); - break; - } - pBaseDict->SetNameFor("Subtype", "Type0"); - pBaseDict->SetNameFor("BaseFont", basefont); - pBaseDict->SetNameFor("Encoding", cmap); - pFontDict->SetFor("W", pWidthArray); - pFontDict->SetNameFor("Type", "Font"); - pFontDict->SetNameFor("Subtype", "CIDFontType2"); - pFontDict->SetNameFor("BaseFont", basefont); - CPDF_Dictionary* pCIDSysInfo = new CPDF_Dictionary(m_pByteStringPool); - pCIDSysInfo->SetStringFor("Registry", "Adobe"); - pCIDSysInfo->SetStringFor("Ordering", ordering); - pCIDSysInfo->SetIntegerFor("Supplement", supplement); - pFontDict->SetFor("CIDSystemInfo", pCIDSysInfo); - CPDF_Array* pArray = new CPDF_Array; - pBaseDict->SetFor("DescendantFonts", pArray); - pArray->AddReference(this, AddIndirectObject(pFontDict)); - return pFontDict; -} - -CPDF_Font* CPDF_Document::AddFont(CFX_Font* pFont, int charset, FX_BOOL bVert) { - if (!pFont) - return nullptr; - - bool bCJK = charset == FXFONT_CHINESEBIG5_CHARSET || - charset == FXFONT_GB2312_CHARSET || - charset == FXFONT_HANGUL_CHARSET || - charset == FXFONT_SHIFTJIS_CHARSET; - CFX_ByteString basefont = pFont->GetFamilyName(); - basefont.Replace(" ", ""); - int flags = - CalculateFlags(pFont->IsBold(), pFont->IsItalic(), pFont->IsFixedWidth(), - false, false, charset == FXFONT_SYMBOL_CHARSET); - - CPDF_Dictionary* pBaseDict = new CPDF_Dictionary(m_pByteStringPool); - pBaseDict->SetNameFor("Type", "Font"); - std::unique_ptr pEncoding( - new CFX_UnicodeEncoding(pFont)); - CPDF_Dictionary* pFontDict = pBaseDict; - if (!bCJK) { - CPDF_Array* pWidths = new CPDF_Array; - for (int charcode = 32; charcode < 128; charcode++) { - int glyph_index = pEncoding->GlyphFromCharCode(charcode); - int char_width = pFont->GetGlyphWidth(glyph_index); - pWidths->AddInteger(char_width); - } - if (charset == FXFONT_ANSI_CHARSET || charset == FXFONT_DEFAULT_CHARSET || - charset == FXFONT_SYMBOL_CHARSET) { - pBaseDict->SetNameFor("Encoding", "WinAnsiEncoding"); - for (int charcode = 128; charcode <= 255; charcode++) { - int glyph_index = pEncoding->GlyphFromCharCode(charcode); - int char_width = pFont->GetGlyphWidth(glyph_index); - pWidths->AddInteger(char_width); - } - } else { - size_t i = CalculateEncodingDict(charset, pBaseDict); - if (i < FX_ArraySize(g_FX_CharsetUnicodes)) { - const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes; - for (int j = 0; j < 128; j++) { - int glyph_index = pEncoding->GlyphFromCharCode(pUnicodes[j]); - int char_width = pFont->GetGlyphWidth(glyph_index); - pWidths->AddInteger(char_width); - } - } - } - ProcessNonbCJK(pBaseDict, pFont->IsBold(), pFont->IsItalic(), basefont, - pWidths); - } else { - pFontDict = ProcessbCJK(pBaseDict, charset, bVert, basefont, - [pFont, &pEncoding](FX_WCHAR start, FX_WCHAR end, - CPDF_Array* widthArr) { - InsertWidthArray1(pFont, pEncoding.get(), start, - end, widthArr); - }); - } - AddIndirectObject(pBaseDict); - int italicangle = - pFont->GetSubstFont() ? pFont->GetSubstFont()->m_ItalicAngle : 0; - FX_RECT bbox; - pFont->GetBBox(bbox); - CPDF_Array* pBBox = new CPDF_Array; - pBBox->AddInteger(bbox.left); - pBBox->AddInteger(bbox.bottom); - pBBox->AddInteger(bbox.right); - pBBox->AddInteger(bbox.top); - int32_t nStemV = 0; - if (pFont->GetSubstFont()) { - nStemV = pFont->GetSubstFont()->m_Weight / 5; - } else { - static const FX_CHAR stem_chars[] = {'i', 'I', '!', '1'}; - const size_t count = FX_ArraySize(stem_chars); - uint32_t glyph = pEncoding->GlyphFromCharCode(stem_chars[0]); - nStemV = pFont->GetGlyphWidth(glyph); - for (size_t i = 1; i < count; i++) { - glyph = pEncoding->GlyphFromCharCode(stem_chars[i]); - int width = pFont->GetGlyphWidth(glyph); - if (width > 0 && width < nStemV) - nStemV = width; - } - } - CPDF_Dictionary* pFontDesc = - CalculateFontDesc(this, basefont, flags, italicangle, pFont->GetAscent(), - pFont->GetDescent(), pBBox, nStemV); - pFontDict->SetReferenceFor("FontDescriptor", this, - AddIndirectObject(pFontDesc)); - return LoadFont(pBaseDict); -} - -#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ -CPDF_Font* CPDF_Document::AddWindowsFont(LOGFONTW* pLogFont, - FX_BOOL bVert, - FX_BOOL bTranslateName) { - LOGFONTA lfa; - FXSYS_memcpy(&lfa, pLogFont, (char*)lfa.lfFaceName - (char*)&lfa); - CFX_ByteString face = CFX_ByteString::FromUnicode(pLogFont->lfFaceName); - if (face.GetLength() >= LF_FACESIZE) - return nullptr; - - FXSYS_strcpy(lfa.lfFaceName, face.c_str()); - return AddWindowsFont(&lfa, bVert, bTranslateName); -} - -CPDF_Font* CPDF_Document::AddWindowsFont(LOGFONTA* pLogFont, - FX_BOOL bVert, - FX_BOOL bTranslateName) { - pLogFont->lfHeight = -1000; - pLogFont->lfWidth = 0; - HGDIOBJ hFont = CreateFontIndirectA(pLogFont); - HDC hDC = CreateCompatibleDC(nullptr); - hFont = SelectObject(hDC, hFont); - int tm_size = GetOutlineTextMetrics(hDC, 0, nullptr); - if (tm_size == 0) { - hFont = SelectObject(hDC, hFont); - DeleteObject(hFont); - DeleteDC(hDC); - return nullptr; - } - - LPBYTE tm_buf = FX_Alloc(BYTE, tm_size); - OUTLINETEXTMETRIC* ptm = reinterpret_cast(tm_buf); - GetOutlineTextMetrics(hDC, tm_size, ptm); - int flags = CalculateFlags(false, pLogFont->lfItalic != 0, - (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH, - (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN, - (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT, - pLogFont->lfCharSet == FXFONT_SYMBOL_CHARSET); - - bool bCJK = pLogFont->lfCharSet == FXFONT_CHINESEBIG5_CHARSET || - pLogFont->lfCharSet == FXFONT_GB2312_CHARSET || - pLogFont->lfCharSet == FXFONT_HANGUL_CHARSET || - pLogFont->lfCharSet == FXFONT_SHIFTJIS_CHARSET; - CFX_ByteString basefont; - if (bTranslateName && bCJK) - basefont = FPDF_GetPSNameFromTT(hDC); - - if (basefont.IsEmpty()) - basefont = pLogFont->lfFaceName; - - int italicangle = ptm->otmItalicAngle / 10; - int ascend = ptm->otmrcFontBox.top; - int descend = ptm->otmrcFontBox.bottom; - int capheight = ptm->otmsCapEmHeight; - int bbox[4] = {ptm->otmrcFontBox.left, ptm->otmrcFontBox.bottom, - ptm->otmrcFontBox.right, ptm->otmrcFontBox.top}; - FX_Free(tm_buf); - basefont.Replace(" ", ""); - CPDF_Dictionary* pBaseDict = new CPDF_Dictionary(m_pByteStringPool); - pBaseDict->SetNameFor("Type", "Font"); - CPDF_Dictionary* pFontDict = pBaseDict; - if (!bCJK) { - if (pLogFont->lfCharSet == FXFONT_ANSI_CHARSET || - pLogFont->lfCharSet == FXFONT_DEFAULT_CHARSET || - pLogFont->lfCharSet == FXFONT_SYMBOL_CHARSET) { - pBaseDict->SetNameFor("Encoding", "WinAnsiEncoding"); - } else { - CalculateEncodingDict(pLogFont->lfCharSet, pBaseDict); - } - int char_widths[224]; - GetCharWidth(hDC, 32, 255, char_widths); - CPDF_Array* pWidths = new CPDF_Array; - for (size_t i = 0; i < 224; i++) - pWidths->AddInteger(char_widths[i]); - ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM, - pLogFont->lfItalic != 0, basefont, pWidths); - } else { - pFontDict = - ProcessbCJK(pBaseDict, pLogFont->lfCharSet, bVert, basefont, - [&hDC](FX_WCHAR start, FX_WCHAR end, CPDF_Array* widthArr) { - InsertWidthArray(hDC, start, end, widthArr); - }); - } - AddIndirectObject(pBaseDict); - CPDF_Array* pBBox = new CPDF_Array; - for (int i = 0; i < 4; i++) - pBBox->AddInteger(bbox[i]); - CPDF_Dictionary* pFontDesc = - CalculateFontDesc(this, basefont, flags, italicangle, ascend, descend, - pBBox, pLogFont->lfWeight / 5); - pFontDesc->SetIntegerFor("CapHeight", capheight); - pFontDict->SetReferenceFor("FontDescriptor", this, - AddIndirectObject(pFontDesc)); - hFont = SelectObject(hDC, hFont); - DeleteObject(hFont); - DeleteDC(hDC); - return LoadFont(pBaseDict); -} -#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_document.h b/core/fpdfapi/fpdf_parser/cpdf_document.h deleted file mode 100644 index 9ae43f7e03..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_document.h +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_DOCUMENT_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_DOCUMENT_H_ - -#include -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h" -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fpdfdoc/cpdf_linklist.h" -#include "core/fxcrt/cfx_string_pool_template.h" -#include "core/fxcrt/cfx_weak_ptr.h" -#include "core/fxcrt/fx_basic.h" - -class CFX_Font; -class CFX_Matrix; -class CPDF_ColorSpace; -class CPDF_DocPageData; -class CPDF_DocRenderData; -class CPDF_Font; -class CPDF_FontEncoding; -class CPDF_IccProfile; -class CPDF_Image; -class CPDF_Parser; -class CPDF_Pattern; -class CPDF_StreamAcc; -class JBig2_DocumentContext; - -#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 CPDF_Document : public CPDF_IndirectObjectHolder { - public: - explicit CPDF_Document(std::unique_ptr pParser); - ~CPDF_Document() override; - - CPDF_Parser* GetParser() const { return m_pParser.get(); } - CPDF_Dictionary* GetRoot() const { return m_pRootDict; } - CPDF_Dictionary* GetInfo() const { return m_pInfoDict; } - CFX_WeakPtr GetByteStringPool() const { - return m_pByteStringPool; - } - - void DeletePage(int iPage); - int GetPageCount() const; - - bool IsPageLoaded(int iPage) const; - CPDF_Dictionary* GetPage(int iPage); - int GetPageIndex(uint32_t objnum); - uint32_t GetUserPermissions() const; - CPDF_DocPageData* GetPageData() const { return m_pDocPage; } - - void SetPageObjNum(int iPage, uint32_t objNum); - - std::unique_ptr* CodecContext() { - return &m_pCodecContext; - } - std::unique_ptr* LinksContext() { return &m_pLinksContext; } - - CPDF_DocRenderData* GetRenderData() const { return m_pDocRender.get(); } - - // |pFontDict| must not be null. - CPDF_Font* LoadFont(CPDF_Dictionary* pFontDict); - CPDF_ColorSpace* LoadColorSpace(CPDF_Object* pCSObj, - CPDF_Dictionary* pResources = nullptr); - - CPDF_Pattern* LoadPattern(CPDF_Object* pObj, - FX_BOOL bShading, - const CFX_Matrix& matrix); - - CPDF_Image* LoadImageF(CPDF_Object* pObj); - CPDF_StreamAcc* LoadFontFile(CPDF_Stream* pStream); - CPDF_IccProfile* LoadIccProfile(CPDF_Stream* pStream); - - void LoadDoc(); - void LoadLinearizedDoc(CPDF_Dictionary* pLinearizationParams); - void LoadPages(); - - void CreateNewDoc(); - CPDF_Dictionary* CreateNewPage(int iPage); - - CPDF_Font* AddStandardFont(const FX_CHAR* font, CPDF_FontEncoding* pEncoding); - CPDF_Font* AddFont(CFX_Font* pFont, int charset, FX_BOOL bVert); -#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 - - private: - friend class CPDF_TestDocument; - - // Retrieve page count information by getting count value from the tree nodes - int RetrievePageCount() const; - CPDF_Dictionary* FindPDFPage(CPDF_Dictionary* pPages, - int iPage, - int nPagesToGo, - int level); - int FindPageIndex(CPDF_Dictionary* pNode, - uint32_t& skip_count, - uint32_t objnum, - int& index, - int level = 0); - CPDF_Object* ParseIndirectObject(uint32_t objnum) override; - void LoadDocInternal(); - size_t CalculateEncodingDict(int charset, CPDF_Dictionary* pBaseDict); - CPDF_Dictionary* GetPagesDict() const; - CPDF_Dictionary* ProcessbCJK( - CPDF_Dictionary* pBaseDict, - int charset, - FX_BOOL bVert, - CFX_ByteString basefont, - std::function Insert); - - std::unique_ptr m_pParser; - CPDF_Dictionary* m_pRootDict; - CPDF_Dictionary* m_pInfoDict; - bool m_bLinearized; - int m_iFirstPageNo; - uint32_t m_dwFirstPageObjNum; - // TODO(thestig): Figure out why this cannot be a std::unique_ptr. - CPDF_DocPageData* m_pDocPage; - std::unique_ptr m_pDocRender; - std::unique_ptr m_pCodecContext; - std::unique_ptr m_pLinksContext; - CFX_ArrayTemplate m_PageList; - CFX_WeakPtr m_pByteStringPool; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_DOCUMENT_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_hint_tables.cpp b/core/fpdfapi/fpdf_parser/cpdf_hint_tables.cpp deleted file mode 100644 index ae602b252d..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_hint_tables.cpp +++ /dev/null @@ -1,524 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_hint_tables.h" - -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_data_avail.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/numerics/safe_conversions.h" - -namespace { - -bool CanReadFromBitStream(const CFX_BitStream* hStream, - const FX_SAFE_UINT32& bits) { - return bits.IsValid() && hStream->BitsRemaining() >= bits.ValueOrDie(); -} - -// Sanity check values from the page table header. The note in the PDF 1.7 -// reference for Table F.3 says the valid range is only 0 through 32. Though 0 -// is not useful either. -bool IsValidPageOffsetHintTableBitCount(uint32_t bits) { - return bits > 0 && bits <= 32; -} - -} // namespace - -CPDF_HintTables::CPDF_HintTables(CPDF_DataAvail* pDataAvail, - CPDF_Dictionary* pLinearized) - : m_pDataAvail(pDataAvail), - m_pLinearizedDict(pLinearized), - m_nFirstPageSharedObjs(0), - m_szFirstPageObjOffset(0) { - ASSERT(m_pLinearizedDict); -} - -CPDF_HintTables::~CPDF_HintTables() {} - -uint32_t CPDF_HintTables::GetItemLength( - uint32_t index, - const std::vector& szArray) { - if (szArray.size() < 2 || index > szArray.size() - 2 || - szArray[index] > szArray[index + 1]) { - return 0; - } - return szArray[index + 1] - szArray[index]; -} - -bool CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { - if (!hStream || hStream->IsEOF()) - return false; - - int nStreamOffset = ReadPrimaryHintStreamOffset(); - if (nStreamOffset < 0) - return false; - - int nStreamLen = ReadPrimaryHintStreamLength(); - if (nStreamLen < 1 || - !pdfium::base::IsValueInRangeForNumericType(nStreamLen)) { - return false; - } - - const uint32_t kHeaderSize = 288; - if (hStream->BitsRemaining() < kHeaderSize) - return false; - - // Item 1: The least number of objects in a page. - const uint32_t dwObjLeastNum = hStream->GetBits(32); - if (!dwObjLeastNum) - return false; - - // Item 2: The location of the first page's page object. - const uint32_t dwFirstObjLoc = hStream->GetBits(32); - if (dwFirstObjLoc > static_cast(nStreamOffset)) { - FX_SAFE_FILESIZE safeLoc = nStreamLen; - safeLoc += dwFirstObjLoc; - if (!safeLoc.IsValid()) - return false; - m_szFirstPageObjOffset = safeLoc.ValueOrDie(); - } else { - if (!pdfium::base::IsValueInRangeForNumericType(dwFirstObjLoc)) - return false; - m_szFirstPageObjOffset = dwFirstObjLoc; - } - - // Item 3: The number of bits needed to represent the difference - // between the greatest and least number of objects in a page. - const uint32_t dwDeltaObjectsBits = hStream->GetBits(16); - if (!IsValidPageOffsetHintTableBitCount(dwDeltaObjectsBits)) - return false; - - // Item 4: The least length of a page in bytes. - const uint32_t dwPageLeastLen = hStream->GetBits(32); - if (!dwPageLeastLen) - return false; - - // Item 5: The number of bits needed to represent the difference - // between the greatest and least length of a page, in bytes. - const uint32_t dwDeltaPageLenBits = hStream->GetBits(16); - if (!IsValidPageOffsetHintTableBitCount(dwDeltaPageLenBits)) - return false; - - // Skip Item 6, 7, 8, 9 total 96 bits. - hStream->SkipBits(96); - - // Item 10: The number of bits needed to represent the greatest - // number of shared object references. - const uint32_t dwSharedObjBits = hStream->GetBits(16); - if (!IsValidPageOffsetHintTableBitCount(dwSharedObjBits)) - return false; - - // Item 11: The number of bits needed to represent the numerically - // greatest shared object identifier used by the pages. - const uint32_t dwSharedIdBits = hStream->GetBits(16); - if (!IsValidPageOffsetHintTableBitCount(dwSharedIdBits)) - return false; - - // Item 12: The number of bits needed to represent the numerator of - // the fractional position for each shared object reference. For each - // shared object referenced from a page, there is an indication of - // where in the page's content stream the object is first referenced. - const uint32_t dwSharedNumeratorBits = hStream->GetBits(16); - if (!IsValidPageOffsetHintTableBitCount(dwSharedNumeratorBits)) - return false; - - // Item 13: Skip Item 13 which has 16 bits. - hStream->SkipBits(16); - - const int nPages = GetNumberOfPages(); - if (nPages < 1 || nPages >= FPDF_PAGE_MAX_NUM) - return false; - - const uint32_t dwPages = pdfium::base::checked_cast(nPages); - FX_SAFE_UINT32 required_bits = dwDeltaObjectsBits; - required_bits *= dwPages; - if (!CanReadFromBitStream(hStream, required_bits)) - return false; - - for (int i = 0; i < nPages; ++i) { - FX_SAFE_UINT32 safeDeltaObj = hStream->GetBits(dwDeltaObjectsBits); - safeDeltaObj += dwObjLeastNum; - if (!safeDeltaObj.IsValid()) - return false; - m_dwDeltaNObjsArray.push_back(safeDeltaObj.ValueOrDie()); - } - hStream->ByteAlign(); - - required_bits = dwDeltaPageLenBits; - required_bits *= dwPages; - if (!CanReadFromBitStream(hStream, required_bits)) - return false; - - std::vector dwPageLenArray; - for (int i = 0; i < nPages; ++i) { - FX_SAFE_UINT32 safePageLen = hStream->GetBits(dwDeltaPageLenBits); - safePageLen += dwPageLeastLen; - if (!safePageLen.IsValid()) - return false; - - dwPageLenArray.push_back(safePageLen.ValueOrDie()); - } - - int nOffsetE = GetEndOfFirstPageOffset(); - if (nOffsetE < 0) - return false; - - int nFirstPageNum = GetFirstPageNumber(); - if (nFirstPageNum < 0 || nFirstPageNum > std::numeric_limits::max() - 1) - return false; - - for (int i = 0; i < nPages; ++i) { - if (i == nFirstPageNum) { - m_szPageOffsetArray.push_back(m_szFirstPageObjOffset); - } else if (i == nFirstPageNum + 1) { - if (i == 1) { - m_szPageOffsetArray.push_back(nOffsetE); - } else { - m_szPageOffsetArray.push_back(m_szPageOffsetArray[i - 2] + - dwPageLenArray[i - 2]); - } - } else { - if (i == 0) { - m_szPageOffsetArray.push_back(nOffsetE); - } else { - m_szPageOffsetArray.push_back(m_szPageOffsetArray[i - 1] + - dwPageLenArray[i - 1]); - } - } - } - - m_szPageOffsetArray.push_back(m_szPageOffsetArray[nPages - 1] + - dwPageLenArray[nPages - 1]); - hStream->ByteAlign(); - - // Number of shared objects. - required_bits = dwSharedObjBits; - required_bits *= dwPages; - if (!CanReadFromBitStream(hStream, required_bits)) - return false; - - for (int i = 0; i < nPages; i++) - m_dwNSharedObjsArray.push_back(hStream->GetBits(dwSharedObjBits)); - hStream->ByteAlign(); - - // Array of identifiers, size = nshared_objects. - for (int i = 0; i < nPages; i++) { - required_bits = dwSharedIdBits; - required_bits *= m_dwNSharedObjsArray[i]; - if (!CanReadFromBitStream(hStream, required_bits)) - return false; - - for (uint32_t j = 0; j < m_dwNSharedObjsArray[i]; j++) - m_dwIdentifierArray.push_back(hStream->GetBits(dwSharedIdBits)); - } - hStream->ByteAlign(); - - for (int i = 0; i < nPages; i++) { - FX_SAFE_UINT32 safeSize = m_dwNSharedObjsArray[i]; - safeSize *= dwSharedNumeratorBits; - if (!CanReadFromBitStream(hStream, safeSize)) - return false; - - hStream->SkipBits(safeSize.ValueOrDie()); - } - hStream->ByteAlign(); - - FX_SAFE_UINT32 safeTotalPageLen = dwPages; - safeTotalPageLen *= dwDeltaPageLenBits; - if (!CanReadFromBitStream(hStream, safeTotalPageLen)) - return false; - - hStream->SkipBits(safeTotalPageLen.ValueOrDie()); - hStream->ByteAlign(); - return true; -} - -bool CPDF_HintTables::ReadSharedObjHintTable(CFX_BitStream* hStream, - uint32_t offset) { - if (!hStream || hStream->IsEOF()) - return false; - - int nStreamOffset = ReadPrimaryHintStreamOffset(); - int nStreamLen = ReadPrimaryHintStreamLength(); - if (nStreamOffset < 0 || nStreamLen < 1) - return false; - - FX_SAFE_UINT32 bit_offset = offset; - bit_offset *= 8; - if (!bit_offset.IsValid() || hStream->GetPos() > bit_offset.ValueOrDie()) - return false; - hStream->SkipBits(bit_offset.ValueOrDie() - hStream->GetPos()); - - const uint32_t kHeaderSize = 192; - if (hStream->BitsRemaining() < kHeaderSize) - return false; - - // Item 1: The object number of the first object in the shared objects - // section. - uint32_t dwFirstSharedObjNum = hStream->GetBits(32); - - // Item 2: The location of the first object in the shared objects section. - uint32_t dwFirstSharedObjLoc = hStream->GetBits(32); - if (dwFirstSharedObjLoc > static_cast(nStreamOffset)) - dwFirstSharedObjLoc += nStreamLen; - - // Item 3: The number of shared object entries for the first page. - m_nFirstPageSharedObjs = hStream->GetBits(32); - - // Item 4: The number of shared object entries for the shared objects - // section, including the number of shared object entries for the first page. - uint32_t dwSharedObjTotal = hStream->GetBits(32); - - // Item 5: The number of bits needed to represent the greatest number of - // objects in a shared object group. Skipped. - hStream->SkipBits(16); - - // Item 6: The least length of a shared object group in bytes. - uint32_t dwGroupLeastLen = hStream->GetBits(32); - - // Item 7: The number of bits needed to represent the difference between the - // greatest and least length of a shared object group, in bytes. - uint32_t dwDeltaGroupLen = hStream->GetBits(16); - - if (dwFirstSharedObjNum >= CPDF_Parser::kMaxObjectNumber || - m_nFirstPageSharedObjs >= CPDF_Parser::kMaxObjectNumber || - dwSharedObjTotal >= CPDF_Parser::kMaxObjectNumber) { - return false; - } - - int nFirstPageObjNum = GetFirstPageObjectNumber(); - if (nFirstPageObjNum < 0) - return false; - - uint32_t dwPrevObjLen = 0; - uint32_t dwCurObjLen = 0; - FX_SAFE_UINT32 required_bits = dwSharedObjTotal; - required_bits *= dwDeltaGroupLen; - if (!CanReadFromBitStream(hStream, required_bits)) - return false; - - for (uint32_t i = 0; i < dwSharedObjTotal; ++i) { - dwPrevObjLen = dwCurObjLen; - FX_SAFE_UINT32 safeObjLen = hStream->GetBits(dwDeltaGroupLen); - safeObjLen += dwGroupLeastLen; - if (!safeObjLen.IsValid()) - return false; - - dwCurObjLen = safeObjLen.ValueOrDie(); - if (i < m_nFirstPageSharedObjs) { - m_dwSharedObjNumArray.push_back(nFirstPageObjNum + i); - if (i == 0) - m_szSharedObjOffsetArray.push_back(m_szFirstPageObjOffset); - } else { - FX_SAFE_UINT32 safeObjNum = dwFirstSharedObjNum; - safeObjNum += i - m_nFirstPageSharedObjs; - if (!safeObjNum.IsValid()) - return false; - - m_dwSharedObjNumArray.push_back(safeObjNum.ValueOrDie()); - if (i == m_nFirstPageSharedObjs) { - FX_SAFE_FILESIZE safeLoc = dwFirstSharedObjLoc; - if (!safeLoc.IsValid()) - return false; - - m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); - } - } - - if (i != 0 && i != m_nFirstPageSharedObjs) { - FX_SAFE_FILESIZE safeLoc = dwPrevObjLen; - safeLoc += m_szSharedObjOffsetArray[i - 1]; - if (!safeLoc.IsValid()) - return false; - - m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); - } - } - - if (dwSharedObjTotal > 0) { - FX_SAFE_FILESIZE safeLoc = dwCurObjLen; - safeLoc += m_szSharedObjOffsetArray[dwSharedObjTotal - 1]; - if (!safeLoc.IsValid()) - return false; - - m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); - } - - hStream->ByteAlign(); - if (hStream->BitsRemaining() < dwSharedObjTotal) - return false; - - hStream->SkipBits(dwSharedObjTotal); - hStream->ByteAlign(); - return true; -} - -bool CPDF_HintTables::GetPagePos(uint32_t index, - FX_FILESIZE* szPageStartPos, - FX_FILESIZE* szPageLength, - uint32_t* dwObjNum) { - *szPageStartPos = m_szPageOffsetArray[index]; - *szPageLength = GetItemLength(index, m_szPageOffsetArray); - - int nFirstPageObjNum = GetFirstPageObjectNumber(); - if (nFirstPageObjNum < 0) - return false; - - int nFirstPageNum = GetFirstPageNumber(); - if (!pdfium::base::IsValueInRangeForNumericType(nFirstPageNum)) - return false; - - uint32_t dwFirstPageNum = static_cast(nFirstPageNum); - if (index == dwFirstPageNum) { - *dwObjNum = nFirstPageObjNum; - return true; - } - - // The object number of remaining pages starts from 1. - *dwObjNum = 1; - for (uint32_t i = 0; i < index; ++i) { - if (i == dwFirstPageNum) - continue; - *dwObjNum += m_dwDeltaNObjsArray[i]; - } - return true; -} - -CPDF_DataAvail::DocAvailStatus CPDF_HintTables::CheckPage( - uint32_t index, - CPDF_DataAvail::DownloadHints* pHints) { - if (!pHints) - return CPDF_DataAvail::DataError; - - int nFirstPageNum = GetFirstPageNumber(); - if (!pdfium::base::IsValueInRangeForNumericType(nFirstPageNum)) - return CPDF_DataAvail::DataError; - - if (index == static_cast(nFirstPageNum)) - return CPDF_DataAvail::DataAvailable; - - uint32_t dwLength = GetItemLength(index, m_szPageOffsetArray); - // If two pages have the same offset, it should be treated as an error. - if (!dwLength) - return CPDF_DataAvail::DataError; - - if (!m_pDataAvail->IsDataAvail(m_szPageOffsetArray[index], dwLength, pHints)) - return CPDF_DataAvail::DataNotAvailable; - - // Download data of shared objects in the page. - uint32_t offset = 0; - for (uint32_t i = 0; i < index; ++i) - offset += m_dwNSharedObjsArray[i]; - - int nFirstPageObjNum = GetFirstPageObjectNumber(); - if (nFirstPageObjNum < 0) - return CPDF_DataAvail::DataError; - - uint32_t dwIndex = 0; - uint32_t dwObjNum = 0; - for (uint32_t j = 0; j < m_dwNSharedObjsArray[index]; ++j) { - dwIndex = m_dwIdentifierArray[offset + j]; - if (dwIndex >= m_dwSharedObjNumArray.size()) - return CPDF_DataAvail::DataNotAvailable; - - dwObjNum = m_dwSharedObjNumArray[dwIndex]; - if (dwObjNum >= static_cast(nFirstPageObjNum) && - dwObjNum < - static_cast(nFirstPageObjNum) + m_nFirstPageSharedObjs) { - continue; - } - - dwLength = GetItemLength(dwIndex, m_szSharedObjOffsetArray); - // If two objects have the same offset, it should be treated as an error. - if (!dwLength) - return CPDF_DataAvail::DataError; - - if (!m_pDataAvail->IsDataAvail(m_szSharedObjOffsetArray[dwIndex], dwLength, - pHints)) { - return CPDF_DataAvail::DataNotAvailable; - } - } - return CPDF_DataAvail::DataAvailable; -} - -bool CPDF_HintTables::LoadHintStream(CPDF_Stream* pHintStream) { - if (!pHintStream) - return false; - - CPDF_Dictionary* pDict = pHintStream->GetDict(); - CPDF_Object* pOffset = pDict ? pDict->GetObjectFor("S") : nullptr; - if (!pOffset || !pOffset->IsNumber()) - return false; - - int shared_hint_table_offset = pOffset->GetInteger(); - if (shared_hint_table_offset <= 0) - return false; - - CPDF_StreamAcc acc; - acc.LoadAllData(pHintStream); - - uint32_t size = acc.GetSize(); - // The header section of page offset hint table is 36 bytes. - // The header section of shared object hint table is 24 bytes. - // Hint table has at least 60 bytes. - const uint32_t kMinStreamLength = 60; - if (size < kMinStreamLength) - return false; - - FX_SAFE_UINT32 safe_shared_hint_table_offset = shared_hint_table_offset; - if (!safe_shared_hint_table_offset.IsValid() || - size < safe_shared_hint_table_offset.ValueOrDie()) { - return false; - } - - CFX_BitStream bs; - bs.Init(acc.GetData(), size); - return ReadPageHintTable(&bs) && - ReadSharedObjHintTable(&bs, shared_hint_table_offset); -} - -int CPDF_HintTables::GetEndOfFirstPageOffset() const { - CPDF_Object* pOffsetE = m_pLinearizedDict->GetDirectObjectFor("E"); - return pOffsetE ? pOffsetE->GetInteger() : -1; -} - -int CPDF_HintTables::GetNumberOfPages() const { - CPDF_Object* pPageNum = m_pLinearizedDict->GetDirectObjectFor("N"); - return pPageNum ? pPageNum->GetInteger() : 0; -} - -int CPDF_HintTables::GetFirstPageObjectNumber() const { - CPDF_Object* pFirstPageObj = m_pLinearizedDict->GetDirectObjectFor("O"); - return pFirstPageObj ? pFirstPageObj->GetInteger() : -1; -} - -int CPDF_HintTables::GetFirstPageNumber() const { - CPDF_Object* pFirstPageNum = m_pLinearizedDict->GetDirectObjectFor("P"); - return pFirstPageNum ? pFirstPageNum->GetInteger() : 0; -} - -int CPDF_HintTables::ReadPrimaryHintStreamOffset() const { - return ReadPrimaryHintStream(0); -} - -int CPDF_HintTables::ReadPrimaryHintStreamLength() const { - return ReadPrimaryHintStream(1); -} - -int CPDF_HintTables::ReadPrimaryHintStream(int index) const { - CPDF_Array* pRange = m_pLinearizedDict->GetArrayFor("H"); - if (!pRange) - return -1; - - CPDF_Object* pStreamLen = pRange->GetDirectObjectAt(index); - return pStreamLen ? pStreamLen->GetInteger() : -1; -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_hint_tables.h b/core/fpdfapi/fpdf_parser/cpdf_hint_tables.h deleted file mode 100644 index 797cb24f50..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_hint_tables.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_HINT_TABLES_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_HINT_TABLES_H_ - -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_data_avail.h" -#include "core/fxcrt/fx_basic.h" -#include "core/fxcrt/fx_stream.h" - -class CFX_BitStream; -class CPDF_Dictionary; -class CPDF_Stream; - -class CPDF_HintTables { - public: - CPDF_HintTables(CPDF_DataAvail* pDataAvail, CPDF_Dictionary* pLinearized); - virtual ~CPDF_HintTables(); - - bool GetPagePos(uint32_t index, - FX_FILESIZE* szPageStartPos, - FX_FILESIZE* szPageLength, - uint32_t* dwObjNum); - - CPDF_DataAvail::DocAvailStatus CheckPage( - uint32_t index, - CPDF_DataAvail::DownloadHints* pHints); - - bool LoadHintStream(CPDF_Stream* pHintStream); - - protected: - bool ReadPageHintTable(CFX_BitStream* hStream); - bool ReadSharedObjHintTable(CFX_BitStream* hStream, uint32_t offset); - - private: - // Tests can override. - virtual int GetEndOfFirstPageOffset() const; - virtual int GetNumberOfPages() const; - virtual int GetFirstPageObjectNumber() const; - virtual int GetFirstPageNumber() const; - virtual int ReadPrimaryHintStreamOffset() const; - virtual int ReadPrimaryHintStreamLength() const; - - // Helper for the ReadPrimaryHintStream methods above. - int ReadPrimaryHintStream(int index) const; - - uint32_t GetItemLength(uint32_t index, - const std::vector& szArray); - - // Owner, outlives this object. - CPDF_DataAvail* const m_pDataAvail; - - // Owned by |m_pDataAvail|. - CPDF_Dictionary* const m_pLinearizedDict; - - uint32_t m_nFirstPageSharedObjs; - FX_FILESIZE m_szFirstPageObjOffset; - std::vector m_dwDeltaNObjsArray; - std::vector m_dwNSharedObjsArray; - std::vector m_dwSharedObjNumArray; - std::vector m_dwIdentifierArray; - std::vector m_szPageOffsetArray; - std::vector m_szSharedObjOffsetArray; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_HINT_TABLES_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.cpp b/core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.cpp deleted file mode 100644 index 30d022a36a..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h" - -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" - -CPDF_IndirectObjectHolder::CPDF_IndirectObjectHolder() : m_LastObjNum(0) {} - -CPDF_IndirectObjectHolder::~CPDF_IndirectObjectHolder() {} - -CPDF_Object* CPDF_IndirectObjectHolder::GetIndirectObject( - uint32_t objnum) const { - auto it = m_IndirectObjs.find(objnum); - return it != m_IndirectObjs.end() ? it->second.get() : nullptr; -} - -CPDF_Object* CPDF_IndirectObjectHolder::GetOrParseIndirectObject( - uint32_t objnum) { - if (objnum == 0) - return nullptr; - - CPDF_Object* pObj = GetIndirectObject(objnum); - if (pObj) - return pObj->GetObjNum() != CPDF_Object::kInvalidObjNum ? pObj : nullptr; - - pObj = ParseIndirectObject(objnum); - if (!pObj) - return nullptr; - - pObj->m_ObjNum = objnum; - m_LastObjNum = std::max(m_LastObjNum, objnum); - m_IndirectObjs[objnum].reset(pObj); - return pObj; -} - -CPDF_Object* CPDF_IndirectObjectHolder::ParseIndirectObject(uint32_t objnum) { - return nullptr; -} - -uint32_t CPDF_IndirectObjectHolder::AddIndirectObject(CPDF_Object* pObj) { - if (pObj->m_ObjNum) - return pObj->m_ObjNum; - - m_LastObjNum++; - m_IndirectObjs[m_LastObjNum].release(); // TODO(tsepez): stop this leak. - m_IndirectObjs[m_LastObjNum].reset(pObj); - pObj->m_ObjNum = m_LastObjNum; - return m_LastObjNum; -} - -bool CPDF_IndirectObjectHolder::ReplaceIndirectObjectIfHigherGeneration( - uint32_t objnum, - CPDF_Object* pObj) { - if (!objnum || !pObj) - return false; - - CPDF_Object* pOldObj = GetIndirectObject(objnum); - if (pOldObj && pObj->GetGenNum() <= pOldObj->GetGenNum()) { - delete pObj; - return false; - } - pObj->m_ObjNum = objnum; - m_IndirectObjs[objnum].reset(pObj); - m_LastObjNum = std::max(m_LastObjNum, objnum); - return true; -} - -void CPDF_IndirectObjectHolder::ReleaseIndirectObject(uint32_t objnum) { - CPDF_Object* pObj = GetIndirectObject(objnum); - if (!pObj || pObj->GetObjNum() == CPDF_Object::kInvalidObjNum) - return; - - m_IndirectObjs.erase(objnum); -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h b/core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h deleted file mode 100644 index 8fb91954c3..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_INDIRECT_OBJECT_HOLDER_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_INDIRECT_OBJECT_HOLDER_H_ - -#include -#include - -#include "core/fxcrt/fx_system.h" - -class CPDF_Object; - -class CPDF_IndirectObjectHolder { - public: - using const_iterator = - std::map>::const_iterator; - - CPDF_IndirectObjectHolder(); - virtual ~CPDF_IndirectObjectHolder(); - - CPDF_Object* GetIndirectObject(uint32_t objnum) const; - CPDF_Object* GetOrParseIndirectObject(uint32_t objnum); - void ReleaseIndirectObject(uint32_t objnum); - - // Take ownership of |pObj|. - uint32_t AddIndirectObject(CPDF_Object* pObj); - bool ReplaceIndirectObjectIfHigherGeneration(uint32_t objnum, - CPDF_Object* pObj); - - uint32_t GetLastObjNum() const { return m_LastObjNum; } - void SetLastObjNum(uint32_t objnum) { m_LastObjNum = objnum; } - - const_iterator begin() const { return m_IndirectObjs.begin(); } - const_iterator end() const { return m_IndirectObjs.end(); } - - protected: - virtual CPDF_Object* ParseIndirectObject(uint32_t objnum); - - private: - uint32_t m_LastObjNum; - std::map> m_IndirectObjs; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_INDIRECT_OBJECT_HOLDER_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_name.cpp b/core/fpdfapi/fpdf_parser/cpdf_name.cpp deleted file mode 100644 index 015c3d214a..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_name.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" - -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" - -CPDF_Name::CPDF_Name(const CFX_ByteString& str) : m_Name(str) {} - -CPDF_Name::~CPDF_Name() {} - -CPDF_Object::Type CPDF_Name::GetType() const { - return NAME; -} - -CPDF_Object* CPDF_Name::Clone() const { - return new CPDF_Name(m_Name); -} - -CFX_ByteString CPDF_Name::GetString() const { - return m_Name; -} - -void CPDF_Name::SetString(const CFX_ByteString& str) { - m_Name = str; -} - -bool CPDF_Name::IsName() const { - return true; -} - -CPDF_Name* CPDF_Name::AsName() { - return this; -} - -const CPDF_Name* CPDF_Name::AsName() const { - return this; -} - -CFX_WideString CPDF_Name::GetUnicodeText() const { - return PDF_DecodeText(m_Name); -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_name.h b/core/fpdfapi/fpdf_parser/cpdf_name.h deleted file mode 100644 index 53b8a35d5e..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_name.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_NAME_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_NAME_H_ - -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" - -class CPDF_Name : public CPDF_Object { - public: - explicit CPDF_Name(const CFX_ByteString& str); - - // CPDF_Object. - Type GetType() const override; - CPDF_Object* Clone() const override; - CFX_ByteString GetString() const override; - CFX_WideString GetUnicodeText() const override; - void SetString(const CFX_ByteString& str) override; - bool IsName() const override; - CPDF_Name* AsName() override; - const CPDF_Name* AsName() const override; - - protected: - ~CPDF_Name() override; - - CFX_ByteString m_Name; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_NAME_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_null.cpp b/core/fpdfapi/fpdf_parser/cpdf_null.cpp deleted file mode 100644 index 2149eaff62..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_null.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_null.h" - -CPDF_Null::CPDF_Null() {} - -CPDF_Object::Type CPDF_Null::GetType() const { - return NULLOBJ; -} - -CPDF_Object* CPDF_Null::Clone() const { - return new CPDF_Null; -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_null.h b/core/fpdfapi/fpdf_parser/cpdf_null.h deleted file mode 100644 index 45d73953ad..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_null.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_NULL_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_NULL_H_ - -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" - -class CPDF_Null : public CPDF_Object { - public: - CPDF_Null(); - - // CPDF_Object. - Type GetType() const override; - CPDF_Object* Clone() const override; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_NULL_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_number.cpp b/core/fpdfapi/fpdf_parser/cpdf_number.cpp deleted file mode 100644 index 28692eabab..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_number.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" - -CPDF_Number::CPDF_Number() : m_bInteger(true), m_Integer(0) {} - -CPDF_Number::CPDF_Number(int value) : m_bInteger(true), m_Integer(value) {} - -CPDF_Number::CPDF_Number(FX_FLOAT value) : m_bInteger(false), m_Float(value) {} - -CPDF_Number::CPDF_Number(const CFX_ByteStringC& str) - : m_bInteger(FX_atonum(str, &m_Integer)) {} - -CPDF_Number::~CPDF_Number() {} - -CPDF_Object::Type CPDF_Number::GetType() const { - return NUMBER; -} - -CPDF_Object* CPDF_Number::Clone() const { - return m_bInteger ? new CPDF_Number(m_Integer) : new CPDF_Number(m_Float); -} - -FX_FLOAT CPDF_Number::GetNumber() const { - return m_bInteger ? static_cast(m_Integer) : m_Float; -} - -int CPDF_Number::GetInteger() const { - return m_bInteger ? m_Integer : static_cast(m_Float); -} - -bool CPDF_Number::IsNumber() const { - return true; -} - -CPDF_Number* CPDF_Number::AsNumber() { - return this; -} - -const CPDF_Number* CPDF_Number::AsNumber() const { - return this; -} - -void CPDF_Number::SetString(const CFX_ByteString& str) { - m_bInteger = FX_atonum(str.AsStringC(), &m_Integer); -} - -CFX_ByteString CPDF_Number::GetString() const { - return m_bInteger ? CFX_ByteString::FormatInteger(m_Integer, FXFORMAT_SIGNED) - : CFX_ByteString::FormatFloat(m_Float); -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_number.h b/core/fpdfapi/fpdf_parser/cpdf_number.h deleted file mode 100644 index 068a9c9594..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_number.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_NUMBER_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_NUMBER_H_ - -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" - -class CPDF_Number : public CPDF_Object { - public: - CPDF_Number(); - explicit CPDF_Number(int value); - explicit CPDF_Number(FX_FLOAT value); - explicit CPDF_Number(const CFX_ByteStringC& str); - - // CPDF_Object. - Type GetType() const override; - CPDF_Object* Clone() const override; - CFX_ByteString GetString() const override; - FX_FLOAT GetNumber() const override; - int GetInteger() const override; - void SetString(const CFX_ByteString& str) override; - bool IsNumber() const override; - CPDF_Number* AsNumber() override; - const CPDF_Number* AsNumber() const override; - - bool IsInteger() const { return m_bInteger; } - - protected: - ~CPDF_Number() override; - - bool m_bInteger; - union { - int m_Integer; - FX_FLOAT m_Float; - }; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_NUMBER_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_object.cpp b/core/fpdfapi/fpdf_parser/cpdf_object.cpp deleted file mode 100644 index ba7490a13f..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_object.cpp +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" - -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h" -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" -#include "core/fxcrt/fx_string.h" -#include "third_party/base/stl_util.h" - -CPDF_Object::~CPDF_Object() {} - -CPDF_Object* CPDF_Object::GetDirect() const { - return const_cast(this); -} - -CPDF_Object* CPDF_Object::CloneObjectNonCyclic(bool bDirect) const { - std::set visited_objs; - return CloneNonCyclic(bDirect, &visited_objs); -} - -CPDF_Object* CPDF_Object::CloneDirectObject() const { - return CloneObjectNonCyclic(true); -} - -CPDF_Object* CPDF_Object::CloneNonCyclic( - bool bDirect, - std::set* pVisited) const { - return Clone(); -} - -void CPDF_Object::Release() { - if (m_ObjNum) - return; - - delete this; -} - -CFX_ByteString CPDF_Object::GetString() const { - return CFX_ByteString(); -} - -CFX_WideString CPDF_Object::GetUnicodeText() const { - return CFX_WideString(); -} - -FX_FLOAT CPDF_Object::GetNumber() const { - return 0; -} - -int CPDF_Object::GetInteger() const { - return 0; -} - -CPDF_Dictionary* CPDF_Object::GetDict() const { - return nullptr; -} - -void CPDF_Object::SetString(const CFX_ByteString& str) { - ASSERT(FALSE); -} - -bool CPDF_Object::IsArray() const { - return false; -} - -bool CPDF_Object::IsBoolean() const { - return false; -} - -bool CPDF_Object::IsDictionary() const { - return false; -} - -bool CPDF_Object::IsName() const { - return false; -} - -bool CPDF_Object::IsNumber() const { - return false; -} - -bool CPDF_Object::IsReference() const { - return false; -} - -bool CPDF_Object::IsStream() const { - return false; -} - -bool CPDF_Object::IsString() const { - return false; -} - -CPDF_Array* CPDF_Object::AsArray() { - return nullptr; -} - -const CPDF_Array* CPDF_Object::AsArray() const { - return nullptr; -} - -CPDF_Boolean* CPDF_Object::AsBoolean() { - return nullptr; -} - -const CPDF_Boolean* CPDF_Object::AsBoolean() const { - return nullptr; -} - -CPDF_Dictionary* CPDF_Object::AsDictionary() { - return nullptr; -} - -const CPDF_Dictionary* CPDF_Object::AsDictionary() const { - return nullptr; -} - -CPDF_Name* CPDF_Object::AsName() { - return nullptr; -} - -const CPDF_Name* CPDF_Object::AsName() const { - return nullptr; -} - -CPDF_Number* CPDF_Object::AsNumber() { - return nullptr; -} - -const CPDF_Number* CPDF_Object::AsNumber() const { - return nullptr; -} - -CPDF_Reference* CPDF_Object::AsReference() { - return nullptr; -} - -const CPDF_Reference* CPDF_Object::AsReference() const { - return nullptr; -} - -CPDF_Stream* CPDF_Object::AsStream() { - return nullptr; -} - -const CPDF_Stream* CPDF_Object::AsStream() const { - return nullptr; -} - -CPDF_String* CPDF_Object::AsString() { - return nullptr; -} - -const CPDF_String* CPDF_Object::AsString() const { - return nullptr; -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_object.h b/core/fpdfapi/fpdf_parser/cpdf_object.h deleted file mode 100644 index 7077bc190b..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_object.h +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_OBJECT_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_OBJECT_H_ - -#include -#include - -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" - -class CPDF_Array; -class CPDF_Boolean; -class CPDF_Dictionary; -class CPDF_Name; -class CPDF_Null; -class CPDF_Number; -class CPDF_Reference; -class CPDF_Stream; -class CPDF_String; - -class CPDF_Object { - public: - static const uint32_t kInvalidObjNum = static_cast(-1); - enum Type { - BOOLEAN = 1, - NUMBER, - STRING, - NAME, - ARRAY, - DICTIONARY, - STREAM, - NULLOBJ, - REFERENCE - }; - - virtual Type GetType() const = 0; - uint32_t GetObjNum() const { return m_ObjNum; } - uint32_t GetGenNum() const { return m_GenNum; } - - // Create a deep copy of the object. - virtual CPDF_Object* Clone() const = 0; - // Create a deep copy of the object except any reference object be - // copied to the object it points to directly. - virtual CPDF_Object* CloneDirectObject() const; - virtual CPDF_Object* GetDirect() const; - - void Release(); - - virtual CFX_ByteString GetString() const; - virtual CFX_WideString GetUnicodeText() const; - virtual FX_FLOAT GetNumber() const; - virtual int GetInteger() const; - virtual CPDF_Dictionary* GetDict() const; - - virtual void SetString(const CFX_ByteString& str); - - virtual bool IsArray() const; - virtual bool IsBoolean() const; - virtual bool IsDictionary() const; - virtual bool IsName() const; - virtual bool IsNumber() const; - virtual bool IsReference() const; - virtual bool IsStream() const; - virtual bool IsString() const; - - virtual CPDF_Array* AsArray(); - virtual const CPDF_Array* AsArray() const; - virtual CPDF_Boolean* AsBoolean(); - virtual const CPDF_Boolean* AsBoolean() const; - virtual CPDF_Dictionary* AsDictionary(); - virtual const CPDF_Dictionary* AsDictionary() const; - virtual CPDF_Name* AsName(); - virtual const CPDF_Name* AsName() const; - virtual CPDF_Number* AsNumber(); - virtual const CPDF_Number* AsNumber() const; - virtual CPDF_Reference* AsReference(); - virtual const CPDF_Reference* AsReference() const; - virtual CPDF_Stream* AsStream(); - virtual const CPDF_Stream* AsStream() const; - virtual CPDF_String* AsString(); - virtual const CPDF_String* AsString() const; - - protected: - friend class CPDF_Array; - friend class CPDF_Dictionary; - friend class CPDF_Document; - friend class CPDF_IndirectObjectHolder; - friend class CPDF_Parser; - friend class CPDF_Reference; - friend class CPDF_Stream; - friend struct std::default_delete; - - CPDF_Object() : m_ObjNum(0), m_GenNum(0) {} - virtual ~CPDF_Object(); - - CPDF_Object* CloneObjectNonCyclic(bool bDirect) const; - - // Create a deep copy of the object with the option to either - // copy a reference object or directly copy the object it refers to - // when |bDirect| is true. - // Also check cyclic reference against |pVisited|, no copy if it is found. - // Complex objects should implement their own CloneNonCyclic() - // function to properly check for possible loop. - virtual CPDF_Object* CloneNonCyclic( - bool bDirect, - std::set* pVisited) const; - - uint32_t m_ObjNum; - uint32_t m_GenNum; - - private: - CPDF_Object(const CPDF_Object& src) {} -}; - -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; -} - -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; -} - -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; -} - -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; -} - -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; -} - -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; -} -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; -} - -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; -} - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_OBJECT_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp b/core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp deleted file mode 100644 index 9b702099bb..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp +++ /dev/null @@ -1,835 +0,0 @@ -// Copyright 2016 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. - -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_null.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" - -#include -#include -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h" -#include "core/fxcrt/fx_basic.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -using ScopedArray = std::unique_ptr>; -using ScopedDict = - std::unique_ptr>; - -void TestArrayAccessors(const CPDF_Array* arr, - size_t index, - const char* str_val, - const char* const_str_val, - int int_val, - float float_val, - CPDF_Array* arr_val, - CPDF_Dictionary* dict_val, - CPDF_Stream* stream_val) { - EXPECT_STREQ(str_val, arr->GetStringAt(index).c_str()); - EXPECT_EQ(int_val, arr->GetIntegerAt(index)); - EXPECT_EQ(float_val, arr->GetNumberAt(index)); - EXPECT_EQ(float_val, arr->GetFloatAt(index)); - EXPECT_EQ(arr_val, arr->GetArrayAt(index)); - EXPECT_EQ(dict_val, arr->GetDictAt(index)); - EXPECT_EQ(stream_val, arr->GetStreamAt(index)); -} - -} // namespace - -class PDFObjectsTest : public testing::Test { - public: - void SetUp() override { - // Initialize different kinds of objects. - // Boolean objects. - CPDF_Boolean* boolean_false_obj = new CPDF_Boolean(false); - CPDF_Boolean* boolean_true_obj = new CPDF_Boolean(true); - // Number objects. - CPDF_Number* number_int_obj = new CPDF_Number(1245); - CPDF_Number* number_float_obj = new CPDF_Number(9.00345f); - // String objects. - CPDF_String* str_reg_obj = new CPDF_String(L"A simple test"); - CPDF_String* str_spec_obj = new CPDF_String(L"\t\n"); - // Name object. - CPDF_Name* name_obj = new CPDF_Name("space"); - // Array object. - 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->SetFor("bool", new CPDF_Boolean(false)); - m_DictObj->SetFor("num", new CPDF_Number(0.23f)); - // Stream object. - const char content[] = "abcdefghijklmnopqrstuvwxyz"; - size_t buf_len = FX_ArraySize(content); - uint8_t* buf = reinterpret_cast(malloc(buf_len)); - memcpy(buf, content, buf_len); - m_StreamDictObj = new CPDF_Dictionary(); - m_StreamDictObj->SetFor("key1", new CPDF_String(L" test dict")); - m_StreamDictObj->SetFor("key2", new CPDF_Number(-1)); - CPDF_Stream* stream_obj = new CPDF_Stream(buf, buf_len, m_StreamDictObj); - // Null Object. - CPDF_Null* null_obj = new CPDF_Null; - // 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, m_ArrayObj, m_DictObj, - stream_obj, null_obj}; - 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()); - 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->GetObjectAt(i), array2->GetObjectAt(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->GetObjectFor(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>; - - // m_ObjHolder needs to be declared first and destructed last since it also - // 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) { - const char* const direct_obj_results[] = { - "false", "true", "1245", "9.00345", "A simple test", "\t\n", "space", - "", "", "", ""}; - // Check for direct objects. - for (size_t i = 0; i < m_DirectObjs.size(); ++i) - EXPECT_STREQ(direct_obj_results[i], m_DirectObjs[i]->GetString().c_str()); - - // Check indirect references. - const char* const indirect_obj_results[] = {"true", "1245", "\t\n", "space", - "", "", ""}; - for (size_t i = 0; i < m_RefObjs.size(); ++i) { - EXPECT_STREQ(indirect_obj_results[i], m_RefObjs[i]->GetString().c_str()); - } -} - -TEST_F(PDFObjectsTest, GetUnicodeText) { - const wchar_t* const 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(direct_obj_results[i], - m_DirectObjs[i]->GetUnicodeText().c_str()); - } - - // Check indirect references. - for (const auto& it : m_RefObjs) - EXPECT_STREQ(L"", it->GetUnicodeText().c_str()); -} - -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 (size_t i = 0; i < m_DirectObjs.size(); ++i) - EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetNumber()); - - // Check indirect references. - const FX_FLOAT indirect_obj_results[] = {0, 1245, 0, 0, 0, 0, 0}; - for (size_t i = 0; i < m_RefObjs.size(); ++i) - EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetNumber()); -} - -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 (size_t i = 0; i < m_DirectObjs.size(); ++i) - EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetInteger()); - - // Check indirect references. - const int indirect_obj_results[] = {1, 1245, 0, 0, 0, 0, 0}; - for (size_t i = 0; i < m_RefObjs.size(); ++i) - EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetInteger()); -} - -TEST_F(PDFObjectsTest, GetDict) { - const CPDF_Dictionary* const direct_obj_results[] = { - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, m_DictObj, m_StreamDictObj, nullptr}; - // Check for direct objects. - for (size_t i = 0; i < m_DirectObjs.size(); ++i) - EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetDict()); - - // Check indirect references. - const CPDF_Dictionary* const indirect_obj_results[] = { - nullptr, nullptr, nullptr, nullptr, nullptr, m_DictObj, m_StreamDictObj}; - for (size_t i = 0; i < m_RefObjs.size(); ++i) - EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetDict()); -} - -TEST_F(PDFObjectsTest, GetArray) { - const CPDF_Array* const 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(direct_obj_results[i], m_DirectObjs[i]->AsArray()); - - // Check indirect references. - for (const auto& it : m_RefObjs) - EXPECT_EQ(nullptr, it->AsArray()); -} - -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_DirectObjTypes[i], m_DirectObjs[i]->GetType()); - - // Check indirect references. - for (const auto& it : m_RefObjs) - EXPECT_EQ(CPDF_Object::REFERENCE, it->GetType()); -} - -TEST_F(PDFObjectsTest, GetDirect) { - // Check for direct objects. - for (size_t i = 0; i < m_DirectObjs.size(); ++i) - EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->GetDirect()); - - // Check indirect references. - for (size_t i = 0; i < m_RefObjs.size(); ++i) - EXPECT_EQ(m_IndirectObjs[i], m_RefObjs[i]->GetDirect()); -} - -TEST_F(PDFObjectsTest, SetString) { - // Check for direct objects. - const char* const set_values[] = {"true", "fake", "3.125f", "097", - "changed", "", "NewName"}; - const char* const 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(expected[i], m_DirectObjs[i]->GetString().c_str()); - } -} - -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].get(), m_DirectObjs[i]->AsArray()); - } else { - EXPECT_FALSE(m_DirectObjs[i]->IsArray()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsArray()); - } - - if (m_DirectObjTypes[i] == CPDF_Object::BOOLEAN) { - EXPECT_TRUE(m_DirectObjs[i]->IsBoolean()); - EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsBoolean()); - } else { - EXPECT_FALSE(m_DirectObjs[i]->IsBoolean()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsBoolean()); - } - - if (m_DirectObjTypes[i] == CPDF_Object::NAME) { - EXPECT_TRUE(m_DirectObjs[i]->IsName()); - EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsName()); - } else { - EXPECT_FALSE(m_DirectObjs[i]->IsName()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsName()); - } - - if (m_DirectObjTypes[i] == CPDF_Object::NUMBER) { - EXPECT_TRUE(m_DirectObjs[i]->IsNumber()); - EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsNumber()); - } else { - EXPECT_FALSE(m_DirectObjs[i]->IsNumber()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsNumber()); - } - - if (m_DirectObjTypes[i] == CPDF_Object::STRING) { - EXPECT_TRUE(m_DirectObjs[i]->IsString()); - EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsString()); - } else { - EXPECT_FALSE(m_DirectObjs[i]->IsString()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsString()); - } - - if (m_DirectObjTypes[i] == CPDF_Object::DICTIONARY) { - EXPECT_TRUE(m_DirectObjs[i]->IsDictionary()); - EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsDictionary()); - } else { - EXPECT_FALSE(m_DirectObjs[i]->IsDictionary()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsDictionary()); - } - - if (m_DirectObjTypes[i] == CPDF_Object::STREAM) { - EXPECT_TRUE(m_DirectObjs[i]->IsStream()); - EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsStream()); - } else { - EXPECT_FALSE(m_DirectObjs[i]->IsStream()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsStream()); - } - - EXPECT_FALSE(m_DirectObjs[i]->IsReference()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsReference()); - } - // Check indirect references. - for (size_t i = 0; i < m_RefObjs.size(); ++i) { - EXPECT_TRUE(m_RefObjs[i]->IsReference()); - EXPECT_EQ(m_RefObjs[i].get(), m_RefObjs[i]->AsReference()); - } -} - -TEST(PDFArrayTest, GetMatrix) { - float elems[][6] = {{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, - {1, 2, 3, 4, 5, 6}, - {2.3f, 4.05f, 3, -2, -3, 0.0f}, - {0.05f, 0.1f, 0.56f, 0.67f, 1.34f, 99.9f}}; - for (size_t i = 0; i < FX_ArraySize(elems); ++i) { - ScopedArray arr(new CPDF_Array); - CFX_Matrix matrix(elems[i][0], elems[i][1], elems[i][2], elems[i][3], - elems[i][4], elems[i][5]); - for (size_t j = 0; j < 6; ++j) - arr->AddNumber(elems[i][j]); - CFX_Matrix arr_matrix = arr->GetMatrix(); - EXPECT_EQ(matrix.GetA(), arr_matrix.GetA()); - EXPECT_EQ(matrix.GetB(), arr_matrix.GetB()); - EXPECT_EQ(matrix.GetC(), arr_matrix.GetC()); - EXPECT_EQ(matrix.GetD(), arr_matrix.GetD()); - EXPECT_EQ(matrix.GetE(), arr_matrix.GetE()); - EXPECT_EQ(matrix.GetF(), arr_matrix.GetF()); - } -} - -TEST(PDFArrayTest, GetRect) { - float elems[][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, - {1, 2, 5, 6}, - {2.3f, 4.05f, -3, 0.0f}, - {0.05f, 0.1f, 1.34f, 99.9f}}; - for (size_t i = 0; i < FX_ArraySize(elems); ++i) { - ScopedArray arr(new CPDF_Array); - CFX_FloatRect rect(elems[i]); - for (size_t j = 0; j < 4; ++j) - arr->AddNumber(elems[i][j]); - CFX_FloatRect arr_rect = arr->GetRect(); - EXPECT_EQ(rect.left, arr_rect.left); - EXPECT_EQ(rect.right, arr_rect.right); - EXPECT_EQ(rect.bottom, arr_rect.bottom); - EXPECT_EQ(rect.top, arr_rect.top); - } -} - -TEST(PDFArrayTest, GetTypeAt) { - { - // Boolean array. - const bool vals[] = {true, false, false, true, true}; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) - arr->InsertAt(i, new CPDF_Boolean(vals[i])); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { - TestArrayAccessors(arr.get(), i, // Array and index. - vals[i] ? "true" : "false", // String value. - nullptr, // Const string value. - vals[i] ? 1 : 0, // Integer value. - 0, // Float value. - nullptr, // Array value. - nullptr, // Dictionary value. - nullptr); // Stream value. - } - } - { - // Integer array. - const int vals[] = {10, 0, -345, 2089345456, -1000000000, 567, 93658767}; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) - arr->InsertAt(i, new CPDF_Number(vals[i])); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { - char buf[33]; - TestArrayAccessors(arr.get(), i, // Array and index. - FXSYS_itoa(vals[i], buf, 10), // String value. - nullptr, // Const string value. - vals[i], // Integer value. - vals[i], // Float value. - nullptr, // Array value. - nullptr, // Dictionary value. - nullptr); // Stream value. - } - } - { - // Float array. - const float vals[] = {0.0f, 0, 10, 10.0f, 0.0345f, - 897.34f, -2.5f, -1.0f, -345.0f, -0.0f}; - const char* const expected_str[] = { - "0", "0", "10", "10", "0.0345", "897.34", "-2.5", "-1", "-345", "0"}; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { - arr->InsertAt(i, new CPDF_Number(vals[i])); - } - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { - TestArrayAccessors(arr.get(), i, // Array and index. - expected_str[i], // String value. - nullptr, // Const string value. - vals[i], // Integer value. - vals[i], // Float value. - nullptr, // Array value. - nullptr, // Dictionary value. - nullptr); // Stream value. - } - } - { - // String and name array - const char* const vals[] = {"this", "adsde$%^", "\r\t", "\"012", - ".", "EYREW", "It is a joke :)"}; - ScopedArray string_array(new CPDF_Array); - ScopedArray name_array(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { - string_array->InsertAt(i, new CPDF_String(vals[i], false)); - name_array->InsertAt(i, new CPDF_Name(vals[i])); - } - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { - TestArrayAccessors(string_array.get(), i, // Array and index. - vals[i], // String value. - vals[i], // Const string value. - 0, // Integer value. - 0, // Float value. - nullptr, // Array value. - nullptr, // Dictionary value. - nullptr); // Stream value. - TestArrayAccessors(name_array.get(), i, // Array and index. - vals[i], // String value. - vals[i], // Const string value. - 0, // Integer value. - 0, // Float value. - nullptr, // Array value. - nullptr, // Dictionary value. - nullptr); // Stream value. - } - } - { - // Null element array. - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < 3; ++i) - arr->InsertAt(i, new CPDF_Null); - for (size_t i = 0; i < 3; ++i) { - TestArrayAccessors(arr.get(), i, // Array and index. - "", // String value. - nullptr, // Const string value. - 0, // Integer value. - 0, // Float value. - nullptr, // Array value. - nullptr, // Dictionary value. - nullptr); // Stream value. - } - } - { - // Array of array. - CPDF_Array* vals[3]; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < 3; ++i) { - vals[i] = new CPDF_Array; - for (size_t j = 0; j < 3; ++j) { - int value = j + 100; - vals[i]->InsertAt(i, new CPDF_Number(value)); - } - arr->InsertAt(i, vals[i]); - } - for (size_t i = 0; i < 3; ++i) { - TestArrayAccessors(arr.get(), i, // Array and index. - "", // String value. - nullptr, // Const string value. - 0, // Integer value. - 0, // Float value. - vals[i], // Array value. - nullptr, // Dictionary value. - nullptr); // Stream value. - } - } - { - // Dictionary array. - CPDF_Dictionary* vals[3]; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < 3; ++i) { - vals[i] = new CPDF_Dictionary(); - for (size_t j = 0; j < 3; ++j) { - std::string key("key"); - char buf[33]; - key.append(FXSYS_itoa(j, buf, 10)); - int value = j + 200; - vals[i]->SetFor(key.c_str(), new CPDF_Number(value)); - } - arr->InsertAt(i, vals[i]); - } - for (size_t i = 0; i < 3; ++i) { - TestArrayAccessors(arr.get(), i, // Array and index. - "", // String value. - nullptr, // Const string value. - 0, // Integer value. - 0, // Float value. - nullptr, // Array value. - vals[i], // Dictionary value. - nullptr); // Stream value. - } - } - { - // Stream array. - CPDF_Dictionary* vals[3]; - CPDF_Stream* stream_vals[3]; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < 3; ++i) { - vals[i] = new CPDF_Dictionary(); - for (size_t j = 0; j < 3; ++j) { - std::string key("key"); - char buf[33]; - key.append(FXSYS_itoa(j, buf, 10)); - int value = j + 200; - vals[i]->SetFor(key.c_str(), new CPDF_Number(value)); - } - uint8_t content[] = "content: this is a stream"; - size_t data_size = FX_ArraySize(content); - uint8_t* data = reinterpret_cast(malloc(data_size)); - memcpy(data, content, data_size); - stream_vals[i] = new CPDF_Stream(data, data_size, vals[i]); - arr->InsertAt(i, stream_vals[i]); - } - for (size_t i = 0; i < 3; ++i) { - TestArrayAccessors(arr.get(), i, // Array and index. - "", // String value. - nullptr, // Const string value. - 0, // Integer value. - 0, // Float value. - nullptr, // Array value. - vals[i], // Dictionary value. - stream_vals[i]); // Stream value. - } - } - { - // Mixed array. - ScopedArray arr(new CPDF_Array); - // Array arr will take ownership of all the objects inserted. - arr->InsertAt(0, new CPDF_Boolean(true)); - arr->InsertAt(1, new CPDF_Boolean(false)); - arr->InsertAt(2, new CPDF_Number(0)); - arr->InsertAt(3, new CPDF_Number(-1234)); - arr->InsertAt(4, new CPDF_Number(2345.0f)); - arr->InsertAt(5, new CPDF_Number(0.05f)); - arr->InsertAt(6, new CPDF_String("", false)); - arr->InsertAt(7, new CPDF_String("It is a test!", false)); - arr->InsertAt(8, new CPDF_Name("NAME")); - arr->InsertAt(9, new CPDF_Name("test")); - arr->InsertAt(10, new CPDF_Null()); - CPDF_Array* arr_val = new CPDF_Array; - arr_val->AddNumber(1); - arr_val->AddNumber(2); - arr->InsertAt(11, arr_val); - CPDF_Dictionary* dict_val = new CPDF_Dictionary(); - dict_val->SetFor("key1", new CPDF_String("Linda", false)); - dict_val->SetFor("key2", new CPDF_String("Zoe", false)); - arr->InsertAt(12, dict_val); - CPDF_Dictionary* stream_dict = new CPDF_Dictionary(); - stream_dict->SetFor("key1", new CPDF_String("John", false)); - stream_dict->SetFor("key2", new CPDF_String("King", false)); - uint8_t data[] = "A stream for test"; - // The data buffer will be owned by stream object, so it needs to be - // dynamically allocated. - size_t buf_size = sizeof(data); - uint8_t* buf = reinterpret_cast(malloc(buf_size)); - memcpy(buf, data, buf_size); - CPDF_Stream* stream_val = new CPDF_Stream(buf, buf_size, stream_dict); - arr->InsertAt(13, stream_val); - const char* const expected_str[] = { - "true", "false", "0", "-1234", "2345", "0.05", "", - "It is a test!", "NAME", "test", "", "", "", ""}; - const int expected_int[] = {1, 0, 0, -1234, 2345, 0, 0, - 0, 0, 0, 0, 0, 0, 0}; - const float expected_float[] = {0, 0, 0, -1234, 2345, 0.05f, 0, - 0, 0, 0, 0, 0, 0, 0}; - for (size_t i = 0; i < arr->GetCount(); ++i) { - EXPECT_STREQ(expected_str[i], arr->GetStringAt(i).c_str()); - EXPECT_EQ(expected_int[i], arr->GetIntegerAt(i)); - EXPECT_EQ(expected_float[i], arr->GetNumberAt(i)); - EXPECT_EQ(expected_float[i], arr->GetFloatAt(i)); - if (i == 11) - EXPECT_EQ(arr_val, arr->GetArrayAt(i)); - else - EXPECT_EQ(nullptr, arr->GetArrayAt(i)); - if (i == 13) { - EXPECT_EQ(stream_dict, arr->GetDictAt(i)); - EXPECT_EQ(stream_val, arr->GetStreamAt(i)); - } else { - EXPECT_EQ(nullptr, arr->GetStreamAt(i)); - if (i == 12) - EXPECT_EQ(dict_val, arr->GetDictAt(i)); - else - EXPECT_EQ(nullptr, arr->GetDictAt(i)); - } - } - } -} - -TEST(PDFArrayTest, AddNumber) { - float vals[] = {1.0f, -1.0f, 0, 0.456734f, - 12345.54321f, 0.5f, 1000, 0.000045f}; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) - arr->AddNumber(vals[i]); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { - EXPECT_EQ(CPDF_Object::NUMBER, arr->GetObjectAt(i)->GetType()); - EXPECT_EQ(vals[i], arr->GetObjectAt(i)->GetNumber()); - } -} - -TEST(PDFArrayTest, AddInteger) { - int vals[] = {0, 1, 934435456, 876, 10000, -1, -24354656, -100}; - ScopedArray arr(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) - arr->AddInteger(vals[i]); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { - EXPECT_EQ(CPDF_Object::NUMBER, arr->GetObjectAt(i)->GetType()); - EXPECT_EQ(vals[i], arr->GetObjectAt(i)->GetNumber()); - } -} - -TEST(PDFArrayTest, AddStringAndName) { - const char* vals[] = {"", "a", "ehjhRIOYTTFdfcdnv", "122323", - "$#%^&**", " ", "This is a test.\r\n"}; - ScopedArray string_array(new CPDF_Array); - ScopedArray name_array(new CPDF_Array); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { - string_array->AddString(vals[i]); - name_array->AddName(vals[i]); - } - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { - EXPECT_EQ(CPDF_Object::STRING, string_array->GetObjectAt(i)->GetType()); - EXPECT_STREQ(vals[i], string_array->GetObjectAt(i)->GetString().c_str()); - EXPECT_EQ(CPDF_Object::NAME, name_array->GetObjectAt(i)->GetType()); - EXPECT_STREQ(vals[i], name_array->GetObjectAt(i)->GetString().c_str()); - } -} - -TEST(PDFArrayTest, AddReferenceAndGetObjectAt) { - std::unique_ptr holder( - new CPDF_IndirectObjectHolder()); - CPDF_Boolean* boolean_obj = new CPDF_Boolean(true); - CPDF_Number* int_obj = new CPDF_Number(-1234); - CPDF_Number* float_obj = new CPDF_Number(2345.089f); - CPDF_String* str_obj = new CPDF_String("Adsfdsf 343434 %&&*\n", false); - CPDF_Name* name_obj = new CPDF_Name("Title:"); - CPDF_Null* null_obj = new CPDF_Null(); - CPDF_Object* indirect_objs[] = {boolean_obj, int_obj, float_obj, - str_obj, name_obj, null_obj}; - unsigned int obj_nums[] = {2, 4, 7, 2345, 799887, 1}; - ScopedArray arr(new CPDF_Array); - ScopedArray arr1(new CPDF_Array); - // Create two arrays of references by different AddReference() APIs. - for (size_t i = 0; i < FX_ArraySize(indirect_objs); ++i) { - // All the indirect objects inserted will be owned by holder. - holder->ReplaceIndirectObjectIfHigherGeneration(obj_nums[i], - indirect_objs[i]); - arr->AddReference(holder.get(), obj_nums[i]); - arr1->AddReference(holder.get(), indirect_objs[i]->GetObjNum()); - } - // Check indirect objects. - for (size_t i = 0; i < FX_ArraySize(obj_nums); ++i) - EXPECT_EQ(indirect_objs[i], holder->GetOrParseIndirectObject(obj_nums[i])); - // Check arrays. - EXPECT_EQ(arr->GetCount(), arr1->GetCount()); - for (size_t i = 0; i < arr->GetCount(); ++i) { - EXPECT_EQ(CPDF_Object::REFERENCE, arr->GetObjectAt(i)->GetType()); - EXPECT_EQ(indirect_objs[i], arr->GetObjectAt(i)->GetDirect()); - EXPECT_EQ(indirect_objs[i], arr->GetDirectObjectAt(i)); - EXPECT_EQ(CPDF_Object::REFERENCE, arr1->GetObjectAt(i)->GetType()); - EXPECT_EQ(indirect_objs[i], arr1->GetObjectAt(i)->GetDirect()); - EXPECT_EQ(indirect_objs[i], arr1->GetDirectObjectAt(i)); - } -} - -TEST(PDFArrayTest, CloneDirectObject) { - CPDF_IndirectObjectHolder objects_holder; - ScopedArray array(new CPDF_Array); - array->AddReference(&objects_holder, 1234); - ASSERT_EQ(1U, array->GetCount()); - CPDF_Object* obj = array->GetObjectAt(0); - ASSERT_TRUE(obj); - EXPECT_TRUE(obj->IsReference()); - - CPDF_Object* cloned_array_object = array->CloneDirectObject(); - ASSERT_TRUE(cloned_array_object); - ASSERT_TRUE(cloned_array_object->IsArray()); - - ScopedArray cloned_array(cloned_array_object->AsArray()); - ASSERT_EQ(1U, cloned_array->GetCount()); - CPDF_Object* cloned_obj = cloned_array->GetObjectAt(0); - EXPECT_FALSE(cloned_obj); -} - -TEST(PDFDictionaryTest, CloneDirectObject) { - CPDF_IndirectObjectHolder objects_holder; - ScopedDict dict(new CPDF_Dictionary()); - dict->SetReferenceFor("foo", &objects_holder, 1234); - ASSERT_EQ(1U, dict->GetCount()); - CPDF_Object* obj = dict->GetObjectFor("foo"); - ASSERT_TRUE(obj); - EXPECT_TRUE(obj->IsReference()); - - CPDF_Object* cloned_dict_object = dict->CloneDirectObject(); - ASSERT_TRUE(cloned_dict_object); - ASSERT_TRUE(cloned_dict_object->IsDictionary()); - - ScopedDict cloned_dict(cloned_dict_object->AsDictionary()); - ASSERT_EQ(1U, cloned_dict->GetCount()); - CPDF_Object* cloned_obj = cloned_dict->GetObjectFor("foo"); - EXPECT_FALSE(cloned_obj); -} - -TEST(PDFObjectTest, CloneCheckLoop) { - { - // Create an object with a reference loop. - ScopedArray arr_obj(new CPDF_Array); - // Dictionary object. - CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); - dict_obj->SetFor("arr", arr_obj.get()); - arr_obj->InsertAt(0, dict_obj); - - // Clone this object to see whether stack overflow will be triggered. - ScopedArray cloned_array(arr_obj->Clone()->AsArray()); - // Cloned object should be the same as the original. - ASSERT_TRUE(cloned_array); - EXPECT_EQ(1u, cloned_array->GetCount()); - CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0); - ASSERT_TRUE(cloned_dict); - ASSERT_TRUE(cloned_dict->IsDictionary()); - // Recursively referenced object is not cloned. - EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("arr")); - } - { - CPDF_IndirectObjectHolder objects_holder; - // Create an object with a reference loop. - CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); - CPDF_Array* arr_obj = new CPDF_Array; - objects_holder.AddIndirectObject(dict_obj); - EXPECT_EQ(1u, dict_obj->GetObjNum()); - dict_obj->SetFor("arr", arr_obj); - arr_obj->InsertAt( - 0, new CPDF_Reference(&objects_holder, dict_obj->GetObjNum())); - CPDF_Object* elem0 = arr_obj->GetObjectAt(0); - ASSERT_TRUE(elem0); - ASSERT_TRUE(elem0->IsReference()); - EXPECT_EQ(1u, elem0->AsReference()->GetRefObjNum()); - EXPECT_EQ(dict_obj, elem0->AsReference()->GetDirect()); - - // Clone this object to see whether stack overflow will be triggered. - ScopedDict cloned_dict(ToDictionary(dict_obj->CloneDirectObject())); - // Cloned object should be the same as the original. - ASSERT_TRUE(cloned_dict); - CPDF_Object* cloned_arr = cloned_dict->GetObjectFor("arr"); - ASSERT_TRUE(cloned_arr); - ASSERT_TRUE(cloned_arr->IsArray()); - EXPECT_EQ(1u, cloned_arr->AsArray()->GetCount()); - // Recursively referenced object is not cloned. - EXPECT_EQ(nullptr, cloned_arr->AsArray()->GetObjectAt(0)); - } -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_parser.cpp b/core/fpdfapi/fpdf_parser/cpdf_parser.cpp deleted file mode 100644 index 182d3869bc..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_parser.cpp +++ /dev/null @@ -1,1637 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" - -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_security_handler.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h" -#include "core/fxcrt/fx_ext.h" -#include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/stl_util.h" - -namespace { - -// A limit on the size of the xref table. Theoretical limits are higher, but -// this may be large enough in practice. -const int32_t kMaxXRefSize = 1048576; - -uint32_t GetVarInt(const uint8_t* p, int32_t n) { - uint32_t result = 0; - for (int32_t i = 0; i < n; ++i) - result = result * 256 + p[i]; - return result; -} - -int32_t GetStreamNCount(CPDF_StreamAcc* pObjStream) { - return pObjStream->GetDict()->GetIntegerFor("N"); -} - -int32_t GetStreamFirst(CPDF_StreamAcc* pObjStream) { - return pObjStream->GetDict()->GetIntegerFor("First"); -} - -} // namespace - -CPDF_Parser::CPDF_Parser() - : m_pDocument(nullptr), - m_bHasParsed(false), - m_bOwnFileRead(true), - m_FileVersion(0), - m_pTrailer(nullptr), - m_pEncryptDict(nullptr), - m_bVersionUpdated(false), - m_pLinearized(nullptr), - m_dwFirstPageNo(0), - m_dwXrefStartObjNum(0) { - m_pSyntax.reset(new CPDF_SyntaxParser); -} - -CPDF_Parser::~CPDF_Parser() { - if (m_pTrailer) - m_pTrailer->Release(); - - ReleaseEncryptHandler(); - SetEncryptDictionary(nullptr); - - if (m_bOwnFileRead && m_pSyntax->m_pFileAccess) { - m_pSyntax->m_pFileAccess->Release(); - m_pSyntax->m_pFileAccess = nullptr; - } - - int32_t iLen = m_Trailers.GetSize(); - for (int32_t i = 0; i < iLen; ++i) { - if (CPDF_Dictionary* trailer = m_Trailers.GetAt(i)) - trailer->Release(); - } - - if (m_pLinearized) - m_pLinearized->Release(); -} - -uint32_t CPDF_Parser::GetLastObjNum() const { - return m_ObjectInfo.empty() ? 0 : m_ObjectInfo.rbegin()->first; -} - -bool CPDF_Parser::IsValidObjectNumber(uint32_t objnum) const { - return !m_ObjectInfo.empty() && objnum <= m_ObjectInfo.rbegin()->first; -} - -FX_FILESIZE CPDF_Parser::GetObjectPositionOrZero(uint32_t objnum) const { - auto it = m_ObjectInfo.find(objnum); - return it != m_ObjectInfo.end() ? it->second.pos : 0; -} - -uint8_t CPDF_Parser::GetObjectType(uint32_t objnum) const { - ASSERT(IsValidObjectNumber(objnum)); - auto it = m_ObjectInfo.find(objnum); - return it != m_ObjectInfo.end() ? it->second.type : 0; -} - -uint16_t CPDF_Parser::GetObjectGenNum(uint32_t objnum) const { - ASSERT(IsValidObjectNumber(objnum)); - auto it = m_ObjectInfo.find(objnum); - return it != m_ObjectInfo.end() ? it->second.gennum : 0; -} - -bool CPDF_Parser::IsObjectFreeOrNull(uint32_t objnum) const { - uint8_t type = GetObjectType(objnum); - return type == 0 || type == 255; -} - -void CPDF_Parser::SetEncryptDictionary(CPDF_Dictionary* pDict) { - m_pEncryptDict = pDict; -} - -CPDF_CryptoHandler* CPDF_Parser::GetCryptoHandler() { - return m_pSyntax->m_pCryptoHandler.get(); -} - -IFX_FileRead* CPDF_Parser::GetFileAccess() const { - return m_pSyntax->m_pFileAccess; -} - -void CPDF_Parser::ShrinkObjectMap(uint32_t objnum) { - if (objnum == 0) { - m_ObjectInfo.clear(); - return; - } - - auto it = m_ObjectInfo.lower_bound(objnum); - while (it != m_ObjectInfo.end()) { - auto saved_it = it++; - m_ObjectInfo.erase(saved_it); - } - - if (!pdfium::ContainsKey(m_ObjectInfo, objnum - 1)) - m_ObjectInfo[objnum - 1].pos = 0; -} - -CPDF_Parser::Error CPDF_Parser::StartParse(IFX_FileRead* pFileAccess, - CPDF_Document* pDocument) { - ASSERT(!m_bHasParsed); - m_bHasParsed = true; - - m_bXRefStream = FALSE; - m_LastXRefOffset = 0; - m_bOwnFileRead = true; - - int32_t offset = GetHeaderOffset(pFileAccess); - if (offset == -1) { - if (pFileAccess) - pFileAccess->Release(); - return FORMAT_ERROR; - } - m_pSyntax->InitParser(pFileAccess, offset); - - uint8_t ch; - if (!m_pSyntax->GetCharAt(5, ch)) - return FORMAT_ERROR; - if (std::isdigit(ch)) - m_FileVersion = FXSYS_toDecimalDigit(static_cast(ch)) * 10; - - if (!m_pSyntax->GetCharAt(7, ch)) - return FORMAT_ERROR; - if (std::isdigit(ch)) - m_FileVersion += FXSYS_toDecimalDigit(static_cast(ch)); - - if (m_pSyntax->m_FileLen < m_pSyntax->m_HeaderOffset + 9) - return FORMAT_ERROR; - - m_pSyntax->RestorePos(m_pSyntax->m_FileLen - m_pSyntax->m_HeaderOffset - 9); - m_pDocument = pDocument; - - FX_BOOL bXRefRebuilt = FALSE; - if (m_pSyntax->SearchWord("startxref", TRUE, FALSE, 4096)) { - m_SortedOffset.insert(m_pSyntax->SavePos()); - m_pSyntax->GetKeyword(); - - bool bNumber; - CFX_ByteString xrefpos_str = m_pSyntax->GetNextWord(&bNumber); - if (!bNumber) - return FORMAT_ERROR; - - m_LastXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str.c_str()); - if (!LoadAllCrossRefV4(m_LastXRefOffset) && - !LoadAllCrossRefV5(m_LastXRefOffset)) { - if (!RebuildCrossRef()) - return FORMAT_ERROR; - - bXRefRebuilt = TRUE; - m_LastXRefOffset = 0; - } - } else { - if (!RebuildCrossRef()) - return FORMAT_ERROR; - - bXRefRebuilt = TRUE; - } - Error eRet = SetEncryptHandler(); - if (eRet != SUCCESS) - return eRet; - - m_pDocument->LoadDoc(); - if (!m_pDocument->GetRoot() || m_pDocument->GetPageCount() == 0) { - if (bXRefRebuilt) - return FORMAT_ERROR; - - ReleaseEncryptHandler(); - if (!RebuildCrossRef()) - return FORMAT_ERROR; - - eRet = SetEncryptHandler(); - if (eRet != SUCCESS) - return eRet; - - m_pDocument->LoadDoc(); - if (!m_pDocument->GetRoot()) - return FORMAT_ERROR; - } - if (GetRootObjNum() == 0) { - ReleaseEncryptHandler(); - if (!RebuildCrossRef() || GetRootObjNum() == 0) - return FORMAT_ERROR; - - eRet = SetEncryptHandler(); - if (eRet != SUCCESS) - return eRet; - } - if (m_pSecurityHandler && !m_pSecurityHandler->IsMetadataEncrypted()) { - CPDF_Reference* pMetadata = - ToReference(m_pDocument->GetRoot()->GetObjectFor("Metadata")); - if (pMetadata) - m_pSyntax->m_MetadataObjnum = pMetadata->GetRefObjNum(); - } - return SUCCESS; -} -CPDF_Parser::Error CPDF_Parser::SetEncryptHandler() { - ReleaseEncryptHandler(); - SetEncryptDictionary(nullptr); - - if (!m_pTrailer) - return FORMAT_ERROR; - - CPDF_Object* pEncryptObj = m_pTrailer->GetObjectFor("Encrypt"); - if (pEncryptObj) { - if (CPDF_Dictionary* pEncryptDict = pEncryptObj->AsDictionary()) { - SetEncryptDictionary(pEncryptDict); - } else if (CPDF_Reference* pRef = pEncryptObj->AsReference()) { - pEncryptObj = m_pDocument->GetOrParseIndirectObject(pRef->GetRefObjNum()); - if (pEncryptObj) - SetEncryptDictionary(pEncryptObj->GetDict()); - } - } - - if (m_pEncryptDict) { - CFX_ByteString filter = m_pEncryptDict->GetStringFor("Filter"); - std::unique_ptr pSecurityHandler; - Error err = HANDLER_ERROR; - if (filter == "Standard") { - pSecurityHandler.reset(new CPDF_SecurityHandler); - err = PASSWORD_ERROR; - } - if (!pSecurityHandler) - return HANDLER_ERROR; - - if (!pSecurityHandler->OnInit(this, m_pEncryptDict)) - return err; - - m_pSecurityHandler = std::move(pSecurityHandler); - std::unique_ptr pCryptoHandler( - m_pSecurityHandler->CreateCryptoHandler()); - if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler.get())) - return HANDLER_ERROR; - m_pSyntax->SetEncrypt(std::move(pCryptoHandler)); - } - return SUCCESS; -} - -void CPDF_Parser::ReleaseEncryptHandler() { - m_pSyntax->m_pCryptoHandler.reset(); - m_pSecurityHandler.reset(); -} - -FX_FILESIZE CPDF_Parser::GetObjectOffset(uint32_t objnum) const { - if (!IsValidObjectNumber(objnum)) - return 0; - - if (GetObjectType(objnum) == 1) - return GetObjectPositionOrZero(objnum); - - if (GetObjectType(objnum) == 2) { - FX_FILESIZE pos = GetObjectPositionOrZero(objnum); - return GetObjectPositionOrZero(pos); - } - return 0; -} - -// Ideally, all the cross reference entries should be verified. -// In reality, we rarely see well-formed cross references don't match -// with the objects. crbug/602650 showed a case where object numbers -// in the cross reference table are all off by one. -bool CPDF_Parser::VerifyCrossRefV4() { - for (const auto& it : m_ObjectInfo) { - if (it.second.pos == 0) - continue; - // Find the first non-zero position. - FX_FILESIZE SavedPos = m_pSyntax->SavePos(); - m_pSyntax->RestorePos(it.second.pos); - bool is_num = false; - CFX_ByteString num_str = m_pSyntax->GetNextWord(&is_num); - m_pSyntax->RestorePos(SavedPos); - if (!is_num || num_str.IsEmpty() || - FXSYS_atoui(num_str.c_str()) != it.first) { - // If the object number read doesn't match the one stored, - // something is wrong with the cross reference table. - return false; - } else { - return true; - } - } - return true; -} - -FX_BOOL CPDF_Parser::LoadAllCrossRefV4(FX_FILESIZE xrefpos) { - if (!LoadCrossRefV4(xrefpos, 0, TRUE)) - return FALSE; - - m_pTrailer = LoadTrailerV4(); - if (!m_pTrailer) - return FALSE; - - int32_t xrefsize = GetDirectInteger(m_pTrailer, "Size"); - if (xrefsize > 0 && xrefsize <= kMaxXRefSize) - ShrinkObjectMap(xrefsize); - - std::vector CrossRefList; - std::vector XRefStreamList; - std::set seen_xrefpos; - - CrossRefList.push_back(xrefpos); - XRefStreamList.push_back(GetDirectInteger(m_pTrailer, "XRefStm")); - seen_xrefpos.insert(xrefpos); - - // When |m_pTrailer| doesn't have Prev entry or Prev entry value is not - // numerical, GetDirectInteger() returns 0. Loading will end. - xrefpos = GetDirectInteger(m_pTrailer, "Prev"); - while (xrefpos) { - // Check for circular references. - if (pdfium::ContainsKey(seen_xrefpos, xrefpos)) - return FALSE; - - seen_xrefpos.insert(xrefpos); - - // SLOW ... - CrossRefList.insert(CrossRefList.begin(), xrefpos); - LoadCrossRefV4(xrefpos, 0, TRUE); - - std::unique_ptr> pDict( - LoadTrailerV4()); - if (!pDict) - return FALSE; - - xrefpos = GetDirectInteger(pDict.get(), "Prev"); - - // SLOW ... - XRefStreamList.insert(XRefStreamList.begin(), - pDict->GetIntegerFor("XRefStm")); - m_Trailers.Add(pDict.release()); - } - - for (size_t i = 0; i < CrossRefList.size(); ++i) { - if (!LoadCrossRefV4(CrossRefList[i], XRefStreamList[i], FALSE)) - return FALSE; - if (i == 0 && !VerifyCrossRefV4()) - return FALSE; - } - return TRUE; -} - -FX_BOOL CPDF_Parser::LoadLinearizedAllCrossRefV4(FX_FILESIZE xrefpos, - uint32_t dwObjCount) { - if (!LoadLinearizedCrossRefV4(xrefpos, dwObjCount)) - return FALSE; - - m_pTrailer = LoadTrailerV4(); - if (!m_pTrailer) - return FALSE; - - int32_t xrefsize = GetDirectInteger(m_pTrailer, "Size"); - if (xrefsize == 0) - return FALSE; - - std::vector CrossRefList; - std::vector XRefStreamList; - std::set seen_xrefpos; - - CrossRefList.push_back(xrefpos); - XRefStreamList.push_back(GetDirectInteger(m_pTrailer, "XRefStm")); - seen_xrefpos.insert(xrefpos); - - xrefpos = GetDirectInteger(m_pTrailer, "Prev"); - while (xrefpos) { - // Check for circular references. - if (pdfium::ContainsKey(seen_xrefpos, xrefpos)) - return FALSE; - - seen_xrefpos.insert(xrefpos); - - // SLOW ... - CrossRefList.insert(CrossRefList.begin(), xrefpos); - LoadCrossRefV4(xrefpos, 0, TRUE); - - std::unique_ptr> pDict( - LoadTrailerV4()); - if (!pDict) - return FALSE; - - xrefpos = GetDirectInteger(pDict.get(), "Prev"); - - // SLOW ... - XRefStreamList.insert(XRefStreamList.begin(), - pDict->GetIntegerFor("XRefStm")); - m_Trailers.Add(pDict.release()); - } - - for (size_t i = 1; i < CrossRefList.size(); ++i) { - if (!LoadCrossRefV4(CrossRefList[i], XRefStreamList[i], FALSE)) - return FALSE; - } - return TRUE; -} - -FX_BOOL CPDF_Parser::LoadLinearizedCrossRefV4(FX_FILESIZE pos, - uint32_t dwObjCount) { - FX_FILESIZE dwStartPos = pos - m_pSyntax->m_HeaderOffset; - - m_pSyntax->RestorePos(dwStartPos); - m_SortedOffset.insert(pos); - - uint32_t start_objnum = 0; - uint32_t count = dwObjCount; - FX_FILESIZE SavedPos = m_pSyntax->SavePos(); - - const int32_t recordsize = 20; - std::vector buf(1024 * recordsize + 1); - buf[1024 * recordsize] = '\0'; - - int32_t nBlocks = count / 1024 + 1; - for (int32_t block = 0; block < nBlocks; block++) { - int32_t block_size = block == nBlocks - 1 ? count % 1024 : 1024; - uint32_t dwReadSize = block_size * recordsize; - if ((FX_FILESIZE)(dwStartPos + dwReadSize) > m_pSyntax->m_FileLen) - return FALSE; - - if (!m_pSyntax->ReadBlock(reinterpret_cast(buf.data()), - dwReadSize)) { - return FALSE; - } - - for (int32_t i = 0; i < block_size; i++) { - uint32_t objnum = start_objnum + block * 1024 + i; - char* pEntry = &buf[i * recordsize]; - if (pEntry[17] == 'f') { - m_ObjectInfo[objnum].pos = 0; - m_ObjectInfo[objnum].type = 0; - } else { - int32_t offset = FXSYS_atoi(pEntry); - if (offset == 0) { - for (int32_t c = 0; c < 10; c++) { - if (!std::isdigit(pEntry[c])) - return FALSE; - } - } - - m_ObjectInfo[objnum].pos = offset; - int32_t version = FXSYS_atoi(pEntry + 11); - if (version >= 1) - m_bVersionUpdated = true; - - m_ObjectInfo[objnum].gennum = version; - if (m_ObjectInfo[objnum].pos < m_pSyntax->m_FileLen) - m_SortedOffset.insert(m_ObjectInfo[objnum].pos); - - m_ObjectInfo[objnum].type = 1; - } - } - } - m_pSyntax->RestorePos(SavedPos + count * recordsize); - return TRUE; -} - -bool CPDF_Parser::LoadCrossRefV4(FX_FILESIZE pos, - FX_FILESIZE streampos, - FX_BOOL bSkip) { - m_pSyntax->RestorePos(pos); - if (m_pSyntax->GetKeyword() != "xref") - return false; - - m_SortedOffset.insert(pos); - if (streampos) - m_SortedOffset.insert(streampos); - - while (1) { - FX_FILESIZE SavedPos = m_pSyntax->SavePos(); - bool bIsNumber; - CFX_ByteString word = m_pSyntax->GetNextWord(&bIsNumber); - if (word.IsEmpty()) - return false; - - if (!bIsNumber) { - m_pSyntax->RestorePos(SavedPos); - break; - } - - uint32_t start_objnum = FXSYS_atoui(word.c_str()); - if (start_objnum >= kMaxObjectNumber) - return false; - - uint32_t count = m_pSyntax->GetDirectNum(); - m_pSyntax->ToNextWord(); - SavedPos = m_pSyntax->SavePos(); - const int32_t recordsize = 20; - - m_dwXrefStartObjNum = start_objnum; - if (!bSkip) { - std::vector buf(1024 * recordsize + 1); - buf[1024 * recordsize] = '\0'; - - int32_t nBlocks = count / 1024 + 1; - for (int32_t block = 0; block < nBlocks; block++) { - int32_t block_size = block == nBlocks - 1 ? count % 1024 : 1024; - m_pSyntax->ReadBlock(reinterpret_cast(buf.data()), - block_size * recordsize); - - for (int32_t i = 0; i < block_size; i++) { - uint32_t objnum = start_objnum + block * 1024 + i; - char* pEntry = &buf[i * recordsize]; - if (pEntry[17] == 'f') { - m_ObjectInfo[objnum].pos = 0; - m_ObjectInfo[objnum].type = 0; - } else { - FX_FILESIZE offset = (FX_FILESIZE)FXSYS_atoi64(pEntry); - if (offset == 0) { - for (int32_t c = 0; c < 10; c++) { - if (!std::isdigit(pEntry[c])) - return false; - } - } - - m_ObjectInfo[objnum].pos = offset; - int32_t version = FXSYS_atoi(pEntry + 11); - if (version >= 1) - m_bVersionUpdated = true; - - m_ObjectInfo[objnum].gennum = version; - if (m_ObjectInfo[objnum].pos < m_pSyntax->m_FileLen) - m_SortedOffset.insert(m_ObjectInfo[objnum].pos); - - m_ObjectInfo[objnum].type = 1; - } - } - } - } - m_pSyntax->RestorePos(SavedPos + count * recordsize); - } - return !streampos || LoadCrossRefV5(&streampos, FALSE); -} - -FX_BOOL CPDF_Parser::LoadAllCrossRefV5(FX_FILESIZE xrefpos) { - if (!LoadCrossRefV5(&xrefpos, TRUE)) - return FALSE; - - std::set seen_xrefpos; - while (xrefpos) { - seen_xrefpos.insert(xrefpos); - if (!LoadCrossRefV5(&xrefpos, FALSE)) - return FALSE; - - // Check for circular references. - if (pdfium::ContainsKey(seen_xrefpos, xrefpos)) - return FALSE; - } - m_ObjectStreamMap.clear(); - m_bXRefStream = TRUE; - return TRUE; -} - -FX_BOOL CPDF_Parser::RebuildCrossRef() { - m_ObjectInfo.clear(); - m_SortedOffset.clear(); - if (m_pTrailer) { - m_pTrailer->Release(); - m_pTrailer = nullptr; - } - - ParserState state = ParserState::kDefault; - - int32_t inside_index = 0; - uint32_t objnum = 0; - uint32_t gennum = 0; - int32_t depth = 0; - - const uint32_t kBufferSize = 4096; - std::vector buffer(kBufferSize); - - FX_FILESIZE pos = m_pSyntax->m_HeaderOffset; - FX_FILESIZE start_pos = 0; - FX_FILESIZE start_pos1 = 0; - FX_FILESIZE last_obj = -1; - FX_FILESIZE last_xref = -1; - FX_FILESIZE last_trailer = -1; - - while (pos < m_pSyntax->m_FileLen) { - const FX_FILESIZE saved_pos = pos; - bool bOverFlow = false; - uint32_t size = - std::min((uint32_t)(m_pSyntax->m_FileLen - pos), kBufferSize); - if (!m_pSyntax->m_pFileAccess->ReadBlock(buffer.data(), pos, size)) - break; - - for (uint32_t i = 0; i < size; i++) { - uint8_t byte = buffer[i]; - switch (state) { - case ParserState::kDefault: - if (PDFCharIsWhitespace(byte)) { - state = ParserState::kWhitespace; - } else if (std::isdigit(byte)) { - --i; - state = ParserState::kWhitespace; - } else if (byte == '%') { - inside_index = 0; - state = ParserState::kComment; - } else if (byte == '(') { - state = ParserState::kString; - depth = 1; - } else if (byte == '<') { - inside_index = 1; - state = ParserState::kHexString; - } else if (byte == '\\') { - state = ParserState::kEscapedString; - } else if (byte == 't') { - state = ParserState::kTrailer; - inside_index = 1; - } - break; - - case ParserState::kWhitespace: - if (std::isdigit(byte)) { - start_pos = pos + i; - state = ParserState::kObjNum; - objnum = FXSYS_toDecimalDigit(static_cast(byte)); - } else if (byte == 't') { - state = ParserState::kTrailer; - inside_index = 1; - } else if (byte == 'x') { - state = ParserState::kXref; - inside_index = 1; - } else if (!PDFCharIsWhitespace(byte)) { - --i; - state = ParserState::kDefault; - } - break; - - case ParserState::kObjNum: - if (std::isdigit(byte)) { - objnum = - objnum * 10 + FXSYS_toDecimalDigit(static_cast(byte)); - } else if (PDFCharIsWhitespace(byte)) { - state = ParserState::kPostObjNum; - } else { - --i; - state = ParserState::kEndObj; - inside_index = 0; - } - break; - - case ParserState::kPostObjNum: - if (std::isdigit(byte)) { - start_pos1 = pos + i; - state = ParserState::kGenNum; - gennum = FXSYS_toDecimalDigit(static_cast(byte)); - } else if (byte == 't') { - state = ParserState::kTrailer; - inside_index = 1; - } else if (!PDFCharIsWhitespace(byte)) { - --i; - state = ParserState::kDefault; - } - break; - - case ParserState::kGenNum: - if (std::isdigit(byte)) { - gennum = - gennum * 10 + FXSYS_toDecimalDigit(static_cast(byte)); - } else if (PDFCharIsWhitespace(byte)) { - state = ParserState::kPostGenNum; - } else { - --i; - state = ParserState::kDefault; - } - break; - - case ParserState::kPostGenNum: - if (byte == 'o') { - state = ParserState::kBeginObj; - inside_index = 1; - } else if (std::isdigit(byte)) { - objnum = gennum; - gennum = FXSYS_toDecimalDigit(static_cast(byte)); - start_pos = start_pos1; - start_pos1 = pos + i; - state = ParserState::kGenNum; - } else if (byte == 't') { - state = ParserState::kTrailer; - inside_index = 1; - } else if (!PDFCharIsWhitespace(byte)) { - --i; - state = ParserState::kDefault; - } - break; - - case ParserState::kBeginObj: - switch (inside_index) { - case 1: - if (byte != 'b') { - --i; - state = ParserState::kDefault; - } else { - inside_index++; - } - break; - case 2: - if (byte != 'j') { - --i; - state = ParserState::kDefault; - } else { - inside_index++; - } - break; - case 3: - if (PDFCharIsWhitespace(byte) || PDFCharIsDelimiter(byte)) { - FX_FILESIZE obj_pos = start_pos - m_pSyntax->m_HeaderOffset; - m_SortedOffset.insert(obj_pos); - last_obj = start_pos; - FX_FILESIZE obj_end = 0; - CPDF_Object* pObject = ParseIndirectObjectAtByStrict( - m_pDocument, obj_pos, objnum, &obj_end); - if (CPDF_Stream* pStream = ToStream(pObject)) { - if (CPDF_Dictionary* pDict = pStream->GetDict()) { - if ((pDict->KeyExist("Type")) && - (pDict->GetStringFor("Type") == "XRef" && - pDict->KeyExist("Size"))) { - CPDF_Object* pRoot = pDict->GetObjectFor("Root"); - if (pRoot && pRoot->GetDict() && - pRoot->GetDict()->GetObjectFor("Pages")) { - if (m_pTrailer) - m_pTrailer->Release(); - m_pTrailer = ToDictionary(pDict->Clone()); - } - } - } - } - - FX_FILESIZE offset = 0; - m_pSyntax->RestorePos(obj_pos); - offset = m_pSyntax->FindTag("obj", 0); - if (offset == -1) - offset = 0; - else - offset += 3; - - FX_FILESIZE nLen = obj_end - obj_pos - offset; - if ((uint32_t)nLen > size - i) { - pos = obj_end + m_pSyntax->m_HeaderOffset; - bOverFlow = true; - } else { - i += (uint32_t)nLen; - } - - if (!m_ObjectInfo.empty() && IsValidObjectNumber(objnum) && - m_ObjectInfo[objnum].pos) { - if (pObject) { - uint32_t oldgen = GetObjectGenNum(objnum); - m_ObjectInfo[objnum].pos = obj_pos; - m_ObjectInfo[objnum].gennum = gennum; - if (oldgen != gennum) - m_bVersionUpdated = true; - } - } else { - m_ObjectInfo[objnum].pos = obj_pos; - m_ObjectInfo[objnum].type = 1; - m_ObjectInfo[objnum].gennum = gennum; - } - - if (pObject) - pObject->Release(); - } - --i; - state = ParserState::kDefault; - break; - } - break; - - case ParserState::kTrailer: - if (inside_index == 7) { - if (PDFCharIsWhitespace(byte) || PDFCharIsDelimiter(byte)) { - last_trailer = pos + i - 7; - m_pSyntax->RestorePos(pos + i - m_pSyntax->m_HeaderOffset); - - CPDF_Object* pObj = m_pSyntax->GetObject(m_pDocument, 0, 0, true); - if (pObj) { - if (!pObj->IsDictionary() && !pObj->AsStream()) { - pObj->Release(); - } else { - CPDF_Stream* pStream = pObj->AsStream(); - if (CPDF_Dictionary* pTrailer = - pStream ? pStream->GetDict() : pObj->AsDictionary()) { - if (m_pTrailer) { - CPDF_Object* pRoot = pTrailer->GetObjectFor("Root"); - CPDF_Reference* pRef = ToReference(pRoot); - if (!pRoot || - (pRef && IsValidObjectNumber(pRef->GetRefObjNum()) && - m_ObjectInfo[pRef->GetRefObjNum()].pos != 0)) { - auto it = pTrailer->begin(); - while (it != pTrailer->end()) { - const CFX_ByteString& key = it->first; - CPDF_Object* pElement = it->second; - ++it; - uint32_t dwObjNum = - pElement ? pElement->GetObjNum() : 0; - if (dwObjNum) { - m_pTrailer->SetReferenceFor(key, m_pDocument, - dwObjNum); - } else { - m_pTrailer->SetFor(key, pElement->Clone()); - } - } - } - pObj->Release(); - } else { - if (pObj->IsStream()) { - m_pTrailer = ToDictionary(pTrailer->Clone()); - pObj->Release(); - } else { - m_pTrailer = pTrailer; - } - - FX_FILESIZE dwSavePos = m_pSyntax->SavePos(); - CFX_ByteString strWord = m_pSyntax->GetKeyword(); - if (!strWord.Compare("startxref")) { - bool bNumber; - CFX_ByteString bsOffset = - m_pSyntax->GetNextWord(&bNumber); - if (bNumber) - m_LastXRefOffset = FXSYS_atoi(bsOffset.c_str()); - } - m_pSyntax->RestorePos(dwSavePos); - } - } else { - pObj->Release(); - } - } - } - } - --i; - state = ParserState::kDefault; - } else if (byte == "trailer"[inside_index]) { - inside_index++; - } else { - --i; - state = ParserState::kDefault; - } - break; - - case ParserState::kXref: - if (inside_index == 4) { - last_xref = pos + i - 4; - state = ParserState::kWhitespace; - } else if (byte == "xref"[inside_index]) { - inside_index++; - } else { - --i; - state = ParserState::kDefault; - } - break; - - case ParserState::kComment: - if (PDFCharIsLineEnding(byte)) - state = ParserState::kDefault; - break; - - case ParserState::kString: - if (byte == ')') { - if (depth > 0) - depth--; - } else if (byte == '(') { - depth++; - } - - if (!depth) - state = ParserState::kDefault; - break; - - case ParserState::kHexString: - if (byte == '>' || (byte == '<' && inside_index == 1)) - state = ParserState::kDefault; - inside_index = 0; - break; - - case ParserState::kEscapedString: - if (PDFCharIsDelimiter(byte) || PDFCharIsWhitespace(byte)) { - --i; - state = ParserState::kDefault; - } - break; - - case ParserState::kEndObj: - if (PDFCharIsWhitespace(byte)) { - state = ParserState::kDefault; - } else if (byte == '%' || byte == '(' || byte == '<' || - byte == '\\') { - state = ParserState::kDefault; - --i; - } else if (inside_index == 6) { - state = ParserState::kDefault; - --i; - } else if (byte == "endobj"[inside_index]) { - inside_index++; - } - break; - } - - if (bOverFlow) { - size = 0; - break; - } - } - pos += size; - - // If the position has not changed at all or went backwards in a loop - // iteration, then break out to prevent infinite looping. - if (pos <= saved_pos) - break; - } - - if (last_xref != -1 && last_xref > last_obj) - last_trailer = last_xref; - else if (last_trailer == -1 || last_xref < last_obj) - last_trailer = m_pSyntax->m_FileLen; - - m_SortedOffset.insert(last_trailer - m_pSyntax->m_HeaderOffset); - return m_pTrailer && !m_ObjectInfo.empty(); -} - -FX_BOOL CPDF_Parser::LoadCrossRefV5(FX_FILESIZE* pos, FX_BOOL bMainXRef) { - CPDF_Object* pObject = ParseIndirectObjectAt(m_pDocument, *pos, 0); - if (!pObject) - return FALSE; - - if (m_pDocument) { - CPDF_Dictionary* pRootDict = m_pDocument->GetRoot(); - if (pRootDict && pRootDict->GetObjNum() == pObject->m_ObjNum) { - // If |pObject| has an objnum assigned then this will leak as Release() - // will early exit. - if (pObject->IsStream()) - pObject->Release(); - return FALSE; - } - if (!m_pDocument->ReplaceIndirectObjectIfHigherGeneration(pObject->m_ObjNum, - pObject)) { - return FALSE; - } - } - - CPDF_Stream* pStream = pObject->AsStream(); - if (!pStream) - return FALSE; - - CPDF_Dictionary* pDict = pStream->GetDict(); - *pos = pDict->GetIntegerFor("Prev"); - int32_t size = pDict->GetIntegerFor("Size"); - if (size < 0) { - pStream->Release(); - return FALSE; - } - - CPDF_Dictionary* pNewTrailer = ToDictionary(pDict->Clone()); - if (bMainXRef) { - m_pTrailer = pNewTrailer; - ShrinkObjectMap(size); - for (auto& it : m_ObjectInfo) - it.second.type = 0; - } else { - m_Trailers.Add(pNewTrailer); - } - - std::vector> arrIndex; - CPDF_Array* pArray = pDict->GetArrayFor("Index"); - if (pArray) { - for (size_t i = 0; i < pArray->GetCount() / 2; i++) { - CPDF_Object* pStartNumObj = pArray->GetObjectAt(i * 2); - CPDF_Object* pCountObj = pArray->GetObjectAt(i * 2 + 1); - - if (ToNumber(pStartNumObj) && ToNumber(pCountObj)) { - int nStartNum = pStartNumObj->GetInteger(); - int nCount = pCountObj->GetInteger(); - if (nStartNum >= 0 && nCount > 0) - arrIndex.push_back(std::make_pair(nStartNum, nCount)); - } - } - } - - if (arrIndex.size() == 0) - arrIndex.push_back(std::make_pair(0, size)); - - pArray = pDict->GetArrayFor("W"); - if (!pArray) { - pStream->Release(); - return FALSE; - } - - CFX_ArrayTemplate WidthArray; - FX_SAFE_UINT32 dwAccWidth = 0; - for (size_t i = 0; i < pArray->GetCount(); ++i) { - WidthArray.Add(pArray->GetIntegerAt(i)); - dwAccWidth += WidthArray[i]; - } - - if (!dwAccWidth.IsValid() || WidthArray.GetSize() < 3) { - pStream->Release(); - return FALSE; - } - - uint32_t totalWidth = dwAccWidth.ValueOrDie(); - CPDF_StreamAcc acc; - acc.LoadAllData(pStream); - - const uint8_t* pData = acc.GetData(); - uint32_t dwTotalSize = acc.GetSize(); - uint32_t segindex = 0; - for (uint32_t i = 0; i < arrIndex.size(); i++) { - int32_t startnum = arrIndex[i].first; - if (startnum < 0) - continue; - - m_dwXrefStartObjNum = - pdfium::base::checked_cast(startnum); - uint32_t count = - pdfium::base::checked_cast(arrIndex[i].second); - FX_SAFE_UINT32 dwCaculatedSize = segindex; - dwCaculatedSize += count; - dwCaculatedSize *= totalWidth; - if (!dwCaculatedSize.IsValid() || - dwCaculatedSize.ValueOrDie() > dwTotalSize) { - continue; - } - - const uint8_t* segstart = pData + segindex * totalWidth; - FX_SAFE_UINT32 dwMaxObjNum = startnum; - dwMaxObjNum += count; - uint32_t dwV5Size = m_ObjectInfo.empty() ? 0 : GetLastObjNum() + 1; - if (!dwMaxObjNum.IsValid() || dwMaxObjNum.ValueOrDie() > dwV5Size) - continue; - - for (uint32_t j = 0; j < count; j++) { - int32_t type = 1; - const uint8_t* entrystart = segstart + j * totalWidth; - if (WidthArray[0]) - type = GetVarInt(entrystart, WidthArray[0]); - - if (GetObjectType(startnum + j) == 255) { - FX_FILESIZE offset = - GetVarInt(entrystart + WidthArray[0], WidthArray[1]); - m_ObjectInfo[startnum + j].pos = offset; - m_SortedOffset.insert(offset); - continue; - } - - if (GetObjectType(startnum + j)) - continue; - - m_ObjectInfo[startnum + j].type = type; - if (type == 0) { - m_ObjectInfo[startnum + j].pos = 0; - } else { - FX_FILESIZE offset = - GetVarInt(entrystart + WidthArray[0], WidthArray[1]); - m_ObjectInfo[startnum + j].pos = offset; - if (type == 1) { - m_SortedOffset.insert(offset); - } else { - if (offset < 0 || !IsValidObjectNumber(offset)) { - pStream->Release(); - return FALSE; - } - m_ObjectInfo[offset].type = 255; - } - } - } - segindex += count; - } - pStream->Release(); - return TRUE; -} - -CPDF_Array* CPDF_Parser::GetIDArray() { - CPDF_Object* pID = m_pTrailer ? m_pTrailer->GetObjectFor("ID") : nullptr; - if (!pID) - return nullptr; - - if (CPDF_Reference* pRef = pID->AsReference()) { - pID = ParseIndirectObject(nullptr, pRef->GetRefObjNum()); - m_pTrailer->SetFor("ID", pID); - } - return ToArray(pID); -} - -uint32_t CPDF_Parser::GetRootObjNum() { - CPDF_Reference* pRef = - ToReference(m_pTrailer ? m_pTrailer->GetObjectFor("Root") : nullptr); - return pRef ? pRef->GetRefObjNum() : 0; -} - -uint32_t CPDF_Parser::GetInfoObjNum() { - CPDF_Reference* pRef = - ToReference(m_pTrailer ? m_pTrailer->GetObjectFor("Info") : nullptr); - return pRef ? pRef->GetRefObjNum() : 0; -} - -CPDF_Object* CPDF_Parser::ParseIndirectObject( - CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum) { - if (!IsValidObjectNumber(objnum)) - return nullptr; - - // Prevent circular parsing the same object. - if (pdfium::ContainsKey(m_ParsingObjNums, objnum)) - return nullptr; - - pdfium::ScopedSetInsertion local_insert(&m_ParsingObjNums, objnum); - if (GetObjectType(objnum) == 1 || GetObjectType(objnum) == 255) { - FX_FILESIZE pos = m_ObjectInfo[objnum].pos; - if (pos <= 0) - return nullptr; - return ParseIndirectObjectAt(pObjList, pos, objnum); - } - if (GetObjectType(objnum) != 2) - return nullptr; - - CPDF_StreamAcc* pObjStream = GetObjectStream(m_ObjectInfo[objnum].pos); - if (!pObjStream) - return nullptr; - - ScopedFileStream file(FX_CreateMemoryStream( - (uint8_t*)pObjStream->GetData(), (size_t)pObjStream->GetSize(), FALSE)); - CPDF_SyntaxParser syntax; - syntax.InitParser(file.get(), 0); - const int32_t offset = GetStreamFirst(pObjStream); - - // Read object numbers from |pObjStream| into a cache. - if (!pdfium::ContainsKey(m_ObjCache, pObjStream)) { - for (int32_t i = GetStreamNCount(pObjStream); i > 0; --i) { - uint32_t thisnum = syntax.GetDirectNum(); - uint32_t thisoff = syntax.GetDirectNum(); - m_ObjCache[pObjStream][thisnum] = thisoff; - } - } - - const auto it = m_ObjCache[pObjStream].find(objnum); - if (it == m_ObjCache[pObjStream].end()) - return nullptr; - - syntax.RestorePos(offset + it->second); - return syntax.GetObject(pObjList, 0, 0, true); -} - -CPDF_StreamAcc* CPDF_Parser::GetObjectStream(uint32_t objnum) { - auto it = m_ObjectStreamMap.find(objnum); - if (it != m_ObjectStreamMap.end()) - return it->second.get(); - - if (!m_pDocument) - return nullptr; - - const CPDF_Stream* pStream = - ToStream(m_pDocument->GetOrParseIndirectObject(objnum)); - if (!pStream) - return nullptr; - - CPDF_StreamAcc* pStreamAcc = new CPDF_StreamAcc; - pStreamAcc->LoadAllData(pStream); - m_ObjectStreamMap[objnum].reset(pStreamAcc); - return pStreamAcc; -} - -FX_FILESIZE CPDF_Parser::GetObjectSize(uint32_t objnum) const { - if (!IsValidObjectNumber(objnum)) - return 0; - - if (GetObjectType(objnum) == 2) - objnum = GetObjectPositionOrZero(objnum); - - if (GetObjectType(objnum) != 1 && GetObjectType(objnum) != 255) - return 0; - - FX_FILESIZE offset = GetObjectPositionOrZero(objnum); - if (offset == 0) - return 0; - - auto it = m_SortedOffset.find(offset); - if (it == m_SortedOffset.end() || ++it == m_SortedOffset.end()) - return 0; - - return *it - offset; -} - -void CPDF_Parser::GetIndirectBinary(uint32_t objnum, - uint8_t*& pBuffer, - uint32_t& size) { - pBuffer = nullptr; - size = 0; - if (!IsValidObjectNumber(objnum)) - return; - - if (GetObjectType(objnum) == 2) { - CPDF_StreamAcc* pObjStream = GetObjectStream(m_ObjectInfo[objnum].pos); - if (!pObjStream) - return; - - int32_t offset = GetStreamFirst(pObjStream); - const uint8_t* pData = pObjStream->GetData(); - uint32_t totalsize = pObjStream->GetSize(); - ScopedFileStream file( - FX_CreateMemoryStream((uint8_t*)pData, (size_t)totalsize, FALSE)); - - CPDF_SyntaxParser syntax; - syntax.InitParser(file.get(), 0); - for (int i = GetStreamNCount(pObjStream); i > 0; --i) { - uint32_t thisnum = syntax.GetDirectNum(); - uint32_t thisoff = syntax.GetDirectNum(); - if (thisnum != objnum) - continue; - - if (i == 1) { - size = totalsize - (thisoff + offset); - } else { - syntax.GetDirectNum(); // Skip nextnum. - uint32_t nextoff = syntax.GetDirectNum(); - size = nextoff - thisoff; - } - - pBuffer = FX_Alloc(uint8_t, size); - FXSYS_memcpy(pBuffer, pData + thisoff + offset, size); - return; - } - return; - } - - if (GetObjectType(objnum) != 1) - return; - - FX_FILESIZE pos = m_ObjectInfo[objnum].pos; - if (pos == 0) - return; - - FX_FILESIZE SavedPos = m_pSyntax->SavePos(); - m_pSyntax->RestorePos(pos); - - bool bIsNumber; - CFX_ByteString word = m_pSyntax->GetNextWord(&bIsNumber); - if (!bIsNumber) { - m_pSyntax->RestorePos(SavedPos); - return; - } - - uint32_t parser_objnum = FXSYS_atoui(word.c_str()); - if (parser_objnum && parser_objnum != objnum) { - m_pSyntax->RestorePos(SavedPos); - return; - } - - word = m_pSyntax->GetNextWord(&bIsNumber); - if (!bIsNumber) { - m_pSyntax->RestorePos(SavedPos); - return; - } - - if (m_pSyntax->GetKeyword() != "obj") { - m_pSyntax->RestorePos(SavedPos); - return; - } - - auto it = m_SortedOffset.find(pos); - if (it == m_SortedOffset.end() || ++it == m_SortedOffset.end()) { - m_pSyntax->RestorePos(SavedPos); - return; - } - - FX_FILESIZE nextoff = *it; - FX_BOOL bNextOffValid = FALSE; - if (nextoff != pos) { - m_pSyntax->RestorePos(nextoff); - word = m_pSyntax->GetNextWord(&bIsNumber); - if (word == "xref") { - bNextOffValid = TRUE; - } else if (bIsNumber) { - word = m_pSyntax->GetNextWord(&bIsNumber); - if (bIsNumber && m_pSyntax->GetKeyword() == "obj") { - bNextOffValid = TRUE; - } - } - } - - if (!bNextOffValid) { - m_pSyntax->RestorePos(pos); - while (1) { - if (m_pSyntax->GetKeyword() == "endobj") - break; - - if (m_pSyntax->SavePos() == m_pSyntax->m_FileLen) - break; - } - nextoff = m_pSyntax->SavePos(); - } - - size = (uint32_t)(nextoff - pos); - pBuffer = FX_Alloc(uint8_t, size); - m_pSyntax->RestorePos(pos); - m_pSyntax->ReadBlock(pBuffer, size); - m_pSyntax->RestorePos(SavedPos); -} - -CPDF_Object* CPDF_Parser::ParseIndirectObjectAt( - CPDF_IndirectObjectHolder* pObjList, - FX_FILESIZE pos, - uint32_t objnum) { - FX_FILESIZE SavedPos = m_pSyntax->SavePos(); - m_pSyntax->RestorePos(pos); - bool bIsNumber; - CFX_ByteString word = m_pSyntax->GetNextWord(&bIsNumber); - if (!bIsNumber) { - m_pSyntax->RestorePos(SavedPos); - return nullptr; - } - - FX_FILESIZE objOffset = m_pSyntax->SavePos(); - objOffset -= word.GetLength(); - uint32_t parser_objnum = FXSYS_atoui(word.c_str()); - if (objnum && parser_objnum != objnum) { - m_pSyntax->RestorePos(SavedPos); - return nullptr; - } - - word = m_pSyntax->GetNextWord(&bIsNumber); - if (!bIsNumber) { - m_pSyntax->RestorePos(SavedPos); - return nullptr; - } - - uint32_t parser_gennum = FXSYS_atoui(word.c_str()); - if (m_pSyntax->GetKeyword() != "obj") { - m_pSyntax->RestorePos(SavedPos); - return nullptr; - } - - CPDF_Object* pObj = - m_pSyntax->GetObject(pObjList, objnum, parser_gennum, true); - m_pSyntax->SavePos(); - - CFX_ByteString bsWord = m_pSyntax->GetKeyword(); - if (bsWord == "endobj") - m_pSyntax->SavePos(); - - m_pSyntax->RestorePos(SavedPos); - if (pObj) { - if (!objnum) - pObj->m_ObjNum = parser_objnum; - pObj->m_GenNum = parser_gennum; - } - return pObj; -} - -CPDF_Object* CPDF_Parser::ParseIndirectObjectAtByStrict( - CPDF_IndirectObjectHolder* pObjList, - FX_FILESIZE pos, - uint32_t objnum, - FX_FILESIZE* pResultPos) { - FX_FILESIZE SavedPos = m_pSyntax->SavePos(); - m_pSyntax->RestorePos(pos); - - bool bIsNumber; - CFX_ByteString word = m_pSyntax->GetNextWord(&bIsNumber); - if (!bIsNumber) { - m_pSyntax->RestorePos(SavedPos); - return nullptr; - } - - uint32_t parser_objnum = FXSYS_atoui(word.c_str()); - if (objnum && parser_objnum != objnum) { - m_pSyntax->RestorePos(SavedPos); - return nullptr; - } - - word = m_pSyntax->GetNextWord(&bIsNumber); - if (!bIsNumber) { - m_pSyntax->RestorePos(SavedPos); - return nullptr; - } - - uint32_t gennum = FXSYS_atoui(word.c_str()); - if (m_pSyntax->GetKeyword() != "obj") { - m_pSyntax->RestorePos(SavedPos); - return nullptr; - } - - CPDF_Object* pObj = m_pSyntax->GetObjectForStrict(pObjList, objnum, gennum); - if (pResultPos) - *pResultPos = m_pSyntax->m_Pos; - - m_pSyntax->RestorePos(SavedPos); - return pObj; -} - -CPDF_Dictionary* CPDF_Parser::LoadTrailerV4() { - if (m_pSyntax->GetKeyword() != "trailer") - return nullptr; - - std::unique_ptr> pObj( - m_pSyntax->GetObject(m_pDocument, 0, 0, true)); - if (!ToDictionary(pObj.get())) - return nullptr; - return pObj.release()->AsDictionary(); -} - -uint32_t CPDF_Parser::GetPermissions() const { - if (!m_pSecurityHandler) - return 0xFFFFFFFF; - - uint32_t dwPermission = m_pSecurityHandler->GetPermissions(); - if (m_pEncryptDict && m_pEncryptDict->GetStringFor("Filter") == "Standard") { - // See PDF Reference 1.7, page 123, table 3.20. - dwPermission &= 0xFFFFFFFC; - dwPermission |= 0xFFFFF0C0; - } - return dwPermission; -} - -FX_BOOL CPDF_Parser::IsLinearizedFile(IFX_FileRead* pFileAccess, - uint32_t offset) { - m_pSyntax->InitParser(pFileAccess, offset); - m_pSyntax->RestorePos(m_pSyntax->m_HeaderOffset + 9); - - FX_FILESIZE SavedPos = m_pSyntax->SavePos(); - bool bIsNumber; - CFX_ByteString word = m_pSyntax->GetNextWord(&bIsNumber); - if (!bIsNumber) - return FALSE; - - uint32_t objnum = FXSYS_atoui(word.c_str()); - word = m_pSyntax->GetNextWord(&bIsNumber); - if (!bIsNumber) - return FALSE; - - uint32_t gennum = FXSYS_atoui(word.c_str()); - if (m_pSyntax->GetKeyword() != "obj") { - m_pSyntax->RestorePos(SavedPos); - return FALSE; - } - - m_pLinearized = m_pSyntax->GetObject(nullptr, objnum, gennum, true); - if (!m_pLinearized) - return FALSE; - - CPDF_Dictionary* pDict = m_pLinearized->GetDict(); - if (pDict && pDict->GetObjectFor("Linearized")) { - m_pSyntax->GetNextWord(nullptr); - - CPDF_Object* pLen = pDict->GetObjectFor("L"); - if (!pLen) { - m_pLinearized->Release(); - m_pLinearized = nullptr; - return FALSE; - } - - if (pLen->GetInteger() != (int)pFileAccess->GetSize()) - return FALSE; - - if (CPDF_Number* pNo = ToNumber(pDict->GetObjectFor("P"))) - m_dwFirstPageNo = pNo->GetInteger(); - - if (CPDF_Number* pTable = ToNumber(pDict->GetObjectFor("T"))) - m_LastXRefOffset = pTable->GetInteger(); - - return TRUE; - } - m_pLinearized->Release(); - m_pLinearized = nullptr; - return FALSE; -} - -CPDF_Parser::Error CPDF_Parser::StartLinearizedParse(IFX_FileRead* pFileAccess, - CPDF_Document* pDocument) { - ASSERT(!m_bHasParsed); - - m_bXRefStream = FALSE; - m_LastXRefOffset = 0; - m_bOwnFileRead = true; - - int32_t offset = GetHeaderOffset(pFileAccess); - if (offset == -1) - return FORMAT_ERROR; - - if (!IsLinearizedFile(pFileAccess, offset)) { - m_pSyntax->m_pFileAccess = nullptr; - return StartParse(pFileAccess, std::move(pDocument)); - } - m_bHasParsed = true; - m_pDocument = pDocument; - - FX_FILESIZE dwFirstXRefOffset = m_pSyntax->SavePos(); - - FX_BOOL bXRefRebuilt = FALSE; - FX_BOOL bLoadV4 = LoadCrossRefV4(dwFirstXRefOffset, 0, FALSE); - if (!bLoadV4 && !LoadCrossRefV5(&dwFirstXRefOffset, TRUE)) { - if (!RebuildCrossRef()) - return FORMAT_ERROR; - - bXRefRebuilt = TRUE; - m_LastXRefOffset = 0; - } - - if (bLoadV4) { - m_pTrailer = LoadTrailerV4(); - if (!m_pTrailer) - return SUCCESS; - - int32_t xrefsize = GetDirectInteger(m_pTrailer, "Size"); - if (xrefsize > 0) - ShrinkObjectMap(xrefsize); - } - - Error eRet = SetEncryptHandler(); - if (eRet != SUCCESS) - return eRet; - - m_pDocument->LoadLinearizedDoc(m_pLinearized->GetDict()); - if (!m_pDocument->GetRoot() || m_pDocument->GetPageCount() == 0) { - if (bXRefRebuilt) - return FORMAT_ERROR; - - ReleaseEncryptHandler(); - if (!RebuildCrossRef()) - return FORMAT_ERROR; - - eRet = SetEncryptHandler(); - if (eRet != SUCCESS) - return eRet; - - m_pDocument->LoadLinearizedDoc(m_pLinearized->GetDict()); - if (!m_pDocument->GetRoot()) - return FORMAT_ERROR; - } - - if (GetRootObjNum() == 0) { - ReleaseEncryptHandler(); - if (!RebuildCrossRef() || GetRootObjNum() == 0) - return FORMAT_ERROR; - - eRet = SetEncryptHandler(); - if (eRet != SUCCESS) - return eRet; - } - - if (m_pSecurityHandler && m_pSecurityHandler->IsMetadataEncrypted()) { - if (CPDF_Reference* pMetadata = - ToReference(m_pDocument->GetRoot()->GetObjectFor("Metadata"))) - m_pSyntax->m_MetadataObjnum = pMetadata->GetRefObjNum(); - } - return SUCCESS; -} - -FX_BOOL CPDF_Parser::LoadLinearizedAllCrossRefV5(FX_FILESIZE xrefpos) { - if (!LoadCrossRefV5(&xrefpos, FALSE)) - return FALSE; - - std::set seen_xrefpos; - while (xrefpos) { - seen_xrefpos.insert(xrefpos); - if (!LoadCrossRefV5(&xrefpos, FALSE)) - return FALSE; - - // Check for circular references. - if (pdfium::ContainsKey(seen_xrefpos, xrefpos)) - return FALSE; - } - m_ObjectStreamMap.clear(); - m_bXRefStream = TRUE; - return TRUE; -} - -CPDF_Parser::Error CPDF_Parser::LoadLinearizedMainXRefTable() { - uint32_t dwSaveMetadataObjnum = m_pSyntax->m_MetadataObjnum; - m_pSyntax->m_MetadataObjnum = 0; - if (m_pTrailer) { - m_pTrailer->Release(); - m_pTrailer = nullptr; - } - - m_pSyntax->RestorePos(m_LastXRefOffset - m_pSyntax->m_HeaderOffset); - uint8_t ch = 0; - uint32_t dwCount = 0; - m_pSyntax->GetNextChar(ch); - while (PDFCharIsWhitespace(ch)) { - ++dwCount; - if (m_pSyntax->m_FileLen >= - (FX_FILESIZE)(m_pSyntax->SavePos() + m_pSyntax->m_HeaderOffset)) { - break; - } - m_pSyntax->GetNextChar(ch); - } - m_LastXRefOffset += dwCount; - m_ObjectStreamMap.clear(); - m_ObjCache.clear(); - - if (!LoadLinearizedAllCrossRefV4(m_LastXRefOffset, m_dwXrefStartObjNum) && - !LoadLinearizedAllCrossRefV5(m_LastXRefOffset)) { - m_LastXRefOffset = 0; - m_pSyntax->m_MetadataObjnum = dwSaveMetadataObjnum; - return FORMAT_ERROR; - } - - m_pSyntax->m_MetadataObjnum = dwSaveMetadataObjnum; - return SUCCESS; -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_parser.h b/core/fpdfapi/fpdf_parser/cpdf_parser.h deleted file mode 100644 index 254b8b0274..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_parser.h +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_PARSER_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_PARSER_H_ - -#include -#include -#include - -#include "core/fxcrt/fx_basic.h" - -class CPDF_Array; -class CPDF_CryptoHandler; -class CPDF_Dictionary; -class CPDF_Document; -class CPDF_IndirectObjectHolder; -class CPDF_Object; -class CPDF_SecurityHandler; -class CPDF_StreamAcc; -class CPDF_SyntaxParser; -class IFX_FileRead; - -class CPDF_Parser { - public: - enum Error { - SUCCESS = 0, - FILE_ERROR, - FORMAT_ERROR, - PASSWORD_ERROR, - HANDLER_ERROR - }; - - // A limit on the maximum object number in the xref table. Theoretical limits - // are higher, but this may be large enough in practice. - static const uint32_t kMaxObjectNumber = 1048576; - - CPDF_Parser(); - ~CPDF_Parser(); - - Error StartParse(IFX_FileRead* pFile, CPDF_Document* pDocument); - Error StartLinearizedParse(IFX_FileRead* pFile, CPDF_Document* pDocument); - - void SetPassword(const FX_CHAR* password) { m_Password = password; } - CFX_ByteString GetPassword() { return m_Password; } - CPDF_Dictionary* GetTrailer() const { return m_pTrailer; } - FX_FILESIZE GetLastXRefOffset() const { return m_LastXRefOffset; } - - uint32_t GetPermissions() const; - uint32_t GetRootObjNum(); - uint32_t GetInfoObjNum(); - CPDF_Array* GetIDArray(); - - CPDF_Dictionary* GetEncryptDict() const { return m_pEncryptDict; } - - CPDF_Object* ParseIndirectObject(CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum); - - uint32_t GetLastObjNum() const; - bool IsValidObjectNumber(uint32_t objnum) const; - FX_FILESIZE GetObjectPositionOrZero(uint32_t objnum) const; - uint8_t GetObjectType(uint32_t objnum) const; - uint16_t GetObjectGenNum(uint32_t objnum) const; - bool IsVersionUpdated() const { return m_bVersionUpdated; } - bool IsObjectFreeOrNull(uint32_t objnum) const; - CPDF_CryptoHandler* GetCryptoHandler(); - IFX_FileRead* GetFileAccess() const; - - FX_FILESIZE GetObjectOffset(uint32_t objnum) const; - FX_FILESIZE GetObjectSize(uint32_t objnum) const; - - void GetIndirectBinary(uint32_t objnum, uint8_t*& pBuffer, uint32_t& size); - int GetFileVersion() const { return m_FileVersion; } - FX_BOOL IsXRefStream() const { return m_bXRefStream; } - - CPDF_Object* ParseIndirectObjectAt(CPDF_IndirectObjectHolder* pObjList, - FX_FILESIZE pos, - uint32_t objnum); - - CPDF_Object* ParseIndirectObjectAtByStrict( - CPDF_IndirectObjectHolder* pObjList, - FX_FILESIZE pos, - uint32_t objnum, - FX_FILESIZE* pResultPos); - - uint32_t GetFirstPageNo() const { return m_dwFirstPageNo; } - - protected: - struct ObjectInfo { - ObjectInfo() : pos(0), type(0), gennum(0) {} - - FX_FILESIZE pos; - uint8_t type; - uint16_t gennum; - }; - - std::unique_ptr m_pSyntax; - std::map m_ObjectInfo; - - bool LoadCrossRefV4(FX_FILESIZE pos, FX_FILESIZE streampos, FX_BOOL bSkip); - FX_BOOL RebuildCrossRef(); - - private: - friend class CPDF_DataAvail; - - enum class ParserState { - kDefault, - kComment, - kWhitespace, - kString, - kHexString, - kEscapedString, - kXref, - kObjNum, - kPostObjNum, - kGenNum, - kPostGenNum, - kTrailer, - kBeginObj, - kEndObj - }; - - CPDF_Object* ParseDirect(CPDF_Object* pObj); - FX_BOOL LoadAllCrossRefV4(FX_FILESIZE pos); - FX_BOOL LoadAllCrossRefV5(FX_FILESIZE pos); - FX_BOOL LoadCrossRefV5(FX_FILESIZE* pos, FX_BOOL bMainXRef); - CPDF_Dictionary* LoadTrailerV4(); - Error SetEncryptHandler(); - void ReleaseEncryptHandler(); - FX_BOOL LoadLinearizedAllCrossRefV4(FX_FILESIZE pos, uint32_t dwObjCount); - FX_BOOL LoadLinearizedCrossRefV4(FX_FILESIZE pos, uint32_t dwObjCount); - FX_BOOL LoadLinearizedAllCrossRefV5(FX_FILESIZE pos); - Error LoadLinearizedMainXRefTable(); - CPDF_StreamAcc* GetObjectStream(uint32_t number); - FX_BOOL IsLinearizedFile(IFX_FileRead* pFileAccess, uint32_t offset); - void SetEncryptDictionary(CPDF_Dictionary* pDict); - void ShrinkObjectMap(uint32_t size); - // A simple check whether the cross reference table matches with - // the objects. - bool VerifyCrossRefV4(); - - CPDF_Document* m_pDocument; // not owned - bool m_bHasParsed; - bool m_bOwnFileRead; - int m_FileVersion; - CPDF_Dictionary* m_pTrailer; - CPDF_Dictionary* m_pEncryptDict; - FX_FILESIZE m_LastXRefOffset; - FX_BOOL m_bXRefStream; - std::unique_ptr m_pSecurityHandler; - CFX_ByteString m_Password; - std::set m_SortedOffset; - CFX_ArrayTemplate m_Trailers; - bool m_bVersionUpdated; - CPDF_Object* m_pLinearized; - uint32_t m_dwFirstPageNo; - uint32_t m_dwXrefStartObjNum; - - // A map of object numbers to indirect streams. Map owns the streams. - std::map> m_ObjectStreamMap; - - // Mapping of object numbers to offsets. The offsets are relative to the first - // object in the stream. - using StreamObjectCache = std::map; - - // Mapping of streams to their object caches. This is valid as long as the - // streams in |m_ObjectStreamMap| are valid. - std::map m_ObjCache; - - // All indirect object numbers that are being parsed. - std::set m_ParsingObjNums; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_PARSER_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_parser_embeddertest.cpp b/core/fpdfapi/fpdf_parser/cpdf_parser_embeddertest.cpp deleted file mode 100644 index f523d6b31b..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_parser_embeddertest.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2015 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. - -#include "public/fpdf_text.h" -#include "testing/embedder_test.h" -#include "testing/gtest/include/gtest/gtest.h" - -class CPDFParserEmbeddertest : public EmbedderTest {}; - -TEST_F(CPDFParserEmbeddertest, LoadError_454695) { - // Test a dictionary with hex string instead of correct content. - // Verify that the defective pdf shouldn't be opened correctly. - EXPECT_FALSE(OpenDocument("bug_454695.pdf")); -} - -TEST_F(CPDFParserEmbeddertest, Bug_481363) { - // Test colorspace object with malformed dictionary. - EXPECT_TRUE(OpenDocument("bug_481363.pdf")); - FPDF_PAGE page = LoadPage(0); - EXPECT_NE(nullptr, page); - UnloadPage(page); -} - -TEST_F(CPDFParserEmbeddertest, Bug_544880) { - // Test self referencing /Pages object. - EXPECT_TRUE(OpenDocument("bug_544880.pdf")); - // Shouldn't crash. We don't check the return value here because we get the - // the count from the "/Count 1" in the testcase (at the time of writing) - // rather than the actual count (0). - (void)GetPageCount(); -} - -TEST_F(CPDFParserEmbeddertest, Feature_Linearized_Loading) { - EXPECT_TRUE(OpenDocument("feature_linearized_loading.pdf", nullptr, true)); -} - -TEST_F(CPDFParserEmbeddertest, Bug_325a) { - EXPECT_FALSE(OpenDocument("bug_325_a.pdf")); -} - -TEST_F(CPDFParserEmbeddertest, Bug_325b) { - EXPECT_FALSE(OpenDocument("bug_325_b.pdf")); -} - -TEST_F(CPDFParserEmbeddertest, Bug_602650) { - // Test the case that cross reference entries, which are well formed, - // but do not match with the objects. - EXPECT_TRUE(OpenDocument("bug_602650.pdf")); - FPDF_PAGE page = LoadPage(0); - EXPECT_NE(nullptr, page); - FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page); - EXPECT_NE(nullptr, text_page); - // The page should not be blank. - EXPECT_LT(0, FPDFText_CountChars(text_page)); - - FPDFText_ClosePage(text_page); - UnloadPage(page); -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_parser_unittest.cpp b/core/fpdfapi/fpdf_parser/cpdf_parser_unittest.cpp deleted file mode 100644 index 9c1de09eb1..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_parser_unittest.cpp +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2015 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. - -#include -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h" -#include "core/fxcrt/fx_ext.h" -#include "core/fxcrt/fx_stream.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/utils/path_service.h" - -// Provide a way to read test data from a buffer instead of a file. -class CFX_TestBufferRead : public IFX_FileRead { - public: - CFX_TestBufferRead(const unsigned char* buffer_in, size_t buf_size) - : buffer_(buffer_in), total_size_(buf_size) {} - - // IFX_Stream - void Release() override { delete this; } - - // IFX_FileRead - FX_BOOL ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override { - if (offset < 0 || offset + size > total_size_) { - return FALSE; - } - - memcpy(buffer, buffer_ + offset, size); - return TRUE; - } - FX_FILESIZE GetSize() override { return (FX_FILESIZE)total_size_; }; - - protected: - const unsigned char* buffer_; - size_t total_size_; -}; - -// A wrapper class to help test member functions of CPDF_Parser. -class CPDF_TestParser : public CPDF_Parser { - public: - CPDF_TestParser() {} - ~CPDF_TestParser() {} - - // Setup reading from a file and initial states. - bool InitTestFromFile(const FX_CHAR* path) { - IFX_FileRead* pFileAccess = FX_CreateFileRead(path); - if (!pFileAccess) - return false; - - // For the test file, the header is set at the beginning. - m_pSyntax->InitParser(pFileAccess, 0); - return true; - } - - // Setup reading from a buffer and initial states. - bool InitTestFromBuffer(const unsigned char* buffer, size_t len) { - CFX_TestBufferRead* buffer_reader = new CFX_TestBufferRead(buffer, len); - - // For the test file, the header is set at the beginning. - m_pSyntax->InitParser(buffer_reader, 0); - return true; - } - - private: - // Add test cases here as private friend so that protected members in - // CPDF_Parser can be accessed by test cases. - // Need to access RebuildCrossRef. - FRIEND_TEST(cpdf_parser, RebuildCrossRefCorrectly); - FRIEND_TEST(cpdf_parser, RebuildCrossRefFailed); - // Need to access LoadCrossRefV4. - FRIEND_TEST(cpdf_parser, LoadCrossRefV4); -}; - -TEST(cpdf_parser, RebuildCrossRefCorrectly) { - CPDF_TestParser parser; - std::string test_file; - ASSERT_TRUE(PathService::GetTestFilePath("parser_rebuildxref_correct.pdf", - &test_file)); - ASSERT_TRUE(parser.InitTestFromFile(test_file.c_str())) << test_file; - - ASSERT_TRUE(parser.RebuildCrossRef()); - const FX_FILESIZE offsets[] = {0, 15, 61, 154, 296, 374, 450}; - const uint16_t versions[] = {0, 0, 2, 4, 6, 8, 0}; - for (size_t i = 0; i < FX_ArraySize(offsets); ++i) - EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos); - for (size_t i = 0; i < FX_ArraySize(versions); ++i) - EXPECT_EQ(versions[i], parser.m_ObjectInfo[i].gennum); -} - -TEST(cpdf_parser, RebuildCrossRefFailed) { - CPDF_TestParser parser; - std::string test_file; - ASSERT_TRUE(PathService::GetTestFilePath( - "parser_rebuildxref_error_notrailer.pdf", &test_file)); - ASSERT_TRUE(parser.InitTestFromFile(test_file.c_str())) << test_file; - - ASSERT_FALSE(parser.RebuildCrossRef()); -} - -TEST(cpdf_parser, LoadCrossRefV4) { - { - const unsigned char xref_table[] = - "xref \n" - "0 6 \n" - "0000000003 65535 f \n" - "0000000017 00000 n \n" - "0000000081 00000 n \n" - "0000000000 00007 f \n" - "0000000331 00000 n \n" - "0000000409 00000 n \n" - "trail"; // Needed to end cross ref table reading. - CPDF_TestParser parser; - ASSERT_TRUE( - parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table))); - - ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, FALSE)); - const FX_FILESIZE offsets[] = {0, 17, 81, 0, 331, 409}; - const uint8_t types[] = {0, 1, 1, 0, 1, 1}; - for (size_t i = 0; i < FX_ArraySize(offsets); ++i) { - EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos); - EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type); - } - } - { - const unsigned char xref_table[] = - "xref \n" - "0 1 \n" - "0000000000 65535 f \n" - "3 1 \n" - "0000025325 00000 n \n" - "8 2 \n" - "0000025518 00002 n \n" - "0000025635 00000 n \n" - "12 1 \n" - "0000025777 00000 n \n" - "trail"; // Needed to end cross ref table reading. - CPDF_TestParser parser; - ASSERT_TRUE( - parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table))); - - ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, FALSE)); - const FX_FILESIZE offsets[] = {0, 0, 0, 25325, 0, 0, 0, - 0, 25518, 25635, 0, 0, 25777}; - const uint8_t types[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1}; - for (size_t i = 0; i < FX_ArraySize(offsets); ++i) { - EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos); - EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type); - } - } - { - const unsigned char xref_table[] = - "xref \n" - "0 1 \n" - "0000000000 65535 f \n" - "3 1 \n" - "0000025325 00000 n \n" - "8 2 \n" - "0000000000 65535 f \n" - "0000025635 00000 n \n" - "12 1 \n" - "0000025777 00000 n \n" - "trail"; // Needed to end cross ref table reading. - CPDF_TestParser parser; - ASSERT_TRUE( - parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table))); - - ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, FALSE)); - const FX_FILESIZE offsets[] = {0, 0, 0, 25325, 0, 0, 0, - 0, 0, 25635, 0, 0, 25777}; - const uint8_t types[] = {0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1}; - for (size_t i = 0; i < FX_ArraySize(offsets); ++i) { - EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos); - EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type); - } - } - { - const unsigned char xref_table[] = - "xref \n" - "0 7 \n" - "0000000002 65535 f \n" - "0000000023 00000 n \n" - "0000000003 65535 f \n" - "0000000004 65535 f \n" - "0000000000 65535 f \n" - "0000000045 00000 n \n" - "0000000179 00000 n \n" - "trail"; // Needed to end cross ref table reading. - CPDF_TestParser parser; - ASSERT_TRUE( - parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table))); - - ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, FALSE)); - const FX_FILESIZE offsets[] = {0, 23, 0, 0, 0, 45, 179}; - const uint8_t types[] = {0, 1, 0, 0, 0, 1, 1}; - for (size_t i = 0; i < FX_ArraySize(offsets); ++i) { - EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos); - EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type); - } - } -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_reference.cpp b/core/fpdfapi/fpdf_parser/cpdf_reference.cpp deleted file mode 100644 index 4f826dc86c..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_reference.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" - -#include "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h" -#include "third_party/base/stl_util.h" - -CPDF_Reference::CPDF_Reference(CPDF_IndirectObjectHolder* pDoc, int objnum) - : m_pObjList(pDoc), m_RefObjNum(objnum) {} - -CPDF_Reference::~CPDF_Reference() {} - -CPDF_Object::Type CPDF_Reference::GetType() const { - return REFERENCE; -} - -CFX_ByteString CPDF_Reference::GetString() const { - CPDF_Object* obj = SafeGetDirect(); - return obj ? obj->GetString() : CFX_ByteString(); -} - -FX_FLOAT CPDF_Reference::GetNumber() const { - CPDF_Object* obj = SafeGetDirect(); - return obj ? obj->GetNumber() : 0; -} - -int CPDF_Reference::GetInteger() const { - CPDF_Object* obj = SafeGetDirect(); - return obj ? obj->GetInteger() : 0; -} - -CPDF_Dictionary* CPDF_Reference::GetDict() const { - CPDF_Object* obj = SafeGetDirect(); - return obj ? obj->GetDict() : nullptr; -} - -bool CPDF_Reference::IsReference() const { - return true; -} - -CPDF_Reference* CPDF_Reference::AsReference() { - return this; -} - -const CPDF_Reference* CPDF_Reference::AsReference() const { - return this; -} - -CPDF_Object* CPDF_Reference::Clone() const { - return CloneObjectNonCyclic(false); -} - -CPDF_Object* CPDF_Reference::CloneNonCyclic( - bool bDirect, - std::set* pVisited) const { - pVisited->insert(this); - if (bDirect) { - auto* pDirect = GetDirect(); - return pDirect && !pdfium::ContainsKey(*pVisited, pDirect) - ? pDirect->CloneNonCyclic(true, pVisited) - : nullptr; - } - return new CPDF_Reference(m_pObjList, m_RefObjNum); -} - -CPDF_Object* CPDF_Reference::SafeGetDirect() const { - CPDF_Object* obj = GetDirect(); - return (obj && !obj->IsReference()) ? obj : nullptr; -} - -void CPDF_Reference::SetRef(CPDF_IndirectObjectHolder* pDoc, uint32_t objnum) { - m_pObjList = pDoc; - m_RefObjNum = objnum; -} - -CPDF_Object* CPDF_Reference::GetDirect() const { - return m_pObjList ? m_pObjList->GetOrParseIndirectObject(m_RefObjNum) - : nullptr; -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_reference.h b/core/fpdfapi/fpdf_parser/cpdf_reference.h deleted file mode 100644 index 1322b97c6f..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_reference.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_REFERENCE_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_REFERENCE_H_ - -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" - -class CPDF_IndirectObjectHolder; - -class CPDF_Reference : public CPDF_Object { - public: - CPDF_Reference(CPDF_IndirectObjectHolder* pDoc, int objnum); - - // CPDF_Object. - Type GetType() const override; - CPDF_Object* Clone() const override; - CPDF_Object* GetDirect() const override; - CFX_ByteString GetString() const override; - FX_FLOAT GetNumber() const override; - int GetInteger() const override; - CPDF_Dictionary* GetDict() const override; - bool IsReference() const override; - CPDF_Reference* AsReference() override; - const CPDF_Reference* AsReference() const override; - - CPDF_IndirectObjectHolder* GetObjList() const { return m_pObjList; } - uint32_t GetRefObjNum() const { return m_RefObjNum; } - - void SetRef(CPDF_IndirectObjectHolder* pDoc, uint32_t objnum); - - protected: - ~CPDF_Reference() override; - - CPDF_Object* CloneNonCyclic( - bool bDirect, - std::set* pVisited) const override; - - CPDF_Object* SafeGetDirect() const; - - CPDF_IndirectObjectHolder* m_pObjList; - uint32_t m_RefObjNum; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_REFERENCE_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_security_handler.cpp b/core/fpdfapi/fpdf_parser/cpdf_security_handler.cpp deleted file mode 100644 index 2a57daab3e..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_security_handler.cpp +++ /dev/null @@ -1,699 +0,0 @@ -// 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_security_handler.h" - -#include - -#include "core/fdrm/crypto/fx_crypt.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" - -namespace { - -const uint8_t defpasscode[32] = { - 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, - 0x56, 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, - 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a}; - -void CalcEncryptKey(CPDF_Dictionary* pEncrypt, - const uint8_t* password, - uint32_t pass_size, - uint8_t* key, - int keylen, - FX_BOOL bIgnoreMeta, - CPDF_Array* pIdArray) { - int revision = pEncrypt->GetIntegerFor("R"); - uint8_t passcode[32]; - for (uint32_t i = 0; i < 32; i++) { - passcode[i] = i < pass_size ? password[i] : defpasscode[i - pass_size]; - } - uint8_t md5[100]; - CRYPT_MD5Start(md5); - CRYPT_MD5Update(md5, passcode, 32); - CFX_ByteString okey = pEncrypt->GetStringFor("O"); - CRYPT_MD5Update(md5, (uint8_t*)okey.c_str(), okey.GetLength()); - uint32_t perm = pEncrypt->GetIntegerFor("P"); - CRYPT_MD5Update(md5, (uint8_t*)&perm, 4); - if (pIdArray) { - CFX_ByteString id = pIdArray->GetStringAt(0); - CRYPT_MD5Update(md5, (uint8_t*)id.c_str(), id.GetLength()); - } - if (!bIgnoreMeta && revision >= 3 && - !pEncrypt->GetIntegerFor("EncryptMetadata", 1)) { - uint32_t tag = (uint32_t)-1; - CRYPT_MD5Update(md5, (uint8_t*)&tag, 4); - } - uint8_t digest[16]; - CRYPT_MD5Finish(md5, digest); - uint32_t copy_len = keylen; - if (copy_len > sizeof(digest)) { - copy_len = sizeof(digest); - } - if (revision >= 3) { - for (int i = 0; i < 50; i++) { - CRYPT_MD5Generate(digest, copy_len, digest); - } - } - FXSYS_memset(key, 0, keylen); - FXSYS_memcpy(key, digest, copy_len); -} - -} // namespace - -CPDF_SecurityHandler::CPDF_SecurityHandler() - : m_Version(0), - m_Revision(0), - m_pParser(nullptr), - m_pEncryptDict(nullptr), - m_Permissions(0), - m_Cipher(FXCIPHER_NONE), - m_KeyLen(0), - m_bOwnerUnlocked(false) {} - -CPDF_SecurityHandler::~CPDF_SecurityHandler() {} - -CPDF_CryptoHandler* CPDF_SecurityHandler::CreateCryptoHandler() { - return new CPDF_CryptoHandler; -} - -FX_BOOL CPDF_SecurityHandler::OnInit(CPDF_Parser* pParser, - CPDF_Dictionary* pEncryptDict) { - m_pParser = pParser; - if (!LoadDict(pEncryptDict)) { - return FALSE; - } - if (m_Cipher == FXCIPHER_NONE) { - return TRUE; - } - return CheckSecurity(m_KeyLen); -} - -FX_BOOL CPDF_SecurityHandler::CheckSecurity(int32_t key_len) { - CFX_ByteString password = m_pParser->GetPassword(); - if (!password.IsEmpty() && - CheckPassword(password.raw_str(), password.GetLength(), TRUE, - m_EncryptKey, key_len)) { - m_bOwnerUnlocked = true; - return TRUE; - } - return CheckPassword(password.raw_str(), password.GetLength(), FALSE, - m_EncryptKey, key_len); -} - -uint32_t CPDF_SecurityHandler::GetPermissions() { - return m_bOwnerUnlocked ? 0xFFFFFFFF : m_Permissions; -} - -static FX_BOOL LoadCryptInfo(CPDF_Dictionary* pEncryptDict, - const CFX_ByteString& name, - int& cipher, - int& keylen) { - int Version = pEncryptDict->GetIntegerFor("V"); - cipher = FXCIPHER_RC4; - keylen = 0; - if (Version >= 4) { - CPDF_Dictionary* pCryptFilters = pEncryptDict->GetDictFor("CF"); - if (!pCryptFilters) { - return FALSE; - } - if (name == "Identity") { - cipher = FXCIPHER_NONE; - } else { - CPDF_Dictionary* pDefFilter = pCryptFilters->GetDictFor(name); - if (!pDefFilter) { - return FALSE; - } - int nKeyBits = 0; - if (Version == 4) { - nKeyBits = pDefFilter->GetIntegerFor("Length", 0); - if (nKeyBits == 0) { - nKeyBits = pEncryptDict->GetIntegerFor("Length", 128); - } - } else { - nKeyBits = pEncryptDict->GetIntegerFor("Length", 256); - } - if (nKeyBits < 40) { - nKeyBits *= 8; - } - keylen = nKeyBits / 8; - CFX_ByteString cipher_name = pDefFilter->GetStringFor("CFM"); - if (cipher_name == "AESV2" || cipher_name == "AESV3") { - cipher = FXCIPHER_AES; - } - } - } else { - keylen = Version > 1 ? pEncryptDict->GetIntegerFor("Length", 40) / 8 : 5; - } - if (keylen > 32 || keylen < 0) { - return FALSE; - } - return TRUE; -} - -FX_BOOL CPDF_SecurityHandler::LoadDict(CPDF_Dictionary* pEncryptDict) { - m_pEncryptDict = pEncryptDict; - m_Version = pEncryptDict->GetIntegerFor("V"); - m_Revision = pEncryptDict->GetIntegerFor("R"); - m_Permissions = pEncryptDict->GetIntegerFor("P", -1); - if (m_Version < 4) - return LoadCryptInfo(pEncryptDict, CFX_ByteString(), m_Cipher, m_KeyLen); - - CFX_ByteString stmf_name = pEncryptDict->GetStringFor("StmF"); - CFX_ByteString strf_name = pEncryptDict->GetStringFor("StrF"); - if (stmf_name != strf_name) - return FALSE; - - return LoadCryptInfo(pEncryptDict, strf_name, m_Cipher, m_KeyLen); -} - -FX_BOOL CPDF_SecurityHandler::LoadDict(CPDF_Dictionary* pEncryptDict, - uint32_t type, - int& cipher, - int& key_len) { - m_pEncryptDict = pEncryptDict; - m_Version = pEncryptDict->GetIntegerFor("V"); - m_Revision = pEncryptDict->GetIntegerFor("R"); - m_Permissions = pEncryptDict->GetIntegerFor("P", -1); - - CFX_ByteString strf_name; - CFX_ByteString stmf_name; - if (m_Version >= 4) { - stmf_name = pEncryptDict->GetStringFor("StmF"); - strf_name = pEncryptDict->GetStringFor("StrF"); - if (stmf_name != strf_name) - return FALSE; - } - if (!LoadCryptInfo(pEncryptDict, strf_name, cipher, key_len)) - return FALSE; - - m_Cipher = cipher; - m_KeyLen = key_len; - return TRUE; -} - -FX_BOOL CPDF_SecurityHandler::GetCryptInfo(int& cipher, - const uint8_t*& buffer, - int& keylen) { - cipher = m_Cipher; - buffer = m_EncryptKey; - keylen = m_KeyLen; - return TRUE; -} -#define FX_GET_32WORD(n, b, i) \ - { \ - (n) = (uint32_t)( \ - ((uint64_t)(b)[(i)] << 24) | ((uint64_t)(b)[(i) + 1] << 16) | \ - ((uint64_t)(b)[(i) + 2] << 8) | ((uint64_t)(b)[(i) + 3])); \ - } -int BigOrder64BitsMod3(uint8_t* data) { - uint64_t ret = 0; - for (int i = 0; i < 4; ++i) { - uint32_t value; - FX_GET_32WORD(value, data, 4 * i); - ret <<= 32; - ret |= value; - ret %= 3; - } - return (int)ret; -} -void Revision6_Hash(const uint8_t* password, - uint32_t size, - const uint8_t* salt, - const uint8_t* vector, - uint8_t* hash) { - int iBlockSize = 32; - uint8_t sha[128]; - CRYPT_SHA256Start(sha); - CRYPT_SHA256Update(sha, password, size); - CRYPT_SHA256Update(sha, salt, 8); - if (vector) { - CRYPT_SHA256Update(sha, vector, 48); - } - uint8_t digest[32]; - CRYPT_SHA256Finish(sha, digest); - CFX_ByteTextBuf buf; - uint8_t* input = digest; - uint8_t* key = input; - uint8_t* iv = input + 16; - uint8_t* E = buf.GetBuffer(); - int iBufLen = buf.GetLength(); - CFX_ByteTextBuf interDigest; - int i = 0; - uint8_t* aes = FX_Alloc(uint8_t, 2048); - while (i < 64 || i < E[iBufLen - 1] + 32) { - int iRoundSize = size + iBlockSize; - if (vector) { - iRoundSize += 48; - } - iBufLen = iRoundSize * 64; - buf.EstimateSize(iBufLen); - E = buf.GetBuffer(); - CFX_ByteTextBuf content; - for (int j = 0; j < 64; ++j) { - content.AppendBlock(password, size); - content.AppendBlock(input, iBlockSize); - if (vector) { - content.AppendBlock(vector, 48); - } - } - CRYPT_AESSetKey(aes, 16, key, 16, TRUE); - CRYPT_AESSetIV(aes, iv); - CRYPT_AESEncrypt(aes, E, content.GetBuffer(), iBufLen); - int iHash = 0; - switch (BigOrder64BitsMod3(E)) { - case 0: - iHash = 0; - iBlockSize = 32; - break; - case 1: - iHash = 1; - iBlockSize = 48; - break; - default: - iHash = 2; - iBlockSize = 64; - break; - } - interDigest.EstimateSize(iBlockSize); - input = interDigest.GetBuffer(); - if (iHash == 0) { - CRYPT_SHA256Generate(E, iBufLen, input); - } else if (iHash == 1) { - CRYPT_SHA384Generate(E, iBufLen, input); - } else if (iHash == 2) { - CRYPT_SHA512Generate(E, iBufLen, input); - } - key = input; - iv = input + 16; - ++i; - } - FX_Free(aes); - if (hash) { - FXSYS_memcpy(hash, input, 32); - } -} -FX_BOOL CPDF_SecurityHandler::AES256_CheckPassword(const uint8_t* password, - uint32_t size, - FX_BOOL bOwner, - uint8_t* key) { - CFX_ByteString okey = - m_pEncryptDict ? m_pEncryptDict->GetStringFor("O") : CFX_ByteString(); - if (okey.GetLength() < 48) { - return FALSE; - } - CFX_ByteString ukey = - m_pEncryptDict ? m_pEncryptDict->GetStringFor("U") : CFX_ByteString(); - if (ukey.GetLength() < 48) { - return FALSE; - } - const uint8_t* pkey = (bOwner ? okey : ukey).raw_str(); - uint8_t sha[128]; - uint8_t digest[32]; - if (m_Revision >= 6) { - Revision6_Hash(password, size, (const uint8_t*)pkey + 32, - bOwner ? ukey.raw_str() : nullptr, digest); - } else { - CRYPT_SHA256Start(sha); - CRYPT_SHA256Update(sha, password, size); - CRYPT_SHA256Update(sha, pkey + 32, 8); - if (bOwner) { - CRYPT_SHA256Update(sha, ukey.raw_str(), 48); - } - CRYPT_SHA256Finish(sha, digest); - } - if (FXSYS_memcmp(digest, pkey, 32) != 0) { - return FALSE; - } - if (!key) { - return TRUE; - } - if (m_Revision >= 6) { - Revision6_Hash(password, size, (const uint8_t*)pkey + 40, - bOwner ? ukey.raw_str() : nullptr, digest); - } else { - CRYPT_SHA256Start(sha); - CRYPT_SHA256Update(sha, password, size); - CRYPT_SHA256Update(sha, pkey + 40, 8); - if (bOwner) { - CRYPT_SHA256Update(sha, ukey.raw_str(), 48); - } - CRYPT_SHA256Finish(sha, digest); - } - CFX_ByteString ekey = m_pEncryptDict - ? m_pEncryptDict->GetStringFor(bOwner ? "OE" : "UE") - : CFX_ByteString(); - if (ekey.GetLength() < 32) { - return FALSE; - } - uint8_t* aes = FX_Alloc(uint8_t, 2048); - CRYPT_AESSetKey(aes, 16, digest, 32, FALSE); - uint8_t iv[16]; - FXSYS_memset(iv, 0, 16); - CRYPT_AESSetIV(aes, iv); - CRYPT_AESDecrypt(aes, key, ekey.raw_str(), 32); - CRYPT_AESSetKey(aes, 16, key, 32, FALSE); - CRYPT_AESSetIV(aes, iv); - CFX_ByteString perms = m_pEncryptDict->GetStringFor("Perms"); - if (perms.IsEmpty()) { - return FALSE; - } - uint8_t perms_buf[16]; - FXSYS_memset(perms_buf, 0, sizeof(perms_buf)); - uint32_t copy_len = sizeof(perms_buf); - if (copy_len > (uint32_t)perms.GetLength()) { - copy_len = perms.GetLength(); - } - FXSYS_memcpy(perms_buf, perms.raw_str(), copy_len); - uint8_t buf[16]; - CRYPT_AESDecrypt(aes, buf, perms_buf, 16); - FX_Free(aes); - if (buf[9] != 'a' || buf[10] != 'd' || buf[11] != 'b') { - return FALSE; - } - if (FXDWORD_GET_LSBFIRST(buf) != m_Permissions) { - return FALSE; - } - if ((buf[8] == 'T' && !IsMetadataEncrypted()) || - (buf[8] == 'F' && IsMetadataEncrypted())) { - return FALSE; - } - return TRUE; -} - -int CPDF_SecurityHandler::CheckPassword(const uint8_t* password, - uint32_t size, - FX_BOOL bOwner, - uint8_t* key, - int32_t key_len) { - if (m_Revision >= 5) { - return AES256_CheckPassword(password, size, bOwner, key); - } - uint8_t keybuf[32]; - if (!key) { - key = keybuf; - } - if (bOwner) { - return CheckOwnerPassword(password, size, key, key_len); - } - return CheckUserPassword(password, size, FALSE, key, key_len) || - CheckUserPassword(password, size, TRUE, key, key_len); -} -FX_BOOL CPDF_SecurityHandler::CheckUserPassword(const uint8_t* password, - uint32_t pass_size, - FX_BOOL bIgnoreEncryptMeta, - uint8_t* key, - int32_t key_len) { - CalcEncryptKey(m_pEncryptDict, password, pass_size, key, key_len, - bIgnoreEncryptMeta, m_pParser->GetIDArray()); - CFX_ByteString ukey = - m_pEncryptDict ? m_pEncryptDict->GetStringFor("U") : CFX_ByteString(); - if (ukey.GetLength() < 16) { - return FALSE; - } - uint8_t ukeybuf[32]; - if (m_Revision == 2) { - FXSYS_memcpy(ukeybuf, defpasscode, 32); - CRYPT_ArcFourCryptBlock(ukeybuf, 32, key, key_len); - } else { - uint8_t test[32], tmpkey[32]; - uint32_t copy_len = sizeof(test); - if (copy_len > (uint32_t)ukey.GetLength()) { - copy_len = ukey.GetLength(); - } - FXSYS_memset(test, 0, sizeof(test)); - FXSYS_memset(tmpkey, 0, sizeof(tmpkey)); - FXSYS_memcpy(test, ukey.c_str(), copy_len); - for (int32_t i = 19; i >= 0; i--) { - for (int j = 0; j < key_len; j++) - tmpkey[j] = key[j] ^ static_cast(i); - CRYPT_ArcFourCryptBlock(test, 32, tmpkey, key_len); - } - uint8_t md5[100]; - CRYPT_MD5Start(md5); - CRYPT_MD5Update(md5, defpasscode, 32); - CPDF_Array* pIdArray = m_pParser->GetIDArray(); - if (pIdArray) { - CFX_ByteString id = pIdArray->GetStringAt(0); - CRYPT_MD5Update(md5, (uint8_t*)id.c_str(), id.GetLength()); - } - CRYPT_MD5Finish(md5, ukeybuf); - return FXSYS_memcmp(test, ukeybuf, 16) == 0; - } - if (FXSYS_memcmp((void*)ukey.c_str(), ukeybuf, 16) == 0) { - return TRUE; - } - return FALSE; -} -CFX_ByteString CPDF_SecurityHandler::GetUserPassword(const uint8_t* owner_pass, - uint32_t pass_size, - int32_t key_len) { - CFX_ByteString okey = m_pEncryptDict->GetStringFor("O"); - uint8_t passcode[32]; - for (uint32_t i = 0; i < 32; i++) { - passcode[i] = i < pass_size ? owner_pass[i] : defpasscode[i - pass_size]; - } - uint8_t digest[16]; - CRYPT_MD5Generate(passcode, 32, digest); - if (m_Revision >= 3) { - for (uint32_t i = 0; i < 50; i++) { - CRYPT_MD5Generate(digest, 16, digest); - } - } - uint8_t enckey[32]; - FXSYS_memset(enckey, 0, sizeof(enckey)); - uint32_t copy_len = key_len; - if (copy_len > sizeof(digest)) { - copy_len = sizeof(digest); - } - FXSYS_memcpy(enckey, digest, copy_len); - int okeylen = okey.GetLength(); - if (okeylen > 32) { - okeylen = 32; - } - uint8_t okeybuf[64]; - FXSYS_memset(okeybuf, 0, sizeof(okeybuf)); - FXSYS_memcpy(okeybuf, okey.c_str(), okeylen); - if (m_Revision == 2) { - CRYPT_ArcFourCryptBlock(okeybuf, okeylen, enckey, key_len); - } else { - for (int32_t i = 19; i >= 0; i--) { - uint8_t tempkey[32]; - FXSYS_memset(tempkey, 0, sizeof(tempkey)); - for (int j = 0; j < m_KeyLen; j++) - tempkey[j] = enckey[j] ^ static_cast(i); - CRYPT_ArcFourCryptBlock(okeybuf, okeylen, tempkey, key_len); - } - } - int len = 32; - while (len && defpasscode[len - 1] == okeybuf[len - 1]) { - len--; - } - return CFX_ByteString(okeybuf, len); -} -FX_BOOL CPDF_SecurityHandler::CheckOwnerPassword(const uint8_t* password, - uint32_t pass_size, - uint8_t* key, - int32_t key_len) { - CFX_ByteString user_pass = GetUserPassword(password, pass_size, key_len); - if (CheckUserPassword(user_pass.raw_str(), user_pass.GetLength(), FALSE, key, - key_len)) { - return TRUE; - } - return CheckUserPassword(user_pass.raw_str(), user_pass.GetLength(), TRUE, - key, key_len); -} - -bool CPDF_SecurityHandler::IsMetadataEncrypted() const { - return m_pEncryptDict->GetBooleanFor("EncryptMetadata", true); -} - -void CPDF_SecurityHandler::OnCreate(CPDF_Dictionary* pEncryptDict, - CPDF_Array* pIdArray, - const uint8_t* user_pass, - uint32_t user_size, - const uint8_t* owner_pass, - uint32_t owner_size, - FX_BOOL bDefault, - uint32_t type) { - int cipher = 0, key_len = 0; - if (!LoadDict(pEncryptDict, type, cipher, key_len)) { - return; - } - if (bDefault && (!owner_pass || owner_size == 0)) { - owner_pass = user_pass; - owner_size = user_size; - } - if (m_Revision >= 5) { - int t = (int)time(nullptr); - uint8_t sha[128]; - CRYPT_SHA256Start(sha); - CRYPT_SHA256Update(sha, (uint8_t*)&t, sizeof t); - CRYPT_SHA256Update(sha, m_EncryptKey, 32); - CRYPT_SHA256Update(sha, (uint8_t*)"there", 5); - CRYPT_SHA256Finish(sha, m_EncryptKey); - AES256_SetPassword(pEncryptDict, user_pass, user_size, FALSE, m_EncryptKey); - if (bDefault) { - AES256_SetPassword(pEncryptDict, owner_pass, owner_size, TRUE, - m_EncryptKey); - AES256_SetPerms(pEncryptDict, m_Permissions, - pEncryptDict->GetBooleanFor("EncryptMetadata", true), - m_EncryptKey); - } - return; - } - if (bDefault) { - uint8_t passcode[32]; - for (uint32_t i = 0; i < 32; i++) { - passcode[i] = - i < owner_size ? owner_pass[i] : defpasscode[i - owner_size]; - } - uint8_t digest[16]; - CRYPT_MD5Generate(passcode, 32, digest); - if (m_Revision >= 3) { - for (uint32_t i = 0; i < 50; i++) - CRYPT_MD5Generate(digest, 16, digest); - } - uint8_t enckey[32]; - FXSYS_memcpy(enckey, digest, key_len); - for (uint32_t i = 0; i < 32; i++) { - passcode[i] = i < user_size ? user_pass[i] : defpasscode[i - user_size]; - } - CRYPT_ArcFourCryptBlock(passcode, 32, enckey, key_len); - uint8_t tempkey[32]; - if (m_Revision >= 3) { - for (uint8_t i = 1; i <= 19; i++) { - for (int j = 0; j < key_len; j++) - tempkey[j] = enckey[j] ^ i; - CRYPT_ArcFourCryptBlock(passcode, 32, tempkey, key_len); - } - } - pEncryptDict->SetStringFor("O", CFX_ByteString(passcode, 32)); - } - CalcEncryptKey(m_pEncryptDict, (uint8_t*)user_pass, user_size, m_EncryptKey, - key_len, FALSE, pIdArray); - if (m_Revision < 3) { - uint8_t tempbuf[32]; - FXSYS_memcpy(tempbuf, defpasscode, 32); - CRYPT_ArcFourCryptBlock(tempbuf, 32, m_EncryptKey, key_len); - pEncryptDict->SetStringFor("U", CFX_ByteString(tempbuf, 32)); - } else { - uint8_t md5[100]; - CRYPT_MD5Start(md5); - CRYPT_MD5Update(md5, defpasscode, 32); - if (pIdArray) { - CFX_ByteString id = pIdArray->GetStringAt(0); - CRYPT_MD5Update(md5, (uint8_t*)id.c_str(), id.GetLength()); - } - uint8_t digest[32]; - CRYPT_MD5Finish(md5, digest); - CRYPT_ArcFourCryptBlock(digest, 16, m_EncryptKey, key_len); - uint8_t tempkey[32]; - for (uint8_t i = 1; i <= 19; i++) { - for (int j = 0; j < key_len; j++) { - tempkey[j] = m_EncryptKey[j] ^ i; - } - CRYPT_ArcFourCryptBlock(digest, 16, tempkey, key_len); - } - CRYPT_MD5Generate(digest, 16, digest + 16); - pEncryptDict->SetStringFor("U", CFX_ByteString(digest, 32)); - } -} -void CPDF_SecurityHandler::OnCreate(CPDF_Dictionary* pEncryptDict, - CPDF_Array* pIdArray, - const uint8_t* user_pass, - uint32_t user_size, - const uint8_t* owner_pass, - uint32_t owner_size, - uint32_t type) { - OnCreate(pEncryptDict, pIdArray, user_pass, user_size, owner_pass, owner_size, - TRUE, type); -} -void CPDF_SecurityHandler::OnCreate(CPDF_Dictionary* pEncryptDict, - CPDF_Array* pIdArray, - const uint8_t* user_pass, - uint32_t user_size, - uint32_t type) { - OnCreate(pEncryptDict, pIdArray, user_pass, user_size, nullptr, 0, FALSE, - type); -} -void CPDF_SecurityHandler::AES256_SetPassword(CPDF_Dictionary* pEncryptDict, - const uint8_t* password, - uint32_t size, - FX_BOOL bOwner, - const uint8_t* key) { - uint8_t sha[128]; - CRYPT_SHA1Start(sha); - CRYPT_SHA1Update(sha, key, 32); - CRYPT_SHA1Update(sha, (uint8_t*)"hello", 5); - uint8_t digest[20]; - CRYPT_SHA1Finish(sha, digest); - CFX_ByteString ukey = pEncryptDict->GetStringFor("U"); - uint8_t digest1[48]; - if (m_Revision >= 6) { - Revision6_Hash(password, size, digest, bOwner ? ukey.raw_str() : nullptr, - digest1); - } else { - CRYPT_SHA256Start(sha); - CRYPT_SHA256Update(sha, password, size); - CRYPT_SHA256Update(sha, digest, 8); - if (bOwner) { - CRYPT_SHA256Update(sha, ukey.raw_str(), ukey.GetLength()); - } - CRYPT_SHA256Finish(sha, digest1); - } - FXSYS_memcpy(digest1 + 32, digest, 16); - pEncryptDict->SetStringFor(bOwner ? "O" : "U", CFX_ByteString(digest1, 48)); - if (m_Revision >= 6) { - Revision6_Hash(password, size, digest + 8, - bOwner ? ukey.raw_str() : nullptr, digest1); - } else { - CRYPT_SHA256Start(sha); - CRYPT_SHA256Update(sha, password, size); - CRYPT_SHA256Update(sha, digest + 8, 8); - if (bOwner) { - CRYPT_SHA256Update(sha, ukey.raw_str(), ukey.GetLength()); - } - CRYPT_SHA256Finish(sha, digest1); - } - uint8_t* aes = FX_Alloc(uint8_t, 2048); - CRYPT_AESSetKey(aes, 16, digest1, 32, TRUE); - uint8_t iv[16]; - FXSYS_memset(iv, 0, 16); - CRYPT_AESSetIV(aes, iv); - CRYPT_AESEncrypt(aes, digest1, key, 32); - FX_Free(aes); - pEncryptDict->SetStringFor(bOwner ? "OE" : "UE", CFX_ByteString(digest1, 32)); -} -void CPDF_SecurityHandler::AES256_SetPerms(CPDF_Dictionary* pEncryptDict, - uint32_t permissions, - FX_BOOL bEncryptMetadata, - const uint8_t* key) { - uint8_t buf[16]; - buf[0] = (uint8_t)permissions; - buf[1] = (uint8_t)(permissions >> 8); - buf[2] = (uint8_t)(permissions >> 16); - buf[3] = (uint8_t)(permissions >> 24); - buf[4] = 0xff; - buf[5] = 0xff; - buf[6] = 0xff; - buf[7] = 0xff; - buf[8] = bEncryptMetadata ? 'T' : 'F'; - buf[9] = 'a'; - buf[10] = 'd'; - buf[11] = 'b'; - uint8_t* aes = FX_Alloc(uint8_t, 2048); - CRYPT_AESSetKey(aes, 16, key, 32, TRUE); - uint8_t iv[16], buf1[16]; - FXSYS_memset(iv, 0, 16); - CRYPT_AESSetIV(aes, iv); - CRYPT_AESEncrypt(aes, buf1, buf, 16); - FX_Free(aes); - pEncryptDict->SetStringFor("Perms", CFX_ByteString(buf1, 16)); -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_security_handler.h b/core/fpdfapi/fpdf_parser/cpdf_security_handler.h deleted file mode 100644 index 33c4c0c17d..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_security_handler.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_SECURITY_HANDLER_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_SECURITY_HANDLER_H_ - -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" - -#define FXCIPHER_NONE 0 -#define FXCIPHER_RC4 1 -#define FXCIPHER_AES 2 -#define FXCIPHER_AES2 3 - -#define PDF_ENCRYPT_CONTENT 0 - -class CPDF_Array; -class CPDF_CryptoHandler; -class CPDF_Dictionary; -class CPDF_Parser; - -class CPDF_SecurityHandler { - public: - CPDF_SecurityHandler(); - ~CPDF_SecurityHandler(); - - FX_BOOL OnInit(CPDF_Parser* pParser, CPDF_Dictionary* pEncryptDict); - uint32_t GetPermissions(); - FX_BOOL GetCryptInfo(int& cipher, const uint8_t*& buffer, int& keylen); - bool IsMetadataEncrypted() const; - CPDF_CryptoHandler* CreateCryptoHandler(); - - void OnCreate(CPDF_Dictionary* pEncryptDict, - CPDF_Array* pIdArray, - const uint8_t* user_pass, - uint32_t user_size, - const uint8_t* owner_pass, - uint32_t owner_size, - uint32_t type = PDF_ENCRYPT_CONTENT); - - void OnCreate(CPDF_Dictionary* pEncryptDict, - CPDF_Array* pIdArray, - const uint8_t* user_pass, - uint32_t user_size, - uint32_t type = PDF_ENCRYPT_CONTENT); - - CFX_ByteString GetUserPassword(const uint8_t* owner_pass, - uint32_t pass_size, - int32_t key_len); - int CheckPassword(const uint8_t* password, - uint32_t pass_size, - FX_BOOL bOwner, - uint8_t* key, - int key_len); - - private: - FX_BOOL LoadDict(CPDF_Dictionary* pEncryptDict); - FX_BOOL LoadDict(CPDF_Dictionary* pEncryptDict, - uint32_t type, - int& cipher, - int& key_len); - - FX_BOOL CheckUserPassword(const uint8_t* password, - uint32_t pass_size, - FX_BOOL bIgnoreEncryptMeta, - uint8_t* key, - int32_t key_len); - - FX_BOOL CheckOwnerPassword(const uint8_t* password, - uint32_t pass_size, - uint8_t* key, - int32_t key_len); - FX_BOOL AES256_CheckPassword(const uint8_t* password, - uint32_t size, - FX_BOOL bOwner, - uint8_t* key); - void AES256_SetPassword(CPDF_Dictionary* pEncryptDict, - const uint8_t* password, - uint32_t size, - FX_BOOL bOwner, - const uint8_t* key); - void AES256_SetPerms(CPDF_Dictionary* pEncryptDict, - uint32_t permission, - FX_BOOL bEncryptMetadata, - const uint8_t* key); - void OnCreate(CPDF_Dictionary* pEncryptDict, - CPDF_Array* pIdArray, - const uint8_t* user_pass, - uint32_t user_size, - const uint8_t* owner_pass, - uint32_t owner_size, - FX_BOOL bDefault, - uint32_t type); - FX_BOOL CheckSecurity(int32_t key_len); - - int m_Version; - int m_Revision; - CPDF_Parser* m_pParser; - CPDF_Dictionary* m_pEncryptDict; - uint32_t m_Permissions; - int m_Cipher; - uint8_t m_EncryptKey[32]; - int m_KeyLen; - bool m_bOwnerUnlocked; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_SECURITY_HANDLER_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_security_handler_embeddertest.cpp b/core/fpdfapi/fpdf_parser/cpdf_security_handler_embeddertest.cpp deleted file mode 100644 index 37b6d8fc33..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_security_handler_embeddertest.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2016 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. - -#include "testing/embedder_test.h" -#include "testing/gtest/include/gtest/gtest.h" - -class CPDFSecurityHandlerEmbeddertest : public EmbedderTest {}; - -TEST_F(CPDFSecurityHandlerEmbeddertest, Unencrypted) { - ASSERT_TRUE(OpenDocument("about_blank.pdf")); - EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocPermissions(document())); -} - -TEST_F(CPDFSecurityHandlerEmbeddertest, UnencryptedWithPassword) { - ASSERT_TRUE(OpenDocument("about_blank.pdf", "foobar")); - EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocPermissions(document())); -} - -TEST_F(CPDFSecurityHandlerEmbeddertest, NoPassword) { - EXPECT_FALSE(OpenDocument("encrypted.pdf")); -} - -TEST_F(CPDFSecurityHandlerEmbeddertest, UserPassword) { - ASSERT_TRUE(OpenDocument("encrypted.pdf", "1234")); - EXPECT_EQ(0xFFFFF2C0, FPDF_GetDocPermissions(document())); -} - -TEST_F(CPDFSecurityHandlerEmbeddertest, OwnerPassword) { - ASSERT_TRUE(OpenDocument("encrypted.pdf", "5678")); - EXPECT_EQ(0xFFFFFFFC, FPDF_GetDocPermissions(document())); -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_simple_parser.cpp b/core/fpdfapi/fpdf_parser/cpdf_simple_parser.cpp deleted file mode 100644 index 821cd1b75b..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_simple_parser.cpp +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h" - -#include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h" - -CPDF_SimpleParser::CPDF_SimpleParser(const uint8_t* pData, uint32_t dwSize) - : m_pData(pData), m_dwSize(dwSize), m_dwCurPos(0) {} - -CPDF_SimpleParser::CPDF_SimpleParser(const CFX_ByteStringC& str) - : m_pData(str.raw_str()), m_dwSize(str.GetLength()), m_dwCurPos(0) {} - -void CPDF_SimpleParser::ParseWord(const uint8_t*& pStart, uint32_t& dwSize) { - pStart = nullptr; - dwSize = 0; - uint8_t ch; - while (1) { - if (m_dwSize <= m_dwCurPos) - return; - ch = m_pData[m_dwCurPos++]; - while (PDFCharIsWhitespace(ch)) { - if (m_dwSize <= m_dwCurPos) - return; - ch = m_pData[m_dwCurPos++]; - } - - if (ch != '%') - break; - - while (1) { - if (m_dwSize <= m_dwCurPos) - return; - ch = m_pData[m_dwCurPos++]; - if (PDFCharIsLineEnding(ch)) - break; - } - } - - uint32_t start_pos = m_dwCurPos - 1; - pStart = m_pData + start_pos; - if (PDFCharIsDelimiter(ch)) { - if (ch == '/') { - while (1) { - if (m_dwSize <= m_dwCurPos) - return; - ch = m_pData[m_dwCurPos++]; - if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { - m_dwCurPos--; - dwSize = m_dwCurPos - start_pos; - return; - } - } - } else { - dwSize = 1; - if (ch == '<') { - if (m_dwSize <= m_dwCurPos) - return; - ch = m_pData[m_dwCurPos++]; - if (ch == '<') - dwSize = 2; - else - m_dwCurPos--; - } else if (ch == '>') { - if (m_dwSize <= m_dwCurPos) - return; - ch = m_pData[m_dwCurPos++]; - if (ch == '>') - dwSize = 2; - else - m_dwCurPos--; - } - } - return; - } - - dwSize = 1; - while (1) { - if (m_dwSize <= m_dwCurPos) - return; - ch = m_pData[m_dwCurPos++]; - - if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { - m_dwCurPos--; - break; - } - dwSize++; - } -} - -CFX_ByteStringC CPDF_SimpleParser::GetWord() { - const uint8_t* pStart; - uint32_t dwSize; - ParseWord(pStart, dwSize); - if (dwSize == 1 && pStart[0] == '<') { - while (m_dwCurPos < m_dwSize && m_pData[m_dwCurPos] != '>') { - m_dwCurPos++; - } - if (m_dwCurPos < m_dwSize) { - m_dwCurPos++; - } - return CFX_ByteStringC(pStart, - (FX_STRSIZE)(m_dwCurPos - (pStart - m_pData))); - } - if (dwSize == 1 && pStart[0] == '(') { - int level = 1; - while (m_dwCurPos < m_dwSize) { - if (m_pData[m_dwCurPos] == ')') { - level--; - if (level == 0) { - break; - } - } - if (m_pData[m_dwCurPos] == '\\') { - if (m_dwSize <= m_dwCurPos) { - break; - } - m_dwCurPos++; - } else if (m_pData[m_dwCurPos] == '(') { - level++; - } - if (m_dwSize <= m_dwCurPos) { - break; - } - m_dwCurPos++; - } - if (m_dwCurPos < m_dwSize) { - m_dwCurPos++; - } - return CFX_ByteStringC(pStart, - (FX_STRSIZE)(m_dwCurPos - (pStart - m_pData))); - } - return CFX_ByteStringC(pStart, dwSize); -} - -bool CPDF_SimpleParser::FindTagParamFromStart(const CFX_ByteStringC& token, - int nParams) { - nParams++; - uint32_t* pBuf = FX_Alloc(uint32_t, nParams); - int buf_index = 0; - int buf_count = 0; - m_dwCurPos = 0; - while (1) { - pBuf[buf_index++] = m_dwCurPos; - if (buf_index == nParams) { - buf_index = 0; - } - buf_count++; - if (buf_count > nParams) { - buf_count = nParams; - } - CFX_ByteStringC word = GetWord(); - if (word.IsEmpty()) { - FX_Free(pBuf); - return false; - } - if (word == token) { - if (buf_count < nParams) { - continue; - } - m_dwCurPos = pBuf[buf_index]; - FX_Free(pBuf); - return true; - } - } - return false; -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_simple_parser.h b/core/fpdfapi/fpdf_parser/cpdf_simple_parser.h deleted file mode 100644 index d23182dcb8..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_simple_parser.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_SIMPLE_PARSER_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_SIMPLE_PARSER_H_ - -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" - -class CPDF_SimpleParser { - public: - CPDF_SimpleParser(const uint8_t* pData, uint32_t dwSize); - CPDF_SimpleParser(const CFX_ByteStringC& str); - - CFX_ByteStringC GetWord(); - - // Find the token and its |nParams| parameters from the start of data, - // and move the current position to the start of those parameters. - bool FindTagParamFromStart(const CFX_ByteStringC& token, int nParams); - - // For testing only. - uint32_t GetCurPos() const { return m_dwCurPos; } - - private: - void ParseWord(const uint8_t*& pStart, uint32_t& dwSize); - - const uint8_t* m_pData; - uint32_t m_dwSize; - uint32_t m_dwCurPos; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_SIMPLE_PARSER_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_simple_parser_unittest.cpp b/core/fpdfapi/fpdf_parser/cpdf_simple_parser_unittest.cpp deleted file mode 100644 index 50bbb528c5..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_simple_parser_unittest.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2016 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. - -#include "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h" - -#include - -#include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h" -#include "core/fxcrt/fx_basic.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/test_support.h" - -TEST(SimpleParserTest, GetWord) { - pdfium::StrFuncTestData test_data[] = { - // Empty src string. - STR_IN_OUT_CASE("", ""), - // Content with whitespaces only. - STR_IN_OUT_CASE(" \t \0 \n", ""), - // Content with comments only. - STR_IN_OUT_CASE("%this is a test case\r\n%2nd line", ""), - // Mixed whitespaces and comments. - STR_IN_OUT_CASE(" \t \0%try()%haha\n %another line \aa", ""), - // Name. - STR_IN_OUT_CASE(" /Tester ", "/Tester"), - // String. - STR_IN_OUT_CASE("\t(nice day)!\n ", "(nice day)"), - // String with nested braces. - STR_IN_OUT_CASE("\t(It is a (long) day)!\n ", "(It is a (long) day)"), - // String with escaped chars. - STR_IN_OUT_CASE("\t(It is a \\(long\\) day!)hi\n ", - "(It is a \\(long\\) day!)"), - // Hex string. - STR_IN_OUT_CASE(" \n<4545acdfedertt>abc ", "<4545acdfedertt>"), - STR_IN_OUT_CASE(" \n<4545aertt>abc ", "<4545a"), - // Dictionary. - STR_IN_OUT_CASE("<>", "<<"), - STR_IN_OUT_CASE("\t\t<< /abc>>", "<<"), - // Handling ending delimiters. - STR_IN_OUT_CASE("> little bear", ">"), - STR_IN_OUT_CASE(") another bear", ")"), STR_IN_OUT_CASE(">> end ", ">>"), - // No ending delimiters. - STR_IN_OUT_CASE("(sdfgfgbcv", "(sdfgfgbcv"), - // Regular cases. - STR_IN_OUT_CASE("apple pear", "apple"), - STR_IN_OUT_CASE(" pi=3.1415 ", "pi=3.1415"), - STR_IN_OUT_CASE(" p t x c ", "p"), STR_IN_OUT_CASE(" pt\0xc ", "pt"), - STR_IN_OUT_CASE(" $^&&*\t\0sdff ", "$^&&*"), - STR_IN_OUT_CASE("\n\r+3.5656 -11.0", "+3.5656"), - }; - for (size_t i = 0; i < FX_ArraySize(test_data); ++i) { - const pdfium::StrFuncTestData& data = test_data[i]; - CPDF_SimpleParser parser(data.input, data.input_size); - CFX_ByteStringC word = parser.GetWord(); - EXPECT_EQ(std::string(reinterpret_cast(data.expected), - data.expected_size), - std::string(word.c_str(), word.GetLength())) - << " for case " << i; - } -} - -TEST(SimpleParserTest, FindTagParamFromStart) { - struct FindTagTestStruct { - const unsigned char* input; - unsigned int input_size; - const char* token; - int num_params; - bool result; - unsigned int result_pos; - } test_data[] = { - // Empty strings. - STR_IN_TEST_CASE("", "Tj", 1, false, 0), - STR_IN_TEST_CASE("", "", 1, false, 0), - // Empty token. - STR_IN_TEST_CASE(" T j", "", 1, false, 5), - // No parameter. - STR_IN_TEST_CASE("Tj", "Tj", 1, false, 2), - STR_IN_TEST_CASE("(Tj", "Tj", 1, false, 3), - // Partial token match. - STR_IN_TEST_CASE("\r12\t34 56 78Tj", "Tj", 1, false, 15), - // Regular cases with various parameters. - STR_IN_TEST_CASE("\r\0abd Tj", "Tj", 1, true, 0), - STR_IN_TEST_CASE("12 4 Tj 3 46 Tj", "Tj", 1, true, 2), - STR_IN_TEST_CASE("er^ 2 (34) (5667) Tj", "Tj", 2, true, 5), - STR_IN_TEST_CASE("<344> (232)\t343.4\n12 45 Tj", "Tj", 3, true, 11), - STR_IN_TEST_CASE("1 2 3 4 5 6 7 8 cm", "cm", 6, true, 3), - }; - for (size_t i = 0; i < FX_ArraySize(test_data); ++i) { - const FindTagTestStruct& data = test_data[i]; - CPDF_SimpleParser parser(data.input, data.input_size); - EXPECT_EQ(data.result, - parser.FindTagParamFromStart(data.token, data.num_params)) - << " for case " << i; - EXPECT_EQ(data.result_pos, parser.GetCurPos()) << " for case " << i; - } -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_stream.cpp b/core/fpdfapi/fpdf_parser/cpdf_stream.cpp deleted file mode 100644 index 4f6d046397..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_stream.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" - -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" -#include "third_party/base/numerics/safe_conversions.h" -#include "third_party/base/stl_util.h" - -CPDF_Stream::CPDF_Stream() {} - -CPDF_Stream::CPDF_Stream(uint8_t* pData, uint32_t size, CPDF_Dictionary* pDict) - : m_pDict(pDict), - m_dwSize(size), - m_pDataBuf(pData) {} - -CPDF_Stream::~CPDF_Stream() {} - -CPDF_Object::Type CPDF_Stream::GetType() const { - return STREAM; -} - -CPDF_Dictionary* CPDF_Stream::GetDict() const { - return m_pDict.get(); -} - -bool CPDF_Stream::IsStream() const { - return true; -} - -CPDF_Stream* CPDF_Stream::AsStream() { - return this; -} - -const CPDF_Stream* CPDF_Stream::AsStream() const { - return this; -} - -void CPDF_Stream::InitStream(const uint8_t* pData, - uint32_t size, - CPDF_Dictionary* pDict) { - m_pDict.reset(pDict); - m_bMemoryBased = true; - m_pFile = nullptr; - m_pDataBuf.reset(FX_Alloc(uint8_t, size)); - if (pData) - FXSYS_memcpy(m_pDataBuf.get(), pData, size); - m_dwSize = size; - if (m_pDict) - m_pDict->SetIntegerFor("Length", m_dwSize); -} - -void CPDF_Stream::InitStreamFromFile(IFX_FileRead* pFile, - CPDF_Dictionary* pDict) { - m_pDict.reset(pDict); - m_bMemoryBased = false; - m_pDataBuf.reset(); - m_pFile = pFile; - m_dwSize = pdfium::base::checked_cast(pFile->GetSize()); - if (m_pDict) - m_pDict->SetIntegerFor("Length", m_dwSize); -} - -CPDF_Object* CPDF_Stream::Clone() const { - return CloneObjectNonCyclic(false); -} - -CPDF_Object* CPDF_Stream::CloneNonCyclic( - bool bDirect, - std::set* pVisited) const { - pVisited->insert(this); - CPDF_StreamAcc acc; - acc.LoadAllData(this, TRUE); - uint32_t streamSize = acc.GetSize(); - CPDF_Dictionary* pDict = GetDict(); - if (pDict && !pdfium::ContainsKey(*pVisited, pDict)) { - pDict = ToDictionary( - static_cast(pDict)->CloneNonCyclic(bDirect, pVisited)); - } - - return new CPDF_Stream(acc.DetachData(), streamSize, pDict); -} - -void CPDF_Stream::SetData(const uint8_t* pData, uint32_t size) { - m_bMemoryBased = true; - m_pDataBuf.reset(FX_Alloc(uint8_t, size)); - if (pData) - FXSYS_memcpy(m_pDataBuf.get(), pData, size); - m_dwSize = size; - if (!m_pDict) - m_pDict.reset(new CPDF_Dictionary()); - m_pDict->SetIntegerFor("Length", size); - m_pDict->RemoveFor("Filter"); - m_pDict->RemoveFor("DecodeParms"); -} - -FX_BOOL CPDF_Stream::ReadRawData(FX_FILESIZE offset, - uint8_t* buf, - uint32_t size) const { - if (m_bMemoryBased && m_pFile) - return m_pFile->ReadBlock(buf, offset, size); - - if (m_pDataBuf) - FXSYS_memcpy(buf, m_pDataBuf.get() + offset, size); - - return TRUE; -} - -CFX_WideString CPDF_Stream::GetUnicodeText() const { - CPDF_StreamAcc stream; - stream.LoadAllData(this, FALSE); - return PDF_DecodeText(stream.GetData(), stream.GetSize()); -} - diff --git a/core/fpdfapi/fpdf_parser/cpdf_stream.h b/core/fpdfapi/fpdf_parser/cpdf_stream.h deleted file mode 100644 index e3bba96346..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_stream.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_STREAM_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_STREAM_H_ - -#include -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fxcrt/fx_basic.h" - -class CPDF_Stream : public CPDF_Object { - public: - CPDF_Stream(); - - // Takes ownership of |pData| and |pDict|. - CPDF_Stream(uint8_t* pData, uint32_t size, CPDF_Dictionary* pDict); - - // CPDF_Object. - Type GetType() const override; - CPDF_Object* Clone() const override; - CPDF_Dictionary* GetDict() const override; - CFX_WideString GetUnicodeText() const override; - bool IsStream() const override; - CPDF_Stream* AsStream() override; - const CPDF_Stream* AsStream() const override; - - uint32_t GetRawSize() const { return m_dwSize; } - uint8_t* GetRawData() const { return m_pDataBuf.get(); } - - // Does not takes onwership of |pData|, copies into internally-owned buffer. - void SetData(const uint8_t* pData, uint32_t size); - - void InitStream(const uint8_t* pData, uint32_t size, CPDF_Dictionary* pDict); - void InitStreamFromFile(IFX_FileRead* pFile, CPDF_Dictionary* pDict); - - FX_BOOL ReadRawData(FX_FILESIZE start_pos, - uint8_t* pBuf, - uint32_t buf_size) const; - - bool IsMemoryBased() const { return m_bMemoryBased; } - - protected: - ~CPDF_Stream() override; - CPDF_Object* CloneNonCyclic( - bool bDirect, - std::set* pVisited) const override; - - std::unique_ptr> m_pDict; - bool m_bMemoryBased = true; - uint32_t m_dwSize = 0; - std::unique_ptr m_pDataBuf; - IFX_FileRead* m_pFile = nullptr; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_STREAM_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_stream_acc.cpp b/core/fpdfapi/fpdf_parser/cpdf_stream_acc.cpp deleted file mode 100644 index a19b796151..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_stream_acc.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" - -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" - -CPDF_StreamAcc::CPDF_StreamAcc() - : m_pData(nullptr), - m_dwSize(0), - m_bNewBuf(FALSE), - m_pImageParam(nullptr), - m_pStream(nullptr), - m_pSrcData(nullptr) {} - -void CPDF_StreamAcc::LoadAllData(const CPDF_Stream* pStream, - FX_BOOL bRawAccess, - uint32_t estimated_size, - FX_BOOL bImageAcc) { - if (!pStream) - return; - - m_pStream = pStream; - if (pStream->IsMemoryBased() && - (!pStream->GetDict()->KeyExist("Filter") || bRawAccess)) { - m_dwSize = pStream->GetRawSize(); - m_pData = pStream->GetRawData(); - return; - } - uint8_t* pSrcData; - uint32_t dwSrcSize = pStream->GetRawSize(); - if (dwSrcSize == 0) - return; - - if (!pStream->IsMemoryBased()) { - pSrcData = m_pSrcData = FX_Alloc(uint8_t, dwSrcSize); - if (!pStream->ReadRawData(0, pSrcData, dwSrcSize)) - return; - } else { - pSrcData = pStream->GetRawData(); - } - if (!pStream->GetDict()->KeyExist("Filter") || bRawAccess) { - m_pData = pSrcData; - m_dwSize = dwSrcSize; - } else { - FX_BOOL bRet = PDF_DataDecode(pSrcData, dwSrcSize, m_pStream->GetDict(), - m_pData, m_dwSize, m_ImageDecoder, - m_pImageParam, estimated_size, bImageAcc); - if (!bRet) { - m_pData = pSrcData; - m_dwSize = dwSrcSize; - } - } - if (pSrcData != pStream->GetRawData() && pSrcData != m_pData) - FX_Free(pSrcData); - m_pSrcData = nullptr; - 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; - return m_pStream ? m_pStream->GetRawData() : nullptr; -} - -uint32_t CPDF_StreamAcc::GetSize() const { - if (m_bNewBuf) - return m_dwSize; - return m_pStream ? m_pStream->GetRawSize() : 0; -} - -uint8_t* CPDF_StreamAcc::DetachData() { - if (m_bNewBuf) { - uint8_t* p = m_pData; - m_pData = nullptr; - m_dwSize = 0; - return p; - } - uint8_t* p = FX_Alloc(uint8_t, m_dwSize); - FXSYS_memcpy(p, m_pData, m_dwSize); - return p; -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_stream_acc.h b/core/fpdfapi/fpdf_parser/cpdf_stream_acc.h deleted file mode 100644 index cf2bc8a01d..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_stream_acc.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_STREAM_ACC_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_STREAM_ACC_H_ - -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" - -class CPDF_StreamAcc { - public: - CPDF_StreamAcc(); - ~CPDF_StreamAcc(); - - void LoadAllData(const CPDF_Stream* pStream, - FX_BOOL bRawAccess = FALSE, - uint32_t estimated_size = 0, - 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; - uint32_t GetSize() const; - const CFX_ByteString& GetImageDecoder() const { return m_ImageDecoder; } - const CPDF_Dictionary* GetImageParam() const { return m_pImageParam; } - uint8_t* DetachData(); - - protected: - uint8_t* m_pData; - uint32_t m_dwSize; - FX_BOOL m_bNewBuf; - CFX_ByteString m_ImageDecoder; - CPDF_Dictionary* m_pImageParam; - const CPDF_Stream* m_pStream; - uint8_t* m_pSrcData; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_STREAM_ACC_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_string.cpp b/core/fpdfapi/fpdf_parser/cpdf_string.cpp deleted file mode 100644 index 4b42b8c22b..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_string.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" - -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" - -CPDF_String::CPDF_String() : m_bHex(FALSE) {} - -CPDF_String::CPDF_String(const CFX_ByteString& str, FX_BOOL bHex) - : m_String(str), m_bHex(bHex) {} - -CPDF_String::CPDF_String(const CFX_WideString& str) : m_bHex(FALSE) { - m_String = PDF_EncodeText(str); -} - -CPDF_String::~CPDF_String() {} - -CPDF_Object::Type CPDF_String::GetType() const { - return STRING; -} - -CPDF_Object* CPDF_String::Clone() const { - return new CPDF_String(m_String, m_bHex); -} - -CFX_ByteString CPDF_String::GetString() const { - return m_String; -} - -void CPDF_String::SetString(const CFX_ByteString& str) { - m_String = str; -} - -bool CPDF_String::IsString() const { - return true; -} - -CPDF_String* CPDF_String::AsString() { - return this; -} - -const CPDF_String* CPDF_String::AsString() const { - return this; -} - -CFX_WideString CPDF_String::GetUnicodeText() const { - return PDF_DecodeText(m_String); -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_string.h b/core/fpdfapi/fpdf_parser/cpdf_string.h deleted file mode 100644 index 2ce0d02ed7..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_string.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_STRING_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_STRING_H_ - -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" - -class CPDF_String : public CPDF_Object { - public: - CPDF_String(); - CPDF_String(const CFX_ByteString& str, FX_BOOL bHex); - explicit CPDF_String(const CFX_WideString& str); - - // CPDF_Object. - Type GetType() const override; - CPDF_Object* Clone() const override; - CFX_ByteString GetString() const override; - CFX_WideString GetUnicodeText() const override; - void SetString(const CFX_ByteString& str) override; - bool IsString() const override; - CPDF_String* AsString() override; - const CPDF_String* AsString() const override; - - FX_BOOL IsHex() const { return m_bHex; } - - protected: - ~CPDF_String() override; - - CFX_ByteString m_String; - FX_BOOL m_bHex; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_STRING_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_syntax_parser.cpp b/core/fpdfapi/fpdf_parser/cpdf_syntax_parser.cpp deleted file mode 100644 index 32a75f98da..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_syntax_parser.cpp +++ /dev/null @@ -1,997 +0,0 @@ -// Copyright 2016 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 - -#include "core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h" - -#include - -#include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" -#include "core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_null.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h" -#include "core/fxcrt/fx_ext.h" -#include "third_party/base/numerics/safe_math.h" - -namespace { - -struct SearchTagRecord { - CFX_ByteStringC m_bsTag; - FX_STRSIZE m_Offset; -}; - -} // namespace - -// static -int CPDF_SyntaxParser::s_CurrentRecursionDepth = 0; - -CPDF_SyntaxParser::CPDF_SyntaxParser() - : CPDF_SyntaxParser(CFX_WeakPtr()) {} - -CPDF_SyntaxParser::CPDF_SyntaxParser( - const CFX_WeakPtr& pPool) - : m_MetadataObjnum(0), - m_pFileAccess(nullptr), - m_pFileBuf(nullptr), - m_BufSize(CPDF_ModuleMgr::kFileBufSize), - m_pPool(pPool) {} - -CPDF_SyntaxParser::~CPDF_SyntaxParser() { - FX_Free(m_pFileBuf); -} - -FX_BOOL CPDF_SyntaxParser::GetCharAt(FX_FILESIZE pos, uint8_t& ch) { - CFX_AutoRestorer save_pos(&m_Pos); - m_Pos = pos; - return GetNextChar(ch); -} - -FX_BOOL CPDF_SyntaxParser::GetNextChar(uint8_t& ch) { - FX_FILESIZE pos = m_Pos + m_HeaderOffset; - if (pos >= m_FileLen) - return FALSE; - - if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) { - FX_FILESIZE read_pos = pos; - uint32_t read_size = m_BufSize; - if ((FX_FILESIZE)read_size > m_FileLen) - read_size = (uint32_t)m_FileLen; - - if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) { - if (m_FileLen < (FX_FILESIZE)read_size) { - read_pos = 0; - read_size = (uint32_t)m_FileLen; - } else { - read_pos = m_FileLen - read_size; - } - } - - if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) - return FALSE; - - m_BufOffset = read_pos; - } - ch = m_pFileBuf[pos - m_BufOffset]; - m_Pos++; - return TRUE; -} - -FX_BOOL CPDF_SyntaxParser::GetCharAtBackward(FX_FILESIZE pos, uint8_t& ch) { - pos += m_HeaderOffset; - if (pos >= m_FileLen) - return FALSE; - - if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) { - FX_FILESIZE read_pos; - if (pos < (FX_FILESIZE)m_BufSize) - read_pos = 0; - else - read_pos = pos - m_BufSize + 1; - - uint32_t read_size = m_BufSize; - if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) { - if (m_FileLen < (FX_FILESIZE)read_size) { - read_pos = 0; - read_size = (uint32_t)m_FileLen; - } else { - read_pos = m_FileLen - read_size; - } - } - - if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) - return FALSE; - - m_BufOffset = read_pos; - } - ch = m_pFileBuf[pos - m_BufOffset]; - return TRUE; -} - -FX_BOOL CPDF_SyntaxParser::ReadBlock(uint8_t* pBuf, uint32_t size) { - if (!m_pFileAccess->ReadBlock(pBuf, m_Pos + m_HeaderOffset, size)) - return FALSE; - m_Pos += size; - return TRUE; -} - -void CPDF_SyntaxParser::GetNextWordInternal(bool* bIsNumber) { - m_WordSize = 0; - if (bIsNumber) - *bIsNumber = true; - - uint8_t ch; - if (!GetNextChar(ch)) - return; - - while (1) { - while (PDFCharIsWhitespace(ch)) { - if (!GetNextChar(ch)) - return; - } - - if (ch != '%') - break; - - while (1) { - if (!GetNextChar(ch)) - return; - if (PDFCharIsLineEnding(ch)) - break; - } - } - - if (PDFCharIsDelimiter(ch)) { - if (bIsNumber) - *bIsNumber = false; - - m_WordBuffer[m_WordSize++] = ch; - if (ch == '/') { - while (1) { - if (!GetNextChar(ch)) - return; - - if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { - m_Pos--; - return; - } - - if (m_WordSize < sizeof(m_WordBuffer) - 1) - m_WordBuffer[m_WordSize++] = ch; - } - } else if (ch == '<') { - if (!GetNextChar(ch)) - return; - - if (ch == '<') - m_WordBuffer[m_WordSize++] = ch; - else - m_Pos--; - } else if (ch == '>') { - if (!GetNextChar(ch)) - return; - - if (ch == '>') - m_WordBuffer[m_WordSize++] = ch; - else - m_Pos--; - } - return; - } - - while (1) { - if (m_WordSize < sizeof(m_WordBuffer) - 1) - m_WordBuffer[m_WordSize++] = ch; - - if (!PDFCharIsNumeric(ch)) { - if (bIsNumber) - *bIsNumber = false; - } - - if (!GetNextChar(ch)) - return; - - if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { - m_Pos--; - break; - } - } -} - -CFX_ByteString CPDF_SyntaxParser::ReadString() { - uint8_t ch; - if (!GetNextChar(ch)) - return CFX_ByteString(); - - CFX_ByteTextBuf buf; - int32_t parlevel = 0; - int32_t status = 0; - int32_t iEscCode = 0; - while (1) { - switch (status) { - case 0: - if (ch == ')') { - if (parlevel == 0) { - return buf.MakeString(); - } - parlevel--; - buf.AppendChar(')'); - } else if (ch == '(') { - parlevel++; - buf.AppendChar('('); - } else if (ch == '\\') { - status = 1; - } else { - buf.AppendChar(ch); - } - break; - case 1: - if (ch >= '0' && ch <= '7') { - iEscCode = FXSYS_toDecimalDigit(static_cast(ch)); - status = 2; - break; - } - - if (ch == 'n') { - buf.AppendChar('\n'); - } else if (ch == 'r') { - buf.AppendChar('\r'); - } else if (ch == 't') { - buf.AppendChar('\t'); - } else if (ch == 'b') { - buf.AppendChar('\b'); - } else if (ch == 'f') { - buf.AppendChar('\f'); - } else if (ch == '\r') { - status = 4; - break; - } else if (ch != '\n') { - buf.AppendChar(ch); - } - status = 0; - break; - case 2: - if (ch >= '0' && ch <= '7') { - iEscCode = - iEscCode * 8 + FXSYS_toDecimalDigit(static_cast(ch)); - status = 3; - } else { - buf.AppendChar(iEscCode); - status = 0; - continue; - } - break; - case 3: - if (ch >= '0' && ch <= '7') { - iEscCode = - iEscCode * 8 + FXSYS_toDecimalDigit(static_cast(ch)); - buf.AppendChar(iEscCode); - status = 0; - } else { - buf.AppendChar(iEscCode); - status = 0; - continue; - } - break; - case 4: - status = 0; - if (ch != '\n') - continue; - break; - } - - if (!GetNextChar(ch)) - break; - } - - GetNextChar(ch); - return buf.MakeString(); -} - -CFX_ByteString CPDF_SyntaxParser::ReadHexString() { - uint8_t ch; - if (!GetNextChar(ch)) - return CFX_ByteString(); - - CFX_ByteTextBuf buf; - bool bFirst = true; - uint8_t code = 0; - while (1) { - if (ch == '>') - break; - - if (std::isxdigit(ch)) { - int val = FXSYS_toHexDigit(ch); - if (bFirst) { - code = val * 16; - } else { - code += val; - buf.AppendByte(code); - } - bFirst = !bFirst; - } - - if (!GetNextChar(ch)) - break; - } - if (!bFirst) - buf.AppendByte(code); - - return buf.MakeString(); -} - -void CPDF_SyntaxParser::ToNextLine() { - uint8_t ch; - while (GetNextChar(ch)) { - if (ch == '\n') - break; - - if (ch == '\r') { - GetNextChar(ch); - if (ch != '\n') - --m_Pos; - break; - } - } -} - -void CPDF_SyntaxParser::ToNextWord() { - uint8_t ch; - if (!GetNextChar(ch)) - return; - - while (1) { - while (PDFCharIsWhitespace(ch)) { - if (!GetNextChar(ch)) - return; - } - - if (ch != '%') - break; - - while (1) { - if (!GetNextChar(ch)) - return; - if (PDFCharIsLineEnding(ch)) - break; - } - } - m_Pos--; -} - -CFX_ByteString CPDF_SyntaxParser::GetNextWord(bool* bIsNumber) { - GetNextWordInternal(bIsNumber); - return CFX_ByteString((const FX_CHAR*)m_WordBuffer, m_WordSize); -} - -CFX_ByteString CPDF_SyntaxParser::GetKeyword() { - return GetNextWord(nullptr); -} - -CPDF_Object* CPDF_SyntaxParser::GetObject(CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - uint32_t gennum, - FX_BOOL bDecrypt) { - CFX_AutoRestorer restorer(&s_CurrentRecursionDepth); - if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth) - return nullptr; - - FX_FILESIZE SavedObjPos = m_Pos; - bool bIsNumber; - CFX_ByteString word = GetNextWord(&bIsNumber); - if (word.GetLength() == 0) - return nullptr; - - if (bIsNumber) { - FX_FILESIZE SavedPos = m_Pos; - CFX_ByteString nextword = GetNextWord(&bIsNumber); - if (bIsNumber) { - CFX_ByteString nextword2 = GetNextWord(nullptr); - if (nextword2 == "R") - return new CPDF_Reference(pObjList, FXSYS_atoui(word.c_str())); - } - m_Pos = SavedPos; - return new CPDF_Number(word.AsStringC()); - } - - if (word == "true" || word == "false") - return new CPDF_Boolean(word == "true"); - - if (word == "null") - return new CPDF_Null; - - if (word == "(") { - CFX_ByteString str = ReadString(); - if (m_pCryptoHandler && bDecrypt) - m_pCryptoHandler->Decrypt(objnum, gennum, str); - return new CPDF_String(MaybeIntern(str), FALSE); - } - - if (word == "<") { - CFX_ByteString str = ReadHexString(); - if (m_pCryptoHandler && bDecrypt) - m_pCryptoHandler->Decrypt(objnum, gennum, str); - return new CPDF_String(MaybeIntern(str), TRUE); - } - - if (word == "[") { - CPDF_Array* pArray = new CPDF_Array; - while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, true)) - pArray->Add(pObj); - - return pArray; - } - - if (word[0] == '/') { - return new CPDF_Name(MaybeIntern( - PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)))); - } - - if (word == "<<") { - int32_t nKeys = 0; - FX_FILESIZE dwSignValuePos = 0; - - std::unique_ptr> pDict( - new CPDF_Dictionary(m_pPool)); - while (1) { - CFX_ByteString key = GetNextWord(nullptr); - if (key.IsEmpty()) - return nullptr; - - FX_FILESIZE SavedPos = m_Pos - key.GetLength(); - if (key == ">>") - break; - - if (key == "endobj") { - m_Pos = SavedPos; - break; - } - - if (key[0] != '/') - continue; - - ++nKeys; - key = PDF_NameDecode(key); - if (key.IsEmpty()) - continue; - - if (key == "/Contents") - dwSignValuePos = m_Pos; - - CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, true); - if (!pObj) - continue; - - CFX_ByteString keyNoSlash(key.raw_str() + 1, key.GetLength() - 1); - pDict->SetFor(keyNoSlash, pObj); - } - - // Only when this is a signature dictionary and has contents, we reset the - // contents to the un-decrypted form. - if (pDict->IsSignatureDict() && dwSignValuePos) { - CFX_AutoRestorer save_pos(&m_Pos); - m_Pos = dwSignValuePos; - pDict->SetFor("Contents", GetObject(pObjList, objnum, gennum, false)); - } - - FX_FILESIZE SavedPos = m_Pos; - CFX_ByteString nextword = GetNextWord(nullptr); - if (nextword != "stream") { - m_Pos = SavedPos; - return pDict.release(); - } - return ReadStream(pDict.release(), objnum, gennum); - } - - if (word == ">>") - m_Pos = SavedObjPos; - - return nullptr; -} - -CPDF_Object* CPDF_SyntaxParser::GetObjectForStrict( - CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - uint32_t gennum) { - CFX_AutoRestorer restorer(&s_CurrentRecursionDepth); - if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth) - return nullptr; - - FX_FILESIZE SavedObjPos = m_Pos; - bool bIsNumber; - CFX_ByteString word = GetNextWord(&bIsNumber); - if (word.GetLength() == 0) - return nullptr; - - if (bIsNumber) { - FX_FILESIZE SavedPos = m_Pos; - CFX_ByteString nextword = GetNextWord(&bIsNumber); - if (bIsNumber) { - CFX_ByteString nextword2 = GetNextWord(nullptr); - if (nextword2 == "R") - return new CPDF_Reference(pObjList, FXSYS_atoui(word.c_str())); - } - m_Pos = SavedPos; - return new CPDF_Number(word.AsStringC()); - } - - if (word == "true" || word == "false") - return new CPDF_Boolean(word == "true"); - - if (word == "null") - return new CPDF_Null; - - if (word == "(") { - CFX_ByteString str = ReadString(); - if (m_pCryptoHandler) - m_pCryptoHandler->Decrypt(objnum, gennum, str); - return new CPDF_String(MaybeIntern(str), FALSE); - } - - if (word == "<") { - CFX_ByteString str = ReadHexString(); - if (m_pCryptoHandler) - m_pCryptoHandler->Decrypt(objnum, gennum, str); - return new CPDF_String(MaybeIntern(str), TRUE); - } - - if (word == "[") { - std::unique_ptr> pArray( - new CPDF_Array); - while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, true)) - pArray->Add(pObj); - - return m_WordBuffer[0] == ']' ? pArray.release() : nullptr; - } - - if (word[0] == '/') { - return new CPDF_Name(MaybeIntern( - PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)))); - } - - if (word == "<<") { - std::unique_ptr> pDict( - new CPDF_Dictionary(m_pPool)); - while (1) { - FX_FILESIZE SavedPos = m_Pos; - CFX_ByteString key = GetNextWord(nullptr); - if (key.IsEmpty()) - return nullptr; - - if (key == ">>") - break; - - if (key == "endobj") { - m_Pos = SavedPos; - break; - } - - if (key[0] != '/') - continue; - - key = PDF_NameDecode(key); - std::unique_ptr> obj( - GetObject(pObjList, objnum, gennum, true)); - if (!obj) { - uint8_t ch; - while (GetNextChar(ch) && ch != 0x0A && ch != 0x0D) { - continue; - } - return nullptr; - } - - if (key.GetLength() > 1) { - pDict->SetFor(CFX_ByteString(key.c_str() + 1, key.GetLength() - 1), - obj.release()); - } - } - - FX_FILESIZE SavedPos = m_Pos; - CFX_ByteString nextword = GetNextWord(nullptr); - if (nextword != "stream") { - m_Pos = SavedPos; - return pDict.release(); - } - - return ReadStream(pDict.release(), objnum, gennum); - } - - if (word == ">>") - m_Pos = SavedObjPos; - - return nullptr; -} - -unsigned int CPDF_SyntaxParser::ReadEOLMarkers(FX_FILESIZE pos) { - unsigned char byte1 = 0; - unsigned char byte2 = 0; - - GetCharAt(pos, byte1); - GetCharAt(pos + 1, byte2); - - if (byte1 == '\r' && byte2 == '\n') - return 2; - - if (byte1 == '\r' || byte1 == '\n') - return 1; - - return 0; -} - -CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict, - uint32_t objnum, - uint32_t gennum) { - CPDF_Object* pLenObj = pDict->GetObjectFor("Length"); - FX_FILESIZE len = -1; - CPDF_Reference* pLenObjRef = ToReference(pLenObj); - - bool differingObjNum = !pLenObjRef || (pLenObjRef->GetObjList() && - pLenObjRef->GetRefObjNum() != objnum); - if (pLenObj && differingObjNum) - len = pLenObj->GetInteger(); - - // Locate the start of stream. - ToNextLine(); - FX_FILESIZE streamStartPos = m_Pos; - - const CFX_ByteStringC kEndStreamStr("endstream"); - const CFX_ByteStringC kEndObjStr("endobj"); - - CPDF_CryptoHandler* pCryptoHandler = - objnum == (uint32_t)m_MetadataObjnum ? nullptr : m_pCryptoHandler.get(); - if (!pCryptoHandler) { - FX_BOOL bSearchForKeyword = TRUE; - if (len >= 0) { - pdfium::base::CheckedNumeric pos = m_Pos; - pos += len; - if (pos.IsValid() && pos.ValueOrDie() < m_FileLen) - m_Pos = pos.ValueOrDie(); - - m_Pos += ReadEOLMarkers(m_Pos); - FXSYS_memset(m_WordBuffer, 0, kEndStreamStr.GetLength() + 1); - GetNextWordInternal(nullptr); - // Earlier version of PDF specification doesn't require EOL marker before - // 'endstream' keyword. If keyword 'endstream' follows the bytes in - // specified length, it signals the end of stream. - if (FXSYS_memcmp(m_WordBuffer, kEndStreamStr.raw_str(), - kEndStreamStr.GetLength()) == 0) { - bSearchForKeyword = FALSE; - } - } - - if (bSearchForKeyword) { - // If len is not available, len needs to be calculated - // by searching the keywords "endstream" or "endobj". - m_Pos = streamStartPos; - FX_FILESIZE endStreamOffset = 0; - while (endStreamOffset >= 0) { - endStreamOffset = FindTag(kEndStreamStr, 0); - - // Can't find "endstream". - if (endStreamOffset < 0) - break; - - // Stop searching when "endstream" is found. - if (IsWholeWord(m_Pos - kEndStreamStr.GetLength(), m_FileLen, - kEndStreamStr, TRUE)) { - endStreamOffset = m_Pos - streamStartPos - kEndStreamStr.GetLength(); - break; - } - } - - m_Pos = streamStartPos; - FX_FILESIZE endObjOffset = 0; - while (endObjOffset >= 0) { - endObjOffset = FindTag(kEndObjStr, 0); - - // Can't find "endobj". - if (endObjOffset < 0) - break; - - // Stop searching when "endobj" is found. - if (IsWholeWord(m_Pos - kEndObjStr.GetLength(), m_FileLen, kEndObjStr, - TRUE)) { - endObjOffset = m_Pos - streamStartPos - kEndObjStr.GetLength(); - break; - } - } - - // Can't find "endstream" or "endobj". - if (endStreamOffset < 0 && endObjOffset < 0) { - pDict->Release(); - return nullptr; - } - - if (endStreamOffset < 0 && endObjOffset >= 0) { - // Correct the position of end stream. - endStreamOffset = endObjOffset; - } else if (endStreamOffset >= 0 && endObjOffset < 0) { - // Correct the position of end obj. - endObjOffset = endStreamOffset; - } else if (endStreamOffset > endObjOffset) { - endStreamOffset = endObjOffset; - } - - len = endStreamOffset; - int numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 2); - if (numMarkers == 2) { - len -= 2; - } else { - numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 1); - if (numMarkers == 1) { - len -= 1; - } - } - - if (len < 0) { - pDict->Release(); - return nullptr; - } - pDict->SetIntegerFor("Length", len); - } - m_Pos = streamStartPos; - } - - if (len < 0) { - pDict->Release(); - return nullptr; - } - - uint8_t* pData = nullptr; - if (len > 0) { - pData = FX_Alloc(uint8_t, len); - ReadBlock(pData, len); - if (pCryptoHandler) { - CFX_BinaryBuf dest_buf; - dest_buf.EstimateSize(pCryptoHandler->DecryptGetSize(len)); - - void* context = pCryptoHandler->DecryptStart(objnum, gennum); - pCryptoHandler->DecryptStream(context, pData, len, dest_buf); - pCryptoHandler->DecryptFinish(context, dest_buf); - - FX_Free(pData); - pData = dest_buf.GetBuffer(); - len = dest_buf.GetSize(); - dest_buf.DetachBuffer(); - } - } - - CPDF_Stream* pStream = new CPDF_Stream(pData, len, pDict); - streamStartPos = m_Pos; - FXSYS_memset(m_WordBuffer, 0, kEndObjStr.GetLength() + 1); - - GetNextWordInternal(nullptr); - - int numMarkers = ReadEOLMarkers(m_Pos); - if (m_WordSize == static_cast(kEndObjStr.GetLength()) && - numMarkers != 0 && - FXSYS_memcmp(m_WordBuffer, kEndObjStr.raw_str(), - kEndObjStr.GetLength()) == 0) { - m_Pos = streamStartPos; - } - return pStream; -} - -void CPDF_SyntaxParser::InitParser(IFX_FileRead* pFileAccess, - uint32_t HeaderOffset) { - FX_Free(m_pFileBuf); - - m_pFileBuf = FX_Alloc(uint8_t, m_BufSize); - m_HeaderOffset = HeaderOffset; - m_FileLen = pFileAccess->GetSize(); - m_Pos = 0; - m_pFileAccess = pFileAccess; - m_BufOffset = 0; - pFileAccess->ReadBlock( - m_pFileBuf, 0, - (size_t)((FX_FILESIZE)m_BufSize > m_FileLen ? m_FileLen : m_BufSize)); -} - -uint32_t CPDF_SyntaxParser::GetDirectNum() { - bool bIsNumber; - GetNextWordInternal(&bIsNumber); - if (!bIsNumber) - return 0; - - m_WordBuffer[m_WordSize] = 0; - return FXSYS_atoui(reinterpret_cast(m_WordBuffer)); -} - -bool CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos, - FX_FILESIZE limit, - const CFX_ByteStringC& tag, - FX_BOOL checkKeyword) { - const uint32_t taglen = tag.GetLength(); - - bool bCheckLeft = !PDFCharIsDelimiter(tag[0]) && !PDFCharIsWhitespace(tag[0]); - bool bCheckRight = !PDFCharIsDelimiter(tag[taglen - 1]) && - !PDFCharIsWhitespace(tag[taglen - 1]); - - uint8_t ch; - if (bCheckRight && startpos + (int32_t)taglen <= limit && - GetCharAt(startpos + (int32_t)taglen, ch)) { - if (PDFCharIsNumeric(ch) || PDFCharIsOther(ch) || - (checkKeyword && PDFCharIsDelimiter(ch))) { - return false; - } - } - - if (bCheckLeft && startpos > 0 && GetCharAt(startpos - 1, ch)) { - if (PDFCharIsNumeric(ch) || PDFCharIsOther(ch) || - (checkKeyword && PDFCharIsDelimiter(ch))) { - return false; - } - } - return true; -} - -// TODO(dsinclair): Split into a SearchWordForward and SearchWordBackwards -// and drop the bool. -FX_BOOL CPDF_SyntaxParser::SearchWord(const CFX_ByteStringC& tag, - FX_BOOL bWholeWord, - FX_BOOL bForward, - FX_FILESIZE limit) { - int32_t taglen = tag.GetLength(); - if (taglen == 0) - return FALSE; - - FX_FILESIZE pos = m_Pos; - int32_t offset = 0; - if (!bForward) - offset = taglen - 1; - - const uint8_t* tag_data = tag.raw_str(); - uint8_t byte; - while (1) { - if (bForward) { - if (limit && pos >= m_Pos + limit) - return FALSE; - - if (!GetCharAt(pos, byte)) - return FALSE; - - } else { - if (limit && pos <= m_Pos - limit) - return FALSE; - - if (!GetCharAtBackward(pos, byte)) - return FALSE; - } - - if (byte == tag_data[offset]) { - if (bForward) { - offset++; - if (offset < taglen) { - pos++; - continue; - } - } else { - offset--; - if (offset >= 0) { - pos--; - continue; - } - } - - FX_FILESIZE startpos = bForward ? pos - taglen + 1 : pos; - if (!bWholeWord || IsWholeWord(startpos, limit, tag, FALSE)) { - m_Pos = startpos; - return TRUE; - } - } - - if (bForward) { - offset = byte == tag_data[0] ? 1 : 0; - pos++; - } else { - offset = byte == tag_data[taglen - 1] ? taglen - 2 : taglen - 1; - pos--; - } - - if (pos < 0) - return FALSE; - } - - return FALSE; -} - -int32_t CPDF_SyntaxParser::SearchMultiWord(const CFX_ByteStringC& tags, - FX_BOOL bWholeWord, - FX_FILESIZE limit) { - int32_t ntags = 1; - for (int i = 0; i < tags.GetLength(); ++i) { - if (tags[i] == 0) - ++ntags; - } - - // Ensure that the input byte string happens to be nul-terminated. This - // need not be the case, but the loop below uses this guarantee to put - // the last pattern into the vector. - ASSERT(tags[tags.GetLength()] == 0); - std::vector patterns(ntags); - uint32_t start = 0; - uint32_t itag = 0; - uint32_t max_len = 0; - for (int i = 0; i <= tags.GetLength(); ++i) { - if (tags[i] == 0) { - uint32_t len = i - start; - max_len = std::max(len, max_len); - patterns[itag].m_bsTag = tags.Mid(start, len); - patterns[itag].m_Offset = 0; - start = i + 1; - ++itag; - } - } - - const FX_FILESIZE pos_limit = m_Pos + limit; - for (FX_FILESIZE pos = m_Pos; !limit || pos < pos_limit; ++pos) { - uint8_t byte; - if (!GetCharAt(pos, byte)) - break; - - for (int i = 0; i < ntags; ++i) { - SearchTagRecord& pat = patterns[i]; - if (pat.m_bsTag[pat.m_Offset] != byte) { - pat.m_Offset = (pat.m_bsTag[0] == byte) ? 1 : 0; - continue; - } - - ++pat.m_Offset; - if (pat.m_Offset != pat.m_bsTag.GetLength()) - continue; - - if (!bWholeWord || IsWholeWord(pos - pat.m_bsTag.GetLength(), limit, - pat.m_bsTag, FALSE)) { - return i; - } - - pat.m_Offset = (pat.m_bsTag[0] == byte) ? 1 : 0; - } - } - return -1; -} - -FX_FILESIZE CPDF_SyntaxParser::FindTag(const CFX_ByteStringC& tag, - FX_FILESIZE limit) { - int32_t taglen = tag.GetLength(); - int32_t match = 0; - limit += m_Pos; - FX_FILESIZE startpos = m_Pos; - - while (1) { - uint8_t ch; - if (!GetNextChar(ch)) - return -1; - - if (ch == tag[match]) { - match++; - if (match == taglen) - return m_Pos - startpos - taglen; - } else { - match = ch == tag[0] ? 1 : 0; - } - - if (limit && m_Pos == limit) - return -1; - } - return -1; -} - -void CPDF_SyntaxParser::SetEncrypt( - std::unique_ptr pCryptoHandler) { - m_pCryptoHandler = std::move(pCryptoHandler); -} - -CFX_ByteString CPDF_SyntaxParser::MaybeIntern(const CFX_ByteString& str) { - return m_pPool ? m_pPool->Intern(str) : str; -} diff --git a/core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h b/core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h deleted file mode 100644 index 3a9f1b473a..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_CPDF_SYNTAX_PARSER_H_ -#define CORE_FPDFAPI_FPDF_PARSER_CPDF_SYNTAX_PARSER_H_ - -#include - -#include "core/fxcrt/cfx_string_pool_template.h" -#include "core/fxcrt/cfx_weak_ptr.h" -#include "core/fxcrt/fx_basic.h" - -class CPDF_CryptoHandler; -class CPDF_Dictionary; -class CPDF_IndirectObjectHolder; -class CPDF_Object; -class CPDF_Stream; -class IFX_FileRead; - -class CPDF_SyntaxParser { - public: - CPDF_SyntaxParser(); - explicit CPDF_SyntaxParser(const CFX_WeakPtr& pPool); - ~CPDF_SyntaxParser(); - - void InitParser(IFX_FileRead* pFileAccess, uint32_t HeaderOffset); - - FX_FILESIZE SavePos() const { return m_Pos; } - void RestorePos(FX_FILESIZE pos) { m_Pos = pos; } - - CPDF_Object* GetObject(CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - uint32_t gennum, - FX_BOOL bDecrypt); - CPDF_Object* GetObjectForStrict(CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - uint32_t gennum); - CFX_ByteString GetKeyword(); - - void ToNextLine(); - void ToNextWord(); - - FX_BOOL SearchWord(const CFX_ByteStringC& word, - FX_BOOL bWholeWord, - FX_BOOL bForward, - FX_FILESIZE limit); - int SearchMultiWord(const CFX_ByteStringC& words, - FX_BOOL bWholeWord, - FX_FILESIZE limit); - FX_FILESIZE FindTag(const CFX_ByteStringC& tag, FX_FILESIZE limit); - - void SetEncrypt(std::unique_ptr pCryptoHandler); - - FX_BOOL ReadBlock(uint8_t* pBuf, uint32_t size); - FX_BOOL GetCharAt(FX_FILESIZE pos, uint8_t& ch); - CFX_ByteString GetNextWord(bool* bIsNumber); - - private: - friend class CPDF_Parser; - friend class CPDF_DataAvail; - friend class cpdf_syntax_parser_ReadHexString_Test; - - static const int kParserMaxRecursionDepth = 64; - static int s_CurrentRecursionDepth; - - uint32_t GetDirectNum(); - FX_BOOL GetNextChar(uint8_t& ch); - FX_BOOL GetCharAtBackward(FX_FILESIZE pos, uint8_t& ch); - void GetNextWordInternal(bool* bIsNumber); - bool IsWholeWord(FX_FILESIZE startpos, - FX_FILESIZE limit, - const CFX_ByteStringC& tag, - FX_BOOL checkKeyword); - - CFX_ByteString ReadString(); - CFX_ByteString ReadHexString(); - unsigned int ReadEOLMarkers(FX_FILESIZE pos); - CPDF_Stream* ReadStream(CPDF_Dictionary* pDict, - uint32_t objnum, - uint32_t gennum); - - CFX_ByteString MaybeIntern(const CFX_ByteString& str); - - FX_FILESIZE m_Pos; - int m_MetadataObjnum; - IFX_FileRead* m_pFileAccess; - FX_FILESIZE m_HeaderOffset; - FX_FILESIZE m_FileLen; - uint8_t* m_pFileBuf; - uint32_t m_BufSize; - FX_FILESIZE m_BufOffset; - std::unique_ptr m_pCryptoHandler; - uint8_t m_WordBuffer[257]; - uint32_t m_WordSize; - CFX_WeakPtr m_pPool; -}; - -#endif // CORE_FPDFAPI_FPDF_PARSER_CPDF_SYNTAX_PARSER_H_ diff --git a/core/fpdfapi/fpdf_parser/cpdf_syntax_parser_unittest.cpp b/core/fpdfapi/fpdf_parser/cpdf_syntax_parser_unittest.cpp deleted file mode 100644 index eb19652a0c..0000000000 --- a/core/fpdfapi/fpdf_parser/cpdf_syntax_parser_unittest.cpp +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2016 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. - -#include -#include - -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h" -#include "core/fxcrt/fx_ext.h" -#include "core/fxcrt/fx_stream.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/utils/path_service.h" - -TEST(cpdf_syntax_parser, ReadHexString) { - { - // Empty string. - uint8_t data[] = ""; - ScopedFileStream stream(FX_CreateMemoryStream(data, 0, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("", parser.ReadHexString()); - EXPECT_EQ(0, parser.SavePos()); - } - - { - // Blank string. - uint8_t data[] = " "; - ScopedFileStream stream(FX_CreateMemoryStream(data, 2, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("", parser.ReadHexString()); - EXPECT_EQ(2, parser.SavePos()); - } - - { - // Skips unknown characters. - uint8_t data[] = "z12b"; - ScopedFileStream stream(FX_CreateMemoryStream(data, 4, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("\x12\xb0", parser.ReadHexString()); - EXPECT_EQ(4, parser.SavePos()); - } - - { - // Skips unknown characters. - uint8_t data[] = "*<&*#$^&@1"; - ScopedFileStream stream(FX_CreateMemoryStream(data, 10, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("\x10", parser.ReadHexString()); - EXPECT_EQ(10, parser.SavePos()); - } - - { - // Skips unknown characters. - uint8_t data[] = "\x80zab"; - ScopedFileStream stream(FX_CreateMemoryStream(data, 4, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("\xab", parser.ReadHexString()); - EXPECT_EQ(4, parser.SavePos()); - } - - { - // Skips unknown characters. - uint8_t data[] = "\xffzab"; - ScopedFileStream stream(FX_CreateMemoryStream(data, 4, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("\xab", parser.ReadHexString()); - EXPECT_EQ(4, parser.SavePos()); - } - - { - // Regular conversion. - uint8_t data[] = "1A2b>abcd"; - ScopedFileStream stream(FX_CreateMemoryStream(data, 9, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("\x1a\x2b", parser.ReadHexString()); - EXPECT_EQ(5, parser.SavePos()); - } - - { - // Position out of bounds. - uint8_t data[] = "12ab>"; - ScopedFileStream stream(FX_CreateMemoryStream(data, 5, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - parser.RestorePos(5); - EXPECT_EQ("", parser.ReadHexString()); - - parser.RestorePos(6); - EXPECT_EQ("", parser.ReadHexString()); - - parser.RestorePos(-1); - EXPECT_EQ("", parser.ReadHexString()); - - parser.RestorePos(std::numeric_limits::max()); - EXPECT_EQ("", parser.ReadHexString()); - - // Check string still parses when set to 0. - parser.RestorePos(0); - EXPECT_EQ("\x12\xab", parser.ReadHexString()); - } - - { - // Missing ending >. - uint8_t data[] = "1A2b"; - ScopedFileStream stream(FX_CreateMemoryStream(data, 4, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("\x1a\x2b", parser.ReadHexString()); - EXPECT_EQ(4, parser.SavePos()); - } - - { - // Missing ending >. - uint8_t data[] = "12abz"; - ScopedFileStream stream(FX_CreateMemoryStream(data, 5, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("\x12\xab", parser.ReadHexString()); - EXPECT_EQ(5, parser.SavePos()); - } - - { - // Uneven number of bytes. - uint8_t data[] = "1A2>asdf"; - ScopedFileStream stream(FX_CreateMemoryStream(data, 8, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("\x1a\x20", parser.ReadHexString()); - EXPECT_EQ(4, parser.SavePos()); - } - - { - // Uneven number of bytes. - uint8_t data[] = "1A2zasdf"; - ScopedFileStream stream(FX_CreateMemoryStream(data, 8, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("\x1a\x2a\xdf", parser.ReadHexString()); - EXPECT_EQ(8, parser.SavePos()); - } - - { - // Just ending character. - uint8_t data[] = ">"; - ScopedFileStream stream(FX_CreateMemoryStream(data, 1, FALSE)); - - CPDF_SyntaxParser parser; - parser.InitParser(stream.get(), 0); - EXPECT_EQ("", parser.ReadHexString()); - EXPECT_EQ(1, parser.SavePos()); - } -} diff --git a/core/fpdfapi/fpdf_parser/fpdf_parser_decode.cpp b/core/fpdfapi/fpdf_parser/fpdf_parser_decode.cpp deleted file mode 100644 index 4f172c0073..0000000000 --- a/core/fpdfapi/fpdf_parser/fpdf_parser_decode.cpp +++ /dev/null @@ -1,575 +0,0 @@ -// 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 - -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" - -#include - -#include -#include -#include - -#include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h" -#include "core/fxcodec/fx_codec.h" -#include "core/fxcrt/fx_ext.h" -#include "third_party/base/stl_util.h" - -namespace { - -const uint32_t kMaxStreamSize = 20 * 1024 * 1024; - -bool CheckFlateDecodeParams(int Colors, int BitsPerComponent, int Columns) { - if (Colors < 0 || BitsPerComponent < 0 || Columns < 0) - return false; - - int check = Columns; - if (check > 0 && Colors > INT_MAX / check) - return false; - - check *= Colors; - if (check > 0 && BitsPerComponent > INT_MAX / check) - return false; - - return check * BitsPerComponent <= INT_MAX - 7; -} - -} // namespace - -const uint16_t PDFDocEncoding[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, - 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, - 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x02d8, 0x02c7, 0x02c6, - 0x02d9, 0x02dd, 0x02db, 0x02da, 0x02dc, 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, - 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, - 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, - 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, - 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, - 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, - 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, - 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, - 0x007e, 0x0000, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, - 0x2044, 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, - 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x0141, 0x0152, 0x0160, 0x0178, - 0x017d, 0x0131, 0x0142, 0x0153, 0x0161, 0x017e, 0x0000, 0x20ac, 0x00a1, - 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, - 0x00ab, 0x00ac, 0x0000, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, - 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, - 0x00bd, 0x00be, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, - 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, - 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, - 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, - 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, - 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, - 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, - 0x00fc, 0x00fd, 0x00fe, 0x00ff}; - -uint32_t A85Decode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t*& dest_buf, - uint32_t& dest_size) { - dest_size = 0; - dest_buf = nullptr; - if (src_size == 0) - return 0; - - // Count legal characters and zeros. - uint32_t zcount = 0; - uint32_t pos = 0; - while (pos < src_size) { - uint8_t ch = src_buf[pos]; - if (ch == 'z') { - zcount++; - } else if ((ch < '!' || ch > 'u') && !PDFCharIsLineEnding(ch) && - ch != ' ' && ch != '\t') { - break; - } - pos++; - } - // No content to decode. - if (pos == 0) - return 0; - - // Count the space needed to contain non-zero characters. The encoding ratio - // of Ascii85 is 4:5. - uint32_t space_for_non_zeroes = (pos - zcount) / 5 * 4 + 4; - if (zcount > (UINT_MAX - space_for_non_zeroes) / 4) { - return (uint32_t)-1; - } - dest_buf = FX_Alloc(uint8_t, zcount * 4 + space_for_non_zeroes); - size_t state = 0; - uint32_t res = 0; - pos = dest_size = 0; - while (pos < src_size) { - uint8_t ch = src_buf[pos++]; - if (PDFCharIsLineEnding(ch) || ch == ' ' || ch == '\t') - continue; - - if (ch == 'z') { - FXSYS_memset(dest_buf + dest_size, 0, 4); - state = 0; - res = 0; - dest_size += 4; - } else if (ch >= '!' && ch <= 'u') { - res = res * 85 + ch - 33; - state++; - if (state == 5) { - for (size_t i = 0; i < 4; i++) { - dest_buf[dest_size++] = (uint8_t)(res >> (3 - i) * 8); - } - state = 0; - res = 0; - } - } else { - // The end or illegal character. - break; - } - } - // Handle partial group. - if (state) { - for (size_t i = state; i < 5; i++) - res = res * 85 + 84; - for (size_t i = 0; i < state - 1; i++) - dest_buf[dest_size++] = (uint8_t)(res >> (3 - i) * 8); - } - if (pos < src_size && src_buf[pos] == '>') - pos++; - return pos; -} - -uint32_t HexDecode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t*& dest_buf, - uint32_t& dest_size) { - dest_size = 0; - if (src_size == 0) { - dest_buf = nullptr; - return 0; - } - - uint32_t i = 0; - // Find the end of data. - while (i < src_size && src_buf[i] != '>') - i++; - - dest_buf = FX_Alloc(uint8_t, i / 2 + 1); - bool bFirst = true; - for (i = 0; i < src_size; i++) { - uint8_t ch = src_buf[i]; - if (PDFCharIsLineEnding(ch) || ch == ' ' || ch == '\t') - continue; - - if (ch == '>') { - ++i; - break; - } - if (!std::isxdigit(ch)) - continue; - - int digit = FXSYS_toHexDigit(ch); - if (bFirst) - dest_buf[dest_size] = digit * 16; - else - dest_buf[dest_size++] += digit; - - bFirst = !bFirst; - } - if (!bFirst) - dest_size++; - return i; -} - -uint32_t RunLengthDecode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t*& dest_buf, - uint32_t& dest_size) { - uint32_t i = 0; - dest_size = 0; - while (i < src_size) { - if (src_buf[i] == 128) - break; - - uint32_t old = dest_size; - if (src_buf[i] < 128) { - dest_size += src_buf[i] + 1; - if (dest_size < old) - return FX_INVALID_OFFSET; - i += src_buf[i] + 2; - } else { - dest_size += 257 - src_buf[i]; - if (dest_size < old) - return FX_INVALID_OFFSET; - i += 2; - } - } - if (dest_size >= kMaxStreamSize) - return FX_INVALID_OFFSET; - - dest_buf = FX_Alloc(uint8_t, dest_size); - i = 0; - int dest_count = 0; - while (i < src_size) { - if (src_buf[i] == 128) - break; - - if (src_buf[i] < 128) { - uint32_t copy_len = src_buf[i] + 1; - uint32_t buf_left = src_size - i - 1; - if (buf_left < copy_len) { - uint32_t delta = copy_len - buf_left; - copy_len = buf_left; - FXSYS_memset(dest_buf + dest_count + copy_len, '\0', delta); - } - FXSYS_memcpy(dest_buf + dest_count, src_buf + i + 1, copy_len); - dest_count += src_buf[i] + 1; - i += src_buf[i] + 2; - } else { - int fill = 0; - if (i < src_size - 1) { - fill = src_buf[i + 1]; - } - FXSYS_memset(dest_buf + dest_count, fill, 257 - src_buf[i]); - dest_count += 257 - src_buf[i]; - i += 2; - } - } - - return std::min(i + 1, src_size); -} - -CCodec_ScanlineDecoder* FPDFAPI_CreateFaxDecoder( - const uint8_t* src_buf, - uint32_t src_size, - int width, - int height, - const CPDF_Dictionary* pParams) { - int K = 0; - bool EndOfLine = false; - bool ByteAlign = false; - bool BlackIs1 = false; - int Columns = 1728; - int Rows = 0; - if (pParams) { - K = pParams->GetIntegerFor("K"); - EndOfLine = !!pParams->GetIntegerFor("EndOfLine"); - ByteAlign = !!pParams->GetIntegerFor("EncodedByteAlign"); - BlackIs1 = !!pParams->GetIntegerFor("BlackIs1"); - Columns = pParams->GetIntegerFor("Columns", 1728); - Rows = pParams->GetIntegerFor("Rows"); - if (Rows > USHRT_MAX) { - Rows = 0; - } - } - return CPDF_ModuleMgr::Get()->GetFaxModule()->CreateDecoder( - src_buf, src_size, width, height, K, EndOfLine, ByteAlign, BlackIs1, - Columns, Rows); -} - -CCodec_ScanlineDecoder* FPDFAPI_CreateFlateDecoder( - const uint8_t* src_buf, - uint32_t src_size, - int width, - int height, - int nComps, - int bpc, - const CPDF_Dictionary* pParams) { - int predictor = 0; - int Colors = 0, BitsPerComponent = 0, Columns = 0; - if (pParams) { - predictor = pParams->GetIntegerFor("Predictor"); - Colors = pParams->GetIntegerFor("Colors", 1); - BitsPerComponent = pParams->GetIntegerFor("BitsPerComponent", 8); - Columns = pParams->GetIntegerFor("Columns", 1); - if (!CheckFlateDecodeParams(Colors, BitsPerComponent, Columns)) { - return nullptr; - } - } - return CPDF_ModuleMgr::Get()->GetFlateModule()->CreateDecoder( - src_buf, src_size, width, height, nComps, bpc, predictor, Colors, - BitsPerComponent, Columns); -} - -uint32_t FPDFAPI_FlateOrLZWDecode(FX_BOOL bLZW, - const uint8_t* src_buf, - uint32_t src_size, - CPDF_Dictionary* pParams, - uint32_t estimated_size, - uint8_t*& dest_buf, - uint32_t& dest_size) { - int predictor = 0; - FX_BOOL bEarlyChange = TRUE; - int Colors = 0, BitsPerComponent = 0, Columns = 0; - if (pParams) { - predictor = pParams->GetIntegerFor("Predictor"); - bEarlyChange = pParams->GetIntegerFor("EarlyChange", 1); - Colors = pParams->GetIntegerFor("Colors", 1); - BitsPerComponent = pParams->GetIntegerFor("BitsPerComponent", 8); - Columns = pParams->GetIntegerFor("Columns", 1); - if (!CheckFlateDecodeParams(Colors, BitsPerComponent, Columns)) { - return (uint32_t)-1; - } - } - return CPDF_ModuleMgr::Get()->GetFlateModule()->FlateOrLZWDecode( - bLZW, src_buf, src_size, bEarlyChange, predictor, Colors, - BitsPerComponent, Columns, estimated_size, dest_buf, dest_size); -} - -FX_BOOL PDF_DataDecode(const uint8_t* src_buf, - uint32_t src_size, - const CPDF_Dictionary* pDict, - uint8_t*& dest_buf, - uint32_t& dest_size, - CFX_ByteString& ImageEncoding, - CPDF_Dictionary*& pImageParms, - uint32_t last_estimated_size, - FX_BOOL bImageAcc) { - CPDF_Object* pDecoder = pDict ? pDict->GetDirectObjectFor("Filter") : nullptr; - if (!pDecoder || (!pDecoder->IsArray() && !pDecoder->IsName())) - return FALSE; - - CPDF_Object* pParams = - pDict ? pDict->GetDirectObjectFor("DecodeParms") : nullptr; - - std::vector> DecoderArray; - if (CPDF_Array* pDecoders = pDecoder->AsArray()) { - CPDF_Array* pParamsArray = ToArray(pParams); - for (size_t i = 0; i < pDecoders->GetCount(); i++) { - DecoderArray.push_back( - {pDecoders->GetStringAt(i), - pParamsArray ? pParamsArray->GetDictAt(i) : nullptr}); - } - } else { - DecoderArray.push_back( - {pDecoder->GetString(), pParams ? pParams->GetDict() : nullptr}); - } - uint8_t* last_buf = const_cast(src_buf); - uint32_t last_size = src_size; - int nSize = pdfium::CollectionSize(DecoderArray); - for (int i = 0; i < nSize; i++) { - int estimated_size = i == nSize - 1 ? last_estimated_size : 0; - CFX_ByteString decoder = DecoderArray[i].first; - CPDF_Dictionary* pParam = ToDictionary(DecoderArray[i].second); - uint8_t* new_buf = nullptr; - uint32_t new_size = (uint32_t)-1; - int offset = -1; - if (decoder == "FlateDecode" || decoder == "Fl") { - if (bImageAcc && i == nSize - 1) { - ImageEncoding = "FlateDecode"; - dest_buf = (uint8_t*)last_buf; - dest_size = last_size; - pImageParms = pParam; - return TRUE; - } - offset = FPDFAPI_FlateOrLZWDecode(FALSE, last_buf, last_size, pParam, - estimated_size, new_buf, new_size); - } else if (decoder == "LZWDecode" || decoder == "LZW") { - offset = FPDFAPI_FlateOrLZWDecode(TRUE, last_buf, last_size, pParam, - estimated_size, new_buf, new_size); - } else if (decoder == "ASCII85Decode" || decoder == "A85") { - offset = A85Decode(last_buf, last_size, new_buf, new_size); - } else if (decoder == "ASCIIHexDecode" || decoder == "AHx") { - offset = HexDecode(last_buf, last_size, new_buf, new_size); - } else if (decoder == "RunLengthDecode" || decoder == "RL") { - if (bImageAcc && i == nSize - 1) { - ImageEncoding = "RunLengthDecode"; - dest_buf = (uint8_t*)last_buf; - dest_size = last_size; - pImageParms = pParam; - return TRUE; - } - offset = RunLengthDecode(last_buf, last_size, new_buf, new_size); - } else if (decoder == "Crypt") { - continue; - } else { - // If we get here, assume it's an image decoder. - if (decoder == "DCT") { - decoder = "DCTDecode"; - } else if (decoder == "CCF") { - decoder = "CCITTFaxDecode"; - } - ImageEncoding = decoder; - pImageParms = pParam; - dest_buf = (uint8_t*)last_buf; - dest_size = last_size; - if (CPDF_Array* pDecoders = pDecoder->AsArray()) - pDecoders->RemoveAt(i + 1, pDecoders->GetCount() - i - 1); - return TRUE; - } - if (last_buf != src_buf) { - FX_Free(last_buf); - } - if (offset == -1) { - FX_Free(new_buf); - return FALSE; - } - last_buf = new_buf; - last_size = new_size; - } - ImageEncoding = ""; - pImageParms = nullptr; - dest_buf = last_buf; - dest_size = last_size; - return TRUE; -} - -CFX_WideString PDF_DecodeText(const uint8_t* src_data, uint32_t src_len) { - CFX_WideString result; - if (src_len >= 2 && ((src_data[0] == 0xfe && src_data[1] == 0xff) || - (src_data[0] == 0xff && src_data[1] == 0xfe))) { - bool bBE = src_data[0] == 0xfe; - uint32_t max_chars = (src_len - 2) / 2; - if (!max_chars) { - return result; - } - if (src_data[0] == 0xff) { - bBE = !src_data[2]; - } - FX_WCHAR* dest_buf = result.GetBuffer(max_chars); - const uint8_t* uni_str = src_data + 2; - int dest_pos = 0; - for (uint32_t i = 0; i < max_chars * 2; i += 2) { - uint16_t unicode = bBE ? (uni_str[i] << 8 | uni_str[i + 1]) - : (uni_str[i + 1] << 8 | uni_str[i]); - if (unicode == 0x1b) { - i += 2; - while (i < max_chars * 2) { - uint16_t unicode2 = bBE ? (uni_str[i] << 8 | uni_str[i + 1]) - : (uni_str[i + 1] << 8 | uni_str[i]); - i += 2; - if (unicode2 == 0x1b) - break; - } - } else { - dest_buf[dest_pos++] = unicode; - } - } - result.ReleaseBuffer(dest_pos); - } else { - FX_WCHAR* dest_buf = result.GetBuffer(src_len); - for (uint32_t i = 0; i < src_len; i++) - dest_buf[i] = PDFDocEncoding[src_data[i]]; - result.ReleaseBuffer(src_len); - } - return result; -} - -CFX_WideString PDF_DecodeText(const CFX_ByteString& bstr) { - return PDF_DecodeText((const uint8_t*)bstr.c_str(), bstr.GetLength()); -} - -CFX_ByteString PDF_EncodeText(const FX_WCHAR* pString, int len) { - if (len == -1) { - len = FXSYS_wcslen(pString); - } - CFX_ByteString result; - FX_CHAR* dest_buf1 = result.GetBuffer(len); - int i; - for (i = 0; i < len; i++) { - int code; - for (code = 0; code < 256; code++) - if (PDFDocEncoding[code] == pString[i]) { - break; - } - if (code == 256) { - break; - } - dest_buf1[i] = code; - } - result.ReleaseBuffer(i); - if (i == len) { - return result; - } - - if (len > INT_MAX / 2 - 1) { - result.ReleaseBuffer(0); - return result; - } - - int encLen = len * 2 + 2; - - uint8_t* dest_buf2 = (uint8_t*)result.GetBuffer(encLen); - dest_buf2[0] = 0xfe; - dest_buf2[1] = 0xff; - dest_buf2 += 2; - for (int j = 0; j < len; j++) { - *dest_buf2++ = pString[i] >> 8; - *dest_buf2++ = (uint8_t)pString[j]; - } - result.ReleaseBuffer(encLen); - return result; -} - -CFX_ByteString PDF_EncodeText(const CFX_WideString& str) { - return PDF_EncodeText(str.c_str(), str.GetLength()); -} - -CFX_ByteString PDF_EncodeString(const CFX_ByteString& src, FX_BOOL bHex) { - CFX_ByteTextBuf result; - int srclen = src.GetLength(); - if (bHex) { - result.AppendChar('<'); - for (int i = 0; i < srclen; i++) { - result.AppendChar("0123456789ABCDEF"[src[i] / 16]); - result.AppendChar("0123456789ABCDEF"[src[i] % 16]); - } - result.AppendChar('>'); - return result.MakeString(); - } - result.AppendChar('('); - for (int i = 0; i < srclen; i++) { - uint8_t ch = src[i]; - if (ch == 0x0a) { - result << "\\n"; - continue; - } - if (ch == 0x0d) { - result << "\\r"; - continue; - } - if (ch == ')' || ch == '\\' || ch == '(') - result.AppendChar('\\'); - result.AppendChar(ch); - } - result.AppendChar(')'); - return result.MakeString(); -} - -bool FlateEncode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t** dest_buf, - uint32_t* dest_size) { - CCodec_ModuleMgr* pEncoders = CPDF_ModuleMgr::Get()->GetCodecModule(); - return pEncoders && - pEncoders->GetFlateModule()->Encode(src_buf, src_size, dest_buf, - dest_size); -} - -bool PngEncode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t** dest_buf, - uint32_t* dest_size) { - CCodec_ModuleMgr* pEncoders = CPDF_ModuleMgr::Get()->GetCodecModule(); - return pEncoders && - pEncoders->GetFlateModule()->PngEncode(src_buf, src_size, dest_buf, - dest_size); -} - -uint32_t FlateDecode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t*& dest_buf, - uint32_t& dest_size) { - CCodec_ModuleMgr* pEncoders = CPDF_ModuleMgr::Get()->GetCodecModule(); - if (pEncoders) { - return pEncoders->GetFlateModule()->FlateOrLZWDecode( - FALSE, src_buf, src_size, FALSE, 0, 0, 0, 0, 0, dest_buf, dest_size); - } - return 0; -} diff --git a/core/fpdfapi/fpdf_parser/fpdf_parser_decode.h b/core/fpdfapi/fpdf_parser/fpdf_parser_decode.h deleted file mode 100644 index fab148bc14..0000000000 --- a/core/fpdfapi/fpdf_parser/fpdf_parser_decode.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_FPDF_PARSER_DECODE_H_ -#define CORE_FPDFAPI_FPDF_PARSER_FPDF_PARSER_DECODE_H_ - -#include "core/fxcrt/fx_basic.h" - -class CPDF_Dictionary; - -// Indexed by 8-bit char code, contains unicode code points. -extern const uint16_t PDFDocEncoding[256]; - -CFX_ByteString PDF_NameDecode(const CFX_ByteStringC& 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 uint8_t* pData, uint32_t size); -CFX_WideString PDF_DecodeText(const CFX_ByteString& bstr); -CFX_ByteString PDF_EncodeText(const FX_WCHAR* pString, int len = -1); -CFX_ByteString PDF_EncodeText(const CFX_WideString& str); - -bool FlateEncode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t** dest_buf, - uint32_t* dest_size); - -// This used to have more parameters like the predictor and bpc, but there was -// only one caller, so the interface has been simplified, the values are hard -// coded, and dead code has been removed. -bool PngEncode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t** dest_buf, - uint32_t* dest_size); - -uint32_t FlateDecode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t*& dest_buf, - uint32_t& dest_size); -uint32_t RunLengthDecode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t*& dest_buf, - uint32_t& dest_size); - -// Public for testing. -uint32_t A85Decode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t*& dest_buf, - uint32_t& dest_size); -// Public for testing. -uint32_t HexDecode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t*& dest_buf, - uint32_t& dest_size); -// Public for testing. -uint32_t FPDFAPI_FlateOrLZWDecode(FX_BOOL bLZW, - const uint8_t* src_buf, - uint32_t src_size, - CPDF_Dictionary* pParams, - uint32_t estimated_size, - uint8_t*& dest_buf, - uint32_t& dest_size); -FX_BOOL PDF_DataDecode(const uint8_t* src_buf, - uint32_t src_size, - const CPDF_Dictionary* pDict, - uint8_t*& dest_buf, - uint32_t& dest_size, - CFX_ByteString& ImageEncoding, - CPDF_Dictionary*& pImageParms, - uint32_t estimated_size, - FX_BOOL bImageAcc); - -#endif // CORE_FPDFAPI_FPDF_PARSER_FPDF_PARSER_DECODE_H_ diff --git a/core/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp b/core/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp deleted file mode 100644 index ab0dc4ea3f..0000000000 --- a/core/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2015 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. - -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" - -#include -#include - -#include "core/fxcrt/fx_basic.h" -#include "testing/embedder_test.h" -#include "testing/fx_string_testhelpers.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/test_support.h" - -class FPDFParserDecodeEmbeddertest : public EmbedderTest {}; - -// NOTE: python's zlib.compress() and zlib.decompress() may be useful for -// external validation of the FlateEncode/FlateDecode test cases. - -TEST_F(FPDFParserDecodeEmbeddertest, FlateEncode) { - pdfium::StrFuncTestData flate_encode_cases[] = { - STR_IN_OUT_CASE("", "\x78\x9c\x03\x00\x00\x00\x00\x01"), - STR_IN_OUT_CASE(" ", "\x78\x9c\x53\x00\x00\x00\x21\x00\x21"), - STR_IN_OUT_CASE("123", "\x78\x9c\x33\x34\x32\x06\x00\01\x2d\x00\x97"), - STR_IN_OUT_CASE("\x00\xff", "\x78\x9c\x63\xf8\x0f\x00\x01\x01\x01\x00"), - STR_IN_OUT_CASE( - "1 0 0 -1 29 763 cm\n0 0 555 735 re\nW n\nq\n0 0 555 734.394 re\n" - "W n\nq\n0.8009 0 0 0.8009 0 0 cm\n1 1 1 RG 1 1 1 rg\n/G0 gs\n" - "0 0 693 917 re\nf\nQ\nQ\n", - "\x78\x9c\x33\x54\x30\x00\x42\x5d\x43\x05\x23\x4b\x05\x73\x33\x63" - "\x85\xe4\x5c\x2e\x90\x80\xa9\xa9\xa9\x82\xb9\xb1\xa9\x42\x51\x2a" - "\x57\xb8\x42\x1e\x57\x21\x92\xa0\x89\x9e\xb1\xa5\x09\x92\x84\x9e" - "\x85\x81\x81\x25\xd8\x14\x24\x26\xd0\x18\x43\x05\x10\x0c\x72\x57" - "\x80\x30\x8a\xd2\xb9\xf4\xdd\x0d\x14\xd2\x8b\xc1\x46\x99\x59\x1a" - "\x2b\x58\x1a\x9a\x83\x8c\x49\xe3\x0a\x04\x42\x00\x37\x4c\x1b\x42"), - }; - - for (size_t i = 0; i < FX_ArraySize(flate_encode_cases); ++i) { - const pdfium::StrFuncTestData& data = flate_encode_cases[i]; - unsigned char* buf = nullptr; - unsigned int buf_size; - EXPECT_TRUE(FlateEncode(data.input, data.input_size, &buf, &buf_size)); - ASSERT_TRUE(buf); - EXPECT_EQ(std::string((const char*)data.expected, data.expected_size), - std::string((const char*)buf, buf_size)) - << " for case " << i; - FX_Free(buf); - } -} - -TEST_F(FPDFParserDecodeEmbeddertest, FlateDecode) { - pdfium::DecodeTestData flate_decode_cases[] = { - STR_IN_OUT_CASE("", "", 0), - STR_IN_OUT_CASE("preposterous nonsense", "", 2), - STR_IN_OUT_CASE("\x78\x9c\x03\x00\x00\x00\x00\x01", "", 8), - STR_IN_OUT_CASE("\x78\x9c\x53\x00\x00\x00\x21\x00\x21", " ", 9), - STR_IN_OUT_CASE("\x78\x9c\x33\x34\x32\x06\x00\01\x2d\x00\x97", "123", 11), - STR_IN_OUT_CASE("\x78\x9c\x63\xf8\x0f\x00\x01\x01\x01\x00", "\x00\xff", - 10), - STR_IN_OUT_CASE( - "\x78\x9c\x33\x54\x30\x00\x42\x5d\x43\x05\x23\x4b\x05\x73\x33\x63" - "\x85\xe4\x5c\x2e\x90\x80\xa9\xa9\xa9\x82\xb9\xb1\xa9\x42\x51\x2a" - "\x57\xb8\x42\x1e\x57\x21\x92\xa0\x89\x9e\xb1\xa5\x09\x92\x84\x9e" - "\x85\x81\x81\x25\xd8\x14\x24\x26\xd0\x18\x43\x05\x10\x0c\x72\x57" - "\x80\x30\x8a\xd2\xb9\xf4\xdd\x0d\x14\xd2\x8b\xc1\x46\x99\x59\x1a" - "\x2b\x58\x1a\x9a\x83\x8c\x49\xe3\x0a\x04\x42\x00\x37\x4c\x1b\x42", - "1 0 0 -1 29 763 cm\n0 0 555 735 re\nW n\nq\n0 0 555 734.394 re\n" - "W n\nq\n0.8009 0 0 0.8009 0 0 cm\n1 1 1 RG 1 1 1 rg\n/G0 gs\n" - "0 0 693 917 re\nf\nQ\nQ\n", - 96), - }; - - for (size_t i = 0; i < FX_ArraySize(flate_decode_cases); ++i) { - const pdfium::DecodeTestData& data = flate_decode_cases[i]; - unsigned char* result = nullptr; - unsigned int result_size; - EXPECT_EQ(data.processed_size, - FlateDecode(data.input, data.input_size, result, result_size)) - << " for case " << i; - ASSERT_TRUE(result); - EXPECT_EQ(std::string((const char*)data.expected, data.expected_size), - std::string((const char*)result, result_size)) - << " for case " << i; - FX_Free(result); - } -} - -TEST_F(FPDFParserDecodeEmbeddertest, Bug_552046) { - // Tests specifying multiple image filters for a stream. Should not cause a - // crash when rendered. - EXPECT_TRUE(OpenDocument("bug_552046.pdf")); - FPDF_PAGE page = LoadPage(0); - FPDF_BITMAP bitmap = RenderPage(page); - FPDFBitmap_Destroy(bitmap); - UnloadPage(page); -} - -TEST_F(FPDFParserDecodeEmbeddertest, Bug_555784) { - // Tests bad input to the run length decoder that caused a heap overflow. - // Should not cause a crash when rendered. - EXPECT_TRUE(OpenDocument("bug_555784.pdf")); - FPDF_PAGE page = LoadPage(0); - FPDF_BITMAP bitmap = RenderPage(page); - FPDFBitmap_Destroy(bitmap); - UnloadPage(page); -} - -TEST_F(FPDFParserDecodeEmbeddertest, Bug_455199) { - // Tests object numbers with a value > 01000000. - // Should open successfully. - EXPECT_TRUE(OpenDocument("bug_455199.pdf")); - FPDF_PAGE page = LoadPage(0); - FPDF_BITMAP bitmap = RenderPage(page); - FPDFBitmap_Destroy(bitmap); - UnloadPage(page); -} diff --git a/core/fpdfapi/fpdf_parser/fpdf_parser_decode_unittest.cpp b/core/fpdfapi/fpdf_parser/fpdf_parser_decode_unittest.cpp deleted file mode 100644 index 469ca4f150..0000000000 --- a/core/fpdfapi/fpdf_parser/fpdf_parser_decode_unittest.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2015 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. - -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" - -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/test_support.h" - -TEST(fpdf_parser_decode, A85Decode) { - pdfium::DecodeTestData test_data[] = { - // Empty src string. - STR_IN_OUT_CASE("", "", 0), - // Empty content in src string. - STR_IN_OUT_CASE("~>", "", 0), - // Regular conversion. - STR_IN_OUT_CASE("FCfN8~>", "test", 7), - // End at the ending mark. - STR_IN_OUT_CASE("FCfN8~>FCfN8", "test", 7), - // Skip whitespaces. - STR_IN_OUT_CASE("\t F C\r\n \tf N 8 ~>", "test", 17), - // No ending mark. - STR_IN_OUT_CASE("@3B0)DJj_BF*)>@Gp#-s", "a funny story :)", 20), - // Non-multiple length. - STR_IN_OUT_CASE("12A", "2k", 3), - // Stop at unknown characters. - STR_IN_OUT_CASE("FCfN8FCfN8vw", "testtest", 11), - }; - for (size_t i = 0; i < FX_ArraySize(test_data); ++i) { - pdfium::DecodeTestData* ptr = &test_data[i]; - uint8_t* result = nullptr; - uint32_t result_size = 0; - EXPECT_EQ(ptr->processed_size, - A85Decode(ptr->input, ptr->input_size, result, result_size)) - << "for case " << i; - ASSERT_EQ(ptr->expected_size, result_size); - for (size_t j = 0; j < result_size; ++j) { - EXPECT_EQ(ptr->expected[j], result[j]) << "for case " << i << " char " - << j; - } - FX_Free(result); - } -} - -TEST(fpdf_parser_decode, HexDecode) { - pdfium::DecodeTestData test_data[] = { - // Empty src string. - STR_IN_OUT_CASE("", "", 0), - // Empty content in src string. - STR_IN_OUT_CASE(">", "", 1), - // Only whitespaces in src string. - STR_IN_OUT_CASE("\t \r\n>", "", 7), - // Regular conversion. - STR_IN_OUT_CASE("12Ac>zzz", "\x12\xac", 5), - // Skip whitespaces. - STR_IN_OUT_CASE("12 Ac\t02\r\nBF>zzz>", "\x12\xac\x02\xbf", 13), - // Non-multiple length. - STR_IN_OUT_CASE("12A>zzz", "\x12\xa0", 4), - // Skips unknown characters. - STR_IN_OUT_CASE("12tk \tAc>zzz", "\x12\xac", 10), - // No ending mark. - STR_IN_OUT_CASE("12AcED3c3456", "\x12\xac\xed\x3c\x34\x56", 12), - }; - for (size_t i = 0; i < FX_ArraySize(test_data); ++i) { - pdfium::DecodeTestData* ptr = &test_data[i]; - uint8_t* result = nullptr; - uint32_t result_size = 0; - EXPECT_EQ(ptr->processed_size, - HexDecode(ptr->input, ptr->input_size, result, result_size)) - << "for case " << i; - ASSERT_EQ(ptr->expected_size, result_size); - for (size_t j = 0; j < result_size; ++j) { - EXPECT_EQ(ptr->expected[j], result[j]) << "for case " << i << " char " - << j; - } - FX_Free(result); - } -} diff --git a/core/fpdfapi/fpdf_parser/fpdf_parser_utility.cpp b/core/fpdfapi/fpdf_parser/fpdf_parser_utility.cpp deleted file mode 100644 index 304cb4a7e6..0000000000 --- a/core/fpdfapi/fpdf_parser/fpdf_parser_utility.cpp +++ /dev/null @@ -1,221 +0,0 @@ -// 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 - -#include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h" - -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" -#include "core/fxcrt/fx_ext.h" - -// Indexed by 8-bit character code, contains either: -// 'W' - for whitespace: NUL, TAB, CR, LF, FF, SPACE, 0x80, 0xff -// 'N' - for numeric: 0123456789+-. -// 'D' - for delimiter: %()/<>[]{} -// 'R' - otherwise. -const char PDF_CharType[256] = { - // NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO - // SI - 'W', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'W', 'W', 'R', 'W', 'W', 'R', - 'R', - - // DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS - // US - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', - 'R', - - // SP ! " # $ % & ยด ( ) * + , - . - // / - 'W', 'R', 'R', 'R', 'R', 'D', 'R', 'R', 'D', 'D', 'R', 'N', 'R', 'N', 'N', - 'D', - - // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? - 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'R', 'R', 'D', 'R', 'D', - 'R', - - // @ A B C D E F G H I J K L M N O - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', - 'R', - - // P Q R S T U V W X Y Z [ \ ] ^ _ - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'D', 'R', 'D', 'R', - 'R', - - // ` a b c d e f g h i j k l m n o - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', - 'R', - - // p q r s t u v w x y z { | } ~ - // DEL - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'D', 'R', 'D', 'R', - 'R', - - 'W', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', - 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'W'}; - -int32_t GetHeaderOffset(IFX_FileRead* pFile) { - const size_t kBufSize = 4; - uint8_t buf[kBufSize]; - for (int32_t offset = 0; offset <= 1024; ++offset) { - if (!pFile->ReadBlock(buf, offset, kBufSize)) - return -1; - - if (memcmp(buf, "%PDF", 4) == 0) - return offset; - } - return -1; -} - -int32_t GetDirectInteger(CPDF_Dictionary* pDict, const CFX_ByteString& key) { - CPDF_Number* pObj = ToNumber(pDict->GetObjectFor(key)); - return pObj ? pObj->GetInteger() : 0; -} - -CFX_ByteString PDF_NameDecode(const CFX_ByteStringC& bstr) { - if (bstr.Find('#') == -1) - return CFX_ByteString(bstr); - - int size = bstr.GetLength(); - CFX_ByteString result; - FX_CHAR* pDestStart = result.GetBuffer(size); - FX_CHAR* pDest = pDestStart; - for (int i = 0; i < size; i++) { - if (bstr[i] == '#' && i < size - 2) { - *pDest++ = - FXSYS_toHexDigit(bstr[i + 1]) * 16 + FXSYS_toHexDigit(bstr[i + 2]); - i += 2; - } else { - *pDest++ = bstr[i]; - } - } - result.ReleaseBuffer((FX_STRSIZE)(pDest - pDestStart)); - return result; -} - -CFX_ByteString PDF_NameDecode(const CFX_ByteString& orig) { - if (orig.Find('#') == -1) - return orig; - return PDF_NameDecode(orig.AsStringC()); -} - -CFX_ByteString PDF_NameEncode(const CFX_ByteString& orig) { - uint8_t* src_buf = (uint8_t*)orig.c_str(); - int src_len = orig.GetLength(); - int dest_len = 0; - int i; - for (i = 0; i < src_len; i++) { - uint8_t ch = src_buf[i]; - if (ch >= 0x80 || PDFCharIsWhitespace(ch) || ch == '#' || - PDFCharIsDelimiter(ch)) { - dest_len += 3; - } else { - dest_len++; - } - } - if (dest_len == src_len) - return orig; - - CFX_ByteString res; - FX_CHAR* dest_buf = res.GetBuffer(dest_len); - dest_len = 0; - for (i = 0; i < src_len; i++) { - uint8_t ch = src_buf[i]; - if (ch >= 0x80 || PDFCharIsWhitespace(ch) || ch == '#' || - PDFCharIsDelimiter(ch)) { - dest_buf[dest_len++] = '#'; - dest_buf[dest_len++] = "0123456789ABCDEF"[ch / 16]; - dest_buf[dest_len++] = "0123456789ABCDEF"[ch % 16]; - } else { - dest_buf[dest_len++] = ch; - } - } - dest_buf[dest_len] = 0; - res.ReleaseBuffer(); - return res; -} - -CFX_ByteTextBuf& operator<<(CFX_ByteTextBuf& buf, const CPDF_Object* pObj) { - if (!pObj) { - buf << " null"; - return buf; - } - switch (pObj->GetType()) { - case CPDF_Object::NULLOBJ: - buf << " null"; - break; - case CPDF_Object::BOOLEAN: - case CPDF_Object::NUMBER: - buf << " " << pObj->GetString(); - break; - case CPDF_Object::STRING: - buf << PDF_EncodeString(pObj->GetString(), pObj->AsString()->IsHex()); - break; - case CPDF_Object::NAME: { - CFX_ByteString str = pObj->GetString(); - buf << "/" << PDF_NameEncode(str); - break; - } - case CPDF_Object::REFERENCE: { - buf << " " << pObj->AsReference()->GetRefObjNum() << " 0 R "; - break; - } - case CPDF_Object::ARRAY: { - const CPDF_Array* p = pObj->AsArray(); - buf << "["; - for (size_t i = 0; i < p->GetCount(); i++) { - CPDF_Object* pElement = p->GetObjectAt(i); - if (pElement && pElement->GetObjNum()) { - buf << " " << pElement->GetObjNum() << " 0 R"; - } else { - buf << pElement; - } - } - buf << "]"; - break; - } - case CPDF_Object::DICTIONARY: { - const CPDF_Dictionary* p = pObj->AsDictionary(); - buf << "<<"; - for (const auto& it : *p) { - const CFX_ByteString& key = it.first; - CPDF_Object* pValue = it.second; - buf << "/" << PDF_NameEncode(key); - if (pValue && pValue->GetObjNum()) { - buf << " " << pValue->GetObjNum() << " 0 R "; - } else { - buf << pValue; - } - } - buf << ">>"; - break; - } - case CPDF_Object::STREAM: { - const CPDF_Stream* p = pObj->AsStream(); - buf << p->GetDict() << "stream\r\n"; - CPDF_StreamAcc acc; - acc.LoadAllData(p, TRUE); - buf.AppendBlock(acc.GetData(), acc.GetSize()); - buf << "\r\nendstream"; - break; - } - default: - ASSERT(FALSE); - break; - } - return buf; -} diff --git a/core/fpdfapi/fpdf_parser/fpdf_parser_utility.h b/core/fpdfapi/fpdf_parser/fpdf_parser_utility.h deleted file mode 100644 index 98bffa7e7c..0000000000 --- a/core/fpdfapi/fpdf_parser/fpdf_parser_utility.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2016 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 CORE_FPDFAPI_FPDF_PARSER_FPDF_PARSER_UTILITY_H_ -#define CORE_FPDFAPI_FPDF_PARSER_FPDF_PARSER_UTILITY_H_ - -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" - -class IFX_FileRead; -class CPDF_Dictionary; - -// Use the accessors below instead of directly accessing PDF_CharType. -extern const char PDF_CharType[256]; - -inline bool PDFCharIsWhitespace(uint8_t c) { - return PDF_CharType[c] == 'W'; -} -inline bool PDFCharIsNumeric(uint8_t c) { - return PDF_CharType[c] == 'N'; -} -inline bool PDFCharIsDelimiter(uint8_t c) { - return PDF_CharType[c] == 'D'; -} -inline bool PDFCharIsOther(uint8_t c) { - return PDF_CharType[c] == 'R'; -} - -inline bool PDFCharIsLineEnding(uint8_t c) { - return c == '\r' || c == '\n'; -} - -int32_t GetHeaderOffset(IFX_FileRead* pFile); -int32_t GetDirectInteger(CPDF_Dictionary* pDict, const CFX_ByteString& key); - -#endif // CORE_FPDFAPI_FPDF_PARSER_FPDF_PARSER_UTILITY_H_ diff --git a/core/fpdfapi/fpdf_render/fpdf_render.cpp b/core/fpdfapi/fpdf_render/fpdf_render.cpp index c3085f1155..ff300f6090 100644 --- a/core/fpdfapi/fpdf_render/fpdf_render.cpp +++ b/core/fpdfapi/fpdf_render/fpdf_render.cpp @@ -11,9 +11,6 @@ #include "core/fpdfapi/cpdf_modulemgr.h" #include "core/fpdfapi/font/cpdf_type3char.h" #include "core/fpdfapi/font/cpdf_type3font.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/fpdf_render/cpdf_pagerendercache.h" #include "core/fpdfapi/fpdf_render/cpdf_progressiverenderer.h" #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" @@ -29,6 +26,9 @@ #include "core/fpdfapi/page/cpdf_pathobject.h" #include "core/fpdfapi/page/cpdf_textobject.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_occontext.h" #include "core/fxge/cfx_fxgedevice.h" #include "core/fxge/cfx_graphstatedata.h" diff --git a/core/fpdfapi/fpdf_render/fpdf_render_cache.cpp b/core/fpdfapi/fpdf_render/fpdf_render_cache.cpp index 758a2d7738..08d749d5a2 100644 --- a/core/fpdfapi/fpdf_render/fpdf_render_cache.cpp +++ b/core/fpdfapi/fpdf_render/fpdf_render_cache.cpp @@ -6,11 +6,11 @@ #include "core/fpdfapi/fpdf_render/cpdf_pagerendercache.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/fpdf_render/cpdf_rendercontext.h" #include "core/fpdfapi/fpdf_render/render_int.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_document.h" struct CACHEINFO { uint32_t time; diff --git a/core/fpdfapi/fpdf_render/fpdf_render_image.cpp b/core/fpdfapi/fpdf_render/fpdf_render_image.cpp index c6b0af8822..d5a28a6019 100644 --- a/core/fpdfapi/fpdf_render/fpdf_render_image.cpp +++ b/core/fpdfapi/fpdf_render/fpdf_render_image.cpp @@ -10,9 +10,6 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/fpdf_render/cpdf_pagerendercache.h" #include "core/fpdfapi/fpdf_render/cpdf_rendercontext.h" #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" @@ -23,6 +20,9 @@ #include "core/fpdfapi/page/cpdf_shadingpattern.h" #include "core/fpdfapi/page/cpdf_tilingpattern.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_occontext.h" #include "core/fxcodec/fx_codec.h" #include "core/fxcrt/fx_safe_types.h" diff --git a/core/fpdfapi/fpdf_render/fpdf_render_loadimage.cpp b/core/fpdfapi/fpdf_render/fpdf_render_loadimage.cpp index 4321a9b75e..ef4074ff15 100644 --- a/core/fpdfapi/fpdf_render/fpdf_render_loadimage.cpp +++ b/core/fpdfapi/fpdf_render/fpdf_render_loadimage.cpp @@ -11,13 +11,13 @@ #include #include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/fpdf_render/cpdf_pagerendercache.h" #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_imageobject.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fxcodec/fx_codec.h" #include "core/fxcrt/fx_safe_types.h" diff --git a/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp b/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp index 3c96e799b2..4bd712e7eb 100644 --- a/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp +++ b/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp @@ -8,8 +8,6 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" #include "core/fpdfapi/fpdf_render/cpdf_rendercontext.h" #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" #include "core/fpdfapi/page/cpdf_form.h" @@ -21,6 +19,8 @@ #include "core/fpdfapi/page/cpdf_shadingpattern.h" #include "core/fpdfapi/page/cpdf_tilingpattern.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fxge/cfx_fxgedevice.h" #include "core/fxge/cfx_pathdata.h" #include "core/fxge/cfx_renderdevice.h" diff --git a/core/fpdfapi/fpdf_render/fpdf_render_text.cpp b/core/fpdfapi/fpdf_render/fpdf_render_text.cpp index b15e8f793e..316cbff3a6 100644 --- a/core/fpdfapi/fpdf_render/fpdf_render_text.cpp +++ b/core/fpdfapi/fpdf_render/fpdf_render_text.cpp @@ -12,8 +12,6 @@ #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/font/cpdf_type3char.h" #include "core/fpdfapi/font/cpdf_type3font.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" #include "core/fpdfapi/fpdf_render/cpdf_textrenderer.h" #include "core/fpdfapi/fpdf_render/cpdf_type3cache.h" @@ -23,6 +21,8 @@ #include "core/fpdfapi/page/cpdf_pathobject.h" #include "core/fpdfapi/page/cpdf_textobject.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fxge/cfx_facecache.h" #include "core/fxge/cfx_fxgedevice.h" #include "core/fxge/cfx_gemodule.h" diff --git a/core/fpdfapi/fpdf_render/render_int.h b/core/fpdfapi/fpdf_render/render_int.h index aea618465e..aa82a9f53c 100644 --- a/core/fpdfapi/fpdf_render/render_int.h +++ b/core/fpdfapi/fpdf_render/render_int.h @@ -11,11 +11,11 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" #include "core/fpdfapi/page/cpdf_clippath.h" #include "core/fpdfapi/page/cpdf_countedobject.h" #include "core/fpdfapi/page/cpdf_graphicstates.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fxge/cfx_fxgedevice.h" #include "core/fxge/cfx_renderdevice.h" diff --git a/core/fpdfapi/page/cpdf_allstates.cpp b/core/fpdfapi/page/cpdf_allstates.cpp index f4a99c3206..70de98e3f0 100644 --- a/core/fpdfapi/page/cpdf_allstates.cpp +++ b/core/fpdfapi/page/cpdf_allstates.cpp @@ -6,9 +6,9 @@ #include "core/fpdfapi/page/cpdf_allstates.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fxge/cfx_graphstatedata.h" namespace { diff --git a/core/fpdfapi/page/cpdf_color.cpp b/core/fpdfapi/page/cpdf_color.cpp index ec49777d47..2ba843ca69 100644 --- a/core/fpdfapi/page/cpdf_color.cpp +++ b/core/fpdfapi/page/cpdf_color.cpp @@ -6,9 +6,9 @@ #include "core/fpdfapi/page/cpdf_color.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fxcrt/fx_system.h" CPDF_Color::CPDF_Color() : m_pCS(nullptr), m_pBuffer(nullptr) {} diff --git a/core/fpdfapi/page/cpdf_colorspace.cpp b/core/fpdfapi/page/cpdf_colorspace.cpp index b43792b19c..5bfd6dedb6 100644 --- a/core/fpdfapi/page/cpdf_colorspace.cpp +++ b/core/fpdfapi/page/cpdf_colorspace.cpp @@ -9,15 +9,15 @@ #include #include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" #include "core/fpdfapi/page/cpdf_pagemodule.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "core/fxcodec/fx_codec.h" namespace { diff --git a/core/fpdfapi/page/cpdf_contentmark.cpp b/core/fpdfapi/page/cpdf_contentmark.cpp index b455b4f28a..4e8625b940 100644 --- a/core/fpdfapi/page/cpdf_contentmark.cpp +++ b/core/fpdfapi/page/cpdf_contentmark.cpp @@ -6,7 +6,7 @@ #include "core/fpdfapi/page/cpdf_contentmark.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "third_party/base/stl_util.h" CPDF_ContentMark::CPDF_ContentMark() {} diff --git a/core/fpdfapi/page/cpdf_contentmarkitem.cpp b/core/fpdfapi/page/cpdf_contentmarkitem.cpp index 90e36d1215..507dc22d9a 100644 --- a/core/fpdfapi/page/cpdf_contentmarkitem.cpp +++ b/core/fpdfapi/page/cpdf_contentmarkitem.cpp @@ -6,7 +6,7 @@ #include "core/fpdfapi/page/cpdf_contentmarkitem.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" CPDF_ContentMarkItem::CPDF_ContentMarkItem() : m_ParamType(None), m_pPropertiesDict(nullptr) {} diff --git a/core/fpdfapi/page/cpdf_form.cpp b/core/fpdfapi/page/cpdf_form.cpp index 73e8139369..18b9fdd94b 100644 --- a/core/fpdfapi/page/cpdf_form.cpp +++ b/core/fpdfapi/page/cpdf_form.cpp @@ -6,11 +6,11 @@ #include "core/fpdfapi/page/cpdf_form.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_pageobjectholder.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_stream.h" CPDF_Form::CPDF_Form(CPDF_Document* pDoc, CPDF_Dictionary* pPageResources, diff --git a/core/fpdfapi/page/cpdf_generalstate.cpp b/core/fpdfapi/page/cpdf_generalstate.cpp index 4b082c0946..4feaaffc6c 100644 --- a/core/fpdfapi/page/cpdf_generalstate.cpp +++ b/core/fpdfapi/page/cpdf_generalstate.cpp @@ -6,8 +6,8 @@ #include "core/fpdfapi/page/cpdf_generalstate.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/fpdf_render/render_int.h" +#include "core/fpdfapi/parser/cpdf_document.h" namespace { diff --git a/core/fpdfapi/page/cpdf_image.cpp b/core/fpdfapi/page/cpdf_image.cpp index eb59dc750e..9ff99689fd 100644 --- a/core/fpdfapi/page/cpdf_image.cpp +++ b/core/fpdfapi/page/cpdf_image.cpp @@ -11,14 +11,14 @@ #include #include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" #include "core/fpdfapi/fpdf_render/cpdf_pagerendercache.h" #include "core/fpdfapi/fpdf_render/render_int.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_boolean.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "core/fxcodec/fx_codec.h" #include "core/fxge/fx_dib.h" diff --git a/core/fpdfapi/page/cpdf_image.h b/core/fpdfapi/page/cpdf_image.h index 0bf806c13e..7058019ba3 100644 --- a/core/fpdfapi/page/cpdf_image.h +++ b/core/fpdfapi/page/cpdf_image.h @@ -7,7 +7,7 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_IMAGE_H_ #define CORE_FPDFAPI_PAGE_CPDF_IMAGE_H_ -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fxcrt/fx_system.h" #define PDF_IMAGE_NO_COMPRESS 0x0000 diff --git a/core/fpdfapi/page/cpdf_imageobject.cpp b/core/fpdfapi/page/cpdf_imageobject.cpp index 8be2cf3c76..9fbebfd8bf 100644 --- a/core/fpdfapi/page/cpdf_imageobject.cpp +++ b/core/fpdfapi/page/cpdf_imageobject.cpp @@ -8,9 +8,9 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_document.h" CPDF_ImageObject::CPDF_ImageObject() : m_pImage(nullptr), m_pImageOwned(false) {} diff --git a/core/fpdfapi/page/cpdf_meshstream.cpp b/core/fpdfapi/page/cpdf_meshstream.cpp index bd877a0920..c3bfcb4ab5 100644 --- a/core/fpdfapi/page/cpdf_meshstream.cpp +++ b/core/fpdfapi/page/cpdf_meshstream.cpp @@ -6,9 +6,9 @@ #include "core/fpdfapi/page/cpdf_meshstream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" #include "core/fpdfapi/page/cpdf_colorspace.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" namespace { diff --git a/core/fpdfapi/page/cpdf_meshstream.h b/core/fpdfapi/page/cpdf_meshstream.h index a2ac9ae868..4d37f17889 100644 --- a/core/fpdfapi/page/cpdf_meshstream.h +++ b/core/fpdfapi/page/cpdf_meshstream.h @@ -10,8 +10,8 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" #include "core/fpdfapi/page/cpdf_shadingpattern.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fxcrt/fx_basic.h" #include "core/fxcrt/fx_system.h" diff --git a/core/fpdfapi/page/cpdf_page.cpp b/core/fpdfapi/page/cpdf_page.cpp index f471760c91..27d54b2748 100644 --- a/core/fpdfapi/page/cpdf_page.cpp +++ b/core/fpdfapi/page/cpdf_page.cpp @@ -9,12 +9,12 @@ #include #include "core/fpdfapi/cpdf_pagerendercontext.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" #include "core/fpdfapi/fpdf_render/cpdf_pagerendercache.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_object.h" #include "third_party/base/stl_util.h" CPDF_Page::CPDF_Page(CPDF_Document* pDocument, diff --git a/core/fpdfapi/page/cpdf_pageobjectholder.cpp b/core/fpdfapi/page/cpdf_pageobjectholder.cpp index bd7830de4d..885d9639bd 100644 --- a/core/fpdfapi/page/cpdf_pageobjectholder.cpp +++ b/core/fpdfapi/page/cpdf_pageobjectholder.cpp @@ -6,9 +6,9 @@ #include "core/fpdfapi/page/cpdf_pageobjectholder.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" CPDF_PageObjectHolder::CPDF_PageObjectHolder() : m_pFormDict(nullptr), diff --git a/core/fpdfapi/page/cpdf_shadingobject.cpp b/core/fpdfapi/page/cpdf_shadingobject.cpp index 28a154374f..8050fc75b9 100644 --- a/core/fpdfapi/page/cpdf_shadingobject.cpp +++ b/core/fpdfapi/page/cpdf_shadingobject.cpp @@ -6,9 +6,9 @@ #include "core/fpdfapi/page/cpdf_shadingobject.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/cpdf_shadingpattern.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_document.h" CPDF_ShadingObject::CPDF_ShadingObject() : m_pShading(nullptr) {} diff --git a/core/fpdfapi/page/cpdf_shadingpattern.cpp b/core/fpdfapi/page/cpdf_shadingpattern.cpp index 5b52e84fb7..eb8dc975c2 100644 --- a/core/fpdfapi/page/cpdf_shadingpattern.cpp +++ b/core/fpdfapi/page/cpdf_shadingpattern.cpp @@ -6,11 +6,11 @@ #include "core/fpdfapi/page/cpdf_shadingpattern.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_object.h" namespace { diff --git a/core/fpdfapi/page/cpdf_textstate.cpp b/core/fpdfapi/page/cpdf_textstate.cpp index ef19b87ae2..85ca9e21ec 100644 --- a/core/fpdfapi/page/cpdf_textstate.cpp +++ b/core/fpdfapi/page/cpdf_textstate.cpp @@ -7,8 +7,8 @@ #include "core/fpdfapi/page/cpdf_textstate.h" #include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_document.h" CPDF_TextState::CPDF_TextState() {} CPDF_TextState::~CPDF_TextState() {} diff --git a/core/fpdfapi/page/cpdf_tilingpattern.cpp b/core/fpdfapi/page/cpdf_tilingpattern.cpp index 1ddc3c6ebc..eb51fbac63 100644 --- a/core/fpdfapi/page/cpdf_tilingpattern.cpp +++ b/core/fpdfapi/page/cpdf_tilingpattern.cpp @@ -6,10 +6,10 @@ #include "core/fpdfapi/page/cpdf_tilingpattern.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" #include "core/fpdfapi/page/cpdf_form.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fpdfapi/parser/cpdf_stream.h" CPDF_TilingPattern::CPDF_TilingPattern(CPDF_Document* pDoc, CPDF_Object* pPatternObj, diff --git a/core/fpdfapi/page/fpdf_page_colors.cpp b/core/fpdfapi/page/fpdf_page_colors.cpp index d6500b716b..e42b695c6c 100644 --- a/core/fpdfapi/page/fpdf_page_colors.cpp +++ b/core/fpdfapi/page/fpdf_page_colors.cpp @@ -11,12 +11,12 @@ #include #include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "core/fxcodec/fx_codec.h" namespace { diff --git a/core/fpdfapi/page/fpdf_page_doc.cpp b/core/fpdfapi/page/fpdf_page_doc.cpp index f11f1b288f..798983fadc 100644 --- a/core/fpdfapi/page/fpdf_page_doc.cpp +++ b/core/fpdfapi/page/fpdf_page_doc.cpp @@ -13,15 +13,15 @@ #include "core/fpdfapi/cpdf_modulemgr.h" #include "core/fpdfapi/font/cpdf_type1font.h" #include "core/fpdfapi/font/font_int.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_pagemodule.h" #include "core/fpdfapi/page/cpdf_pattern.h" #include "core/fpdfapi/page/cpdf_shadingpattern.h" #include "core/fpdfapi/page/cpdf_tilingpattern.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "third_party/base/stl_util.h" void CPDF_ModuleMgr::InitPageModule() { diff --git a/core/fpdfapi/page/fpdf_page_func.cpp b/core/fpdfapi/page/fpdf_page_func.cpp index e11d8dd754..bf44a1e7c5 100644 --- a/core/fpdfapi/page/fpdf_page_func.cpp +++ b/core/fpdfapi/page/fpdf_page_func.cpp @@ -13,12 +13,12 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" #include "core/fpdfapi/page/cpdf_psengine.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_simple_parser.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fxcrt/fx_safe_types.h" #include "third_party/base/numerics/safe_conversions_impl.h" diff --git a/core/fpdfapi/page/fpdf_page_parser.cpp b/core/fpdfapi/page/fpdf_page_parser.cpp index e19d99a971..48a24da5c5 100644 --- a/core/fpdfapi/page/fpdf_page_parser.cpp +++ b/core/fpdfapi/page/fpdf_page_parser.cpp @@ -13,15 +13,6 @@ #include "core/fpdfapi/edit/cpdf_creator.h" #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/font/cpdf_type3font.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" #include "core/fpdfapi/page/cpdf_allstates.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_formobject.h" @@ -33,6 +24,15 @@ #include "core/fpdfapi/page/cpdf_shadingobject.h" #include "core/fpdfapi/page/cpdf_shadingpattern.h" #include "core/fpdfapi/page/cpdf_textobject.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxge/cfx_graphstatedata.h" #include "core/fxge/cfx_pathdata.h" diff --git a/core/fpdfapi/page/fpdf_page_parser_old.cpp b/core/fpdfapi/page/fpdf_page_parser_old.cpp index fb89b14db9..7dc8d3e1d6 100644 --- a/core/fpdfapi/page/fpdf_page_parser_old.cpp +++ b/core/fpdfapi/page/fpdf_page_parser_old.cpp @@ -10,23 +10,23 @@ #include "core/fpdfapi/cpdf_modulemgr.h" #include "core/fpdfapi/font/cpdf_type3char.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_null.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h" #include "core/fpdfapi/page/cpdf_allstates.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_path.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_boolean.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_null.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcodec/fx_codec.h" #include "core/fxcrt/fx_ext.h" #include "core/fxcrt/fx_safe_types.h" diff --git a/core/fpdfapi/parser/cfdf_document.cpp b/core/fpdfapi/parser/cfdf_document.cpp new file mode 100644 index 0000000000..a1518dfed0 --- /dev/null +++ b/core/fpdfapi/parser/cfdf_document.cpp @@ -0,0 +1,102 @@ +// 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 + +#include "core/fpdfapi/parser/cfdf_document.h" + +#include "core/fpdfapi/edit/cpdf_creator.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_syntax_parser.h" +#include "third_party/base/ptr_util.h" + +CFDF_Document::CFDF_Document() + : CPDF_IndirectObjectHolder(), + m_pRootDict(nullptr), + m_pFile(nullptr), + m_bOwnFile(FALSE), + m_pByteStringPool(pdfium::MakeUnique()) {} + +CFDF_Document::~CFDF_Document() { + if (m_bOwnFile && m_pFile) + m_pFile->Release(); + m_pByteStringPool.DeleteObject(); // Make weak. +} + +CFDF_Document* CFDF_Document::CreateNewDoc() { + CFDF_Document* pDoc = new CFDF_Document; + pDoc->m_pRootDict = new CPDF_Dictionary(pDoc->GetByteStringPool()); + pDoc->AddIndirectObject(pDoc->m_pRootDict); + pDoc->m_pRootDict->SetFor("FDF", + new CPDF_Dictionary(pDoc->GetByteStringPool())); + return pDoc; +} + +CFDF_Document* CFDF_Document::ParseFile(IFX_FileRead* pFile, FX_BOOL bOwnFile) { + if (!pFile) + return nullptr; + + std::unique_ptr pDoc(new CFDF_Document); + pDoc->ParseStream(pFile, bOwnFile); + return pDoc->m_pRootDict ? pDoc.release() : nullptr; +} + +CFDF_Document* CFDF_Document::ParseMemory(const uint8_t* pData, uint32_t size) { + return CFDF_Document::ParseFile(FX_CreateMemoryStream((uint8_t*)pData, size), + TRUE); +} + +void CFDF_Document::ParseStream(IFX_FileRead* pFile, FX_BOOL bOwnFile) { + m_pFile = pFile; + m_bOwnFile = bOwnFile; + CPDF_SyntaxParser parser; + parser.InitParser(m_pFile, 0); + while (1) { + bool bNumber; + CFX_ByteString word = parser.GetNextWord(&bNumber); + if (bNumber) { + uint32_t objnum = FXSYS_atoui(word.c_str()); + word = parser.GetNextWord(&bNumber); + if (!bNumber) + break; + + word = parser.GetNextWord(nullptr); + if (word != "obj") + break; + + CPDF_Object* pObj = parser.GetObject(this, objnum, 0, true); + if (!pObj) + break; + + ReplaceIndirectObjectIfHigherGeneration(objnum, pObj); + word = parser.GetNextWord(nullptr); + if (word != "endobj") + break; + } else { + if (word != "trailer") + break; + + if (CPDF_Dictionary* pMainDict = + ToDictionary(parser.GetObject(this, 0, 0, true))) { + m_pRootDict = pMainDict->GetDictFor("Root"); + pMainDict->Release(); + } + break; + } + } +} + +FX_BOOL CFDF_Document::WriteBuf(CFX_ByteTextBuf& buf) const { + if (!m_pRootDict) + return FALSE; + + buf << "%FDF-1.2\r\n"; + for (const auto& pair : *this) + buf << pair.first << " 0 obj\r\n" + << pair.second.get() << "\r\nendobj\r\n\r\n"; + + buf << "trailer\r\n<GetObjNum() + << " 0 R>>\r\n%%EOF\r\n"; + return TRUE; +} diff --git a/core/fpdfapi/parser/cfdf_document.h b/core/fpdfapi/parser/cfdf_document.h new file mode 100644 index 0000000000..21ac62d11c --- /dev/null +++ b/core/fpdfapi/parser/cfdf_document.h @@ -0,0 +1,42 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CFDF_DOCUMENT_H_ +#define CORE_FPDFAPI_PARSER_CFDF_DOCUMENT_H_ + +#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/cfx_string_pool_template.h" +#include "core/fxcrt/cfx_weak_ptr.h" +#include "core/fxcrt/fx_basic.h" + +class CPDF_Dictionary; + +class CFDF_Document : public CPDF_IndirectObjectHolder { + public: + static CFDF_Document* CreateNewDoc(); + static CFDF_Document* ParseFile(IFX_FileRead* pFile, + FX_BOOL bOwnFile = FALSE); + static CFDF_Document* ParseMemory(const uint8_t* pData, uint32_t size); + ~CFDF_Document() override; + + FX_BOOL WriteBuf(CFX_ByteTextBuf& buf) const; + CPDF_Dictionary* GetRoot() const { return m_pRootDict; } + CFX_WeakPtr GetByteStringPool() const { + return m_pByteStringPool; + } + + protected: + CFDF_Document(); + void ParseStream(IFX_FileRead* pFile, FX_BOOL bOwnFile); + + CPDF_Dictionary* m_pRootDict; + IFX_FileRead* m_pFile; + FX_BOOL m_bOwnFile; + CFX_WeakPtr m_pByteStringPool; +}; + +#endif // CORE_FPDFAPI_PARSER_CFDF_DOCUMENT_H_ diff --git a/core/fpdfapi/parser/cpdf_array.cpp b/core/fpdfapi/parser/cpdf_array.cpp new file mode 100644 index 0000000000..61e69e8a53 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_array.cpp @@ -0,0 +1,200 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_array.h" + +#include + +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "third_party/base/logging.h" +#include "third_party/base/stl_util.h" + +CPDF_Array::CPDF_Array() {} + +CPDF_Array::~CPDF_Array() { + // Mark the object as deleted so that it will not be deleted again + // in case of cyclic references. + m_ObjNum = kInvalidObjNum; + for (auto& it : m_Objects) { + if (it) + it->Release(); + } +} + +CPDF_Object::Type CPDF_Array::GetType() const { + return ARRAY; +} + +bool CPDF_Array::IsArray() const { + return true; +} + +CPDF_Array* CPDF_Array::AsArray() { + return this; +} + +const CPDF_Array* CPDF_Array::AsArray() const { + return this; +} + +CPDF_Object* CPDF_Array::Clone() const { + return CloneObjectNonCyclic(false); +} + +CPDF_Object* CPDF_Array::CloneNonCyclic( + bool bDirect, + std::set* pVisited) const { + pVisited->insert(this); + CPDF_Array* pCopy = new CPDF_Array(); + for (size_t i = 0; i < GetCount(); i++) { + CPDF_Object* value = m_Objects[i]; + if (!pdfium::ContainsKey(*pVisited, value)) + pCopy->m_Objects.push_back(value->CloneNonCyclic(bDirect, pVisited)); + } + return pCopy; +} + +CFX_FloatRect CPDF_Array::GetRect() { + CFX_FloatRect rect; + if (!IsArray() || m_Objects.size() != 4) + return rect; + + rect.left = GetNumberAt(0); + rect.bottom = GetNumberAt(1); + rect.right = GetNumberAt(2); + rect.top = GetNumberAt(3); + return rect; +} + +CFX_Matrix CPDF_Array::GetMatrix() { + CFX_Matrix matrix; + if (!IsArray() || m_Objects.size() != 6) + return matrix; + + matrix.Set(GetNumberAt(0), GetNumberAt(1), GetNumberAt(2), GetNumberAt(3), + GetNumberAt(4), GetNumberAt(5)); + return matrix; +} + +CPDF_Object* CPDF_Array::GetObjectAt(size_t i) const { + if (i >= m_Objects.size()) + return nullptr; + return m_Objects[i]; +} + +CPDF_Object* CPDF_Array::GetDirectObjectAt(size_t i) const { + if (i >= m_Objects.size()) + return nullptr; + return m_Objects[i]->GetDirect(); +} + +CFX_ByteString CPDF_Array::GetStringAt(size_t i) const { + if (i >= m_Objects.size()) + return CFX_ByteString(); + return m_Objects[i]->GetString(); +} + +int CPDF_Array::GetIntegerAt(size_t i) const { + if (i >= m_Objects.size()) + return 0; + return m_Objects[i]->GetInteger(); +} + +FX_FLOAT CPDF_Array::GetNumberAt(size_t i) const { + if (i >= m_Objects.size()) + return 0; + return m_Objects[i]->GetNumber(); +} + +CPDF_Dictionary* CPDF_Array::GetDictAt(size_t i) const { + CPDF_Object* p = GetDirectObjectAt(i); + if (!p) + return nullptr; + if (CPDF_Dictionary* pDict = p->AsDictionary()) + return pDict; + if (CPDF_Stream* pStream = p->AsStream()) + return pStream->GetDict(); + return nullptr; +} + +CPDF_Stream* CPDF_Array::GetStreamAt(size_t i) const { + return ToStream(GetDirectObjectAt(i)); +} + +CPDF_Array* CPDF_Array::GetArrayAt(size_t i) const { + return ToArray(GetDirectObjectAt(i)); +} + +void CPDF_Array::RemoveAt(size_t i, size_t nCount) { + if (i >= m_Objects.size()) + return; + + if (nCount <= 0 || nCount > m_Objects.size() - i) + return; + + for (size_t j = 0; j < nCount; ++j) { + if (CPDF_Object* p = m_Objects[i + j]) + p->Release(); + } + m_Objects.erase(m_Objects.begin() + i, m_Objects.begin() + i + nCount); +} + +void CPDF_Array::SetAt(size_t i, CPDF_Object* pObj) { + ASSERT(IsArray()); + CHECK(!pObj || pObj->GetObjNum() == 0); + if (i >= m_Objects.size()) { + ASSERT(false); + return; + } + if (CPDF_Object* pOld = m_Objects[i]) + pOld->Release(); + + m_Objects[i] = pObj; +} + +void CPDF_Array::InsertAt(size_t index, CPDF_Object* pObj) { + ASSERT(IsArray()); + CHECK(!pObj || pObj->GetObjNum() == 0); + if (index >= m_Objects.size()) { + // Allocate space first. + m_Objects.resize(index + 1, nullptr); + m_Objects[index] = pObj; + } else { + // Directly insert. + m_Objects.insert(m_Objects.begin() + index, pObj); + } +} + +void CPDF_Array::Add(CPDF_Object* pObj) { + ASSERT(IsArray()); + CHECK(!pObj || pObj->GetObjNum() == 0); + m_Objects.push_back(pObj); +} + +void CPDF_Array::AddName(const CFX_ByteString& str) { + Add(new CPDF_Name(str)); +} + +void CPDF_Array::AddString(const CFX_ByteString& str) { + Add(new CPDF_String(str, FALSE)); +} + +void CPDF_Array::AddInteger(int i) { + Add(new CPDF_Number(i)); +} + +void CPDF_Array::AddNumber(FX_FLOAT f) { + Add(new CPDF_Number(f)); +} + +void CPDF_Array::AddReference(CPDF_IndirectObjectHolder* pDoc, + uint32_t objnum) { + Add(new CPDF_Reference(pDoc, objnum)); +} diff --git a/core/fpdfapi/parser/cpdf_array.h b/core/fpdfapi/parser/cpdf_array.h new file mode 100644 index 0000000000..25bbdd56f2 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_array.h @@ -0,0 +1,72 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_ARRAY_H_ +#define CORE_FPDFAPI_PARSER_CPDF_ARRAY_H_ + +#include +#include + +#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/fx_basic.h" +#include "core/fxcrt/fx_coordinates.h" + +class CPDF_Array : public CPDF_Object { + public: + using iterator = std::vector::iterator; + using const_iterator = std::vector::const_iterator; + + CPDF_Array(); + + // CPDF_Object. + Type GetType() const override; + CPDF_Object* Clone() const override; + bool IsArray() const override; + CPDF_Array* AsArray() override; + const CPDF_Array* AsArray() const override; + + bool IsEmpty() const { return m_Objects.empty(); } + size_t GetCount() const { return m_Objects.size(); } + CPDF_Object* GetObjectAt(size_t index) const; + CPDF_Object* GetDirectObjectAt(size_t index) const; + CFX_ByteString GetStringAt(size_t index) const; + int GetIntegerAt(size_t index) const; + FX_FLOAT GetNumberAt(size_t index) const; + CPDF_Dictionary* GetDictAt(size_t index) const; + CPDF_Stream* GetStreamAt(size_t index) const; + CPDF_Array* GetArrayAt(size_t index) const; + FX_FLOAT GetFloatAt(size_t index) const { return GetNumberAt(index); } + CFX_Matrix GetMatrix(); + CFX_FloatRect GetRect(); + + void SetAt(size_t index, CPDF_Object* pObj); + void InsertAt(size_t index, CPDF_Object* pObj); + void RemoveAt(size_t index, size_t nCount = 1); + + void Add(CPDF_Object* pObj); + 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, uint32_t objnum); + + iterator begin() { return m_Objects.begin(); } + iterator end() { return m_Objects.end(); } + const_iterator begin() const { return m_Objects.begin(); } + const_iterator end() const { return m_Objects.end(); } + + protected: + ~CPDF_Array() override; + + CPDF_Object* CloneNonCyclic( + bool bDirect, + std::set* pVisited) const override; + + std::vector m_Objects; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_ARRAY_H_ diff --git a/core/fpdfapi/parser/cpdf_array_unittest.cpp b/core/fpdfapi/parser/cpdf_array_unittest.cpp new file mode 100644 index 0000000000..bc9f578021 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_array_unittest.cpp @@ -0,0 +1,180 @@ +// Copyright 2016 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. + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" + +#include + +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +using ScopedArray = std::unique_ptr>; + +} // namespace + +TEST(cpdf_array, RemoveAt) { + { + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->AddInteger(elems[i]); + arr->RemoveAt(3, 3); + int expected[] = {1, 2, 3, 7, 8, 9, 10}; + EXPECT_EQ(FX_ArraySize(expected), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(expected); ++i) + EXPECT_EQ(expected[i], arr->GetIntegerAt(i)); + arr->RemoveAt(4, 2); + int expected2[] = {1, 2, 3, 7, 10}; + EXPECT_EQ(FX_ArraySize(expected2), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(expected2); ++i) + EXPECT_EQ(expected2[i], arr->GetIntegerAt(i)); + } + { + // When the range is out of bound, RemoveAt has no effect. + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->AddInteger(elems[i]); + arr->RemoveAt(8, 5); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); + arr->RemoveAt(0, 12); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + arr->RemoveAt(11, 1); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + } +} + +TEST(cpdf_array, InsertAt) { + { + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); + arr->InsertAt(3, new CPDF_Number(33)); + arr->InsertAt(6, new CPDF_Number(55)); + arr->InsertAt(12, new CPDF_Number(12)); + int expected[] = {1, 2, 3, 33, 4, 5, 55, 6, 7, 8, 9, 10, 12}; + EXPECT_EQ(FX_ArraySize(expected), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(expected); ++i) + EXPECT_EQ(expected[i], arr->GetIntegerAt(i)); + } + { + // When the position to insert is beyond the upper bound, + // an element is inserted at that position while other unfilled + // positions have nullptr. + int elems[] = {1, 2}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + arr->InsertAt(10, new CPDF_Number(10)); + EXPECT_EQ(11u, arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); + for (size_t i = FX_ArraySize(elems); i < 10; ++i) + EXPECT_EQ(nullptr, arr->GetObjectAt(i)); + EXPECT_EQ(10, arr->GetIntegerAt(10)); + } +} + +TEST(cpdf_array, Clone) { + { + // Basic case. + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + ScopedArray arr2(arr->Clone()->AsArray()); + EXPECT_EQ(arr->GetCount(), arr2->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) { + // Clone() always create new objects. + EXPECT_NE(arr->GetObjectAt(i), arr2->GetObjectAt(i)); + EXPECT_EQ(arr->GetIntegerAt(i), arr2->GetIntegerAt(i)); + } + } + { + // Clone() with and without dereferencing reference objects. + static const size_t kNumOfRows = 3; + static const size_t kNumOfRowElems = 5; + int elems[kNumOfRows][kNumOfRowElems] = { + {1, 2, 3, 4, 5}, {10, 9, 8, 7, 6}, {11, 12, 13, 14, 15}}; + ScopedArray arr(new CPDF_Array); + // Indirect references to indirect objects. + std::unique_ptr obj_holder( + new CPDF_IndirectObjectHolder()); + for (size_t i = 0; i < kNumOfRows; ++i) { + CPDF_Array* arr_elem = new CPDF_Array; + for (size_t j = 0; j < kNumOfRowElems; ++j) { + CPDF_Number* obj = new CPDF_Number(elems[i][j]); + // Starts object number from 1. + int obj_num = i * kNumOfRowElems + j + 1; + obj_holder->ReplaceIndirectObjectIfHigherGeneration(obj_num, obj); + arr_elem->InsertAt(j, new CPDF_Reference(obj_holder.get(), obj_num)); + } + arr->InsertAt(i, arr_elem); + } + ASSERT_EQ(kNumOfRows, arr->GetCount()); + // Not dereferencing reference objects means just creating new references + // instead of new copies of direct objects. + ScopedArray arr1(arr->Clone()->AsArray()); + EXPECT_EQ(arr->GetCount(), arr1->GetCount()); + // Dereferencing reference objects creates new copies of direct objects. + ScopedArray arr2(arr->CloneDirectObject()->AsArray()); + EXPECT_EQ(arr->GetCount(), arr2->GetCount()); + for (size_t i = 0; i < kNumOfRows; ++i) { + CPDF_Array* arr_elem = arr->GetObjectAt(i)->AsArray(); + CPDF_Array* arr1_elem = arr1->GetObjectAt(i)->AsArray(); + CPDF_Array* arr2_elem = arr2->GetObjectAt(i)->AsArray(); + EXPECT_NE(arr_elem, arr1_elem); + EXPECT_NE(arr_elem, arr2_elem); + for (size_t j = 0; j < kNumOfRowElems; ++j) { + auto elem_obj = arr_elem->GetObjectAt(j); + auto elem_obj1 = arr1_elem->GetObjectAt(j); + auto elem_obj2 = arr2_elem->GetObjectAt(j); + // Results from not deferencing reference objects. + EXPECT_NE(elem_obj, elem_obj1); + EXPECT_TRUE(elem_obj1->IsReference()); + EXPECT_EQ(elem_obj->GetDirect(), elem_obj1->GetDirect()); + EXPECT_EQ(elem_obj->GetInteger(), elem_obj1->GetInteger()); + // Results from deferencing reference objects. + EXPECT_NE(elem_obj, elem_obj2); + EXPECT_TRUE(elem_obj2->IsNumber()); + EXPECT_NE(elem_obj->GetDirect(), elem_obj2); + EXPECT_EQ(elem_obj->GetObjNum(), elem_obj2->GetObjNum()); + EXPECT_EQ(elem_obj->GetInteger(), elem_obj2->GetInteger()); + } + } + arr.reset(); + ASSERT_EQ(kNumOfRows, arr1->GetCount()); + for (size_t i = 0; i < kNumOfRows; ++i) { + for (size_t j = 0; j < kNumOfRowElems; ++j) { + // Results from not deferencing reference objects. + auto elem_obj1 = arr1->GetObjectAt(i)->AsArray()->GetObjectAt(j); + EXPECT_TRUE(elem_obj1->IsReference()); + EXPECT_EQ(elems[i][j], elem_obj1->GetInteger()); + // Results from deferencing reference objects. + EXPECT_EQ(elems[i][j], + arr2->GetObjectAt(i)->AsArray()->GetIntegerAt(j)); + } + } + } +} + +TEST(cpdf_array, Iterator) { + int elems[] = {-23, -11, 3, 455, 2345877, + 0, 7895330, -12564334, 10000, -100000}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + size_t index = 0; + for (const auto& it : *arr) + EXPECT_EQ(elems[index++], it->AsNumber()->GetInteger()); +} diff --git a/core/fpdfapi/parser/cpdf_boolean.cpp b/core/fpdfapi/parser/cpdf_boolean.cpp new file mode 100644 index 0000000000..416b6ff4bc --- /dev/null +++ b/core/fpdfapi/parser/cpdf_boolean.cpp @@ -0,0 +1,45 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_boolean.h" + +CPDF_Boolean::CPDF_Boolean() : m_bValue(false) {} + +CPDF_Boolean::CPDF_Boolean(bool value) : m_bValue(value) {} + +CPDF_Boolean::~CPDF_Boolean() {} + +CPDF_Object::Type CPDF_Boolean::GetType() const { + return BOOLEAN; +} + +CPDF_Object* CPDF_Boolean::Clone() const { + return new CPDF_Boolean(m_bValue); +} + +CFX_ByteString CPDF_Boolean::GetString() const { + return m_bValue ? "true" : "false"; +} + +int CPDF_Boolean::GetInteger() const { + return m_bValue; +} + +void CPDF_Boolean::SetString(const CFX_ByteString& str) { + m_bValue = (str == "true"); +} + +bool CPDF_Boolean::IsBoolean() const { + return true; +} + +CPDF_Boolean* CPDF_Boolean::AsBoolean() { + return this; +} + +const CPDF_Boolean* CPDF_Boolean::AsBoolean() const { + return this; +} diff --git a/core/fpdfapi/parser/cpdf_boolean.h b/core/fpdfapi/parser/cpdf_boolean.h new file mode 100644 index 0000000000..89ed17d743 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_boolean.h @@ -0,0 +1,35 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_BOOLEAN_H_ +#define CORE_FPDFAPI_PARSER_CPDF_BOOLEAN_H_ + +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/fx_system.h" + +class CPDF_Boolean : public CPDF_Object { + public: + CPDF_Boolean(); + explicit CPDF_Boolean(bool value); + + // CPDF_Object. + Type GetType() const override; + CPDF_Object* Clone() const override; + CFX_ByteString GetString() const override; + int GetInteger() const override; + void SetString(const CFX_ByteString& str) override; + bool IsBoolean() const override; + CPDF_Boolean* AsBoolean() override; + const CPDF_Boolean* AsBoolean() const override; + + protected: + ~CPDF_Boolean() override; + + bool m_bValue; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_BOOLEAN_H_ diff --git a/core/fpdfapi/parser/cpdf_crypto_handler.cpp b/core/fpdfapi/parser/cpdf_crypto_handler.cpp new file mode 100644 index 0000000000..f7dc19e243 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_crypto_handler.cpp @@ -0,0 +1,342 @@ +// 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 + +#include "core/fpdfapi/parser/cpdf_crypto_handler.h" + +#include + +#include "core/fdrm/crypto/fx_crypt.h" +#include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fpdfapi/parser/cpdf_security_handler.h" +#include "core/fpdfapi/parser/cpdf_simple_parser.h" + +void CPDF_CryptoHandler::CryptBlock(FX_BOOL bEncrypt, + uint32_t objnum, + uint32_t gennum, + const uint8_t* src_buf, + uint32_t src_size, + uint8_t* dest_buf, + uint32_t& dest_size) { + if (m_Cipher == FXCIPHER_NONE) { + FXSYS_memcpy(dest_buf, src_buf, src_size); + return; + } + uint8_t realkey[16]; + int realkeylen = 16; + if (m_Cipher != FXCIPHER_AES || m_KeyLen != 32) { + uint8_t key1[32]; + PopulateKey(objnum, gennum, key1); + + if (m_Cipher == FXCIPHER_AES) { + FXSYS_memcpy(key1 + m_KeyLen + 5, "sAlT", 4); + } + CRYPT_MD5Generate( + key1, m_Cipher == FXCIPHER_AES ? m_KeyLen + 9 : m_KeyLen + 5, realkey); + realkeylen = m_KeyLen + 5; + if (realkeylen > 16) { + realkeylen = 16; + } + } + if (m_Cipher == FXCIPHER_AES) { + CRYPT_AESSetKey(m_pAESContext, 16, m_KeyLen == 32 ? m_EncryptKey : realkey, + m_KeyLen, bEncrypt); + if (bEncrypt) { + uint8_t iv[16]; + for (int i = 0; i < 16; i++) { + iv[i] = (uint8_t)rand(); + } + CRYPT_AESSetIV(m_pAESContext, iv); + FXSYS_memcpy(dest_buf, iv, 16); + int nblocks = src_size / 16; + CRYPT_AESEncrypt(m_pAESContext, dest_buf + 16, src_buf, nblocks * 16); + uint8_t padding[16]; + FXSYS_memcpy(padding, src_buf + nblocks * 16, src_size % 16); + FXSYS_memset(padding + src_size % 16, 16 - src_size % 16, + 16 - src_size % 16); + CRYPT_AESEncrypt(m_pAESContext, dest_buf + nblocks * 16 + 16, padding, + 16); + dest_size = 32 + nblocks * 16; + } else { + CRYPT_AESSetIV(m_pAESContext, src_buf); + CRYPT_AESDecrypt(m_pAESContext, dest_buf, src_buf + 16, src_size - 16); + dest_size = src_size - 16; + dest_size -= dest_buf[dest_size - 1]; + } + } else { + ASSERT(dest_size == src_size); + if (dest_buf != src_buf) { + FXSYS_memcpy(dest_buf, src_buf, src_size); + } + CRYPT_ArcFourCryptBlock(dest_buf, dest_size, realkey, realkeylen); + } +} + +struct AESCryptContext { + uint8_t m_Context[2048]; + FX_BOOL m_bIV; + uint8_t m_Block[16]; + uint32_t m_BlockOffset; +}; + +void* CPDF_CryptoHandler::CryptStart(uint32_t objnum, + uint32_t gennum, + FX_BOOL bEncrypt) { + if (m_Cipher == FXCIPHER_NONE) { + return this; + } + if (m_Cipher == FXCIPHER_AES && m_KeyLen == 32) { + AESCryptContext* pContext = FX_Alloc(AESCryptContext, 1); + pContext->m_bIV = TRUE; + pContext->m_BlockOffset = 0; + CRYPT_AESSetKey(pContext->m_Context, 16, m_EncryptKey, 32, bEncrypt); + if (bEncrypt) { + for (int i = 0; i < 16; i++) { + pContext->m_Block[i] = (uint8_t)rand(); + } + CRYPT_AESSetIV(pContext->m_Context, pContext->m_Block); + } + return pContext; + } + uint8_t key1[48]; + PopulateKey(objnum, gennum, key1); + + if (m_Cipher == FXCIPHER_AES) { + FXSYS_memcpy(key1 + m_KeyLen + 5, "sAlT", 4); + } + uint8_t realkey[16]; + CRYPT_MD5Generate( + key1, m_Cipher == FXCIPHER_AES ? m_KeyLen + 9 : m_KeyLen + 5, realkey); + int realkeylen = m_KeyLen + 5; + if (realkeylen > 16) { + realkeylen = 16; + } + if (m_Cipher == FXCIPHER_AES) { + AESCryptContext* pContext = FX_Alloc(AESCryptContext, 1); + pContext->m_bIV = TRUE; + pContext->m_BlockOffset = 0; + CRYPT_AESSetKey(pContext->m_Context, 16, realkey, 16, bEncrypt); + if (bEncrypt) { + for (int i = 0; i < 16; i++) { + pContext->m_Block[i] = (uint8_t)rand(); + } + CRYPT_AESSetIV(pContext->m_Context, pContext->m_Block); + } + return pContext; + } + void* pContext = FX_Alloc(uint8_t, 1040); + CRYPT_ArcFourSetup(pContext, realkey, realkeylen); + return pContext; +} + +FX_BOOL CPDF_CryptoHandler::CryptStream(void* context, + const uint8_t* src_buf, + uint32_t src_size, + CFX_BinaryBuf& dest_buf, + FX_BOOL bEncrypt) { + if (!context) { + return FALSE; + } + if (m_Cipher == FXCIPHER_NONE) { + dest_buf.AppendBlock(src_buf, src_size); + return TRUE; + } + if (m_Cipher == FXCIPHER_RC4) { + int old_size = dest_buf.GetSize(); + dest_buf.AppendBlock(src_buf, src_size); + CRYPT_ArcFourCrypt(context, dest_buf.GetBuffer() + old_size, src_size); + return TRUE; + } + AESCryptContext* pContext = (AESCryptContext*)context; + if (pContext->m_bIV && bEncrypt) { + dest_buf.AppendBlock(pContext->m_Block, 16); + pContext->m_bIV = FALSE; + } + uint32_t src_off = 0; + uint32_t src_left = src_size; + while (1) { + uint32_t copy_size = 16 - pContext->m_BlockOffset; + if (copy_size > src_left) { + copy_size = src_left; + } + FXSYS_memcpy(pContext->m_Block + pContext->m_BlockOffset, src_buf + src_off, + copy_size); + src_off += copy_size; + src_left -= copy_size; + pContext->m_BlockOffset += copy_size; + if (pContext->m_BlockOffset == 16) { + if (!bEncrypt && pContext->m_bIV) { + CRYPT_AESSetIV(pContext->m_Context, pContext->m_Block); + pContext->m_bIV = FALSE; + pContext->m_BlockOffset = 0; + } else if (src_off < src_size) { + uint8_t block_buf[16]; + if (bEncrypt) { + CRYPT_AESEncrypt(pContext->m_Context, block_buf, pContext->m_Block, + 16); + } else { + CRYPT_AESDecrypt(pContext->m_Context, block_buf, pContext->m_Block, + 16); + } + dest_buf.AppendBlock(block_buf, 16); + pContext->m_BlockOffset = 0; + } + } + if (!src_left) { + break; + } + } + return TRUE; +} +FX_BOOL CPDF_CryptoHandler::CryptFinish(void* context, + CFX_BinaryBuf& dest_buf, + FX_BOOL bEncrypt) { + if (!context) { + return FALSE; + } + if (m_Cipher == FXCIPHER_NONE) { + return TRUE; + } + if (m_Cipher == FXCIPHER_RC4) { + FX_Free(context); + return TRUE; + } + AESCryptContext* pContext = (AESCryptContext*)context; + if (bEncrypt) { + uint8_t block_buf[16]; + if (pContext->m_BlockOffset == 16) { + CRYPT_AESEncrypt(pContext->m_Context, block_buf, pContext->m_Block, 16); + dest_buf.AppendBlock(block_buf, 16); + pContext->m_BlockOffset = 0; + } + FXSYS_memset(pContext->m_Block + pContext->m_BlockOffset, + (uint8_t)(16 - pContext->m_BlockOffset), + 16 - pContext->m_BlockOffset); + CRYPT_AESEncrypt(pContext->m_Context, block_buf, pContext->m_Block, 16); + dest_buf.AppendBlock(block_buf, 16); + } else if (pContext->m_BlockOffset == 16) { + uint8_t block_buf[16]; + CRYPT_AESDecrypt(pContext->m_Context, block_buf, pContext->m_Block, 16); + if (block_buf[15] <= 16) { + dest_buf.AppendBlock(block_buf, 16 - block_buf[15]); + } + } + FX_Free(pContext); + return TRUE; +} + +void CPDF_CryptoHandler::Decrypt(uint32_t objnum, + uint32_t gennum, + CFX_ByteString& str) { + CFX_BinaryBuf dest_buf; + void* context = DecryptStart(objnum, gennum); + DecryptStream(context, str.raw_str(), str.GetLength(), dest_buf); + DecryptFinish(context, dest_buf); + str = CFX_ByteString(dest_buf.GetBuffer(), dest_buf.GetSize()); +} + +void* CPDF_CryptoHandler::DecryptStart(uint32_t objnum, uint32_t gennum) { + return CryptStart(objnum, gennum, FALSE); +} +uint32_t CPDF_CryptoHandler::DecryptGetSize(uint32_t src_size) { + return m_Cipher == FXCIPHER_AES ? src_size - 16 : src_size; +} + +FX_BOOL CPDF_CryptoHandler::Init(CPDF_Dictionary* pEncryptDict, + CPDF_SecurityHandler* pSecurityHandler) { + const uint8_t* key; + if (!pSecurityHandler->GetCryptInfo(m_Cipher, key, m_KeyLen)) { + return FALSE; + } + if (m_KeyLen > 32 || m_KeyLen < 0) { + return FALSE; + } + if (m_Cipher != FXCIPHER_NONE) { + FXSYS_memcpy(m_EncryptKey, key, m_KeyLen); + } + if (m_Cipher == FXCIPHER_AES) { + m_pAESContext = FX_Alloc(uint8_t, 2048); + } + return TRUE; +} + +FX_BOOL CPDF_CryptoHandler::Init(int cipher, const uint8_t* key, int keylen) { + if (cipher == FXCIPHER_AES) { + switch (keylen) { + case 16: + case 24: + case 32: + break; + default: + return FALSE; + } + } else if (cipher == FXCIPHER_AES2) { + if (keylen != 32) { + return FALSE; + } + } else if (cipher == FXCIPHER_RC4) { + if (keylen < 5 || keylen > 16) { + return FALSE; + } + } else { + if (keylen > 32) { + keylen = 32; + } + } + m_Cipher = cipher; + m_KeyLen = keylen; + FXSYS_memcpy(m_EncryptKey, key, keylen); + if (m_Cipher == FXCIPHER_AES) { + m_pAESContext = FX_Alloc(uint8_t, 2048); + } + return TRUE; +} +FX_BOOL CPDF_CryptoHandler::DecryptStream(void* context, + const uint8_t* src_buf, + uint32_t src_size, + CFX_BinaryBuf& dest_buf) { + return CryptStream(context, src_buf, src_size, dest_buf, FALSE); +} +FX_BOOL CPDF_CryptoHandler::DecryptFinish(void* context, + CFX_BinaryBuf& dest_buf) { + return CryptFinish(context, dest_buf, FALSE); +} +uint32_t CPDF_CryptoHandler::EncryptGetSize(uint32_t objnum, + uint32_t version, + const uint8_t* src_buf, + uint32_t src_size) { + if (m_Cipher == FXCIPHER_AES) { + return src_size + 32; + } + return src_size; +} +FX_BOOL CPDF_CryptoHandler::EncryptContent(uint32_t objnum, + uint32_t gennum, + const uint8_t* src_buf, + uint32_t src_size, + uint8_t* dest_buf, + uint32_t& dest_size) { + CryptBlock(TRUE, objnum, gennum, src_buf, src_size, dest_buf, dest_size); + return TRUE; +} +CPDF_CryptoHandler::CPDF_CryptoHandler() { + m_pAESContext = nullptr; + m_Cipher = FXCIPHER_NONE; + m_KeyLen = 0; +} +CPDF_CryptoHandler::~CPDF_CryptoHandler() { + FX_Free(m_pAESContext); +} + +void CPDF_CryptoHandler::PopulateKey(uint32_t objnum, + uint32_t gennum, + uint8_t* key) { + FXSYS_memcpy(key, m_EncryptKey, m_KeyLen); + key[m_KeyLen + 0] = (uint8_t)objnum; + key[m_KeyLen + 1] = (uint8_t)(objnum >> 8); + key[m_KeyLen + 2] = (uint8_t)(objnum >> 16); + key[m_KeyLen + 3] = (uint8_t)gennum; + key[m_KeyLen + 4] = (uint8_t)(gennum >> 8); +} diff --git a/core/fpdfapi/parser/cpdf_crypto_handler.h b/core/fpdfapi/parser/cpdf_crypto_handler.h new file mode 100644 index 0000000000..37612f9ef0 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_crypto_handler.h @@ -0,0 +1,70 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_CRYPTO_HANDLER_H_ +#define CORE_FPDFAPI_PARSER_CPDF_CRYPTO_HANDLER_H_ + +#include "core/fxcrt/fx_basic.h" +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/fx_system.h" + +class CPDF_Dictionary; +class CPDF_SecurityHandler; + +class CPDF_CryptoHandler { + public: + CPDF_CryptoHandler(); + ~CPDF_CryptoHandler(); + + FX_BOOL Init(CPDF_Dictionary* pEncryptDict, + CPDF_SecurityHandler* pSecurityHandler); + uint32_t DecryptGetSize(uint32_t src_size); + void* DecryptStart(uint32_t objnum, uint32_t gennum); + void Decrypt(uint32_t objnum, uint32_t gennum, CFX_ByteString& str); + FX_BOOL DecryptStream(void* context, + const uint8_t* src_buf, + uint32_t src_size, + CFX_BinaryBuf& dest_buf); + FX_BOOL DecryptFinish(void* context, CFX_BinaryBuf& dest_buf); + uint32_t EncryptGetSize(uint32_t objnum, + uint32_t version, + const uint8_t* src_buf, + uint32_t src_size); + FX_BOOL EncryptContent(uint32_t objnum, + uint32_t version, + const uint8_t* src_buf, + uint32_t src_size, + uint8_t* dest_buf, + uint32_t& dest_size); + + FX_BOOL Init(int cipher, const uint8_t* key, int keylen); + + protected: + void CryptBlock(FX_BOOL bEncrypt, + uint32_t objnum, + uint32_t gennum, + const uint8_t* src_buf, + uint32_t src_size, + uint8_t* dest_buf, + uint32_t& dest_size); + void* CryptStart(uint32_t objnum, uint32_t gennum, FX_BOOL bEncrypt); + FX_BOOL CryptStream(void* context, + const uint8_t* src_buf, + uint32_t src_size, + CFX_BinaryBuf& dest_buf, + FX_BOOL bEncrypt); + FX_BOOL CryptFinish(void* context, CFX_BinaryBuf& dest_buf, FX_BOOL bEncrypt); + + uint8_t m_EncryptKey[32]; + int m_KeyLen; + int m_Cipher; + uint8_t* m_pAESContext; + + private: + void PopulateKey(uint32_t objnum, uint32_t gennum, uint8_t* key); +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_CRYPTO_HANDLER_H_ diff --git a/core/fpdfapi/parser/cpdf_data_avail.cpp b/core/fpdfapi/parser/cpdf_data_avail.cpp new file mode 100644 index 0000000000..da7f6948a3 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_data_avail.cpp @@ -0,0 +1,1844 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_data_avail.h" + +#include +#include +#include + +#include "core/fpdfapi/cpdf_modulemgr.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_hint_tables.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcrt/fx_ext.h" +#include "core/fxcrt/fx_safe_types.h" +#include "third_party/base/stl_util.h" + +CPDF_DataAvail::FileAvail::~FileAvail() {} + +CPDF_DataAvail::DownloadHints::~DownloadHints() {} + +// static +int CPDF_DataAvail::s_CurrentDataAvailRecursionDepth = 0; + +CPDF_DataAvail::CPDF_DataAvail(FileAvail* pFileAvail, + IFX_FileRead* pFileRead, + FX_BOOL bSupportHintTable) + : m_pFileAvail(pFileAvail), m_pFileRead(pFileRead) { + m_Pos = 0; + m_dwFileLen = 0; + if (m_pFileRead) { + m_dwFileLen = (uint32_t)m_pFileRead->GetSize(); + } + m_dwCurrentOffset = 0; + m_dwXRefOffset = 0; + m_bufferOffset = 0; + m_dwFirstPageNo = 0; + m_bufferSize = 0; + m_PagesObjNum = 0; + m_dwCurrentXRefSteam = 0; + m_dwAcroFormObjNum = 0; + m_dwInfoObjNum = 0; + m_pDocument = 0; + m_dwEncryptObjNum = 0; + m_dwPrevXRefOffset = 0; + m_dwLastXRefOffset = 0; + m_bDocAvail = FALSE; + m_bMainXRefLoadTried = FALSE; + m_bDocAvail = FALSE; + m_bLinearized = FALSE; + m_bPagesLoad = FALSE; + m_bPagesTreeLoad = FALSE; + m_bMainXRefLoadedOK = FALSE; + m_bAnnotsLoad = FALSE; + m_bHaveAcroForm = FALSE; + m_bAcroFormLoad = FALSE; + m_bPageLoadedOK = FALSE; + m_bNeedDownLoadResource = FALSE; + m_bLinearizedFormParamLoad = FALSE; + m_pLinearized = nullptr; + m_pRoot = nullptr; + m_pTrailer = nullptr; + m_pCurrentParser = nullptr; + m_pAcroForm = nullptr; + m_pPageDict = nullptr; + m_pPageResource = nullptr; + m_docStatus = PDF_DATAAVAIL_HEADER; + m_parser.m_bOwnFileRead = false; + m_bTotalLoadPageTree = FALSE; + m_bCurPageDictLoadOK = FALSE; + m_bLinearedDataOK = FALSE; + m_bSupportHintTable = bSupportHintTable; +} +CPDF_DataAvail::~CPDF_DataAvail() { + m_pHintTables.reset(); + if (m_pLinearized) + m_pLinearized->Release(); + + if (m_pRoot) + m_pRoot->Release(); + + if (m_pTrailer) + m_pTrailer->Release(); + + int iSize = m_arrayAcroforms.GetSize(); + for (int i = 0; i < iSize; ++i) + m_arrayAcroforms.GetAt(i)->Release(); +} + +void CPDF_DataAvail::SetDocument(CPDF_Document* pDoc) { + m_pDocument = pDoc; +} + +uint32_t CPDF_DataAvail::GetObjectSize(uint32_t objnum, FX_FILESIZE& offset) { + CPDF_Parser* pParser = m_pDocument->GetParser(); + if (!pParser || !pParser->IsValidObjectNumber(objnum)) + return 0; + + if (pParser->GetObjectType(objnum) == 2) + objnum = pParser->GetObjectPositionOrZero(objnum); + + if (pParser->GetObjectType(objnum) != 1 && + pParser->GetObjectType(objnum) != 255) { + return 0; + } + + offset = pParser->GetObjectPositionOrZero(objnum); + if (offset == 0) + return 0; + + auto it = pParser->m_SortedOffset.find(offset); + if (it == pParser->m_SortedOffset.end() || + ++it == pParser->m_SortedOffset.end()) { + return 0; + } + return *it - offset; +} + +FX_BOOL CPDF_DataAvail::IsObjectsAvail( + CFX_ArrayTemplate& obj_array, + FX_BOOL bParsePage, + DownloadHints* pHints, + CFX_ArrayTemplate& ret_array) { + if (!obj_array.GetSize()) + return TRUE; + + uint32_t count = 0; + CFX_ArrayTemplate new_obj_array; + for (int i = 0; i < obj_array.GetSize(); i++) { + CPDF_Object* pObj = obj_array[i]; + if (!pObj) + continue; + + int32_t type = pObj->GetType(); + switch (type) { + case CPDF_Object::ARRAY: { + CPDF_Array* pArray = pObj->AsArray(); + for (size_t k = 0; k < pArray->GetCount(); ++k) + new_obj_array.Add(pArray->GetObjectAt(k)); + } break; + case CPDF_Object::STREAM: + pObj = pObj->GetDict(); + case CPDF_Object::DICTIONARY: { + CPDF_Dictionary* pDict = pObj->GetDict(); + if (pDict && pDict->GetStringFor("Type") == "Page" && !bParsePage) + continue; + + for (const auto& it : *pDict) { + const CFX_ByteString& key = it.first; + CPDF_Object* value = it.second; + if (key != "Parent") + new_obj_array.Add(value); + } + } break; + case CPDF_Object::REFERENCE: { + CPDF_Reference* pRef = pObj->AsReference(); + uint32_t dwNum = pRef->GetRefObjNum(); + + FX_FILESIZE offset; + uint32_t size = GetObjectSize(dwNum, offset); + if (size == 0 || offset < 0 || offset >= m_dwFileLen) + break; + + if (!IsDataAvail(offset, size, pHints)) { + ret_array.Add(pObj); + count++; + } else if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) { + m_ObjectSet.insert(dwNum); + CPDF_Object* pReferred = + m_pDocument->GetOrParseIndirectObject(pRef->GetRefObjNum()); + if (pReferred) + new_obj_array.Add(pReferred); + } + } break; + } + } + + if (count > 0) { + for (int i = 0; i < new_obj_array.GetSize(); ++i) { + CPDF_Object* pObj = new_obj_array[i]; + if (CPDF_Reference* pRef = pObj->AsReference()) { + uint32_t dwNum = pRef->GetRefObjNum(); + if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) + ret_array.Add(pObj); + } else { + ret_array.Add(pObj); + } + } + return FALSE; + } + + obj_array.RemoveAll(); + obj_array.Append(new_obj_array); + return IsObjectsAvail(obj_array, FALSE, pHints, ret_array); +} + +CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsDocAvail( + DownloadHints* pHints) { + if (!m_dwFileLen && m_pFileRead) { + m_dwFileLen = (uint32_t)m_pFileRead->GetSize(); + if (!m_dwFileLen) + return DataError; + } + + while (!m_bDocAvail) { + if (!CheckDocStatus(pHints)) + return DataNotAvailable; + } + + return DataAvailable; +} + +FX_BOOL CPDF_DataAvail::CheckAcroFormSubObject(DownloadHints* pHints) { + if (!m_objs_array.GetSize()) { + m_objs_array.RemoveAll(); + m_ObjectSet.clear(); + CFX_ArrayTemplate obj_array; + obj_array.Append(m_arrayAcroforms); + FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); + if (bRet) + m_objs_array.RemoveAll(); + return bRet; + } + + CFX_ArrayTemplate new_objs_array; + FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); + if (bRet) { + int32_t iSize = m_arrayAcroforms.GetSize(); + for (int32_t i = 0; i < iSize; ++i) { + m_arrayAcroforms.GetAt(i)->Release(); + } + m_arrayAcroforms.RemoveAll(); + } else { + m_objs_array.RemoveAll(); + m_objs_array.Append(new_objs_array); + } + return bRet; +} + +FX_BOOL CPDF_DataAvail::CheckAcroForm(DownloadHints* pHints) { + FX_BOOL bExist = FALSE; + m_pAcroForm = GetObject(m_dwAcroFormObjNum, pHints, &bExist); + if (!bExist) { + m_docStatus = PDF_DATAAVAIL_PAGETREE; + return TRUE; + } + + if (!m_pAcroForm) { + if (m_docStatus == PDF_DATAAVAIL_ERROR) { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + return TRUE; + } + return FALSE; + } + + m_arrayAcroforms.Add(m_pAcroForm); + m_docStatus = PDF_DATAAVAIL_PAGETREE; + return TRUE; +} + +FX_BOOL CPDF_DataAvail::CheckDocStatus(DownloadHints* pHints) { + switch (m_docStatus) { + case PDF_DATAAVAIL_HEADER: + return CheckHeader(pHints); + case PDF_DATAAVAIL_FIRSTPAGE: + case PDF_DATAAVAIL_FIRSTPAGE_PREPARE: + return CheckFirstPage(pHints); + case PDF_DATAAVAIL_HINTTABLE: + return CheckHintTables(pHints); + case PDF_DATAAVAIL_END: + return CheckEnd(pHints); + case PDF_DATAAVAIL_CROSSREF: + return CheckCrossRef(pHints); + case PDF_DATAAVAIL_CROSSREF_ITEM: + return CheckCrossRefItem(pHints); + case PDF_DATAAVAIL_CROSSREF_STREAM: + return CheckAllCrossRefStream(pHints); + case PDF_DATAAVAIL_TRAILER: + return CheckTrailer(pHints); + case PDF_DATAAVAIL_TRAILER_APPEND: + return CheckTrailerAppend(pHints); + case PDF_DATAAVAIL_LOADALLCROSSREF: + return LoadAllXref(pHints); + case PDF_DATAAVAIL_LOADALLFILE: + return LoadAllFile(pHints); + case PDF_DATAAVAIL_ROOT: + return CheckRoot(pHints); + case PDF_DATAAVAIL_INFO: + return CheckInfo(pHints); + case PDF_DATAAVAIL_ACROFORM: + return CheckAcroForm(pHints); + case PDF_DATAAVAIL_PAGETREE: + if (m_bTotalLoadPageTree) + return CheckPages(pHints); + return LoadDocPages(pHints); + case PDF_DATAAVAIL_PAGE: + if (m_bTotalLoadPageTree) + return CheckPage(pHints); + m_docStatus = PDF_DATAAVAIL_PAGE_LATERLOAD; + return TRUE; + case PDF_DATAAVAIL_ERROR: + return LoadAllFile(pHints); + case PDF_DATAAVAIL_PAGE_LATERLOAD: + m_docStatus = PDF_DATAAVAIL_PAGE; + default: + m_bDocAvail = TRUE; + return TRUE; + } +} + +FX_BOOL CPDF_DataAvail::CheckPageStatus(DownloadHints* pHints) { + switch (m_docStatus) { + case PDF_DATAAVAIL_PAGETREE: + return CheckPages(pHints); + case PDF_DATAAVAIL_PAGE: + return CheckPage(pHints); + case PDF_DATAAVAIL_ERROR: + return LoadAllFile(pHints); + default: + m_bPagesTreeLoad = TRUE; + m_bPagesLoad = TRUE; + return TRUE; + } +} + +FX_BOOL CPDF_DataAvail::LoadAllFile(DownloadHints* pHints) { + if (m_pFileAvail->IsDataAvail(0, (uint32_t)m_dwFileLen)) { + m_docStatus = PDF_DATAAVAIL_DONE; + return TRUE; + } + + pHints->AddSegment(0, (uint32_t)m_dwFileLen); + return FALSE; +} + +FX_BOOL CPDF_DataAvail::LoadAllXref(DownloadHints* pHints) { + m_parser.m_pSyntax->InitParser(m_pFileRead, (uint32_t)m_dwHeaderOffset); + m_parser.m_bOwnFileRead = false; + if (!m_parser.LoadAllCrossRefV4(m_dwLastXRefOffset) && + !m_parser.LoadAllCrossRefV5(m_dwLastXRefOffset)) { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + return FALSE; + } + + m_dwRootObjNum = m_parser.GetRootObjNum(); + m_dwInfoObjNum = m_parser.GetInfoObjNum(); + m_pCurrentParser = &m_parser; + m_docStatus = PDF_DATAAVAIL_ROOT; + return TRUE; +} + +CPDF_Object* CPDF_DataAvail::GetObject(uint32_t objnum, + DownloadHints* pHints, + FX_BOOL* pExistInFile) { + CPDF_Object* pRet = nullptr; + uint32_t size = 0; + FX_FILESIZE offset = 0; + CPDF_Parser* pParser = nullptr; + + if (pExistInFile) + *pExistInFile = TRUE; + + if (m_pDocument) { + size = GetObjectSize(objnum, offset); + pParser = m_pDocument->GetParser(); + } else { + size = (uint32_t)m_parser.GetObjectSize(objnum); + offset = m_parser.GetObjectOffset(objnum); + pParser = &m_parser; + } + + if (!IsDataAvail(offset, size, pHints)) + return nullptr; + + if (pParser) + pRet = pParser->ParseIndirectObject(nullptr, objnum); + + if (!pRet && pExistInFile) + *pExistInFile = FALSE; + + return pRet; +} + +FX_BOOL CPDF_DataAvail::CheckInfo(DownloadHints* pHints) { + FX_BOOL bExist = FALSE; + CPDF_Object* pInfo = GetObject(m_dwInfoObjNum, pHints, &bExist); + if (!bExist) { + m_docStatus = + (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); + return TRUE; + } + + if (!pInfo) { + if (m_docStatus == PDF_DATAAVAIL_ERROR) { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + return TRUE; + } + + if (m_Pos == m_dwFileLen) + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + if (pInfo) + pInfo->Release(); + + m_docStatus = + (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); + + return TRUE; +} + +FX_BOOL CPDF_DataAvail::CheckRoot(DownloadHints* pHints) { + FX_BOOL bExist = FALSE; + m_pRoot = GetObject(m_dwRootObjNum, pHints, &bExist); + if (!bExist) { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + return TRUE; + } + + if (!m_pRoot) { + if (m_docStatus == PDF_DATAAVAIL_ERROR) { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + return TRUE; + } + return FALSE; + } + + CPDF_Dictionary* pDict = m_pRoot->GetDict(); + if (!pDict) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + CPDF_Reference* pRef = ToReference(pDict->GetObjectFor("Pages")); + if (!pRef) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + m_PagesObjNum = pRef->GetRefObjNum(); + CPDF_Reference* pAcroFormRef = + ToReference(m_pRoot->GetDict()->GetObjectFor("AcroForm")); + if (pAcroFormRef) { + m_bHaveAcroForm = TRUE; + m_dwAcroFormObjNum = pAcroFormRef->GetRefObjNum(); + } + + if (m_dwInfoObjNum) { + m_docStatus = PDF_DATAAVAIL_INFO; + } else { + m_docStatus = + m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE; + } + return TRUE; +} + +FX_BOOL CPDF_DataAvail::PreparePageItem() { + CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); + CPDF_Reference* pRef = + ToReference(pRoot ? pRoot->GetObjectFor("Pages") : nullptr); + if (!pRef) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + m_PagesObjNum = pRef->GetRefObjNum(); + m_pCurrentParser = m_pDocument->GetParser(); + m_docStatus = PDF_DATAAVAIL_PAGETREE; + return TRUE; +} + +bool CPDF_DataAvail::IsFirstCheck(uint32_t dwPage) { + return m_pageMapCheckState.insert(dwPage).second; +} + +void CPDF_DataAvail::ResetFirstCheck(uint32_t dwPage) { + m_pageMapCheckState.erase(dwPage); +} + +FX_BOOL CPDF_DataAvail::CheckPage(DownloadHints* pHints) { + uint32_t iPageObjs = m_PageObjList.GetSize(); + CFX_ArrayTemplate UnavailObjList; + for (uint32_t i = 0; i < iPageObjs; ++i) { + uint32_t dwPageObjNum = m_PageObjList.GetAt(i); + FX_BOOL bExist = FALSE; + CPDF_Object* pObj = GetObject(dwPageObjNum, pHints, &bExist); + if (!pObj) { + if (bExist) + UnavailObjList.Add(dwPageObjNum); + continue; + } + + CPDF_Array* pArray = ToArray(pObj); + if (pArray) { + for (CPDF_Object* pArrayObj : *pArray) { + if (CPDF_Reference* pRef = ToReference(pArrayObj)) + UnavailObjList.Add(pRef->GetRefObjNum()); + } + } + + if (!pObj->IsDictionary()) { + pObj->Release(); + continue; + } + + CFX_ByteString type = pObj->GetDict()->GetStringFor("Type"); + if (type == "Pages") { + m_PagesArray.Add(pObj); + continue; + } + pObj->Release(); + } + + m_PageObjList.RemoveAll(); + if (UnavailObjList.GetSize()) { + m_PageObjList.Append(UnavailObjList); + return FALSE; + } + + uint32_t iPages = m_PagesArray.GetSize(); + for (uint32_t i = 0; i < iPages; i++) { + CPDF_Object* pPages = m_PagesArray.GetAt(i); + if (!pPages) + continue; + + if (!GetPageKids(m_pCurrentParser, pPages)) { + pPages->Release(); + while (++i < iPages) { + pPages = m_PagesArray.GetAt(i); + pPages->Release(); + } + m_PagesArray.RemoveAll(); + + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + pPages->Release(); + } + + m_PagesArray.RemoveAll(); + if (!m_PageObjList.GetSize()) + m_docStatus = PDF_DATAAVAIL_DONE; + return TRUE; +} + +FX_BOOL CPDF_DataAvail::GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages) { + if (!pParser) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + CPDF_Dictionary* pDict = pPages->GetDict(); + CPDF_Object* pKids = pDict ? pDict->GetObjectFor("Kids") : nullptr; + if (!pKids) + return TRUE; + + switch (pKids->GetType()) { + case CPDF_Object::REFERENCE: + m_PageObjList.Add(pKids->AsReference()->GetRefObjNum()); + break; + case CPDF_Object::ARRAY: { + CPDF_Array* pKidsArray = pKids->AsArray(); + for (size_t i = 0; i < pKidsArray->GetCount(); ++i) { + if (CPDF_Reference* pRef = ToReference(pKidsArray->GetObjectAt(i))) + m_PageObjList.Add(pRef->GetRefObjNum()); + } + } break; + default: + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + return TRUE; +} + +FX_BOOL CPDF_DataAvail::CheckPages(DownloadHints* pHints) { + FX_BOOL bExist = FALSE; + CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); + if (!bExist) { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + return TRUE; + } + + if (!pPages) { + if (m_docStatus == PDF_DATAAVAIL_ERROR) { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + return TRUE; + } + return FALSE; + } + + if (!GetPageKids(m_pCurrentParser, pPages)) { + pPages->Release(); + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + pPages->Release(); + m_docStatus = PDF_DATAAVAIL_PAGE; + return TRUE; +} + +FX_BOOL CPDF_DataAvail::CheckHeader(DownloadHints* pHints) { + ASSERT(m_dwFileLen >= 0); + const uint32_t kReqSize = std::min(static_cast(m_dwFileLen), 1024U); + + if (m_pFileAvail->IsDataAvail(0, kReqSize)) { + uint8_t buffer[1024]; + m_pFileRead->ReadBlock(buffer, 0, kReqSize); + + if (IsLinearizedFile(buffer, kReqSize)) { + m_docStatus = PDF_DATAAVAIL_FIRSTPAGE; + } else { + if (m_docStatus == PDF_DATAAVAIL_ERROR) + return FALSE; + m_docStatus = PDF_DATAAVAIL_END; + } + return TRUE; + } + + pHints->AddSegment(0, kReqSize); + return FALSE; +} + +FX_BOOL CPDF_DataAvail::CheckFirstPage(DownloadHints* pHints) { + CPDF_Dictionary* pDict = m_pLinearized->GetDict(); + CPDF_Object* pEndOffSet = pDict ? pDict->GetObjectFor("E") : nullptr; + if (!pEndOffSet) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + CPDF_Object* pXRefOffset = pDict ? pDict->GetObjectFor("T") : nullptr; + if (!pXRefOffset) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + CPDF_Object* pFileLen = pDict ? pDict->GetObjectFor("L") : nullptr; + if (!pFileLen) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + FX_BOOL bNeedDownLoad = FALSE; + if (pEndOffSet->IsNumber()) { + uint32_t dwEnd = pEndOffSet->GetInteger(); + dwEnd += 512; + if ((FX_FILESIZE)dwEnd > m_dwFileLen) + dwEnd = (uint32_t)m_dwFileLen; + + int32_t iStartPos = (int32_t)(m_dwFileLen > 1024 ? 1024 : m_dwFileLen); + int32_t iSize = dwEnd > 1024 ? dwEnd - 1024 : 0; + if (!m_pFileAvail->IsDataAvail(iStartPos, iSize)) { + pHints->AddSegment(iStartPos, iSize); + bNeedDownLoad = TRUE; + } + } + + m_dwLastXRefOffset = 0; + FX_FILESIZE dwFileLen = 0; + if (pXRefOffset->IsNumber()) + m_dwLastXRefOffset = pXRefOffset->GetInteger(); + + if (pFileLen->IsNumber()) + dwFileLen = pFileLen->GetInteger(); + + if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, + (uint32_t)(dwFileLen - m_dwLastXRefOffset))) { + if (m_docStatus == PDF_DATAAVAIL_FIRSTPAGE) { + uint32_t dwSize = (uint32_t)(dwFileLen - m_dwLastXRefOffset); + FX_FILESIZE offset = m_dwLastXRefOffset; + if (dwSize < 512 && dwFileLen > 512) { + dwSize = 512; + offset = dwFileLen - 512; + } + pHints->AddSegment(offset, dwSize); + } + } else { + m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; + } + + if (bNeedDownLoad || m_docStatus != PDF_DATAAVAIL_FIRSTPAGE_PREPARE) { + m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; + return FALSE; + } + + m_docStatus = + m_bSupportHintTable ? PDF_DATAAVAIL_HINTTABLE : PDF_DATAAVAIL_DONE; + return TRUE; +} + +FX_BOOL CPDF_DataAvail::IsDataAvail(FX_FILESIZE offset, + uint32_t size, + DownloadHints* pHints) { + if (offset < 0 || offset > m_dwFileLen) + return TRUE; + + FX_SAFE_FILESIZE safeSize = offset; + safeSize += size; + safeSize += 512; + if (!safeSize.IsValid() || safeSize.ValueOrDie() > m_dwFileLen) + size = m_dwFileLen - offset; + else + size += 512; + + if (!m_pFileAvail->IsDataAvail(offset, size)) { + pHints->AddSegment(offset, size); + return FALSE; + } + return TRUE; +} + +FX_BOOL CPDF_DataAvail::CheckHintTables(DownloadHints* pHints) { + CPDF_Dictionary* pDict = m_pLinearized->GetDict(); + if (!pDict) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + // The actual value is not required here, but validate its existence and type. + CPDF_Number* pFirstPage = ToNumber(pDict->GetDirectObjectFor("O")); + if (!pFirstPage || !pFirstPage->IsInteger()) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + CPDF_Number* pPageCount = ToNumber(pDict->GetDirectObjectFor("N")); + if (!pPageCount || !pPageCount->IsInteger()) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + int nPageCount = pPageCount->GetInteger(); + if (nPageCount <= 1) { + m_docStatus = PDF_DATAAVAIL_DONE; + return TRUE; + } + + CPDF_Array* pHintStreamRange = pDict->GetArrayFor("H"); + size_t nHintStreamSize = pHintStreamRange ? pHintStreamRange->GetCount() : 0; + if (nHintStreamSize != 2 && nHintStreamSize != 4) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + for (const CPDF_Object* pArrayObject : *pHintStreamRange) { + const CPDF_Number* pNumber = ToNumber(pArrayObject->GetDirect()); + if (!pNumber || !pNumber->IsInteger()) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + } + + FX_FILESIZE szHintStart = pHintStreamRange->GetIntegerAt(0); + FX_FILESIZE szHintLength = pHintStreamRange->GetIntegerAt(1); + if (szHintStart < 0 || szHintLength <= 0) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + if (!IsDataAvail(szHintStart, szHintLength, pHints)) + return FALSE; + + m_syntaxParser.InitParser(m_pFileRead, m_dwHeaderOffset); + + std::unique_ptr pHintTables( + new CPDF_HintTables(this, pDict)); + std::unique_ptr> pHintStream( + ParseIndirectObjectAt(szHintStart, 0)); + CPDF_Stream* pStream = ToStream(pHintStream.get()); + if (pStream && pHintTables->LoadHintStream(pStream)) + m_pHintTables = std::move(pHintTables); + + m_docStatus = PDF_DATAAVAIL_DONE; + return TRUE; +} + +CPDF_Object* CPDF_DataAvail::ParseIndirectObjectAt( + FX_FILESIZE pos, + uint32_t objnum, + CPDF_IndirectObjectHolder* pObjList) { + FX_FILESIZE SavedPos = m_syntaxParser.SavePos(); + m_syntaxParser.RestorePos(pos); + + bool bIsNumber; + CFX_ByteString word = m_syntaxParser.GetNextWord(&bIsNumber); + if (!bIsNumber) + return nullptr; + + uint32_t parser_objnum = FXSYS_atoui(word.c_str()); + if (objnum && parser_objnum != objnum) + return nullptr; + + word = m_syntaxParser.GetNextWord(&bIsNumber); + if (!bIsNumber) + return nullptr; + + uint32_t gennum = FXSYS_atoui(word.c_str()); + if (m_syntaxParser.GetKeyword() != "obj") { + m_syntaxParser.RestorePos(SavedPos); + return nullptr; + } + + CPDF_Object* pObj = + m_syntaxParser.GetObject(pObjList, parser_objnum, gennum, true); + m_syntaxParser.RestorePos(SavedPos); + return pObj; +} + +CPDF_DataAvail::DocLinearizationStatus CPDF_DataAvail::IsLinearizedPDF() { + const uint32_t kReqSize = 1024; + if (!m_pFileAvail->IsDataAvail(0, kReqSize)) + return LinearizationUnknown; + + if (!m_pFileRead) + return NotLinearized; + + FX_FILESIZE dwSize = m_pFileRead->GetSize(); + if (dwSize < (FX_FILESIZE)kReqSize) + return LinearizationUnknown; + + uint8_t buffer[1024]; + m_pFileRead->ReadBlock(buffer, 0, kReqSize); + if (IsLinearizedFile(buffer, kReqSize)) + return Linearized; + + return NotLinearized; +} + +FX_BOOL CPDF_DataAvail::IsLinearized() { + return m_bLinearized; +} + +FX_BOOL CPDF_DataAvail::IsLinearizedFile(uint8_t* pData, uint32_t dwLen) { + if (m_pLinearized) + return m_bLinearized; + + ScopedFileStream file(FX_CreateMemoryStream(pData, (size_t)dwLen, FALSE)); + + int32_t offset = GetHeaderOffset(file.get()); + if (offset == -1) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + m_dwHeaderOffset = offset; + m_syntaxParser.InitParser(file.get(), offset); + m_syntaxParser.RestorePos(m_syntaxParser.m_HeaderOffset + 9); + + bool bNumber; + CFX_ByteString wordObjNum = m_syntaxParser.GetNextWord(&bNumber); + if (!bNumber) + return FALSE; + + uint32_t objnum = FXSYS_atoui(wordObjNum.c_str()); + m_pLinearized = + ParseIndirectObjectAt(m_syntaxParser.m_HeaderOffset + 9, objnum); + if (!m_pLinearized) + return FALSE; + + CPDF_Dictionary* pDict = m_pLinearized->GetDict(); + if (!pDict || !pDict->GetObjectFor("Linearized")) + return FALSE; + + CPDF_Object* pLen = pDict->GetObjectFor("L"); + if (!pLen) + return FALSE; + + if ((FX_FILESIZE)pLen->GetInteger() != m_pFileRead->GetSize()) + return FALSE; + + m_bLinearized = TRUE; + + if (CPDF_Number* pNo = ToNumber(pDict->GetObjectFor("P"))) + m_dwFirstPageNo = pNo->GetInteger(); + + return TRUE; +} + +FX_BOOL CPDF_DataAvail::CheckEnd(DownloadHints* pHints) { + uint32_t req_pos = (uint32_t)(m_dwFileLen > 1024 ? m_dwFileLen - 1024 : 0); + uint32_t dwSize = (uint32_t)(m_dwFileLen - req_pos); + + if (m_pFileAvail->IsDataAvail(req_pos, dwSize)) { + uint8_t buffer[1024]; + m_pFileRead->ReadBlock(buffer, req_pos, dwSize); + + ScopedFileStream file(FX_CreateMemoryStream(buffer, (size_t)dwSize, FALSE)); + m_syntaxParser.InitParser(file.get(), 0); + m_syntaxParser.RestorePos(dwSize - 1); + + if (m_syntaxParser.SearchWord("startxref", TRUE, FALSE, dwSize)) { + m_syntaxParser.GetNextWord(nullptr); + + bool bNumber; + CFX_ByteString xrefpos_str = m_syntaxParser.GetNextWord(&bNumber); + if (!bNumber) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + m_dwXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str.c_str()); + if (!m_dwXRefOffset || m_dwXRefOffset > m_dwFileLen) { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + return TRUE; + } + + m_dwLastXRefOffset = m_dwXRefOffset; + SetStartOffset(m_dwXRefOffset); + m_docStatus = PDF_DATAAVAIL_CROSSREF; + return TRUE; + } + + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + return TRUE; + } + + pHints->AddSegment(req_pos, dwSize); + return FALSE; +} + +int32_t CPDF_DataAvail::CheckCrossRefStream(DownloadHints* pHints, + FX_FILESIZE& xref_offset) { + xref_offset = 0; + uint32_t req_size = + (uint32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); + + if (m_pFileAvail->IsDataAvail(m_Pos, req_size)) { + int32_t iSize = (int32_t)(m_Pos + req_size - m_dwCurrentXRefSteam); + CFX_BinaryBuf buf(iSize); + uint8_t* pBuf = buf.GetBuffer(); + + m_pFileRead->ReadBlock(pBuf, m_dwCurrentXRefSteam, iSize); + + ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); + m_parser.m_pSyntax->InitParser(file.get(), 0); + + bool bNumber; + CFX_ByteString objnum = m_parser.m_pSyntax->GetNextWord(&bNumber); + if (!bNumber) + return -1; + + uint32_t objNum = FXSYS_atoui(objnum.c_str()); + CPDF_Object* pObj = m_parser.ParseIndirectObjectAt(nullptr, 0, objNum); + if (!pObj) { + m_Pos += m_parser.m_pSyntax->SavePos(); + return 0; + } + + CPDF_Dictionary* pDict = pObj->GetDict(); + CPDF_Name* pName = ToName(pDict ? pDict->GetObjectFor("Type") : nullptr); + if (pName) { + if (pName->GetString() == "XRef") { + m_Pos += m_parser.m_pSyntax->SavePos(); + xref_offset = pObj->GetDict()->GetIntegerFor("Prev"); + pObj->Release(); + return 1; + } + } + pObj->Release(); + return -1; + } + pHints->AddSegment(m_Pos, req_size); + return 0; +} + +void CPDF_DataAvail::SetStartOffset(FX_FILESIZE dwOffset) { + m_Pos = dwOffset; +} + +FX_BOOL CPDF_DataAvail::GetNextToken(CFX_ByteString& token) { + uint8_t ch; + if (!GetNextChar(ch)) + return FALSE; + + while (1) { + while (PDFCharIsWhitespace(ch)) { + if (!GetNextChar(ch)) + return FALSE; + } + + if (ch != '%') + break; + + while (1) { + if (!GetNextChar(ch)) + return FALSE; + if (PDFCharIsLineEnding(ch)) + break; + } + } + + uint8_t buffer[256]; + uint32_t index = 0; + if (PDFCharIsDelimiter(ch)) { + buffer[index++] = ch; + if (ch == '/') { + while (1) { + if (!GetNextChar(ch)) + return FALSE; + + if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { + m_Pos--; + CFX_ByteString ret(buffer, index); + token = ret; + return TRUE; + } + + if (index < sizeof(buffer)) + buffer[index++] = ch; + } + } else if (ch == '<') { + if (!GetNextChar(ch)) + return FALSE; + + if (ch == '<') + buffer[index++] = ch; + else + m_Pos--; + } else if (ch == '>') { + if (!GetNextChar(ch)) + return FALSE; + + if (ch == '>') + buffer[index++] = ch; + else + m_Pos--; + } + + CFX_ByteString ret(buffer, index); + token = ret; + return TRUE; + } + + while (1) { + if (index < sizeof(buffer)) + buffer[index++] = ch; + + if (!GetNextChar(ch)) + return FALSE; + + if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { + m_Pos--; + break; + } + } + + token = CFX_ByteString(buffer, index); + return TRUE; +} + +FX_BOOL CPDF_DataAvail::GetNextChar(uint8_t& ch) { + FX_FILESIZE pos = m_Pos; + if (pos >= m_dwFileLen) + return FALSE; + + if (m_bufferOffset >= pos || + (FX_FILESIZE)(m_bufferOffset + m_bufferSize) <= pos) { + FX_FILESIZE read_pos = pos; + uint32_t read_size = 512; + if ((FX_FILESIZE)read_size > m_dwFileLen) + read_size = (uint32_t)m_dwFileLen; + + if ((FX_FILESIZE)(read_pos + read_size) > m_dwFileLen) + read_pos = m_dwFileLen - read_size; + + if (!m_pFileRead->ReadBlock(m_bufferData, read_pos, read_size)) + return FALSE; + + m_bufferOffset = read_pos; + m_bufferSize = read_size; + } + ch = m_bufferData[pos - m_bufferOffset]; + m_Pos++; + return TRUE; +} + +FX_BOOL CPDF_DataAvail::CheckCrossRefItem(DownloadHints* pHints) { + int32_t iSize = 0; + CFX_ByteString token; + while (1) { + if (!GetNextToken(token)) { + iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); + pHints->AddSegment(m_Pos, iSize); + return FALSE; + } + + if (token == "trailer") { + m_dwTrailerOffset = m_Pos; + m_docStatus = PDF_DATAAVAIL_TRAILER; + return TRUE; + } + } +} + +FX_BOOL CPDF_DataAvail::CheckAllCrossRefStream(DownloadHints* pHints) { + FX_FILESIZE xref_offset = 0; + + int32_t nRet = CheckCrossRefStream(pHints, xref_offset); + if (nRet == 1) { + if (!xref_offset) { + m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; + } else { + m_dwCurrentXRefSteam = xref_offset; + m_Pos = xref_offset; + } + return TRUE; + } + + if (nRet == -1) + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; +} + +FX_BOOL CPDF_DataAvail::CheckCrossRef(DownloadHints* pHints) { + int32_t iSize = 0; + CFX_ByteString token; + if (!GetNextToken(token)) { + iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); + pHints->AddSegment(m_Pos, iSize); + return FALSE; + } + + if (token == "xref") { + while (1) { + if (!GetNextToken(token)) { + iSize = + (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); + pHints->AddSegment(m_Pos, iSize); + m_docStatus = PDF_DATAAVAIL_CROSSREF_ITEM; + return FALSE; + } + + if (token == "trailer") { + m_dwTrailerOffset = m_Pos; + m_docStatus = PDF_DATAAVAIL_TRAILER; + return TRUE; + } + } + } else { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + return TRUE; + } + return FALSE; +} + +FX_BOOL CPDF_DataAvail::CheckTrailerAppend(DownloadHints* pHints) { + if (m_Pos < m_dwFileLen) { + FX_FILESIZE dwAppendPos = m_Pos + m_syntaxParser.SavePos(); + int32_t iSize = (int32_t)( + dwAppendPos + 512 > m_dwFileLen ? m_dwFileLen - dwAppendPos : 512); + + if (!m_pFileAvail->IsDataAvail(dwAppendPos, iSize)) { + pHints->AddSegment(dwAppendPos, iSize); + return FALSE; + } + } + + if (m_dwPrevXRefOffset) { + SetStartOffset(m_dwPrevXRefOffset); + m_docStatus = PDF_DATAAVAIL_CROSSREF; + } else { + m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; + } + return TRUE; +} + +FX_BOOL CPDF_DataAvail::CheckTrailer(DownloadHints* pHints) { + int32_t iTrailerSize = + (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); + if (m_pFileAvail->IsDataAvail(m_Pos, iTrailerSize)) { + int32_t iSize = (int32_t)(m_Pos + iTrailerSize - m_dwTrailerOffset); + CFX_BinaryBuf buf(iSize); + uint8_t* pBuf = buf.GetBuffer(); + if (!pBuf) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + if (!m_pFileRead->ReadBlock(pBuf, m_dwTrailerOffset, iSize)) + return FALSE; + + ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); + m_syntaxParser.InitParser(file.get(), 0); + + std::unique_ptr> pTrailer( + m_syntaxParser.GetObject(nullptr, 0, 0, true)); + if (!pTrailer) { + m_Pos += m_syntaxParser.SavePos(); + pHints->AddSegment(m_Pos, iTrailerSize); + return FALSE; + } + + if (!pTrailer->IsDictionary()) + return FALSE; + + CPDF_Dictionary* pTrailerDict = pTrailer->GetDict(); + CPDF_Object* pEncrypt = pTrailerDict->GetObjectFor("Encrypt"); + if (ToReference(pEncrypt)) { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + return TRUE; + } + + uint32_t xrefpos = GetDirectInteger(pTrailerDict, "Prev"); + if (xrefpos) { + m_dwPrevXRefOffset = GetDirectInteger(pTrailerDict, "XRefStm"); + if (m_dwPrevXRefOffset) { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + } else { + m_dwPrevXRefOffset = xrefpos; + if (m_dwPrevXRefOffset >= m_dwFileLen) { + m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + } else { + SetStartOffset(m_dwPrevXRefOffset); + m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; + } + } + return TRUE; + } + m_dwPrevXRefOffset = 0; + m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; + return TRUE; + } + pHints->AddSegment(m_Pos, iTrailerSize); + return FALSE; +} + +FX_BOOL CPDF_DataAvail::CheckPage(uint32_t dwPage, DownloadHints* pHints) { + while (TRUE) { + switch (m_docStatus) { + case PDF_DATAAVAIL_PAGETREE: + if (!LoadDocPages(pHints)) + return FALSE; + break; + case PDF_DATAAVAIL_PAGE: + if (!LoadDocPage(dwPage, pHints)) + return FALSE; + break; + case PDF_DATAAVAIL_ERROR: + return LoadAllFile(pHints); + default: + m_bPagesTreeLoad = TRUE; + m_bPagesLoad = TRUE; + m_bCurPageDictLoadOK = TRUE; + m_docStatus = PDF_DATAAVAIL_PAGE; + return TRUE; + } + } +} + +FX_BOOL CPDF_DataAvail::CheckArrayPageNode(uint32_t dwPageNo, + PageNode* pPageNode, + DownloadHints* pHints) { + FX_BOOL bExist = FALSE; + CPDF_Object* pPages = GetObject(dwPageNo, pHints, &bExist); + if (!bExist) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + if (!pPages) { + if (m_docStatus == PDF_DATAAVAIL_ERROR) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + return FALSE; + } + + CPDF_Array* pArray = pPages->AsArray(); + if (!pArray) { + pPages->Release(); + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + pPageNode->m_type = PDF_PAGENODE_PAGES; + for (size_t i = 0; i < pArray->GetCount(); ++i) { + CPDF_Reference* pKid = ToReference(pArray->GetObjectAt(i)); + if (!pKid) + continue; + + PageNode* pNode = new PageNode(); + pPageNode->m_childNode.Add(pNode); + pNode->m_dwPageNo = pKid->GetRefObjNum(); + } + pPages->Release(); + return TRUE; +} + +FX_BOOL CPDF_DataAvail::CheckUnkownPageNode(uint32_t dwPageNo, + PageNode* pPageNode, + DownloadHints* pHints) { + FX_BOOL bExist = FALSE; + CPDF_Object* pPage = GetObject(dwPageNo, pHints, &bExist); + if (!bExist) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + if (!pPage) { + if (m_docStatus == PDF_DATAAVAIL_ERROR) + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + if (pPage->IsArray()) { + pPageNode->m_dwPageNo = dwPageNo; + pPageNode->m_type = PDF_PAGENODE_ARRAY; + pPage->Release(); + return TRUE; + } + + if (!pPage->IsDictionary()) { + pPage->Release(); + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + pPageNode->m_dwPageNo = dwPageNo; + CPDF_Dictionary* pDict = pPage->GetDict(); + CFX_ByteString type = pDict->GetStringFor("Type"); + if (type == "Pages") { + pPageNode->m_type = PDF_PAGENODE_PAGES; + CPDF_Object* pKids = pDict->GetObjectFor("Kids"); + if (!pKids) { + m_docStatus = PDF_DATAAVAIL_PAGE; + return TRUE; + } + + switch (pKids->GetType()) { + case CPDF_Object::REFERENCE: { + CPDF_Reference* pKid = pKids->AsReference(); + PageNode* pNode = new PageNode(); + pPageNode->m_childNode.Add(pNode); + pNode->m_dwPageNo = pKid->GetRefObjNum(); + } break; + case CPDF_Object::ARRAY: { + CPDF_Array* pKidsArray = pKids->AsArray(); + for (size_t i = 0; i < pKidsArray->GetCount(); ++i) { + CPDF_Reference* pKid = ToReference(pKidsArray->GetObjectAt(i)); + if (!pKid) + continue; + + PageNode* pNode = new PageNode(); + pPageNode->m_childNode.Add(pNode); + pNode->m_dwPageNo = pKid->GetRefObjNum(); + } + } break; + default: + break; + } + } else if (type == "Page") { + pPageNode->m_type = PDF_PAGENODE_PAGE; + } else { + pPage->Release(); + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + pPage->Release(); + return TRUE; +} + +FX_BOOL CPDF_DataAvail::CheckPageNode(CPDF_DataAvail::PageNode& pageNodes, + int32_t iPage, + int32_t& iCount, + DownloadHints* pHints, + int level) { + if (level >= kMaxPageRecursionDepth) + return FALSE; + + int32_t iSize = pageNodes.m_childNode.GetSize(); + if (iSize <= 0 || iPage >= iSize) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + for (int32_t i = 0; i < iSize; ++i) { + PageNode* pNode = pageNodes.m_childNode.GetAt(i); + if (!pNode) + continue; + + switch (pNode->m_type) { + case PDF_PAGENODE_UNKNOWN: + if (!CheckUnkownPageNode(pNode->m_dwPageNo, pNode, pHints)) { + return FALSE; + } + --i; + break; + case PDF_PAGENODE_PAGE: + iCount++; + if (iPage == iCount && m_pDocument) + m_pDocument->SetPageObjNum(iPage, pNode->m_dwPageNo); + break; + case PDF_PAGENODE_PAGES: + if (!CheckPageNode(*pNode, iPage, iCount, pHints, level + 1)) + return FALSE; + break; + case PDF_PAGENODE_ARRAY: + if (!CheckArrayPageNode(pNode->m_dwPageNo, pNode, pHints)) + return FALSE; + --i; + break; + } + + if (iPage == iCount) { + m_docStatus = PDF_DATAAVAIL_DONE; + return TRUE; + } + } + return TRUE; +} + +FX_BOOL CPDF_DataAvail::LoadDocPage(uint32_t dwPage, DownloadHints* pHints) { + FX_SAFE_INT32 safePage = pdfium::base::checked_cast(dwPage); + int32_t iPage = safePage.ValueOrDie(); + if (m_pDocument->GetPageCount() <= iPage || + m_pDocument->IsPageLoaded(iPage)) { + m_docStatus = PDF_DATAAVAIL_DONE; + return TRUE; + } + + if (m_pageNodes.m_type == PDF_PAGENODE_PAGE) { + if (iPage == 0) { + m_docStatus = PDF_DATAAVAIL_DONE; + return TRUE; + } + m_docStatus = PDF_DATAAVAIL_ERROR; + return TRUE; + } + int32_t iCount = -1; + return CheckPageNode(m_pageNodes, iPage, iCount, pHints, 0); +} + +FX_BOOL CPDF_DataAvail::CheckPageCount(DownloadHints* pHints) { + FX_BOOL bExist = FALSE; + CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); + if (!bExist) { + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + if (!pPages) + return FALSE; + + CPDF_Dictionary* pPagesDict = pPages->GetDict(); + if (!pPagesDict) { + pPages->Release(); + m_docStatus = PDF_DATAAVAIL_ERROR; + return FALSE; + } + + if (!pPagesDict->KeyExist("Kids")) { + pPages->Release(); + return TRUE; + } + + int count = pPagesDict->GetIntegerFor("Count"); + if (count > 0) { + pPages->Release(); + return TRUE; + } + + pPages->Release(); + return FALSE; +} + +FX_BOOL CPDF_DataAvail::LoadDocPages(DownloadHints* pHints) { + if (!CheckUnkownPageNode(m_PagesObjNum, &m_pageNodes, pHints)) + return FALSE; + + if (CheckPageCount(pHints)) { + m_docStatus = PDF_DATAAVAIL_PAGE; + return TRUE; + } + + m_bTotalLoadPageTree = TRUE; + return FALSE; +} + +FX_BOOL CPDF_DataAvail::LoadPages(DownloadHints* pHints) { + while (!m_bPagesTreeLoad) { + if (!CheckPageStatus(pHints)) + return FALSE; + } + + if (m_bPagesLoad) + return TRUE; + + m_pDocument->LoadPages(); + return FALSE; +} + +CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedData( + DownloadHints* pHints) { + if (m_bLinearedDataOK) + return DataAvailable; + + if (!m_bMainXRefLoadTried) { + FX_SAFE_UINT32 data_size = m_dwFileLen; + data_size -= m_dwLastXRefOffset; + if (!data_size.IsValid()) + return DataError; + + if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, + data_size.ValueOrDie())) { + pHints->AddSegment(m_dwLastXRefOffset, data_size.ValueOrDie()); + return DataNotAvailable; + } + + CPDF_Parser::Error eRet = + m_pDocument->GetParser()->LoadLinearizedMainXRefTable(); + m_bMainXRefLoadTried = TRUE; + if (eRet != CPDF_Parser::SUCCESS) + return DataError; + + if (!PreparePageItem()) + return DataNotAvailable; + + m_bMainXRefLoadedOK = TRUE; + m_bLinearedDataOK = TRUE; + } + + return m_bLinearedDataOK ? DataAvailable : DataNotAvailable; +} + +FX_BOOL CPDF_DataAvail::CheckPageAnnots(uint32_t dwPage, + DownloadHints* pHints) { + if (!m_objs_array.GetSize()) { + m_objs_array.RemoveAll(); + m_ObjectSet.clear(); + + FX_SAFE_INT32 safePage = pdfium::base::checked_cast(dwPage); + CPDF_Dictionary* pPageDict = m_pDocument->GetPage(safePage.ValueOrDie()); + if (!pPageDict) + return TRUE; + + CPDF_Object* pAnnots = pPageDict->GetObjectFor("Annots"); + if (!pAnnots) + return TRUE; + + CFX_ArrayTemplate obj_array; + obj_array.Add(pAnnots); + + FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); + if (bRet) + m_objs_array.RemoveAll(); + + return bRet; + } + + CFX_ArrayTemplate new_objs_array; + FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); + m_objs_array.RemoveAll(); + if (!bRet) + m_objs_array.Append(new_objs_array); + + return bRet; +} + +CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedFirstPage( + uint32_t dwPage, + DownloadHints* pHints) { + if (!m_bAnnotsLoad) { + if (!CheckPageAnnots(dwPage, pHints)) + return DataNotAvailable; + m_bAnnotsLoad = TRUE; + } + + DocAvailStatus nRet = CheckLinearizedData(pHints); + if (nRet == DataAvailable) + m_bPageLoadedOK = FALSE; + return nRet; +} + +FX_BOOL CPDF_DataAvail::HaveResourceAncestor(CPDF_Dictionary* pDict) { + CFX_AutoRestorer restorer(&s_CurrentDataAvailRecursionDepth); + if (++s_CurrentDataAvailRecursionDepth > kMaxDataAvailRecursionDepth) + return FALSE; + + CPDF_Object* pParent = pDict->GetObjectFor("Parent"); + if (!pParent) + return FALSE; + + CPDF_Dictionary* pParentDict = pParent->GetDict(); + if (!pParentDict) + return FALSE; + + CPDF_Object* pRet = pParentDict->GetObjectFor("Resources"); + if (pRet) { + m_pPageResource = pRet; + return TRUE; + } + + return HaveResourceAncestor(pParentDict); +} + +CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsPageAvail( + uint32_t dwPage, + DownloadHints* pHints) { + if (!m_pDocument) + return DataError; + + if (IsFirstCheck(dwPage)) { + m_bCurPageDictLoadOK = FALSE; + m_bPageLoadedOK = FALSE; + m_bAnnotsLoad = FALSE; + m_bNeedDownLoadResource = FALSE; + m_objs_array.RemoveAll(); + m_ObjectSet.clear(); + } + + if (pdfium::ContainsKey(m_pagesLoadState, dwPage)) + return DataAvailable; + + if (m_bLinearized) { + if (dwPage == m_dwFirstPageNo) { + DocAvailStatus nRet = CheckLinearizedFirstPage(dwPage, pHints); + if (nRet == DataAvailable) + m_pagesLoadState.insert(dwPage); + return nRet; + } + + DocAvailStatus nResult = CheckLinearizedData(pHints); + if (nResult != DataAvailable) + return nResult; + + if (m_pHintTables) { + nResult = m_pHintTables->CheckPage(dwPage, pHints); + if (nResult != DataAvailable) + return nResult; + m_pagesLoadState.insert(dwPage); + return DataAvailable; + } + + if (m_bMainXRefLoadedOK) { + if (m_bTotalLoadPageTree) { + if (!LoadPages(pHints)) + return DataNotAvailable; + } else { + if (!m_bCurPageDictLoadOK && !CheckPage(dwPage, pHints)) + return DataNotAvailable; + } + } else { + if (!LoadAllFile(pHints)) + return DataNotAvailable; + m_pDocument->GetParser()->RebuildCrossRef(); + ResetFirstCheck(dwPage); + return DataAvailable; + } + } else { + if (!m_bTotalLoadPageTree && !m_bCurPageDictLoadOK && + !CheckPage(dwPage, pHints)) { + return DataNotAvailable; + } + } + + if (m_bHaveAcroForm && !m_bAcroFormLoad) { + if (!CheckAcroFormSubObject(pHints)) + return DataNotAvailable; + m_bAcroFormLoad = TRUE; + } + + if (!m_bPageLoadedOK) { + if (!m_objs_array.GetSize()) { + m_objs_array.RemoveAll(); + m_ObjectSet.clear(); + + FX_SAFE_INT32 safePage = pdfium::base::checked_cast(dwPage); + m_pPageDict = m_pDocument->GetPage(safePage.ValueOrDie()); + if (!m_pPageDict) { + ResetFirstCheck(dwPage); + return DataAvailable; + } + + CFX_ArrayTemplate obj_array; + obj_array.Add(m_pPageDict); + FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); + if (!bRet) + return DataNotAvailable; + + m_objs_array.RemoveAll(); + } else { + CFX_ArrayTemplate new_objs_array; + FX_BOOL bRet = + IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); + + m_objs_array.RemoveAll(); + if (!bRet) { + m_objs_array.Append(new_objs_array); + return DataNotAvailable; + } + } + m_bPageLoadedOK = TRUE; + } + + if (!m_bAnnotsLoad) { + if (!CheckPageAnnots(dwPage, pHints)) + return DataNotAvailable; + m_bAnnotsLoad = TRUE; + } + + if (m_pPageDict && !m_bNeedDownLoadResource) { + m_pPageResource = m_pPageDict->GetObjectFor("Resources"); + m_bNeedDownLoadResource = + m_pPageResource || HaveResourceAncestor(m_pPageDict); + } + + if (m_bNeedDownLoadResource) { + if (!CheckResources(pHints)) + return DataNotAvailable; + m_bNeedDownLoadResource = FALSE; + } + + m_bPageLoadedOK = FALSE; + m_bAnnotsLoad = FALSE; + m_bCurPageDictLoadOK = FALSE; + + ResetFirstCheck(dwPage); + m_pagesLoadState.insert(dwPage); + return DataAvailable; +} + +FX_BOOL CPDF_DataAvail::CheckResources(DownloadHints* pHints) { + if (!m_objs_array.GetSize()) { + m_objs_array.RemoveAll(); + CFX_ArrayTemplate obj_array; + obj_array.Add(m_pPageResource); + + FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); + if (bRet) + m_objs_array.RemoveAll(); + return bRet; + } + + CFX_ArrayTemplate new_objs_array; + FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); + m_objs_array.RemoveAll(); + if (!bRet) + m_objs_array.Append(new_objs_array); + return bRet; +} + +void CPDF_DataAvail::GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, + uint32_t* pSize) { + if (pPos) + *pPos = m_dwLastXRefOffset; + if (pSize) + *pSize = (uint32_t)(m_dwFileLen - m_dwLastXRefOffset); +} + +int CPDF_DataAvail::GetPageCount() const { + if (m_pLinearized) { + CPDF_Dictionary* pDict = m_pLinearized->GetDict(); + CPDF_Object* pObj = pDict ? pDict->GetDirectObjectFor("N") : nullptr; + return pObj ? pObj->GetInteger() : 0; + } + return m_pDocument ? m_pDocument->GetPageCount() : 0; +} + +CPDF_Dictionary* CPDF_DataAvail::GetPage(int index) { + if (!m_pDocument || index < 0 || index >= GetPageCount()) + return nullptr; + + if (m_pLinearized) { + CPDF_Dictionary* pDict = m_pLinearized->GetDict(); + CPDF_Object* pObj = pDict ? pDict->GetDirectObjectFor("P") : nullptr; + + int pageNum = pObj ? pObj->GetInteger() : 0; + if (m_pHintTables && index != pageNum) { + FX_FILESIZE szPageStartPos = 0; + FX_FILESIZE szPageLength = 0; + uint32_t dwObjNum = 0; + bool bPagePosGot = m_pHintTables->GetPagePos(index, &szPageStartPos, + &szPageLength, &dwObjNum); + if (!bPagePosGot) + return nullptr; + + m_syntaxParser.InitParser(m_pFileRead, (uint32_t)szPageStartPos); + CPDF_Object* pPageDict = ParseIndirectObjectAt(0, dwObjNum, m_pDocument); + if (!pPageDict) + return nullptr; + + if (!m_pDocument->ReplaceIndirectObjectIfHigherGeneration(dwObjNum, + pPageDict)) { + return nullptr; + } + return pPageDict->GetDict(); + } + } + return m_pDocument->GetPage(index); +} + +CPDF_DataAvail::DocFormStatus CPDF_DataAvail::IsFormAvail( + DownloadHints* pHints) { + if (!m_pDocument) + return FormAvailable; + + if (!m_bLinearizedFormParamLoad) { + CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); + if (!pRoot) + return FormAvailable; + + CPDF_Object* pAcroForm = pRoot->GetObjectFor("AcroForm"); + if (!pAcroForm) + return FormNotExist; + + DocAvailStatus nDocStatus = CheckLinearizedData(pHints); + if (nDocStatus == DataError) + return FormError; + if (nDocStatus == DataNotAvailable) + return FormNotAvailable; + + if (!m_objs_array.GetSize()) + m_objs_array.Add(pAcroForm->GetDict()); + m_bLinearizedFormParamLoad = TRUE; + } + + CFX_ArrayTemplate new_objs_array; + FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); + m_objs_array.RemoveAll(); + if (!bRet) { + m_objs_array.Append(new_objs_array); + return FormNotAvailable; + } + return FormAvailable; +} + +CPDF_DataAvail::PageNode::PageNode() : m_type(PDF_PAGENODE_UNKNOWN) {} + +CPDF_DataAvail::PageNode::~PageNode() { + for (int32_t i = 0; i < m_childNode.GetSize(); ++i) + delete m_childNode[i]; + m_childNode.RemoveAll(); +} diff --git a/core/fpdfapi/parser/cpdf_data_avail.h b/core/fpdfapi/parser/cpdf_data_avail.h new file mode 100644 index 0000000000..f4fb753d1d --- /dev/null +++ b/core/fpdfapi/parser/cpdf_data_avail.h @@ -0,0 +1,253 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_DATA_AVAIL_H_ +#define CORE_FPDFAPI_PARSER_CPDF_DATA_AVAIL_H_ + +#include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fpdfapi/parser/cpdf_syntax_parser.h" +#include "core/fxcrt/fx_basic.h" + +class CPDF_Dictionary; +class CPDF_HintTables; +class CPDF_IndirectObjectHolder; +class CPDF_Parser; + +enum PDF_DATAAVAIL_STATUS { + PDF_DATAAVAIL_HEADER = 0, + PDF_DATAAVAIL_FIRSTPAGE, + PDF_DATAAVAIL_FIRSTPAGE_PREPARE, + PDF_DATAAVAIL_HINTTABLE, + PDF_DATAAVAIL_END, + PDF_DATAAVAIL_CROSSREF, + PDF_DATAAVAIL_CROSSREF_ITEM, + PDF_DATAAVAIL_CROSSREF_STREAM, + PDF_DATAAVAIL_TRAILER, + PDF_DATAAVAIL_LOADALLCROSSREF, + 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 +}; + +enum PDF_PAGENODE_TYPE { + PDF_PAGENODE_UNKNOWN = 0, + PDF_PAGENODE_PAGE, + PDF_PAGENODE_PAGES, + PDF_PAGENODE_ARRAY, +}; + +class CPDF_DataAvail final { + public: + // Must match PDF_DATA_* definitions in public/fpdf_dataavail.h, but cannot + // #include that header. fpdfsdk/fpdf_dataavail.cpp has static_asserts + // to make sure the two sets of values match. + enum DocAvailStatus { + DataError = -1, // PDF_DATA_ERROR + DataNotAvailable = 0, // PDF_DATA_NOTAVAIL + DataAvailable = 1, // PDF_DATA_AVAIL + }; + + // Must match PDF_*LINEAR* definitions in public/fpdf_dataavail.h, but cannot + // #include that header. fpdfsdk/fpdf_dataavail.cpp has static_asserts + // to make sure the two sets of values match. + enum DocLinearizationStatus { + LinearizationUnknown = -1, // PDF_LINEARIZATION_UNKNOWN + NotLinearized = 0, // PDF_NOT_LINEARIZED + Linearized = 1, // PDF_LINEARIZED + }; + + // Must match PDF_FORM_* definitions in public/fpdf_dataavail.h, but cannot + // #include that header. fpdfsdk/fpdf_dataavail.cpp has static_asserts + // to make sure the two sets of values match. + enum DocFormStatus { + FormError = -1, // PDF_FORM_ERROR + FormNotAvailable = 0, // PDF_FORM_NOTAVAIL + FormAvailable = 1, // PDF_FORM_AVAIL + FormNotExist = 2, // PDF_FORM_NOTEXIST + }; + + class FileAvail { + public: + virtual ~FileAvail(); + virtual FX_BOOL IsDataAvail(FX_FILESIZE offset, uint32_t size) = 0; + }; + + class DownloadHints { + public: + virtual ~DownloadHints(); + virtual void AddSegment(FX_FILESIZE offset, uint32_t size) = 0; + }; + + CPDF_DataAvail(FileAvail* pFileAvail, + IFX_FileRead* pFileRead, + FX_BOOL bSupportHintTable); + ~CPDF_DataAvail(); + + DocAvailStatus IsDocAvail(DownloadHints* pHints); + void SetDocument(CPDF_Document* pDoc); + DocAvailStatus IsPageAvail(uint32_t dwPage, DownloadHints* pHints); + DocFormStatus IsFormAvail(DownloadHints* pHints); + DocLinearizationStatus IsLinearizedPDF(); + FX_BOOL IsLinearized(); + void GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, uint32_t* pSize); + IFX_FileRead* GetFileRead() const { return m_pFileRead; } + int GetPageCount() const; + CPDF_Dictionary* GetPage(int index); + + friend class CPDF_HintTables; + + protected: + class PageNode { + public: + PageNode(); + ~PageNode(); + + PDF_PAGENODE_TYPE m_type; + uint32_t m_dwPageNo; + CFX_ArrayTemplate m_childNode; + }; + + static const int kMaxDataAvailRecursionDepth = 64; + static int s_CurrentDataAvailRecursionDepth; + static const int kMaxPageRecursionDepth = 1024; + + uint32_t GetObjectSize(uint32_t objnum, FX_FILESIZE& offset); + FX_BOOL IsObjectsAvail(CFX_ArrayTemplate& obj_array, + FX_BOOL bParsePage, + DownloadHints* pHints, + CFX_ArrayTemplate& ret_array); + FX_BOOL CheckDocStatus(DownloadHints* pHints); + FX_BOOL CheckHeader(DownloadHints* pHints); + FX_BOOL CheckFirstPage(DownloadHints* pHints); + FX_BOOL CheckHintTables(DownloadHints* pHints); + FX_BOOL CheckEnd(DownloadHints* pHints); + FX_BOOL CheckCrossRef(DownloadHints* pHints); + FX_BOOL CheckCrossRefItem(DownloadHints* pHints); + FX_BOOL CheckTrailer(DownloadHints* pHints); + FX_BOOL CheckRoot(DownloadHints* pHints); + FX_BOOL CheckInfo(DownloadHints* pHints); + FX_BOOL CheckPages(DownloadHints* pHints); + FX_BOOL CheckPage(DownloadHints* pHints); + FX_BOOL CheckResources(DownloadHints* pHints); + FX_BOOL CheckAnnots(DownloadHints* pHints); + FX_BOOL CheckAcroForm(DownloadHints* pHints); + FX_BOOL CheckAcroFormSubObject(DownloadHints* pHints); + FX_BOOL CheckTrailerAppend(DownloadHints* pHints); + FX_BOOL CheckPageStatus(DownloadHints* pHints); + FX_BOOL CheckAllCrossRefStream(DownloadHints* pHints); + + int32_t CheckCrossRefStream(DownloadHints* pHints, FX_FILESIZE& xref_offset); + FX_BOOL IsLinearizedFile(uint8_t* pData, uint32_t dwLen); + void SetStartOffset(FX_FILESIZE dwOffset); + FX_BOOL GetNextToken(CFX_ByteString& token); + FX_BOOL GetNextChar(uint8_t& ch); + CPDF_Object* ParseIndirectObjectAt( + FX_FILESIZE pos, + uint32_t objnum, + CPDF_IndirectObjectHolder* pObjList = nullptr); + CPDF_Object* GetObject(uint32_t objnum, + DownloadHints* pHints, + FX_BOOL* pExistInFile); + FX_BOOL GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages); + FX_BOOL PreparePageItem(); + FX_BOOL LoadPages(DownloadHints* pHints); + FX_BOOL LoadAllXref(DownloadHints* pHints); + FX_BOOL LoadAllFile(DownloadHints* pHints); + DocAvailStatus CheckLinearizedData(DownloadHints* pHints); + FX_BOOL CheckPageAnnots(uint32_t dwPage, DownloadHints* pHints); + + DocAvailStatus CheckLinearizedFirstPage(uint32_t dwPage, + DownloadHints* pHints); + FX_BOOL HaveResourceAncestor(CPDF_Dictionary* pDict); + FX_BOOL CheckPage(uint32_t dwPage, DownloadHints* pHints); + FX_BOOL LoadDocPages(DownloadHints* pHints); + FX_BOOL LoadDocPage(uint32_t dwPage, DownloadHints* pHints); + FX_BOOL CheckPageNode(PageNode& pageNodes, + int32_t iPage, + int32_t& iCount, + DownloadHints* pHints, + int level); + FX_BOOL CheckUnkownPageNode(uint32_t dwPageNo, + PageNode* pPageNode, + DownloadHints* pHints); + FX_BOOL CheckArrayPageNode(uint32_t dwPageNo, + PageNode* pPageNode, + DownloadHints* pHints); + FX_BOOL CheckPageCount(DownloadHints* pHints); + bool IsFirstCheck(uint32_t dwPage); + void ResetFirstCheck(uint32_t dwPage); + FX_BOOL IsDataAvail(FX_FILESIZE offset, uint32_t size, DownloadHints* pHints); + + FileAvail* const m_pFileAvail; + IFX_FileRead* const m_pFileRead; + CPDF_Parser m_parser; + CPDF_SyntaxParser m_syntaxParser; + CPDF_Object* m_pRoot; + uint32_t m_dwRootObjNum; + uint32_t 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; + FX_FILESIZE m_dwFileLen; + CPDF_Document* m_pDocument; + std::set m_ObjectSet; + CFX_ArrayTemplate m_objs_array; + FX_FILESIZE m_Pos; + FX_FILESIZE m_bufferOffset; + uint32_t m_bufferSize; + CFX_ByteString m_WordBuf; + uint8_t m_bufferData[512]; + CFX_ArrayTemplate m_XRefStreamList; + CFX_ArrayTemplate m_PageObjList; + uint32_t m_PagesObjNum; + FX_BOOL m_bLinearized; + uint32_t m_dwFirstPageNo; + FX_BOOL m_bLinearedDataOK; + FX_BOOL m_bMainXRefLoadTried; + 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; + uint32_t m_dwAcroFormObjNum; + FX_BOOL m_bAcroFormLoad; + CPDF_Object* m_pAcroForm; + CFX_ArrayTemplate m_arrayAcroforms; + CPDF_Dictionary* m_pPageDict; + CPDF_Object* m_pPageResource; + FX_BOOL m_bNeedDownLoadResource; + FX_BOOL m_bPageLoadedOK; + FX_BOOL m_bLinearizedFormParamLoad; + CFX_ArrayTemplate m_PagesArray; + uint32_t m_dwEncryptObjNum; + FX_FILESIZE m_dwPrevXRefOffset; + FX_BOOL m_bTotalLoadPageTree; + FX_BOOL m_bCurPageDictLoadOK; + PageNode m_pageNodes; + std::set m_pageMapCheckState; + std::set m_pagesLoadState; + std::unique_ptr m_pHintTables; + FX_BOOL m_bSupportHintTable; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_DATA_AVAIL_H_ diff --git a/core/fpdfapi/parser/cpdf_dictionary.cpp b/core/fpdfapi/parser/cpdf_dictionary.cpp new file mode 100644 index 0000000000..7601c5b831 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_dictionary.cpp @@ -0,0 +1,275 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_dictionary.h" + +#include +#include + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_boolean.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "third_party/base/logging.h" +#include "third_party/base/stl_util.h" + +CPDF_Dictionary::CPDF_Dictionary() + : CPDF_Dictionary(CFX_WeakPtr()) {} + +CPDF_Dictionary::CPDF_Dictionary(const CFX_WeakPtr& pPool) + : m_pPool(pPool) {} + +CPDF_Dictionary::~CPDF_Dictionary() { + // Mark the object as deleted so that it will not be deleted again + // in case of cyclic references. + m_ObjNum = kInvalidObjNum; + for (const auto& it : m_Map) { + if (it.second) + it.second->Release(); + } +} + +CPDF_Object::Type CPDF_Dictionary::GetType() const { + return DICTIONARY; +} + +CPDF_Dictionary* CPDF_Dictionary::GetDict() const { + // The method should be made non-const if we want to not be const. + // See bug #234. + return const_cast(this); +} + +bool CPDF_Dictionary::IsDictionary() const { + return true; +} + +CPDF_Dictionary* CPDF_Dictionary::AsDictionary() { + return this; +} + +const CPDF_Dictionary* CPDF_Dictionary::AsDictionary() const { + return this; +} + +CPDF_Object* CPDF_Dictionary::Clone() const { + return CloneObjectNonCyclic(false); +} + +CPDF_Object* CPDF_Dictionary::CloneNonCyclic( + bool bDirect, + std::set* pVisited) const { + pVisited->insert(this); + CPDF_Dictionary* pCopy = new CPDF_Dictionary(m_pPool); + for (const auto& it : *this) { + CPDF_Object* value = it.second; + if (!pdfium::ContainsKey(*pVisited, value)) { + pCopy->m_Map.insert( + std::make_pair(it.first, value->CloneNonCyclic(bDirect, pVisited))); + } + } + return pCopy; +} + +CPDF_Object* CPDF_Dictionary::GetObjectFor(const CFX_ByteString& key) const { + auto it = m_Map.find(key); + return it != m_Map.end() ? it->second : nullptr; +} + +CPDF_Object* CPDF_Dictionary::GetDirectObjectFor( + const CFX_ByteString& key) const { + CPDF_Object* p = GetObjectFor(key); + return p ? p->GetDirect() : nullptr; +} + +CFX_ByteString CPDF_Dictionary::GetStringFor(const CFX_ByteString& key) const { + CPDF_Object* p = GetObjectFor(key); + return p ? p->GetString() : CFX_ByteString(); +} + +CFX_WideString CPDF_Dictionary::GetUnicodeTextFor( + const CFX_ByteString& key) const { + CPDF_Object* p = GetObjectFor(key); + if (CPDF_Reference* pRef = ToReference(p)) + p = pRef->GetDirect(); + return p ? p->GetUnicodeText() : CFX_WideString(); +} + +CFX_ByteString CPDF_Dictionary::GetStringFor(const CFX_ByteString& key, + const CFX_ByteString& def) const { + CPDF_Object* p = GetObjectFor(key); + return p ? p->GetString() : CFX_ByteString(def); +} + +int CPDF_Dictionary::GetIntegerFor(const CFX_ByteString& key) const { + CPDF_Object* p = GetObjectFor(key); + return p ? p->GetInteger() : 0; +} + +int CPDF_Dictionary::GetIntegerFor(const CFX_ByteString& key, int def) const { + CPDF_Object* p = GetObjectFor(key); + return p ? p->GetInteger() : def; +} + +FX_FLOAT CPDF_Dictionary::GetNumberFor(const CFX_ByteString& key) const { + CPDF_Object* p = GetObjectFor(key); + return p ? p->GetNumber() : 0; +} + +bool CPDF_Dictionary::GetBooleanFor(const CFX_ByteString& key, + bool bDefault) const { + CPDF_Object* p = GetObjectFor(key); + return ToBoolean(p) ? p->GetInteger() != 0 : bDefault; +} + +CPDF_Dictionary* CPDF_Dictionary::GetDictFor(const CFX_ByteString& key) const { + CPDF_Object* p = GetDirectObjectFor(key); + if (!p) + return nullptr; + if (CPDF_Dictionary* pDict = p->AsDictionary()) + return pDict; + if (CPDF_Stream* pStream = p->AsStream()) + return pStream->GetDict(); + return nullptr; +} + +CPDF_Array* CPDF_Dictionary::GetArrayFor(const CFX_ByteString& key) const { + return ToArray(GetDirectObjectFor(key)); +} + +CPDF_Stream* CPDF_Dictionary::GetStreamFor(const CFX_ByteString& key) const { + return ToStream(GetDirectObjectFor(key)); +} + +CFX_FloatRect CPDF_Dictionary::GetRectFor(const CFX_ByteString& key) const { + CFX_FloatRect rect; + CPDF_Array* pArray = GetArrayFor(key); + if (pArray) + rect = pArray->GetRect(); + return rect; +} + +CFX_Matrix CPDF_Dictionary::GetMatrixFor(const CFX_ByteString& key) const { + CFX_Matrix matrix; + CPDF_Array* pArray = GetArrayFor(key); + if (pArray) + matrix = pArray->GetMatrix(); + return matrix; +} + +FX_BOOL CPDF_Dictionary::KeyExist(const CFX_ByteString& key) const { + return pdfium::ContainsKey(m_Map, key); +} + +bool CPDF_Dictionary::IsSignatureDict() const { + CPDF_Object* pType = GetDirectObjectFor("Type"); + if (!pType) + pType = GetDirectObjectFor("FT"); + return pType && pType->GetString() == "Sig"; +} + +void CPDF_Dictionary::SetFor(const CFX_ByteString& key, CPDF_Object* pObj) { + CHECK(!pObj || pObj->GetObjNum() == 0); + auto it = m_Map.find(key); + if (it == m_Map.end()) { + if (pObj) + m_Map.insert(std::make_pair(MaybeIntern(key), pObj)); + return; + } + + if (it->second == pObj) + return; + it->second->Release(); + + if (pObj) + it->second = pObj; + else + m_Map.erase(it); +} + +void CPDF_Dictionary::RemoveFor(const CFX_ByteString& key) { + auto it = m_Map.find(key); + if (it == m_Map.end()) + return; + + it->second->Release(); + m_Map.erase(it); +} + +void CPDF_Dictionary::ReplaceKey(const CFX_ByteString& oldkey, + const CFX_ByteString& newkey) { + auto old_it = m_Map.find(oldkey); + if (old_it == m_Map.end()) + return; + + auto new_it = m_Map.find(newkey); + if (new_it == old_it) + return; + + if (new_it != m_Map.end()) { + new_it->second->Release(); + new_it->second = old_it->second; + } else { + m_Map.insert(std::make_pair(MaybeIntern(newkey), old_it->second)); + } + m_Map.erase(old_it); +} + +void CPDF_Dictionary::SetIntegerFor(const CFX_ByteString& key, int i) { + SetFor(key, new CPDF_Number(i)); +} + +void CPDF_Dictionary::SetNameFor(const CFX_ByteString& key, + const CFX_ByteString& name) { + SetFor(key, new CPDF_Name(MaybeIntern(name))); +} + +void CPDF_Dictionary::SetStringFor(const CFX_ByteString& key, + const CFX_ByteString& str) { + SetFor(key, new CPDF_String(MaybeIntern(str), FALSE)); +} + +void CPDF_Dictionary::SetReferenceFor(const CFX_ByteString& key, + CPDF_IndirectObjectHolder* pDoc, + uint32_t objnum) { + SetFor(key, new CPDF_Reference(pDoc, objnum)); +} + +void CPDF_Dictionary::SetNumberFor(const CFX_ByteString& key, FX_FLOAT f) { + SetFor(key, new CPDF_Number(f)); +} + +void CPDF_Dictionary::SetBooleanFor(const CFX_ByteString& key, bool bValue) { + SetFor(key, new CPDF_Boolean(bValue)); +} + +void CPDF_Dictionary::SetRectFor(const CFX_ByteString& key, + const CFX_FloatRect& rect) { + CPDF_Array* pArray = new CPDF_Array; + pArray->AddNumber(rect.left); + pArray->AddNumber(rect.bottom); + pArray->AddNumber(rect.right); + pArray->AddNumber(rect.top); + SetFor(key, pArray); +} + +void CPDF_Dictionary::SetMatrixFor(const CFX_ByteString& key, + const CFX_Matrix& matrix) { + CPDF_Array* pArray = new CPDF_Array; + pArray->AddNumber(matrix.a); + pArray->AddNumber(matrix.b); + pArray->AddNumber(matrix.c); + pArray->AddNumber(matrix.d); + pArray->AddNumber(matrix.e); + pArray->AddNumber(matrix.f); + SetFor(key, pArray); +} + +CFX_ByteString CPDF_Dictionary::MaybeIntern(const CFX_ByteString& str) { + return m_pPool ? m_pPool->Intern(str) : str; +} diff --git a/core/fpdfapi/parser/cpdf_dictionary.h b/core/fpdfapi/parser/cpdf_dictionary.h new file mode 100644 index 0000000000..2da4409b71 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_dictionary.h @@ -0,0 +1,98 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_DICTIONARY_H_ +#define CORE_FPDFAPI_PARSER_CPDF_DICTIONARY_H_ + +#include +#include + +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/cfx_string_pool_template.h" +#include "core/fxcrt/cfx_weak_ptr.h" +#include "core/fxcrt/fx_coordinates.h" +#include "core/fxcrt/fx_string.h" + +class CPDF_IndirectObjectHolder; + +class CPDF_Dictionary : public CPDF_Object { + public: + using iterator = std::map::iterator; + using const_iterator = std::map::const_iterator; + + CPDF_Dictionary(); + explicit CPDF_Dictionary(const CFX_WeakPtr& pPool); + + // CPDF_Object. + Type GetType() const override; + CPDF_Object* Clone() const override; + CPDF_Dictionary* GetDict() const override; + bool IsDictionary() const override; + CPDF_Dictionary* AsDictionary() override; + const CPDF_Dictionary* AsDictionary() const override; + + size_t GetCount() const { return m_Map.size(); } + CPDF_Object* GetObjectFor(const CFX_ByteString& key) const; + CPDF_Object* GetDirectObjectFor(const CFX_ByteString& key) const; + CFX_ByteString GetStringFor(const CFX_ByteString& key) const; + CFX_ByteString GetStringFor(const CFX_ByteString& key, + const CFX_ByteString& default_str) const; + CFX_WideString GetUnicodeTextFor(const CFX_ByteString& key) const; + int GetIntegerFor(const CFX_ByteString& key) const; + int GetIntegerFor(const CFX_ByteString& key, int default_int) const; + bool GetBooleanFor(const CFX_ByteString& key, bool bDefault = false) const; + FX_FLOAT GetNumberFor(const CFX_ByteString& key) const; + CPDF_Dictionary* GetDictFor(const CFX_ByteString& key) const; + CPDF_Stream* GetStreamFor(const CFX_ByteString& key) const; + CPDF_Array* GetArrayFor(const CFX_ByteString& key) const; + CFX_FloatRect GetRectFor(const CFX_ByteString& key) const; + CFX_Matrix GetMatrixFor(const CFX_ByteString& key) const; + FX_FLOAT GetFloatFor(const CFX_ByteString& key) const { + return GetNumberFor(key); + } + + FX_BOOL KeyExist(const CFX_ByteString& key) const; + bool IsSignatureDict() const; + + // Set* functions invalidate iterators for the element with the key |key|. + void SetFor(const CFX_ByteString& key, CPDF_Object* pObj); + void SetNameFor(const CFX_ByteString& key, const CFX_ByteString& name); + void SetStringFor(const CFX_ByteString& key, const CFX_ByteString& str); + void SetIntegerFor(const CFX_ByteString& key, int i); + void SetNumberFor(const CFX_ByteString& key, FX_FLOAT f); + void SetReferenceFor(const CFX_ByteString& key, + CPDF_IndirectObjectHolder* pDoc, + uint32_t objnum); + void SetRectFor(const CFX_ByteString& key, const CFX_FloatRect& rect); + void SetMatrixFor(const CFX_ByteString& key, const CFX_Matrix& matrix); + void SetBooleanFor(const CFX_ByteString& key, bool bValue); + + // Invalidates iterators for the element with the key |key|. + void RemoveFor(const CFX_ByteString& key); + + // Invalidates iterators for the element with the key |oldkey|. + void ReplaceKey(const CFX_ByteString& oldkey, const CFX_ByteString& newkey); + + 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(); } + + CFX_WeakPtr GetByteStringPool() const { return m_pPool; } + + protected: + ~CPDF_Dictionary() override; + + CFX_ByteString MaybeIntern(const CFX_ByteString& str); + CPDF_Object* CloneNonCyclic( + bool bDirect, + std::set* visited) const override; + + CFX_WeakPtr m_pPool; + std::map m_Map; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_DICTIONARY_H_ diff --git a/core/fpdfapi/parser/cpdf_document.cpp b/core/fpdfapi/parser/cpdf_document.cpp new file mode 100644 index 0000000000..bf6439cc8c --- /dev/null +++ b/core/fpdfapi/parser/cpdf_document.cpp @@ -0,0 +1,1020 @@ +// 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 + +#include "core/fpdfapi/parser/cpdf_document.h" + +#include +#include +#include + +#include "core/fpdfapi/cpdf_modulemgr.h" +#include "core/fpdfapi/font/cpdf_fontencoding.h" +#include "core/fpdfapi/fpdf_render/render_int.h" +#include "core/fpdfapi/page/cpdf_pagemodule.h" +#include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fxcodec/JBig2_DocumentContext.h" +#include "core/fxge/cfx_unicodeencoding.h" +#include "core/fxge/fx_font.h" +#include "third_party/base/ptr_util.h" +#include "third_party/base/stl_util.h" + +namespace { + +const int FX_MAX_PAGE_LEVEL = 1024; + +const uint16_t g_FX_CP874Unicodes[128] = { + 0x20AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x2026, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2018, + 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00A0, 0x0E01, 0x0E02, 0x0E03, + 0x0E04, 0x0E05, 0x0E06, 0x0E07, 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, + 0x0E0D, 0x0E0E, 0x0E0F, 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, + 0x0E16, 0x0E17, 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, + 0x0E1F, 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, 0x0E30, + 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, 0x0E38, 0x0E39, + 0x0E3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E3F, 0x0E40, 0x0E41, 0x0E42, + 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, + 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, + 0x0E55, 0x0E56, 0x0E57, 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0000, 0x0000, + 0x0000, 0x0000, +}; +const uint16_t g_FX_CP1250Unicodes[128] = { + 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, 0x0000, + 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, 0x0000, 0x2018, + 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0161, + 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, 0x00A0, 0x02C7, 0x02D8, 0x0141, + 0x00A4, 0x0104, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, + 0x00AD, 0x00AE, 0x017B, 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, + 0x00B6, 0x00B7, 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, + 0x017C, 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, 0x0110, + 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, 0x0158, 0x016E, + 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, 0x0155, 0x00E1, 0x00E2, + 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, 0x010D, 0x00E9, 0x0119, 0x00EB, + 0x011B, 0x00ED, 0x00EE, 0x010F, 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, + 0x0151, 0x00F6, 0x00F7, 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, + 0x0163, 0x02D9, +}; +const uint16_t g_FX_CP1251Unicodes[128] = { + 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, 0x20AC, + 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, 0x0452, 0x2018, + 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0459, + 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, 0x00A0, 0x040E, 0x045E, 0x0408, + 0x00A4, 0x0490, 0x00A6, 0x00A7, 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, + 0x00AD, 0x00AE, 0x0407, 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, + 0x00B6, 0x00B7, 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, + 0x0457, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, + 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, + 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, + 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, + 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, + 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, + 0x044E, 0x044F, +}; +const uint16_t g_FX_CP1253Unicodes[128] = { + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x0000, + 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2018, + 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0000, + 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, 0x00A0, 0x0385, 0x0386, 0x00A3, + 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, + 0x00AD, 0x00AE, 0x2015, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, + 0x00B6, 0x00B7, 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, + 0x038F, 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, + 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, + 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, 0x03B0, 0x03B1, 0x03B2, + 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, + 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, + 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, + 0x03CE, 0x0000, +}; +const uint16_t g_FX_CP1254Unicodes[128] = { + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, + 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000, 0x0000, 0x2018, + 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, + 0x203A, 0x0153, 0x0000, 0x0000, 0x0178, 0x00A0, 0x00A1, 0x00A2, 0x00A3, + 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, + 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, + 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, + 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x011E, + 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, + 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, 0x00E0, 0x00E1, 0x00E2, + 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, + 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, + 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, + 0x015F, 0x00FF, +}; +const uint16_t g_FX_CP1255Unicodes[128] = { + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, + 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2018, + 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0000, + 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, 0x00A0, 0x00A1, 0x00A2, 0x00A3, + 0x20AA, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, + 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, + 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, + 0x00BF, 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, + 0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, 0x05C0, + 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x05D0, 0x05D1, 0x05D2, + 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, + 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, + 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, + 0x200F, 0x0000, +}; +const uint16_t g_FX_CP1256Unicodes[128] = { + 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, + 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, 0x06AF, 0x2018, + 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x06A9, 0x2122, 0x0691, + 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, 0x00A0, 0x060C, 0x00A2, 0x00A3, + 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, + 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, + 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, + 0x061F, 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, + 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, 0x0637, 0x0638, + 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643, 0x00E0, 0x0644, 0x00E2, + 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, + 0x0649, 0x064A, 0x00EE, 0x00EF, 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, + 0x064F, 0x0650, 0x00F7, 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, + 0x200F, 0x06D2, +}; +const uint16_t g_FX_CP1257Unicodes[128] = { + 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, 0x0000, + 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8, 0x0000, 0x2018, + 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0000, + 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000, 0x00A0, 0x0000, 0x00A2, 0x00A3, + 0x00A4, 0x0000, 0x00A6, 0x00A7, 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, + 0x00AD, 0x00AE, 0x00C6, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, + 0x00B6, 0x00B7, 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, + 0x00E6, 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, 0x0160, + 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, 0x0172, 0x0141, + 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, 0x0105, 0x012F, 0x0101, + 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, 0x010D, 0x00E9, 0x017A, 0x0117, + 0x0123, 0x0137, 0x012B, 0x013C, 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, + 0x00F5, 0x00F6, 0x00F7, 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, + 0x017E, 0x02D9, +}; + +struct FX_CharsetUnicodes { + uint8_t m_Charset; + const uint16_t* m_pUnicodes; +}; + +const FX_CharsetUnicodes g_FX_CharsetUnicodes[] = { + {FXFONT_THAI_CHARSET, g_FX_CP874Unicodes}, + {FXFONT_EASTEUROPE_CHARSET, g_FX_CP1250Unicodes}, + {FXFONT_RUSSIAN_CHARSET, g_FX_CP1251Unicodes}, + {FXFONT_GREEK_CHARSET, g_FX_CP1253Unicodes}, + {FXFONT_TURKISH_CHARSET, g_FX_CP1254Unicodes}, + {FXFONT_HEBREW_CHARSET, g_FX_CP1255Unicodes}, + {FXFONT_ARABIC_CHARSET, g_FX_CP1256Unicodes}, + {FXFONT_BALTIC_CHARSET, g_FX_CP1257Unicodes}, +}; + +void InsertWidthArrayImpl(int* widths, int size, CPDF_Array* pWidthArray) { + int i; + for (i = 1; i < size; i++) { + if (widths[i] != *widths) + break; + } + if (i == size) { + int first = pWidthArray->GetIntegerAt(pWidthArray->GetCount() - 1); + pWidthArray->AddInteger(first + size - 1); + pWidthArray->AddInteger(*widths); + } else { + CPDF_Array* pWidthArray1 = new CPDF_Array; + pWidthArray->Add(pWidthArray1); + for (i = 0; i < size; i++) + pWidthArray1->AddInteger(widths[i]); + } + FX_Free(widths); +} + +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ +void InsertWidthArray(HDC hDC, int start, int end, CPDF_Array* pWidthArray) { + int size = end - start + 1; + int* widths = FX_Alloc(int, size); + GetCharWidth(hDC, start, end, widths); + InsertWidthArrayImpl(widths, size, pWidthArray); +} + +CFX_ByteString FPDF_GetPSNameFromTT(HDC hDC) { + CFX_ByteString result; + DWORD size = ::GetFontData(hDC, 'eman', 0, nullptr, 0); + if (size != GDI_ERROR) { + LPBYTE buffer = FX_Alloc(BYTE, size); + ::GetFontData(hDC, 'eman', 0, buffer, size); + result = GetNameFromTT(buffer, size, 6); + FX_Free(buffer); + } + return result; +} +#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + +void InsertWidthArray1(CFX_Font* pFont, + CFX_UnicodeEncoding* pEncoding, + FX_WCHAR start, + FX_WCHAR end, + CPDF_Array* pWidthArray) { + int size = end - start + 1; + int* widths = FX_Alloc(int, size); + int i; + for (i = 0; i < size; i++) { + int glyph_index = pEncoding->GlyphFromCharCode(start + i); + widths[i] = pFont->GetGlyphWidth(glyph_index); + } + InsertWidthArrayImpl(widths, size, pWidthArray); +} + +int InsertDeletePDFPage(CPDF_Document* pDoc, + CPDF_Dictionary* pPages, + int nPagesToGo, + CPDF_Dictionary* pPage, + FX_BOOL bInsert, + std::set* pVisited) { + CPDF_Array* pKidList = pPages->GetArrayFor("Kids"); + if (!pKidList) + return -1; + + for (size_t i = 0; i < pKidList->GetCount(); i++) { + CPDF_Dictionary* pKid = pKidList->GetDictAt(i); + if (pKid->GetStringFor("Type") == "Page") { + if (nPagesToGo == 0) { + if (bInsert) { + pKidList->InsertAt(i, new CPDF_Reference(pDoc, pPage->GetObjNum())); + pPage->SetReferenceFor("Parent", pDoc, pPages->GetObjNum()); + } else { + pKidList->RemoveAt(i); + } + pPages->SetIntegerFor( + "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1)); + return 1; + } + nPagesToGo--; + } else { + int nPages = pKid->GetIntegerFor("Count"); + if (nPagesToGo < nPages) { + if (pdfium::ContainsKey(*pVisited, pKid)) + return -1; + + pdfium::ScopedSetInsertion insertion(pVisited, pKid); + if (InsertDeletePDFPage(pDoc, pKid, nPagesToGo, pPage, bInsert, + pVisited) < 0) { + return -1; + } + pPages->SetIntegerFor( + "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1)); + return 1; + } + nPagesToGo -= nPages; + } + } + return 0; +} + +int InsertNewPage(CPDF_Document* pDoc, + int iPage, + CPDF_Dictionary* pPageDict, + CFX_ArrayTemplate& pageList) { + CPDF_Dictionary* pRoot = pDoc->GetRoot(); + CPDF_Dictionary* pPages = pRoot ? pRoot->GetDictFor("Pages") : nullptr; + if (!pPages) + return -1; + + int nPages = pDoc->GetPageCount(); + if (iPage < 0 || iPage > nPages) + return -1; + + if (iPage == nPages) { + CPDF_Array* pPagesList = pPages->GetArrayFor("Kids"); + if (!pPagesList) { + pPagesList = new CPDF_Array; + pPages->SetFor("Kids", pPagesList); + } + pPagesList->Add(new CPDF_Reference(pDoc, pPageDict->GetObjNum())); + pPages->SetIntegerFor("Count", nPages + 1); + pPageDict->SetReferenceFor("Parent", pDoc, pPages->GetObjNum()); + } else { + std::set stack = {pPages}; + if (InsertDeletePDFPage(pDoc, pPages, iPage, pPageDict, TRUE, &stack) < 0) + return -1; + } + pageList.InsertAt(iPage, pPageDict->GetObjNum()); + return iPage; +} + +int CountPages(CPDF_Dictionary* pPages, + std::set* visited_pages) { + int count = pPages->GetIntegerFor("Count"); + if (count > 0 && count < FPDF_PAGE_MAX_NUM) + return count; + CPDF_Array* pKidList = pPages->GetArrayFor("Kids"); + if (!pKidList) + return 0; + count = 0; + for (size_t i = 0; i < pKidList->GetCount(); i++) { + CPDF_Dictionary* pKid = pKidList->GetDictAt(i); + if (!pKid || pdfium::ContainsKey(*visited_pages, pKid)) + continue; + if (pKid->KeyExist("Kids")) { + // Use |visited_pages| to help detect circular references of pages. + pdfium::ScopedSetInsertion local_add(visited_pages, + pKid); + count += CountPages(pKid, visited_pages); + } else { + // This page is a leaf node. + count++; + } + } + pPages->SetIntegerFor("Count", count); + return count; +} + +int CalculateFlags(bool bold, + bool italic, + bool fixedPitch, + bool serif, + bool script, + bool symbolic) { + int flags = 0; + if (bold) + flags |= PDFFONT_FORCEBOLD; + if (italic) + flags |= PDFFONT_ITALIC; + if (fixedPitch) + flags |= PDFFONT_FIXEDPITCH; + if (serif) + flags |= PDFFONT_SERIF; + if (script) + flags |= PDFFONT_SCRIPT; + if (symbolic) + flags |= PDFFONT_SYMBOLIC; + else + flags |= PDFFONT_NONSYMBOLIC; + return flags; +} + +void ProcessNonbCJK(CPDF_Dictionary* pBaseDict, + bool bold, + bool italic, + CFX_ByteString basefont, + CPDF_Array* pWidths) { + if (bold && italic) + basefont += ",BoldItalic"; + else if (bold) + basefont += ",Bold"; + else if (italic) + basefont += ",Italic"; + pBaseDict->SetNameFor("Subtype", "TrueType"); + pBaseDict->SetNameFor("BaseFont", basefont); + pBaseDict->SetNumberFor("FirstChar", 32); + pBaseDict->SetNumberFor("LastChar", 255); + pBaseDict->SetFor("Widths", pWidths); +} + +CPDF_Dictionary* CalculateFontDesc(CPDF_Document* pDoc, + CFX_ByteString basefont, + int flags, + int italicangle, + int ascend, + int descend, + CPDF_Array* bbox, + int32_t stemV) { + CPDF_Dictionary* pFontDesc = new CPDF_Dictionary(pDoc->GetByteStringPool()); + pFontDesc->SetNameFor("Type", "FontDescriptor"); + pFontDesc->SetNameFor("FontName", basefont); + pFontDesc->SetIntegerFor("Flags", flags); + pFontDesc->SetFor("FontBBox", bbox); + pFontDesc->SetIntegerFor("ItalicAngle", italicangle); + pFontDesc->SetIntegerFor("Ascent", ascend); + pFontDesc->SetIntegerFor("Descent", descend); + pFontDesc->SetIntegerFor("StemV", stemV); + return pFontDesc; +} + +} // namespace + +CPDF_Document::CPDF_Document(std::unique_ptr pParser) + : CPDF_IndirectObjectHolder(), + m_pParser(std::move(pParser)), + m_pRootDict(nullptr), + m_pInfoDict(nullptr), + m_bLinearized(false), + m_iFirstPageNo(0), + m_dwFirstPageObjNum(0), + m_pDocPage(new CPDF_DocPageData(this)), + m_pDocRender(new CPDF_DocRenderData(this)), + m_pByteStringPool(pdfium::MakeUnique()) { + if (pParser) + SetLastObjNum(m_pParser->GetLastObjNum()); +} + +CPDF_Document::~CPDF_Document() { + delete m_pDocPage; + CPDF_ModuleMgr::Get()->GetPageModule()->ClearStockFont(this); + m_pByteStringPool.DeleteObject(); // Make weak. +} + +CPDF_Object* CPDF_Document::ParseIndirectObject(uint32_t objnum) { + return m_pParser ? m_pParser->ParseIndirectObject(this, objnum) : nullptr; +} + +void CPDF_Document::LoadDocInternal() { + SetLastObjNum(m_pParser->GetLastObjNum()); + + CPDF_Object* pRootObj = GetOrParseIndirectObject(m_pParser->GetRootObjNum()); + if (!pRootObj) + return; + + m_pRootDict = pRootObj->GetDict(); + if (!m_pRootDict) + return; + + CPDF_Object* pInfoObj = GetOrParseIndirectObject(m_pParser->GetInfoObjNum()); + if (pInfoObj) + m_pInfoDict = pInfoObj->GetDict(); +} + +void CPDF_Document::LoadDoc() { + LoadDocInternal(); + m_PageList.SetSize(RetrievePageCount()); +} + +void CPDF_Document::LoadLinearizedDoc(CPDF_Dictionary* pLinearizationParams) { + m_bLinearized = true; + LoadDocInternal(); + + uint32_t dwPageCount = 0; + CPDF_Object* pCount = pLinearizationParams->GetObjectFor("N"); + if (ToNumber(pCount)) + dwPageCount = pCount->GetInteger(); + m_PageList.SetSize(dwPageCount); + + CPDF_Object* pNo = pLinearizationParams->GetObjectFor("P"); + if (ToNumber(pNo)) + m_iFirstPageNo = pNo->GetInteger(); + + CPDF_Object* pObjNum = pLinearizationParams->GetObjectFor("O"); + if (ToNumber(pObjNum)) + m_dwFirstPageObjNum = pObjNum->GetInteger(); +} + +void CPDF_Document::LoadPages() { + m_PageList.SetSize(RetrievePageCount()); +} + +CPDF_Dictionary* CPDF_Document::FindPDFPage(CPDF_Dictionary* pPages, + int iPage, + int nPagesToGo, + int level) { + CPDF_Array* pKidList = pPages->GetArrayFor("Kids"); + if (!pKidList) + return nPagesToGo == 0 ? pPages : nullptr; + + if (level >= FX_MAX_PAGE_LEVEL) + return nullptr; + + for (size_t i = 0; i < pKidList->GetCount(); i++) { + CPDF_Dictionary* pKid = pKidList->GetDictAt(i); + if (!pKid) { + nPagesToGo--; + continue; + } + if (pKid == pPages) + continue; + if (!pKid->KeyExist("Kids")) { + if (nPagesToGo == 0) + return pKid; + + m_PageList.SetAt(iPage - nPagesToGo, pKid->GetObjNum()); + nPagesToGo--; + } else { + int nPages = pKid->GetIntegerFor("Count"); + if (nPagesToGo < nPages) + return FindPDFPage(pKid, iPage, nPagesToGo, level + 1); + + nPagesToGo -= nPages; + } + } + return nullptr; +} + +CPDF_Dictionary* CPDF_Document::GetPagesDict() const { + CPDF_Dictionary* pRoot = GetRoot(); + return pRoot ? pRoot->GetDictFor("Pages") : nullptr; +} + +bool CPDF_Document::IsPageLoaded(int iPage) const { + return !!m_PageList.GetAt(iPage); +} + +CPDF_Dictionary* CPDF_Document::GetPage(int iPage) { + if (iPage < 0 || iPage >= m_PageList.GetSize()) + return nullptr; + + if (m_bLinearized && (iPage == m_iFirstPageNo)) { + if (CPDF_Dictionary* pDict = + ToDictionary(GetOrParseIndirectObject(m_dwFirstPageObjNum))) { + return pDict; + } + } + + int objnum = m_PageList.GetAt(iPage); + if (objnum) { + if (CPDF_Dictionary* pDict = ToDictionary(GetOrParseIndirectObject(objnum))) + return pDict; + } + + CPDF_Dictionary* pPages = GetPagesDict(); + if (!pPages) + return nullptr; + + CPDF_Dictionary* pPage = FindPDFPage(pPages, iPage, iPage, 0); + if (!pPage) + return nullptr; + + m_PageList.SetAt(iPage, pPage->GetObjNum()); + return pPage; +} + +void CPDF_Document::SetPageObjNum(int iPage, uint32_t objNum) { + m_PageList.SetAt(iPage, objNum); +} + +int CPDF_Document::FindPageIndex(CPDF_Dictionary* pNode, + uint32_t& skip_count, + uint32_t objnum, + int& index, + int level) { + if (!pNode->KeyExist("Kids")) { + if (objnum == pNode->GetObjNum()) + return index; + + if (skip_count) + skip_count--; + + index++; + return -1; + } + + CPDF_Array* pKidList = pNode->GetArrayFor("Kids"); + if (!pKidList) + return -1; + + if (level >= FX_MAX_PAGE_LEVEL) + return -1; + + size_t count = pNode->GetIntegerFor("Count"); + if (count <= skip_count) { + skip_count -= count; + index += count; + return -1; + } + + if (count && count == pKidList->GetCount()) { + for (size_t i = 0; i < count; i++) { + if (CPDF_Reference* pKid = ToReference(pKidList->GetObjectAt(i))) { + if (pKid->GetRefObjNum() == objnum) { + m_PageList.SetAt(index + i, objnum); + return static_cast(index + i); + } + } + } + } + + for (size_t i = 0; i < pKidList->GetCount(); i++) { + CPDF_Dictionary* pKid = pKidList->GetDictAt(i); + if (!pKid || pKid == pNode) + continue; + + int found_index = FindPageIndex(pKid, skip_count, objnum, index, level + 1); + if (found_index >= 0) + return found_index; + } + return -1; +} + +int CPDF_Document::GetPageIndex(uint32_t objnum) { + uint32_t nPages = m_PageList.GetSize(); + uint32_t skip_count = 0; + bool bSkipped = false; + for (uint32_t i = 0; i < nPages; i++) { + uint32_t objnum1 = m_PageList.GetAt(i); + if (objnum1 == objnum) + return i; + + if (!bSkipped && objnum1 == 0) { + skip_count = i; + bSkipped = true; + } + } + CPDF_Dictionary* pPages = GetPagesDict(); + if (!pPages) + return -1; + + int index = 0; + return FindPageIndex(pPages, skip_count, objnum, index); +} + +int CPDF_Document::GetPageCount() const { + return m_PageList.GetSize(); +} + +int CPDF_Document::RetrievePageCount() const { + CPDF_Dictionary* pPages = GetPagesDict(); + if (!pPages) + return 0; + + if (!pPages->KeyExist("Kids")) + return 1; + + std::set visited_pages; + visited_pages.insert(pPages); + return CountPages(pPages, &visited_pages); +} + +uint32_t CPDF_Document::GetUserPermissions() const { + // https://bugs.chromium.org/p/pdfium/issues/detail?id=499 + if (!m_pParser) { +#ifndef PDF_ENABLE_XFA + return 0; +#else // PDF_ENABLE_XFA + return 0xFFFFFFFF; +#endif + } + return m_pParser->GetPermissions(); +} + +CPDF_Font* CPDF_Document::LoadFont(CPDF_Dictionary* pFontDict) { + ASSERT(pFontDict); + return m_pDocPage->GetFont(pFontDict, FALSE); +} + +CPDF_StreamAcc* CPDF_Document::LoadFontFile(CPDF_Stream* pStream) { + return m_pDocPage->GetFontFileStreamAcc(pStream); +} + +CPDF_ColorSpace* CPDF_Document::LoadColorSpace(CPDF_Object* pCSObj, + CPDF_Dictionary* pResources) { + return m_pDocPage->GetColorSpace(pCSObj, pResources); +} + +CPDF_Pattern* CPDF_Document::LoadPattern(CPDF_Object* pPatternObj, + FX_BOOL bShading, + const CFX_Matrix& matrix) { + return m_pDocPage->GetPattern(pPatternObj, bShading, matrix); +} + +CPDF_IccProfile* CPDF_Document::LoadIccProfile(CPDF_Stream* pStream) { + return m_pDocPage->GetIccProfile(pStream); +} + +CPDF_Image* CPDF_Document::LoadImageF(CPDF_Object* pObj) { + if (!pObj) + return nullptr; + + ASSERT(pObj->GetObjNum()); + return m_pDocPage->GetImage(pObj); +} + +void CPDF_Document::CreateNewDoc() { + ASSERT(!m_pRootDict && !m_pInfoDict); + m_pRootDict = new CPDF_Dictionary(m_pByteStringPool); + m_pRootDict->SetNameFor("Type", "Catalog"); + AddIndirectObject(m_pRootDict); + + CPDF_Dictionary* pPages = new CPDF_Dictionary(m_pByteStringPool); + pPages->SetNameFor("Type", "Pages"); + pPages->SetNumberFor("Count", 0); + pPages->SetFor("Kids", new CPDF_Array); + m_pRootDict->SetReferenceFor("Pages", this, AddIndirectObject(pPages)); + m_pInfoDict = new CPDF_Dictionary(m_pByteStringPool); + AddIndirectObject(m_pInfoDict); +} + +CPDF_Dictionary* CPDF_Document::CreateNewPage(int iPage) { + CPDF_Dictionary* pDict = new CPDF_Dictionary(m_pByteStringPool); + pDict->SetNameFor("Type", "Page"); + uint32_t dwObjNum = AddIndirectObject(pDict); + if (InsertNewPage(this, iPage, pDict, m_PageList) < 0) { + ReleaseIndirectObject(dwObjNum); + return nullptr; + } + return pDict; +} + +void CPDF_Document::DeletePage(int iPage) { + CPDF_Dictionary* pPages = GetPagesDict(); + if (!pPages) + return; + + int nPages = pPages->GetIntegerFor("Count"); + if (iPage < 0 || iPage >= nPages) + return; + + std::set stack = {pPages}; + if (InsertDeletePDFPage(this, pPages, iPage, nullptr, FALSE, &stack) < 0) + return; + + m_PageList.RemoveAt(iPage); +} + +CPDF_Font* CPDF_Document::AddStandardFont(const FX_CHAR* font, + CPDF_FontEncoding* pEncoding) { + CFX_ByteString name(font); + if (PDF_GetStandardFontName(&name) < 0) + return nullptr; + return GetPageData()->GetStandardFont(name, pEncoding); +} + +size_t CPDF_Document::CalculateEncodingDict(int charset, + CPDF_Dictionary* pBaseDict) { + size_t i; + for (i = 0; i < FX_ArraySize(g_FX_CharsetUnicodes); ++i) { + if (g_FX_CharsetUnicodes[i].m_Charset == charset) + break; + } + if (i == FX_ArraySize(g_FX_CharsetUnicodes)) + return i; + CPDF_Dictionary* pEncodingDict = new CPDF_Dictionary(m_pByteStringPool); + pEncodingDict->SetNameFor("BaseEncoding", "WinAnsiEncoding"); + CPDF_Array* pArray = new CPDF_Array; + pArray->AddInteger(128); + const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes; + for (int j = 0; j < 128; j++) { + CFX_ByteString name = PDF_AdobeNameFromUnicode(pUnicodes[j]); + pArray->AddName(name.IsEmpty() ? ".notdef" : name); + } + pEncodingDict->SetFor("Differences", pArray); + pBaseDict->SetReferenceFor("Encoding", this, + AddIndirectObject(pEncodingDict)); + + return i; +} + +CPDF_Dictionary* CPDF_Document::ProcessbCJK( + CPDF_Dictionary* pBaseDict, + int charset, + FX_BOOL bVert, + CFX_ByteString basefont, + std::function Insert) { + CPDF_Dictionary* pFontDict = new CPDF_Dictionary(m_pByteStringPool); + CFX_ByteString cmap; + CFX_ByteString ordering; + int supplement = 0; + CPDF_Array* pWidthArray = new CPDF_Array; + switch (charset) { + case FXFONT_CHINESEBIG5_CHARSET: + cmap = bVert ? "ETenms-B5-V" : "ETenms-B5-H"; + ordering = "CNS1"; + supplement = 4; + pWidthArray->AddInteger(1); + Insert(0x20, 0x7e, pWidthArray); + break; + case FXFONT_GB2312_CHARSET: + cmap = bVert ? "GBK-EUC-V" : "GBK-EUC-H"; + ordering = "GB1"; + supplement = 2; + pWidthArray->AddInteger(7716); + Insert(0x20, 0x20, pWidthArray); + pWidthArray->AddInteger(814); + Insert(0x21, 0x7e, pWidthArray); + break; + case FXFONT_HANGUL_CHARSET: + cmap = bVert ? "KSCms-UHC-V" : "KSCms-UHC-H"; + ordering = "Korea1"; + supplement = 2; + pWidthArray->AddInteger(1); + Insert(0x20, 0x7e, pWidthArray); + break; + case FXFONT_SHIFTJIS_CHARSET: + cmap = bVert ? "90ms-RKSJ-V" : "90ms-RKSJ-H"; + ordering = "Japan1"; + supplement = 5; + pWidthArray->AddInteger(231); + Insert(0x20, 0x7d, pWidthArray); + pWidthArray->AddInteger(326); + Insert(0xa0, 0xa0, pWidthArray); + pWidthArray->AddInteger(327); + Insert(0xa1, 0xdf, pWidthArray); + pWidthArray->AddInteger(631); + Insert(0x7e, 0x7e, pWidthArray); + break; + } + pBaseDict->SetNameFor("Subtype", "Type0"); + pBaseDict->SetNameFor("BaseFont", basefont); + pBaseDict->SetNameFor("Encoding", cmap); + pFontDict->SetFor("W", pWidthArray); + pFontDict->SetNameFor("Type", "Font"); + pFontDict->SetNameFor("Subtype", "CIDFontType2"); + pFontDict->SetNameFor("BaseFont", basefont); + CPDF_Dictionary* pCIDSysInfo = new CPDF_Dictionary(m_pByteStringPool); + pCIDSysInfo->SetStringFor("Registry", "Adobe"); + pCIDSysInfo->SetStringFor("Ordering", ordering); + pCIDSysInfo->SetIntegerFor("Supplement", supplement); + pFontDict->SetFor("CIDSystemInfo", pCIDSysInfo); + CPDF_Array* pArray = new CPDF_Array; + pBaseDict->SetFor("DescendantFonts", pArray); + pArray->AddReference(this, AddIndirectObject(pFontDict)); + return pFontDict; +} + +CPDF_Font* CPDF_Document::AddFont(CFX_Font* pFont, int charset, FX_BOOL bVert) { + if (!pFont) + return nullptr; + + bool bCJK = charset == FXFONT_CHINESEBIG5_CHARSET || + charset == FXFONT_GB2312_CHARSET || + charset == FXFONT_HANGUL_CHARSET || + charset == FXFONT_SHIFTJIS_CHARSET; + CFX_ByteString basefont = pFont->GetFamilyName(); + basefont.Replace(" ", ""); + int flags = + CalculateFlags(pFont->IsBold(), pFont->IsItalic(), pFont->IsFixedWidth(), + false, false, charset == FXFONT_SYMBOL_CHARSET); + + CPDF_Dictionary* pBaseDict = new CPDF_Dictionary(m_pByteStringPool); + pBaseDict->SetNameFor("Type", "Font"); + std::unique_ptr pEncoding( + new CFX_UnicodeEncoding(pFont)); + CPDF_Dictionary* pFontDict = pBaseDict; + if (!bCJK) { + CPDF_Array* pWidths = new CPDF_Array; + for (int charcode = 32; charcode < 128; charcode++) { + int glyph_index = pEncoding->GlyphFromCharCode(charcode); + int char_width = pFont->GetGlyphWidth(glyph_index); + pWidths->AddInteger(char_width); + } + if (charset == FXFONT_ANSI_CHARSET || charset == FXFONT_DEFAULT_CHARSET || + charset == FXFONT_SYMBOL_CHARSET) { + pBaseDict->SetNameFor("Encoding", "WinAnsiEncoding"); + for (int charcode = 128; charcode <= 255; charcode++) { + int glyph_index = pEncoding->GlyphFromCharCode(charcode); + int char_width = pFont->GetGlyphWidth(glyph_index); + pWidths->AddInteger(char_width); + } + } else { + size_t i = CalculateEncodingDict(charset, pBaseDict); + if (i < FX_ArraySize(g_FX_CharsetUnicodes)) { + const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes; + for (int j = 0; j < 128; j++) { + int glyph_index = pEncoding->GlyphFromCharCode(pUnicodes[j]); + int char_width = pFont->GetGlyphWidth(glyph_index); + pWidths->AddInteger(char_width); + } + } + } + ProcessNonbCJK(pBaseDict, pFont->IsBold(), pFont->IsItalic(), basefont, + pWidths); + } else { + pFontDict = ProcessbCJK(pBaseDict, charset, bVert, basefont, + [pFont, &pEncoding](FX_WCHAR start, FX_WCHAR end, + CPDF_Array* widthArr) { + InsertWidthArray1(pFont, pEncoding.get(), start, + end, widthArr); + }); + } + AddIndirectObject(pBaseDict); + int italicangle = + pFont->GetSubstFont() ? pFont->GetSubstFont()->m_ItalicAngle : 0; + FX_RECT bbox; + pFont->GetBBox(bbox); + CPDF_Array* pBBox = new CPDF_Array; + pBBox->AddInteger(bbox.left); + pBBox->AddInteger(bbox.bottom); + pBBox->AddInteger(bbox.right); + pBBox->AddInteger(bbox.top); + int32_t nStemV = 0; + if (pFont->GetSubstFont()) { + nStemV = pFont->GetSubstFont()->m_Weight / 5; + } else { + static const FX_CHAR stem_chars[] = {'i', 'I', '!', '1'}; + const size_t count = FX_ArraySize(stem_chars); + uint32_t glyph = pEncoding->GlyphFromCharCode(stem_chars[0]); + nStemV = pFont->GetGlyphWidth(glyph); + for (size_t i = 1; i < count; i++) { + glyph = pEncoding->GlyphFromCharCode(stem_chars[i]); + int width = pFont->GetGlyphWidth(glyph); + if (width > 0 && width < nStemV) + nStemV = width; + } + } + CPDF_Dictionary* pFontDesc = + CalculateFontDesc(this, basefont, flags, italicangle, pFont->GetAscent(), + pFont->GetDescent(), pBBox, nStemV); + pFontDict->SetReferenceFor("FontDescriptor", this, + AddIndirectObject(pFontDesc)); + return LoadFont(pBaseDict); +} + +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ +CPDF_Font* CPDF_Document::AddWindowsFont(LOGFONTW* pLogFont, + FX_BOOL bVert, + FX_BOOL bTranslateName) { + LOGFONTA lfa; + FXSYS_memcpy(&lfa, pLogFont, (char*)lfa.lfFaceName - (char*)&lfa); + CFX_ByteString face = CFX_ByteString::FromUnicode(pLogFont->lfFaceName); + if (face.GetLength() >= LF_FACESIZE) + return nullptr; + + FXSYS_strcpy(lfa.lfFaceName, face.c_str()); + return AddWindowsFont(&lfa, bVert, bTranslateName); +} + +CPDF_Font* CPDF_Document::AddWindowsFont(LOGFONTA* pLogFont, + FX_BOOL bVert, + FX_BOOL bTranslateName) { + pLogFont->lfHeight = -1000; + pLogFont->lfWidth = 0; + HGDIOBJ hFont = CreateFontIndirectA(pLogFont); + HDC hDC = CreateCompatibleDC(nullptr); + hFont = SelectObject(hDC, hFont); + int tm_size = GetOutlineTextMetrics(hDC, 0, nullptr); + if (tm_size == 0) { + hFont = SelectObject(hDC, hFont); + DeleteObject(hFont); + DeleteDC(hDC); + return nullptr; + } + + LPBYTE tm_buf = FX_Alloc(BYTE, tm_size); + OUTLINETEXTMETRIC* ptm = reinterpret_cast(tm_buf); + GetOutlineTextMetrics(hDC, tm_size, ptm); + int flags = CalculateFlags(false, pLogFont->lfItalic != 0, + (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH, + (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN, + (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT, + pLogFont->lfCharSet == FXFONT_SYMBOL_CHARSET); + + bool bCJK = pLogFont->lfCharSet == FXFONT_CHINESEBIG5_CHARSET || + pLogFont->lfCharSet == FXFONT_GB2312_CHARSET || + pLogFont->lfCharSet == FXFONT_HANGUL_CHARSET || + pLogFont->lfCharSet == FXFONT_SHIFTJIS_CHARSET; + CFX_ByteString basefont; + if (bTranslateName && bCJK) + basefont = FPDF_GetPSNameFromTT(hDC); + + if (basefont.IsEmpty()) + basefont = pLogFont->lfFaceName; + + int italicangle = ptm->otmItalicAngle / 10; + int ascend = ptm->otmrcFontBox.top; + int descend = ptm->otmrcFontBox.bottom; + int capheight = ptm->otmsCapEmHeight; + int bbox[4] = {ptm->otmrcFontBox.left, ptm->otmrcFontBox.bottom, + ptm->otmrcFontBox.right, ptm->otmrcFontBox.top}; + FX_Free(tm_buf); + basefont.Replace(" ", ""); + CPDF_Dictionary* pBaseDict = new CPDF_Dictionary(m_pByteStringPool); + pBaseDict->SetNameFor("Type", "Font"); + CPDF_Dictionary* pFontDict = pBaseDict; + if (!bCJK) { + if (pLogFont->lfCharSet == FXFONT_ANSI_CHARSET || + pLogFont->lfCharSet == FXFONT_DEFAULT_CHARSET || + pLogFont->lfCharSet == FXFONT_SYMBOL_CHARSET) { + pBaseDict->SetNameFor("Encoding", "WinAnsiEncoding"); + } else { + CalculateEncodingDict(pLogFont->lfCharSet, pBaseDict); + } + int char_widths[224]; + GetCharWidth(hDC, 32, 255, char_widths); + CPDF_Array* pWidths = new CPDF_Array; + for (size_t i = 0; i < 224; i++) + pWidths->AddInteger(char_widths[i]); + ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM, + pLogFont->lfItalic != 0, basefont, pWidths); + } else { + pFontDict = + ProcessbCJK(pBaseDict, pLogFont->lfCharSet, bVert, basefont, + [&hDC](FX_WCHAR start, FX_WCHAR end, CPDF_Array* widthArr) { + InsertWidthArray(hDC, start, end, widthArr); + }); + } + AddIndirectObject(pBaseDict); + CPDF_Array* pBBox = new CPDF_Array; + for (int i = 0; i < 4; i++) + pBBox->AddInteger(bbox[i]); + CPDF_Dictionary* pFontDesc = + CalculateFontDesc(this, basefont, flags, italicangle, ascend, descend, + pBBox, pLogFont->lfWeight / 5); + pFontDesc->SetIntegerFor("CapHeight", capheight); + pFontDict->SetReferenceFor("FontDescriptor", this, + AddIndirectObject(pFontDesc)); + hFont = SelectObject(hDC, hFont); + DeleteObject(hFont); + DeleteDC(hDC); + return LoadFont(pBaseDict); +} +#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ diff --git a/core/fpdfapi/parser/cpdf_document.h b/core/fpdfapi/parser/cpdf_document.h new file mode 100644 index 0000000000..83ceb77b08 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_document.h @@ -0,0 +1,145 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_DOCUMENT_H_ +#define CORE_FPDFAPI_PARSER_CPDF_DOCUMENT_H_ + +#include +#include + +#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fpdfdoc/cpdf_linklist.h" +#include "core/fxcrt/cfx_string_pool_template.h" +#include "core/fxcrt/cfx_weak_ptr.h" +#include "core/fxcrt/fx_basic.h" + +class CFX_Font; +class CFX_Matrix; +class CPDF_ColorSpace; +class CPDF_DocPageData; +class CPDF_DocRenderData; +class CPDF_Font; +class CPDF_FontEncoding; +class CPDF_IccProfile; +class CPDF_Image; +class CPDF_Parser; +class CPDF_Pattern; +class CPDF_StreamAcc; +class JBig2_DocumentContext; + +#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 CPDF_Document : public CPDF_IndirectObjectHolder { + public: + explicit CPDF_Document(std::unique_ptr pParser); + ~CPDF_Document() override; + + CPDF_Parser* GetParser() const { return m_pParser.get(); } + CPDF_Dictionary* GetRoot() const { return m_pRootDict; } + CPDF_Dictionary* GetInfo() const { return m_pInfoDict; } + CFX_WeakPtr GetByteStringPool() const { + return m_pByteStringPool; + } + + void DeletePage(int iPage); + int GetPageCount() const; + + bool IsPageLoaded(int iPage) const; + CPDF_Dictionary* GetPage(int iPage); + int GetPageIndex(uint32_t objnum); + uint32_t GetUserPermissions() const; + CPDF_DocPageData* GetPageData() const { return m_pDocPage; } + + void SetPageObjNum(int iPage, uint32_t objNum); + + std::unique_ptr* CodecContext() { + return &m_pCodecContext; + } + std::unique_ptr* LinksContext() { return &m_pLinksContext; } + + CPDF_DocRenderData* GetRenderData() const { return m_pDocRender.get(); } + + // |pFontDict| must not be null. + CPDF_Font* LoadFont(CPDF_Dictionary* pFontDict); + CPDF_ColorSpace* LoadColorSpace(CPDF_Object* pCSObj, + CPDF_Dictionary* pResources = nullptr); + + CPDF_Pattern* LoadPattern(CPDF_Object* pObj, + FX_BOOL bShading, + const CFX_Matrix& matrix); + + CPDF_Image* LoadImageF(CPDF_Object* pObj); + CPDF_StreamAcc* LoadFontFile(CPDF_Stream* pStream); + CPDF_IccProfile* LoadIccProfile(CPDF_Stream* pStream); + + void LoadDoc(); + void LoadLinearizedDoc(CPDF_Dictionary* pLinearizationParams); + void LoadPages(); + + void CreateNewDoc(); + CPDF_Dictionary* CreateNewPage(int iPage); + + CPDF_Font* AddStandardFont(const FX_CHAR* font, CPDF_FontEncoding* pEncoding); + CPDF_Font* AddFont(CFX_Font* pFont, int charset, FX_BOOL bVert); +#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 + + private: + friend class CPDF_TestDocument; + + // Retrieve page count information by getting count value from the tree nodes + int RetrievePageCount() const; + CPDF_Dictionary* FindPDFPage(CPDF_Dictionary* pPages, + int iPage, + int nPagesToGo, + int level); + int FindPageIndex(CPDF_Dictionary* pNode, + uint32_t& skip_count, + uint32_t objnum, + int& index, + int level = 0); + CPDF_Object* ParseIndirectObject(uint32_t objnum) override; + void LoadDocInternal(); + size_t CalculateEncodingDict(int charset, CPDF_Dictionary* pBaseDict); + CPDF_Dictionary* GetPagesDict() const; + CPDF_Dictionary* ProcessbCJK( + CPDF_Dictionary* pBaseDict, + int charset, + FX_BOOL bVert, + CFX_ByteString basefont, + std::function Insert); + + std::unique_ptr m_pParser; + CPDF_Dictionary* m_pRootDict; + CPDF_Dictionary* m_pInfoDict; + bool m_bLinearized; + int m_iFirstPageNo; + uint32_t m_dwFirstPageObjNum; + // TODO(thestig): Figure out why this cannot be a std::unique_ptr. + CPDF_DocPageData* m_pDocPage; + std::unique_ptr m_pDocRender; + std::unique_ptr m_pCodecContext; + std::unique_ptr m_pLinksContext; + CFX_ArrayTemplate m_PageList; + CFX_WeakPtr m_pByteStringPool; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_DOCUMENT_H_ diff --git a/core/fpdfapi/parser/cpdf_hint_tables.cpp b/core/fpdfapi/parser/cpdf_hint_tables.cpp new file mode 100644 index 0000000000..045b94cac5 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_hint_tables.cpp @@ -0,0 +1,524 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_hint_tables.h" + +#include + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_data_avail.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fxcrt/fx_safe_types.h" +#include "third_party/base/numerics/safe_conversions.h" + +namespace { + +bool CanReadFromBitStream(const CFX_BitStream* hStream, + const FX_SAFE_UINT32& bits) { + return bits.IsValid() && hStream->BitsRemaining() >= bits.ValueOrDie(); +} + +// Sanity check values from the page table header. The note in the PDF 1.7 +// reference for Table F.3 says the valid range is only 0 through 32. Though 0 +// is not useful either. +bool IsValidPageOffsetHintTableBitCount(uint32_t bits) { + return bits > 0 && bits <= 32; +} + +} // namespace + +CPDF_HintTables::CPDF_HintTables(CPDF_DataAvail* pDataAvail, + CPDF_Dictionary* pLinearized) + : m_pDataAvail(pDataAvail), + m_pLinearizedDict(pLinearized), + m_nFirstPageSharedObjs(0), + m_szFirstPageObjOffset(0) { + ASSERT(m_pLinearizedDict); +} + +CPDF_HintTables::~CPDF_HintTables() {} + +uint32_t CPDF_HintTables::GetItemLength( + uint32_t index, + const std::vector& szArray) { + if (szArray.size() < 2 || index > szArray.size() - 2 || + szArray[index] > szArray[index + 1]) { + return 0; + } + return szArray[index + 1] - szArray[index]; +} + +bool CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { + if (!hStream || hStream->IsEOF()) + return false; + + int nStreamOffset = ReadPrimaryHintStreamOffset(); + if (nStreamOffset < 0) + return false; + + int nStreamLen = ReadPrimaryHintStreamLength(); + if (nStreamLen < 1 || + !pdfium::base::IsValueInRangeForNumericType(nStreamLen)) { + return false; + } + + const uint32_t kHeaderSize = 288; + if (hStream->BitsRemaining() < kHeaderSize) + return false; + + // Item 1: The least number of objects in a page. + const uint32_t dwObjLeastNum = hStream->GetBits(32); + if (!dwObjLeastNum) + return false; + + // Item 2: The location of the first page's page object. + const uint32_t dwFirstObjLoc = hStream->GetBits(32); + if (dwFirstObjLoc > static_cast(nStreamOffset)) { + FX_SAFE_FILESIZE safeLoc = nStreamLen; + safeLoc += dwFirstObjLoc; + if (!safeLoc.IsValid()) + return false; + m_szFirstPageObjOffset = safeLoc.ValueOrDie(); + } else { + if (!pdfium::base::IsValueInRangeForNumericType(dwFirstObjLoc)) + return false; + m_szFirstPageObjOffset = dwFirstObjLoc; + } + + // Item 3: The number of bits needed to represent the difference + // between the greatest and least number of objects in a page. + const uint32_t dwDeltaObjectsBits = hStream->GetBits(16); + if (!IsValidPageOffsetHintTableBitCount(dwDeltaObjectsBits)) + return false; + + // Item 4: The least length of a page in bytes. + const uint32_t dwPageLeastLen = hStream->GetBits(32); + if (!dwPageLeastLen) + return false; + + // Item 5: The number of bits needed to represent the difference + // between the greatest and least length of a page, in bytes. + const uint32_t dwDeltaPageLenBits = hStream->GetBits(16); + if (!IsValidPageOffsetHintTableBitCount(dwDeltaPageLenBits)) + return false; + + // Skip Item 6, 7, 8, 9 total 96 bits. + hStream->SkipBits(96); + + // Item 10: The number of bits needed to represent the greatest + // number of shared object references. + const uint32_t dwSharedObjBits = hStream->GetBits(16); + if (!IsValidPageOffsetHintTableBitCount(dwSharedObjBits)) + return false; + + // Item 11: The number of bits needed to represent the numerically + // greatest shared object identifier used by the pages. + const uint32_t dwSharedIdBits = hStream->GetBits(16); + if (!IsValidPageOffsetHintTableBitCount(dwSharedIdBits)) + return false; + + // Item 12: The number of bits needed to represent the numerator of + // the fractional position for each shared object reference. For each + // shared object referenced from a page, there is an indication of + // where in the page's content stream the object is first referenced. + const uint32_t dwSharedNumeratorBits = hStream->GetBits(16); + if (!IsValidPageOffsetHintTableBitCount(dwSharedNumeratorBits)) + return false; + + // Item 13: Skip Item 13 which has 16 bits. + hStream->SkipBits(16); + + const int nPages = GetNumberOfPages(); + if (nPages < 1 || nPages >= FPDF_PAGE_MAX_NUM) + return false; + + const uint32_t dwPages = pdfium::base::checked_cast(nPages); + FX_SAFE_UINT32 required_bits = dwDeltaObjectsBits; + required_bits *= dwPages; + if (!CanReadFromBitStream(hStream, required_bits)) + return false; + + for (int i = 0; i < nPages; ++i) { + FX_SAFE_UINT32 safeDeltaObj = hStream->GetBits(dwDeltaObjectsBits); + safeDeltaObj += dwObjLeastNum; + if (!safeDeltaObj.IsValid()) + return false; + m_dwDeltaNObjsArray.push_back(safeDeltaObj.ValueOrDie()); + } + hStream->ByteAlign(); + + required_bits = dwDeltaPageLenBits; + required_bits *= dwPages; + if (!CanReadFromBitStream(hStream, required_bits)) + return false; + + std::vector dwPageLenArray; + for (int i = 0; i < nPages; ++i) { + FX_SAFE_UINT32 safePageLen = hStream->GetBits(dwDeltaPageLenBits); + safePageLen += dwPageLeastLen; + if (!safePageLen.IsValid()) + return false; + + dwPageLenArray.push_back(safePageLen.ValueOrDie()); + } + + int nOffsetE = GetEndOfFirstPageOffset(); + if (nOffsetE < 0) + return false; + + int nFirstPageNum = GetFirstPageNumber(); + if (nFirstPageNum < 0 || nFirstPageNum > std::numeric_limits::max() - 1) + return false; + + for (int i = 0; i < nPages; ++i) { + if (i == nFirstPageNum) { + m_szPageOffsetArray.push_back(m_szFirstPageObjOffset); + } else if (i == nFirstPageNum + 1) { + if (i == 1) { + m_szPageOffsetArray.push_back(nOffsetE); + } else { + m_szPageOffsetArray.push_back(m_szPageOffsetArray[i - 2] + + dwPageLenArray[i - 2]); + } + } else { + if (i == 0) { + m_szPageOffsetArray.push_back(nOffsetE); + } else { + m_szPageOffsetArray.push_back(m_szPageOffsetArray[i - 1] + + dwPageLenArray[i - 1]); + } + } + } + + m_szPageOffsetArray.push_back(m_szPageOffsetArray[nPages - 1] + + dwPageLenArray[nPages - 1]); + hStream->ByteAlign(); + + // Number of shared objects. + required_bits = dwSharedObjBits; + required_bits *= dwPages; + if (!CanReadFromBitStream(hStream, required_bits)) + return false; + + for (int i = 0; i < nPages; i++) + m_dwNSharedObjsArray.push_back(hStream->GetBits(dwSharedObjBits)); + hStream->ByteAlign(); + + // Array of identifiers, size = nshared_objects. + for (int i = 0; i < nPages; i++) { + required_bits = dwSharedIdBits; + required_bits *= m_dwNSharedObjsArray[i]; + if (!CanReadFromBitStream(hStream, required_bits)) + return false; + + for (uint32_t j = 0; j < m_dwNSharedObjsArray[i]; j++) + m_dwIdentifierArray.push_back(hStream->GetBits(dwSharedIdBits)); + } + hStream->ByteAlign(); + + for (int i = 0; i < nPages; i++) { + FX_SAFE_UINT32 safeSize = m_dwNSharedObjsArray[i]; + safeSize *= dwSharedNumeratorBits; + if (!CanReadFromBitStream(hStream, safeSize)) + return false; + + hStream->SkipBits(safeSize.ValueOrDie()); + } + hStream->ByteAlign(); + + FX_SAFE_UINT32 safeTotalPageLen = dwPages; + safeTotalPageLen *= dwDeltaPageLenBits; + if (!CanReadFromBitStream(hStream, safeTotalPageLen)) + return false; + + hStream->SkipBits(safeTotalPageLen.ValueOrDie()); + hStream->ByteAlign(); + return true; +} + +bool CPDF_HintTables::ReadSharedObjHintTable(CFX_BitStream* hStream, + uint32_t offset) { + if (!hStream || hStream->IsEOF()) + return false; + + int nStreamOffset = ReadPrimaryHintStreamOffset(); + int nStreamLen = ReadPrimaryHintStreamLength(); + if (nStreamOffset < 0 || nStreamLen < 1) + return false; + + FX_SAFE_UINT32 bit_offset = offset; + bit_offset *= 8; + if (!bit_offset.IsValid() || hStream->GetPos() > bit_offset.ValueOrDie()) + return false; + hStream->SkipBits(bit_offset.ValueOrDie() - hStream->GetPos()); + + const uint32_t kHeaderSize = 192; + if (hStream->BitsRemaining() < kHeaderSize) + return false; + + // Item 1: The object number of the first object in the shared objects + // section. + uint32_t dwFirstSharedObjNum = hStream->GetBits(32); + + // Item 2: The location of the first object in the shared objects section. + uint32_t dwFirstSharedObjLoc = hStream->GetBits(32); + if (dwFirstSharedObjLoc > static_cast(nStreamOffset)) + dwFirstSharedObjLoc += nStreamLen; + + // Item 3: The number of shared object entries for the first page. + m_nFirstPageSharedObjs = hStream->GetBits(32); + + // Item 4: The number of shared object entries for the shared objects + // section, including the number of shared object entries for the first page. + uint32_t dwSharedObjTotal = hStream->GetBits(32); + + // Item 5: The number of bits needed to represent the greatest number of + // objects in a shared object group. Skipped. + hStream->SkipBits(16); + + // Item 6: The least length of a shared object group in bytes. + uint32_t dwGroupLeastLen = hStream->GetBits(32); + + // Item 7: The number of bits needed to represent the difference between the + // greatest and least length of a shared object group, in bytes. + uint32_t dwDeltaGroupLen = hStream->GetBits(16); + + if (dwFirstSharedObjNum >= CPDF_Parser::kMaxObjectNumber || + m_nFirstPageSharedObjs >= CPDF_Parser::kMaxObjectNumber || + dwSharedObjTotal >= CPDF_Parser::kMaxObjectNumber) { + return false; + } + + int nFirstPageObjNum = GetFirstPageObjectNumber(); + if (nFirstPageObjNum < 0) + return false; + + uint32_t dwPrevObjLen = 0; + uint32_t dwCurObjLen = 0; + FX_SAFE_UINT32 required_bits = dwSharedObjTotal; + required_bits *= dwDeltaGroupLen; + if (!CanReadFromBitStream(hStream, required_bits)) + return false; + + for (uint32_t i = 0; i < dwSharedObjTotal; ++i) { + dwPrevObjLen = dwCurObjLen; + FX_SAFE_UINT32 safeObjLen = hStream->GetBits(dwDeltaGroupLen); + safeObjLen += dwGroupLeastLen; + if (!safeObjLen.IsValid()) + return false; + + dwCurObjLen = safeObjLen.ValueOrDie(); + if (i < m_nFirstPageSharedObjs) { + m_dwSharedObjNumArray.push_back(nFirstPageObjNum + i); + if (i == 0) + m_szSharedObjOffsetArray.push_back(m_szFirstPageObjOffset); + } else { + FX_SAFE_UINT32 safeObjNum = dwFirstSharedObjNum; + safeObjNum += i - m_nFirstPageSharedObjs; + if (!safeObjNum.IsValid()) + return false; + + m_dwSharedObjNumArray.push_back(safeObjNum.ValueOrDie()); + if (i == m_nFirstPageSharedObjs) { + FX_SAFE_FILESIZE safeLoc = dwFirstSharedObjLoc; + if (!safeLoc.IsValid()) + return false; + + m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); + } + } + + if (i != 0 && i != m_nFirstPageSharedObjs) { + FX_SAFE_FILESIZE safeLoc = dwPrevObjLen; + safeLoc += m_szSharedObjOffsetArray[i - 1]; + if (!safeLoc.IsValid()) + return false; + + m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); + } + } + + if (dwSharedObjTotal > 0) { + FX_SAFE_FILESIZE safeLoc = dwCurObjLen; + safeLoc += m_szSharedObjOffsetArray[dwSharedObjTotal - 1]; + if (!safeLoc.IsValid()) + return false; + + m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); + } + + hStream->ByteAlign(); + if (hStream->BitsRemaining() < dwSharedObjTotal) + return false; + + hStream->SkipBits(dwSharedObjTotal); + hStream->ByteAlign(); + return true; +} + +bool CPDF_HintTables::GetPagePos(uint32_t index, + FX_FILESIZE* szPageStartPos, + FX_FILESIZE* szPageLength, + uint32_t* dwObjNum) { + *szPageStartPos = m_szPageOffsetArray[index]; + *szPageLength = GetItemLength(index, m_szPageOffsetArray); + + int nFirstPageObjNum = GetFirstPageObjectNumber(); + if (nFirstPageObjNum < 0) + return false; + + int nFirstPageNum = GetFirstPageNumber(); + if (!pdfium::base::IsValueInRangeForNumericType(nFirstPageNum)) + return false; + + uint32_t dwFirstPageNum = static_cast(nFirstPageNum); + if (index == dwFirstPageNum) { + *dwObjNum = nFirstPageObjNum; + return true; + } + + // The object number of remaining pages starts from 1. + *dwObjNum = 1; + for (uint32_t i = 0; i < index; ++i) { + if (i == dwFirstPageNum) + continue; + *dwObjNum += m_dwDeltaNObjsArray[i]; + } + return true; +} + +CPDF_DataAvail::DocAvailStatus CPDF_HintTables::CheckPage( + uint32_t index, + CPDF_DataAvail::DownloadHints* pHints) { + if (!pHints) + return CPDF_DataAvail::DataError; + + int nFirstPageNum = GetFirstPageNumber(); + if (!pdfium::base::IsValueInRangeForNumericType(nFirstPageNum)) + return CPDF_DataAvail::DataError; + + if (index == static_cast(nFirstPageNum)) + return CPDF_DataAvail::DataAvailable; + + uint32_t dwLength = GetItemLength(index, m_szPageOffsetArray); + // If two pages have the same offset, it should be treated as an error. + if (!dwLength) + return CPDF_DataAvail::DataError; + + if (!m_pDataAvail->IsDataAvail(m_szPageOffsetArray[index], dwLength, pHints)) + return CPDF_DataAvail::DataNotAvailable; + + // Download data of shared objects in the page. + uint32_t offset = 0; + for (uint32_t i = 0; i < index; ++i) + offset += m_dwNSharedObjsArray[i]; + + int nFirstPageObjNum = GetFirstPageObjectNumber(); + if (nFirstPageObjNum < 0) + return CPDF_DataAvail::DataError; + + uint32_t dwIndex = 0; + uint32_t dwObjNum = 0; + for (uint32_t j = 0; j < m_dwNSharedObjsArray[index]; ++j) { + dwIndex = m_dwIdentifierArray[offset + j]; + if (dwIndex >= m_dwSharedObjNumArray.size()) + return CPDF_DataAvail::DataNotAvailable; + + dwObjNum = m_dwSharedObjNumArray[dwIndex]; + if (dwObjNum >= static_cast(nFirstPageObjNum) && + dwObjNum < + static_cast(nFirstPageObjNum) + m_nFirstPageSharedObjs) { + continue; + } + + dwLength = GetItemLength(dwIndex, m_szSharedObjOffsetArray); + // If two objects have the same offset, it should be treated as an error. + if (!dwLength) + return CPDF_DataAvail::DataError; + + if (!m_pDataAvail->IsDataAvail(m_szSharedObjOffsetArray[dwIndex], dwLength, + pHints)) { + return CPDF_DataAvail::DataNotAvailable; + } + } + return CPDF_DataAvail::DataAvailable; +} + +bool CPDF_HintTables::LoadHintStream(CPDF_Stream* pHintStream) { + if (!pHintStream) + return false; + + CPDF_Dictionary* pDict = pHintStream->GetDict(); + CPDF_Object* pOffset = pDict ? pDict->GetObjectFor("S") : nullptr; + if (!pOffset || !pOffset->IsNumber()) + return false; + + int shared_hint_table_offset = pOffset->GetInteger(); + if (shared_hint_table_offset <= 0) + return false; + + CPDF_StreamAcc acc; + acc.LoadAllData(pHintStream); + + uint32_t size = acc.GetSize(); + // The header section of page offset hint table is 36 bytes. + // The header section of shared object hint table is 24 bytes. + // Hint table has at least 60 bytes. + const uint32_t kMinStreamLength = 60; + if (size < kMinStreamLength) + return false; + + FX_SAFE_UINT32 safe_shared_hint_table_offset = shared_hint_table_offset; + if (!safe_shared_hint_table_offset.IsValid() || + size < safe_shared_hint_table_offset.ValueOrDie()) { + return false; + } + + CFX_BitStream bs; + bs.Init(acc.GetData(), size); + return ReadPageHintTable(&bs) && + ReadSharedObjHintTable(&bs, shared_hint_table_offset); +} + +int CPDF_HintTables::GetEndOfFirstPageOffset() const { + CPDF_Object* pOffsetE = m_pLinearizedDict->GetDirectObjectFor("E"); + return pOffsetE ? pOffsetE->GetInteger() : -1; +} + +int CPDF_HintTables::GetNumberOfPages() const { + CPDF_Object* pPageNum = m_pLinearizedDict->GetDirectObjectFor("N"); + return pPageNum ? pPageNum->GetInteger() : 0; +} + +int CPDF_HintTables::GetFirstPageObjectNumber() const { + CPDF_Object* pFirstPageObj = m_pLinearizedDict->GetDirectObjectFor("O"); + return pFirstPageObj ? pFirstPageObj->GetInteger() : -1; +} + +int CPDF_HintTables::GetFirstPageNumber() const { + CPDF_Object* pFirstPageNum = m_pLinearizedDict->GetDirectObjectFor("P"); + return pFirstPageNum ? pFirstPageNum->GetInteger() : 0; +} + +int CPDF_HintTables::ReadPrimaryHintStreamOffset() const { + return ReadPrimaryHintStream(0); +} + +int CPDF_HintTables::ReadPrimaryHintStreamLength() const { + return ReadPrimaryHintStream(1); +} + +int CPDF_HintTables::ReadPrimaryHintStream(int index) const { + CPDF_Array* pRange = m_pLinearizedDict->GetArrayFor("H"); + if (!pRange) + return -1; + + CPDF_Object* pStreamLen = pRange->GetDirectObjectAt(index); + return pStreamLen ? pStreamLen->GetInteger() : -1; +} diff --git a/core/fpdfapi/parser/cpdf_hint_tables.h b/core/fpdfapi/parser/cpdf_hint_tables.h new file mode 100644 index 0000000000..84f48cf41f --- /dev/null +++ b/core/fpdfapi/parser/cpdf_hint_tables.h @@ -0,0 +1,71 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_HINT_TABLES_H_ +#define CORE_FPDFAPI_PARSER_CPDF_HINT_TABLES_H_ + +#include + +#include "core/fpdfapi/parser/cpdf_data_avail.h" +#include "core/fxcrt/fx_basic.h" +#include "core/fxcrt/fx_stream.h" + +class CFX_BitStream; +class CPDF_Dictionary; +class CPDF_Stream; + +class CPDF_HintTables { + public: + CPDF_HintTables(CPDF_DataAvail* pDataAvail, CPDF_Dictionary* pLinearized); + virtual ~CPDF_HintTables(); + + bool GetPagePos(uint32_t index, + FX_FILESIZE* szPageStartPos, + FX_FILESIZE* szPageLength, + uint32_t* dwObjNum); + + CPDF_DataAvail::DocAvailStatus CheckPage( + uint32_t index, + CPDF_DataAvail::DownloadHints* pHints); + + bool LoadHintStream(CPDF_Stream* pHintStream); + + protected: + bool ReadPageHintTable(CFX_BitStream* hStream); + bool ReadSharedObjHintTable(CFX_BitStream* hStream, uint32_t offset); + + private: + // Tests can override. + virtual int GetEndOfFirstPageOffset() const; + virtual int GetNumberOfPages() const; + virtual int GetFirstPageObjectNumber() const; + virtual int GetFirstPageNumber() const; + virtual int ReadPrimaryHintStreamOffset() const; + virtual int ReadPrimaryHintStreamLength() const; + + // Helper for the ReadPrimaryHintStream methods above. + int ReadPrimaryHintStream(int index) const; + + uint32_t GetItemLength(uint32_t index, + const std::vector& szArray); + + // Owner, outlives this object. + CPDF_DataAvail* const m_pDataAvail; + + // Owned by |m_pDataAvail|. + CPDF_Dictionary* const m_pLinearizedDict; + + uint32_t m_nFirstPageSharedObjs; + FX_FILESIZE m_szFirstPageObjOffset; + std::vector m_dwDeltaNObjsArray; + std::vector m_dwNSharedObjsArray; + std::vector m_dwSharedObjNumArray; + std::vector m_dwIdentifierArray; + std::vector m_szPageOffsetArray; + std::vector m_szSharedObjOffsetArray; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_HINT_TABLES_H_ diff --git a/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp b/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp new file mode 100644 index 0000000000..6e549de5a7 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp @@ -0,0 +1,79 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" + +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fpdfapi/parser/cpdf_parser.h" + +CPDF_IndirectObjectHolder::CPDF_IndirectObjectHolder() : m_LastObjNum(0) {} + +CPDF_IndirectObjectHolder::~CPDF_IndirectObjectHolder() {} + +CPDF_Object* CPDF_IndirectObjectHolder::GetIndirectObject( + uint32_t objnum) const { + auto it = m_IndirectObjs.find(objnum); + return it != m_IndirectObjs.end() ? it->second.get() : nullptr; +} + +CPDF_Object* CPDF_IndirectObjectHolder::GetOrParseIndirectObject( + uint32_t objnum) { + if (objnum == 0) + return nullptr; + + CPDF_Object* pObj = GetIndirectObject(objnum); + if (pObj) + return pObj->GetObjNum() != CPDF_Object::kInvalidObjNum ? pObj : nullptr; + + pObj = ParseIndirectObject(objnum); + if (!pObj) + return nullptr; + + pObj->m_ObjNum = objnum; + m_LastObjNum = std::max(m_LastObjNum, objnum); + m_IndirectObjs[objnum].reset(pObj); + return pObj; +} + +CPDF_Object* CPDF_IndirectObjectHolder::ParseIndirectObject(uint32_t objnum) { + return nullptr; +} + +uint32_t CPDF_IndirectObjectHolder::AddIndirectObject(CPDF_Object* pObj) { + if (pObj->m_ObjNum) + return pObj->m_ObjNum; + + m_LastObjNum++; + m_IndirectObjs[m_LastObjNum].release(); // TODO(tsepez): stop this leak. + m_IndirectObjs[m_LastObjNum].reset(pObj); + pObj->m_ObjNum = m_LastObjNum; + return m_LastObjNum; +} + +bool CPDF_IndirectObjectHolder::ReplaceIndirectObjectIfHigherGeneration( + uint32_t objnum, + CPDF_Object* pObj) { + if (!objnum || !pObj) + return false; + + CPDF_Object* pOldObj = GetIndirectObject(objnum); + if (pOldObj && pObj->GetGenNum() <= pOldObj->GetGenNum()) { + delete pObj; + return false; + } + pObj->m_ObjNum = objnum; + m_IndirectObjs[objnum].reset(pObj); + m_LastObjNum = std::max(m_LastObjNum, objnum); + return true; +} + +void CPDF_IndirectObjectHolder::ReleaseIndirectObject(uint32_t objnum) { + CPDF_Object* pObj = GetIndirectObject(objnum); + if (!pObj || pObj->GetObjNum() == CPDF_Object::kInvalidObjNum) + return; + + m_IndirectObjs.erase(objnum); +} diff --git a/core/fpdfapi/parser/cpdf_indirect_object_holder.h b/core/fpdfapi/parser/cpdf_indirect_object_holder.h new file mode 100644 index 0000000000..da4e942b5d --- /dev/null +++ b/core/fpdfapi/parser/cpdf_indirect_object_holder.h @@ -0,0 +1,48 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_INDIRECT_OBJECT_HOLDER_H_ +#define CORE_FPDFAPI_PARSER_CPDF_INDIRECT_OBJECT_HOLDER_H_ + +#include +#include + +#include "core/fxcrt/fx_system.h" + +class CPDF_Object; + +class CPDF_IndirectObjectHolder { + public: + using const_iterator = + std::map>::const_iterator; + + CPDF_IndirectObjectHolder(); + virtual ~CPDF_IndirectObjectHolder(); + + CPDF_Object* GetIndirectObject(uint32_t objnum) const; + CPDF_Object* GetOrParseIndirectObject(uint32_t objnum); + void ReleaseIndirectObject(uint32_t objnum); + + // Take ownership of |pObj|. + uint32_t AddIndirectObject(CPDF_Object* pObj); + bool ReplaceIndirectObjectIfHigherGeneration(uint32_t objnum, + CPDF_Object* pObj); + + uint32_t GetLastObjNum() const { return m_LastObjNum; } + void SetLastObjNum(uint32_t objnum) { m_LastObjNum = objnum; } + + const_iterator begin() const { return m_IndirectObjs.begin(); } + const_iterator end() const { return m_IndirectObjs.end(); } + + protected: + virtual CPDF_Object* ParseIndirectObject(uint32_t objnum); + + private: + uint32_t m_LastObjNum; + std::map> m_IndirectObjs; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_INDIRECT_OBJECT_HOLDER_H_ diff --git a/core/fpdfapi/parser/cpdf_name.cpp b/core/fpdfapi/parser/cpdf_name.cpp new file mode 100644 index 0000000000..5cc8479c3b --- /dev/null +++ b/core/fpdfapi/parser/cpdf_name.cpp @@ -0,0 +1,45 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_name.h" + +#include "core/fpdfapi/parser/fpdf_parser_decode.h" + +CPDF_Name::CPDF_Name(const CFX_ByteString& str) : m_Name(str) {} + +CPDF_Name::~CPDF_Name() {} + +CPDF_Object::Type CPDF_Name::GetType() const { + return NAME; +} + +CPDF_Object* CPDF_Name::Clone() const { + return new CPDF_Name(m_Name); +} + +CFX_ByteString CPDF_Name::GetString() const { + return m_Name; +} + +void CPDF_Name::SetString(const CFX_ByteString& str) { + m_Name = str; +} + +bool CPDF_Name::IsName() const { + return true; +} + +CPDF_Name* CPDF_Name::AsName() { + return this; +} + +const CPDF_Name* CPDF_Name::AsName() const { + return this; +} + +CFX_WideString CPDF_Name::GetUnicodeText() const { + return PDF_DecodeText(m_Name); +} diff --git a/core/fpdfapi/parser/cpdf_name.h b/core/fpdfapi/parser/cpdf_name.h new file mode 100644 index 0000000000..e6b460de39 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_name.h @@ -0,0 +1,32 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_NAME_H_ +#define CORE_FPDFAPI_PARSER_CPDF_NAME_H_ + +#include "core/fpdfapi/parser/cpdf_object.h" + +class CPDF_Name : public CPDF_Object { + public: + explicit CPDF_Name(const CFX_ByteString& str); + + // CPDF_Object. + Type GetType() const override; + CPDF_Object* Clone() const override; + CFX_ByteString GetString() const override; + CFX_WideString GetUnicodeText() const override; + void SetString(const CFX_ByteString& str) override; + bool IsName() const override; + CPDF_Name* AsName() override; + const CPDF_Name* AsName() const override; + + protected: + ~CPDF_Name() override; + + CFX_ByteString m_Name; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_NAME_H_ diff --git a/core/fpdfapi/parser/cpdf_null.cpp b/core/fpdfapi/parser/cpdf_null.cpp new file mode 100644 index 0000000000..dd23101aa8 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_null.cpp @@ -0,0 +1,17 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_null.h" + +CPDF_Null::CPDF_Null() {} + +CPDF_Object::Type CPDF_Null::GetType() const { + return NULLOBJ; +} + +CPDF_Object* CPDF_Null::Clone() const { + return new CPDF_Null; +} diff --git a/core/fpdfapi/parser/cpdf_null.h b/core/fpdfapi/parser/cpdf_null.h new file mode 100644 index 0000000000..2b8b053b99 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_null.h @@ -0,0 +1,21 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_NULL_H_ +#define CORE_FPDFAPI_PARSER_CPDF_NULL_H_ + +#include "core/fpdfapi/parser/cpdf_object.h" + +class CPDF_Null : public CPDF_Object { + public: + CPDF_Null(); + + // CPDF_Object. + Type GetType() const override; + CPDF_Object* Clone() const override; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_NULL_H_ diff --git a/core/fpdfapi/parser/cpdf_number.cpp b/core/fpdfapi/parser/cpdf_number.cpp new file mode 100644 index 0000000000..3ae629ede9 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_number.cpp @@ -0,0 +1,55 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_number.h" + +CPDF_Number::CPDF_Number() : m_bInteger(true), m_Integer(0) {} + +CPDF_Number::CPDF_Number(int value) : m_bInteger(true), m_Integer(value) {} + +CPDF_Number::CPDF_Number(FX_FLOAT value) : m_bInteger(false), m_Float(value) {} + +CPDF_Number::CPDF_Number(const CFX_ByteStringC& str) + : m_bInteger(FX_atonum(str, &m_Integer)) {} + +CPDF_Number::~CPDF_Number() {} + +CPDF_Object::Type CPDF_Number::GetType() const { + return NUMBER; +} + +CPDF_Object* CPDF_Number::Clone() const { + return m_bInteger ? new CPDF_Number(m_Integer) : new CPDF_Number(m_Float); +} + +FX_FLOAT CPDF_Number::GetNumber() const { + return m_bInteger ? static_cast(m_Integer) : m_Float; +} + +int CPDF_Number::GetInteger() const { + return m_bInteger ? m_Integer : static_cast(m_Float); +} + +bool CPDF_Number::IsNumber() const { + return true; +} + +CPDF_Number* CPDF_Number::AsNumber() { + return this; +} + +const CPDF_Number* CPDF_Number::AsNumber() const { + return this; +} + +void CPDF_Number::SetString(const CFX_ByteString& str) { + m_bInteger = FX_atonum(str.AsStringC(), &m_Integer); +} + +CFX_ByteString CPDF_Number::GetString() const { + return m_bInteger ? CFX_ByteString::FormatInteger(m_Integer, FXFORMAT_SIGNED) + : CFX_ByteString::FormatFloat(m_Float); +} diff --git a/core/fpdfapi/parser/cpdf_number.h b/core/fpdfapi/parser/cpdf_number.h new file mode 100644 index 0000000000..8c708e93f1 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_number.h @@ -0,0 +1,44 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_NUMBER_H_ +#define CORE_FPDFAPI_PARSER_CPDF_NUMBER_H_ + +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/fx_system.h" + +class CPDF_Number : public CPDF_Object { + public: + CPDF_Number(); + explicit CPDF_Number(int value); + explicit CPDF_Number(FX_FLOAT value); + explicit CPDF_Number(const CFX_ByteStringC& str); + + // CPDF_Object. + Type GetType() const override; + CPDF_Object* Clone() const override; + CFX_ByteString GetString() const override; + FX_FLOAT GetNumber() const override; + int GetInteger() const override; + void SetString(const CFX_ByteString& str) override; + bool IsNumber() const override; + CPDF_Number* AsNumber() override; + const CPDF_Number* AsNumber() const override; + + bool IsInteger() const { return m_bInteger; } + + protected: + ~CPDF_Number() override; + + bool m_bInteger; + union { + int m_Integer; + FX_FLOAT m_Float; + }; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_NUMBER_H_ diff --git a/core/fpdfapi/parser/cpdf_object.cpp b/core/fpdfapi/parser/cpdf_object.cpp new file mode 100644 index 0000000000..3bf0a953db --- /dev/null +++ b/core/fpdfapi/parser/cpdf_object.cpp @@ -0,0 +1,165 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_object.h" + +#include + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" +#include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fxcrt/fx_string.h" +#include "third_party/base/stl_util.h" + +CPDF_Object::~CPDF_Object() {} + +CPDF_Object* CPDF_Object::GetDirect() const { + return const_cast(this); +} + +CPDF_Object* CPDF_Object::CloneObjectNonCyclic(bool bDirect) const { + std::set visited_objs; + return CloneNonCyclic(bDirect, &visited_objs); +} + +CPDF_Object* CPDF_Object::CloneDirectObject() const { + return CloneObjectNonCyclic(true); +} + +CPDF_Object* CPDF_Object::CloneNonCyclic( + bool bDirect, + std::set* pVisited) const { + return Clone(); +} + +void CPDF_Object::Release() { + if (m_ObjNum) + return; + + delete this; +} + +CFX_ByteString CPDF_Object::GetString() const { + return CFX_ByteString(); +} + +CFX_WideString CPDF_Object::GetUnicodeText() const { + return CFX_WideString(); +} + +FX_FLOAT CPDF_Object::GetNumber() const { + return 0; +} + +int CPDF_Object::GetInteger() const { + return 0; +} + +CPDF_Dictionary* CPDF_Object::GetDict() const { + return nullptr; +} + +void CPDF_Object::SetString(const CFX_ByteString& str) { + ASSERT(FALSE); +} + +bool CPDF_Object::IsArray() const { + return false; +} + +bool CPDF_Object::IsBoolean() const { + return false; +} + +bool CPDF_Object::IsDictionary() const { + return false; +} + +bool CPDF_Object::IsName() const { + return false; +} + +bool CPDF_Object::IsNumber() const { + return false; +} + +bool CPDF_Object::IsReference() const { + return false; +} + +bool CPDF_Object::IsStream() const { + return false; +} + +bool CPDF_Object::IsString() const { + return false; +} + +CPDF_Array* CPDF_Object::AsArray() { + return nullptr; +} + +const CPDF_Array* CPDF_Object::AsArray() const { + return nullptr; +} + +CPDF_Boolean* CPDF_Object::AsBoolean() { + return nullptr; +} + +const CPDF_Boolean* CPDF_Object::AsBoolean() const { + return nullptr; +} + +CPDF_Dictionary* CPDF_Object::AsDictionary() { + return nullptr; +} + +const CPDF_Dictionary* CPDF_Object::AsDictionary() const { + return nullptr; +} + +CPDF_Name* CPDF_Object::AsName() { + return nullptr; +} + +const CPDF_Name* CPDF_Object::AsName() const { + return nullptr; +} + +CPDF_Number* CPDF_Object::AsNumber() { + return nullptr; +} + +const CPDF_Number* CPDF_Object::AsNumber() const { + return nullptr; +} + +CPDF_Reference* CPDF_Object::AsReference() { + return nullptr; +} + +const CPDF_Reference* CPDF_Object::AsReference() const { + return nullptr; +} + +CPDF_Stream* CPDF_Object::AsStream() { + return nullptr; +} + +const CPDF_Stream* CPDF_Object::AsStream() const { + return nullptr; +} + +CPDF_String* CPDF_Object::AsString() { + return nullptr; +} + +const CPDF_String* CPDF_Object::AsString() const { + return nullptr; +} diff --git a/core/fpdfapi/parser/cpdf_object.h b/core/fpdfapi/parser/cpdf_object.h new file mode 100644 index 0000000000..75400f3a53 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_object.h @@ -0,0 +1,183 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_OBJECT_H_ +#define CORE_FPDFAPI_PARSER_CPDF_OBJECT_H_ + +#include +#include + +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/fx_system.h" + +class CPDF_Array; +class CPDF_Boolean; +class CPDF_Dictionary; +class CPDF_Name; +class CPDF_Null; +class CPDF_Number; +class CPDF_Reference; +class CPDF_Stream; +class CPDF_String; + +class CPDF_Object { + public: + static const uint32_t kInvalidObjNum = static_cast(-1); + enum Type { + BOOLEAN = 1, + NUMBER, + STRING, + NAME, + ARRAY, + DICTIONARY, + STREAM, + NULLOBJ, + REFERENCE + }; + + virtual Type GetType() const = 0; + uint32_t GetObjNum() const { return m_ObjNum; } + uint32_t GetGenNum() const { return m_GenNum; } + + // Create a deep copy of the object. + virtual CPDF_Object* Clone() const = 0; + // Create a deep copy of the object except any reference object be + // copied to the object it points to directly. + virtual CPDF_Object* CloneDirectObject() const; + virtual CPDF_Object* GetDirect() const; + + void Release(); + + virtual CFX_ByteString GetString() const; + virtual CFX_WideString GetUnicodeText() const; + virtual FX_FLOAT GetNumber() const; + virtual int GetInteger() const; + virtual CPDF_Dictionary* GetDict() const; + + virtual void SetString(const CFX_ByteString& str); + + virtual bool IsArray() const; + virtual bool IsBoolean() const; + virtual bool IsDictionary() const; + virtual bool IsName() const; + virtual bool IsNumber() const; + virtual bool IsReference() const; + virtual bool IsStream() const; + virtual bool IsString() const; + + virtual CPDF_Array* AsArray(); + virtual const CPDF_Array* AsArray() const; + virtual CPDF_Boolean* AsBoolean(); + virtual const CPDF_Boolean* AsBoolean() const; + virtual CPDF_Dictionary* AsDictionary(); + virtual const CPDF_Dictionary* AsDictionary() const; + virtual CPDF_Name* AsName(); + virtual const CPDF_Name* AsName() const; + virtual CPDF_Number* AsNumber(); + virtual const CPDF_Number* AsNumber() const; + virtual CPDF_Reference* AsReference(); + virtual const CPDF_Reference* AsReference() const; + virtual CPDF_Stream* AsStream(); + virtual const CPDF_Stream* AsStream() const; + virtual CPDF_String* AsString(); + virtual const CPDF_String* AsString() const; + + protected: + friend class CPDF_Array; + friend class CPDF_Dictionary; + friend class CPDF_Document; + friend class CPDF_IndirectObjectHolder; + friend class CPDF_Parser; + friend class CPDF_Reference; + friend class CPDF_Stream; + friend struct std::default_delete; + + CPDF_Object() : m_ObjNum(0), m_GenNum(0) {} + virtual ~CPDF_Object(); + + CPDF_Object* CloneObjectNonCyclic(bool bDirect) const; + + // Create a deep copy of the object with the option to either + // copy a reference object or directly copy the object it refers to + // when |bDirect| is true. + // Also check cyclic reference against |pVisited|, no copy if it is found. + // Complex objects should implement their own CloneNonCyclic() + // function to properly check for possible loop. + virtual CPDF_Object* CloneNonCyclic( + bool bDirect, + std::set* pVisited) const; + + uint32_t m_ObjNum; + uint32_t m_GenNum; + + private: + CPDF_Object(const CPDF_Object& src) {} +}; + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} +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; +} + +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; +} + +#endif // CORE_FPDFAPI_PARSER_CPDF_OBJECT_H_ diff --git a/core/fpdfapi/parser/cpdf_object_unittest.cpp b/core/fpdfapi/parser/cpdf_object_unittest.cpp new file mode 100644 index 0000000000..b2177afd8a --- /dev/null +++ b/core/fpdfapi/parser/cpdf_object_unittest.cpp @@ -0,0 +1,835 @@ +// Copyright 2016 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. + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_boolean.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_null.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_string.h" + +#include +#include +#include + +#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" +#include "core/fxcrt/fx_basic.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +using ScopedArray = std::unique_ptr>; +using ScopedDict = + std::unique_ptr>; + +void TestArrayAccessors(const CPDF_Array* arr, + size_t index, + const char* str_val, + const char* const_str_val, + int int_val, + float float_val, + CPDF_Array* arr_val, + CPDF_Dictionary* dict_val, + CPDF_Stream* stream_val) { + EXPECT_STREQ(str_val, arr->GetStringAt(index).c_str()); + EXPECT_EQ(int_val, arr->GetIntegerAt(index)); + EXPECT_EQ(float_val, arr->GetNumberAt(index)); + EXPECT_EQ(float_val, arr->GetFloatAt(index)); + EXPECT_EQ(arr_val, arr->GetArrayAt(index)); + EXPECT_EQ(dict_val, arr->GetDictAt(index)); + EXPECT_EQ(stream_val, arr->GetStreamAt(index)); +} + +} // namespace + +class PDFObjectsTest : public testing::Test { + public: + void SetUp() override { + // Initialize different kinds of objects. + // Boolean objects. + CPDF_Boolean* boolean_false_obj = new CPDF_Boolean(false); + CPDF_Boolean* boolean_true_obj = new CPDF_Boolean(true); + // Number objects. + CPDF_Number* number_int_obj = new CPDF_Number(1245); + CPDF_Number* number_float_obj = new CPDF_Number(9.00345f); + // String objects. + CPDF_String* str_reg_obj = new CPDF_String(L"A simple test"); + CPDF_String* str_spec_obj = new CPDF_String(L"\t\n"); + // Name object. + CPDF_Name* name_obj = new CPDF_Name("space"); + // Array object. + 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->SetFor("bool", new CPDF_Boolean(false)); + m_DictObj->SetFor("num", new CPDF_Number(0.23f)); + // Stream object. + const char content[] = "abcdefghijklmnopqrstuvwxyz"; + size_t buf_len = FX_ArraySize(content); + uint8_t* buf = reinterpret_cast(malloc(buf_len)); + memcpy(buf, content, buf_len); + m_StreamDictObj = new CPDF_Dictionary(); + m_StreamDictObj->SetFor("key1", new CPDF_String(L" test dict")); + m_StreamDictObj->SetFor("key2", new CPDF_Number(-1)); + CPDF_Stream* stream_obj = new CPDF_Stream(buf, buf_len, m_StreamDictObj); + // Null Object. + CPDF_Null* null_obj = new CPDF_Null; + // 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, m_ArrayObj, m_DictObj, + stream_obj, null_obj}; + 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()); + 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->GetObjectAt(i), array2->GetObjectAt(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->GetObjectFor(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>; + + // m_ObjHolder needs to be declared first and destructed last since it also + // 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) { + const char* const direct_obj_results[] = { + "false", "true", "1245", "9.00345", "A simple test", "\t\n", "space", + "", "", "", ""}; + // Check for direct objects. + for (size_t i = 0; i < m_DirectObjs.size(); ++i) + EXPECT_STREQ(direct_obj_results[i], m_DirectObjs[i]->GetString().c_str()); + + // Check indirect references. + const char* const indirect_obj_results[] = {"true", "1245", "\t\n", "space", + "", "", ""}; + for (size_t i = 0; i < m_RefObjs.size(); ++i) { + EXPECT_STREQ(indirect_obj_results[i], m_RefObjs[i]->GetString().c_str()); + } +} + +TEST_F(PDFObjectsTest, GetUnicodeText) { + const wchar_t* const 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(direct_obj_results[i], + m_DirectObjs[i]->GetUnicodeText().c_str()); + } + + // Check indirect references. + for (const auto& it : m_RefObjs) + EXPECT_STREQ(L"", it->GetUnicodeText().c_str()); +} + +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 (size_t i = 0; i < m_DirectObjs.size(); ++i) + EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetNumber()); + + // Check indirect references. + const FX_FLOAT indirect_obj_results[] = {0, 1245, 0, 0, 0, 0, 0}; + for (size_t i = 0; i < m_RefObjs.size(); ++i) + EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetNumber()); +} + +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 (size_t i = 0; i < m_DirectObjs.size(); ++i) + EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetInteger()); + + // Check indirect references. + const int indirect_obj_results[] = {1, 1245, 0, 0, 0, 0, 0}; + for (size_t i = 0; i < m_RefObjs.size(); ++i) + EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetInteger()); +} + +TEST_F(PDFObjectsTest, GetDict) { + const CPDF_Dictionary* const direct_obj_results[] = { + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, m_DictObj, m_StreamDictObj, nullptr}; + // Check for direct objects. + for (size_t i = 0; i < m_DirectObjs.size(); ++i) + EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetDict()); + + // Check indirect references. + const CPDF_Dictionary* const indirect_obj_results[] = { + nullptr, nullptr, nullptr, nullptr, nullptr, m_DictObj, m_StreamDictObj}; + for (size_t i = 0; i < m_RefObjs.size(); ++i) + EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetDict()); +} + +TEST_F(PDFObjectsTest, GetArray) { + const CPDF_Array* const 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(direct_obj_results[i], m_DirectObjs[i]->AsArray()); + + // Check indirect references. + for (const auto& it : m_RefObjs) + EXPECT_EQ(nullptr, it->AsArray()); +} + +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_DirectObjTypes[i], m_DirectObjs[i]->GetType()); + + // Check indirect references. + for (const auto& it : m_RefObjs) + EXPECT_EQ(CPDF_Object::REFERENCE, it->GetType()); +} + +TEST_F(PDFObjectsTest, GetDirect) { + // Check for direct objects. + for (size_t i = 0; i < m_DirectObjs.size(); ++i) + EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->GetDirect()); + + // Check indirect references. + for (size_t i = 0; i < m_RefObjs.size(); ++i) + EXPECT_EQ(m_IndirectObjs[i], m_RefObjs[i]->GetDirect()); +} + +TEST_F(PDFObjectsTest, SetString) { + // Check for direct objects. + const char* const set_values[] = {"true", "fake", "3.125f", "097", + "changed", "", "NewName"}; + const char* const 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(expected[i], m_DirectObjs[i]->GetString().c_str()); + } +} + +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].get(), m_DirectObjs[i]->AsArray()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsArray()); + EXPECT_EQ(nullptr, m_DirectObjs[i]->AsArray()); + } + + if (m_DirectObjTypes[i] == CPDF_Object::BOOLEAN) { + EXPECT_TRUE(m_DirectObjs[i]->IsBoolean()); + EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsBoolean()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsBoolean()); + EXPECT_EQ(nullptr, m_DirectObjs[i]->AsBoolean()); + } + + if (m_DirectObjTypes[i] == CPDF_Object::NAME) { + EXPECT_TRUE(m_DirectObjs[i]->IsName()); + EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsName()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsName()); + EXPECT_EQ(nullptr, m_DirectObjs[i]->AsName()); + } + + if (m_DirectObjTypes[i] == CPDF_Object::NUMBER) { + EXPECT_TRUE(m_DirectObjs[i]->IsNumber()); + EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsNumber()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsNumber()); + EXPECT_EQ(nullptr, m_DirectObjs[i]->AsNumber()); + } + + if (m_DirectObjTypes[i] == CPDF_Object::STRING) { + EXPECT_TRUE(m_DirectObjs[i]->IsString()); + EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsString()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsString()); + EXPECT_EQ(nullptr, m_DirectObjs[i]->AsString()); + } + + if (m_DirectObjTypes[i] == CPDF_Object::DICTIONARY) { + EXPECT_TRUE(m_DirectObjs[i]->IsDictionary()); + EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsDictionary()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsDictionary()); + EXPECT_EQ(nullptr, m_DirectObjs[i]->AsDictionary()); + } + + if (m_DirectObjTypes[i] == CPDF_Object::STREAM) { + EXPECT_TRUE(m_DirectObjs[i]->IsStream()); + EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsStream()); + } else { + EXPECT_FALSE(m_DirectObjs[i]->IsStream()); + EXPECT_EQ(nullptr, m_DirectObjs[i]->AsStream()); + } + + EXPECT_FALSE(m_DirectObjs[i]->IsReference()); + EXPECT_EQ(nullptr, m_DirectObjs[i]->AsReference()); + } + // Check indirect references. + for (size_t i = 0; i < m_RefObjs.size(); ++i) { + EXPECT_TRUE(m_RefObjs[i]->IsReference()); + EXPECT_EQ(m_RefObjs[i].get(), m_RefObjs[i]->AsReference()); + } +} + +TEST(PDFArrayTest, GetMatrix) { + float elems[][6] = {{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {1, 2, 3, 4, 5, 6}, + {2.3f, 4.05f, 3, -2, -3, 0.0f}, + {0.05f, 0.1f, 0.56f, 0.67f, 1.34f, 99.9f}}; + for (size_t i = 0; i < FX_ArraySize(elems); ++i) { + ScopedArray arr(new CPDF_Array); + CFX_Matrix matrix(elems[i][0], elems[i][1], elems[i][2], elems[i][3], + elems[i][4], elems[i][5]); + for (size_t j = 0; j < 6; ++j) + arr->AddNumber(elems[i][j]); + CFX_Matrix arr_matrix = arr->GetMatrix(); + EXPECT_EQ(matrix.GetA(), arr_matrix.GetA()); + EXPECT_EQ(matrix.GetB(), arr_matrix.GetB()); + EXPECT_EQ(matrix.GetC(), arr_matrix.GetC()); + EXPECT_EQ(matrix.GetD(), arr_matrix.GetD()); + EXPECT_EQ(matrix.GetE(), arr_matrix.GetE()); + EXPECT_EQ(matrix.GetF(), arr_matrix.GetF()); + } +} + +TEST(PDFArrayTest, GetRect) { + float elems[][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, + {1, 2, 5, 6}, + {2.3f, 4.05f, -3, 0.0f}, + {0.05f, 0.1f, 1.34f, 99.9f}}; + for (size_t i = 0; i < FX_ArraySize(elems); ++i) { + ScopedArray arr(new CPDF_Array); + CFX_FloatRect rect(elems[i]); + for (size_t j = 0; j < 4; ++j) + arr->AddNumber(elems[i][j]); + CFX_FloatRect arr_rect = arr->GetRect(); + EXPECT_EQ(rect.left, arr_rect.left); + EXPECT_EQ(rect.right, arr_rect.right); + EXPECT_EQ(rect.bottom, arr_rect.bottom); + EXPECT_EQ(rect.top, arr_rect.top); + } +} + +TEST(PDFArrayTest, GetTypeAt) { + { + // Boolean array. + const bool vals[] = {true, false, false, true, true}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(vals); ++i) + arr->InsertAt(i, new CPDF_Boolean(vals[i])); + for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + TestArrayAccessors(arr.get(), i, // Array and index. + vals[i] ? "true" : "false", // String value. + nullptr, // Const string value. + vals[i] ? 1 : 0, // Integer value. + 0, // Float value. + nullptr, // Array value. + nullptr, // Dictionary value. + nullptr); // Stream value. + } + } + { + // Integer array. + const int vals[] = {10, 0, -345, 2089345456, -1000000000, 567, 93658767}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(vals); ++i) + arr->InsertAt(i, new CPDF_Number(vals[i])); + for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + char buf[33]; + TestArrayAccessors(arr.get(), i, // Array and index. + FXSYS_itoa(vals[i], buf, 10), // String value. + nullptr, // Const string value. + vals[i], // Integer value. + vals[i], // Float value. + nullptr, // Array value. + nullptr, // Dictionary value. + nullptr); // Stream value. + } + } + { + // Float array. + const float vals[] = {0.0f, 0, 10, 10.0f, 0.0345f, + 897.34f, -2.5f, -1.0f, -345.0f, -0.0f}; + const char* const expected_str[] = { + "0", "0", "10", "10", "0.0345", "897.34", "-2.5", "-1", "-345", "0"}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + arr->InsertAt(i, new CPDF_Number(vals[i])); + } + for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + TestArrayAccessors(arr.get(), i, // Array and index. + expected_str[i], // String value. + nullptr, // Const string value. + vals[i], // Integer value. + vals[i], // Float value. + nullptr, // Array value. + nullptr, // Dictionary value. + nullptr); // Stream value. + } + } + { + // String and name array + const char* const vals[] = {"this", "adsde$%^", "\r\t", "\"012", + ".", "EYREW", "It is a joke :)"}; + ScopedArray string_array(new CPDF_Array); + ScopedArray name_array(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + string_array->InsertAt(i, new CPDF_String(vals[i], false)); + name_array->InsertAt(i, new CPDF_Name(vals[i])); + } + for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + TestArrayAccessors(string_array.get(), i, // Array and index. + vals[i], // String value. + vals[i], // Const string value. + 0, // Integer value. + 0, // Float value. + nullptr, // Array value. + nullptr, // Dictionary value. + nullptr); // Stream value. + TestArrayAccessors(name_array.get(), i, // Array and index. + vals[i], // String value. + vals[i], // Const string value. + 0, // Integer value. + 0, // Float value. + nullptr, // Array value. + nullptr, // Dictionary value. + nullptr); // Stream value. + } + } + { + // Null element array. + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < 3; ++i) + arr->InsertAt(i, new CPDF_Null); + for (size_t i = 0; i < 3; ++i) { + TestArrayAccessors(arr.get(), i, // Array and index. + "", // String value. + nullptr, // Const string value. + 0, // Integer value. + 0, // Float value. + nullptr, // Array value. + nullptr, // Dictionary value. + nullptr); // Stream value. + } + } + { + // Array of array. + CPDF_Array* vals[3]; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < 3; ++i) { + vals[i] = new CPDF_Array; + for (size_t j = 0; j < 3; ++j) { + int value = j + 100; + vals[i]->InsertAt(i, new CPDF_Number(value)); + } + arr->InsertAt(i, vals[i]); + } + for (size_t i = 0; i < 3; ++i) { + TestArrayAccessors(arr.get(), i, // Array and index. + "", // String value. + nullptr, // Const string value. + 0, // Integer value. + 0, // Float value. + vals[i], // Array value. + nullptr, // Dictionary value. + nullptr); // Stream value. + } + } + { + // Dictionary array. + CPDF_Dictionary* vals[3]; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < 3; ++i) { + vals[i] = new CPDF_Dictionary(); + for (size_t j = 0; j < 3; ++j) { + std::string key("key"); + char buf[33]; + key.append(FXSYS_itoa(j, buf, 10)); + int value = j + 200; + vals[i]->SetFor(key.c_str(), new CPDF_Number(value)); + } + arr->InsertAt(i, vals[i]); + } + for (size_t i = 0; i < 3; ++i) { + TestArrayAccessors(arr.get(), i, // Array and index. + "", // String value. + nullptr, // Const string value. + 0, // Integer value. + 0, // Float value. + nullptr, // Array value. + vals[i], // Dictionary value. + nullptr); // Stream value. + } + } + { + // Stream array. + CPDF_Dictionary* vals[3]; + CPDF_Stream* stream_vals[3]; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < 3; ++i) { + vals[i] = new CPDF_Dictionary(); + for (size_t j = 0; j < 3; ++j) { + std::string key("key"); + char buf[33]; + key.append(FXSYS_itoa(j, buf, 10)); + int value = j + 200; + vals[i]->SetFor(key.c_str(), new CPDF_Number(value)); + } + uint8_t content[] = "content: this is a stream"; + size_t data_size = FX_ArraySize(content); + uint8_t* data = reinterpret_cast(malloc(data_size)); + memcpy(data, content, data_size); + stream_vals[i] = new CPDF_Stream(data, data_size, vals[i]); + arr->InsertAt(i, stream_vals[i]); + } + for (size_t i = 0; i < 3; ++i) { + TestArrayAccessors(arr.get(), i, // Array and index. + "", // String value. + nullptr, // Const string value. + 0, // Integer value. + 0, // Float value. + nullptr, // Array value. + vals[i], // Dictionary value. + stream_vals[i]); // Stream value. + } + } + { + // Mixed array. + ScopedArray arr(new CPDF_Array); + // Array arr will take ownership of all the objects inserted. + arr->InsertAt(0, new CPDF_Boolean(true)); + arr->InsertAt(1, new CPDF_Boolean(false)); + arr->InsertAt(2, new CPDF_Number(0)); + arr->InsertAt(3, new CPDF_Number(-1234)); + arr->InsertAt(4, new CPDF_Number(2345.0f)); + arr->InsertAt(5, new CPDF_Number(0.05f)); + arr->InsertAt(6, new CPDF_String("", false)); + arr->InsertAt(7, new CPDF_String("It is a test!", false)); + arr->InsertAt(8, new CPDF_Name("NAME")); + arr->InsertAt(9, new CPDF_Name("test")); + arr->InsertAt(10, new CPDF_Null()); + CPDF_Array* arr_val = new CPDF_Array; + arr_val->AddNumber(1); + arr_val->AddNumber(2); + arr->InsertAt(11, arr_val); + CPDF_Dictionary* dict_val = new CPDF_Dictionary(); + dict_val->SetFor("key1", new CPDF_String("Linda", false)); + dict_val->SetFor("key2", new CPDF_String("Zoe", false)); + arr->InsertAt(12, dict_val); + CPDF_Dictionary* stream_dict = new CPDF_Dictionary(); + stream_dict->SetFor("key1", new CPDF_String("John", false)); + stream_dict->SetFor("key2", new CPDF_String("King", false)); + uint8_t data[] = "A stream for test"; + // The data buffer will be owned by stream object, so it needs to be + // dynamically allocated. + size_t buf_size = sizeof(data); + uint8_t* buf = reinterpret_cast(malloc(buf_size)); + memcpy(buf, data, buf_size); + CPDF_Stream* stream_val = new CPDF_Stream(buf, buf_size, stream_dict); + arr->InsertAt(13, stream_val); + const char* const expected_str[] = { + "true", "false", "0", "-1234", "2345", "0.05", "", + "It is a test!", "NAME", "test", "", "", "", ""}; + const int expected_int[] = {1, 0, 0, -1234, 2345, 0, 0, + 0, 0, 0, 0, 0, 0, 0}; + const float expected_float[] = {0, 0, 0, -1234, 2345, 0.05f, 0, + 0, 0, 0, 0, 0, 0, 0}; + for (size_t i = 0; i < arr->GetCount(); ++i) { + EXPECT_STREQ(expected_str[i], arr->GetStringAt(i).c_str()); + EXPECT_EQ(expected_int[i], arr->GetIntegerAt(i)); + EXPECT_EQ(expected_float[i], arr->GetNumberAt(i)); + EXPECT_EQ(expected_float[i], arr->GetFloatAt(i)); + if (i == 11) + EXPECT_EQ(arr_val, arr->GetArrayAt(i)); + else + EXPECT_EQ(nullptr, arr->GetArrayAt(i)); + if (i == 13) { + EXPECT_EQ(stream_dict, arr->GetDictAt(i)); + EXPECT_EQ(stream_val, arr->GetStreamAt(i)); + } else { + EXPECT_EQ(nullptr, arr->GetStreamAt(i)); + if (i == 12) + EXPECT_EQ(dict_val, arr->GetDictAt(i)); + else + EXPECT_EQ(nullptr, arr->GetDictAt(i)); + } + } + } +} + +TEST(PDFArrayTest, AddNumber) { + float vals[] = {1.0f, -1.0f, 0, 0.456734f, + 12345.54321f, 0.5f, 1000, 0.000045f}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(vals); ++i) + arr->AddNumber(vals[i]); + for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + EXPECT_EQ(CPDF_Object::NUMBER, arr->GetObjectAt(i)->GetType()); + EXPECT_EQ(vals[i], arr->GetObjectAt(i)->GetNumber()); + } +} + +TEST(PDFArrayTest, AddInteger) { + int vals[] = {0, 1, 934435456, 876, 10000, -1, -24354656, -100}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(vals); ++i) + arr->AddInteger(vals[i]); + for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + EXPECT_EQ(CPDF_Object::NUMBER, arr->GetObjectAt(i)->GetType()); + EXPECT_EQ(vals[i], arr->GetObjectAt(i)->GetNumber()); + } +} + +TEST(PDFArrayTest, AddStringAndName) { + const char* vals[] = {"", "a", "ehjhRIOYTTFdfcdnv", "122323", + "$#%^&**", " ", "This is a test.\r\n"}; + ScopedArray string_array(new CPDF_Array); + ScopedArray name_array(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + string_array->AddString(vals[i]); + name_array->AddName(vals[i]); + } + for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + EXPECT_EQ(CPDF_Object::STRING, string_array->GetObjectAt(i)->GetType()); + EXPECT_STREQ(vals[i], string_array->GetObjectAt(i)->GetString().c_str()); + EXPECT_EQ(CPDF_Object::NAME, name_array->GetObjectAt(i)->GetType()); + EXPECT_STREQ(vals[i], name_array->GetObjectAt(i)->GetString().c_str()); + } +} + +TEST(PDFArrayTest, AddReferenceAndGetObjectAt) { + std::unique_ptr holder( + new CPDF_IndirectObjectHolder()); + CPDF_Boolean* boolean_obj = new CPDF_Boolean(true); + CPDF_Number* int_obj = new CPDF_Number(-1234); + CPDF_Number* float_obj = new CPDF_Number(2345.089f); + CPDF_String* str_obj = new CPDF_String("Adsfdsf 343434 %&&*\n", false); + CPDF_Name* name_obj = new CPDF_Name("Title:"); + CPDF_Null* null_obj = new CPDF_Null(); + CPDF_Object* indirect_objs[] = {boolean_obj, int_obj, float_obj, + str_obj, name_obj, null_obj}; + unsigned int obj_nums[] = {2, 4, 7, 2345, 799887, 1}; + ScopedArray arr(new CPDF_Array); + ScopedArray arr1(new CPDF_Array); + // Create two arrays of references by different AddReference() APIs. + for (size_t i = 0; i < FX_ArraySize(indirect_objs); ++i) { + // All the indirect objects inserted will be owned by holder. + holder->ReplaceIndirectObjectIfHigherGeneration(obj_nums[i], + indirect_objs[i]); + arr->AddReference(holder.get(), obj_nums[i]); + arr1->AddReference(holder.get(), indirect_objs[i]->GetObjNum()); + } + // Check indirect objects. + for (size_t i = 0; i < FX_ArraySize(obj_nums); ++i) + EXPECT_EQ(indirect_objs[i], holder->GetOrParseIndirectObject(obj_nums[i])); + // Check arrays. + EXPECT_EQ(arr->GetCount(), arr1->GetCount()); + for (size_t i = 0; i < arr->GetCount(); ++i) { + EXPECT_EQ(CPDF_Object::REFERENCE, arr->GetObjectAt(i)->GetType()); + EXPECT_EQ(indirect_objs[i], arr->GetObjectAt(i)->GetDirect()); + EXPECT_EQ(indirect_objs[i], arr->GetDirectObjectAt(i)); + EXPECT_EQ(CPDF_Object::REFERENCE, arr1->GetObjectAt(i)->GetType()); + EXPECT_EQ(indirect_objs[i], arr1->GetObjectAt(i)->GetDirect()); + EXPECT_EQ(indirect_objs[i], arr1->GetDirectObjectAt(i)); + } +} + +TEST(PDFArrayTest, CloneDirectObject) { + CPDF_IndirectObjectHolder objects_holder; + ScopedArray array(new CPDF_Array); + array->AddReference(&objects_holder, 1234); + ASSERT_EQ(1U, array->GetCount()); + CPDF_Object* obj = array->GetObjectAt(0); + ASSERT_TRUE(obj); + EXPECT_TRUE(obj->IsReference()); + + CPDF_Object* cloned_array_object = array->CloneDirectObject(); + ASSERT_TRUE(cloned_array_object); + ASSERT_TRUE(cloned_array_object->IsArray()); + + ScopedArray cloned_array(cloned_array_object->AsArray()); + ASSERT_EQ(1U, cloned_array->GetCount()); + CPDF_Object* cloned_obj = cloned_array->GetObjectAt(0); + EXPECT_FALSE(cloned_obj); +} + +TEST(PDFDictionaryTest, CloneDirectObject) { + CPDF_IndirectObjectHolder objects_holder; + ScopedDict dict(new CPDF_Dictionary()); + dict->SetReferenceFor("foo", &objects_holder, 1234); + ASSERT_EQ(1U, dict->GetCount()); + CPDF_Object* obj = dict->GetObjectFor("foo"); + ASSERT_TRUE(obj); + EXPECT_TRUE(obj->IsReference()); + + CPDF_Object* cloned_dict_object = dict->CloneDirectObject(); + ASSERT_TRUE(cloned_dict_object); + ASSERT_TRUE(cloned_dict_object->IsDictionary()); + + ScopedDict cloned_dict(cloned_dict_object->AsDictionary()); + ASSERT_EQ(1U, cloned_dict->GetCount()); + CPDF_Object* cloned_obj = cloned_dict->GetObjectFor("foo"); + EXPECT_FALSE(cloned_obj); +} + +TEST(PDFObjectTest, CloneCheckLoop) { + { + // Create an object with a reference loop. + ScopedArray arr_obj(new CPDF_Array); + // Dictionary object. + CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); + dict_obj->SetFor("arr", arr_obj.get()); + arr_obj->InsertAt(0, dict_obj); + + // Clone this object to see whether stack overflow will be triggered. + ScopedArray cloned_array(arr_obj->Clone()->AsArray()); + // Cloned object should be the same as the original. + ASSERT_TRUE(cloned_array); + EXPECT_EQ(1u, cloned_array->GetCount()); + CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0); + ASSERT_TRUE(cloned_dict); + ASSERT_TRUE(cloned_dict->IsDictionary()); + // Recursively referenced object is not cloned. + EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("arr")); + } + { + CPDF_IndirectObjectHolder objects_holder; + // Create an object with a reference loop. + CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); + CPDF_Array* arr_obj = new CPDF_Array; + objects_holder.AddIndirectObject(dict_obj); + EXPECT_EQ(1u, dict_obj->GetObjNum()); + dict_obj->SetFor("arr", arr_obj); + arr_obj->InsertAt( + 0, new CPDF_Reference(&objects_holder, dict_obj->GetObjNum())); + CPDF_Object* elem0 = arr_obj->GetObjectAt(0); + ASSERT_TRUE(elem0); + ASSERT_TRUE(elem0->IsReference()); + EXPECT_EQ(1u, elem0->AsReference()->GetRefObjNum()); + EXPECT_EQ(dict_obj, elem0->AsReference()->GetDirect()); + + // Clone this object to see whether stack overflow will be triggered. + ScopedDict cloned_dict(ToDictionary(dict_obj->CloneDirectObject())); + // Cloned object should be the same as the original. + ASSERT_TRUE(cloned_dict); + CPDF_Object* cloned_arr = cloned_dict->GetObjectFor("arr"); + ASSERT_TRUE(cloned_arr); + ASSERT_TRUE(cloned_arr->IsArray()); + EXPECT_EQ(1u, cloned_arr->AsArray()->GetCount()); + // Recursively referenced object is not cloned. + EXPECT_EQ(nullptr, cloned_arr->AsArray()->GetObjectAt(0)); + } +} diff --git a/core/fpdfapi/parser/cpdf_parser.cpp b/core/fpdfapi/parser/cpdf_parser.cpp new file mode 100644 index 0000000000..17539101a1 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_parser.cpp @@ -0,0 +1,1637 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_parser.h" + +#include + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_crypto_handler.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_security_handler.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_syntax_parser.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcrt/fx_ext.h" +#include "core/fxcrt/fx_safe_types.h" +#include "third_party/base/stl_util.h" + +namespace { + +// A limit on the size of the xref table. Theoretical limits are higher, but +// this may be large enough in practice. +const int32_t kMaxXRefSize = 1048576; + +uint32_t GetVarInt(const uint8_t* p, int32_t n) { + uint32_t result = 0; + for (int32_t i = 0; i < n; ++i) + result = result * 256 + p[i]; + return result; +} + +int32_t GetStreamNCount(CPDF_StreamAcc* pObjStream) { + return pObjStream->GetDict()->GetIntegerFor("N"); +} + +int32_t GetStreamFirst(CPDF_StreamAcc* pObjStream) { + return pObjStream->GetDict()->GetIntegerFor("First"); +} + +} // namespace + +CPDF_Parser::CPDF_Parser() + : m_pDocument(nullptr), + m_bHasParsed(false), + m_bOwnFileRead(true), + m_FileVersion(0), + m_pTrailer(nullptr), + m_pEncryptDict(nullptr), + m_bVersionUpdated(false), + m_pLinearized(nullptr), + m_dwFirstPageNo(0), + m_dwXrefStartObjNum(0) { + m_pSyntax.reset(new CPDF_SyntaxParser); +} + +CPDF_Parser::~CPDF_Parser() { + if (m_pTrailer) + m_pTrailer->Release(); + + ReleaseEncryptHandler(); + SetEncryptDictionary(nullptr); + + if (m_bOwnFileRead && m_pSyntax->m_pFileAccess) { + m_pSyntax->m_pFileAccess->Release(); + m_pSyntax->m_pFileAccess = nullptr; + } + + int32_t iLen = m_Trailers.GetSize(); + for (int32_t i = 0; i < iLen; ++i) { + if (CPDF_Dictionary* trailer = m_Trailers.GetAt(i)) + trailer->Release(); + } + + if (m_pLinearized) + m_pLinearized->Release(); +} + +uint32_t CPDF_Parser::GetLastObjNum() const { + return m_ObjectInfo.empty() ? 0 : m_ObjectInfo.rbegin()->first; +} + +bool CPDF_Parser::IsValidObjectNumber(uint32_t objnum) const { + return !m_ObjectInfo.empty() && objnum <= m_ObjectInfo.rbegin()->first; +} + +FX_FILESIZE CPDF_Parser::GetObjectPositionOrZero(uint32_t objnum) const { + auto it = m_ObjectInfo.find(objnum); + return it != m_ObjectInfo.end() ? it->second.pos : 0; +} + +uint8_t CPDF_Parser::GetObjectType(uint32_t objnum) const { + ASSERT(IsValidObjectNumber(objnum)); + auto it = m_ObjectInfo.find(objnum); + return it != m_ObjectInfo.end() ? it->second.type : 0; +} + +uint16_t CPDF_Parser::GetObjectGenNum(uint32_t objnum) const { + ASSERT(IsValidObjectNumber(objnum)); + auto it = m_ObjectInfo.find(objnum); + return it != m_ObjectInfo.end() ? it->second.gennum : 0; +} + +bool CPDF_Parser::IsObjectFreeOrNull(uint32_t objnum) const { + uint8_t type = GetObjectType(objnum); + return type == 0 || type == 255; +} + +void CPDF_Parser::SetEncryptDictionary(CPDF_Dictionary* pDict) { + m_pEncryptDict = pDict; +} + +CPDF_CryptoHandler* CPDF_Parser::GetCryptoHandler() { + return m_pSyntax->m_pCryptoHandler.get(); +} + +IFX_FileRead* CPDF_Parser::GetFileAccess() const { + return m_pSyntax->m_pFileAccess; +} + +void CPDF_Parser::ShrinkObjectMap(uint32_t objnum) { + if (objnum == 0) { + m_ObjectInfo.clear(); + return; + } + + auto it = m_ObjectInfo.lower_bound(objnum); + while (it != m_ObjectInfo.end()) { + auto saved_it = it++; + m_ObjectInfo.erase(saved_it); + } + + if (!pdfium::ContainsKey(m_ObjectInfo, objnum - 1)) + m_ObjectInfo[objnum - 1].pos = 0; +} + +CPDF_Parser::Error CPDF_Parser::StartParse(IFX_FileRead* pFileAccess, + CPDF_Document* pDocument) { + ASSERT(!m_bHasParsed); + m_bHasParsed = true; + + m_bXRefStream = FALSE; + m_LastXRefOffset = 0; + m_bOwnFileRead = true; + + int32_t offset = GetHeaderOffset(pFileAccess); + if (offset == -1) { + if (pFileAccess) + pFileAccess->Release(); + return FORMAT_ERROR; + } + m_pSyntax->InitParser(pFileAccess, offset); + + uint8_t ch; + if (!m_pSyntax->GetCharAt(5, ch)) + return FORMAT_ERROR; + if (std::isdigit(ch)) + m_FileVersion = FXSYS_toDecimalDigit(static_cast(ch)) * 10; + + if (!m_pSyntax->GetCharAt(7, ch)) + return FORMAT_ERROR; + if (std::isdigit(ch)) + m_FileVersion += FXSYS_toDecimalDigit(static_cast(ch)); + + if (m_pSyntax->m_FileLen < m_pSyntax->m_HeaderOffset + 9) + return FORMAT_ERROR; + + m_pSyntax->RestorePos(m_pSyntax->m_FileLen - m_pSyntax->m_HeaderOffset - 9); + m_pDocument = pDocument; + + FX_BOOL bXRefRebuilt = FALSE; + if (m_pSyntax->SearchWord("startxref", TRUE, FALSE, 4096)) { + m_SortedOffset.insert(m_pSyntax->SavePos()); + m_pSyntax->GetKeyword(); + + bool bNumber; + CFX_ByteString xrefpos_str = m_pSyntax->GetNextWord(&bNumber); + if (!bNumber) + return FORMAT_ERROR; + + m_LastXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str.c_str()); + if (!LoadAllCrossRefV4(m_LastXRefOffset) && + !LoadAllCrossRefV5(m_LastXRefOffset)) { + if (!RebuildCrossRef()) + return FORMAT_ERROR; + + bXRefRebuilt = TRUE; + m_LastXRefOffset = 0; + } + } else { + if (!RebuildCrossRef()) + return FORMAT_ERROR; + + bXRefRebuilt = TRUE; + } + Error eRet = SetEncryptHandler(); + if (eRet != SUCCESS) + return eRet; + + m_pDocument->LoadDoc(); + if (!m_pDocument->GetRoot() || m_pDocument->GetPageCount() == 0) { + if (bXRefRebuilt) + return FORMAT_ERROR; + + ReleaseEncryptHandler(); + if (!RebuildCrossRef()) + return FORMAT_ERROR; + + eRet = SetEncryptHandler(); + if (eRet != SUCCESS) + return eRet; + + m_pDocument->LoadDoc(); + if (!m_pDocument->GetRoot()) + return FORMAT_ERROR; + } + if (GetRootObjNum() == 0) { + ReleaseEncryptHandler(); + if (!RebuildCrossRef() || GetRootObjNum() == 0) + return FORMAT_ERROR; + + eRet = SetEncryptHandler(); + if (eRet != SUCCESS) + return eRet; + } + if (m_pSecurityHandler && !m_pSecurityHandler->IsMetadataEncrypted()) { + CPDF_Reference* pMetadata = + ToReference(m_pDocument->GetRoot()->GetObjectFor("Metadata")); + if (pMetadata) + m_pSyntax->m_MetadataObjnum = pMetadata->GetRefObjNum(); + } + return SUCCESS; +} +CPDF_Parser::Error CPDF_Parser::SetEncryptHandler() { + ReleaseEncryptHandler(); + SetEncryptDictionary(nullptr); + + if (!m_pTrailer) + return FORMAT_ERROR; + + CPDF_Object* pEncryptObj = m_pTrailer->GetObjectFor("Encrypt"); + if (pEncryptObj) { + if (CPDF_Dictionary* pEncryptDict = pEncryptObj->AsDictionary()) { + SetEncryptDictionary(pEncryptDict); + } else if (CPDF_Reference* pRef = pEncryptObj->AsReference()) { + pEncryptObj = m_pDocument->GetOrParseIndirectObject(pRef->GetRefObjNum()); + if (pEncryptObj) + SetEncryptDictionary(pEncryptObj->GetDict()); + } + } + + if (m_pEncryptDict) { + CFX_ByteString filter = m_pEncryptDict->GetStringFor("Filter"); + std::unique_ptr pSecurityHandler; + Error err = HANDLER_ERROR; + if (filter == "Standard") { + pSecurityHandler.reset(new CPDF_SecurityHandler); + err = PASSWORD_ERROR; + } + if (!pSecurityHandler) + return HANDLER_ERROR; + + if (!pSecurityHandler->OnInit(this, m_pEncryptDict)) + return err; + + m_pSecurityHandler = std::move(pSecurityHandler); + std::unique_ptr pCryptoHandler( + m_pSecurityHandler->CreateCryptoHandler()); + if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler.get())) + return HANDLER_ERROR; + m_pSyntax->SetEncrypt(std::move(pCryptoHandler)); + } + return SUCCESS; +} + +void CPDF_Parser::ReleaseEncryptHandler() { + m_pSyntax->m_pCryptoHandler.reset(); + m_pSecurityHandler.reset(); +} + +FX_FILESIZE CPDF_Parser::GetObjectOffset(uint32_t objnum) const { + if (!IsValidObjectNumber(objnum)) + return 0; + + if (GetObjectType(objnum) == 1) + return GetObjectPositionOrZero(objnum); + + if (GetObjectType(objnum) == 2) { + FX_FILESIZE pos = GetObjectPositionOrZero(objnum); + return GetObjectPositionOrZero(pos); + } + return 0; +} + +// Ideally, all the cross reference entries should be verified. +// In reality, we rarely see well-formed cross references don't match +// with the objects. crbug/602650 showed a case where object numbers +// in the cross reference table are all off by one. +bool CPDF_Parser::VerifyCrossRefV4() { + for (const auto& it : m_ObjectInfo) { + if (it.second.pos == 0) + continue; + // Find the first non-zero position. + FX_FILESIZE SavedPos = m_pSyntax->SavePos(); + m_pSyntax->RestorePos(it.second.pos); + bool is_num = false; + CFX_ByteString num_str = m_pSyntax->GetNextWord(&is_num); + m_pSyntax->RestorePos(SavedPos); + if (!is_num || num_str.IsEmpty() || + FXSYS_atoui(num_str.c_str()) != it.first) { + // If the object number read doesn't match the one stored, + // something is wrong with the cross reference table. + return false; + } else { + return true; + } + } + return true; +} + +FX_BOOL CPDF_Parser::LoadAllCrossRefV4(FX_FILESIZE xrefpos) { + if (!LoadCrossRefV4(xrefpos, 0, TRUE)) + return FALSE; + + m_pTrailer = LoadTrailerV4(); + if (!m_pTrailer) + return FALSE; + + int32_t xrefsize = GetDirectInteger(m_pTrailer, "Size"); + if (xrefsize > 0 && xrefsize <= kMaxXRefSize) + ShrinkObjectMap(xrefsize); + + std::vector CrossRefList; + std::vector XRefStreamList; + std::set seen_xrefpos; + + CrossRefList.push_back(xrefpos); + XRefStreamList.push_back(GetDirectInteger(m_pTrailer, "XRefStm")); + seen_xrefpos.insert(xrefpos); + + // When |m_pTrailer| doesn't have Prev entry or Prev entry value is not + // numerical, GetDirectInteger() returns 0. Loading will end. + xrefpos = GetDirectInteger(m_pTrailer, "Prev"); + while (xrefpos) { + // Check for circular references. + if (pdfium::ContainsKey(seen_xrefpos, xrefpos)) + return FALSE; + + seen_xrefpos.insert(xrefpos); + + // SLOW ... + CrossRefList.insert(CrossRefList.begin(), xrefpos); + LoadCrossRefV4(xrefpos, 0, TRUE); + + std::unique_ptr> pDict( + LoadTrailerV4()); + if (!pDict) + return FALSE; + + xrefpos = GetDirectInteger(pDict.get(), "Prev"); + + // SLOW ... + XRefStreamList.insert(XRefStreamList.begin(), + pDict->GetIntegerFor("XRefStm")); + m_Trailers.Add(pDict.release()); + } + + for (size_t i = 0; i < CrossRefList.size(); ++i) { + if (!LoadCrossRefV4(CrossRefList[i], XRefStreamList[i], FALSE)) + return FALSE; + if (i == 0 && !VerifyCrossRefV4()) + return FALSE; + } + return TRUE; +} + +FX_BOOL CPDF_Parser::LoadLinearizedAllCrossRefV4(FX_FILESIZE xrefpos, + uint32_t dwObjCount) { + if (!LoadLinearizedCrossRefV4(xrefpos, dwObjCount)) + return FALSE; + + m_pTrailer = LoadTrailerV4(); + if (!m_pTrailer) + return FALSE; + + int32_t xrefsize = GetDirectInteger(m_pTrailer, "Size"); + if (xrefsize == 0) + return FALSE; + + std::vector CrossRefList; + std::vector XRefStreamList; + std::set seen_xrefpos; + + CrossRefList.push_back(xrefpos); + XRefStreamList.push_back(GetDirectInteger(m_pTrailer, "XRefStm")); + seen_xrefpos.insert(xrefpos); + + xrefpos = GetDirectInteger(m_pTrailer, "Prev"); + while (xrefpos) { + // Check for circular references. + if (pdfium::ContainsKey(seen_xrefpos, xrefpos)) + return FALSE; + + seen_xrefpos.insert(xrefpos); + + // SLOW ... + CrossRefList.insert(CrossRefList.begin(), xrefpos); + LoadCrossRefV4(xrefpos, 0, TRUE); + + std::unique_ptr> pDict( + LoadTrailerV4()); + if (!pDict) + return FALSE; + + xrefpos = GetDirectInteger(pDict.get(), "Prev"); + + // SLOW ... + XRefStreamList.insert(XRefStreamList.begin(), + pDict->GetIntegerFor("XRefStm")); + m_Trailers.Add(pDict.release()); + } + + for (size_t i = 1; i < CrossRefList.size(); ++i) { + if (!LoadCrossRefV4(CrossRefList[i], XRefStreamList[i], FALSE)) + return FALSE; + } + return TRUE; +} + +FX_BOOL CPDF_Parser::LoadLinearizedCrossRefV4(FX_FILESIZE pos, + uint32_t dwObjCount) { + FX_FILESIZE dwStartPos = pos - m_pSyntax->m_HeaderOffset; + + m_pSyntax->RestorePos(dwStartPos); + m_SortedOffset.insert(pos); + + uint32_t start_objnum = 0; + uint32_t count = dwObjCount; + FX_FILESIZE SavedPos = m_pSyntax->SavePos(); + + const int32_t recordsize = 20; + std::vector buf(1024 * recordsize + 1); + buf[1024 * recordsize] = '\0'; + + int32_t nBlocks = count / 1024 + 1; + for (int32_t block = 0; block < nBlocks; block++) { + int32_t block_size = block == nBlocks - 1 ? count % 1024 : 1024; + uint32_t dwReadSize = block_size * recordsize; + if ((FX_FILESIZE)(dwStartPos + dwReadSize) > m_pSyntax->m_FileLen) + return FALSE; + + if (!m_pSyntax->ReadBlock(reinterpret_cast(buf.data()), + dwReadSize)) { + return FALSE; + } + + for (int32_t i = 0; i < block_size; i++) { + uint32_t objnum = start_objnum + block * 1024 + i; + char* pEntry = &buf[i * recordsize]; + if (pEntry[17] == 'f') { + m_ObjectInfo[objnum].pos = 0; + m_ObjectInfo[objnum].type = 0; + } else { + int32_t offset = FXSYS_atoi(pEntry); + if (offset == 0) { + for (int32_t c = 0; c < 10; c++) { + if (!std::isdigit(pEntry[c])) + return FALSE; + } + } + + m_ObjectInfo[objnum].pos = offset; + int32_t version = FXSYS_atoi(pEntry + 11); + if (version >= 1) + m_bVersionUpdated = true; + + m_ObjectInfo[objnum].gennum = version; + if (m_ObjectInfo[objnum].pos < m_pSyntax->m_FileLen) + m_SortedOffset.insert(m_ObjectInfo[objnum].pos); + + m_ObjectInfo[objnum].type = 1; + } + } + } + m_pSyntax->RestorePos(SavedPos + count * recordsize); + return TRUE; +} + +bool CPDF_Parser::LoadCrossRefV4(FX_FILESIZE pos, + FX_FILESIZE streampos, + FX_BOOL bSkip) { + m_pSyntax->RestorePos(pos); + if (m_pSyntax->GetKeyword() != "xref") + return false; + + m_SortedOffset.insert(pos); + if (streampos) + m_SortedOffset.insert(streampos); + + while (1) { + FX_FILESIZE SavedPos = m_pSyntax->SavePos(); + bool bIsNumber; + CFX_ByteString word = m_pSyntax->GetNextWord(&bIsNumber); + if (word.IsEmpty()) + return false; + + if (!bIsNumber) { + m_pSyntax->RestorePos(SavedPos); + break; + } + + uint32_t start_objnum = FXSYS_atoui(word.c_str()); + if (start_objnum >= kMaxObjectNumber) + return false; + + uint32_t count = m_pSyntax->GetDirectNum(); + m_pSyntax->ToNextWord(); + SavedPos = m_pSyntax->SavePos(); + const int32_t recordsize = 20; + + m_dwXrefStartObjNum = start_objnum; + if (!bSkip) { + std::vector buf(1024 * recordsize + 1); + buf[1024 * recordsize] = '\0'; + + int32_t nBlocks = count / 1024 + 1; + for (int32_t block = 0; block < nBlocks; block++) { + int32_t block_size = block == nBlocks - 1 ? count % 1024 : 1024; + m_pSyntax->ReadBlock(reinterpret_cast(buf.data()), + block_size * recordsize); + + for (int32_t i = 0; i < block_size; i++) { + uint32_t objnum = start_objnum + block * 1024 + i; + char* pEntry = &buf[i * recordsize]; + if (pEntry[17] == 'f') { + m_ObjectInfo[objnum].pos = 0; + m_ObjectInfo[objnum].type = 0; + } else { + FX_FILESIZE offset = (FX_FILESIZE)FXSYS_atoi64(pEntry); + if (offset == 0) { + for (int32_t c = 0; c < 10; c++) { + if (!std::isdigit(pEntry[c])) + return false; + } + } + + m_ObjectInfo[objnum].pos = offset; + int32_t version = FXSYS_atoi(pEntry + 11); + if (version >= 1) + m_bVersionUpdated = true; + + m_ObjectInfo[objnum].gennum = version; + if (m_ObjectInfo[objnum].pos < m_pSyntax->m_FileLen) + m_SortedOffset.insert(m_ObjectInfo[objnum].pos); + + m_ObjectInfo[objnum].type = 1; + } + } + } + } + m_pSyntax->RestorePos(SavedPos + count * recordsize); + } + return !streampos || LoadCrossRefV5(&streampos, FALSE); +} + +FX_BOOL CPDF_Parser::LoadAllCrossRefV5(FX_FILESIZE xrefpos) { + if (!LoadCrossRefV5(&xrefpos, TRUE)) + return FALSE; + + std::set seen_xrefpos; + while (xrefpos) { + seen_xrefpos.insert(xrefpos); + if (!LoadCrossRefV5(&xrefpos, FALSE)) + return FALSE; + + // Check for circular references. + if (pdfium::ContainsKey(seen_xrefpos, xrefpos)) + return FALSE; + } + m_ObjectStreamMap.clear(); + m_bXRefStream = TRUE; + return TRUE; +} + +FX_BOOL CPDF_Parser::RebuildCrossRef() { + m_ObjectInfo.clear(); + m_SortedOffset.clear(); + if (m_pTrailer) { + m_pTrailer->Release(); + m_pTrailer = nullptr; + } + + ParserState state = ParserState::kDefault; + + int32_t inside_index = 0; + uint32_t objnum = 0; + uint32_t gennum = 0; + int32_t depth = 0; + + const uint32_t kBufferSize = 4096; + std::vector buffer(kBufferSize); + + FX_FILESIZE pos = m_pSyntax->m_HeaderOffset; + FX_FILESIZE start_pos = 0; + FX_FILESIZE start_pos1 = 0; + FX_FILESIZE last_obj = -1; + FX_FILESIZE last_xref = -1; + FX_FILESIZE last_trailer = -1; + + while (pos < m_pSyntax->m_FileLen) { + const FX_FILESIZE saved_pos = pos; + bool bOverFlow = false; + uint32_t size = + std::min((uint32_t)(m_pSyntax->m_FileLen - pos), kBufferSize); + if (!m_pSyntax->m_pFileAccess->ReadBlock(buffer.data(), pos, size)) + break; + + for (uint32_t i = 0; i < size; i++) { + uint8_t byte = buffer[i]; + switch (state) { + case ParserState::kDefault: + if (PDFCharIsWhitespace(byte)) { + state = ParserState::kWhitespace; + } else if (std::isdigit(byte)) { + --i; + state = ParserState::kWhitespace; + } else if (byte == '%') { + inside_index = 0; + state = ParserState::kComment; + } else if (byte == '(') { + state = ParserState::kString; + depth = 1; + } else if (byte == '<') { + inside_index = 1; + state = ParserState::kHexString; + } else if (byte == '\\') { + state = ParserState::kEscapedString; + } else if (byte == 't') { + state = ParserState::kTrailer; + inside_index = 1; + } + break; + + case ParserState::kWhitespace: + if (std::isdigit(byte)) { + start_pos = pos + i; + state = ParserState::kObjNum; + objnum = FXSYS_toDecimalDigit(static_cast(byte)); + } else if (byte == 't') { + state = ParserState::kTrailer; + inside_index = 1; + } else if (byte == 'x') { + state = ParserState::kXref; + inside_index = 1; + } else if (!PDFCharIsWhitespace(byte)) { + --i; + state = ParserState::kDefault; + } + break; + + case ParserState::kObjNum: + if (std::isdigit(byte)) { + objnum = + objnum * 10 + FXSYS_toDecimalDigit(static_cast(byte)); + } else if (PDFCharIsWhitespace(byte)) { + state = ParserState::kPostObjNum; + } else { + --i; + state = ParserState::kEndObj; + inside_index = 0; + } + break; + + case ParserState::kPostObjNum: + if (std::isdigit(byte)) { + start_pos1 = pos + i; + state = ParserState::kGenNum; + gennum = FXSYS_toDecimalDigit(static_cast(byte)); + } else if (byte == 't') { + state = ParserState::kTrailer; + inside_index = 1; + } else if (!PDFCharIsWhitespace(byte)) { + --i; + state = ParserState::kDefault; + } + break; + + case ParserState::kGenNum: + if (std::isdigit(byte)) { + gennum = + gennum * 10 + FXSYS_toDecimalDigit(static_cast(byte)); + } else if (PDFCharIsWhitespace(byte)) { + state = ParserState::kPostGenNum; + } else { + --i; + state = ParserState::kDefault; + } + break; + + case ParserState::kPostGenNum: + if (byte == 'o') { + state = ParserState::kBeginObj; + inside_index = 1; + } else if (std::isdigit(byte)) { + objnum = gennum; + gennum = FXSYS_toDecimalDigit(static_cast(byte)); + start_pos = start_pos1; + start_pos1 = pos + i; + state = ParserState::kGenNum; + } else if (byte == 't') { + state = ParserState::kTrailer; + inside_index = 1; + } else if (!PDFCharIsWhitespace(byte)) { + --i; + state = ParserState::kDefault; + } + break; + + case ParserState::kBeginObj: + switch (inside_index) { + case 1: + if (byte != 'b') { + --i; + state = ParserState::kDefault; + } else { + inside_index++; + } + break; + case 2: + if (byte != 'j') { + --i; + state = ParserState::kDefault; + } else { + inside_index++; + } + break; + case 3: + if (PDFCharIsWhitespace(byte) || PDFCharIsDelimiter(byte)) { + FX_FILESIZE obj_pos = start_pos - m_pSyntax->m_HeaderOffset; + m_SortedOffset.insert(obj_pos); + last_obj = start_pos; + FX_FILESIZE obj_end = 0; + CPDF_Object* pObject = ParseIndirectObjectAtByStrict( + m_pDocument, obj_pos, objnum, &obj_end); + if (CPDF_Stream* pStream = ToStream(pObject)) { + if (CPDF_Dictionary* pDict = pStream->GetDict()) { + if ((pDict->KeyExist("Type")) && + (pDict->GetStringFor("Type") == "XRef" && + pDict->KeyExist("Size"))) { + CPDF_Object* pRoot = pDict->GetObjectFor("Root"); + if (pRoot && pRoot->GetDict() && + pRoot->GetDict()->GetObjectFor("Pages")) { + if (m_pTrailer) + m_pTrailer->Release(); + m_pTrailer = ToDictionary(pDict->Clone()); + } + } + } + } + + FX_FILESIZE offset = 0; + m_pSyntax->RestorePos(obj_pos); + offset = m_pSyntax->FindTag("obj", 0); + if (offset == -1) + offset = 0; + else + offset += 3; + + FX_FILESIZE nLen = obj_end - obj_pos - offset; + if ((uint32_t)nLen > size - i) { + pos = obj_end + m_pSyntax->m_HeaderOffset; + bOverFlow = true; + } else { + i += (uint32_t)nLen; + } + + if (!m_ObjectInfo.empty() && IsValidObjectNumber(objnum) && + m_ObjectInfo[objnum].pos) { + if (pObject) { + uint32_t oldgen = GetObjectGenNum(objnum); + m_ObjectInfo[objnum].pos = obj_pos; + m_ObjectInfo[objnum].gennum = gennum; + if (oldgen != gennum) + m_bVersionUpdated = true; + } + } else { + m_ObjectInfo[objnum].pos = obj_pos; + m_ObjectInfo[objnum].type = 1; + m_ObjectInfo[objnum].gennum = gennum; + } + + if (pObject) + pObject->Release(); + } + --i; + state = ParserState::kDefault; + break; + } + break; + + case ParserState::kTrailer: + if (inside_index == 7) { + if (PDFCharIsWhitespace(byte) || PDFCharIsDelimiter(byte)) { + last_trailer = pos + i - 7; + m_pSyntax->RestorePos(pos + i - m_pSyntax->m_HeaderOffset); + + CPDF_Object* pObj = m_pSyntax->GetObject(m_pDocument, 0, 0, true); + if (pObj) { + if (!pObj->IsDictionary() && !pObj->AsStream()) { + pObj->Release(); + } else { + CPDF_Stream* pStream = pObj->AsStream(); + if (CPDF_Dictionary* pTrailer = + pStream ? pStream->GetDict() : pObj->AsDictionary()) { + if (m_pTrailer) { + CPDF_Object* pRoot = pTrailer->GetObjectFor("Root"); + CPDF_Reference* pRef = ToReference(pRoot); + if (!pRoot || + (pRef && IsValidObjectNumber(pRef->GetRefObjNum()) && + m_ObjectInfo[pRef->GetRefObjNum()].pos != 0)) { + auto it = pTrailer->begin(); + while (it != pTrailer->end()) { + const CFX_ByteString& key = it->first; + CPDF_Object* pElement = it->second; + ++it; + uint32_t dwObjNum = + pElement ? pElement->GetObjNum() : 0; + if (dwObjNum) { + m_pTrailer->SetReferenceFor(key, m_pDocument, + dwObjNum); + } else { + m_pTrailer->SetFor(key, pElement->Clone()); + } + } + } + pObj->Release(); + } else { + if (pObj->IsStream()) { + m_pTrailer = ToDictionary(pTrailer->Clone()); + pObj->Release(); + } else { + m_pTrailer = pTrailer; + } + + FX_FILESIZE dwSavePos = m_pSyntax->SavePos(); + CFX_ByteString strWord = m_pSyntax->GetKeyword(); + if (!strWord.Compare("startxref")) { + bool bNumber; + CFX_ByteString bsOffset = + m_pSyntax->GetNextWord(&bNumber); + if (bNumber) + m_LastXRefOffset = FXSYS_atoi(bsOffset.c_str()); + } + m_pSyntax->RestorePos(dwSavePos); + } + } else { + pObj->Release(); + } + } + } + } + --i; + state = ParserState::kDefault; + } else if (byte == "trailer"[inside_index]) { + inside_index++; + } else { + --i; + state = ParserState::kDefault; + } + break; + + case ParserState::kXref: + if (inside_index == 4) { + last_xref = pos + i - 4; + state = ParserState::kWhitespace; + } else if (byte == "xref"[inside_index]) { + inside_index++; + } else { + --i; + state = ParserState::kDefault; + } + break; + + case ParserState::kComment: + if (PDFCharIsLineEnding(byte)) + state = ParserState::kDefault; + break; + + case ParserState::kString: + if (byte == ')') { + if (depth > 0) + depth--; + } else if (byte == '(') { + depth++; + } + + if (!depth) + state = ParserState::kDefault; + break; + + case ParserState::kHexString: + if (byte == '>' || (byte == '<' && inside_index == 1)) + state = ParserState::kDefault; + inside_index = 0; + break; + + case ParserState::kEscapedString: + if (PDFCharIsDelimiter(byte) || PDFCharIsWhitespace(byte)) { + --i; + state = ParserState::kDefault; + } + break; + + case ParserState::kEndObj: + if (PDFCharIsWhitespace(byte)) { + state = ParserState::kDefault; + } else if (byte == '%' || byte == '(' || byte == '<' || + byte == '\\') { + state = ParserState::kDefault; + --i; + } else if (inside_index == 6) { + state = ParserState::kDefault; + --i; + } else if (byte == "endobj"[inside_index]) { + inside_index++; + } + break; + } + + if (bOverFlow) { + size = 0; + break; + } + } + pos += size; + + // If the position has not changed at all or went backwards in a loop + // iteration, then break out to prevent infinite looping. + if (pos <= saved_pos) + break; + } + + if (last_xref != -1 && last_xref > last_obj) + last_trailer = last_xref; + else if (last_trailer == -1 || last_xref < last_obj) + last_trailer = m_pSyntax->m_FileLen; + + m_SortedOffset.insert(last_trailer - m_pSyntax->m_HeaderOffset); + return m_pTrailer && !m_ObjectInfo.empty(); +} + +FX_BOOL CPDF_Parser::LoadCrossRefV5(FX_FILESIZE* pos, FX_BOOL bMainXRef) { + CPDF_Object* pObject = ParseIndirectObjectAt(m_pDocument, *pos, 0); + if (!pObject) + return FALSE; + + if (m_pDocument) { + CPDF_Dictionary* pRootDict = m_pDocument->GetRoot(); + if (pRootDict && pRootDict->GetObjNum() == pObject->m_ObjNum) { + // If |pObject| has an objnum assigned then this will leak as Release() + // will early exit. + if (pObject->IsStream()) + pObject->Release(); + return FALSE; + } + if (!m_pDocument->ReplaceIndirectObjectIfHigherGeneration(pObject->m_ObjNum, + pObject)) { + return FALSE; + } + } + + CPDF_Stream* pStream = pObject->AsStream(); + if (!pStream) + return FALSE; + + CPDF_Dictionary* pDict = pStream->GetDict(); + *pos = pDict->GetIntegerFor("Prev"); + int32_t size = pDict->GetIntegerFor("Size"); + if (size < 0) { + pStream->Release(); + return FALSE; + } + + CPDF_Dictionary* pNewTrailer = ToDictionary(pDict->Clone()); + if (bMainXRef) { + m_pTrailer = pNewTrailer; + ShrinkObjectMap(size); + for (auto& it : m_ObjectInfo) + it.second.type = 0; + } else { + m_Trailers.Add(pNewTrailer); + } + + std::vector> arrIndex; + CPDF_Array* pArray = pDict->GetArrayFor("Index"); + if (pArray) { + for (size_t i = 0; i < pArray->GetCount() / 2; i++) { + CPDF_Object* pStartNumObj = pArray->GetObjectAt(i * 2); + CPDF_Object* pCountObj = pArray->GetObjectAt(i * 2 + 1); + + if (ToNumber(pStartNumObj) && ToNumber(pCountObj)) { + int nStartNum = pStartNumObj->GetInteger(); + int nCount = pCountObj->GetInteger(); + if (nStartNum >= 0 && nCount > 0) + arrIndex.push_back(std::make_pair(nStartNum, nCount)); + } + } + } + + if (arrIndex.size() == 0) + arrIndex.push_back(std::make_pair(0, size)); + + pArray = pDict->GetArrayFor("W"); + if (!pArray) { + pStream->Release(); + return FALSE; + } + + CFX_ArrayTemplate WidthArray; + FX_SAFE_UINT32 dwAccWidth = 0; + for (size_t i = 0; i < pArray->GetCount(); ++i) { + WidthArray.Add(pArray->GetIntegerAt(i)); + dwAccWidth += WidthArray[i]; + } + + if (!dwAccWidth.IsValid() || WidthArray.GetSize() < 3) { + pStream->Release(); + return FALSE; + } + + uint32_t totalWidth = dwAccWidth.ValueOrDie(); + CPDF_StreamAcc acc; + acc.LoadAllData(pStream); + + const uint8_t* pData = acc.GetData(); + uint32_t dwTotalSize = acc.GetSize(); + uint32_t segindex = 0; + for (uint32_t i = 0; i < arrIndex.size(); i++) { + int32_t startnum = arrIndex[i].first; + if (startnum < 0) + continue; + + m_dwXrefStartObjNum = + pdfium::base::checked_cast(startnum); + uint32_t count = + pdfium::base::checked_cast(arrIndex[i].second); + FX_SAFE_UINT32 dwCaculatedSize = segindex; + dwCaculatedSize += count; + dwCaculatedSize *= totalWidth; + if (!dwCaculatedSize.IsValid() || + dwCaculatedSize.ValueOrDie() > dwTotalSize) { + continue; + } + + const uint8_t* segstart = pData + segindex * totalWidth; + FX_SAFE_UINT32 dwMaxObjNum = startnum; + dwMaxObjNum += count; + uint32_t dwV5Size = m_ObjectInfo.empty() ? 0 : GetLastObjNum() + 1; + if (!dwMaxObjNum.IsValid() || dwMaxObjNum.ValueOrDie() > dwV5Size) + continue; + + for (uint32_t j = 0; j < count; j++) { + int32_t type = 1; + const uint8_t* entrystart = segstart + j * totalWidth; + if (WidthArray[0]) + type = GetVarInt(entrystart, WidthArray[0]); + + if (GetObjectType(startnum + j) == 255) { + FX_FILESIZE offset = + GetVarInt(entrystart + WidthArray[0], WidthArray[1]); + m_ObjectInfo[startnum + j].pos = offset; + m_SortedOffset.insert(offset); + continue; + } + + if (GetObjectType(startnum + j)) + continue; + + m_ObjectInfo[startnum + j].type = type; + if (type == 0) { + m_ObjectInfo[startnum + j].pos = 0; + } else { + FX_FILESIZE offset = + GetVarInt(entrystart + WidthArray[0], WidthArray[1]); + m_ObjectInfo[startnum + j].pos = offset; + if (type == 1) { + m_SortedOffset.insert(offset); + } else { + if (offset < 0 || !IsValidObjectNumber(offset)) { + pStream->Release(); + return FALSE; + } + m_ObjectInfo[offset].type = 255; + } + } + } + segindex += count; + } + pStream->Release(); + return TRUE; +} + +CPDF_Array* CPDF_Parser::GetIDArray() { + CPDF_Object* pID = m_pTrailer ? m_pTrailer->GetObjectFor("ID") : nullptr; + if (!pID) + return nullptr; + + if (CPDF_Reference* pRef = pID->AsReference()) { + pID = ParseIndirectObject(nullptr, pRef->GetRefObjNum()); + m_pTrailer->SetFor("ID", pID); + } + return ToArray(pID); +} + +uint32_t CPDF_Parser::GetRootObjNum() { + CPDF_Reference* pRef = + ToReference(m_pTrailer ? m_pTrailer->GetObjectFor("Root") : nullptr); + return pRef ? pRef->GetRefObjNum() : 0; +} + +uint32_t CPDF_Parser::GetInfoObjNum() { + CPDF_Reference* pRef = + ToReference(m_pTrailer ? m_pTrailer->GetObjectFor("Info") : nullptr); + return pRef ? pRef->GetRefObjNum() : 0; +} + +CPDF_Object* CPDF_Parser::ParseIndirectObject( + CPDF_IndirectObjectHolder* pObjList, + uint32_t objnum) { + if (!IsValidObjectNumber(objnum)) + return nullptr; + + // Prevent circular parsing the same object. + if (pdfium::ContainsKey(m_ParsingObjNums, objnum)) + return nullptr; + + pdfium::ScopedSetInsertion local_insert(&m_ParsingObjNums, objnum); + if (GetObjectType(objnum) == 1 || GetObjectType(objnum) == 255) { + FX_FILESIZE pos = m_ObjectInfo[objnum].pos; + if (pos <= 0) + return nullptr; + return ParseIndirectObjectAt(pObjList, pos, objnum); + } + if (GetObjectType(objnum) != 2) + return nullptr; + + CPDF_StreamAcc* pObjStream = GetObjectStream(m_ObjectInfo[objnum].pos); + if (!pObjStream) + return nullptr; + + ScopedFileStream file(FX_CreateMemoryStream( + (uint8_t*)pObjStream->GetData(), (size_t)pObjStream->GetSize(), FALSE)); + CPDF_SyntaxParser syntax; + syntax.InitParser(file.get(), 0); + const int32_t offset = GetStreamFirst(pObjStream); + + // Read object numbers from |pObjStream| into a cache. + if (!pdfium::ContainsKey(m_ObjCache, pObjStream)) { + for (int32_t i = GetStreamNCount(pObjStream); i > 0; --i) { + uint32_t thisnum = syntax.GetDirectNum(); + uint32_t thisoff = syntax.GetDirectNum(); + m_ObjCache[pObjStream][thisnum] = thisoff; + } + } + + const auto it = m_ObjCache[pObjStream].find(objnum); + if (it == m_ObjCache[pObjStream].end()) + return nullptr; + + syntax.RestorePos(offset + it->second); + return syntax.GetObject(pObjList, 0, 0, true); +} + +CPDF_StreamAcc* CPDF_Parser::GetObjectStream(uint32_t objnum) { + auto it = m_ObjectStreamMap.find(objnum); + if (it != m_ObjectStreamMap.end()) + return it->second.get(); + + if (!m_pDocument) + return nullptr; + + const CPDF_Stream* pStream = + ToStream(m_pDocument->GetOrParseIndirectObject(objnum)); + if (!pStream) + return nullptr; + + CPDF_StreamAcc* pStreamAcc = new CPDF_StreamAcc; + pStreamAcc->LoadAllData(pStream); + m_ObjectStreamMap[objnum].reset(pStreamAcc); + return pStreamAcc; +} + +FX_FILESIZE CPDF_Parser::GetObjectSize(uint32_t objnum) const { + if (!IsValidObjectNumber(objnum)) + return 0; + + if (GetObjectType(objnum) == 2) + objnum = GetObjectPositionOrZero(objnum); + + if (GetObjectType(objnum) != 1 && GetObjectType(objnum) != 255) + return 0; + + FX_FILESIZE offset = GetObjectPositionOrZero(objnum); + if (offset == 0) + return 0; + + auto it = m_SortedOffset.find(offset); + if (it == m_SortedOffset.end() || ++it == m_SortedOffset.end()) + return 0; + + return *it - offset; +} + +void CPDF_Parser::GetIndirectBinary(uint32_t objnum, + uint8_t*& pBuffer, + uint32_t& size) { + pBuffer = nullptr; + size = 0; + if (!IsValidObjectNumber(objnum)) + return; + + if (GetObjectType(objnum) == 2) { + CPDF_StreamAcc* pObjStream = GetObjectStream(m_ObjectInfo[objnum].pos); + if (!pObjStream) + return; + + int32_t offset = GetStreamFirst(pObjStream); + const uint8_t* pData = pObjStream->GetData(); + uint32_t totalsize = pObjStream->GetSize(); + ScopedFileStream file( + FX_CreateMemoryStream((uint8_t*)pData, (size_t)totalsize, FALSE)); + + CPDF_SyntaxParser syntax; + syntax.InitParser(file.get(), 0); + for (int i = GetStreamNCount(pObjStream); i > 0; --i) { + uint32_t thisnum = syntax.GetDirectNum(); + uint32_t thisoff = syntax.GetDirectNum(); + if (thisnum != objnum) + continue; + + if (i == 1) { + size = totalsize - (thisoff + offset); + } else { + syntax.GetDirectNum(); // Skip nextnum. + uint32_t nextoff = syntax.GetDirectNum(); + size = nextoff - thisoff; + } + + pBuffer = FX_Alloc(uint8_t, size); + FXSYS_memcpy(pBuffer, pData + thisoff + offset, size); + return; + } + return; + } + + if (GetObjectType(objnum) != 1) + return; + + FX_FILESIZE pos = m_ObjectInfo[objnum].pos; + if (pos == 0) + return; + + FX_FILESIZE SavedPos = m_pSyntax->SavePos(); + m_pSyntax->RestorePos(pos); + + bool bIsNumber; + CFX_ByteString word = m_pSyntax->GetNextWord(&bIsNumber); + if (!bIsNumber) { + m_pSyntax->RestorePos(SavedPos); + return; + } + + uint32_t parser_objnum = FXSYS_atoui(word.c_str()); + if (parser_objnum && parser_objnum != objnum) { + m_pSyntax->RestorePos(SavedPos); + return; + } + + word = m_pSyntax->GetNextWord(&bIsNumber); + if (!bIsNumber) { + m_pSyntax->RestorePos(SavedPos); + return; + } + + if (m_pSyntax->GetKeyword() != "obj") { + m_pSyntax->RestorePos(SavedPos); + return; + } + + auto it = m_SortedOffset.find(pos); + if (it == m_SortedOffset.end() || ++it == m_SortedOffset.end()) { + m_pSyntax->RestorePos(SavedPos); + return; + } + + FX_FILESIZE nextoff = *it; + FX_BOOL bNextOffValid = FALSE; + if (nextoff != pos) { + m_pSyntax->RestorePos(nextoff); + word = m_pSyntax->GetNextWord(&bIsNumber); + if (word == "xref") { + bNextOffValid = TRUE; + } else if (bIsNumber) { + word = m_pSyntax->GetNextWord(&bIsNumber); + if (bIsNumber && m_pSyntax->GetKeyword() == "obj") { + bNextOffValid = TRUE; + } + } + } + + if (!bNextOffValid) { + m_pSyntax->RestorePos(pos); + while (1) { + if (m_pSyntax->GetKeyword() == "endobj") + break; + + if (m_pSyntax->SavePos() == m_pSyntax->m_FileLen) + break; + } + nextoff = m_pSyntax->SavePos(); + } + + size = (uint32_t)(nextoff - pos); + pBuffer = FX_Alloc(uint8_t, size); + m_pSyntax->RestorePos(pos); + m_pSyntax->ReadBlock(pBuffer, size); + m_pSyntax->RestorePos(SavedPos); +} + +CPDF_Object* CPDF_Parser::ParseIndirectObjectAt( + CPDF_IndirectObjectHolder* pObjList, + FX_FILESIZE pos, + uint32_t objnum) { + FX_FILESIZE SavedPos = m_pSyntax->SavePos(); + m_pSyntax->RestorePos(pos); + bool bIsNumber; + CFX_ByteString word = m_pSyntax->GetNextWord(&bIsNumber); + if (!bIsNumber) { + m_pSyntax->RestorePos(SavedPos); + return nullptr; + } + + FX_FILESIZE objOffset = m_pSyntax->SavePos(); + objOffset -= word.GetLength(); + uint32_t parser_objnum = FXSYS_atoui(word.c_str()); + if (objnum && parser_objnum != objnum) { + m_pSyntax->RestorePos(SavedPos); + return nullptr; + } + + word = m_pSyntax->GetNextWord(&bIsNumber); + if (!bIsNumber) { + m_pSyntax->RestorePos(SavedPos); + return nullptr; + } + + uint32_t parser_gennum = FXSYS_atoui(word.c_str()); + if (m_pSyntax->GetKeyword() != "obj") { + m_pSyntax->RestorePos(SavedPos); + return nullptr; + } + + CPDF_Object* pObj = + m_pSyntax->GetObject(pObjList, objnum, parser_gennum, true); + m_pSyntax->SavePos(); + + CFX_ByteString bsWord = m_pSyntax->GetKeyword(); + if (bsWord == "endobj") + m_pSyntax->SavePos(); + + m_pSyntax->RestorePos(SavedPos); + if (pObj) { + if (!objnum) + pObj->m_ObjNum = parser_objnum; + pObj->m_GenNum = parser_gennum; + } + return pObj; +} + +CPDF_Object* CPDF_Parser::ParseIndirectObjectAtByStrict( + CPDF_IndirectObjectHolder* pObjList, + FX_FILESIZE pos, + uint32_t objnum, + FX_FILESIZE* pResultPos) { + FX_FILESIZE SavedPos = m_pSyntax->SavePos(); + m_pSyntax->RestorePos(pos); + + bool bIsNumber; + CFX_ByteString word = m_pSyntax->GetNextWord(&bIsNumber); + if (!bIsNumber) { + m_pSyntax->RestorePos(SavedPos); + return nullptr; + } + + uint32_t parser_objnum = FXSYS_atoui(word.c_str()); + if (objnum && parser_objnum != objnum) { + m_pSyntax->RestorePos(SavedPos); + return nullptr; + } + + word = m_pSyntax->GetNextWord(&bIsNumber); + if (!bIsNumber) { + m_pSyntax->RestorePos(SavedPos); + return nullptr; + } + + uint32_t gennum = FXSYS_atoui(word.c_str()); + if (m_pSyntax->GetKeyword() != "obj") { + m_pSyntax->RestorePos(SavedPos); + return nullptr; + } + + CPDF_Object* pObj = m_pSyntax->GetObjectForStrict(pObjList, objnum, gennum); + if (pResultPos) + *pResultPos = m_pSyntax->m_Pos; + + m_pSyntax->RestorePos(SavedPos); + return pObj; +} + +CPDF_Dictionary* CPDF_Parser::LoadTrailerV4() { + if (m_pSyntax->GetKeyword() != "trailer") + return nullptr; + + std::unique_ptr> pObj( + m_pSyntax->GetObject(m_pDocument, 0, 0, true)); + if (!ToDictionary(pObj.get())) + return nullptr; + return pObj.release()->AsDictionary(); +} + +uint32_t CPDF_Parser::GetPermissions() const { + if (!m_pSecurityHandler) + return 0xFFFFFFFF; + + uint32_t dwPermission = m_pSecurityHandler->GetPermissions(); + if (m_pEncryptDict && m_pEncryptDict->GetStringFor("Filter") == "Standard") { + // See PDF Reference 1.7, page 123, table 3.20. + dwPermission &= 0xFFFFFFFC; + dwPermission |= 0xFFFFF0C0; + } + return dwPermission; +} + +FX_BOOL CPDF_Parser::IsLinearizedFile(IFX_FileRead* pFileAccess, + uint32_t offset) { + m_pSyntax->InitParser(pFileAccess, offset); + m_pSyntax->RestorePos(m_pSyntax->m_HeaderOffset + 9); + + FX_FILESIZE SavedPos = m_pSyntax->SavePos(); + bool bIsNumber; + CFX_ByteString word = m_pSyntax->GetNextWord(&bIsNumber); + if (!bIsNumber) + return FALSE; + + uint32_t objnum = FXSYS_atoui(word.c_str()); + word = m_pSyntax->GetNextWord(&bIsNumber); + if (!bIsNumber) + return FALSE; + + uint32_t gennum = FXSYS_atoui(word.c_str()); + if (m_pSyntax->GetKeyword() != "obj") { + m_pSyntax->RestorePos(SavedPos); + return FALSE; + } + + m_pLinearized = m_pSyntax->GetObject(nullptr, objnum, gennum, true); + if (!m_pLinearized) + return FALSE; + + CPDF_Dictionary* pDict = m_pLinearized->GetDict(); + if (pDict && pDict->GetObjectFor("Linearized")) { + m_pSyntax->GetNextWord(nullptr); + + CPDF_Object* pLen = pDict->GetObjectFor("L"); + if (!pLen) { + m_pLinearized->Release(); + m_pLinearized = nullptr; + return FALSE; + } + + if (pLen->GetInteger() != (int)pFileAccess->GetSize()) + return FALSE; + + if (CPDF_Number* pNo = ToNumber(pDict->GetObjectFor("P"))) + m_dwFirstPageNo = pNo->GetInteger(); + + if (CPDF_Number* pTable = ToNumber(pDict->GetObjectFor("T"))) + m_LastXRefOffset = pTable->GetInteger(); + + return TRUE; + } + m_pLinearized->Release(); + m_pLinearized = nullptr; + return FALSE; +} + +CPDF_Parser::Error CPDF_Parser::StartLinearizedParse(IFX_FileRead* pFileAccess, + CPDF_Document* pDocument) { + ASSERT(!m_bHasParsed); + + m_bXRefStream = FALSE; + m_LastXRefOffset = 0; + m_bOwnFileRead = true; + + int32_t offset = GetHeaderOffset(pFileAccess); + if (offset == -1) + return FORMAT_ERROR; + + if (!IsLinearizedFile(pFileAccess, offset)) { + m_pSyntax->m_pFileAccess = nullptr; + return StartParse(pFileAccess, std::move(pDocument)); + } + m_bHasParsed = true; + m_pDocument = pDocument; + + FX_FILESIZE dwFirstXRefOffset = m_pSyntax->SavePos(); + + FX_BOOL bXRefRebuilt = FALSE; + FX_BOOL bLoadV4 = LoadCrossRefV4(dwFirstXRefOffset, 0, FALSE); + if (!bLoadV4 && !LoadCrossRefV5(&dwFirstXRefOffset, TRUE)) { + if (!RebuildCrossRef()) + return FORMAT_ERROR; + + bXRefRebuilt = TRUE; + m_LastXRefOffset = 0; + } + + if (bLoadV4) { + m_pTrailer = LoadTrailerV4(); + if (!m_pTrailer) + return SUCCESS; + + int32_t xrefsize = GetDirectInteger(m_pTrailer, "Size"); + if (xrefsize > 0) + ShrinkObjectMap(xrefsize); + } + + Error eRet = SetEncryptHandler(); + if (eRet != SUCCESS) + return eRet; + + m_pDocument->LoadLinearizedDoc(m_pLinearized->GetDict()); + if (!m_pDocument->GetRoot() || m_pDocument->GetPageCount() == 0) { + if (bXRefRebuilt) + return FORMAT_ERROR; + + ReleaseEncryptHandler(); + if (!RebuildCrossRef()) + return FORMAT_ERROR; + + eRet = SetEncryptHandler(); + if (eRet != SUCCESS) + return eRet; + + m_pDocument->LoadLinearizedDoc(m_pLinearized->GetDict()); + if (!m_pDocument->GetRoot()) + return FORMAT_ERROR; + } + + if (GetRootObjNum() == 0) { + ReleaseEncryptHandler(); + if (!RebuildCrossRef() || GetRootObjNum() == 0) + return FORMAT_ERROR; + + eRet = SetEncryptHandler(); + if (eRet != SUCCESS) + return eRet; + } + + if (m_pSecurityHandler && m_pSecurityHandler->IsMetadataEncrypted()) { + if (CPDF_Reference* pMetadata = + ToReference(m_pDocument->GetRoot()->GetObjectFor("Metadata"))) + m_pSyntax->m_MetadataObjnum = pMetadata->GetRefObjNum(); + } + return SUCCESS; +} + +FX_BOOL CPDF_Parser::LoadLinearizedAllCrossRefV5(FX_FILESIZE xrefpos) { + if (!LoadCrossRefV5(&xrefpos, FALSE)) + return FALSE; + + std::set seen_xrefpos; + while (xrefpos) { + seen_xrefpos.insert(xrefpos); + if (!LoadCrossRefV5(&xrefpos, FALSE)) + return FALSE; + + // Check for circular references. + if (pdfium::ContainsKey(seen_xrefpos, xrefpos)) + return FALSE; + } + m_ObjectStreamMap.clear(); + m_bXRefStream = TRUE; + return TRUE; +} + +CPDF_Parser::Error CPDF_Parser::LoadLinearizedMainXRefTable() { + uint32_t dwSaveMetadataObjnum = m_pSyntax->m_MetadataObjnum; + m_pSyntax->m_MetadataObjnum = 0; + if (m_pTrailer) { + m_pTrailer->Release(); + m_pTrailer = nullptr; + } + + m_pSyntax->RestorePos(m_LastXRefOffset - m_pSyntax->m_HeaderOffset); + uint8_t ch = 0; + uint32_t dwCount = 0; + m_pSyntax->GetNextChar(ch); + while (PDFCharIsWhitespace(ch)) { + ++dwCount; + if (m_pSyntax->m_FileLen >= + (FX_FILESIZE)(m_pSyntax->SavePos() + m_pSyntax->m_HeaderOffset)) { + break; + } + m_pSyntax->GetNextChar(ch); + } + m_LastXRefOffset += dwCount; + m_ObjectStreamMap.clear(); + m_ObjCache.clear(); + + if (!LoadLinearizedAllCrossRefV4(m_LastXRefOffset, m_dwXrefStartObjNum) && + !LoadLinearizedAllCrossRefV5(m_LastXRefOffset)) { + m_LastXRefOffset = 0; + m_pSyntax->m_MetadataObjnum = dwSaveMetadataObjnum; + return FORMAT_ERROR; + } + + m_pSyntax->m_MetadataObjnum = dwSaveMetadataObjnum; + return SUCCESS; +} diff --git a/core/fpdfapi/parser/cpdf_parser.h b/core/fpdfapi/parser/cpdf_parser.h new file mode 100644 index 0000000000..876ea6cb3d --- /dev/null +++ b/core/fpdfapi/parser/cpdf_parser.h @@ -0,0 +1,177 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_PARSER_H_ +#define CORE_FPDFAPI_PARSER_CPDF_PARSER_H_ + +#include +#include +#include + +#include "core/fxcrt/fx_basic.h" + +class CPDF_Array; +class CPDF_CryptoHandler; +class CPDF_Dictionary; +class CPDF_Document; +class CPDF_IndirectObjectHolder; +class CPDF_Object; +class CPDF_SecurityHandler; +class CPDF_StreamAcc; +class CPDF_SyntaxParser; +class IFX_FileRead; + +class CPDF_Parser { + public: + enum Error { + SUCCESS = 0, + FILE_ERROR, + FORMAT_ERROR, + PASSWORD_ERROR, + HANDLER_ERROR + }; + + // A limit on the maximum object number in the xref table. Theoretical limits + // are higher, but this may be large enough in practice. + static const uint32_t kMaxObjectNumber = 1048576; + + CPDF_Parser(); + ~CPDF_Parser(); + + Error StartParse(IFX_FileRead* pFile, CPDF_Document* pDocument); + Error StartLinearizedParse(IFX_FileRead* pFile, CPDF_Document* pDocument); + + void SetPassword(const FX_CHAR* password) { m_Password = password; } + CFX_ByteString GetPassword() { return m_Password; } + CPDF_Dictionary* GetTrailer() const { return m_pTrailer; } + FX_FILESIZE GetLastXRefOffset() const { return m_LastXRefOffset; } + + uint32_t GetPermissions() const; + uint32_t GetRootObjNum(); + uint32_t GetInfoObjNum(); + CPDF_Array* GetIDArray(); + + CPDF_Dictionary* GetEncryptDict() const { return m_pEncryptDict; } + + CPDF_Object* ParseIndirectObject(CPDF_IndirectObjectHolder* pObjList, + uint32_t objnum); + + uint32_t GetLastObjNum() const; + bool IsValidObjectNumber(uint32_t objnum) const; + FX_FILESIZE GetObjectPositionOrZero(uint32_t objnum) const; + uint8_t GetObjectType(uint32_t objnum) const; + uint16_t GetObjectGenNum(uint32_t objnum) const; + bool IsVersionUpdated() const { return m_bVersionUpdated; } + bool IsObjectFreeOrNull(uint32_t objnum) const; + CPDF_CryptoHandler* GetCryptoHandler(); + IFX_FileRead* GetFileAccess() const; + + FX_FILESIZE GetObjectOffset(uint32_t objnum) const; + FX_FILESIZE GetObjectSize(uint32_t objnum) const; + + void GetIndirectBinary(uint32_t objnum, uint8_t*& pBuffer, uint32_t& size); + int GetFileVersion() const { return m_FileVersion; } + FX_BOOL IsXRefStream() const { return m_bXRefStream; } + + CPDF_Object* ParseIndirectObjectAt(CPDF_IndirectObjectHolder* pObjList, + FX_FILESIZE pos, + uint32_t objnum); + + CPDF_Object* ParseIndirectObjectAtByStrict( + CPDF_IndirectObjectHolder* pObjList, + FX_FILESIZE pos, + uint32_t objnum, + FX_FILESIZE* pResultPos); + + uint32_t GetFirstPageNo() const { return m_dwFirstPageNo; } + + protected: + struct ObjectInfo { + ObjectInfo() : pos(0), type(0), gennum(0) {} + + FX_FILESIZE pos; + uint8_t type; + uint16_t gennum; + }; + + std::unique_ptr m_pSyntax; + std::map m_ObjectInfo; + + bool LoadCrossRefV4(FX_FILESIZE pos, FX_FILESIZE streampos, FX_BOOL bSkip); + FX_BOOL RebuildCrossRef(); + + private: + friend class CPDF_DataAvail; + + enum class ParserState { + kDefault, + kComment, + kWhitespace, + kString, + kHexString, + kEscapedString, + kXref, + kObjNum, + kPostObjNum, + kGenNum, + kPostGenNum, + kTrailer, + kBeginObj, + kEndObj + }; + + CPDF_Object* ParseDirect(CPDF_Object* pObj); + FX_BOOL LoadAllCrossRefV4(FX_FILESIZE pos); + FX_BOOL LoadAllCrossRefV5(FX_FILESIZE pos); + FX_BOOL LoadCrossRefV5(FX_FILESIZE* pos, FX_BOOL bMainXRef); + CPDF_Dictionary* LoadTrailerV4(); + Error SetEncryptHandler(); + void ReleaseEncryptHandler(); + FX_BOOL LoadLinearizedAllCrossRefV4(FX_FILESIZE pos, uint32_t dwObjCount); + FX_BOOL LoadLinearizedCrossRefV4(FX_FILESIZE pos, uint32_t dwObjCount); + FX_BOOL LoadLinearizedAllCrossRefV5(FX_FILESIZE pos); + Error LoadLinearizedMainXRefTable(); + CPDF_StreamAcc* GetObjectStream(uint32_t number); + FX_BOOL IsLinearizedFile(IFX_FileRead* pFileAccess, uint32_t offset); + void SetEncryptDictionary(CPDF_Dictionary* pDict); + void ShrinkObjectMap(uint32_t size); + // A simple check whether the cross reference table matches with + // the objects. + bool VerifyCrossRefV4(); + + CPDF_Document* m_pDocument; // not owned + bool m_bHasParsed; + bool m_bOwnFileRead; + int m_FileVersion; + CPDF_Dictionary* m_pTrailer; + CPDF_Dictionary* m_pEncryptDict; + FX_FILESIZE m_LastXRefOffset; + FX_BOOL m_bXRefStream; + std::unique_ptr m_pSecurityHandler; + CFX_ByteString m_Password; + std::set m_SortedOffset; + CFX_ArrayTemplate m_Trailers; + bool m_bVersionUpdated; + CPDF_Object* m_pLinearized; + uint32_t m_dwFirstPageNo; + uint32_t m_dwXrefStartObjNum; + + // A map of object numbers to indirect streams. Map owns the streams. + std::map> m_ObjectStreamMap; + + // Mapping of object numbers to offsets. The offsets are relative to the first + // object in the stream. + using StreamObjectCache = std::map; + + // Mapping of streams to their object caches. This is valid as long as the + // streams in |m_ObjectStreamMap| are valid. + std::map m_ObjCache; + + // All indirect object numbers that are being parsed. + std::set m_ParsingObjNums; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_PARSER_H_ diff --git a/core/fpdfapi/parser/cpdf_parser_embeddertest.cpp b/core/fpdfapi/parser/cpdf_parser_embeddertest.cpp new file mode 100644 index 0000000000..f523d6b31b --- /dev/null +++ b/core/fpdfapi/parser/cpdf_parser_embeddertest.cpp @@ -0,0 +1,59 @@ +// Copyright 2015 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. + +#include "public/fpdf_text.h" +#include "testing/embedder_test.h" +#include "testing/gtest/include/gtest/gtest.h" + +class CPDFParserEmbeddertest : public EmbedderTest {}; + +TEST_F(CPDFParserEmbeddertest, LoadError_454695) { + // Test a dictionary with hex string instead of correct content. + // Verify that the defective pdf shouldn't be opened correctly. + EXPECT_FALSE(OpenDocument("bug_454695.pdf")); +} + +TEST_F(CPDFParserEmbeddertest, Bug_481363) { + // Test colorspace object with malformed dictionary. + EXPECT_TRUE(OpenDocument("bug_481363.pdf")); + FPDF_PAGE page = LoadPage(0); + EXPECT_NE(nullptr, page); + UnloadPage(page); +} + +TEST_F(CPDFParserEmbeddertest, Bug_544880) { + // Test self referencing /Pages object. + EXPECT_TRUE(OpenDocument("bug_544880.pdf")); + // Shouldn't crash. We don't check the return value here because we get the + // the count from the "/Count 1" in the testcase (at the time of writing) + // rather than the actual count (0). + (void)GetPageCount(); +} + +TEST_F(CPDFParserEmbeddertest, Feature_Linearized_Loading) { + EXPECT_TRUE(OpenDocument("feature_linearized_loading.pdf", nullptr, true)); +} + +TEST_F(CPDFParserEmbeddertest, Bug_325a) { + EXPECT_FALSE(OpenDocument("bug_325_a.pdf")); +} + +TEST_F(CPDFParserEmbeddertest, Bug_325b) { + EXPECT_FALSE(OpenDocument("bug_325_b.pdf")); +} + +TEST_F(CPDFParserEmbeddertest, Bug_602650) { + // Test the case that cross reference entries, which are well formed, + // but do not match with the objects. + EXPECT_TRUE(OpenDocument("bug_602650.pdf")); + FPDF_PAGE page = LoadPage(0); + EXPECT_NE(nullptr, page); + FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page); + EXPECT_NE(nullptr, text_page); + // The page should not be blank. + EXPECT_LT(0, FPDFText_CountChars(text_page)); + + FPDFText_ClosePage(text_page); + UnloadPage(page); +} diff --git a/core/fpdfapi/parser/cpdf_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_parser_unittest.cpp new file mode 100644 index 0000000000..c97b88e6d1 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_parser_unittest.cpp @@ -0,0 +1,202 @@ +// Copyright 2015 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. + +#include +#include + +#include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fpdfapi/parser/cpdf_syntax_parser.h" +#include "core/fxcrt/fx_ext.h" +#include "core/fxcrt/fx_stream.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/utils/path_service.h" + +// Provide a way to read test data from a buffer instead of a file. +class CFX_TestBufferRead : public IFX_FileRead { + public: + CFX_TestBufferRead(const unsigned char* buffer_in, size_t buf_size) + : buffer_(buffer_in), total_size_(buf_size) {} + + // IFX_Stream + void Release() override { delete this; } + + // IFX_FileRead + FX_BOOL ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override { + if (offset < 0 || offset + size > total_size_) { + return FALSE; + } + + memcpy(buffer, buffer_ + offset, size); + return TRUE; + } + FX_FILESIZE GetSize() override { return (FX_FILESIZE)total_size_; }; + + protected: + const unsigned char* buffer_; + size_t total_size_; +}; + +// A wrapper class to help test member functions of CPDF_Parser. +class CPDF_TestParser : public CPDF_Parser { + public: + CPDF_TestParser() {} + ~CPDF_TestParser() {} + + // Setup reading from a file and initial states. + bool InitTestFromFile(const FX_CHAR* path) { + IFX_FileRead* pFileAccess = FX_CreateFileRead(path); + if (!pFileAccess) + return false; + + // For the test file, the header is set at the beginning. + m_pSyntax->InitParser(pFileAccess, 0); + return true; + } + + // Setup reading from a buffer and initial states. + bool InitTestFromBuffer(const unsigned char* buffer, size_t len) { + CFX_TestBufferRead* buffer_reader = new CFX_TestBufferRead(buffer, len); + + // For the test file, the header is set at the beginning. + m_pSyntax->InitParser(buffer_reader, 0); + return true; + } + + private: + // Add test cases here as private friend so that protected members in + // CPDF_Parser can be accessed by test cases. + // Need to access RebuildCrossRef. + FRIEND_TEST(cpdf_parser, RebuildCrossRefCorrectly); + FRIEND_TEST(cpdf_parser, RebuildCrossRefFailed); + // Need to access LoadCrossRefV4. + FRIEND_TEST(cpdf_parser, LoadCrossRefV4); +}; + +TEST(cpdf_parser, RebuildCrossRefCorrectly) { + CPDF_TestParser parser; + std::string test_file; + ASSERT_TRUE(PathService::GetTestFilePath("parser_rebuildxref_correct.pdf", + &test_file)); + ASSERT_TRUE(parser.InitTestFromFile(test_file.c_str())) << test_file; + + ASSERT_TRUE(parser.RebuildCrossRef()); + const FX_FILESIZE offsets[] = {0, 15, 61, 154, 296, 374, 450}; + const uint16_t versions[] = {0, 0, 2, 4, 6, 8, 0}; + for (size_t i = 0; i < FX_ArraySize(offsets); ++i) + EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos); + for (size_t i = 0; i < FX_ArraySize(versions); ++i) + EXPECT_EQ(versions[i], parser.m_ObjectInfo[i].gennum); +} + +TEST(cpdf_parser, RebuildCrossRefFailed) { + CPDF_TestParser parser; + std::string test_file; + ASSERT_TRUE(PathService::GetTestFilePath( + "parser_rebuildxref_error_notrailer.pdf", &test_file)); + ASSERT_TRUE(parser.InitTestFromFile(test_file.c_str())) << test_file; + + ASSERT_FALSE(parser.RebuildCrossRef()); +} + +TEST(cpdf_parser, LoadCrossRefV4) { + { + const unsigned char xref_table[] = + "xref \n" + "0 6 \n" + "0000000003 65535 f \n" + "0000000017 00000 n \n" + "0000000081 00000 n \n" + "0000000000 00007 f \n" + "0000000331 00000 n \n" + "0000000409 00000 n \n" + "trail"; // Needed to end cross ref table reading. + CPDF_TestParser parser; + ASSERT_TRUE( + parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table))); + + ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, FALSE)); + const FX_FILESIZE offsets[] = {0, 17, 81, 0, 331, 409}; + const uint8_t types[] = {0, 1, 1, 0, 1, 1}; + for (size_t i = 0; i < FX_ArraySize(offsets); ++i) { + EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos); + EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type); + } + } + { + const unsigned char xref_table[] = + "xref \n" + "0 1 \n" + "0000000000 65535 f \n" + "3 1 \n" + "0000025325 00000 n \n" + "8 2 \n" + "0000025518 00002 n \n" + "0000025635 00000 n \n" + "12 1 \n" + "0000025777 00000 n \n" + "trail"; // Needed to end cross ref table reading. + CPDF_TestParser parser; + ASSERT_TRUE( + parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table))); + + ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, FALSE)); + const FX_FILESIZE offsets[] = {0, 0, 0, 25325, 0, 0, 0, + 0, 25518, 25635, 0, 0, 25777}; + const uint8_t types[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1}; + for (size_t i = 0; i < FX_ArraySize(offsets); ++i) { + EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos); + EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type); + } + } + { + const unsigned char xref_table[] = + "xref \n" + "0 1 \n" + "0000000000 65535 f \n" + "3 1 \n" + "0000025325 00000 n \n" + "8 2 \n" + "0000000000 65535 f \n" + "0000025635 00000 n \n" + "12 1 \n" + "0000025777 00000 n \n" + "trail"; // Needed to end cross ref table reading. + CPDF_TestParser parser; + ASSERT_TRUE( + parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table))); + + ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, FALSE)); + const FX_FILESIZE offsets[] = {0, 0, 0, 25325, 0, 0, 0, + 0, 0, 25635, 0, 0, 25777}; + const uint8_t types[] = {0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1}; + for (size_t i = 0; i < FX_ArraySize(offsets); ++i) { + EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos); + EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type); + } + } + { + const unsigned char xref_table[] = + "xref \n" + "0 7 \n" + "0000000002 65535 f \n" + "0000000023 00000 n \n" + "0000000003 65535 f \n" + "0000000004 65535 f \n" + "0000000000 65535 f \n" + "0000000045 00000 n \n" + "0000000179 00000 n \n" + "trail"; // Needed to end cross ref table reading. + CPDF_TestParser parser; + ASSERT_TRUE( + parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table))); + + ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, FALSE)); + const FX_FILESIZE offsets[] = {0, 23, 0, 0, 0, 45, 179}; + const uint8_t types[] = {0, 1, 0, 0, 0, 1, 1}; + for (size_t i = 0; i < FX_ArraySize(offsets); ++i) { + EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos); + EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type); + } + } +} diff --git a/core/fpdfapi/parser/cpdf_reference.cpp b/core/fpdfapi/parser/cpdf_reference.cpp new file mode 100644 index 0000000000..a9cdf54855 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_reference.cpp @@ -0,0 +1,83 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_reference.h" + +#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" +#include "third_party/base/stl_util.h" + +CPDF_Reference::CPDF_Reference(CPDF_IndirectObjectHolder* pDoc, int objnum) + : m_pObjList(pDoc), m_RefObjNum(objnum) {} + +CPDF_Reference::~CPDF_Reference() {} + +CPDF_Object::Type CPDF_Reference::GetType() const { + return REFERENCE; +} + +CFX_ByteString CPDF_Reference::GetString() const { + CPDF_Object* obj = SafeGetDirect(); + return obj ? obj->GetString() : CFX_ByteString(); +} + +FX_FLOAT CPDF_Reference::GetNumber() const { + CPDF_Object* obj = SafeGetDirect(); + return obj ? obj->GetNumber() : 0; +} + +int CPDF_Reference::GetInteger() const { + CPDF_Object* obj = SafeGetDirect(); + return obj ? obj->GetInteger() : 0; +} + +CPDF_Dictionary* CPDF_Reference::GetDict() const { + CPDF_Object* obj = SafeGetDirect(); + return obj ? obj->GetDict() : nullptr; +} + +bool CPDF_Reference::IsReference() const { + return true; +} + +CPDF_Reference* CPDF_Reference::AsReference() { + return this; +} + +const CPDF_Reference* CPDF_Reference::AsReference() const { + return this; +} + +CPDF_Object* CPDF_Reference::Clone() const { + return CloneObjectNonCyclic(false); +} + +CPDF_Object* CPDF_Reference::CloneNonCyclic( + bool bDirect, + std::set* pVisited) const { + pVisited->insert(this); + if (bDirect) { + auto* pDirect = GetDirect(); + return pDirect && !pdfium::ContainsKey(*pVisited, pDirect) + ? pDirect->CloneNonCyclic(true, pVisited) + : nullptr; + } + return new CPDF_Reference(m_pObjList, m_RefObjNum); +} + +CPDF_Object* CPDF_Reference::SafeGetDirect() const { + CPDF_Object* obj = GetDirect(); + return (obj && !obj->IsReference()) ? obj : nullptr; +} + +void CPDF_Reference::SetRef(CPDF_IndirectObjectHolder* pDoc, uint32_t objnum) { + m_pObjList = pDoc; + m_RefObjNum = objnum; +} + +CPDF_Object* CPDF_Reference::GetDirect() const { + return m_pObjList ? m_pObjList->GetOrParseIndirectObject(m_RefObjNum) + : nullptr; +} diff --git a/core/fpdfapi/parser/cpdf_reference.h b/core/fpdfapi/parser/cpdf_reference.h new file mode 100644 index 0000000000..8c57d85e0e --- /dev/null +++ b/core/fpdfapi/parser/cpdf_reference.h @@ -0,0 +1,50 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_REFERENCE_H_ +#define CORE_FPDFAPI_PARSER_CPDF_REFERENCE_H_ + +#include + +#include "core/fpdfapi/parser/cpdf_object.h" + +class CPDF_IndirectObjectHolder; + +class CPDF_Reference : public CPDF_Object { + public: + CPDF_Reference(CPDF_IndirectObjectHolder* pDoc, int objnum); + + // CPDF_Object. + Type GetType() const override; + CPDF_Object* Clone() const override; + CPDF_Object* GetDirect() const override; + CFX_ByteString GetString() const override; + FX_FLOAT GetNumber() const override; + int GetInteger() const override; + CPDF_Dictionary* GetDict() const override; + bool IsReference() const override; + CPDF_Reference* AsReference() override; + const CPDF_Reference* AsReference() const override; + + CPDF_IndirectObjectHolder* GetObjList() const { return m_pObjList; } + uint32_t GetRefObjNum() const { return m_RefObjNum; } + + void SetRef(CPDF_IndirectObjectHolder* pDoc, uint32_t objnum); + + protected: + ~CPDF_Reference() override; + + CPDF_Object* CloneNonCyclic( + bool bDirect, + std::set* pVisited) const override; + + CPDF_Object* SafeGetDirect() const; + + CPDF_IndirectObjectHolder* m_pObjList; + uint32_t m_RefObjNum; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_REFERENCE_H_ diff --git a/core/fpdfapi/parser/cpdf_security_handler.cpp b/core/fpdfapi/parser/cpdf_security_handler.cpp new file mode 100644 index 0000000000..039ba4e1ab --- /dev/null +++ b/core/fpdfapi/parser/cpdf_security_handler.cpp @@ -0,0 +1,699 @@ +// 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 + +#include "core/fpdfapi/parser/cpdf_security_handler.h" + +#include + +#include "core/fdrm/crypto/fx_crypt.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_crypto_handler.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fpdfapi/parser/cpdf_parser.h" + +namespace { + +const uint8_t defpasscode[32] = { + 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, + 0x56, 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, + 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a}; + +void CalcEncryptKey(CPDF_Dictionary* pEncrypt, + const uint8_t* password, + uint32_t pass_size, + uint8_t* key, + int keylen, + FX_BOOL bIgnoreMeta, + CPDF_Array* pIdArray) { + int revision = pEncrypt->GetIntegerFor("R"); + uint8_t passcode[32]; + for (uint32_t i = 0; i < 32; i++) { + passcode[i] = i < pass_size ? password[i] : defpasscode[i - pass_size]; + } + uint8_t md5[100]; + CRYPT_MD5Start(md5); + CRYPT_MD5Update(md5, passcode, 32); + CFX_ByteString okey = pEncrypt->GetStringFor("O"); + CRYPT_MD5Update(md5, (uint8_t*)okey.c_str(), okey.GetLength()); + uint32_t perm = pEncrypt->GetIntegerFor("P"); + CRYPT_MD5Update(md5, (uint8_t*)&perm, 4); + if (pIdArray) { + CFX_ByteString id = pIdArray->GetStringAt(0); + CRYPT_MD5Update(md5, (uint8_t*)id.c_str(), id.GetLength()); + } + if (!bIgnoreMeta && revision >= 3 && + !pEncrypt->GetIntegerFor("EncryptMetadata", 1)) { + uint32_t tag = (uint32_t)-1; + CRYPT_MD5Update(md5, (uint8_t*)&tag, 4); + } + uint8_t digest[16]; + CRYPT_MD5Finish(md5, digest); + uint32_t copy_len = keylen; + if (copy_len > sizeof(digest)) { + copy_len = sizeof(digest); + } + if (revision >= 3) { + for (int i = 0; i < 50; i++) { + CRYPT_MD5Generate(digest, copy_len, digest); + } + } + FXSYS_memset(key, 0, keylen); + FXSYS_memcpy(key, digest, copy_len); +} + +} // namespace + +CPDF_SecurityHandler::CPDF_SecurityHandler() + : m_Version(0), + m_Revision(0), + m_pParser(nullptr), + m_pEncryptDict(nullptr), + m_Permissions(0), + m_Cipher(FXCIPHER_NONE), + m_KeyLen(0), + m_bOwnerUnlocked(false) {} + +CPDF_SecurityHandler::~CPDF_SecurityHandler() {} + +CPDF_CryptoHandler* CPDF_SecurityHandler::CreateCryptoHandler() { + return new CPDF_CryptoHandler; +} + +FX_BOOL CPDF_SecurityHandler::OnInit(CPDF_Parser* pParser, + CPDF_Dictionary* pEncryptDict) { + m_pParser = pParser; + if (!LoadDict(pEncryptDict)) { + return FALSE; + } + if (m_Cipher == FXCIPHER_NONE) { + return TRUE; + } + return CheckSecurity(m_KeyLen); +} + +FX_BOOL CPDF_SecurityHandler::CheckSecurity(int32_t key_len) { + CFX_ByteString password = m_pParser->GetPassword(); + if (!password.IsEmpty() && + CheckPassword(password.raw_str(), password.GetLength(), TRUE, + m_EncryptKey, key_len)) { + m_bOwnerUnlocked = true; + return TRUE; + } + return CheckPassword(password.raw_str(), password.GetLength(), FALSE, + m_EncryptKey, key_len); +} + +uint32_t CPDF_SecurityHandler::GetPermissions() { + return m_bOwnerUnlocked ? 0xFFFFFFFF : m_Permissions; +} + +static FX_BOOL LoadCryptInfo(CPDF_Dictionary* pEncryptDict, + const CFX_ByteString& name, + int& cipher, + int& keylen) { + int Version = pEncryptDict->GetIntegerFor("V"); + cipher = FXCIPHER_RC4; + keylen = 0; + if (Version >= 4) { + CPDF_Dictionary* pCryptFilters = pEncryptDict->GetDictFor("CF"); + if (!pCryptFilters) { + return FALSE; + } + if (name == "Identity") { + cipher = FXCIPHER_NONE; + } else { + CPDF_Dictionary* pDefFilter = pCryptFilters->GetDictFor(name); + if (!pDefFilter) { + return FALSE; + } + int nKeyBits = 0; + if (Version == 4) { + nKeyBits = pDefFilter->GetIntegerFor("Length", 0); + if (nKeyBits == 0) { + nKeyBits = pEncryptDict->GetIntegerFor("Length", 128); + } + } else { + nKeyBits = pEncryptDict->GetIntegerFor("Length", 256); + } + if (nKeyBits < 40) { + nKeyBits *= 8; + } + keylen = nKeyBits / 8; + CFX_ByteString cipher_name = pDefFilter->GetStringFor("CFM"); + if (cipher_name == "AESV2" || cipher_name == "AESV3") { + cipher = FXCIPHER_AES; + } + } + } else { + keylen = Version > 1 ? pEncryptDict->GetIntegerFor("Length", 40) / 8 : 5; + } + if (keylen > 32 || keylen < 0) { + return FALSE; + } + return TRUE; +} + +FX_BOOL CPDF_SecurityHandler::LoadDict(CPDF_Dictionary* pEncryptDict) { + m_pEncryptDict = pEncryptDict; + m_Version = pEncryptDict->GetIntegerFor("V"); + m_Revision = pEncryptDict->GetIntegerFor("R"); + m_Permissions = pEncryptDict->GetIntegerFor("P", -1); + if (m_Version < 4) + return LoadCryptInfo(pEncryptDict, CFX_ByteString(), m_Cipher, m_KeyLen); + + CFX_ByteString stmf_name = pEncryptDict->GetStringFor("StmF"); + CFX_ByteString strf_name = pEncryptDict->GetStringFor("StrF"); + if (stmf_name != strf_name) + return FALSE; + + return LoadCryptInfo(pEncryptDict, strf_name, m_Cipher, m_KeyLen); +} + +FX_BOOL CPDF_SecurityHandler::LoadDict(CPDF_Dictionary* pEncryptDict, + uint32_t type, + int& cipher, + int& key_len) { + m_pEncryptDict = pEncryptDict; + m_Version = pEncryptDict->GetIntegerFor("V"); + m_Revision = pEncryptDict->GetIntegerFor("R"); + m_Permissions = pEncryptDict->GetIntegerFor("P", -1); + + CFX_ByteString strf_name; + CFX_ByteString stmf_name; + if (m_Version >= 4) { + stmf_name = pEncryptDict->GetStringFor("StmF"); + strf_name = pEncryptDict->GetStringFor("StrF"); + if (stmf_name != strf_name) + return FALSE; + } + if (!LoadCryptInfo(pEncryptDict, strf_name, cipher, key_len)) + return FALSE; + + m_Cipher = cipher; + m_KeyLen = key_len; + return TRUE; +} + +FX_BOOL CPDF_SecurityHandler::GetCryptInfo(int& cipher, + const uint8_t*& buffer, + int& keylen) { + cipher = m_Cipher; + buffer = m_EncryptKey; + keylen = m_KeyLen; + return TRUE; +} +#define FX_GET_32WORD(n, b, i) \ + { \ + (n) = (uint32_t)( \ + ((uint64_t)(b)[(i)] << 24) | ((uint64_t)(b)[(i) + 1] << 16) | \ + ((uint64_t)(b)[(i) + 2] << 8) | ((uint64_t)(b)[(i) + 3])); \ + } +int BigOrder64BitsMod3(uint8_t* data) { + uint64_t ret = 0; + for (int i = 0; i < 4; ++i) { + uint32_t value; + FX_GET_32WORD(value, data, 4 * i); + ret <<= 32; + ret |= value; + ret %= 3; + } + return (int)ret; +} +void Revision6_Hash(const uint8_t* password, + uint32_t size, + const uint8_t* salt, + const uint8_t* vector, + uint8_t* hash) { + int iBlockSize = 32; + uint8_t sha[128]; + CRYPT_SHA256Start(sha); + CRYPT_SHA256Update(sha, password, size); + CRYPT_SHA256Update(sha, salt, 8); + if (vector) { + CRYPT_SHA256Update(sha, vector, 48); + } + uint8_t digest[32]; + CRYPT_SHA256Finish(sha, digest); + CFX_ByteTextBuf buf; + uint8_t* input = digest; + uint8_t* key = input; + uint8_t* iv = input + 16; + uint8_t* E = buf.GetBuffer(); + int iBufLen = buf.GetLength(); + CFX_ByteTextBuf interDigest; + int i = 0; + uint8_t* aes = FX_Alloc(uint8_t, 2048); + while (i < 64 || i < E[iBufLen - 1] + 32) { + int iRoundSize = size + iBlockSize; + if (vector) { + iRoundSize += 48; + } + iBufLen = iRoundSize * 64; + buf.EstimateSize(iBufLen); + E = buf.GetBuffer(); + CFX_ByteTextBuf content; + for (int j = 0; j < 64; ++j) { + content.AppendBlock(password, size); + content.AppendBlock(input, iBlockSize); + if (vector) { + content.AppendBlock(vector, 48); + } + } + CRYPT_AESSetKey(aes, 16, key, 16, TRUE); + CRYPT_AESSetIV(aes, iv); + CRYPT_AESEncrypt(aes, E, content.GetBuffer(), iBufLen); + int iHash = 0; + switch (BigOrder64BitsMod3(E)) { + case 0: + iHash = 0; + iBlockSize = 32; + break; + case 1: + iHash = 1; + iBlockSize = 48; + break; + default: + iHash = 2; + iBlockSize = 64; + break; + } + interDigest.EstimateSize(iBlockSize); + input = interDigest.GetBuffer(); + if (iHash == 0) { + CRYPT_SHA256Generate(E, iBufLen, input); + } else if (iHash == 1) { + CRYPT_SHA384Generate(E, iBufLen, input); + } else if (iHash == 2) { + CRYPT_SHA512Generate(E, iBufLen, input); + } + key = input; + iv = input + 16; + ++i; + } + FX_Free(aes); + if (hash) { + FXSYS_memcpy(hash, input, 32); + } +} +FX_BOOL CPDF_SecurityHandler::AES256_CheckPassword(const uint8_t* password, + uint32_t size, + FX_BOOL bOwner, + uint8_t* key) { + CFX_ByteString okey = + m_pEncryptDict ? m_pEncryptDict->GetStringFor("O") : CFX_ByteString(); + if (okey.GetLength() < 48) { + return FALSE; + } + CFX_ByteString ukey = + m_pEncryptDict ? m_pEncryptDict->GetStringFor("U") : CFX_ByteString(); + if (ukey.GetLength() < 48) { + return FALSE; + } + const uint8_t* pkey = (bOwner ? okey : ukey).raw_str(); + uint8_t sha[128]; + uint8_t digest[32]; + if (m_Revision >= 6) { + Revision6_Hash(password, size, (const uint8_t*)pkey + 32, + bOwner ? ukey.raw_str() : nullptr, digest); + } else { + CRYPT_SHA256Start(sha); + CRYPT_SHA256Update(sha, password, size); + CRYPT_SHA256Update(sha, pkey + 32, 8); + if (bOwner) { + CRYPT_SHA256Update(sha, ukey.raw_str(), 48); + } + CRYPT_SHA256Finish(sha, digest); + } + if (FXSYS_memcmp(digest, pkey, 32) != 0) { + return FALSE; + } + if (!key) { + return TRUE; + } + if (m_Revision >= 6) { + Revision6_Hash(password, size, (const uint8_t*)pkey + 40, + bOwner ? ukey.raw_str() : nullptr, digest); + } else { + CRYPT_SHA256Start(sha); + CRYPT_SHA256Update(sha, password, size); + CRYPT_SHA256Update(sha, pkey + 40, 8); + if (bOwner) { + CRYPT_SHA256Update(sha, ukey.raw_str(), 48); + } + CRYPT_SHA256Finish(sha, digest); + } + CFX_ByteString ekey = m_pEncryptDict + ? m_pEncryptDict->GetStringFor(bOwner ? "OE" : "UE") + : CFX_ByteString(); + if (ekey.GetLength() < 32) { + return FALSE; + } + uint8_t* aes = FX_Alloc(uint8_t, 2048); + CRYPT_AESSetKey(aes, 16, digest, 32, FALSE); + uint8_t iv[16]; + FXSYS_memset(iv, 0, 16); + CRYPT_AESSetIV(aes, iv); + CRYPT_AESDecrypt(aes, key, ekey.raw_str(), 32); + CRYPT_AESSetKey(aes, 16, key, 32, FALSE); + CRYPT_AESSetIV(aes, iv); + CFX_ByteString perms = m_pEncryptDict->GetStringFor("Perms"); + if (perms.IsEmpty()) { + return FALSE; + } + uint8_t perms_buf[16]; + FXSYS_memset(perms_buf, 0, sizeof(perms_buf)); + uint32_t copy_len = sizeof(perms_buf); + if (copy_len > (uint32_t)perms.GetLength()) { + copy_len = perms.GetLength(); + } + FXSYS_memcpy(perms_buf, perms.raw_str(), copy_len); + uint8_t buf[16]; + CRYPT_AESDecrypt(aes, buf, perms_buf, 16); + FX_Free(aes); + if (buf[9] != 'a' || buf[10] != 'd' || buf[11] != 'b') { + return FALSE; + } + if (FXDWORD_GET_LSBFIRST(buf) != m_Permissions) { + return FALSE; + } + if ((buf[8] == 'T' && !IsMetadataEncrypted()) || + (buf[8] == 'F' && IsMetadataEncrypted())) { + return FALSE; + } + return TRUE; +} + +int CPDF_SecurityHandler::CheckPassword(const uint8_t* password, + uint32_t size, + FX_BOOL bOwner, + uint8_t* key, + int32_t key_len) { + if (m_Revision >= 5) { + return AES256_CheckPassword(password, size, bOwner, key); + } + uint8_t keybuf[32]; + if (!key) { + key = keybuf; + } + if (bOwner) { + return CheckOwnerPassword(password, size, key, key_len); + } + return CheckUserPassword(password, size, FALSE, key, key_len) || + CheckUserPassword(password, size, TRUE, key, key_len); +} +FX_BOOL CPDF_SecurityHandler::CheckUserPassword(const uint8_t* password, + uint32_t pass_size, + FX_BOOL bIgnoreEncryptMeta, + uint8_t* key, + int32_t key_len) { + CalcEncryptKey(m_pEncryptDict, password, pass_size, key, key_len, + bIgnoreEncryptMeta, m_pParser->GetIDArray()); + CFX_ByteString ukey = + m_pEncryptDict ? m_pEncryptDict->GetStringFor("U") : CFX_ByteString(); + if (ukey.GetLength() < 16) { + return FALSE; + } + uint8_t ukeybuf[32]; + if (m_Revision == 2) { + FXSYS_memcpy(ukeybuf, defpasscode, 32); + CRYPT_ArcFourCryptBlock(ukeybuf, 32, key, key_len); + } else { + uint8_t test[32], tmpkey[32]; + uint32_t copy_len = sizeof(test); + if (copy_len > (uint32_t)ukey.GetLength()) { + copy_len = ukey.GetLength(); + } + FXSYS_memset(test, 0, sizeof(test)); + FXSYS_memset(tmpkey, 0, sizeof(tmpkey)); + FXSYS_memcpy(test, ukey.c_str(), copy_len); + for (int32_t i = 19; i >= 0; i--) { + for (int j = 0; j < key_len; j++) + tmpkey[j] = key[j] ^ static_cast(i); + CRYPT_ArcFourCryptBlock(test, 32, tmpkey, key_len); + } + uint8_t md5[100]; + CRYPT_MD5Start(md5); + CRYPT_MD5Update(md5, defpasscode, 32); + CPDF_Array* pIdArray = m_pParser->GetIDArray(); + if (pIdArray) { + CFX_ByteString id = pIdArray->GetStringAt(0); + CRYPT_MD5Update(md5, (uint8_t*)id.c_str(), id.GetLength()); + } + CRYPT_MD5Finish(md5, ukeybuf); + return FXSYS_memcmp(test, ukeybuf, 16) == 0; + } + if (FXSYS_memcmp((void*)ukey.c_str(), ukeybuf, 16) == 0) { + return TRUE; + } + return FALSE; +} +CFX_ByteString CPDF_SecurityHandler::GetUserPassword(const uint8_t* owner_pass, + uint32_t pass_size, + int32_t key_len) { + CFX_ByteString okey = m_pEncryptDict->GetStringFor("O"); + uint8_t passcode[32]; + for (uint32_t i = 0; i < 32; i++) { + passcode[i] = i < pass_size ? owner_pass[i] : defpasscode[i - pass_size]; + } + uint8_t digest[16]; + CRYPT_MD5Generate(passcode, 32, digest); + if (m_Revision >= 3) { + for (uint32_t i = 0; i < 50; i++) { + CRYPT_MD5Generate(digest, 16, digest); + } + } + uint8_t enckey[32]; + FXSYS_memset(enckey, 0, sizeof(enckey)); + uint32_t copy_len = key_len; + if (copy_len > sizeof(digest)) { + copy_len = sizeof(digest); + } + FXSYS_memcpy(enckey, digest, copy_len); + int okeylen = okey.GetLength(); + if (okeylen > 32) { + okeylen = 32; + } + uint8_t okeybuf[64]; + FXSYS_memset(okeybuf, 0, sizeof(okeybuf)); + FXSYS_memcpy(okeybuf, okey.c_str(), okeylen); + if (m_Revision == 2) { + CRYPT_ArcFourCryptBlock(okeybuf, okeylen, enckey, key_len); + } else { + for (int32_t i = 19; i >= 0; i--) { + uint8_t tempkey[32]; + FXSYS_memset(tempkey, 0, sizeof(tempkey)); + for (int j = 0; j < m_KeyLen; j++) + tempkey[j] = enckey[j] ^ static_cast(i); + CRYPT_ArcFourCryptBlock(okeybuf, okeylen, tempkey, key_len); + } + } + int len = 32; + while (len && defpasscode[len - 1] == okeybuf[len - 1]) { + len--; + } + return CFX_ByteString(okeybuf, len); +} +FX_BOOL CPDF_SecurityHandler::CheckOwnerPassword(const uint8_t* password, + uint32_t pass_size, + uint8_t* key, + int32_t key_len) { + CFX_ByteString user_pass = GetUserPassword(password, pass_size, key_len); + if (CheckUserPassword(user_pass.raw_str(), user_pass.GetLength(), FALSE, key, + key_len)) { + return TRUE; + } + return CheckUserPassword(user_pass.raw_str(), user_pass.GetLength(), TRUE, + key, key_len); +} + +bool CPDF_SecurityHandler::IsMetadataEncrypted() const { + return m_pEncryptDict->GetBooleanFor("EncryptMetadata", true); +} + +void CPDF_SecurityHandler::OnCreate(CPDF_Dictionary* pEncryptDict, + CPDF_Array* pIdArray, + const uint8_t* user_pass, + uint32_t user_size, + const uint8_t* owner_pass, + uint32_t owner_size, + FX_BOOL bDefault, + uint32_t type) { + int cipher = 0, key_len = 0; + if (!LoadDict(pEncryptDict, type, cipher, key_len)) { + return; + } + if (bDefault && (!owner_pass || owner_size == 0)) { + owner_pass = user_pass; + owner_size = user_size; + } + if (m_Revision >= 5) { + int t = (int)time(nullptr); + uint8_t sha[128]; + CRYPT_SHA256Start(sha); + CRYPT_SHA256Update(sha, (uint8_t*)&t, sizeof t); + CRYPT_SHA256Update(sha, m_EncryptKey, 32); + CRYPT_SHA256Update(sha, (uint8_t*)"there", 5); + CRYPT_SHA256Finish(sha, m_EncryptKey); + AES256_SetPassword(pEncryptDict, user_pass, user_size, FALSE, m_EncryptKey); + if (bDefault) { + AES256_SetPassword(pEncryptDict, owner_pass, owner_size, TRUE, + m_EncryptKey); + AES256_SetPerms(pEncryptDict, m_Permissions, + pEncryptDict->GetBooleanFor("EncryptMetadata", true), + m_EncryptKey); + } + return; + } + if (bDefault) { + uint8_t passcode[32]; + for (uint32_t i = 0; i < 32; i++) { + passcode[i] = + i < owner_size ? owner_pass[i] : defpasscode[i - owner_size]; + } + uint8_t digest[16]; + CRYPT_MD5Generate(passcode, 32, digest); + if (m_Revision >= 3) { + for (uint32_t i = 0; i < 50; i++) + CRYPT_MD5Generate(digest, 16, digest); + } + uint8_t enckey[32]; + FXSYS_memcpy(enckey, digest, key_len); + for (uint32_t i = 0; i < 32; i++) { + passcode[i] = i < user_size ? user_pass[i] : defpasscode[i - user_size]; + } + CRYPT_ArcFourCryptBlock(passcode, 32, enckey, key_len); + uint8_t tempkey[32]; + if (m_Revision >= 3) { + for (uint8_t i = 1; i <= 19; i++) { + for (int j = 0; j < key_len; j++) + tempkey[j] = enckey[j] ^ i; + CRYPT_ArcFourCryptBlock(passcode, 32, tempkey, key_len); + } + } + pEncryptDict->SetStringFor("O", CFX_ByteString(passcode, 32)); + } + CalcEncryptKey(m_pEncryptDict, (uint8_t*)user_pass, user_size, m_EncryptKey, + key_len, FALSE, pIdArray); + if (m_Revision < 3) { + uint8_t tempbuf[32]; + FXSYS_memcpy(tempbuf, defpasscode, 32); + CRYPT_ArcFourCryptBlock(tempbuf, 32, m_EncryptKey, key_len); + pEncryptDict->SetStringFor("U", CFX_ByteString(tempbuf, 32)); + } else { + uint8_t md5[100]; + CRYPT_MD5Start(md5); + CRYPT_MD5Update(md5, defpasscode, 32); + if (pIdArray) { + CFX_ByteString id = pIdArray->GetStringAt(0); + CRYPT_MD5Update(md5, (uint8_t*)id.c_str(), id.GetLength()); + } + uint8_t digest[32]; + CRYPT_MD5Finish(md5, digest); + CRYPT_ArcFourCryptBlock(digest, 16, m_EncryptKey, key_len); + uint8_t tempkey[32]; + for (uint8_t i = 1; i <= 19; i++) { + for (int j = 0; j < key_len; j++) { + tempkey[j] = m_EncryptKey[j] ^ i; + } + CRYPT_ArcFourCryptBlock(digest, 16, tempkey, key_len); + } + CRYPT_MD5Generate(digest, 16, digest + 16); + pEncryptDict->SetStringFor("U", CFX_ByteString(digest, 32)); + } +} +void CPDF_SecurityHandler::OnCreate(CPDF_Dictionary* pEncryptDict, + CPDF_Array* pIdArray, + const uint8_t* user_pass, + uint32_t user_size, + const uint8_t* owner_pass, + uint32_t owner_size, + uint32_t type) { + OnCreate(pEncryptDict, pIdArray, user_pass, user_size, owner_pass, owner_size, + TRUE, type); +} +void CPDF_SecurityHandler::OnCreate(CPDF_Dictionary* pEncryptDict, + CPDF_Array* pIdArray, + const uint8_t* user_pass, + uint32_t user_size, + uint32_t type) { + OnCreate(pEncryptDict, pIdArray, user_pass, user_size, nullptr, 0, FALSE, + type); +} +void CPDF_SecurityHandler::AES256_SetPassword(CPDF_Dictionary* pEncryptDict, + const uint8_t* password, + uint32_t size, + FX_BOOL bOwner, + const uint8_t* key) { + uint8_t sha[128]; + CRYPT_SHA1Start(sha); + CRYPT_SHA1Update(sha, key, 32); + CRYPT_SHA1Update(sha, (uint8_t*)"hello", 5); + uint8_t digest[20]; + CRYPT_SHA1Finish(sha, digest); + CFX_ByteString ukey = pEncryptDict->GetStringFor("U"); + uint8_t digest1[48]; + if (m_Revision >= 6) { + Revision6_Hash(password, size, digest, bOwner ? ukey.raw_str() : nullptr, + digest1); + } else { + CRYPT_SHA256Start(sha); + CRYPT_SHA256Update(sha, password, size); + CRYPT_SHA256Update(sha, digest, 8); + if (bOwner) { + CRYPT_SHA256Update(sha, ukey.raw_str(), ukey.GetLength()); + } + CRYPT_SHA256Finish(sha, digest1); + } + FXSYS_memcpy(digest1 + 32, digest, 16); + pEncryptDict->SetStringFor(bOwner ? "O" : "U", CFX_ByteString(digest1, 48)); + if (m_Revision >= 6) { + Revision6_Hash(password, size, digest + 8, + bOwner ? ukey.raw_str() : nullptr, digest1); + } else { + CRYPT_SHA256Start(sha); + CRYPT_SHA256Update(sha, password, size); + CRYPT_SHA256Update(sha, digest + 8, 8); + if (bOwner) { + CRYPT_SHA256Update(sha, ukey.raw_str(), ukey.GetLength()); + } + CRYPT_SHA256Finish(sha, digest1); + } + uint8_t* aes = FX_Alloc(uint8_t, 2048); + CRYPT_AESSetKey(aes, 16, digest1, 32, TRUE); + uint8_t iv[16]; + FXSYS_memset(iv, 0, 16); + CRYPT_AESSetIV(aes, iv); + CRYPT_AESEncrypt(aes, digest1, key, 32); + FX_Free(aes); + pEncryptDict->SetStringFor(bOwner ? "OE" : "UE", CFX_ByteString(digest1, 32)); +} +void CPDF_SecurityHandler::AES256_SetPerms(CPDF_Dictionary* pEncryptDict, + uint32_t permissions, + FX_BOOL bEncryptMetadata, + const uint8_t* key) { + uint8_t buf[16]; + buf[0] = (uint8_t)permissions; + buf[1] = (uint8_t)(permissions >> 8); + buf[2] = (uint8_t)(permissions >> 16); + buf[3] = (uint8_t)(permissions >> 24); + buf[4] = 0xff; + buf[5] = 0xff; + buf[6] = 0xff; + buf[7] = 0xff; + buf[8] = bEncryptMetadata ? 'T' : 'F'; + buf[9] = 'a'; + buf[10] = 'd'; + buf[11] = 'b'; + uint8_t* aes = FX_Alloc(uint8_t, 2048); + CRYPT_AESSetKey(aes, 16, key, 32, TRUE); + uint8_t iv[16], buf1[16]; + FXSYS_memset(iv, 0, 16); + CRYPT_AESSetIV(aes, iv); + CRYPT_AESEncrypt(aes, buf1, buf, 16); + FX_Free(aes); + pEncryptDict->SetStringFor("Perms", CFX_ByteString(buf1, 16)); +} diff --git a/core/fpdfapi/parser/cpdf_security_handler.h b/core/fpdfapi/parser/cpdf_security_handler.h new file mode 100644 index 0000000000..686a25c1c5 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_security_handler.h @@ -0,0 +1,110 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_SECURITY_HANDLER_H_ +#define CORE_FPDFAPI_PARSER_CPDF_SECURITY_HANDLER_H_ + +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/fx_system.h" + +#define FXCIPHER_NONE 0 +#define FXCIPHER_RC4 1 +#define FXCIPHER_AES 2 +#define FXCIPHER_AES2 3 + +#define PDF_ENCRYPT_CONTENT 0 + +class CPDF_Array; +class CPDF_CryptoHandler; +class CPDF_Dictionary; +class CPDF_Parser; + +class CPDF_SecurityHandler { + public: + CPDF_SecurityHandler(); + ~CPDF_SecurityHandler(); + + FX_BOOL OnInit(CPDF_Parser* pParser, CPDF_Dictionary* pEncryptDict); + uint32_t GetPermissions(); + FX_BOOL GetCryptInfo(int& cipher, const uint8_t*& buffer, int& keylen); + bool IsMetadataEncrypted() const; + CPDF_CryptoHandler* CreateCryptoHandler(); + + void OnCreate(CPDF_Dictionary* pEncryptDict, + CPDF_Array* pIdArray, + const uint8_t* user_pass, + uint32_t user_size, + const uint8_t* owner_pass, + uint32_t owner_size, + uint32_t type = PDF_ENCRYPT_CONTENT); + + void OnCreate(CPDF_Dictionary* pEncryptDict, + CPDF_Array* pIdArray, + const uint8_t* user_pass, + uint32_t user_size, + uint32_t type = PDF_ENCRYPT_CONTENT); + + CFX_ByteString GetUserPassword(const uint8_t* owner_pass, + uint32_t pass_size, + int32_t key_len); + int CheckPassword(const uint8_t* password, + uint32_t pass_size, + FX_BOOL bOwner, + uint8_t* key, + int key_len); + + private: + FX_BOOL LoadDict(CPDF_Dictionary* pEncryptDict); + FX_BOOL LoadDict(CPDF_Dictionary* pEncryptDict, + uint32_t type, + int& cipher, + int& key_len); + + FX_BOOL CheckUserPassword(const uint8_t* password, + uint32_t pass_size, + FX_BOOL bIgnoreEncryptMeta, + uint8_t* key, + int32_t key_len); + + FX_BOOL CheckOwnerPassword(const uint8_t* password, + uint32_t pass_size, + uint8_t* key, + int32_t key_len); + FX_BOOL AES256_CheckPassword(const uint8_t* password, + uint32_t size, + FX_BOOL bOwner, + uint8_t* key); + void AES256_SetPassword(CPDF_Dictionary* pEncryptDict, + const uint8_t* password, + uint32_t size, + FX_BOOL bOwner, + const uint8_t* key); + void AES256_SetPerms(CPDF_Dictionary* pEncryptDict, + uint32_t permission, + FX_BOOL bEncryptMetadata, + const uint8_t* key); + void OnCreate(CPDF_Dictionary* pEncryptDict, + CPDF_Array* pIdArray, + const uint8_t* user_pass, + uint32_t user_size, + const uint8_t* owner_pass, + uint32_t owner_size, + FX_BOOL bDefault, + uint32_t type); + FX_BOOL CheckSecurity(int32_t key_len); + + int m_Version; + int m_Revision; + CPDF_Parser* m_pParser; + CPDF_Dictionary* m_pEncryptDict; + uint32_t m_Permissions; + int m_Cipher; + uint8_t m_EncryptKey[32]; + int m_KeyLen; + bool m_bOwnerUnlocked; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_SECURITY_HANDLER_H_ diff --git a/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp b/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp new file mode 100644 index 0000000000..37b6d8fc33 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp @@ -0,0 +1,32 @@ +// Copyright 2016 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. + +#include "testing/embedder_test.h" +#include "testing/gtest/include/gtest/gtest.h" + +class CPDFSecurityHandlerEmbeddertest : public EmbedderTest {}; + +TEST_F(CPDFSecurityHandlerEmbeddertest, Unencrypted) { + ASSERT_TRUE(OpenDocument("about_blank.pdf")); + EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocPermissions(document())); +} + +TEST_F(CPDFSecurityHandlerEmbeddertest, UnencryptedWithPassword) { + ASSERT_TRUE(OpenDocument("about_blank.pdf", "foobar")); + EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocPermissions(document())); +} + +TEST_F(CPDFSecurityHandlerEmbeddertest, NoPassword) { + EXPECT_FALSE(OpenDocument("encrypted.pdf")); +} + +TEST_F(CPDFSecurityHandlerEmbeddertest, UserPassword) { + ASSERT_TRUE(OpenDocument("encrypted.pdf", "1234")); + EXPECT_EQ(0xFFFFF2C0, FPDF_GetDocPermissions(document())); +} + +TEST_F(CPDFSecurityHandlerEmbeddertest, OwnerPassword) { + ASSERT_TRUE(OpenDocument("encrypted.pdf", "5678")); + EXPECT_EQ(0xFFFFFFFC, FPDF_GetDocPermissions(document())); +} diff --git a/core/fpdfapi/parser/cpdf_simple_parser.cpp b/core/fpdfapi/parser/cpdf_simple_parser.cpp new file mode 100644 index 0000000000..650c216e05 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_simple_parser.cpp @@ -0,0 +1,170 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_simple_parser.h" + +#include "core/fpdfapi/parser/fpdf_parser_utility.h" + +CPDF_SimpleParser::CPDF_SimpleParser(const uint8_t* pData, uint32_t dwSize) + : m_pData(pData), m_dwSize(dwSize), m_dwCurPos(0) {} + +CPDF_SimpleParser::CPDF_SimpleParser(const CFX_ByteStringC& str) + : m_pData(str.raw_str()), m_dwSize(str.GetLength()), m_dwCurPos(0) {} + +void CPDF_SimpleParser::ParseWord(const uint8_t*& pStart, uint32_t& dwSize) { + pStart = nullptr; + dwSize = 0; + uint8_t ch; + while (1) { + if (m_dwSize <= m_dwCurPos) + return; + ch = m_pData[m_dwCurPos++]; + while (PDFCharIsWhitespace(ch)) { + if (m_dwSize <= m_dwCurPos) + return; + ch = m_pData[m_dwCurPos++]; + } + + if (ch != '%') + break; + + while (1) { + if (m_dwSize <= m_dwCurPos) + return; + ch = m_pData[m_dwCurPos++]; + if (PDFCharIsLineEnding(ch)) + break; + } + } + + uint32_t start_pos = m_dwCurPos - 1; + pStart = m_pData + start_pos; + if (PDFCharIsDelimiter(ch)) { + if (ch == '/') { + while (1) { + if (m_dwSize <= m_dwCurPos) + return; + ch = m_pData[m_dwCurPos++]; + if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { + m_dwCurPos--; + dwSize = m_dwCurPos - start_pos; + return; + } + } + } else { + dwSize = 1; + if (ch == '<') { + if (m_dwSize <= m_dwCurPos) + return; + ch = m_pData[m_dwCurPos++]; + if (ch == '<') + dwSize = 2; + else + m_dwCurPos--; + } else if (ch == '>') { + if (m_dwSize <= m_dwCurPos) + return; + ch = m_pData[m_dwCurPos++]; + if (ch == '>') + dwSize = 2; + else + m_dwCurPos--; + } + } + return; + } + + dwSize = 1; + while (1) { + if (m_dwSize <= m_dwCurPos) + return; + ch = m_pData[m_dwCurPos++]; + + if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { + m_dwCurPos--; + break; + } + dwSize++; + } +} + +CFX_ByteStringC CPDF_SimpleParser::GetWord() { + const uint8_t* pStart; + uint32_t dwSize; + ParseWord(pStart, dwSize); + if (dwSize == 1 && pStart[0] == '<') { + while (m_dwCurPos < m_dwSize && m_pData[m_dwCurPos] != '>') { + m_dwCurPos++; + } + if (m_dwCurPos < m_dwSize) { + m_dwCurPos++; + } + return CFX_ByteStringC(pStart, + (FX_STRSIZE)(m_dwCurPos - (pStart - m_pData))); + } + if (dwSize == 1 && pStart[0] == '(') { + int level = 1; + while (m_dwCurPos < m_dwSize) { + if (m_pData[m_dwCurPos] == ')') { + level--; + if (level == 0) { + break; + } + } + if (m_pData[m_dwCurPos] == '\\') { + if (m_dwSize <= m_dwCurPos) { + break; + } + m_dwCurPos++; + } else if (m_pData[m_dwCurPos] == '(') { + level++; + } + if (m_dwSize <= m_dwCurPos) { + break; + } + m_dwCurPos++; + } + if (m_dwCurPos < m_dwSize) { + m_dwCurPos++; + } + return CFX_ByteStringC(pStart, + (FX_STRSIZE)(m_dwCurPos - (pStart - m_pData))); + } + return CFX_ByteStringC(pStart, dwSize); +} + +bool CPDF_SimpleParser::FindTagParamFromStart(const CFX_ByteStringC& token, + int nParams) { + nParams++; + uint32_t* pBuf = FX_Alloc(uint32_t, nParams); + int buf_index = 0; + int buf_count = 0; + m_dwCurPos = 0; + while (1) { + pBuf[buf_index++] = m_dwCurPos; + if (buf_index == nParams) { + buf_index = 0; + } + buf_count++; + if (buf_count > nParams) { + buf_count = nParams; + } + CFX_ByteStringC word = GetWord(); + if (word.IsEmpty()) { + FX_Free(pBuf); + return false; + } + if (word == token) { + if (buf_count < nParams) { + continue; + } + m_dwCurPos = pBuf[buf_index]; + FX_Free(pBuf); + return true; + } + } + return false; +} diff --git a/core/fpdfapi/parser/cpdf_simple_parser.h b/core/fpdfapi/parser/cpdf_simple_parser.h new file mode 100644 index 0000000000..c638b8a04b --- /dev/null +++ b/core/fpdfapi/parser/cpdf_simple_parser.h @@ -0,0 +1,35 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_SIMPLE_PARSER_H_ +#define CORE_FPDFAPI_PARSER_CPDF_SIMPLE_PARSER_H_ + +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/fx_system.h" + +class CPDF_SimpleParser { + public: + CPDF_SimpleParser(const uint8_t* pData, uint32_t dwSize); + CPDF_SimpleParser(const CFX_ByteStringC& str); + + CFX_ByteStringC GetWord(); + + // Find the token and its |nParams| parameters from the start of data, + // and move the current position to the start of those parameters. + bool FindTagParamFromStart(const CFX_ByteStringC& token, int nParams); + + // For testing only. + uint32_t GetCurPos() const { return m_dwCurPos; } + + private: + void ParseWord(const uint8_t*& pStart, uint32_t& dwSize); + + const uint8_t* m_pData; + uint32_t m_dwSize; + uint32_t m_dwCurPos; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_SIMPLE_PARSER_H_ diff --git a/core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp new file mode 100644 index 0000000000..5f56b948cd --- /dev/null +++ b/core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp @@ -0,0 +1,96 @@ +// Copyright 2016 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. + +#include "core/fpdfapi/parser/cpdf_simple_parser.h" + +#include + +#include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcrt/fx_basic.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/test_support.h" + +TEST(SimpleParserTest, GetWord) { + pdfium::StrFuncTestData test_data[] = { + // Empty src string. + STR_IN_OUT_CASE("", ""), + // Content with whitespaces only. + STR_IN_OUT_CASE(" \t \0 \n", ""), + // Content with comments only. + STR_IN_OUT_CASE("%this is a test case\r\n%2nd line", ""), + // Mixed whitespaces and comments. + STR_IN_OUT_CASE(" \t \0%try()%haha\n %another line \aa", ""), + // Name. + STR_IN_OUT_CASE(" /Tester ", "/Tester"), + // String. + STR_IN_OUT_CASE("\t(nice day)!\n ", "(nice day)"), + // String with nested braces. + STR_IN_OUT_CASE("\t(It is a (long) day)!\n ", "(It is a (long) day)"), + // String with escaped chars. + STR_IN_OUT_CASE("\t(It is a \\(long\\) day!)hi\n ", + "(It is a \\(long\\) day!)"), + // Hex string. + STR_IN_OUT_CASE(" \n<4545acdfedertt>abc ", "<4545acdfedertt>"), + STR_IN_OUT_CASE(" \n<4545aertt>abc ", "<4545a"), + // Dictionary. + STR_IN_OUT_CASE("<>", "<<"), + STR_IN_OUT_CASE("\t\t<< /abc>>", "<<"), + // Handling ending delimiters. + STR_IN_OUT_CASE("> little bear", ">"), + STR_IN_OUT_CASE(") another bear", ")"), STR_IN_OUT_CASE(">> end ", ">>"), + // No ending delimiters. + STR_IN_OUT_CASE("(sdfgfgbcv", "(sdfgfgbcv"), + // Regular cases. + STR_IN_OUT_CASE("apple pear", "apple"), + STR_IN_OUT_CASE(" pi=3.1415 ", "pi=3.1415"), + STR_IN_OUT_CASE(" p t x c ", "p"), STR_IN_OUT_CASE(" pt\0xc ", "pt"), + STR_IN_OUT_CASE(" $^&&*\t\0sdff ", "$^&&*"), + STR_IN_OUT_CASE("\n\r+3.5656 -11.0", "+3.5656"), + }; + for (size_t i = 0; i < FX_ArraySize(test_data); ++i) { + const pdfium::StrFuncTestData& data = test_data[i]; + CPDF_SimpleParser parser(data.input, data.input_size); + CFX_ByteStringC word = parser.GetWord(); + EXPECT_EQ(std::string(reinterpret_cast(data.expected), + data.expected_size), + std::string(word.c_str(), word.GetLength())) + << " for case " << i; + } +} + +TEST(SimpleParserTest, FindTagParamFromStart) { + struct FindTagTestStruct { + const unsigned char* input; + unsigned int input_size; + const char* token; + int num_params; + bool result; + unsigned int result_pos; + } test_data[] = { + // Empty strings. + STR_IN_TEST_CASE("", "Tj", 1, false, 0), + STR_IN_TEST_CASE("", "", 1, false, 0), + // Empty token. + STR_IN_TEST_CASE(" T j", "", 1, false, 5), + // No parameter. + STR_IN_TEST_CASE("Tj", "Tj", 1, false, 2), + STR_IN_TEST_CASE("(Tj", "Tj", 1, false, 3), + // Partial token match. + STR_IN_TEST_CASE("\r12\t34 56 78Tj", "Tj", 1, false, 15), + // Regular cases with various parameters. + STR_IN_TEST_CASE("\r\0abd Tj", "Tj", 1, true, 0), + STR_IN_TEST_CASE("12 4 Tj 3 46 Tj", "Tj", 1, true, 2), + STR_IN_TEST_CASE("er^ 2 (34) (5667) Tj", "Tj", 2, true, 5), + STR_IN_TEST_CASE("<344> (232)\t343.4\n12 45 Tj", "Tj", 3, true, 11), + STR_IN_TEST_CASE("1 2 3 4 5 6 7 8 cm", "cm", 6, true, 3), + }; + for (size_t i = 0; i < FX_ArraySize(test_data); ++i) { + const FindTagTestStruct& data = test_data[i]; + CPDF_SimpleParser parser(data.input, data.input_size); + EXPECT_EQ(data.result, + parser.FindTagParamFromStart(data.token, data.num_params)) + << " for case " << i; + EXPECT_EQ(data.result_pos, parser.GetCurPos()) << " for case " << i; + } +} diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp new file mode 100644 index 0000000000..c221edec68 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_stream.cpp @@ -0,0 +1,116 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_stream.h" + +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "third_party/base/numerics/safe_conversions.h" +#include "third_party/base/stl_util.h" + +CPDF_Stream::CPDF_Stream() {} + +CPDF_Stream::CPDF_Stream(uint8_t* pData, uint32_t size, CPDF_Dictionary* pDict) + : m_pDict(pDict), m_dwSize(size), m_pDataBuf(pData) {} + +CPDF_Stream::~CPDF_Stream() {} + +CPDF_Object::Type CPDF_Stream::GetType() const { + return STREAM; +} + +CPDF_Dictionary* CPDF_Stream::GetDict() const { + return m_pDict.get(); +} + +bool CPDF_Stream::IsStream() const { + return true; +} + +CPDF_Stream* CPDF_Stream::AsStream() { + return this; +} + +const CPDF_Stream* CPDF_Stream::AsStream() const { + return this; +} + +void CPDF_Stream::InitStream(const uint8_t* pData, + uint32_t size, + CPDF_Dictionary* pDict) { + m_pDict.reset(pDict); + m_bMemoryBased = true; + m_pFile = nullptr; + m_pDataBuf.reset(FX_Alloc(uint8_t, size)); + if (pData) + FXSYS_memcpy(m_pDataBuf.get(), pData, size); + m_dwSize = size; + if (m_pDict) + m_pDict->SetIntegerFor("Length", m_dwSize); +} + +void CPDF_Stream::InitStreamFromFile(IFX_FileRead* pFile, + CPDF_Dictionary* pDict) { + m_pDict.reset(pDict); + m_bMemoryBased = false; + m_pDataBuf.reset(); + m_pFile = pFile; + m_dwSize = pdfium::base::checked_cast(pFile->GetSize()); + if (m_pDict) + m_pDict->SetIntegerFor("Length", m_dwSize); +} + +CPDF_Object* CPDF_Stream::Clone() const { + return CloneObjectNonCyclic(false); +} + +CPDF_Object* CPDF_Stream::CloneNonCyclic( + bool bDirect, + std::set* pVisited) const { + pVisited->insert(this); + CPDF_StreamAcc acc; + acc.LoadAllData(this, TRUE); + uint32_t streamSize = acc.GetSize(); + CPDF_Dictionary* pDict = GetDict(); + if (pDict && !pdfium::ContainsKey(*pVisited, pDict)) { + pDict = ToDictionary( + static_cast(pDict)->CloneNonCyclic(bDirect, pVisited)); + } + + return new CPDF_Stream(acc.DetachData(), streamSize, pDict); +} + +void CPDF_Stream::SetData(const uint8_t* pData, uint32_t size) { + m_bMemoryBased = true; + m_pDataBuf.reset(FX_Alloc(uint8_t, size)); + if (pData) + FXSYS_memcpy(m_pDataBuf.get(), pData, size); + m_dwSize = size; + if (!m_pDict) + m_pDict.reset(new CPDF_Dictionary()); + m_pDict->SetIntegerFor("Length", size); + m_pDict->RemoveFor("Filter"); + m_pDict->RemoveFor("DecodeParms"); +} + +FX_BOOL CPDF_Stream::ReadRawData(FX_FILESIZE offset, + uint8_t* buf, + uint32_t size) const { + if (m_bMemoryBased && m_pFile) + return m_pFile->ReadBlock(buf, offset, size); + + if (m_pDataBuf) + FXSYS_memcpy(buf, m_pDataBuf.get() + offset, size); + + return TRUE; +} + +CFX_WideString CPDF_Stream::GetUnicodeText() const { + CPDF_StreamAcc stream; + stream.LoadAllData(this, FALSE); + return PDF_DecodeText(stream.GetData(), stream.GetSize()); +} diff --git a/core/fpdfapi/parser/cpdf_stream.h b/core/fpdfapi/parser/cpdf_stream.h new file mode 100644 index 0000000000..6a4f1011c0 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_stream.h @@ -0,0 +1,61 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_STREAM_H_ +#define CORE_FPDFAPI_PARSER_CPDF_STREAM_H_ + +#include +#include + +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/fx_basic.h" + +class CPDF_Stream : public CPDF_Object { + public: + CPDF_Stream(); + + // Takes ownership of |pData| and |pDict|. + CPDF_Stream(uint8_t* pData, uint32_t size, CPDF_Dictionary* pDict); + + // CPDF_Object. + Type GetType() const override; + CPDF_Object* Clone() const override; + CPDF_Dictionary* GetDict() const override; + CFX_WideString GetUnicodeText() const override; + bool IsStream() const override; + CPDF_Stream* AsStream() override; + const CPDF_Stream* AsStream() const override; + + uint32_t GetRawSize() const { return m_dwSize; } + uint8_t* GetRawData() const { return m_pDataBuf.get(); } + + // Does not takes onwership of |pData|, copies into internally-owned buffer. + void SetData(const uint8_t* pData, uint32_t size); + + void InitStream(const uint8_t* pData, uint32_t size, CPDF_Dictionary* pDict); + void InitStreamFromFile(IFX_FileRead* pFile, CPDF_Dictionary* pDict); + + FX_BOOL ReadRawData(FX_FILESIZE start_pos, + uint8_t* pBuf, + uint32_t buf_size) const; + + bool IsMemoryBased() const { return m_bMemoryBased; } + + protected: + ~CPDF_Stream() override; + CPDF_Object* CloneNonCyclic( + bool bDirect, + std::set* pVisited) const override; + + std::unique_ptr> m_pDict; + bool m_bMemoryBased = true; + uint32_t m_dwSize = 0; + std::unique_ptr m_pDataBuf; + IFX_FileRead* m_pFile = nullptr; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_STREAM_H_ diff --git a/core/fpdfapi/parser/cpdf_stream_acc.cpp b/core/fpdfapi/parser/cpdf_stream_acc.cpp new file mode 100644 index 0000000000..e8bf6d7e15 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_stream_acc.cpp @@ -0,0 +1,91 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_stream_acc.h" + +#include "core/fpdfapi/parser/fpdf_parser_decode.h" + +CPDF_StreamAcc::CPDF_StreamAcc() + : m_pData(nullptr), + m_dwSize(0), + m_bNewBuf(FALSE), + m_pImageParam(nullptr), + m_pStream(nullptr), + m_pSrcData(nullptr) {} + +void CPDF_StreamAcc::LoadAllData(const CPDF_Stream* pStream, + FX_BOOL bRawAccess, + uint32_t estimated_size, + FX_BOOL bImageAcc) { + if (!pStream) + return; + + m_pStream = pStream; + if (pStream->IsMemoryBased() && + (!pStream->GetDict()->KeyExist("Filter") || bRawAccess)) { + m_dwSize = pStream->GetRawSize(); + m_pData = pStream->GetRawData(); + return; + } + uint8_t* pSrcData; + uint32_t dwSrcSize = pStream->GetRawSize(); + if (dwSrcSize == 0) + return; + + if (!pStream->IsMemoryBased()) { + pSrcData = m_pSrcData = FX_Alloc(uint8_t, dwSrcSize); + if (!pStream->ReadRawData(0, pSrcData, dwSrcSize)) + return; + } else { + pSrcData = pStream->GetRawData(); + } + if (!pStream->GetDict()->KeyExist("Filter") || bRawAccess) { + m_pData = pSrcData; + m_dwSize = dwSrcSize; + } else { + FX_BOOL bRet = PDF_DataDecode(pSrcData, dwSrcSize, m_pStream->GetDict(), + m_pData, m_dwSize, m_ImageDecoder, + m_pImageParam, estimated_size, bImageAcc); + if (!bRet) { + m_pData = pSrcData; + m_dwSize = dwSrcSize; + } + } + if (pSrcData != pStream->GetRawData() && pSrcData != m_pData) + FX_Free(pSrcData); + m_pSrcData = nullptr; + 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; + return m_pStream ? m_pStream->GetRawData() : nullptr; +} + +uint32_t CPDF_StreamAcc::GetSize() const { + if (m_bNewBuf) + return m_dwSize; + return m_pStream ? m_pStream->GetRawSize() : 0; +} + +uint8_t* CPDF_StreamAcc::DetachData() { + if (m_bNewBuf) { + uint8_t* p = m_pData; + m_pData = nullptr; + m_dwSize = 0; + return p; + } + uint8_t* p = FX_Alloc(uint8_t, m_dwSize); + FXSYS_memcpy(p, m_pData, m_dwSize); + return p; +} diff --git a/core/fpdfapi/parser/cpdf_stream_acc.h b/core/fpdfapi/parser/cpdf_stream_acc.h new file mode 100644 index 0000000000..c4f312a113 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_stream_acc.h @@ -0,0 +1,46 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_STREAM_ACC_H_ +#define CORE_FPDFAPI_PARSER_CPDF_STREAM_ACC_H_ + +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/fx_system.h" + +class CPDF_StreamAcc { + public: + CPDF_StreamAcc(); + ~CPDF_StreamAcc(); + + void LoadAllData(const CPDF_Stream* pStream, + FX_BOOL bRawAccess = FALSE, + uint32_t estimated_size = 0, + 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; + uint32_t GetSize() const; + const CFX_ByteString& GetImageDecoder() const { return m_ImageDecoder; } + const CPDF_Dictionary* GetImageParam() const { return m_pImageParam; } + uint8_t* DetachData(); + + protected: + uint8_t* m_pData; + uint32_t m_dwSize; + FX_BOOL m_bNewBuf; + CFX_ByteString m_ImageDecoder; + CPDF_Dictionary* m_pImageParam; + const CPDF_Stream* m_pStream; + uint8_t* m_pSrcData; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_STREAM_ACC_H_ diff --git a/core/fpdfapi/parser/cpdf_string.cpp b/core/fpdfapi/parser/cpdf_string.cpp new file mode 100644 index 0000000000..73c7d4cf69 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_string.cpp @@ -0,0 +1,52 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_string.h" + +#include "core/fpdfapi/parser/fpdf_parser_decode.h" + +CPDF_String::CPDF_String() : m_bHex(FALSE) {} + +CPDF_String::CPDF_String(const CFX_ByteString& str, FX_BOOL bHex) + : m_String(str), m_bHex(bHex) {} + +CPDF_String::CPDF_String(const CFX_WideString& str) : m_bHex(FALSE) { + m_String = PDF_EncodeText(str); +} + +CPDF_String::~CPDF_String() {} + +CPDF_Object::Type CPDF_String::GetType() const { + return STRING; +} + +CPDF_Object* CPDF_String::Clone() const { + return new CPDF_String(m_String, m_bHex); +} + +CFX_ByteString CPDF_String::GetString() const { + return m_String; +} + +void CPDF_String::SetString(const CFX_ByteString& str) { + m_String = str; +} + +bool CPDF_String::IsString() const { + return true; +} + +CPDF_String* CPDF_String::AsString() { + return this; +} + +const CPDF_String* CPDF_String::AsString() const { + return this; +} + +CFX_WideString CPDF_String::GetUnicodeText() const { + return PDF_DecodeText(m_String); +} diff --git a/core/fpdfapi/parser/cpdf_string.h b/core/fpdfapi/parser/cpdf_string.h new file mode 100644 index 0000000000..d99e00c403 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_string.h @@ -0,0 +1,39 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_STRING_H_ +#define CORE_FPDFAPI_PARSER_CPDF_STRING_H_ + +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/fx_system.h" + +class CPDF_String : public CPDF_Object { + public: + CPDF_String(); + CPDF_String(const CFX_ByteString& str, FX_BOOL bHex); + explicit CPDF_String(const CFX_WideString& str); + + // CPDF_Object. + Type GetType() const override; + CPDF_Object* Clone() const override; + CFX_ByteString GetString() const override; + CFX_WideString GetUnicodeText() const override; + void SetString(const CFX_ByteString& str) override; + bool IsString() const override; + CPDF_String* AsString() override; + const CPDF_String* AsString() const override; + + FX_BOOL IsHex() const { return m_bHex; } + + protected: + ~CPDF_String() override; + + CFX_ByteString m_String; + FX_BOOL m_bHex; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_STRING_H_ diff --git a/core/fpdfapi/parser/cpdf_syntax_parser.cpp b/core/fpdfapi/parser/cpdf_syntax_parser.cpp new file mode 100644 index 0000000000..e7f25d15c2 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_syntax_parser.cpp @@ -0,0 +1,997 @@ +// Copyright 2016 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 + +#include "core/fpdfapi/parser/cpdf_syntax_parser.h" + +#include + +#include "core/fpdfapi/cpdf_modulemgr.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_boolean.h" +#include "core/fpdfapi/parser/cpdf_crypto_handler.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_null.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcrt/fx_ext.h" +#include "third_party/base/numerics/safe_math.h" + +namespace { + +struct SearchTagRecord { + CFX_ByteStringC m_bsTag; + FX_STRSIZE m_Offset; +}; + +} // namespace + +// static +int CPDF_SyntaxParser::s_CurrentRecursionDepth = 0; + +CPDF_SyntaxParser::CPDF_SyntaxParser() + : CPDF_SyntaxParser(CFX_WeakPtr()) {} + +CPDF_SyntaxParser::CPDF_SyntaxParser( + const CFX_WeakPtr& pPool) + : m_MetadataObjnum(0), + m_pFileAccess(nullptr), + m_pFileBuf(nullptr), + m_BufSize(CPDF_ModuleMgr::kFileBufSize), + m_pPool(pPool) {} + +CPDF_SyntaxParser::~CPDF_SyntaxParser() { + FX_Free(m_pFileBuf); +} + +FX_BOOL CPDF_SyntaxParser::GetCharAt(FX_FILESIZE pos, uint8_t& ch) { + CFX_AutoRestorer save_pos(&m_Pos); + m_Pos = pos; + return GetNextChar(ch); +} + +FX_BOOL CPDF_SyntaxParser::GetNextChar(uint8_t& ch) { + FX_FILESIZE pos = m_Pos + m_HeaderOffset; + if (pos >= m_FileLen) + return FALSE; + + if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) { + FX_FILESIZE read_pos = pos; + uint32_t read_size = m_BufSize; + if ((FX_FILESIZE)read_size > m_FileLen) + read_size = (uint32_t)m_FileLen; + + if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) { + if (m_FileLen < (FX_FILESIZE)read_size) { + read_pos = 0; + read_size = (uint32_t)m_FileLen; + } else { + read_pos = m_FileLen - read_size; + } + } + + if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) + return FALSE; + + m_BufOffset = read_pos; + } + ch = m_pFileBuf[pos - m_BufOffset]; + m_Pos++; + return TRUE; +} + +FX_BOOL CPDF_SyntaxParser::GetCharAtBackward(FX_FILESIZE pos, uint8_t& ch) { + pos += m_HeaderOffset; + if (pos >= m_FileLen) + return FALSE; + + if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) { + FX_FILESIZE read_pos; + if (pos < (FX_FILESIZE)m_BufSize) + read_pos = 0; + else + read_pos = pos - m_BufSize + 1; + + uint32_t read_size = m_BufSize; + if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) { + if (m_FileLen < (FX_FILESIZE)read_size) { + read_pos = 0; + read_size = (uint32_t)m_FileLen; + } else { + read_pos = m_FileLen - read_size; + } + } + + if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) + return FALSE; + + m_BufOffset = read_pos; + } + ch = m_pFileBuf[pos - m_BufOffset]; + return TRUE; +} + +FX_BOOL CPDF_SyntaxParser::ReadBlock(uint8_t* pBuf, uint32_t size) { + if (!m_pFileAccess->ReadBlock(pBuf, m_Pos + m_HeaderOffset, size)) + return FALSE; + m_Pos += size; + return TRUE; +} + +void CPDF_SyntaxParser::GetNextWordInternal(bool* bIsNumber) { + m_WordSize = 0; + if (bIsNumber) + *bIsNumber = true; + + uint8_t ch; + if (!GetNextChar(ch)) + return; + + while (1) { + while (PDFCharIsWhitespace(ch)) { + if (!GetNextChar(ch)) + return; + } + + if (ch != '%') + break; + + while (1) { + if (!GetNextChar(ch)) + return; + if (PDFCharIsLineEnding(ch)) + break; + } + } + + if (PDFCharIsDelimiter(ch)) { + if (bIsNumber) + *bIsNumber = false; + + m_WordBuffer[m_WordSize++] = ch; + if (ch == '/') { + while (1) { + if (!GetNextChar(ch)) + return; + + if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { + m_Pos--; + return; + } + + if (m_WordSize < sizeof(m_WordBuffer) - 1) + m_WordBuffer[m_WordSize++] = ch; + } + } else if (ch == '<') { + if (!GetNextChar(ch)) + return; + + if (ch == '<') + m_WordBuffer[m_WordSize++] = ch; + else + m_Pos--; + } else if (ch == '>') { + if (!GetNextChar(ch)) + return; + + if (ch == '>') + m_WordBuffer[m_WordSize++] = ch; + else + m_Pos--; + } + return; + } + + while (1) { + if (m_WordSize < sizeof(m_WordBuffer) - 1) + m_WordBuffer[m_WordSize++] = ch; + + if (!PDFCharIsNumeric(ch)) { + if (bIsNumber) + *bIsNumber = false; + } + + if (!GetNextChar(ch)) + return; + + if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { + m_Pos--; + break; + } + } +} + +CFX_ByteString CPDF_SyntaxParser::ReadString() { + uint8_t ch; + if (!GetNextChar(ch)) + return CFX_ByteString(); + + CFX_ByteTextBuf buf; + int32_t parlevel = 0; + int32_t status = 0; + int32_t iEscCode = 0; + while (1) { + switch (status) { + case 0: + if (ch == ')') { + if (parlevel == 0) { + return buf.MakeString(); + } + parlevel--; + buf.AppendChar(')'); + } else if (ch == '(') { + parlevel++; + buf.AppendChar('('); + } else if (ch == '\\') { + status = 1; + } else { + buf.AppendChar(ch); + } + break; + case 1: + if (ch >= '0' && ch <= '7') { + iEscCode = FXSYS_toDecimalDigit(static_cast(ch)); + status = 2; + break; + } + + if (ch == 'n') { + buf.AppendChar('\n'); + } else if (ch == 'r') { + buf.AppendChar('\r'); + } else if (ch == 't') { + buf.AppendChar('\t'); + } else if (ch == 'b') { + buf.AppendChar('\b'); + } else if (ch == 'f') { + buf.AppendChar('\f'); + } else if (ch == '\r') { + status = 4; + break; + } else if (ch != '\n') { + buf.AppendChar(ch); + } + status = 0; + break; + case 2: + if (ch >= '0' && ch <= '7') { + iEscCode = + iEscCode * 8 + FXSYS_toDecimalDigit(static_cast(ch)); + status = 3; + } else { + buf.AppendChar(iEscCode); + status = 0; + continue; + } + break; + case 3: + if (ch >= '0' && ch <= '7') { + iEscCode = + iEscCode * 8 + FXSYS_toDecimalDigit(static_cast(ch)); + buf.AppendChar(iEscCode); + status = 0; + } else { + buf.AppendChar(iEscCode); + status = 0; + continue; + } + break; + case 4: + status = 0; + if (ch != '\n') + continue; + break; + } + + if (!GetNextChar(ch)) + break; + } + + GetNextChar(ch); + return buf.MakeString(); +} + +CFX_ByteString CPDF_SyntaxParser::ReadHexString() { + uint8_t ch; + if (!GetNextChar(ch)) + return CFX_ByteString(); + + CFX_ByteTextBuf buf; + bool bFirst = true; + uint8_t code = 0; + while (1) { + if (ch == '>') + break; + + if (std::isxdigit(ch)) { + int val = FXSYS_toHexDigit(ch); + if (bFirst) { + code = val * 16; + } else { + code += val; + buf.AppendByte(code); + } + bFirst = !bFirst; + } + + if (!GetNextChar(ch)) + break; + } + if (!bFirst) + buf.AppendByte(code); + + return buf.MakeString(); +} + +void CPDF_SyntaxParser::ToNextLine() { + uint8_t ch; + while (GetNextChar(ch)) { + if (ch == '\n') + break; + + if (ch == '\r') { + GetNextChar(ch); + if (ch != '\n') + --m_Pos; + break; + } + } +} + +void CPDF_SyntaxParser::ToNextWord() { + uint8_t ch; + if (!GetNextChar(ch)) + return; + + while (1) { + while (PDFCharIsWhitespace(ch)) { + if (!GetNextChar(ch)) + return; + } + + if (ch != '%') + break; + + while (1) { + if (!GetNextChar(ch)) + return; + if (PDFCharIsLineEnding(ch)) + break; + } + } + m_Pos--; +} + +CFX_ByteString CPDF_SyntaxParser::GetNextWord(bool* bIsNumber) { + GetNextWordInternal(bIsNumber); + return CFX_ByteString((const FX_CHAR*)m_WordBuffer, m_WordSize); +} + +CFX_ByteString CPDF_SyntaxParser::GetKeyword() { + return GetNextWord(nullptr); +} + +CPDF_Object* CPDF_SyntaxParser::GetObject(CPDF_IndirectObjectHolder* pObjList, + uint32_t objnum, + uint32_t gennum, + FX_BOOL bDecrypt) { + CFX_AutoRestorer restorer(&s_CurrentRecursionDepth); + if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth) + return nullptr; + + FX_FILESIZE SavedObjPos = m_Pos; + bool bIsNumber; + CFX_ByteString word = GetNextWord(&bIsNumber); + if (word.GetLength() == 0) + return nullptr; + + if (bIsNumber) { + FX_FILESIZE SavedPos = m_Pos; + CFX_ByteString nextword = GetNextWord(&bIsNumber); + if (bIsNumber) { + CFX_ByteString nextword2 = GetNextWord(nullptr); + if (nextword2 == "R") + return new CPDF_Reference(pObjList, FXSYS_atoui(word.c_str())); + } + m_Pos = SavedPos; + return new CPDF_Number(word.AsStringC()); + } + + if (word == "true" || word == "false") + return new CPDF_Boolean(word == "true"); + + if (word == "null") + return new CPDF_Null; + + if (word == "(") { + CFX_ByteString str = ReadString(); + if (m_pCryptoHandler && bDecrypt) + m_pCryptoHandler->Decrypt(objnum, gennum, str); + return new CPDF_String(MaybeIntern(str), FALSE); + } + + if (word == "<") { + CFX_ByteString str = ReadHexString(); + if (m_pCryptoHandler && bDecrypt) + m_pCryptoHandler->Decrypt(objnum, gennum, str); + return new CPDF_String(MaybeIntern(str), TRUE); + } + + if (word == "[") { + CPDF_Array* pArray = new CPDF_Array; + while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, true)) + pArray->Add(pObj); + + return pArray; + } + + if (word[0] == '/') { + return new CPDF_Name(MaybeIntern( + PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)))); + } + + if (word == "<<") { + int32_t nKeys = 0; + FX_FILESIZE dwSignValuePos = 0; + + std::unique_ptr> pDict( + new CPDF_Dictionary(m_pPool)); + while (1) { + CFX_ByteString key = GetNextWord(nullptr); + if (key.IsEmpty()) + return nullptr; + + FX_FILESIZE SavedPos = m_Pos - key.GetLength(); + if (key == ">>") + break; + + if (key == "endobj") { + m_Pos = SavedPos; + break; + } + + if (key[0] != '/') + continue; + + ++nKeys; + key = PDF_NameDecode(key); + if (key.IsEmpty()) + continue; + + if (key == "/Contents") + dwSignValuePos = m_Pos; + + CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, true); + if (!pObj) + continue; + + CFX_ByteString keyNoSlash(key.raw_str() + 1, key.GetLength() - 1); + pDict->SetFor(keyNoSlash, pObj); + } + + // Only when this is a signature dictionary and has contents, we reset the + // contents to the un-decrypted form. + if (pDict->IsSignatureDict() && dwSignValuePos) { + CFX_AutoRestorer save_pos(&m_Pos); + m_Pos = dwSignValuePos; + pDict->SetFor("Contents", GetObject(pObjList, objnum, gennum, false)); + } + + FX_FILESIZE SavedPos = m_Pos; + CFX_ByteString nextword = GetNextWord(nullptr); + if (nextword != "stream") { + m_Pos = SavedPos; + return pDict.release(); + } + return ReadStream(pDict.release(), objnum, gennum); + } + + if (word == ">>") + m_Pos = SavedObjPos; + + return nullptr; +} + +CPDF_Object* CPDF_SyntaxParser::GetObjectForStrict( + CPDF_IndirectObjectHolder* pObjList, + uint32_t objnum, + uint32_t gennum) { + CFX_AutoRestorer restorer(&s_CurrentRecursionDepth); + if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth) + return nullptr; + + FX_FILESIZE SavedObjPos = m_Pos; + bool bIsNumber; + CFX_ByteString word = GetNextWord(&bIsNumber); + if (word.GetLength() == 0) + return nullptr; + + if (bIsNumber) { + FX_FILESIZE SavedPos = m_Pos; + CFX_ByteString nextword = GetNextWord(&bIsNumber); + if (bIsNumber) { + CFX_ByteString nextword2 = GetNextWord(nullptr); + if (nextword2 == "R") + return new CPDF_Reference(pObjList, FXSYS_atoui(word.c_str())); + } + m_Pos = SavedPos; + return new CPDF_Number(word.AsStringC()); + } + + if (word == "true" || word == "false") + return new CPDF_Boolean(word == "true"); + + if (word == "null") + return new CPDF_Null; + + if (word == "(") { + CFX_ByteString str = ReadString(); + if (m_pCryptoHandler) + m_pCryptoHandler->Decrypt(objnum, gennum, str); + return new CPDF_String(MaybeIntern(str), FALSE); + } + + if (word == "<") { + CFX_ByteString str = ReadHexString(); + if (m_pCryptoHandler) + m_pCryptoHandler->Decrypt(objnum, gennum, str); + return new CPDF_String(MaybeIntern(str), TRUE); + } + + if (word == "[") { + std::unique_ptr> pArray( + new CPDF_Array); + while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, true)) + pArray->Add(pObj); + + return m_WordBuffer[0] == ']' ? pArray.release() : nullptr; + } + + if (word[0] == '/') { + return new CPDF_Name(MaybeIntern( + PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)))); + } + + if (word == "<<") { + std::unique_ptr> pDict( + new CPDF_Dictionary(m_pPool)); + while (1) { + FX_FILESIZE SavedPos = m_Pos; + CFX_ByteString key = GetNextWord(nullptr); + if (key.IsEmpty()) + return nullptr; + + if (key == ">>") + break; + + if (key == "endobj") { + m_Pos = SavedPos; + break; + } + + if (key[0] != '/') + continue; + + key = PDF_NameDecode(key); + std::unique_ptr> obj( + GetObject(pObjList, objnum, gennum, true)); + if (!obj) { + uint8_t ch; + while (GetNextChar(ch) && ch != 0x0A && ch != 0x0D) { + continue; + } + return nullptr; + } + + if (key.GetLength() > 1) { + pDict->SetFor(CFX_ByteString(key.c_str() + 1, key.GetLength() - 1), + obj.release()); + } + } + + FX_FILESIZE SavedPos = m_Pos; + CFX_ByteString nextword = GetNextWord(nullptr); + if (nextword != "stream") { + m_Pos = SavedPos; + return pDict.release(); + } + + return ReadStream(pDict.release(), objnum, gennum); + } + + if (word == ">>") + m_Pos = SavedObjPos; + + return nullptr; +} + +unsigned int CPDF_SyntaxParser::ReadEOLMarkers(FX_FILESIZE pos) { + unsigned char byte1 = 0; + unsigned char byte2 = 0; + + GetCharAt(pos, byte1); + GetCharAt(pos + 1, byte2); + + if (byte1 == '\r' && byte2 == '\n') + return 2; + + if (byte1 == '\r' || byte1 == '\n') + return 1; + + return 0; +} + +CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict, + uint32_t objnum, + uint32_t gennum) { + CPDF_Object* pLenObj = pDict->GetObjectFor("Length"); + FX_FILESIZE len = -1; + CPDF_Reference* pLenObjRef = ToReference(pLenObj); + + bool differingObjNum = !pLenObjRef || (pLenObjRef->GetObjList() && + pLenObjRef->GetRefObjNum() != objnum); + if (pLenObj && differingObjNum) + len = pLenObj->GetInteger(); + + // Locate the start of stream. + ToNextLine(); + FX_FILESIZE streamStartPos = m_Pos; + + const CFX_ByteStringC kEndStreamStr("endstream"); + const CFX_ByteStringC kEndObjStr("endobj"); + + CPDF_CryptoHandler* pCryptoHandler = + objnum == (uint32_t)m_MetadataObjnum ? nullptr : m_pCryptoHandler.get(); + if (!pCryptoHandler) { + FX_BOOL bSearchForKeyword = TRUE; + if (len >= 0) { + pdfium::base::CheckedNumeric pos = m_Pos; + pos += len; + if (pos.IsValid() && pos.ValueOrDie() < m_FileLen) + m_Pos = pos.ValueOrDie(); + + m_Pos += ReadEOLMarkers(m_Pos); + FXSYS_memset(m_WordBuffer, 0, kEndStreamStr.GetLength() + 1); + GetNextWordInternal(nullptr); + // Earlier version of PDF specification doesn't require EOL marker before + // 'endstream' keyword. If keyword 'endstream' follows the bytes in + // specified length, it signals the end of stream. + if (FXSYS_memcmp(m_WordBuffer, kEndStreamStr.raw_str(), + kEndStreamStr.GetLength()) == 0) { + bSearchForKeyword = FALSE; + } + } + + if (bSearchForKeyword) { + // If len is not available, len needs to be calculated + // by searching the keywords "endstream" or "endobj". + m_Pos = streamStartPos; + FX_FILESIZE endStreamOffset = 0; + while (endStreamOffset >= 0) { + endStreamOffset = FindTag(kEndStreamStr, 0); + + // Can't find "endstream". + if (endStreamOffset < 0) + break; + + // Stop searching when "endstream" is found. + if (IsWholeWord(m_Pos - kEndStreamStr.GetLength(), m_FileLen, + kEndStreamStr, TRUE)) { + endStreamOffset = m_Pos - streamStartPos - kEndStreamStr.GetLength(); + break; + } + } + + m_Pos = streamStartPos; + FX_FILESIZE endObjOffset = 0; + while (endObjOffset >= 0) { + endObjOffset = FindTag(kEndObjStr, 0); + + // Can't find "endobj". + if (endObjOffset < 0) + break; + + // Stop searching when "endobj" is found. + if (IsWholeWord(m_Pos - kEndObjStr.GetLength(), m_FileLen, kEndObjStr, + TRUE)) { + endObjOffset = m_Pos - streamStartPos - kEndObjStr.GetLength(); + break; + } + } + + // Can't find "endstream" or "endobj". + if (endStreamOffset < 0 && endObjOffset < 0) { + pDict->Release(); + return nullptr; + } + + if (endStreamOffset < 0 && endObjOffset >= 0) { + // Correct the position of end stream. + endStreamOffset = endObjOffset; + } else if (endStreamOffset >= 0 && endObjOffset < 0) { + // Correct the position of end obj. + endObjOffset = endStreamOffset; + } else if (endStreamOffset > endObjOffset) { + endStreamOffset = endObjOffset; + } + + len = endStreamOffset; + int numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 2); + if (numMarkers == 2) { + len -= 2; + } else { + numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 1); + if (numMarkers == 1) { + len -= 1; + } + } + + if (len < 0) { + pDict->Release(); + return nullptr; + } + pDict->SetIntegerFor("Length", len); + } + m_Pos = streamStartPos; + } + + if (len < 0) { + pDict->Release(); + return nullptr; + } + + uint8_t* pData = nullptr; + if (len > 0) { + pData = FX_Alloc(uint8_t, len); + ReadBlock(pData, len); + if (pCryptoHandler) { + CFX_BinaryBuf dest_buf; + dest_buf.EstimateSize(pCryptoHandler->DecryptGetSize(len)); + + void* context = pCryptoHandler->DecryptStart(objnum, gennum); + pCryptoHandler->DecryptStream(context, pData, len, dest_buf); + pCryptoHandler->DecryptFinish(context, dest_buf); + + FX_Free(pData); + pData = dest_buf.GetBuffer(); + len = dest_buf.GetSize(); + dest_buf.DetachBuffer(); + } + } + + CPDF_Stream* pStream = new CPDF_Stream(pData, len, pDict); + streamStartPos = m_Pos; + FXSYS_memset(m_WordBuffer, 0, kEndObjStr.GetLength() + 1); + + GetNextWordInternal(nullptr); + + int numMarkers = ReadEOLMarkers(m_Pos); + if (m_WordSize == static_cast(kEndObjStr.GetLength()) && + numMarkers != 0 && + FXSYS_memcmp(m_WordBuffer, kEndObjStr.raw_str(), + kEndObjStr.GetLength()) == 0) { + m_Pos = streamStartPos; + } + return pStream; +} + +void CPDF_SyntaxParser::InitParser(IFX_FileRead* pFileAccess, + uint32_t HeaderOffset) { + FX_Free(m_pFileBuf); + + m_pFileBuf = FX_Alloc(uint8_t, m_BufSize); + m_HeaderOffset = HeaderOffset; + m_FileLen = pFileAccess->GetSize(); + m_Pos = 0; + m_pFileAccess = pFileAccess; + m_BufOffset = 0; + pFileAccess->ReadBlock( + m_pFileBuf, 0, + (size_t)((FX_FILESIZE)m_BufSize > m_FileLen ? m_FileLen : m_BufSize)); +} + +uint32_t CPDF_SyntaxParser::GetDirectNum() { + bool bIsNumber; + GetNextWordInternal(&bIsNumber); + if (!bIsNumber) + return 0; + + m_WordBuffer[m_WordSize] = 0; + return FXSYS_atoui(reinterpret_cast(m_WordBuffer)); +} + +bool CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos, + FX_FILESIZE limit, + const CFX_ByteStringC& tag, + FX_BOOL checkKeyword) { + const uint32_t taglen = tag.GetLength(); + + bool bCheckLeft = !PDFCharIsDelimiter(tag[0]) && !PDFCharIsWhitespace(tag[0]); + bool bCheckRight = !PDFCharIsDelimiter(tag[taglen - 1]) && + !PDFCharIsWhitespace(tag[taglen - 1]); + + uint8_t ch; + if (bCheckRight && startpos + (int32_t)taglen <= limit && + GetCharAt(startpos + (int32_t)taglen, ch)) { + if (PDFCharIsNumeric(ch) || PDFCharIsOther(ch) || + (checkKeyword && PDFCharIsDelimiter(ch))) { + return false; + } + } + + if (bCheckLeft && startpos > 0 && GetCharAt(startpos - 1, ch)) { + if (PDFCharIsNumeric(ch) || PDFCharIsOther(ch) || + (checkKeyword && PDFCharIsDelimiter(ch))) { + return false; + } + } + return true; +} + +// TODO(dsinclair): Split into a SearchWordForward and SearchWordBackwards +// and drop the bool. +FX_BOOL CPDF_SyntaxParser::SearchWord(const CFX_ByteStringC& tag, + FX_BOOL bWholeWord, + FX_BOOL bForward, + FX_FILESIZE limit) { + int32_t taglen = tag.GetLength(); + if (taglen == 0) + return FALSE; + + FX_FILESIZE pos = m_Pos; + int32_t offset = 0; + if (!bForward) + offset = taglen - 1; + + const uint8_t* tag_data = tag.raw_str(); + uint8_t byte; + while (1) { + if (bForward) { + if (limit && pos >= m_Pos + limit) + return FALSE; + + if (!GetCharAt(pos, byte)) + return FALSE; + + } else { + if (limit && pos <= m_Pos - limit) + return FALSE; + + if (!GetCharAtBackward(pos, byte)) + return FALSE; + } + + if (byte == tag_data[offset]) { + if (bForward) { + offset++; + if (offset < taglen) { + pos++; + continue; + } + } else { + offset--; + if (offset >= 0) { + pos--; + continue; + } + } + + FX_FILESIZE startpos = bForward ? pos - taglen + 1 : pos; + if (!bWholeWord || IsWholeWord(startpos, limit, tag, FALSE)) { + m_Pos = startpos; + return TRUE; + } + } + + if (bForward) { + offset = byte == tag_data[0] ? 1 : 0; + pos++; + } else { + offset = byte == tag_data[taglen - 1] ? taglen - 2 : taglen - 1; + pos--; + } + + if (pos < 0) + return FALSE; + } + + return FALSE; +} + +int32_t CPDF_SyntaxParser::SearchMultiWord(const CFX_ByteStringC& tags, + FX_BOOL bWholeWord, + FX_FILESIZE limit) { + int32_t ntags = 1; + for (int i = 0; i < tags.GetLength(); ++i) { + if (tags[i] == 0) + ++ntags; + } + + // Ensure that the input byte string happens to be nul-terminated. This + // need not be the case, but the loop below uses this guarantee to put + // the last pattern into the vector. + ASSERT(tags[tags.GetLength()] == 0); + std::vector patterns(ntags); + uint32_t start = 0; + uint32_t itag = 0; + uint32_t max_len = 0; + for (int i = 0; i <= tags.GetLength(); ++i) { + if (tags[i] == 0) { + uint32_t len = i - start; + max_len = std::max(len, max_len); + patterns[itag].m_bsTag = tags.Mid(start, len); + patterns[itag].m_Offset = 0; + start = i + 1; + ++itag; + } + } + + const FX_FILESIZE pos_limit = m_Pos + limit; + for (FX_FILESIZE pos = m_Pos; !limit || pos < pos_limit; ++pos) { + uint8_t byte; + if (!GetCharAt(pos, byte)) + break; + + for (int i = 0; i < ntags; ++i) { + SearchTagRecord& pat = patterns[i]; + if (pat.m_bsTag[pat.m_Offset] != byte) { + pat.m_Offset = (pat.m_bsTag[0] == byte) ? 1 : 0; + continue; + } + + ++pat.m_Offset; + if (pat.m_Offset != pat.m_bsTag.GetLength()) + continue; + + if (!bWholeWord || IsWholeWord(pos - pat.m_bsTag.GetLength(), limit, + pat.m_bsTag, FALSE)) { + return i; + } + + pat.m_Offset = (pat.m_bsTag[0] == byte) ? 1 : 0; + } + } + return -1; +} + +FX_FILESIZE CPDF_SyntaxParser::FindTag(const CFX_ByteStringC& tag, + FX_FILESIZE limit) { + int32_t taglen = tag.GetLength(); + int32_t match = 0; + limit += m_Pos; + FX_FILESIZE startpos = m_Pos; + + while (1) { + uint8_t ch; + if (!GetNextChar(ch)) + return -1; + + if (ch == tag[match]) { + match++; + if (match == taglen) + return m_Pos - startpos - taglen; + } else { + match = ch == tag[0] ? 1 : 0; + } + + if (limit && m_Pos == limit) + return -1; + } + return -1; +} + +void CPDF_SyntaxParser::SetEncrypt( + std::unique_ptr pCryptoHandler) { + m_pCryptoHandler = std::move(pCryptoHandler); +} + +CFX_ByteString CPDF_SyntaxParser::MaybeIntern(const CFX_ByteString& str) { + return m_pPool ? m_pPool->Intern(str) : str; +} diff --git a/core/fpdfapi/parser/cpdf_syntax_parser.h b/core/fpdfapi/parser/cpdf_syntax_parser.h new file mode 100644 index 0000000000..444a94bde1 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_syntax_parser.h @@ -0,0 +1,101 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_CPDF_SYNTAX_PARSER_H_ +#define CORE_FPDFAPI_PARSER_CPDF_SYNTAX_PARSER_H_ + +#include + +#include "core/fxcrt/cfx_string_pool_template.h" +#include "core/fxcrt/cfx_weak_ptr.h" +#include "core/fxcrt/fx_basic.h" + +class CPDF_CryptoHandler; +class CPDF_Dictionary; +class CPDF_IndirectObjectHolder; +class CPDF_Object; +class CPDF_Stream; +class IFX_FileRead; + +class CPDF_SyntaxParser { + public: + CPDF_SyntaxParser(); + explicit CPDF_SyntaxParser(const CFX_WeakPtr& pPool); + ~CPDF_SyntaxParser(); + + void InitParser(IFX_FileRead* pFileAccess, uint32_t HeaderOffset); + + FX_FILESIZE SavePos() const { return m_Pos; } + void RestorePos(FX_FILESIZE pos) { m_Pos = pos; } + + CPDF_Object* GetObject(CPDF_IndirectObjectHolder* pObjList, + uint32_t objnum, + uint32_t gennum, + FX_BOOL bDecrypt); + CPDF_Object* GetObjectForStrict(CPDF_IndirectObjectHolder* pObjList, + uint32_t objnum, + uint32_t gennum); + CFX_ByteString GetKeyword(); + + void ToNextLine(); + void ToNextWord(); + + FX_BOOL SearchWord(const CFX_ByteStringC& word, + FX_BOOL bWholeWord, + FX_BOOL bForward, + FX_FILESIZE limit); + int SearchMultiWord(const CFX_ByteStringC& words, + FX_BOOL bWholeWord, + FX_FILESIZE limit); + FX_FILESIZE FindTag(const CFX_ByteStringC& tag, FX_FILESIZE limit); + + void SetEncrypt(std::unique_ptr pCryptoHandler); + + FX_BOOL ReadBlock(uint8_t* pBuf, uint32_t size); + FX_BOOL GetCharAt(FX_FILESIZE pos, uint8_t& ch); + CFX_ByteString GetNextWord(bool* bIsNumber); + + private: + friend class CPDF_Parser; + friend class CPDF_DataAvail; + friend class cpdf_syntax_parser_ReadHexString_Test; + + static const int kParserMaxRecursionDepth = 64; + static int s_CurrentRecursionDepth; + + uint32_t GetDirectNum(); + FX_BOOL GetNextChar(uint8_t& ch); + FX_BOOL GetCharAtBackward(FX_FILESIZE pos, uint8_t& ch); + void GetNextWordInternal(bool* bIsNumber); + bool IsWholeWord(FX_FILESIZE startpos, + FX_FILESIZE limit, + const CFX_ByteStringC& tag, + FX_BOOL checkKeyword); + + CFX_ByteString ReadString(); + CFX_ByteString ReadHexString(); + unsigned int ReadEOLMarkers(FX_FILESIZE pos); + CPDF_Stream* ReadStream(CPDF_Dictionary* pDict, + uint32_t objnum, + uint32_t gennum); + + CFX_ByteString MaybeIntern(const CFX_ByteString& str); + + FX_FILESIZE m_Pos; + int m_MetadataObjnum; + IFX_FileRead* m_pFileAccess; + FX_FILESIZE m_HeaderOffset; + FX_FILESIZE m_FileLen; + uint8_t* m_pFileBuf; + uint32_t m_BufSize; + FX_FILESIZE m_BufOffset; + std::unique_ptr m_pCryptoHandler; + uint8_t m_WordBuffer[257]; + uint32_t m_WordSize; + CFX_WeakPtr m_pPool; +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_SYNTAX_PARSER_H_ diff --git a/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp new file mode 100644 index 0000000000..45a0698078 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp @@ -0,0 +1,171 @@ +// Copyright 2016 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. + +#include +#include + +#include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fpdfapi/parser/cpdf_syntax_parser.h" +#include "core/fxcrt/fx_ext.h" +#include "core/fxcrt/fx_stream.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/utils/path_service.h" + +TEST(cpdf_syntax_parser, ReadHexString) { + { + // Empty string. + uint8_t data[] = ""; + ScopedFileStream stream(FX_CreateMemoryStream(data, 0, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("", parser.ReadHexString()); + EXPECT_EQ(0, parser.SavePos()); + } + + { + // Blank string. + uint8_t data[] = " "; + ScopedFileStream stream(FX_CreateMemoryStream(data, 2, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("", parser.ReadHexString()); + EXPECT_EQ(2, parser.SavePos()); + } + + { + // Skips unknown characters. + uint8_t data[] = "z12b"; + ScopedFileStream stream(FX_CreateMemoryStream(data, 4, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("\x12\xb0", parser.ReadHexString()); + EXPECT_EQ(4, parser.SavePos()); + } + + { + // Skips unknown characters. + uint8_t data[] = "*<&*#$^&@1"; + ScopedFileStream stream(FX_CreateMemoryStream(data, 10, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("\x10", parser.ReadHexString()); + EXPECT_EQ(10, parser.SavePos()); + } + + { + // Skips unknown characters. + uint8_t data[] = "\x80zab"; + ScopedFileStream stream(FX_CreateMemoryStream(data, 4, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("\xab", parser.ReadHexString()); + EXPECT_EQ(4, parser.SavePos()); + } + + { + // Skips unknown characters. + uint8_t data[] = "\xffzab"; + ScopedFileStream stream(FX_CreateMemoryStream(data, 4, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("\xab", parser.ReadHexString()); + EXPECT_EQ(4, parser.SavePos()); + } + + { + // Regular conversion. + uint8_t data[] = "1A2b>abcd"; + ScopedFileStream stream(FX_CreateMemoryStream(data, 9, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("\x1a\x2b", parser.ReadHexString()); + EXPECT_EQ(5, parser.SavePos()); + } + + { + // Position out of bounds. + uint8_t data[] = "12ab>"; + ScopedFileStream stream(FX_CreateMemoryStream(data, 5, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + parser.RestorePos(5); + EXPECT_EQ("", parser.ReadHexString()); + + parser.RestorePos(6); + EXPECT_EQ("", parser.ReadHexString()); + + parser.RestorePos(-1); + EXPECT_EQ("", parser.ReadHexString()); + + parser.RestorePos(std::numeric_limits::max()); + EXPECT_EQ("", parser.ReadHexString()); + + // Check string still parses when set to 0. + parser.RestorePos(0); + EXPECT_EQ("\x12\xab", parser.ReadHexString()); + } + + { + // Missing ending >. + uint8_t data[] = "1A2b"; + ScopedFileStream stream(FX_CreateMemoryStream(data, 4, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("\x1a\x2b", parser.ReadHexString()); + EXPECT_EQ(4, parser.SavePos()); + } + + { + // Missing ending >. + uint8_t data[] = "12abz"; + ScopedFileStream stream(FX_CreateMemoryStream(data, 5, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("\x12\xab", parser.ReadHexString()); + EXPECT_EQ(5, parser.SavePos()); + } + + { + // Uneven number of bytes. + uint8_t data[] = "1A2>asdf"; + ScopedFileStream stream(FX_CreateMemoryStream(data, 8, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("\x1a\x20", parser.ReadHexString()); + EXPECT_EQ(4, parser.SavePos()); + } + + { + // Uneven number of bytes. + uint8_t data[] = "1A2zasdf"; + ScopedFileStream stream(FX_CreateMemoryStream(data, 8, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("\x1a\x2a\xdf", parser.ReadHexString()); + EXPECT_EQ(8, parser.SavePos()); + } + + { + // Just ending character. + uint8_t data[] = ">"; + ScopedFileStream stream(FX_CreateMemoryStream(data, 1, FALSE)); + + CPDF_SyntaxParser parser; + parser.InitParser(stream.get(), 0); + EXPECT_EQ("", parser.ReadHexString()); + EXPECT_EQ(1, parser.SavePos()); + } +} diff --git a/core/fpdfapi/parser/fpdf_parser_decode.cpp b/core/fpdfapi/parser/fpdf_parser_decode.cpp new file mode 100644 index 0000000000..88712c9760 --- /dev/null +++ b/core/fpdfapi/parser/fpdf_parser_decode.cpp @@ -0,0 +1,575 @@ +// 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 + +#include "core/fpdfapi/parser/fpdf_parser_decode.h" + +#include + +#include +#include +#include + +#include "core/fpdfapi/cpdf_modulemgr.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcodec/fx_codec.h" +#include "core/fxcrt/fx_ext.h" +#include "third_party/base/stl_util.h" + +namespace { + +const uint32_t kMaxStreamSize = 20 * 1024 * 1024; + +bool CheckFlateDecodeParams(int Colors, int BitsPerComponent, int Columns) { + if (Colors < 0 || BitsPerComponent < 0 || Columns < 0) + return false; + + int check = Columns; + if (check > 0 && Colors > INT_MAX / check) + return false; + + check *= Colors; + if (check > 0 && BitsPerComponent > INT_MAX / check) + return false; + + return check * BitsPerComponent <= INT_MAX - 7; +} + +} // namespace + +const uint16_t PDFDocEncoding[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, + 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, + 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x02d8, 0x02c7, 0x02c6, + 0x02d9, 0x02dd, 0x02db, 0x02da, 0x02dc, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, + 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, + 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, + 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, + 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, + 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, + 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, + 0x007e, 0x0000, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, + 0x2044, 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, + 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x0141, 0x0152, 0x0160, 0x0178, + 0x017d, 0x0131, 0x0142, 0x0153, 0x0161, 0x017e, 0x0000, 0x20ac, 0x00a1, + 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, + 0x00ab, 0x00ac, 0x0000, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, + 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, + 0x00bd, 0x00be, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, + 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, + 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, + 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, + 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, + 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, + 0x00fc, 0x00fd, 0x00fe, 0x00ff}; + +uint32_t A85Decode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t*& dest_buf, + uint32_t& dest_size) { + dest_size = 0; + dest_buf = nullptr; + if (src_size == 0) + return 0; + + // Count legal characters and zeros. + uint32_t zcount = 0; + uint32_t pos = 0; + while (pos < src_size) { + uint8_t ch = src_buf[pos]; + if (ch == 'z') { + zcount++; + } else if ((ch < '!' || ch > 'u') && !PDFCharIsLineEnding(ch) && + ch != ' ' && ch != '\t') { + break; + } + pos++; + } + // No content to decode. + if (pos == 0) + return 0; + + // Count the space needed to contain non-zero characters. The encoding ratio + // of Ascii85 is 4:5. + uint32_t space_for_non_zeroes = (pos - zcount) / 5 * 4 + 4; + if (zcount > (UINT_MAX - space_for_non_zeroes) / 4) { + return (uint32_t)-1; + } + dest_buf = FX_Alloc(uint8_t, zcount * 4 + space_for_non_zeroes); + size_t state = 0; + uint32_t res = 0; + pos = dest_size = 0; + while (pos < src_size) { + uint8_t ch = src_buf[pos++]; + if (PDFCharIsLineEnding(ch) || ch == ' ' || ch == '\t') + continue; + + if (ch == 'z') { + FXSYS_memset(dest_buf + dest_size, 0, 4); + state = 0; + res = 0; + dest_size += 4; + } else if (ch >= '!' && ch <= 'u') { + res = res * 85 + ch - 33; + state++; + if (state == 5) { + for (size_t i = 0; i < 4; i++) { + dest_buf[dest_size++] = (uint8_t)(res >> (3 - i) * 8); + } + state = 0; + res = 0; + } + } else { + // The end or illegal character. + break; + } + } + // Handle partial group. + if (state) { + for (size_t i = state; i < 5; i++) + res = res * 85 + 84; + for (size_t i = 0; i < state - 1; i++) + dest_buf[dest_size++] = (uint8_t)(res >> (3 - i) * 8); + } + if (pos < src_size && src_buf[pos] == '>') + pos++; + return pos; +} + +uint32_t HexDecode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t*& dest_buf, + uint32_t& dest_size) { + dest_size = 0; + if (src_size == 0) { + dest_buf = nullptr; + return 0; + } + + uint32_t i = 0; + // Find the end of data. + while (i < src_size && src_buf[i] != '>') + i++; + + dest_buf = FX_Alloc(uint8_t, i / 2 + 1); + bool bFirst = true; + for (i = 0; i < src_size; i++) { + uint8_t ch = src_buf[i]; + if (PDFCharIsLineEnding(ch) || ch == ' ' || ch == '\t') + continue; + + if (ch == '>') { + ++i; + break; + } + if (!std::isxdigit(ch)) + continue; + + int digit = FXSYS_toHexDigit(ch); + if (bFirst) + dest_buf[dest_size] = digit * 16; + else + dest_buf[dest_size++] += digit; + + bFirst = !bFirst; + } + if (!bFirst) + dest_size++; + return i; +} + +uint32_t RunLengthDecode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t*& dest_buf, + uint32_t& dest_size) { + uint32_t i = 0; + dest_size = 0; + while (i < src_size) { + if (src_buf[i] == 128) + break; + + uint32_t old = dest_size; + if (src_buf[i] < 128) { + dest_size += src_buf[i] + 1; + if (dest_size < old) + return FX_INVALID_OFFSET; + i += src_buf[i] + 2; + } else { + dest_size += 257 - src_buf[i]; + if (dest_size < old) + return FX_INVALID_OFFSET; + i += 2; + } + } + if (dest_size >= kMaxStreamSize) + return FX_INVALID_OFFSET; + + dest_buf = FX_Alloc(uint8_t, dest_size); + i = 0; + int dest_count = 0; + while (i < src_size) { + if (src_buf[i] == 128) + break; + + if (src_buf[i] < 128) { + uint32_t copy_len = src_buf[i] + 1; + uint32_t buf_left = src_size - i - 1; + if (buf_left < copy_len) { + uint32_t delta = copy_len - buf_left; + copy_len = buf_left; + FXSYS_memset(dest_buf + dest_count + copy_len, '\0', delta); + } + FXSYS_memcpy(dest_buf + dest_count, src_buf + i + 1, copy_len); + dest_count += src_buf[i] + 1; + i += src_buf[i] + 2; + } else { + int fill = 0; + if (i < src_size - 1) { + fill = src_buf[i + 1]; + } + FXSYS_memset(dest_buf + dest_count, fill, 257 - src_buf[i]); + dest_count += 257 - src_buf[i]; + i += 2; + } + } + + return std::min(i + 1, src_size); +} + +CCodec_ScanlineDecoder* FPDFAPI_CreateFaxDecoder( + const uint8_t* src_buf, + uint32_t src_size, + int width, + int height, + const CPDF_Dictionary* pParams) { + int K = 0; + bool EndOfLine = false; + bool ByteAlign = false; + bool BlackIs1 = false; + int Columns = 1728; + int Rows = 0; + if (pParams) { + K = pParams->GetIntegerFor("K"); + EndOfLine = !!pParams->GetIntegerFor("EndOfLine"); + ByteAlign = !!pParams->GetIntegerFor("EncodedByteAlign"); + BlackIs1 = !!pParams->GetIntegerFor("BlackIs1"); + Columns = pParams->GetIntegerFor("Columns", 1728); + Rows = pParams->GetIntegerFor("Rows"); + if (Rows > USHRT_MAX) { + Rows = 0; + } + } + return CPDF_ModuleMgr::Get()->GetFaxModule()->CreateDecoder( + src_buf, src_size, width, height, K, EndOfLine, ByteAlign, BlackIs1, + Columns, Rows); +} + +CCodec_ScanlineDecoder* FPDFAPI_CreateFlateDecoder( + const uint8_t* src_buf, + uint32_t src_size, + int width, + int height, + int nComps, + int bpc, + const CPDF_Dictionary* pParams) { + int predictor = 0; + int Colors = 0, BitsPerComponent = 0, Columns = 0; + if (pParams) { + predictor = pParams->GetIntegerFor("Predictor"); + Colors = pParams->GetIntegerFor("Colors", 1); + BitsPerComponent = pParams->GetIntegerFor("BitsPerComponent", 8); + Columns = pParams->GetIntegerFor("Columns", 1); + if (!CheckFlateDecodeParams(Colors, BitsPerComponent, Columns)) { + return nullptr; + } + } + return CPDF_ModuleMgr::Get()->GetFlateModule()->CreateDecoder( + src_buf, src_size, width, height, nComps, bpc, predictor, Colors, + BitsPerComponent, Columns); +} + +uint32_t FPDFAPI_FlateOrLZWDecode(FX_BOOL bLZW, + const uint8_t* src_buf, + uint32_t src_size, + CPDF_Dictionary* pParams, + uint32_t estimated_size, + uint8_t*& dest_buf, + uint32_t& dest_size) { + int predictor = 0; + FX_BOOL bEarlyChange = TRUE; + int Colors = 0, BitsPerComponent = 0, Columns = 0; + if (pParams) { + predictor = pParams->GetIntegerFor("Predictor"); + bEarlyChange = pParams->GetIntegerFor("EarlyChange", 1); + Colors = pParams->GetIntegerFor("Colors", 1); + BitsPerComponent = pParams->GetIntegerFor("BitsPerComponent", 8); + Columns = pParams->GetIntegerFor("Columns", 1); + if (!CheckFlateDecodeParams(Colors, BitsPerComponent, Columns)) { + return (uint32_t)-1; + } + } + return CPDF_ModuleMgr::Get()->GetFlateModule()->FlateOrLZWDecode( + bLZW, src_buf, src_size, bEarlyChange, predictor, Colors, + BitsPerComponent, Columns, estimated_size, dest_buf, dest_size); +} + +FX_BOOL PDF_DataDecode(const uint8_t* src_buf, + uint32_t src_size, + const CPDF_Dictionary* pDict, + uint8_t*& dest_buf, + uint32_t& dest_size, + CFX_ByteString& ImageEncoding, + CPDF_Dictionary*& pImageParms, + uint32_t last_estimated_size, + FX_BOOL bImageAcc) { + CPDF_Object* pDecoder = pDict ? pDict->GetDirectObjectFor("Filter") : nullptr; + if (!pDecoder || (!pDecoder->IsArray() && !pDecoder->IsName())) + return FALSE; + + CPDF_Object* pParams = + pDict ? pDict->GetDirectObjectFor("DecodeParms") : nullptr; + + std::vector> DecoderArray; + if (CPDF_Array* pDecoders = pDecoder->AsArray()) { + CPDF_Array* pParamsArray = ToArray(pParams); + for (size_t i = 0; i < pDecoders->GetCount(); i++) { + DecoderArray.push_back( + {pDecoders->GetStringAt(i), + pParamsArray ? pParamsArray->GetDictAt(i) : nullptr}); + } + } else { + DecoderArray.push_back( + {pDecoder->GetString(), pParams ? pParams->GetDict() : nullptr}); + } + uint8_t* last_buf = const_cast(src_buf); + uint32_t last_size = src_size; + int nSize = pdfium::CollectionSize(DecoderArray); + for (int i = 0; i < nSize; i++) { + int estimated_size = i == nSize - 1 ? last_estimated_size : 0; + CFX_ByteString decoder = DecoderArray[i].first; + CPDF_Dictionary* pParam = ToDictionary(DecoderArray[i].second); + uint8_t* new_buf = nullptr; + uint32_t new_size = (uint32_t)-1; + int offset = -1; + if (decoder == "FlateDecode" || decoder == "Fl") { + if (bImageAcc && i == nSize - 1) { + ImageEncoding = "FlateDecode"; + dest_buf = (uint8_t*)last_buf; + dest_size = last_size; + pImageParms = pParam; + return TRUE; + } + offset = FPDFAPI_FlateOrLZWDecode(FALSE, last_buf, last_size, pParam, + estimated_size, new_buf, new_size); + } else if (decoder == "LZWDecode" || decoder == "LZW") { + offset = FPDFAPI_FlateOrLZWDecode(TRUE, last_buf, last_size, pParam, + estimated_size, new_buf, new_size); + } else if (decoder == "ASCII85Decode" || decoder == "A85") { + offset = A85Decode(last_buf, last_size, new_buf, new_size); + } else if (decoder == "ASCIIHexDecode" || decoder == "AHx") { + offset = HexDecode(last_buf, last_size, new_buf, new_size); + } else if (decoder == "RunLengthDecode" || decoder == "RL") { + if (bImageAcc && i == nSize - 1) { + ImageEncoding = "RunLengthDecode"; + dest_buf = (uint8_t*)last_buf; + dest_size = last_size; + pImageParms = pParam; + return TRUE; + } + offset = RunLengthDecode(last_buf, last_size, new_buf, new_size); + } else if (decoder == "Crypt") { + continue; + } else { + // If we get here, assume it's an image decoder. + if (decoder == "DCT") { + decoder = "DCTDecode"; + } else if (decoder == "CCF") { + decoder = "CCITTFaxDecode"; + } + ImageEncoding = decoder; + pImageParms = pParam; + dest_buf = (uint8_t*)last_buf; + dest_size = last_size; + if (CPDF_Array* pDecoders = pDecoder->AsArray()) + pDecoders->RemoveAt(i + 1, pDecoders->GetCount() - i - 1); + return TRUE; + } + if (last_buf != src_buf) { + FX_Free(last_buf); + } + if (offset == -1) { + FX_Free(new_buf); + return FALSE; + } + last_buf = new_buf; + last_size = new_size; + } + ImageEncoding = ""; + pImageParms = nullptr; + dest_buf = last_buf; + dest_size = last_size; + return TRUE; +} + +CFX_WideString PDF_DecodeText(const uint8_t* src_data, uint32_t src_len) { + CFX_WideString result; + if (src_len >= 2 && ((src_data[0] == 0xfe && src_data[1] == 0xff) || + (src_data[0] == 0xff && src_data[1] == 0xfe))) { + bool bBE = src_data[0] == 0xfe; + uint32_t max_chars = (src_len - 2) / 2; + if (!max_chars) { + return result; + } + if (src_data[0] == 0xff) { + bBE = !src_data[2]; + } + FX_WCHAR* dest_buf = result.GetBuffer(max_chars); + const uint8_t* uni_str = src_data + 2; + int dest_pos = 0; + for (uint32_t i = 0; i < max_chars * 2; i += 2) { + uint16_t unicode = bBE ? (uni_str[i] << 8 | uni_str[i + 1]) + : (uni_str[i + 1] << 8 | uni_str[i]); + if (unicode == 0x1b) { + i += 2; + while (i < max_chars * 2) { + uint16_t unicode2 = bBE ? (uni_str[i] << 8 | uni_str[i + 1]) + : (uni_str[i + 1] << 8 | uni_str[i]); + i += 2; + if (unicode2 == 0x1b) + break; + } + } else { + dest_buf[dest_pos++] = unicode; + } + } + result.ReleaseBuffer(dest_pos); + } else { + FX_WCHAR* dest_buf = result.GetBuffer(src_len); + for (uint32_t i = 0; i < src_len; i++) + dest_buf[i] = PDFDocEncoding[src_data[i]]; + result.ReleaseBuffer(src_len); + } + return result; +} + +CFX_WideString PDF_DecodeText(const CFX_ByteString& bstr) { + return PDF_DecodeText((const uint8_t*)bstr.c_str(), bstr.GetLength()); +} + +CFX_ByteString PDF_EncodeText(const FX_WCHAR* pString, int len) { + if (len == -1) { + len = FXSYS_wcslen(pString); + } + CFX_ByteString result; + FX_CHAR* dest_buf1 = result.GetBuffer(len); + int i; + for (i = 0; i < len; i++) { + int code; + for (code = 0; code < 256; code++) + if (PDFDocEncoding[code] == pString[i]) { + break; + } + if (code == 256) { + break; + } + dest_buf1[i] = code; + } + result.ReleaseBuffer(i); + if (i == len) { + return result; + } + + if (len > INT_MAX / 2 - 1) { + result.ReleaseBuffer(0); + return result; + } + + int encLen = len * 2 + 2; + + uint8_t* dest_buf2 = (uint8_t*)result.GetBuffer(encLen); + dest_buf2[0] = 0xfe; + dest_buf2[1] = 0xff; + dest_buf2 += 2; + for (int j = 0; j < len; j++) { + *dest_buf2++ = pString[i] >> 8; + *dest_buf2++ = (uint8_t)pString[j]; + } + result.ReleaseBuffer(encLen); + return result; +} + +CFX_ByteString PDF_EncodeText(const CFX_WideString& str) { + return PDF_EncodeText(str.c_str(), str.GetLength()); +} + +CFX_ByteString PDF_EncodeString(const CFX_ByteString& src, FX_BOOL bHex) { + CFX_ByteTextBuf result; + int srclen = src.GetLength(); + if (bHex) { + result.AppendChar('<'); + for (int i = 0; i < srclen; i++) { + result.AppendChar("0123456789ABCDEF"[src[i] / 16]); + result.AppendChar("0123456789ABCDEF"[src[i] % 16]); + } + result.AppendChar('>'); + return result.MakeString(); + } + result.AppendChar('('); + for (int i = 0; i < srclen; i++) { + uint8_t ch = src[i]; + if (ch == 0x0a) { + result << "\\n"; + continue; + } + if (ch == 0x0d) { + result << "\\r"; + continue; + } + if (ch == ')' || ch == '\\' || ch == '(') + result.AppendChar('\\'); + result.AppendChar(ch); + } + result.AppendChar(')'); + return result.MakeString(); +} + +bool FlateEncode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t** dest_buf, + uint32_t* dest_size) { + CCodec_ModuleMgr* pEncoders = CPDF_ModuleMgr::Get()->GetCodecModule(); + return pEncoders && + pEncoders->GetFlateModule()->Encode(src_buf, src_size, dest_buf, + dest_size); +} + +bool PngEncode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t** dest_buf, + uint32_t* dest_size) { + CCodec_ModuleMgr* pEncoders = CPDF_ModuleMgr::Get()->GetCodecModule(); + return pEncoders && + pEncoders->GetFlateModule()->PngEncode(src_buf, src_size, dest_buf, + dest_size); +} + +uint32_t FlateDecode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t*& dest_buf, + uint32_t& dest_size) { + CCodec_ModuleMgr* pEncoders = CPDF_ModuleMgr::Get()->GetCodecModule(); + if (pEncoders) { + return pEncoders->GetFlateModule()->FlateOrLZWDecode( + FALSE, src_buf, src_size, FALSE, 0, 0, 0, 0, 0, dest_buf, dest_size); + } + return 0; +} diff --git a/core/fpdfapi/parser/fpdf_parser_decode.h b/core/fpdfapi/parser/fpdf_parser_decode.h new file mode 100644 index 0000000000..3a5d532831 --- /dev/null +++ b/core/fpdfapi/parser/fpdf_parser_decode.h @@ -0,0 +1,77 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_FPDF_PARSER_DECODE_H_ +#define CORE_FPDFAPI_PARSER_FPDF_PARSER_DECODE_H_ + +#include "core/fxcrt/fx_basic.h" + +class CPDF_Dictionary; + +// Indexed by 8-bit char code, contains unicode code points. +extern const uint16_t PDFDocEncoding[256]; + +CFX_ByteString PDF_NameDecode(const CFX_ByteStringC& 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 uint8_t* pData, uint32_t size); +CFX_WideString PDF_DecodeText(const CFX_ByteString& bstr); +CFX_ByteString PDF_EncodeText(const FX_WCHAR* pString, int len = -1); +CFX_ByteString PDF_EncodeText(const CFX_WideString& str); + +bool FlateEncode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t** dest_buf, + uint32_t* dest_size); + +// This used to have more parameters like the predictor and bpc, but there was +// only one caller, so the interface has been simplified, the values are hard +// coded, and dead code has been removed. +bool PngEncode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t** dest_buf, + uint32_t* dest_size); + +uint32_t FlateDecode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t*& dest_buf, + uint32_t& dest_size); +uint32_t RunLengthDecode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t*& dest_buf, + uint32_t& dest_size); + +// Public for testing. +uint32_t A85Decode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t*& dest_buf, + uint32_t& dest_size); +// Public for testing. +uint32_t HexDecode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t*& dest_buf, + uint32_t& dest_size); +// Public for testing. +uint32_t FPDFAPI_FlateOrLZWDecode(FX_BOOL bLZW, + const uint8_t* src_buf, + uint32_t src_size, + CPDF_Dictionary* pParams, + uint32_t estimated_size, + uint8_t*& dest_buf, + uint32_t& dest_size); +FX_BOOL PDF_DataDecode(const uint8_t* src_buf, + uint32_t src_size, + const CPDF_Dictionary* pDict, + uint8_t*& dest_buf, + uint32_t& dest_size, + CFX_ByteString& ImageEncoding, + CPDF_Dictionary*& pImageParms, + uint32_t estimated_size, + FX_BOOL bImageAcc); + +#endif // CORE_FPDFAPI_PARSER_FPDF_PARSER_DECODE_H_ diff --git a/core/fpdfapi/parser/fpdf_parser_decode_embeddertest.cpp b/core/fpdfapi/parser/fpdf_parser_decode_embeddertest.cpp new file mode 100644 index 0000000000..639dcbf44c --- /dev/null +++ b/core/fpdfapi/parser/fpdf_parser_decode_embeddertest.cpp @@ -0,0 +1,117 @@ +// Copyright 2015 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. + +#include "core/fpdfapi/parser/fpdf_parser_decode.h" + +#include +#include + +#include "core/fxcrt/fx_basic.h" +#include "testing/embedder_test.h" +#include "testing/fx_string_testhelpers.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/test_support.h" + +class FPDFParserDecodeEmbeddertest : public EmbedderTest {}; + +// NOTE: python's zlib.compress() and zlib.decompress() may be useful for +// external validation of the FlateEncode/FlateDecode test cases. + +TEST_F(FPDFParserDecodeEmbeddertest, FlateEncode) { + pdfium::StrFuncTestData flate_encode_cases[] = { + STR_IN_OUT_CASE("", "\x78\x9c\x03\x00\x00\x00\x00\x01"), + STR_IN_OUT_CASE(" ", "\x78\x9c\x53\x00\x00\x00\x21\x00\x21"), + STR_IN_OUT_CASE("123", "\x78\x9c\x33\x34\x32\x06\x00\01\x2d\x00\x97"), + STR_IN_OUT_CASE("\x00\xff", "\x78\x9c\x63\xf8\x0f\x00\x01\x01\x01\x00"), + STR_IN_OUT_CASE( + "1 0 0 -1 29 763 cm\n0 0 555 735 re\nW n\nq\n0 0 555 734.394 re\n" + "W n\nq\n0.8009 0 0 0.8009 0 0 cm\n1 1 1 RG 1 1 1 rg\n/G0 gs\n" + "0 0 693 917 re\nf\nQ\nQ\n", + "\x78\x9c\x33\x54\x30\x00\x42\x5d\x43\x05\x23\x4b\x05\x73\x33\x63" + "\x85\xe4\x5c\x2e\x90\x80\xa9\xa9\xa9\x82\xb9\xb1\xa9\x42\x51\x2a" + "\x57\xb8\x42\x1e\x57\x21\x92\xa0\x89\x9e\xb1\xa5\x09\x92\x84\x9e" + "\x85\x81\x81\x25\xd8\x14\x24\x26\xd0\x18\x43\x05\x10\x0c\x72\x57" + "\x80\x30\x8a\xd2\xb9\xf4\xdd\x0d\x14\xd2\x8b\xc1\x46\x99\x59\x1a" + "\x2b\x58\x1a\x9a\x83\x8c\x49\xe3\x0a\x04\x42\x00\x37\x4c\x1b\x42"), + }; + + for (size_t i = 0; i < FX_ArraySize(flate_encode_cases); ++i) { + const pdfium::StrFuncTestData& data = flate_encode_cases[i]; + unsigned char* buf = nullptr; + unsigned int buf_size; + EXPECT_TRUE(FlateEncode(data.input, data.input_size, &buf, &buf_size)); + ASSERT_TRUE(buf); + EXPECT_EQ(std::string((const char*)data.expected, data.expected_size), + std::string((const char*)buf, buf_size)) + << " for case " << i; + FX_Free(buf); + } +} + +TEST_F(FPDFParserDecodeEmbeddertest, FlateDecode) { + pdfium::DecodeTestData flate_decode_cases[] = { + STR_IN_OUT_CASE("", "", 0), + STR_IN_OUT_CASE("preposterous nonsense", "", 2), + STR_IN_OUT_CASE("\x78\x9c\x03\x00\x00\x00\x00\x01", "", 8), + STR_IN_OUT_CASE("\x78\x9c\x53\x00\x00\x00\x21\x00\x21", " ", 9), + STR_IN_OUT_CASE("\x78\x9c\x33\x34\x32\x06\x00\01\x2d\x00\x97", "123", 11), + STR_IN_OUT_CASE("\x78\x9c\x63\xf8\x0f\x00\x01\x01\x01\x00", "\x00\xff", + 10), + STR_IN_OUT_CASE( + "\x78\x9c\x33\x54\x30\x00\x42\x5d\x43\x05\x23\x4b\x05\x73\x33\x63" + "\x85\xe4\x5c\x2e\x90\x80\xa9\xa9\xa9\x82\xb9\xb1\xa9\x42\x51\x2a" + "\x57\xb8\x42\x1e\x57\x21\x92\xa0\x89\x9e\xb1\xa5\x09\x92\x84\x9e" + "\x85\x81\x81\x25\xd8\x14\x24\x26\xd0\x18\x43\x05\x10\x0c\x72\x57" + "\x80\x30\x8a\xd2\xb9\xf4\xdd\x0d\x14\xd2\x8b\xc1\x46\x99\x59\x1a" + "\x2b\x58\x1a\x9a\x83\x8c\x49\xe3\x0a\x04\x42\x00\x37\x4c\x1b\x42", + "1 0 0 -1 29 763 cm\n0 0 555 735 re\nW n\nq\n0 0 555 734.394 re\n" + "W n\nq\n0.8009 0 0 0.8009 0 0 cm\n1 1 1 RG 1 1 1 rg\n/G0 gs\n" + "0 0 693 917 re\nf\nQ\nQ\n", + 96), + }; + + for (size_t i = 0; i < FX_ArraySize(flate_decode_cases); ++i) { + const pdfium::DecodeTestData& data = flate_decode_cases[i]; + unsigned char* result = nullptr; + unsigned int result_size; + EXPECT_EQ(data.processed_size, + FlateDecode(data.input, data.input_size, result, result_size)) + << " for case " << i; + ASSERT_TRUE(result); + EXPECT_EQ(std::string((const char*)data.expected, data.expected_size), + std::string((const char*)result, result_size)) + << " for case " << i; + FX_Free(result); + } +} + +TEST_F(FPDFParserDecodeEmbeddertest, Bug_552046) { + // Tests specifying multiple image filters for a stream. Should not cause a + // crash when rendered. + EXPECT_TRUE(OpenDocument("bug_552046.pdf")); + FPDF_PAGE page = LoadPage(0); + FPDF_BITMAP bitmap = RenderPage(page); + FPDFBitmap_Destroy(bitmap); + UnloadPage(page); +} + +TEST_F(FPDFParserDecodeEmbeddertest, Bug_555784) { + // Tests bad input to the run length decoder that caused a heap overflow. + // Should not cause a crash when rendered. + EXPECT_TRUE(OpenDocument("bug_555784.pdf")); + FPDF_PAGE page = LoadPage(0); + FPDF_BITMAP bitmap = RenderPage(page); + FPDFBitmap_Destroy(bitmap); + UnloadPage(page); +} + +TEST_F(FPDFParserDecodeEmbeddertest, Bug_455199) { + // Tests object numbers with a value > 01000000. + // Should open successfully. + EXPECT_TRUE(OpenDocument("bug_455199.pdf")); + FPDF_PAGE page = LoadPage(0); + FPDF_BITMAP bitmap = RenderPage(page); + FPDFBitmap_Destroy(bitmap); + UnloadPage(page); +} diff --git a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp new file mode 100644 index 0000000000..83860f9146 --- /dev/null +++ b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp @@ -0,0 +1,78 @@ +// Copyright 2015 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. + +#include "core/fpdfapi/parser/fpdf_parser_decode.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/test_support.h" + +TEST(fpdf_parser_decode, A85Decode) { + pdfium::DecodeTestData test_data[] = { + // Empty src string. + STR_IN_OUT_CASE("", "", 0), + // Empty content in src string. + STR_IN_OUT_CASE("~>", "", 0), + // Regular conversion. + STR_IN_OUT_CASE("FCfN8~>", "test", 7), + // End at the ending mark. + STR_IN_OUT_CASE("FCfN8~>FCfN8", "test", 7), + // Skip whitespaces. + STR_IN_OUT_CASE("\t F C\r\n \tf N 8 ~>", "test", 17), + // No ending mark. + STR_IN_OUT_CASE("@3B0)DJj_BF*)>@Gp#-s", "a funny story :)", 20), + // Non-multiple length. + STR_IN_OUT_CASE("12A", "2k", 3), + // Stop at unknown characters. + STR_IN_OUT_CASE("FCfN8FCfN8vw", "testtest", 11), + }; + for (size_t i = 0; i < FX_ArraySize(test_data); ++i) { + pdfium::DecodeTestData* ptr = &test_data[i]; + uint8_t* result = nullptr; + uint32_t result_size = 0; + EXPECT_EQ(ptr->processed_size, + A85Decode(ptr->input, ptr->input_size, result, result_size)) + << "for case " << i; + ASSERT_EQ(ptr->expected_size, result_size); + for (size_t j = 0; j < result_size; ++j) { + EXPECT_EQ(ptr->expected[j], result[j]) << "for case " << i << " char " + << j; + } + FX_Free(result); + } +} + +TEST(fpdf_parser_decode, HexDecode) { + pdfium::DecodeTestData test_data[] = { + // Empty src string. + STR_IN_OUT_CASE("", "", 0), + // Empty content in src string. + STR_IN_OUT_CASE(">", "", 1), + // Only whitespaces in src string. + STR_IN_OUT_CASE("\t \r\n>", "", 7), + // Regular conversion. + STR_IN_OUT_CASE("12Ac>zzz", "\x12\xac", 5), + // Skip whitespaces. + STR_IN_OUT_CASE("12 Ac\t02\r\nBF>zzz>", "\x12\xac\x02\xbf", 13), + // Non-multiple length. + STR_IN_OUT_CASE("12A>zzz", "\x12\xa0", 4), + // Skips unknown characters. + STR_IN_OUT_CASE("12tk \tAc>zzz", "\x12\xac", 10), + // No ending mark. + STR_IN_OUT_CASE("12AcED3c3456", "\x12\xac\xed\x3c\x34\x56", 12), + }; + for (size_t i = 0; i < FX_ArraySize(test_data); ++i) { + pdfium::DecodeTestData* ptr = &test_data[i]; + uint8_t* result = nullptr; + uint32_t result_size = 0; + EXPECT_EQ(ptr->processed_size, + HexDecode(ptr->input, ptr->input_size, result, result_size)) + << "for case " << i; + ASSERT_EQ(ptr->expected_size, result_size); + for (size_t j = 0; j < result_size; ++j) { + EXPECT_EQ(ptr->expected[j], result[j]) << "for case " << i << " char " + << j; + } + FX_Free(result); + } +} diff --git a/core/fpdfapi/parser/fpdf_parser_utility.cpp b/core/fpdfapi/parser/fpdf_parser_utility.cpp new file mode 100644 index 0000000000..10fac7fa1c --- /dev/null +++ b/core/fpdfapi/parser/fpdf_parser_utility.cpp @@ -0,0 +1,221 @@ +// 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 + +#include "core/fpdfapi/parser/fpdf_parser_utility.h" + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fxcrt/fx_ext.h" + +// Indexed by 8-bit character code, contains either: +// 'W' - for whitespace: NUL, TAB, CR, LF, FF, SPACE, 0x80, 0xff +// 'N' - for numeric: 0123456789+-. +// 'D' - for delimiter: %()/<>[]{} +// 'R' - otherwise. +const char PDF_CharType[256] = { + // NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO + // SI + 'W', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'W', 'W', 'R', 'W', 'W', 'R', + 'R', + + // DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS + // US + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + 'R', + + // SP ! " # $ % & ยด ( ) * + , - . + // / + 'W', 'R', 'R', 'R', 'R', 'D', 'R', 'R', 'D', 'D', 'R', 'N', 'R', 'N', 'N', + 'D', + + // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'R', 'R', 'D', 'R', 'D', + 'R', + + // @ A B C D E F G H I J K L M N O + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + 'R', + + // P Q R S T U V W X Y Z [ \ ] ^ _ + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'D', 'R', 'D', 'R', + 'R', + + // ` a b c d e f g h i j k l m n o + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + 'R', + + // p q r s t u v w x y z { | } ~ + // DEL + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'D', 'R', 'D', 'R', + 'R', + + 'W', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'W'}; + +int32_t GetHeaderOffset(IFX_FileRead* pFile) { + const size_t kBufSize = 4; + uint8_t buf[kBufSize]; + for (int32_t offset = 0; offset <= 1024; ++offset) { + if (!pFile->ReadBlock(buf, offset, kBufSize)) + return -1; + + if (memcmp(buf, "%PDF", 4) == 0) + return offset; + } + return -1; +} + +int32_t GetDirectInteger(CPDF_Dictionary* pDict, const CFX_ByteString& key) { + CPDF_Number* pObj = ToNumber(pDict->GetObjectFor(key)); + return pObj ? pObj->GetInteger() : 0; +} + +CFX_ByteString PDF_NameDecode(const CFX_ByteStringC& bstr) { + if (bstr.Find('#') == -1) + return CFX_ByteString(bstr); + + int size = bstr.GetLength(); + CFX_ByteString result; + FX_CHAR* pDestStart = result.GetBuffer(size); + FX_CHAR* pDest = pDestStart; + for (int i = 0; i < size; i++) { + if (bstr[i] == '#' && i < size - 2) { + *pDest++ = + FXSYS_toHexDigit(bstr[i + 1]) * 16 + FXSYS_toHexDigit(bstr[i + 2]); + i += 2; + } else { + *pDest++ = bstr[i]; + } + } + result.ReleaseBuffer((FX_STRSIZE)(pDest - pDestStart)); + return result; +} + +CFX_ByteString PDF_NameDecode(const CFX_ByteString& orig) { + if (orig.Find('#') == -1) + return orig; + return PDF_NameDecode(orig.AsStringC()); +} + +CFX_ByteString PDF_NameEncode(const CFX_ByteString& orig) { + uint8_t* src_buf = (uint8_t*)orig.c_str(); + int src_len = orig.GetLength(); + int dest_len = 0; + int i; + for (i = 0; i < src_len; i++) { + uint8_t ch = src_buf[i]; + if (ch >= 0x80 || PDFCharIsWhitespace(ch) || ch == '#' || + PDFCharIsDelimiter(ch)) { + dest_len += 3; + } else { + dest_len++; + } + } + if (dest_len == src_len) + return orig; + + CFX_ByteString res; + FX_CHAR* dest_buf = res.GetBuffer(dest_len); + dest_len = 0; + for (i = 0; i < src_len; i++) { + uint8_t ch = src_buf[i]; + if (ch >= 0x80 || PDFCharIsWhitespace(ch) || ch == '#' || + PDFCharIsDelimiter(ch)) { + dest_buf[dest_len++] = '#'; + dest_buf[dest_len++] = "0123456789ABCDEF"[ch / 16]; + dest_buf[dest_len++] = "0123456789ABCDEF"[ch % 16]; + } else { + dest_buf[dest_len++] = ch; + } + } + dest_buf[dest_len] = 0; + res.ReleaseBuffer(); + return res; +} + +CFX_ByteTextBuf& operator<<(CFX_ByteTextBuf& buf, const CPDF_Object* pObj) { + if (!pObj) { + buf << " null"; + return buf; + } + switch (pObj->GetType()) { + case CPDF_Object::NULLOBJ: + buf << " null"; + break; + case CPDF_Object::BOOLEAN: + case CPDF_Object::NUMBER: + buf << " " << pObj->GetString(); + break; + case CPDF_Object::STRING: + buf << PDF_EncodeString(pObj->GetString(), pObj->AsString()->IsHex()); + break; + case CPDF_Object::NAME: { + CFX_ByteString str = pObj->GetString(); + buf << "/" << PDF_NameEncode(str); + break; + } + case CPDF_Object::REFERENCE: { + buf << " " << pObj->AsReference()->GetRefObjNum() << " 0 R "; + break; + } + case CPDF_Object::ARRAY: { + const CPDF_Array* p = pObj->AsArray(); + buf << "["; + for (size_t i = 0; i < p->GetCount(); i++) { + CPDF_Object* pElement = p->GetObjectAt(i); + if (pElement && pElement->GetObjNum()) { + buf << " " << pElement->GetObjNum() << " 0 R"; + } else { + buf << pElement; + } + } + buf << "]"; + break; + } + case CPDF_Object::DICTIONARY: { + const CPDF_Dictionary* p = pObj->AsDictionary(); + buf << "<<"; + for (const auto& it : *p) { + const CFX_ByteString& key = it.first; + CPDF_Object* pValue = it.second; + buf << "/" << PDF_NameEncode(key); + if (pValue && pValue->GetObjNum()) { + buf << " " << pValue->GetObjNum() << " 0 R "; + } else { + buf << pValue; + } + } + buf << ">>"; + break; + } + case CPDF_Object::STREAM: { + const CPDF_Stream* p = pObj->AsStream(); + buf << p->GetDict() << "stream\r\n"; + CPDF_StreamAcc acc; + acc.LoadAllData(p, TRUE); + buf.AppendBlock(acc.GetData(), acc.GetSize()); + buf << "\r\nendstream"; + break; + } + default: + ASSERT(FALSE); + break; + } + return buf; +} diff --git a/core/fpdfapi/parser/fpdf_parser_utility.h b/core/fpdfapi/parser/fpdf_parser_utility.h new file mode 100644 index 0000000000..4c0187ed4a --- /dev/null +++ b/core/fpdfapi/parser/fpdf_parser_utility.h @@ -0,0 +1,39 @@ +// Copyright 2016 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 CORE_FPDFAPI_PARSER_FPDF_PARSER_UTILITY_H_ +#define CORE_FPDFAPI_PARSER_FPDF_PARSER_UTILITY_H_ + +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/fx_system.h" + +class IFX_FileRead; +class CPDF_Dictionary; + +// Use the accessors below instead of directly accessing PDF_CharType. +extern const char PDF_CharType[256]; + +inline bool PDFCharIsWhitespace(uint8_t c) { + return PDF_CharType[c] == 'W'; +} +inline bool PDFCharIsNumeric(uint8_t c) { + return PDF_CharType[c] == 'N'; +} +inline bool PDFCharIsDelimiter(uint8_t c) { + return PDF_CharType[c] == 'D'; +} +inline bool PDFCharIsOther(uint8_t c) { + return PDF_CharType[c] == 'R'; +} + +inline bool PDFCharIsLineEnding(uint8_t c) { + return c == '\r' || c == '\n'; +} + +int32_t GetHeaderOffset(IFX_FileRead* pFile); +int32_t GetDirectInteger(CPDF_Dictionary* pDict, const CFX_ByteString& key); + +#endif // CORE_FPDFAPI_PARSER_FPDF_PARSER_UTILITY_H_ diff --git a/core/fpdfdoc/cpdf_action.cpp b/core/fpdfdoc/cpdf_action.cpp index d23925745e..dabc0bb102 100644 --- a/core/fpdfdoc/cpdf_action.cpp +++ b/core/fpdfdoc/cpdf_action.cpp @@ -6,8 +6,8 @@ #include "core/fpdfdoc/cpdf_action.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_filespec.h" #include "core/fpdfdoc/cpdf_nametree.h" diff --git a/core/fpdfdoc/cpdf_action.h b/core/fpdfdoc/cpdf_action.h index 5b985fb855..426edb12e9 100644 --- a/core/fpdfdoc/cpdf_action.h +++ b/core/fpdfdoc/cpdf_action.h @@ -7,7 +7,7 @@ #ifndef CORE_FPDFDOC_CPDF_ACTION_H_ #define CORE_FPDFDOC_CPDF_ACTION_H_ -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfdoc/cpdf_dest.h" #include "core/fxcrt/fx_string.h" diff --git a/core/fpdfdoc/cpdf_actionfields.cpp b/core/fpdfdoc/cpdf_actionfields.cpp index d87da28016..35ec92c1b8 100644 --- a/core/fpdfdoc/cpdf_actionfields.cpp +++ b/core/fpdfdoc/cpdf_actionfields.cpp @@ -6,8 +6,8 @@ #include "core/fpdfdoc/cpdf_actionfields.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfdoc/cpdf_action.h" size_t CPDF_ActionFields::GetFieldsCount() const { diff --git a/core/fpdfdoc/cpdf_annot.cpp b/core/fpdfdoc/cpdf_annot.cpp index 85c3906620..5cb0281aab 100644 --- a/core/fpdfdoc/cpdf_annot.cpp +++ b/core/fpdfdoc/cpdf_annot.cpp @@ -6,12 +6,12 @@ #include "core/fpdfdoc/cpdf_annot.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/fpdf_render/cpdf_rendercontext.h" #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpvt_generateap.h" #include "core/fxcrt/fx_memory.h" #include "core/fxge/cfx_graphstatedata.h" diff --git a/core/fpdfdoc/cpdf_annotlist.cpp b/core/fpdfdoc/cpdf_annotlist.cpp index c99f22a615..d496584e8a 100644 --- a/core/fpdfdoc/cpdf_annotlist.cpp +++ b/core/fpdfdoc/cpdf_annotlist.cpp @@ -6,10 +6,10 @@ #include "core/fpdfdoc/cpdf_annotlist.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfdoc/cpdf_annot.h" #include "core/fpdfdoc/cpdf_interform.h" #include "core/fpdfdoc/cpdf_occontext.h" diff --git a/core/fpdfdoc/cpdf_apsettings.cpp b/core/fpdfdoc/cpdf_apsettings.cpp index 1c20792cf6..f9127a2720 100644 --- a/core/fpdfdoc/cpdf_apsettings.cpp +++ b/core/fpdfdoc/cpdf_apsettings.cpp @@ -6,8 +6,8 @@ #include "core/fpdfdoc/cpdf_apsettings.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfdoc/cpdf_formcontrol.h" CPDF_ApSettings::CPDF_ApSettings(CPDF_Dictionary* pDict) : m_pDict(pDict) {} diff --git a/core/fpdfdoc/cpdf_bookmark.cpp b/core/fpdfdoc/cpdf_bookmark.cpp index 191a26df14..303f0fcce3 100644 --- a/core/fpdfdoc/cpdf_bookmark.cpp +++ b/core/fpdfdoc/cpdf_bookmark.cpp @@ -6,8 +6,8 @@ #include "core/fpdfdoc/cpdf_bookmark.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfdoc/cpdf_nametree.h" #include "core/fxge/fx_dib.h" diff --git a/core/fpdfdoc/cpdf_bookmarktree.cpp b/core/fpdfdoc/cpdf_bookmarktree.cpp index 7ede3fefff..2a4314547c 100644 --- a/core/fpdfdoc/cpdf_bookmarktree.cpp +++ b/core/fpdfdoc/cpdf_bookmarktree.cpp @@ -6,7 +6,7 @@ #include "core/fpdfdoc/cpdf_bookmarktree.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_document.h" CPDF_Bookmark CPDF_BookmarkTree::GetFirstChild( const CPDF_Bookmark& parent) const { diff --git a/core/fpdfdoc/cpdf_defaultappearance.cpp b/core/fpdfdoc/cpdf_defaultappearance.cpp index 39f2d23745..e1094604fa 100644 --- a/core/fpdfdoc/cpdf_defaultappearance.cpp +++ b/core/fpdfdoc/cpdf_defaultappearance.cpp @@ -6,8 +6,8 @@ #include "core/fpdfdoc/cpdf_defaultappearance.h" -#include "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/cpdf_simple_parser.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpdf_formcontrol.h" FX_BOOL CPDF_DefaultAppearance::HasFont() { diff --git a/core/fpdfdoc/cpdf_dest.cpp b/core/fpdfdoc/cpdf_dest.cpp index da4b9a6f69..312ef87346 100644 --- a/core/fpdfdoc/cpdf_dest.cpp +++ b/core/fpdfdoc/cpdf_dest.cpp @@ -6,8 +6,8 @@ #include "core/fpdfdoc/cpdf_dest.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" namespace { diff --git a/core/fpdfdoc/cpdf_filespec.cpp b/core/fpdfdoc/cpdf_filespec.cpp index c361113df5..46b7f8a446 100644 --- a/core/fpdfdoc/cpdf_filespec.cpp +++ b/core/fpdfdoc/cpdf_filespec.cpp @@ -6,9 +6,9 @@ #include "core/fpdfdoc/cpdf_filespec.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fxcrt/fx_system.h" namespace { diff --git a/core/fpdfdoc/cpdf_filespec_unittest.cpp b/core/fpdfdoc/cpdf_filespec_unittest.cpp index 3daba53aba..72b073510b 100644 --- a/core/fpdfdoc/cpdf_filespec_unittest.cpp +++ b/core/fpdfdoc/cpdf_filespec_unittest.cpp @@ -5,9 +5,9 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfdoc/cpdf_filespec.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/test_support.h" diff --git a/core/fpdfdoc/cpdf_formcontrol.cpp b/core/fpdfdoc/cpdf_formcontrol.cpp index b8f57a53c4..f09935c121 100644 --- a/core/fpdfdoc/cpdf_formcontrol.cpp +++ b/core/fpdfdoc/cpdf_formcontrol.cpp @@ -8,12 +8,12 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" #include "core/fpdfapi/fpdf_render/cpdf_rendercontext.h" #include "core/fpdfapi/page/cpdf_form.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpdf_interform.h" #include "core/fxge/cfx_renderdevice.h" diff --git a/core/fpdfdoc/cpdf_formfield.cpp b/core/fpdfdoc/cpdf_formfield.cpp index 4b4ba7fb47..dc45fbcec7 100644 --- a/core/fpdfdoc/cpdf_formfield.cpp +++ b/core/fpdfdoc/cpdf_formfield.cpp @@ -8,13 +8,13 @@ #include -#include "core/fpdfapi/fpdf_parser/cfdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/cfdf_document.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_simple_parser.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpdf_formcontrol.h" #include "core/fpdfdoc/cpdf_interform.h" #include "core/fpdfdoc/cpvt_generateap.h" diff --git a/core/fpdfdoc/cpdf_formfield_unittest.cpp b/core/fpdfdoc/cpdf_formfield_unittest.cpp index 42391d1491..11cccf19b8 100644 --- a/core/fpdfdoc/cpdf_formfield_unittest.cpp +++ b/core/fpdfdoc/cpdf_formfield_unittest.cpp @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" #include "core/fpdfdoc/cpdf_formfield.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/core/fpdfdoc/cpdf_iconfit.cpp b/core/fpdfdoc/cpdf_iconfit.cpp index dacd521c80..7834710588 100644 --- a/core/fpdfdoc/cpdf_iconfit.cpp +++ b/core/fpdfdoc/cpdf_iconfit.cpp @@ -6,8 +6,8 @@ #include "core/fpdfdoc/cpdf_iconfit.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fxcrt/fx_string.h" CPDF_IconFit::ScaleMethod CPDF_IconFit::GetScaleMethod() { diff --git a/core/fpdfdoc/cpdf_interform.cpp b/core/fpdfdoc/cpdf_interform.cpp index 7a14d9c227..bda0ac2831 100644 --- a/core/fpdfdoc/cpdf_interform.cpp +++ b/core/fpdfdoc/cpdf_interform.cpp @@ -8,11 +8,11 @@ #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/font/cpdf_fontencoding.h" -#include "core/fpdfapi/fpdf_parser/cfdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cfdf_document.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfdoc/cpdf_filespec.h" #include "core/fpdfdoc/cpdf_formcontrol.h" #include "core/fpdfdoc/cpdf_interform.h" diff --git a/core/fpdfdoc/cpdf_interform.h b/core/fpdfdoc/cpdf_interform.h index 71d4517cbb..fef4ae2bc4 100644 --- a/core/fpdfdoc/cpdf_interform.h +++ b/core/fpdfdoc/cpdf_interform.h @@ -11,7 +11,7 @@ #include #include -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpdf_defaultappearance.h" #include "core/fxcrt/fx_string.h" #include "core/fxcrt/fx_system.h" diff --git a/core/fpdfdoc/cpdf_link.cpp b/core/fpdfdoc/cpdf_link.cpp index 3c2df15f5a..20ec486df2 100644 --- a/core/fpdfdoc/cpdf_link.cpp +++ b/core/fpdfdoc/cpdf_link.cpp @@ -6,7 +6,7 @@ #include "core/fpdfdoc/cpdf_link.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfdoc/cpdf_nametree.h" CFX_FloatRect CPDF_Link::GetRect() { diff --git a/core/fpdfdoc/cpdf_linklist.cpp b/core/fpdfdoc/cpdf_linklist.cpp index 1d2cddd05a..2d8f7e2339 100644 --- a/core/fpdfdoc/cpdf_linklist.cpp +++ b/core/fpdfdoc/cpdf_linklist.cpp @@ -6,8 +6,8 @@ #include "core/fpdfdoc/cpdf_linklist.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_array.h" CPDF_LinkList::CPDF_LinkList() {} diff --git a/core/fpdfdoc/cpdf_metadata.cpp b/core/fpdfdoc/cpdf_metadata.cpp index 3f90b66a64..226194682c 100644 --- a/core/fpdfdoc/cpdf_metadata.cpp +++ b/core/fpdfdoc/cpdf_metadata.cpp @@ -6,9 +6,9 @@ #include "core/fpdfdoc/cpdf_metadata.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fxcrt/fx_xml.h" CPDF_Metadata::CPDF_Metadata(CPDF_Document* pDoc) { diff --git a/core/fpdfdoc/cpdf_nametree.cpp b/core/fpdfdoc/cpdf_nametree.cpp index 37aab075c0..b8d1eb0ab1 100644 --- a/core/fpdfdoc/cpdf_nametree.cpp +++ b/core/fpdfdoc/cpdf_nametree.cpp @@ -6,9 +6,9 @@ #include "core/fpdfdoc/cpdf_nametree.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" namespace { diff --git a/core/fpdfdoc/cpdf_numbertree.cpp b/core/fpdfdoc/cpdf_numbertree.cpp index 47ce194b60..5f2bc06666 100644 --- a/core/fpdfdoc/cpdf_numbertree.cpp +++ b/core/fpdfdoc/cpdf_numbertree.cpp @@ -6,8 +6,8 @@ #include "core/fpdfdoc/cpdf_numbertree.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" namespace { diff --git a/core/fpdfdoc/cpdf_occontext.cpp b/core/fpdfdoc/cpdf_occontext.cpp index d9c742c78f..c4272f4897 100644 --- a/core/fpdfdoc/cpdf_occontext.cpp +++ b/core/fpdfdoc/cpdf_occontext.cpp @@ -6,9 +6,9 @@ #include "core/fpdfdoc/cpdf_occontext.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/cpdf_pageobject.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" namespace { diff --git a/core/fpdfdoc/cpdf_pagelabel.cpp b/core/fpdfdoc/cpdf_pagelabel.cpp index 35aa2fda9f..64075ef55a 100644 --- a/core/fpdfdoc/cpdf_pagelabel.cpp +++ b/core/fpdfdoc/cpdf_pagelabel.cpp @@ -6,9 +6,9 @@ #include "core/fpdfdoc/cpdf_pagelabel.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpdf_numbertree.h" namespace { diff --git a/core/fpdfdoc/cpdf_viewerpreferences.cpp b/core/fpdfdoc/cpdf_viewerpreferences.cpp index 98e22b3d44..fb005bef86 100644 --- a/core/fpdfdoc/cpdf_viewerpreferences.cpp +++ b/core/fpdfdoc/cpdf_viewerpreferences.cpp @@ -6,7 +6,7 @@ #include "core/fpdfdoc/cpdf_viewerpreferences.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_document.h" CPDF_ViewerPreferences::CPDF_ViewerPreferences(CPDF_Document* pDoc) : m_pDoc(pDoc) {} diff --git a/core/fpdfdoc/cpvt_color.cpp b/core/fpdfdoc/cpvt_color.cpp index e42fad3398..e0e6a26db7 100644 --- a/core/fpdfdoc/cpvt_color.cpp +++ b/core/fpdfdoc/cpvt_color.cpp @@ -6,7 +6,7 @@ #include "core/fpdfdoc/cpvt_color.h" -#include "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h" +#include "core/fpdfapi/parser/cpdf_simple_parser.h" // Static. CPVT_Color CPVT_Color::ParseColor(const CFX_ByteString& str) { diff --git a/core/fpdfdoc/cpvt_color.h b/core/fpdfdoc/cpvt_color.h index 0eec252703..4d4942dbf9 100644 --- a/core/fpdfdoc/cpvt_color.h +++ b/core/fpdfdoc/cpvt_color.h @@ -7,7 +7,7 @@ #ifndef CORE_FPDFDOC_CPVT_COLOR_H_ #define CORE_FPDFDOC_CPVT_COLOR_H_ -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_array.h" #include "core/fxcrt/fx_string.h" #include "core/fxcrt/fx_system.h" diff --git a/core/fpdfdoc/cpvt_fontmap.cpp b/core/fpdfdoc/cpvt_fontmap.cpp index 4a3bafd56a..a47595a6ac 100644 --- a/core/fpdfdoc/cpvt_fontmap.cpp +++ b/core/fpdfdoc/cpvt_fontmap.cpp @@ -7,8 +7,8 @@ #include "core/fpdfdoc/cpvt_fontmap.h" #include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_interform.h" CPVT_FontMap::CPVT_FontMap(CPDF_Document* pDoc, diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp index 0b75b3d33d..28b436a05c 100644 --- a/core/fpdfdoc/cpvt_generateap.cpp +++ b/core/fpdfdoc/cpvt_generateap.cpp @@ -9,11 +9,11 @@ #include #include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_simple_parser.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpdf_annot.h" #include "core/fpdfdoc/cpdf_formfield.h" #include "core/fpdfdoc/cpvt_color.h" diff --git a/core/fpdfdoc/doc_tagged.cpp b/core/fpdfdoc/doc_tagged.cpp index 551732d836..ba80c2171b 100644 --- a/core/fpdfdoc/doc_tagged.cpp +++ b/core/fpdfdoc/doc_tagged.cpp @@ -6,11 +6,11 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfdoc/cpdf_numbertree.h" #include "core/fpdfdoc/fpdf_tagged.h" #include "core/fpdfdoc/tagged_int.h" diff --git a/core/fpdftext/cpdf_textpage.cpp b/core/fpdftext/cpdf_textpage.cpp index e6bd13015e..a65af601cc 100644 --- a/core/fpdftext/cpdf_textpage.cpp +++ b/core/fpdftext/cpdf_textpage.cpp @@ -11,13 +11,13 @@ #include #include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_formobject.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_textobject.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdftext/unicodenormalizationdata.h" #include "core/fxcrt/fx_bidi.h" #include "core/fxcrt/fx_ext.h" diff --git a/core/fxcodec/codec/fx_codec_jbig.cpp b/core/fxcodec/codec/fx_codec_jbig.cpp index 7b8d99ae89..3d3fe74eb1 100644 --- a/core/fxcodec/codec/fx_codec_jbig.cpp +++ b/core/fxcodec/codec/fx_codec_jbig.cpp @@ -8,7 +8,7 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fxcodec/JBig2_DocumentContext.h" #include "core/fxcodec/jbig2/JBig2_Context.h" #include "core/fxcodec/jbig2/JBig2_Image.h" diff --git a/core/fxcodec/jbig2/JBig2_BitStream.cpp b/core/fxcodec/jbig2/JBig2_BitStream.cpp index 7aee93d95f..b5dfe92cda 100644 --- a/core/fxcodec/jbig2/JBig2_BitStream.cpp +++ b/core/fxcodec/jbig2/JBig2_BitStream.cpp @@ -8,8 +8,8 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" CJBig2_BitStream::CJBig2_BitStream(CPDF_StreamAcc* pSrcStream) : m_pBuf(pSrcStream->GetData()), diff --git a/core/fxcodec/jbig2/JBig2_Context.cpp b/core/fxcodec/jbig2/JBig2_Context.cpp index ee5800d7e0..4239223669 100644 --- a/core/fxcodec/jbig2/JBig2_Context.cpp +++ b/core/fxcodec/jbig2/JBig2_Context.cpp @@ -11,8 +11,8 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fxcodec/jbig2/JBig2_ArithDecoder.h" #include "core/fxcodec/jbig2/JBig2_BitStream.h" #include "core/fxcodec/jbig2/JBig2_GrdProc.h" diff --git a/core/fxcodec/jbig2/JBig2_Context.h b/core/fxcodec/jbig2/JBig2_Context.h index ab94d9eb98..2de5ebbf2c 100644 --- a/core/fxcodec/jbig2/JBig2_Context.h +++ b/core/fxcodec/jbig2/JBig2_Context.h @@ -12,7 +12,7 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" +#include "core/fpdfapi/parser/cpdf_object.h" #include "core/fxcodec/fx_codec_def.h" #include "core/fxcodec/jbig2/JBig2_List.h" #include "core/fxcodec/jbig2/JBig2_Page.h" diff --git a/core/fxge/dib/fx_dib_engine_unittest.cpp b/core/fxge/dib/fx_dib_engine_unittest.cpp index b7c79c390a..927951d3bd 100644 --- a/core/fxge/dib/fx_dib_engine_unittest.cpp +++ b/core/fxge/dib/fx_dib_engine_unittest.cpp @@ -4,10 +4,10 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" #include "core/fpdfapi/fpdf_render/render_int.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fxcrt/fx_memory.h" #include "core/fxge/dib/dib_int.h" #include "core/fxge/fx_dib.h" diff --git a/core/fxge/ge/cfx_graphstate.cpp b/core/fxge/ge/cfx_graphstate.cpp index aaff154e65..7eb6d3d853 100644 --- a/core/fxge/ge/cfx_graphstate.cpp +++ b/core/fxge/ge/cfx_graphstate.cpp @@ -6,7 +6,7 @@ #include "core/fxge/cfx_graphstate.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_array.h" CFX_GraphState::CFX_GraphState() {} diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp index c37933a50c..2e70e8014b 100644 --- a/core/fxge/skia/fx_skia_device.cpp +++ b/core/fxge/skia/fx_skia_device.cpp @@ -9,11 +9,11 @@ #include "core/fxcodec/fx_codec.h" #include "core/fxcrt/fx_memory.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" #include "core/fpdfapi/page/cpdf_shadingpattern.h" #include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fxge/cfx_fxgedevice.h" #include "core/fxge/cfx_gemodule.h" #include "core/fxge/cfx_graphstatedata.h" diff --git a/fpdfsdk/DEPS b/fpdfsdk/DEPS index 971b36a865..6bd4d7db8c 100644 --- a/fpdfsdk/DEPS +++ b/fpdfsdk/DEPS @@ -3,7 +3,7 @@ include_rules = [ '+core/fpdfapi', '+core/fpdfapi/edit', '+core/fpdfapi/page', - '+core/fpdfapi/fpdf_parser', + '+core/fpdfapi/parser', '+core/fpdfapi/fpdf_render', '+core/fpdfdoc', '+core/fxcodec', diff --git a/fpdfsdk/cfx_systemhandler.cpp b/fpdfsdk/cfx_systemhandler.cpp index ffc0a79147..adcc5bee56 100644 --- a/fpdfsdk/cfx_systemhandler.cpp +++ b/fpdfsdk/cfx_systemhandler.cpp @@ -8,7 +8,7 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fxge/cfx_fontmapper.h" #include "core/fxge/cfx_fontmgr.h" #include "core/fxge/cfx_gemodule.h" diff --git a/fpdfsdk/cpdfsdk_baannot.cpp b/fpdfsdk/cpdfsdk_baannot.cpp index 163eb2574e..7d2a92ac10 100644 --- a/fpdfsdk/cpdfsdk_baannot.cpp +++ b/fpdfsdk/cpdfsdk_baannot.cpp @@ -6,11 +6,11 @@ #include "fpdfsdk/cpdfsdk_baannot.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "fpdfsdk/cpdfsdk_datetime.h" #include "fpdfsdk/cpdfsdk_document.h" #include "fpdfsdk/cpdfsdk_pageview.h" diff --git a/fpdfsdk/cpdfsdk_baannothandler.cpp b/fpdfsdk/cpdfsdk_baannothandler.cpp index 4e4d284b61..c22ee4a76e 100644 --- a/fpdfsdk/cpdfsdk_baannothandler.cpp +++ b/fpdfsdk/cpdfsdk_baannothandler.cpp @@ -9,8 +9,8 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_interform.h" #include "fpdfsdk/cpdfsdk_annot.h" #include "fpdfsdk/cpdfsdk_baannot.h" diff --git a/fpdfsdk/cpdfsdk_document.cpp b/fpdfsdk/cpdfsdk_document.cpp index 6179ef88d4..86d3b76e81 100644 --- a/fpdfsdk/cpdfsdk_document.cpp +++ b/fpdfsdk/cpdfsdk_document.cpp @@ -6,10 +6,10 @@ #include "fpdfsdk/cpdfsdk_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_object.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_object.h" #include "core/fpdfdoc/cpdf_action.h" #include "core/fpdfdoc/cpdf_docjsactions.h" #include "core/fpdfdoc/cpdf_occontext.h" diff --git a/fpdfsdk/cpdfsdk_document.h b/fpdfsdk/cpdfsdk_document.h index f693588da0..196fba42cc 100644 --- a/fpdfsdk/cpdfsdk_document.h +++ b/fpdfsdk/cpdfsdk_document.h @@ -10,7 +10,7 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fxcrt/cfx_observable.h" #include "fpdfsdk/cpdfsdk_annot.h" #include "fpdfsdk/fsdk_define.h" diff --git a/fpdfsdk/cpdfsdk_environment.h b/fpdfsdk/cpdfsdk_environment.h index 0b46f55ac6..9943d38c67 100644 --- a/fpdfsdk/cpdfsdk_environment.h +++ b/fpdfsdk/cpdfsdk_environment.h @@ -9,8 +9,8 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_occontext.h" #include "core/fxcrt/cfx_observable.h" #include "fpdfsdk/cfx_systemhandler.h" diff --git a/fpdfsdk/cpdfsdk_interform.cpp b/fpdfsdk/cpdfsdk_interform.cpp index a5f3f127ba..bc6f2d30fb 100644 --- a/fpdfsdk/cpdfsdk_interform.cpp +++ b/fpdfsdk/cpdfsdk_interform.cpp @@ -10,11 +10,11 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cfdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cfdf_document.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfdoc/cpdf_actionfields.h" #include "core/fpdfdoc/cpdf_interform.h" #include "core/fxge/cfx_graphstatedata.h" diff --git a/fpdfsdk/cpdfsdk_pageview.cpp b/fpdfsdk/cpdfsdk_pageview.cpp index f877d25da5..ee92b867a2 100644 --- a/fpdfsdk/cpdfsdk_pageview.cpp +++ b/fpdfsdk/cpdfsdk_pageview.cpp @@ -9,8 +9,8 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_annotlist.h" #include "core/fpdfdoc/cpdf_interform.h" #include "fpdfsdk/cpdfsdk_annot.h" diff --git a/fpdfsdk/cpdfsdk_widget.cpp b/fpdfsdk/cpdfsdk_widget.cpp index 76cfa2a1f8..412f040e19 100644 --- a/fpdfsdk/cpdfsdk_widget.cpp +++ b/fpdfsdk/cpdfsdk_widget.cpp @@ -8,9 +8,9 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfdoc/cpdf_defaultappearance.h" #include "core/fpdfdoc/cpdf_formcontrol.h" #include "core/fpdfdoc/cpdf_formfield.h" diff --git a/fpdfsdk/cpdfsdk_widgethandler.cpp b/fpdfsdk/cpdfsdk_widgethandler.cpp index 6647fd996a..2d36fb18a4 100644 --- a/fpdfsdk/cpdfsdk_widgethandler.cpp +++ b/fpdfsdk/cpdfsdk_widgethandler.cpp @@ -9,8 +9,8 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_interform.h" #include "fpdfsdk/cpdfsdk_annot.h" #include "fpdfsdk/cpdfsdk_document.h" diff --git a/fpdfsdk/formfiller/cba_fontmap.cpp b/fpdfsdk/formfiller/cba_fontmap.cpp index 797cfe57f9..26feaf765d 100644 --- a/fpdfsdk/formfiller/cba_fontmap.cpp +++ b/fpdfsdk/formfiller/cba_fontmap.cpp @@ -7,11 +7,11 @@ #include "fpdfsdk/formfiller/cba_fontmap.h" #include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_simple_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_simple_parser.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpdf_formfield.h" #include "core/fxge/cfx_substfont.h" #include "fpdfsdk/cpdfsdk_annot.h" diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp index 7e6def2cfe..b2789d7f90 100644 --- a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp +++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp @@ -6,8 +6,8 @@ #include "fpdfsdk/formfiller/cffl_interactiveformfiller.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fxge/cfx_graphstatedata.h" #include "core/fxge/cfx_pathdata.h" #include "core/fxge/cfx_renderdevice.h" diff --git a/fpdfsdk/fpdf_dataavail.cpp b/fpdfsdk/fpdf_dataavail.cpp index f38f38eaa9..fb866ec229 100644 --- a/fpdfsdk/fpdf_dataavail.cpp +++ b/fpdfsdk/fpdf_dataavail.cpp @@ -9,8 +9,8 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_data_avail.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_data_avail.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "fpdfsdk/fsdk_define.h" #include "public/fpdf_formfill.h" #include "third_party/base/ptr_util.h" diff --git a/fpdfsdk/fpdf_ext.cpp b/fpdfsdk/fpdf_ext.cpp index 66247545d9..432e91853a 100644 --- a/fpdfsdk/fpdf_ext.cpp +++ b/fpdfsdk/fpdf_ext.cpp @@ -9,8 +9,8 @@ #include #include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_annot.h" #include "core/fpdfdoc/cpdf_interform.h" #include "core/fpdfdoc/cpdf_metadata.h" diff --git a/fpdfsdk/fpdf_flatten.cpp b/fpdfsdk/fpdf_flatten.cpp index 2eac4e9513..854a99258f 100644 --- a/fpdfsdk/fpdf_flatten.cpp +++ b/fpdfsdk/fpdf_flatten.cpp @@ -8,13 +8,13 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/cpdf_pageobject.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfdoc/cpdf_annot.h" #include "fpdfsdk/fsdk_define.h" diff --git a/fpdfsdk/fpdf_transformpage.cpp b/fpdfsdk/fpdf_transformpage.cpp index 7a904702cc..dfaebd3143 100644 --- a/fpdfsdk/fpdf_transformpage.cpp +++ b/fpdfsdk/fpdf_transformpage.cpp @@ -6,15 +6,15 @@ #include "public/fpdf_transformpage.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" #include "core/fpdfapi/page/cpdf_clippath.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_path.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fxge/cfx_pathdata.h" #include "fpdfsdk/fsdk_define.h" diff --git a/fpdfsdk/fpdfdoc.cpp b/fpdfsdk/fpdfdoc.cpp index 639fed9dff..37cad53486 100644 --- a/fpdfsdk/fpdfdoc.cpp +++ b/fpdfsdk/fpdfdoc.cpp @@ -8,9 +8,9 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_bookmark.h" #include "core/fpdfdoc/cpdf_bookmarktree.h" #include "fpdfsdk/fsdk_define.h" diff --git a/fpdfsdk/fpdfdoc_unittest.cpp b/fpdfsdk/fpdfdoc_unittest.cpp index e559f60125..ef976775fe 100644 --- a/fpdfsdk/fpdfdoc_unittest.cpp +++ b/fpdfsdk/fpdfdoc_unittest.cpp @@ -8,12 +8,12 @@ #include #include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/test_support.h" #include "third_party/base/ptr_util.h" diff --git a/fpdfsdk/fpdfeditpage.cpp b/fpdfsdk/fpdfeditpage.cpp index 2b7c350915..861e14ed66 100644 --- a/fpdfsdk/fpdfeditpage.cpp +++ b/fpdfsdk/fpdfeditpage.cpp @@ -11,10 +11,6 @@ #include #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_formobject.h" #include "core/fpdfapi/page/cpdf_imageobject.h" @@ -22,6 +18,10 @@ #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_pathobject.h" #include "core/fpdfapi/page/cpdf_shadingobject.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfdoc/cpdf_annot.h" #include "core/fpdfdoc/cpdf_annotlist.h" #include "fpdfsdk/fsdk_define.h" diff --git a/fpdfsdk/fpdfformfill.cpp b/fpdfsdk/fpdfformfill.cpp index 624bbb39c7..1c1cab10e8 100644 --- a/fpdfsdk/fpdfformfill.cpp +++ b/fpdfsdk/fpdfformfill.cpp @@ -9,9 +9,9 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_formcontrol.h" #include "core/fpdfdoc/cpdf_formfield.h" #include "core/fpdfdoc/cpdf_interform.h" diff --git a/fpdfsdk/fpdfppo.cpp b/fpdfsdk/fpdfppo.cpp index d0dde33cb6..f41f904e17 100644 --- a/fpdfsdk/fpdfppo.cpp +++ b/fpdfsdk/fpdfppo.cpp @@ -10,13 +10,13 @@ #include #include -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_name.h" -#include "core/fpdfapi/fpdf_parser/cpdf_number.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "fpdfsdk/fsdk_define.h" #include "third_party/base/stl_util.h" diff --git a/fpdfsdk/fpdfsave.cpp b/fpdfsdk/fpdfsave.cpp index d29f8d206c..72cba11426 100644 --- a/fpdfsdk/fpdfsave.cpp +++ b/fpdfsdk/fpdfsave.cpp @@ -9,11 +9,11 @@ #include #include "core/fpdfapi/edit/cpdf_creator.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "core/fxcrt/fx_ext.h" #include "fpdfsdk/fsdk_define.h" #include "public/fpdf_edit.h" diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp index 48a1b06307..6b3e0c2c0a 100644 --- a/fpdfsdk/fpdfview.cpp +++ b/fpdfsdk/fpdfview.cpp @@ -11,12 +11,12 @@ #include "core/fpdfapi/cpdf_modulemgr.h" #include "core/fpdfapi/cpdf_pagerendercontext.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" #include "core/fpdfapi/fpdf_render/cpdf_progressiverenderer.h" #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpdf_annotlist.h" #include "core/fpdfdoc/cpdf_nametree.h" #include "core/fpdfdoc/cpdf_occontext.h" diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp index 207f320865..3910a701ce 100644 --- a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp +++ b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp @@ -6,9 +6,9 @@ #include "fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" -#include "core/fpdfapi/fpdf_parser/cpdf_string.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_string.h" #include "fpdfsdk/cpdfsdk_document.h" #include "fpdfsdk/cpdfsdk_environment.h" #include "fpdfsdk/cpdfsdk_interform.h" diff --git a/fpdfsdk/fpdfxfa/fpdfxfa_doc.cpp b/fpdfsdk/fpdfxfa/fpdfxfa_doc.cpp index 3bbcfe46bd..a49a2708ef 100644 --- a/fpdfsdk/fpdfxfa/fpdfxfa_doc.cpp +++ b/fpdfsdk/fpdfxfa/fpdfxfa_doc.cpp @@ -6,7 +6,7 @@ #include "fpdfsdk/fpdfxfa/fpdfxfa_doc.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "fpdfsdk/cpdfsdk_document.h" #include "fpdfsdk/cpdfsdk_environment.h" #include "fpdfsdk/cpdfsdk_interform.h" diff --git a/fpdfsdk/fpdfxfa/fpdfxfa_page.cpp b/fpdfsdk/fpdfxfa/fpdfxfa_page.cpp index 4a0ebf0d15..c8a2a6c206 100644 --- a/fpdfsdk/fpdfxfa/fpdfxfa_page.cpp +++ b/fpdfsdk/fpdfxfa/fpdfxfa_page.cpp @@ -6,8 +6,8 @@ #include "fpdfsdk/fpdfxfa/fpdfxfa_page.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "fpdfsdk/fpdfxfa/fpdfxfa_doc.h" #include "fpdfsdk/fpdfxfa/fpdfxfa_util.h" #include "fpdfsdk/fsdk_define.h" diff --git a/fpdfsdk/fsdk_actionhandler.cpp b/fpdfsdk/fsdk_actionhandler.cpp index 58734e08dc..85eb9d69f5 100644 --- a/fpdfsdk/fsdk_actionhandler.cpp +++ b/fpdfsdk/fsdk_actionhandler.cpp @@ -8,7 +8,7 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfdoc/cpdf_formfield.h" #include "core/fpdfdoc/cpdf_interform.h" #include "fpdfsdk/cpdfsdk_document.h" diff --git a/fpdfsdk/fsdk_define.h b/fpdfsdk/fsdk_define.h index 248a1a9d04..94b18128a0 100644 --- a/fpdfsdk/fsdk_define.h +++ b/fpdfsdk/fsdk_define.h @@ -7,7 +7,7 @@ #ifndef FPDFSDK_FSDK_DEFINE_H_ #define FPDFSDK_FSDK_DEFINE_H_ -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" +#include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fxge/fx_dib.h" #include "public/fpdfview.h" diff --git a/fpdfsdk/fxedit/fxet_ap.cpp b/fpdfsdk/fxedit/fxet_ap.cpp index c16ccdf0c4..448a539581 100644 --- a/fpdfsdk/fxedit/fxet_ap.cpp +++ b/fpdfsdk/fxedit/fxet_ap.cpp @@ -5,7 +5,7 @@ // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpvt_word.h" #include "core/fpdfdoc/ipvt_fontmap.h" #include "fpdfsdk/fxedit/fx_edit.h" diff --git a/fpdfsdk/fxedit/fxet_edit.cpp b/fpdfsdk/fxedit/fxet_edit.cpp index 2ebbf2cb05..962c579355 100644 --- a/fpdfsdk/fxedit/fxet_edit.cpp +++ b/fpdfsdk/fxedit/fxet_edit.cpp @@ -11,13 +11,13 @@ #include #include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" #include "core/fpdfapi/fpdf_render/cpdf_textrenderer.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_pageobjectholder.h" #include "core/fpdfapi/page/cpdf_pathobject.h" #include "core/fpdfapi/page/cpdf_textobject.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpvt_section.h" #include "core/fpdfdoc/cpvt_word.h" #include "core/fpdfdoc/ipvt_fontmap.h" diff --git a/fpdfsdk/javascript/Document.cpp b/fpdfsdk/javascript/Document.cpp index db1b5b0809..233097e42c 100644 --- a/fpdfsdk/javascript/Document.cpp +++ b/fpdfsdk/javascript/Document.cpp @@ -10,10 +10,10 @@ #include #include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpdf_interform.h" #include "core/fpdfdoc/cpdf_nametree.h" #include "fpdfsdk/cpdfsdk_annotiterator.h" diff --git a/fpdfsdk/javascript/Field.cpp b/fpdfsdk/javascript/Field.cpp index 35eeefa83e..241f5a1865 100644 --- a/fpdfsdk/javascript/Field.cpp +++ b/fpdfsdk/javascript/Field.cpp @@ -12,8 +12,8 @@ #include #include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_interform.h" #include "fpdfsdk/cpdfsdk_document.h" #include "fpdfsdk/cpdfsdk_environment.h" diff --git a/fpdfsdk/pdfwindow/PWL_FontMap.cpp b/fpdfsdk/pdfwindow/PWL_FontMap.cpp index 6b0f4fe881..a6f79e283c 100644 --- a/fpdfsdk/pdfwindow/PWL_FontMap.cpp +++ b/fpdfsdk/pdfwindow/PWL_FontMap.cpp @@ -9,8 +9,8 @@ #include "core/fpdfapi/cpdf_modulemgr.h" #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/font/cpdf_fontencoding.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/cpdf_parser.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fpdfdoc/ipvt_fontmap.h" #include "fpdfsdk/pdfwindow/PWL_Wnd.h" #include "third_party/base/ptr_util.h" diff --git a/fpdfsdk/pdfwindow/PWL_Icon.cpp b/fpdfsdk/pdfwindow/PWL_Icon.cpp index 094453f344..19adf91cfe 100644 --- a/fpdfsdk/pdfwindow/PWL_Icon.cpp +++ b/fpdfsdk/pdfwindow/PWL_Icon.cpp @@ -6,8 +6,8 @@ #include "fpdfsdk/pdfwindow/PWL_Icon.h" -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "fpdfsdk/pdfwindow/PWL_Utils.h" #include "fpdfsdk/pdfwindow/PWL_Wnd.h" diff --git a/xfa/DEPS b/xfa/DEPS index 02e836ef76..812a31c1c1 100644 --- a/xfa/DEPS +++ b/xfa/DEPS @@ -1,6 +1,6 @@ include_rules = [ '+core/fxcrt', - '+core/fpdfapi/fpdf_parser', + '+core/fpdfapi/parser', '+core/fxge', '+third_party/bigint' ] diff --git a/xfa/fxfa/app/DEPS b/xfa/fxfa/app/DEPS index 662b4b9d14..bab6ddb1de 100644 --- a/xfa/fxfa/app/DEPS +++ b/xfa/fxfa/app/DEPS @@ -2,7 +2,7 @@ include_rules = [ '+core/fdrm/crypto', '+core/fpdfapi/font', '+core/fpdfapi/page', - '+core/fpdfapi/fpdf_parser', + '+core/fpdfapi/parser', '+core/fpdfdoc', '+core/fxcodec', '+core/fxcodec/codec', diff --git a/xfa/fxfa/app/xfa_ffdoc.cpp b/xfa/fxfa/app/xfa_ffdoc.cpp index 600f8bb264..5e39adc0b3 100644 --- a/xfa/fxfa/app/xfa_ffdoc.cpp +++ b/xfa/fxfa/app/xfa_ffdoc.cpp @@ -8,9 +8,9 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_array.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpdf_nametree.h" #include "core/fxcrt/fx_ext.h" #include "core/fxcrt/fx_memory.h" diff --git a/xfa/fxfa/app/xfa_fontmgr.cpp b/xfa/fxfa/app/xfa_fontmgr.cpp index 156bd69588..6e54c41408 100644 --- a/xfa/fxfa/app/xfa_fontmgr.cpp +++ b/xfa/fxfa/app/xfa_fontmgr.cpp @@ -11,8 +11,8 @@ #include #include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" -#include "core/fpdfapi/fpdf_parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "xfa/fgas/font/fgas_gefont.h" #include "xfa/fxfa/xfa_ffapp.h" #include "xfa/fxfa/xfa_ffdoc.h" diff --git a/xfa/fxfa/xfa_ffapp.h b/xfa/fxfa/xfa_ffapp.h index d7465b145d..b3353616de 100644 --- a/xfa/fxfa/xfa_ffapp.h +++ b/xfa/fxfa/xfa_ffapp.h @@ -9,8 +9,8 @@ #include -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h" -#include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "xfa/fgas/font/fgas_font.h" #include "xfa/fwl/core/ifwl_app.h" #include "xfa/fxfa/fxfa.h" -- cgit v1.2.3