diff --git a/glib/demo/print.c b/glib/demo/print.c index 7cf918fcf..509764cc0 100644 --- a/glib/demo/print.c +++ b/glib/demo/print.c @@ -64,7 +64,7 @@ static void pgd_print_draw_page(GtkPrintOperation *op, GtkPrintContext *context, GtkPrintSettings *settings; #endif PgdPrintOptions options; - PopplerPrintFlags flags = 0; + PopplerRenderAnnotsFlags flags = 0; page = poppler_document_get_page(demo->doc, page_nr); if (!page) { @@ -82,20 +82,20 @@ static void pgd_print_draw_page(GtkPrintOperation *op, GtkPrintContext *context, #endif switch (options) { case PRINT_DOCUMENT: - flags |= POPPLER_PRINT_DOCUMENT; + flags = POPPLER_RENDER_ANNOTS_PRINT_DOCUMENT; break; case PRINT_DOCUMENT_MARKUPS: - flags |= POPPLER_PRINT_MARKUP_ANNOTS; + flags = POPPLER_RENDER_ANNOTS_PRINT_MARKUP; break; case PRINT_DOCUMENT_STAMPS: - flags |= POPPLER_PRINT_STAMP_ANNOTS_ONLY; + flags = POPPLER_RENDER_ANNOTS_PRINT_STAMP; break; default: g_assert_not_reached(); } cr = gtk_print_context_get_cairo_context(context); - poppler_page_render_for_printing_with_options(page, cr, flags); + poppler_page_render_full(page, cr, TRUE, flags); g_object_unref(page); } diff --git a/glib/demo/render.c b/glib/demo/render.c index 13e7bc212..39e80ff8d 100644 --- a/glib/demo/render.c +++ b/glib/demo/render.c @@ -33,6 +33,7 @@ typedef struct gint rotate; GdkRectangle slice; gboolean printing; + gboolean highlight; GtkWidget *swindow; GtkWidget *darea; @@ -139,8 +140,10 @@ static void pgd_render_start(GtkButton *button, PgdRenderDemo *demo) if (demo->printing) { poppler_page_render_for_printing(page, cr); - } else { + } else if (demo->highlight) { poppler_page_render(page, cr); + } else { + poppler_page_render_full(page, cr, FALSE, POPPLER_RENDER_ANNOTS_ALL & (~POPPLER_RENDER_ANNOTS_HIGHLIGHT)); } cairo_restore(cr); @@ -209,6 +212,11 @@ static void pgd_render_printing_selector_changed(GtkToggleButton *tooglebutton, demo->printing = gtk_toggle_button_get_active(tooglebutton); } +static void pgd_render_highlight_selector_changed(GtkToggleButton *tooglebutton, PgdRenderDemo *demo) +{ + demo->highlight = gtk_toggle_button_get_active(tooglebutton); +} + static void pgd_render_slice_selector_value_changed(GtkSpinButton *spinbutton, PgdRenderDemo *demo) { demo->slice.x = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(demo->slice_x)); @@ -224,7 +232,7 @@ GtkWidget *pgd_render_properties_selector_create(PgdRenderDemo *demo) GtkWidget *page_hbox, *page_selector; GtkWidget *scale_hbox, *scale_selector; GtkWidget *rotate_hbox, *rotate_selector; - GtkWidget *printing_selector; + GtkWidget *selector; GtkWidget *slice_hbox; GtkWidget *button; gint n_pages; @@ -292,10 +300,15 @@ GtkWidget *pgd_render_properties_selector_create(PgdRenderDemo *demo) gtk_box_pack_start(GTK_BOX(hbox), rotate_hbox, FALSE, TRUE, 0); gtk_widget_show(rotate_hbox); - printing_selector = gtk_check_button_new_with_label("Printing"); - g_signal_connect(printing_selector, "toggled", G_CALLBACK(pgd_render_printing_selector_changed), (gpointer)demo); - gtk_box_pack_start(GTK_BOX(hbox), printing_selector, FALSE, TRUE, 0); - gtk_widget_show(printing_selector); + selector = gtk_check_button_new_with_label("Printing"); + g_signal_connect(selector, "toggled", G_CALLBACK(pgd_render_printing_selector_changed), (gpointer)demo); + gtk_box_pack_start(GTK_BOX(hbox), selector, FALSE, TRUE, 0); + gtk_widget_show(selector); + + selector = gtk_check_button_new_with_label("Render highlight annots"); + g_signal_connect(selector, "toggled", G_CALLBACK(pgd_render_highlight_selector_changed), (gpointer)demo); + gtk_box_pack_start(GTK_BOX(hbox), selector, FALSE, TRUE, 0); + gtk_widget_show(selector); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12); gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); diff --git a/glib/poppler-annot.cc b/glib/poppler-annot.cc index 5a25707a0..e0f3ecf46 100644 --- a/glib/poppler-annot.cc +++ b/glib/poppler-annot.cc @@ -2037,13 +2037,17 @@ void poppler_annot_free_text_set_font_desc(PopplerAnnotFreeText *poppler_annot, * * Gets the font description (i.e. font family name, style, weight, stretch and size). * - * Returns: (transfer full): a copy of the annotation font description + * Returns: (nullable) (transfer full): a copy of the annotation font description, or NULL if there is + * no font description set. * * Since: 24.12.0 **/ PopplerFontDescription *poppler_annot_free_text_get_font_desc(PopplerAnnotFreeText *poppler_annot) { - return poppler_font_description_copy(poppler_annot->font_desc); + if (poppler_annot->font_desc) { + return poppler_font_description_copy(poppler_annot->font_desc); + } + return nullptr; } /** diff --git a/glib/poppler-form-field.cc b/glib/poppler-form-field.cc index 52f513f94..879807a25 100644 --- a/glib/poppler-form-field.cc +++ b/glib/poppler-form-field.cc @@ -362,11 +362,9 @@ gchar *poppler_form_field_get_mapping_name(PopplerFormField *field) **/ gchar *poppler_form_field_get_name(PopplerFormField *field) { - GooString *tmp; - g_return_val_if_fail(POPPLER_IS_FORM_FIELD(field), NULL); - tmp = field->widget->getFullyQualifiedName(); + const GooString *tmp = field->widget->getFullyQualifiedName(); return tmp ? _poppler_goo_string_to_utf8(tmp) : nullptr; } diff --git a/glib/poppler-page.cc b/glib/poppler-page.cc index a9c34957e..3e56a086a 100644 --- a/glib/poppler-page.cc +++ b/glib/poppler-page.cc @@ -271,45 +271,41 @@ static TextPage *poppler_page_get_text_page(PopplerPage *page) return page->text; } -static gboolean annot_is_markup(Annot *annot) -{ - switch (annot->getType()) { - case Annot::typeLink: - case Annot::typePopup: - case Annot::typeMovie: - case Annot::typeScreen: - case Annot::typePrinterMark: - case Annot::typeTrapNet: - case Annot::typeWatermark: - case Annot::type3D: - case Annot::typeWidget: - return FALSE; - default: - return TRUE; - } -} - -static bool poppler_print_annot_cb(Annot *annot, void *user_data) +static bool annots_display_decide_cb(Annot *annot, void *user_data) { - PopplerPrintFlags user_print_flags = (PopplerPrintFlags)GPOINTER_TO_INT(user_data); - - if (user_print_flags & POPPLER_PRINT_STAMP_ANNOTS_ONLY && (annot->getType() == Annot::typeStamp)) { - return true; - } + PopplerRenderAnnotsFlags flags = (PopplerRenderAnnotsFlags)GPOINTER_TO_UINT(user_data); + Annot::AnnotSubtype type = annot->getType(); + int typeMask = 1 << MAX(0, (((int)type) - 1)); - if (user_print_flags & POPPLER_PRINT_MARKUP_ANNOTS && annot_is_markup(annot)) { + if (flags & typeMask) { return true; } - - /* Form fields are always printed */ - return (annot->getType() == Annot::typeWidget); + return false; } -static void _poppler_page_render(PopplerPage *page, cairo_t *cairo, bool printing, PopplerPrintFlags print_flags) +/** + * poppler_page_render_full: + * @page: the page to render from + * @cairo: cairo context to render to + * @printing: cairo context to render to + * @flags: flags which allow to select which annotations to render + * + * Render the page to the given cairo context, manually selecting which + * annotations should be displayed. + * + * The @printing parameter determines whether a page is rendered for printing + * or for displaying it on a screen. See the documentation for + * poppler_page_render_for_printing() for the differences between rendering to + * the screen and rendering to a printer. + * + * Since: 25.02 + **/ +void poppler_page_render_full(PopplerPage *page, cairo_t *cairo, gboolean printing, PopplerRenderAnnotsFlags flags) { CairoOutputDev *output_dev; g_return_if_fail(POPPLER_IS_PAGE(page)); + g_return_if_fail(cairo != nullptr); output_dev = page->document->output_dev; output_dev->setCairo(cairo); @@ -319,12 +315,13 @@ static void _poppler_page_render(PopplerPage *page, cairo_t *cairo, bool printin page->text = new TextPage(false); output_dev->setTextPage(page->text); } - /* NOTE: instead of passing -1 we should/could use cairo_clip_extents() - * to get a bounding box */ + cairo_save(cairo); page->page->displaySlice(output_dev, 72.0, 72.0, 0, false, /* useMediaBox */ true, /* Crop */ - -1, -1, -1, -1, printing, nullptr, nullptr, printing ? poppler_print_annot_cb : nullptr, printing ? GINT_TO_POINTER((gint)print_flags) : nullptr); + -1, -1, -1, -1, /* instead of passing -1 we could use cairo_clip_extents() to get a bounding box */ + + printing, nullptr, nullptr, annots_display_decide_cb, GUINT_TO_POINTER((guint)flags)); cairo_restore(cairo); output_dev->setCairo(nullptr); @@ -345,9 +342,7 @@ static void _poppler_page_render(PopplerPage *page, cairo_t *cairo, bool printin **/ void poppler_page_render(PopplerPage *page, cairo_t *cairo) { - g_return_if_fail(POPPLER_IS_PAGE(page)); - - _poppler_page_render(page, cairo, false, (PopplerPrintFlags)0); + poppler_page_render_full(page, cairo, false, POPPLER_RENDER_ANNOTS_ALL); } /** @@ -363,13 +358,24 @@ void poppler_page_render(PopplerPage *page, cairo_t *cairo) * differences between rendering to the screen and rendering to a printer. * * Since: 0.16 + * + * Deprecated: 25.02: Use poppler_page_render_full() instead. **/ +G_GNUC_BEGIN_IGNORE_DEPRECATIONS void poppler_page_render_for_printing_with_options(PopplerPage *page, cairo_t *cairo, PopplerPrintFlags options) { - g_return_if_fail(POPPLER_IS_PAGE(page)); + int flags = (int)POPPLER_RENDER_ANNOTS_PRINT_DOCUMENT; + + if (options & POPPLER_PRINT_STAMP_ANNOTS_ONLY) { + flags |= POPPLER_RENDER_ANNOTS_PRINT_STAMP; + } + if (options & POPPLER_PRINT_MARKUP_ANNOTS) { + flags |= POPPLER_RENDER_ANNOTS_PRINT_MARKUP; + } - _poppler_page_render(page, cairo, true, options); + poppler_page_render_full(page, cairo, true, (PopplerRenderAnnotsFlags)flags); } +G_GNUC_END_IGNORE_DEPRECATIONS /** * poppler_page_render_for_printing: @@ -378,7 +384,8 @@ void poppler_page_render_for_printing_with_options(PopplerPage *page, cairo_t *c * * Render the page to the given cairo context for printing with * #POPPLER_PRINT_ALL flags selected. If you want a different set of flags, - * use poppler_page_render_for_printing_with_options(). + * use poppler_page_render_full() with printing #TRUE and the corresponding + * flags. * * The difference between poppler_page_render() and this function is that some * things get rendered differently between screens and printers: @@ -409,9 +416,7 @@ void poppler_page_render_for_printing_with_options(PopplerPage *page, cairo_t *c **/ void poppler_page_render_for_printing(PopplerPage *page, cairo_t *cairo) { - g_return_if_fail(POPPLER_IS_PAGE(page)); - - _poppler_page_render(page, cairo, true, POPPLER_PRINT_ALL); + poppler_page_render_full(page, cairo, true, POPPLER_RENDER_ANNOTS_PRINT_ALL); } static cairo_surface_t *create_surface_from_thumbnail_data(guchar *data, gint width, gint height, gint rowstride) diff --git a/glib/poppler-page.h b/glib/poppler-page.h index de4896f74..d6872bdde 100644 --- a/glib/poppler-page.h +++ b/glib/poppler-page.h @@ -37,9 +37,13 @@ GType poppler_page_get_type(void) G_GNUC_CONST; POPPLER_PUBLIC void poppler_page_render(PopplerPage *page, cairo_t *cairo); POPPLER_PUBLIC +void poppler_page_render_full(PopplerPage *page, cairo_t *cairo, gboolean printing, PopplerRenderAnnotsFlags flags); +POPPLER_PUBLIC void poppler_page_render_for_printing(PopplerPage *page, cairo_t *cairo); +G_GNUC_BEGIN_IGNORE_DEPRECATIONS POPPLER_PUBLIC -void poppler_page_render_for_printing_with_options(PopplerPage *page, cairo_t *cairo, PopplerPrintFlags options); +void poppler_page_render_for_printing_with_options(PopplerPage *page, cairo_t *cairo, PopplerPrintFlags options) G_GNUC_DEPRECATED_FOR(poppler_page_render_full); +G_GNUC_END_IGNORE_DEPRECATIONS POPPLER_PUBLIC cairo_surface_t *poppler_page_get_thumbnail(PopplerPage *page); POPPLER_PUBLIC diff --git a/glib/poppler.h b/glib/poppler.h index 435e28c59..ed5edccd1 100644 --- a/glib/poppler.h +++ b/glib/poppler.h @@ -131,6 +131,91 @@ typedef enum POPPLER_SELECTION_LINE } PopplerSelectionStyle; +/** + * PopplerRenderFlags: + * @POPPLER_RENDER_ANNOTS_NONE: do not render annotations + * @POPPLER_RENDER_ANNOTS_TEXT: render text annotations + * @POPPLER_RENDER_ANNOTS_LINK: render link annotations + * @POPPLER_RENDER_ANNOTS_FREETEXT: render freetext annotations, + * @POPPLER_RENDER_ANNOTS_LINE: render line annotations, + * @POPPLER_RENDER_ANNOTS_SQUARE: render square annotations, + * @POPPLER_RENDER_ANNOTS_CIRCLE: render circle annotations, + * @POPPLER_RENDER_ANNOTS_POLYGON: render polygon annotations, + * @POPPLER_RENDER_ANNOTS_POLYLINE: render polyline annotations, + * @POPPLER_RENDER_ANNOTS_HIGHLIGHT: render highlight annotations, + * @POPPLER_RENDER_ANNOTS_UNDERLINE: render underline annotations, + * @POPPLER_RENDER_ANNOTS_SQUIGGLY: render squiggly annotations, + * @POPPLER_RENDER_ANNOTS_STRIKEOUT: render strikeout annotations, + * @POPPLER_RENDER_ANNOTS_STAMP: render stamp annotations, + * @POPPLER_RENDER_ANNOTS_CARET: render caret annotations, + * @POPPLER_RENDER_ANNOTS_INK: render ink annotations, + * @POPPLER_RENDER_ANNOTS_POPUP: render popup annotations, + * @POPPLER_RENDER_ANNOTS_FILEATTACHMENT: render fileattachment annotations, + * @POPPLER_RENDER_ANNOTS_SOUND: render sound annotations, + * @POPPLER_RENDER_ANNOTS_MOVIE: render movie annotations, + * @POPPLER_RENDER_ANNOTS_WIDGET: render widget annotations, + * @POPPLER_RENDER_ANNOTS_SCREEN: render screen annotations, + * @POPPLER_RENDER_ANNOTS_PRINTERMARK: render printermark annotations, + * @POPPLER_RENDER_ANNOTS_TRAPNET: render trapnet annotations, + * @POPPLER_RENDER_ANNOTS_WATERMARK: render watermark annotations, + * @POPPLER_RENDER_ANNOTS_3D: render 3D annotations, + * @POPPLER_RENDER_ANNOTS_RICHMEDIA: render richmedia annotations, + * @POPPLER_RENDER_ANNOTS_PRINT_DOCUMENT: render the default annotations used for printing + * @POPPLER_RENDER_ANNOTS_PRINT_MARKUP: render markup annotations and default annotations used for printing + * @POPPLER_RENDER_ANNOTS_PRINT_STAMP: render stamp annotations and default annotations used for printing + * @POPPLER_RENDER_ANNOTS_PRINT_ALL: render all possible annotations used for printing + * @POPPLER_RENDER_ANNOTS_ALL: render all annotations + * + * Flags to select which annotations to render. If the flag corresponding to a + * certain annotation type is on, then such annotation type will be rendered, + * when appropriate (e.g: won't be renderer if the annotation is not visible). + * This allows to combine multiple flags, like + * `POPPLER_RENDER_ANNOTS_LINK | POPPLER_RENDER_ANNOTS_TEXT`, or disable some + * specific annotations like + * `POPPLER_RENDER_ANNOTS_ALL & (~POPPLER_RENDER_ANNOTS_TEXT)` + * + * Since: 25.02 + */ +typedef enum /*< flags >*/ +{ + POPPLER_RENDER_ANNOTS_NONE = 0, + POPPLER_RENDER_ANNOTS_TEXT = 1 << 0, + POPPLER_RENDER_ANNOTS_LINK = 1 << 1, + POPPLER_RENDER_ANNOTS_FREETEXT = 1 << 2, + POPPLER_RENDER_ANNOTS_LINE = 1 << 3, + POPPLER_RENDER_ANNOTS_SQUARE = 1 << 4, + POPPLER_RENDER_ANNOTS_CIRCLE = 1 << 5, + POPPLER_RENDER_ANNOTS_POLYGON = 1 << 6, + POPPLER_RENDER_ANNOTS_POLYLINE = 1 << 7, + POPPLER_RENDER_ANNOTS_HIGHLIGHT = 1 << 8, + POPPLER_RENDER_ANNOTS_UNDERLINE = 1 << 9, + POPPLER_RENDER_ANNOTS_SQUIGGLY = 1 << 10, + POPPLER_RENDER_ANNOTS_STRIKEOUT = 1 << 11, + POPPLER_RENDER_ANNOTS_STAMP = 1 << 12, + POPPLER_RENDER_ANNOTS_CARET = 1 << 13, + POPPLER_RENDER_ANNOTS_INK = 1 << 14, + POPPLER_RENDER_ANNOTS_POPUP = 1 << 15, + POPPLER_RENDER_ANNOTS_FILEATTACHMENT = 1 << 16, + POPPLER_RENDER_ANNOTS_SOUND = 1 << 17, + POPPLER_RENDER_ANNOTS_MOVIE = 1 << 18, + POPPLER_RENDER_ANNOTS_WIDGET = 1 << 19, + POPPLER_RENDER_ANNOTS_SCREEN = 1 << 20, + POPPLER_RENDER_ANNOTS_PRINTERMARK = 1 << 21, + POPPLER_RENDER_ANNOTS_TRAPNET = 1 << 22, + POPPLER_RENDER_ANNOTS_WATERMARK = 1 << 23, + POPPLER_RENDER_ANNOTS_3D = 1 << 24, + POPPLER_RENDER_ANNOTS_RICHMEDIA = 1 << 25, + + /* Everything below are special flags to combine them all */ + POPPLER_RENDER_ANNOTS_PRINT_DOCUMENT = POPPLER_RENDER_ANNOTS_WIDGET, + POPPLER_RENDER_ANNOTS_PRINT_MARKUP = ~(POPPLER_RENDER_ANNOTS_LINK | POPPLER_RENDER_ANNOTS_POPUP | POPPLER_RENDER_ANNOTS_MOVIE | POPPLER_RENDER_ANNOTS_SCREEN | POPPLER_RENDER_ANNOTS_PRINTERMARK | POPPLER_RENDER_ANNOTS_TRAPNET + | POPPLER_RENDER_ANNOTS_WATERMARK | POPPLER_RENDER_ANNOTS_3D), + POPPLER_RENDER_ANNOTS_PRINT_STAMP = POPPLER_RENDER_ANNOTS_WIDGET | POPPLER_RENDER_ANNOTS_STAMP, + POPPLER_RENDER_ANNOTS_PRINT_ALL = POPPLER_RENDER_ANNOTS_PRINT_MARKUP, + /* Enable all flags, by shifting and substracting the last one */ + POPPLER_RENDER_ANNOTS_ALL = (POPPLER_RENDER_ANNOTS_RICHMEDIA << 1) - 1 +} PopplerRenderAnnotsFlags; + /** * PopplerPrintFlags: * @POPPLER_PRINT_DOCUMENT: print main document contents @@ -140,6 +225,9 @@ typedef enum * * Printing flags * + * Deprecated: 25.02: Use poppler_page_render_full() and + * #PopplerRenderAnnotsFlags instead. + * * Since: 0.16 */ typedef enum /*< flags >*/ @@ -148,7 +236,7 @@ typedef enum /*< flags >*/ POPPLER_PRINT_MARKUP_ANNOTS = 1 << 0, POPPLER_PRINT_STAMP_ANNOTS_ONLY = 1 << 1, POPPLER_PRINT_ALL = POPPLER_PRINT_MARKUP_ANNOTS -} PopplerPrintFlags; +} PopplerPrintFlags G_GNUC_DEPRECATED_FOR(PopplerRenderAnnotsFlags); /** * PopplerFindFlags: diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt index 95e6426e2..86f7e3610 100644 --- a/glib/reference/poppler-sections.txt +++ b/glib/reference/poppler-sections.txt @@ -77,6 +77,7 @@ poppler_page_get_thumbnail_size poppler_page_get_transition poppler_page_remove_annot poppler_page_render +poppler_page_render_full poppler_page_render_for_printing poppler_page_render_for_printing_with_options poppler_page_render_selection diff --git a/glib/tests/CMakeLists.txt b/glib/tests/CMakeLists.txt index 19ebf57e9..a09c66d54 100644 --- a/glib/tests/CMakeLists.txt +++ b/glib/tests/CMakeLists.txt @@ -1,7 +1,3 @@ -macro(POPPLER_ADD_TESTCASE exe arg1) - add_test(${exe}-${arg1} ${EXE} ${EXECUTABLE_OUTPUT_PATH}/poppler-check-bb ${TESTDATADIR}/unittestcases/${arg1} ${ARGN}) -endmacro(POPPLER_ADD_TESTCASE) - add_definitions(-DTESTDATADIR=\"${TESTDATADIR}\") set(poppler_check_text_SRCS @@ -18,27 +14,31 @@ poppler_add_test(poppler-check-bb BUILD_GTK_TESTS ${poppler_check_bb_SRCS}) target_link_libraries(poppler-check-text poppler-glib PkgConfig::GTK3) target_link_libraries(poppler-check-bb poppler-glib PkgConfig::GTK3) -poppler_add_testcase(poppler-check-bb shapes+attachments.pdf 42.5 42.5 557.5 557.5) -poppler_add_testcase(poppler-check-bb orientation.pdf 34 34 83.74 49 793 34 808 97.19 488.02 793 561 808 34 503.61 49 561) -poppler_add_testcase(poppler-check-bb xr01.pdf 148.71 126.35 308.11 704.57) -poppler_add_testcase(poppler-check-bb xr02.pdf 133.77 124.81 308.11 704.57 133.77 124.80 308.11 704.57) -poppler_add_testcase(poppler-check-bb russian.pdf 71.5 76.81 197.69 131.09) -poppler_add_testcase(poppler-check-bb vis_policy_test.pdf 90 77.93 312.01 265.13) -poppler_add_testcase(poppler-check-bb searchAcrossLines.pdf 107.15 105.23 523.85 691 85.04 94 538.59 762.19) -poppler_add_testcase(poppler-check-bb deseret.pdf 56.8 57.15 109.5 72.8) -poppler_add_testcase(poppler-check-bb fieldWithUtf16Names.pdf 56.65 56.65 264.55 83.05) -poppler_add_testcase(poppler-check-bb bug7063.pdf 56.8 57.46 244.29 118.79) -poppler_add_testcase(poppler-check-bb WithActualText.pdf 100 90.72 331.01 102.35) -poppler_add_testcase(poppler-check-bb Issue637.pdf 70.87 53 293 105.37) -poppler_add_testcase(poppler-check-bb truetype.pdf 17.5 17.5 577.5 225.62) -poppler_add_testcase(poppler-check-bb form_set_icon.pdf 0 0 362.835 272.126) -poppler_add_testcase(poppler-check-bb imageretrieve+attachment.pdf 0 0 610.56 792) -poppler_add_testcase(poppler-check-bb checkbox_issue_159.pdf 2.84 14.17 553.18 840.87) -poppler_add_testcase(poppler-check-bb NestedLayers.pdf 0 191 612 792) -poppler_add_testcase(poppler-check-bb A6EmbeddedFiles.pdf 18 18 558.36 751.92) -poppler_add_testcase(poppler-check-bb latex-hyperref-checkbox-issue-655.pdf 148.71 123.81 308.11 704.57) -poppler_add_testcase(poppler-check-bb utf16le-annot.pdf 55.47 54.78 98.74 96.12) -poppler_add_testcase(poppler-check-bb type3.pdf -p 10 125.80 130 509.30 695 125.80 132 538.03 693) +macro(GLIB_ADD_BBTEST arg1) + add_test(poppler-check-bb-${arg1} ${EXE} ${EXECUTABLE_OUTPUT_PATH}/poppler-check-bb ${TESTDATADIR}/unittestcases/${arg1} ${ARGN}) +endmacro(GLIB_ADD_BBTEST) + +glib_add_bbtest(shapes+attachments.pdf 42.5 42.5 557.5 557.5) +glib_add_bbtest(orientation.pdf 34 34 83.74 49 793 34 808 97.19 488.02 793 561 808 34 503.61 49 561) +glib_add_bbtest(xr01.pdf 148.71 126.35 308.11 704.57) +glib_add_bbtest(xr02.pdf 133.77 124.81 308.11 704.57 133.77 124.80 308.11 704.57) +glib_add_bbtest(russian.pdf 71.5 76.81 197.69 131.09) +glib_add_bbtest(vis_policy_test.pdf 90 77.93 312.01 265.13) +glib_add_bbtest(searchAcrossLines.pdf 107.15 105.23 523.85 691 85.04 94 538.59 762.19) +glib_add_bbtest(deseret.pdf 56.8 57.15 109.5 72.8) +glib_add_bbtest(fieldWithUtf16Names.pdf 56.65 56.65 264.55 83.05) +glib_add_bbtest(bug7063.pdf 56.8 57.46 244.29 118.79) +glib_add_bbtest(WithActualText.pdf 100 90.72 331.01 102.35) +glib_add_bbtest(Issue637.pdf 70.87 53 293 105.37) +glib_add_bbtest(truetype.pdf 17.5 17.5 577.5 225.62) +glib_add_bbtest(form_set_icon.pdf 0 0 362.835 272.126) +glib_add_bbtest(imageretrieve+attachment.pdf 0 0 610.56 792) +glib_add_bbtest(checkbox_issue_159.pdf 2.84 14.17 553.18 840.87) +glib_add_bbtest(NestedLayers.pdf 0 191 612 792) +glib_add_bbtest(A6EmbeddedFiles.pdf 18 18 558.36 751.92) +glib_add_bbtest(latex-hyperref-checkbox-issue-655.pdf 148.71 123.81 308.11 704.57) +glib_add_bbtest(utf16le-annot.pdf 55.47 54.78 98.74 96.12) +glib_add_bbtest(type3.pdf -p 10 125.80 130 509.30 695 125.80 132 538.03 693) add_executable(pdfdrawbb pdfdrawbb.c) target_link_libraries(pdfdrawbb poppler-glib) diff --git a/goo/gdir.h b/goo/gdir.h deleted file mode 100644 index 760687919..000000000 --- a/goo/gdir.h +++ /dev/null @@ -1,96 +0,0 @@ -//======================================================================== -// -// gfile.h -// -// Miscellaneous file and directory name manipulation. -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2006 Kristian Høgsberg -// Copyright (C) 2009, 2011, 2012, 2017, 2018, 2021, 2022 Albert Astals Cid -// Copyright (C) 2009 Kovid Goyal -// Copyright (C) 2013 Adam Reichold -// Copyright (C) 2013, 2017 Adrian Johnson -// Copyright (C) 2014 Bogdan Cristea -// Copyright (C) 2014 Peter Breitenlohner -// Copyright (C) 2017 Christoph Cullmann -// Copyright (C) 2017 Thomas Freitag -// Copyright (C) 2018 Mojca Miklavec -// Copyright (C) 2019 Christian Persch -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#ifndef GDIR_H -#define GDIR_H - -#include "poppler-config.h" - -#include - -class GooString; - -#if defined(_WIN32) -# include -#else -# include -#endif - -//------------------------------------------------------------------------ -// GDir and GDirEntry -//------------------------------------------------------------------------ - -class GDirEntry -{ -public: - GDirEntry(const char *dirPath, const char *nameA, bool doStat); - ~GDirEntry(); - - GDirEntry(const GDirEntry &other) = delete; - GDirEntry &operator=(const GDirEntry &other) = delete; - - const GooString *getName() const { return name; } - const GooString *getFullPath() const { return fullPath; } - bool isDir() const { return dir; } - -private: - GooString *name; // dir/file name - GooString *fullPath; - bool dir; // is it a directory? -}; - -class GDir -{ -public: - explicit GDir(const char *name, bool doStatA = true); - ~GDir(); - - GDir(const GDir &other) = delete; - GDir &operator=(const GDir &other) = delete; - - std::unique_ptr getNextEntry(); - void rewind(); - -private: - GooString *path; // directory path - bool doStat; // call stat() for each entry? -#if defined(_WIN32) - WIN32_FIND_DATAA ffd; - HANDLE hnd; -#else - DIR *dir; // the DIR structure from opendir() -#endif -}; - -#endif diff --git a/goo/gfile.cc b/goo/gfile.cc index fb42e0288..499550a60 100644 --- a/goo/gfile.cc +++ b/goo/gfile.cc @@ -48,7 +48,6 @@ #include #include "GooString.h" #include "gfile.h" -#include "gdir.h" // Some systems don't define this, so just make it something reasonably // large. @@ -434,106 +433,3 @@ bool GooFile::modificationTimeChangedSinceOpen() const } #endif // _WIN32 - -//------------------------------------------------------------------------ -// GDir and GDirEntry -//------------------------------------------------------------------------ - -GDirEntry::GDirEntry(const char *dirPath, const char *nameA, bool doStat) -{ -#ifdef _WIN32 - DWORD fa; -#else - struct stat st; -#endif - - name = new GooString(nameA); - dir = false; - fullPath = new GooString(dirPath); - appendToPath(fullPath, nameA); - if (doStat) { -#ifdef _WIN32 - fa = GetFileAttributesA(fullPath->c_str()); - dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY)); -#else - if (stat(fullPath->c_str(), &st) == 0) { - dir = S_ISDIR(st.st_mode); - } -#endif - } -} - -GDirEntry::~GDirEntry() -{ - delete fullPath; - delete name; -} - -GDir::GDir(const char *name, bool doStatA) -{ - path = new GooString(name); - doStat = doStatA; -#ifdef _WIN32 - std::unique_ptr tmp = path->copy(); - tmp->append("/*.*"); - hnd = FindFirstFileA(tmp->c_str(), &ffd); -#else - dir = opendir(name); -#endif -} - -GDir::~GDir() -{ - delete path; -#ifdef _WIN32 - if (hnd != INVALID_HANDLE_VALUE) { - FindClose(hnd); - hnd = INVALID_HANDLE_VALUE; - } -#else - if (dir) { - closedir(dir); - } -#endif -} - -std::unique_ptr GDir::getNextEntry() -{ -#ifdef _WIN32 - if (hnd != INVALID_HANDLE_VALUE) { - auto e = std::make_unique(path->c_str(), ffd.cFileName, doStat); - if (!FindNextFileA(hnd, &ffd)) { - FindClose(hnd); - hnd = INVALID_HANDLE_VALUE; - } - return e; - } -#else - struct dirent *ent; - if (dir) { - do { - ent = readdir(dir); - } while (ent && (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))); - if (ent) { - return std::make_unique(path->c_str(), ent->d_name, doStat); - } - } -#endif - - return {}; -} - -void GDir::rewind() -{ -#ifdef _WIN32 - if (hnd != INVALID_HANDLE_VALUE) - FindClose(hnd); - std::unique_ptr tmp = path->copy(); - tmp->append("/*.*"); - hnd = FindFirstFileA(tmp->c_str(), &ffd); -#else - if (dir) { - rewinddir(dir); - } -#endif -} diff --git a/poppler/Catalog.h b/poppler/Catalog.h index 0b5ebaccc..730695c51 100644 --- a/poppler/Catalog.h +++ b/poppler/Catalog.h @@ -32,7 +32,7 @@ // Copyright (C) 2020 Katarina Behrens // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, . Work sponsored by Technische Universität Dresden // Copyright (C) 2021 RM -// Copyright (C) 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela +// Copyright (C) 2024, 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // Copyright (C) 2024 Hubert Figuière // // To see a description of the changes please see the Changelog file that diff --git a/poppler/CurlPDFDocBuilder.cc b/poppler/CurlPDFDocBuilder.cc index 44b5b920a..2c3a16a38 100644 --- a/poppler/CurlPDFDocBuilder.cc +++ b/poppler/CurlPDFDocBuilder.cc @@ -7,6 +7,7 @@ // Copyright 2010 Hib Eris // Copyright 2010, 2017, 2022, 2024 Albert Astals Cid // Copyright 2021 Oliver Sander +// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // //======================================================================== diff --git a/poppler/CurlPDFDocBuilder.h b/poppler/CurlPDFDocBuilder.h index e50375085..e91691a66 100644 --- a/poppler/CurlPDFDocBuilder.h +++ b/poppler/CurlPDFDocBuilder.h @@ -7,6 +7,7 @@ // Copyright 2010 Hib Eris // Copyright 2010, 2018, 2022 Albert Astals Cid // Copyright 2021 Oliver Sander +// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // //======================================================================== diff --git a/poppler/FDPDFDocBuilder.cc b/poppler/FDPDFDocBuilder.cc index c12a74f17..1382b2999 100644 --- a/poppler/FDPDFDocBuilder.cc +++ b/poppler/FDPDFDocBuilder.cc @@ -8,6 +8,7 @@ // Copyright 2010, 2017, 2021, 2022 Albert Astals Cid // Copyright 2021 Oliver Sander // Copyright 2021 Christian Persch +// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // //======================================================================== diff --git a/poppler/FDPDFDocBuilder.h b/poppler/FDPDFDocBuilder.h index d13684f4b..017d0d8a2 100644 --- a/poppler/FDPDFDocBuilder.h +++ b/poppler/FDPDFDocBuilder.h @@ -8,6 +8,7 @@ // Copyright 2010, 2018, 2022 Albert Astals Cid // Copyright 2021 Oliver Sander // Copyright 2021 Christian Persch +// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // //======================================================================== diff --git a/poppler/FileSpec.h b/poppler/FileSpec.h index a5470091c..d1d5bd3cb 100644 --- a/poppler/FileSpec.h +++ b/poppler/FileSpec.h @@ -7,7 +7,7 @@ // // Copyright (C) 2008 Carlos Garcia Campos // Copyright (C) 2017-2019, 2021, 2024 Albert Astals Cid -// Copyright (C) 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela +// Copyright (C) 2024, 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git diff --git a/poppler/Form.cc b/poppler/Form.cc index 150178344..b67f8515e 100644 --- a/poppler/Form.cc +++ b/poppler/Form.cc @@ -91,32 +91,28 @@ template inline constexpr bool always_false_v = false; // return a newly allocated char* containing an UTF16BE string of size length -char *pdfDocEncodingToUTF16(const std::string &orig, int *length) +std::string pdfDocEncodingToUTF16(const std::string &orig) { // double size, a unicode char takes 2 char, add 2 for the unicode marker - *length = 2 + 2 * orig.size(); - char *result = new char[(*length)]; - const char *cstring = orig.c_str(); + int length = 2 + 2 * orig.size(); + std::string result; + result.reserve(length); // unicode marker - result[0] = '\xfe'; - result[1] = '\xff'; + result.push_back('\xfe'); + result.push_back('\xff'); // convert to utf16 - for (int i = 2, j = 0; i < (*length); i += 2, j++) { - Unicode u = pdfDocEncoding[(unsigned int)((unsigned char)cstring[j])] & 0xffff; - result[i] = (u >> 8) & 0xff; - result[i + 1] = u & 0xff; + for (int i = 2, j = 0; i < (length); i += 2, j++) { + Unicode u = pdfDocEncoding[(unsigned int)((unsigned char)orig[j])] & 0xffff; + result.push_back((u >> 8) & 0xff); + result.push_back(u & 0xff); } return result; } -static GooString *convertToUtf16(GooString *pdfDocEncodingString) +static std::unique_ptr convertToUtf16(GooString *pdfDocEncodingString) { - int tmp_length; - char *tmp_str = pdfDocEncodingToUTF16(pdfDocEncodingString->toStr(), &tmp_length); - delete pdfDocEncodingString; - pdfDocEncodingString = new GooString(tmp_str + 2, tmp_length - 2); // Remove the unicode BOM - delete[] tmp_str; - return pdfDocEncodingString; + std::string tmpStr = pdfDocEncodingToUTF16(pdfDocEncodingString->toStr()); + return std::make_unique(tmpStr.c_str() + 2, tmpStr.size() - 2); // Remove the unicode BOM } FormWidget::FormWidget(PDFDoc *docA, Object *aobj, unsigned num, Ref aref, FormField *fieldA) @@ -207,7 +203,7 @@ const GooString *FormWidget::getMappingName() const return field->getMappingName(); } -GooString *FormWidget::getFullyQualifiedName() +const GooString *FormWidget::getFullyQualifiedName() { return field->getFullyQualifiedName(); } @@ -1113,11 +1109,7 @@ void FormField::setPartialName(const GooString &name) xref->setModifiedObject(&obj, ref); } -FormField::~FormField() -{ - - delete fullyQualifiedName; -} +FormField::~FormField() = default; void FormField::print(int indent) { @@ -1202,17 +1194,17 @@ FormWidget *FormField::findWidgetByRef(Ref aref) return nullptr; } -GooString *FormField::getFullyQualifiedName() +const GooString *FormField::getFullyQualifiedName() const { Object parentObj; const GooString *parent_name; bool unicode_encoded = false; if (fullyQualifiedName) { - return fullyQualifiedName; + return fullyQualifiedName.get(); } - fullyQualifiedName = new GooString(); + fullyQualifiedName = std::make_unique(); std::set parsedRefs; Ref parentRef; @@ -1230,16 +1222,14 @@ GooString *FormField::getFullyQualifiedName() if (hasUnicodeByteOrderMark(parent_name->toStr())) { fullyQualifiedName->insert(0, parent_name->c_str() + 2, parent_name->getLength() - 2); // Remove the unicode BOM } else { - int tmp_length; - char *tmp_str = pdfDocEncodingToUTF16(parent_name->toStr(), &tmp_length); - fullyQualifiedName->insert(0, tmp_str + 2, tmp_length - 2); // Remove the unicode BOM - delete[] tmp_str; + std::string tmp_str = pdfDocEncodingToUTF16(parent_name->toStr()); + fullyQualifiedName->insert(0, tmp_str.c_str() + 2, tmp_str.size() - 2); // Remove the unicode BOM } } else { fullyQualifiedName->insert(0, '.'); // 1-byte ascii period if (hasUnicodeByteOrderMark(parent_name->toStr())) { unicode_encoded = true; - fullyQualifiedName = convertToUtf16(fullyQualifiedName); + fullyQualifiedName = convertToUtf16(fullyQualifiedName.get()); fullyQualifiedName->insert(0, parent_name->c_str() + 2, parent_name->getLength() - 2); // Remove the unicode BOM } else { fullyQualifiedName->insert(0, parent_name); @@ -1249,7 +1239,7 @@ GooString *FormField::getFullyQualifiedName() parentObj = parentObj.getDict()->lookup("Parent", &parentRef); if (parentRef != Ref::INVALID() && !parsedRefs.insert(parentRef.num).second) { error(errSyntaxError, -1, "FormField: Loop while trying to look for Parents"); - return fullyQualifiedName; + return fullyQualifiedName.get(); } } @@ -1258,15 +1248,13 @@ GooString *FormField::getFullyQualifiedName() if (hasUnicodeByteOrderMark(partialName->toStr())) { fullyQualifiedName->append(partialName->c_str() + 2, partialName->getLength() - 2); // Remove the unicode BOM } else { - int tmp_length; - char *tmp_str = pdfDocEncodingToUTF16(partialName->toStr(), &tmp_length); - fullyQualifiedName->append(tmp_str + 2, tmp_length - 2); // Remove the unicode BOM - delete[] tmp_str; + std::string tmp_str = pdfDocEncodingToUTF16(partialName->toStr()); + fullyQualifiedName->append(tmp_str.c_str() + 2, tmp_str.size() - 2); // Remove the unicode BOM } } else { if (hasUnicodeByteOrderMark(partialName->toStr())) { unicode_encoded = true; - fullyQualifiedName = convertToUtf16(fullyQualifiedName); + fullyQualifiedName = convertToUtf16(fullyQualifiedName.get()); fullyQualifiedName->append(partialName->c_str() + 2, partialName->getLength() - 2); // Remove the unicode BOM } else { fullyQualifiedName->append(partialName.get()); @@ -1290,7 +1278,7 @@ GooString *FormField::getFullyQualifiedName() prependUnicodeByteOrderMark(fullyQualifiedName->toNonConstStr()); } - return fullyQualifiedName; + return fullyQualifiedName.get(); } void FormField::updateChildrenAppearance() @@ -1658,16 +1646,13 @@ void FormFieldText::fillContent(FillValueType fillType) } } else if (obj1.getString()->getLength() > 0) { // non-unicode string -- assume pdfDocEncoding and try to convert to UTF16BE - int tmp_length; - char *tmp_str = pdfDocEncodingToUTF16(obj1.getString()->toStr(), &tmp_length); + std::string tmp_str = pdfDocEncodingToUTF16(obj1.getString()->toStr()); if (fillType == fillDefaultValue) { - defaultContent = std::make_unique(tmp_str, tmp_length); + defaultContent = std::make_unique(std::move(tmp_str)); } else { - content = std::make_unique(tmp_str, tmp_length); + content = std::make_unique(std::move(tmp_str)); } - - delete[] tmp_str; } } } diff --git a/poppler/Form.h b/poppler/Form.h index 6e5728165..dc124dd32 100644 --- a/poppler/Form.h +++ b/poppler/Form.h @@ -125,7 +125,7 @@ class POPPLER_PRIVATE_EXPORT FormWidget void setPartialName(const GooString &name); const GooString *getAlternateUiName() const; const GooString *getMappingName() const; - GooString *getFullyQualifiedName(); + const GooString *getFullyQualifiedName(); bool isModified() const; @@ -375,7 +375,7 @@ class POPPLER_PRIVATE_EXPORT FormField void setPartialName(const GooString &name); const GooString *getAlternateUiName() const { return alternateUiName.get(); } const GooString *getMappingName() const { return mappingName.get(); } - GooString *getFullyQualifiedName(); + const GooString *getFullyQualifiedName() const; FormWidget *findWidgetByRef(Ref aref); int getNumWidgets() const { return terminal ? widgets.size() : 0; } @@ -418,7 +418,7 @@ class POPPLER_PRIVATE_EXPORT FormField std::unique_ptr partialName; // T field std::unique_ptr alternateUiName; // TU field std::unique_ptr mappingName; // TM field - GooString *fullyQualifiedName; + mutable std::unique_ptr fullyQualifiedName; // Variable Text std::unique_ptr defaultAppearance; diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index 4e269100e..b675fa7a8 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -49,6 +49,7 @@ // Copyright (C) 2023 Anton Thomasson // Copyright (C) 2024 Nelson Benítez León // Copyright (C) 2024 Athul Raj Kollareth +// Copyright (C) 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git diff --git a/poppler/GlobalParams.cc b/poppler/GlobalParams.cc index 013f2c2bf..7f67c3904 100644 --- a/poppler/GlobalParams.cc +++ b/poppler/GlobalParams.cc @@ -46,7 +46,7 @@ // Copyright (C) 2021 sunderme // Copyright (C) 2022 Even Rouault // Copyright (C) 2022 Claes Nästén -// Copyright (C) 2023, 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela +// Copyright (C) 2023-2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // Copyright (C) 2023 Shivodit Gill // Copyright (C) 2024 Keyu Tao // @@ -61,6 +61,7 @@ #include #include #include +#include #ifdef _WIN32 # include # include @@ -71,10 +72,8 @@ # include #endif #include "goo/glibc.h" -#include "goo/gmem.h" #include "goo/GooString.h" #include "goo/gfile.h" -#include "goo/gdir.h" #include "Error.h" #include "NameToCharCode.h" #include "CharCodeToUnicode.h" @@ -409,7 +408,7 @@ const SysFontInfo *SysFontList::find(const std::string &name, bool fixedWidth, b // parsing //------------------------------------------------------------------------ -GlobalParams::GlobalParams(const char *customPopplerDataDir) : popplerDataDir(customPopplerDataDir) +GlobalParams::GlobalParams(const std::string &customPopplerDataDir) : popplerDataDir(customPopplerDataDir) { // scan the encoding in reverse because we want the lowest-numbered // index for each char name ('space' is encoded twice) @@ -466,49 +465,30 @@ GlobalParams::GlobalParams(const char *customPopplerDataDir) : popplerDataDir(cu void GlobalParams::scanEncodingDirs() { - GDir *dir; - std::unique_ptr entry; - const char *dataRoot = popplerDataDir ? popplerDataDir : POPPLER_DATADIR; + std::string dataRoot = !popplerDataDir.empty() ? popplerDataDir : std::string { POPPLER_DATADIR }; - // allocate buffer large enough to append "/nameToUnicode" - size_t bufSize = strlen(dataRoot) + strlen("/nameToUnicode") + 1; - char *dataPathBuffer = new char[bufSize]; - - snprintf(dataPathBuffer, bufSize, "%s/nameToUnicode", dataRoot); - dir = new GDir(dataPathBuffer, true); - while (entry = dir->getNextEntry(), entry != nullptr) { - if (!entry->isDir()) { - parseNameToUnicode(entry->getFullPath()); + std::error_code ec; // if ec is set, we also get the end iterator, so that's kind of okay. If not creating with a error code, we get an exception if poppler data is missing + for (const auto &entry : std::filesystem::directory_iterator { dataRoot + "/nameToUnicode", ec }) { + if (entry.is_regular_file()) { + parseNameToUnicode(entry.path()); } } - delete dir; - snprintf(dataPathBuffer, bufSize, "%s/cidToUnicode", dataRoot); - dir = new GDir(dataPathBuffer, false); - while (entry = dir->getNextEntry(), entry != nullptr) { - addCIDToUnicode(entry->getName(), entry->getFullPath()); + for (const auto &entry : std::filesystem::directory_iterator { dataRoot + "/cidToUnicode", ec }) { + addCIDToUnicode(entry.path().filename().string(), entry.path().string()); } - delete dir; - snprintf(dataPathBuffer, bufSize, "%s/unicodeMap", dataRoot); - dir = new GDir(dataPathBuffer, false); - while (entry = dir->getNextEntry(), entry != nullptr) { - addUnicodeMap(entry->getName(), entry->getFullPath()); + for (const auto &entry : std::filesystem::directory_iterator { dataRoot + "/unicodeMap", ec }) { + addUnicodeMap(entry.path().filename().string(), entry.path().string()); } - delete dir; - snprintf(dataPathBuffer, bufSize, "%s/cMap", dataRoot); - dir = new GDir(dataPathBuffer, false); - while (entry = dir->getNextEntry(), entry != nullptr) { - addCMapDir(entry->getName(), entry->getFullPath()); - toUnicodeDirs.push_back(entry->getFullPath()->copy()); + for (const auto &entry : std::filesystem::directory_iterator { dataRoot + "/cMap", ec }) { + addCMapDir(entry.path().filename().string(), entry.path().string()); + toUnicodeDirs.push_back(entry.path().string()); } - delete dir; - - delete[] dataPathBuffer; } -void GlobalParams::parseNameToUnicode(const GooString *name) +void GlobalParams::parseNameToUnicode(const std::filesystem::path &name) { char *tok1, *tok2; FILE *f; @@ -517,8 +497,8 @@ void GlobalParams::parseNameToUnicode(const GooString *name) Unicode u; char *tokptr; - if (!(f = openFile(name->c_str(), "r"))) { - error(errIO, -1, "Couldn't open 'nameToUnicode' file '{0:t}'", name); + if (!(f = openFile(name.string().c_str(), "r"))) { + error(errIO, -1, "Couldn't open 'nameToUnicode' file '{0:s}'", name.string().c_str()); return; } line = 1; @@ -529,26 +509,26 @@ void GlobalParams::parseNameToUnicode(const GooString *name) sscanf(tok1, "%x", &u); nameToUnicodeText->add(tok2, u); } else { - error(errConfig, -1, "Bad line in 'nameToUnicode' file ({0:t}:{1:d})", name, line); + error(errConfig, -1, "Bad line in 'nameToUnicode' file ({0:s}:{1:d})", name.string().c_str(), line); } ++line; } fclose(f); } -void GlobalParams::addCIDToUnicode(const GooString *collection, const GooString *fileName) +void GlobalParams::addCIDToUnicode(std::string &&collection, std::string &&fileName) { - cidToUnicodes[collection->toStr()] = fileName->toStr(); + cidToUnicodes[collection] = fileName; } -void GlobalParams::addUnicodeMap(const GooString *encodingName, const GooString *fileName) +void GlobalParams::addUnicodeMap(std::string &&encodingName, std::string &&fileName) { - unicodeMaps[encodingName->toStr()] = fileName->toStr(); + unicodeMaps[encodingName] = fileName; } -void GlobalParams::addCMapDir(const GooString *collection, const GooString *dir) +void GlobalParams::addCMapDir(std::string &&collection, std::string &&dir) { - cMapDirs.emplace(collection->toStr(), dir->toStr()); + cMapDirs.emplace(collection, dir); } bool GlobalParams::parseYesNo2(const char *token, bool *flag) @@ -653,8 +633,8 @@ FILE *GlobalParams::findToUnicodeFile(const GooString *name) FILE *f; globalParamsLocker(); - for (const std::unique_ptr &dir : toUnicodeDirs) { - fileName = appendToPath(dir->copy().release(), name->c_str()); + for (const std::string &dir : toUnicodeDirs) { + fileName = appendToPath(new GooString(dir), name->c_str()); f = openFile(fileName->c_str(), "r"); delete fileName; if (f) { @@ -1561,7 +1541,7 @@ GlobalParamsIniter::GlobalParamsIniter(ErrorCallback errorCallback) const std::scoped_lock lock { mutex }; if (count == 0) { - globalParams = std::make_unique(!customDataDir.empty() ? customDataDir.c_str() : nullptr); + globalParams = std::make_unique(customDataDir); setErrorCallback(errorCallback); } diff --git a/poppler/GlobalParams.h b/poppler/GlobalParams.h index 06964642d..3bd9d7b63 100644 --- a/poppler/GlobalParams.h +++ b/poppler/GlobalParams.h @@ -29,7 +29,7 @@ // Copyright (C) 2018, 2020 Adam Reichold // Copyright (C) 2019 Oliver Sander // Copyright (C) 2023 Shivodit Gill -// Copyright (C) 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela +// Copyright (C) 2024, 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -52,6 +52,7 @@ #include #include #include +#include class GooString; class NameToCharCode; @@ -112,7 +113,7 @@ class POPPLER_PRIVATE_EXPORT GlobalParams { public: // Initialize the global parameters - explicit GlobalParams(const char *customPopplerDataDir = nullptr); + explicit GlobalParams(const std::string &customPopplerDataDir = {}); ~GlobalParams(); @@ -168,12 +169,12 @@ class POPPLER_PRIVATE_EXPORT GlobalParams static bool parseYesNo2(const char *token, bool *flag); private: - void parseNameToUnicode(const GooString *name); + void parseNameToUnicode(const std::filesystem::path &name); void scanEncodingDirs(); - void addCIDToUnicode(const GooString *collection, const GooString *fileName); - void addUnicodeMap(const GooString *encodingName, const GooString *fileName); - void addCMapDir(const GooString *collection, const GooString *dir); + void addCIDToUnicode(std::string &&collection, std::string &&fileName); + void addUnicodeMap(std::string &&encodingName, std::string &&fileName); + void addCMapDir(std::string &&collection, std::string &&dir); //----- static tables @@ -197,7 +198,7 @@ class POPPLER_PRIVATE_EXPORT GlobalParams std::unordered_map unicodeMaps; // list of CMap dirs, indexed by collection std::unordered_multimap cMapDirs; - std::vector> toUnicodeDirs; // list of ToUnicode CMap dirs + std::vector toUnicodeDirs; // list of ToUnicode CMap dirs bool baseFontsInitialized; #ifdef _WIN32 // windows font substitutes (for CID fonts) @@ -223,7 +224,7 @@ class POPPLER_PRIVATE_EXPORT GlobalParams mutable std::recursive_mutex unicodeMapCacheMutex; mutable std::recursive_mutex cMapCacheMutex; - const char *popplerDataDir; + std::string popplerDataDir; }; class POPPLER_PRIVATE_EXPORT GlobalParamsIniter diff --git a/poppler/GlobalParamsWin.cc b/poppler/GlobalParamsWin.cc index 9c77fa454..63ca37332 100644 --- a/poppler/GlobalParamsWin.cc +++ b/poppler/GlobalParamsWin.cc @@ -15,6 +15,7 @@ // Copyright (C) 2019 Oliver Sander // Copyright (C) 2021 Stefan Löffler // Copyright (C) 2021 sunderme + // Copyright (C) 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela TODO: instead of a fixed mapping defined in displayFontTab, it could scan the whole fonts directory, parse TTF files and build font @@ -377,7 +378,7 @@ void GlobalParams::setupBaseFonts(const char *dir) sysFonts->scanWindowsFonts(winFontDir); } - const char *dataRoot = popplerDataDir ? popplerDataDir : POPPLER_DATADIR; + std::string dataRoot = !popplerDataDir.empty() ? popplerDataDir : std::string { POPPLER_DATADIR }; const std::string fileName = std::string(dataRoot).append("/cidfmap"); // try to open file diff --git a/poppler/LocalPDFDocBuilder.cc b/poppler/LocalPDFDocBuilder.cc index 31801b8d5..72b277b35 100644 --- a/poppler/LocalPDFDocBuilder.cc +++ b/poppler/LocalPDFDocBuilder.cc @@ -7,6 +7,7 @@ // Copyright 2010 Hib Eris // Copyright 2010, 2022, 2024 Albert Astals Cid // Copyright 2021 Oliver Sander +// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // //======================================================================== diff --git a/poppler/LocalPDFDocBuilder.h b/poppler/LocalPDFDocBuilder.h index f58f046ba..9d3c4427c 100644 --- a/poppler/LocalPDFDocBuilder.h +++ b/poppler/LocalPDFDocBuilder.h @@ -7,6 +7,7 @@ // Copyright 2010 Hib Eris // Copyright 2010, 2018, 2022 Albert Astals Cid // Copyright 2021 Oliver Sander +// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // //======================================================================== diff --git a/poppler/NSSCryptoSignBackend.cc b/poppler/NSSCryptoSignBackend.cc index efe5e9071..dac270f73 100644 --- a/poppler/NSSCryptoSignBackend.cc +++ b/poppler/NSSCryptoSignBackend.cc @@ -18,7 +18,7 @@ // Copyright 2021 Marek Kasik // Copyright 2022 Erich E. Hoover // Copyright 2023 Tobias Deiminger -// Copyright 2023, 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela +// Copyright 2023-2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // Copyright 2023 Ingo Klöcker // //======================================================================== @@ -27,11 +27,11 @@ #include "CryptoSignBackend.h" #include "NSSCryptoSignBackend.h" -#include "goo/gdir.h" #include "goo/gmem.h" #include #include +#include #include @@ -693,11 +693,10 @@ static std::optional getDefaultFirefoxCertDB() const std::string firefoxPath = std::string(env) + "/.mozilla/firefox/"; #endif - GDir firefoxDir(firefoxPath.c_str()); - std::unique_ptr entry; - while (entry = firefoxDir.getNextEntry(), entry != nullptr) { - if (entry->isDir() && entry->getName()->toStr().find("default") != std::string::npos) { - return entry->getFullPath()->toStr(); + std::error_code ec; // ensures directory_iterator doesn't throw exceptions + for (const auto &entry : std::filesystem::directory_iterator { firefoxPath, ec }) { + if (entry.is_directory() && entry.path().string().find("default") != std::string::npos) { + return entry.path().string(); } } return {}; diff --git a/poppler/OptionalContent.cc b/poppler/OptionalContent.cc index b337a5f3b..174c23627 100644 --- a/poppler/OptionalContent.cc +++ b/poppler/OptionalContent.cc @@ -9,6 +9,7 @@ // Copyright 2008 Mark Kaplan // Copyright 2018 Adam Reichold // Copyright 2019 Oliver Sander +// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // // Released under the GPL (version 2, or later, at your option) // diff --git a/poppler/OptionalContent.h b/poppler/OptionalContent.h index 0e3ddc7fa..0767560e5 100644 --- a/poppler/OptionalContent.h +++ b/poppler/OptionalContent.h @@ -7,6 +7,7 @@ // Copyright 2013, 2018, 2019, 2021 Albert Astals Cid // Copyright 2018 Adam Reichold // Copyright 2019 Oliver Sander +// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // // Released under the GPL (version 2, or later, at your option) // diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index 6f94ac2b7..5e2de9c91 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -147,9 +147,9 @@ PDFDoc::PDFDoc(std::unique_ptr &&fileNameA, const std::optionalc_str()); + std::u16string u16fileName = utf8ToUtf16(fileName->toStr()); + wchar_t *wFileName = (wchar_t *)u16fileName.data(); file = GooFile::open(wFileName); - gfree(wFileName); #else file = GooFile::open(fileName->toStr()); #endif diff --git a/poppler/PDFDocBuilder.h b/poppler/PDFDocBuilder.h index b9cff7310..43988e32d 100644 --- a/poppler/PDFDocBuilder.h +++ b/poppler/PDFDocBuilder.h @@ -7,6 +7,7 @@ // Copyright 2010 Hib Eris // Copyright 2010, 2018, 2020, 2022 Albert Astals Cid // Copyright 2021 Oliver Sander +// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // //======================================================================== diff --git a/poppler/PDFDocEncoding.h b/poppler/PDFDocEncoding.h index 01f381589..c121d227e 100644 --- a/poppler/PDFDocEncoding.h +++ b/poppler/PDFDocEncoding.h @@ -34,6 +34,6 @@ class GooString; extern const Unicode POPPLER_PRIVATE_EXPORT pdfDocEncoding[256]; -char POPPLER_PRIVATE_EXPORT *pdfDocEncodingToUTF16(const std::string &orig, int *length); +std::string POPPLER_PRIVATE_EXPORT pdfDocEncodingToUTF16(const std::string &orig); #endif diff --git a/poppler/PDFDocFactory.cc b/poppler/PDFDocFactory.cc index 9bf7978d3..1acdde37d 100644 --- a/poppler/PDFDocFactory.cc +++ b/poppler/PDFDocFactory.cc @@ -10,6 +10,7 @@ // Copyright 2018 Adam Reichold // Copyright 2019, 2021 Oliver Sander // Copyright 2021 Christian Persch +// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // //======================================================================== diff --git a/poppler/PDFDocFactory.h b/poppler/PDFDocFactory.h index 20a0dcce5..9e70b01d2 100644 --- a/poppler/PDFDocFactory.h +++ b/poppler/PDFDocFactory.h @@ -7,6 +7,7 @@ // Copyright 2010 Hib Eris // Copyright 2010, 2018, 2021, 2022 Albert Astals Cid // Copyright 2019, 2021 Oliver Sander +// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // //======================================================================== diff --git a/poppler/Page.cc b/poppler/Page.cc index d2a4e5a23..917f7cebc 100644 --- a/poppler/Page.cc +++ b/poppler/Page.cc @@ -34,7 +34,7 @@ // Copyright (C) 2020, 2021 Nelson Benítez León // Copyright (C) 2020 Philipp Knechtges // Copyright (C) 2024 Pablo Correa Gómez -// Copyright (C) 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela +// Copyright (C) 2024, 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git diff --git a/poppler/Page.h b/poppler/Page.h index 7faf1bd17..b2ff8e097 100644 --- a/poppler/Page.h +++ b/poppler/Page.h @@ -27,7 +27,7 @@ // Copyright (C) 2020 Oliver Sander // Copyright (C) 2020, 2021 Nelson Benítez León // Copyright (C) 2024 Pablo Correa Gómez -// Copyright (C) 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela +// Copyright (C) 2024, 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git diff --git a/poppler/UTF.cc b/poppler/UTF.cc index 38fb0a28e..7e99a3891 100644 --- a/poppler/UTF.cc +++ b/poppler/UTF.cc @@ -21,7 +21,7 @@ // Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, . Work sponsored by the LiMux project of the city of Munich // Copyright (C) 2018, 2020 Nelson Benítez León // Copyright (C) 2021 Georgiy Sgibnev . Work sponsored by lab50.net. -// Copyright (C) 2023, 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela +// Copyright (C) 2023-2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // Copyright (C) 2023 Even Rouault // Copyright (C) 2023, 2024 Oliver Sander // @@ -207,67 +207,42 @@ inline uint32_t decodeUtf8(uint32_t *state, uint32_t *codep, char byte) return *state; } -int utf8CountUCS4(const char *utf8) +std::vector utf8ToUCS4(std::string_view utf8) { uint32_t codepoint; uint32_t state = 0; - int count = 0; - - while (*utf8) { - decodeUtf8(&state, &codepoint, *utf8); - if (state == UTF8_ACCEPT) { - count++; - } else if (state == UTF8_REJECT) { - count++; // replace with REPLACEMENT_CHAR - state = 0; - } - utf8++; - } - if (state != UTF8_ACCEPT && state != UTF8_REJECT) { - count++; // replace with REPLACEMENT_CHAR - } - - return count; -} -int utf8ToUCS4(const char *utf8, Unicode **ucs4_out) -{ - int len = utf8CountUCS4(utf8); - Unicode *u = (Unicode *)gmallocn(len, sizeof(Unicode)); - int n = 0; - uint32_t codepoint; - uint32_t state = 0; + std::vector u; - while (*utf8 && n < len) { - decodeUtf8(&state, &codepoint, *utf8); + for (auto c : utf8) { + decodeUtf8(&state, &codepoint, c); if (state == UTF8_ACCEPT) { - u[n++] = codepoint; + u.push_back(codepoint); } else if (state == UTF8_REJECT) { - u[n++] = REPLACEMENT_CHAR; // invalid byte for this position + u.push_back(REPLACEMENT_CHAR); // invalid byte for this position state = 0; } - utf8++; } if (state != UTF8_ACCEPT && state != UTF8_REJECT) { - u[n] = REPLACEMENT_CHAR; // invalid byte for this position + u.push_back(REPLACEMENT_CHAR); // invalid byte for this position } + u.shrink_to_fit(); - *ucs4_out = u; - return len; + return u; } // Count number of UTF-16 code units required to convert a UTF-8 string // (excluding terminating NULL). Each invalid byte is counted as a // code point since the UTF-8 conversion functions will replace it with // REPLACEMENT_CHAR. -int utf8CountUtf16CodeUnits(const char *utf8) +int utf8CountUtf16CodeUnits(std::string_view utf8) { uint32_t codepoint; uint32_t state = 0; int count = 0; - while (*utf8) { - decodeUtf8(&state, &codepoint, *utf8); + for (auto c : utf8) { + decodeUtf8(&state, &codepoint, c); if (state == UTF8_ACCEPT) { if (codepoint < 0x10000) { count++; @@ -280,7 +255,6 @@ int utf8CountUtf16CodeUnits(const char *utf8) count++; // replace with REPLACEMENT_CHAR state = 0; } - utf8++; } if (state != UTF8_ACCEPT && state != UTF8_REJECT) { count++; // replace with REPLACEMENT_CHAR @@ -289,78 +263,52 @@ int utf8CountUtf16CodeUnits(const char *utf8) return count; } -int utf8ToUtf16(const char *utf8, int maxUtf8, uint16_t *utf16, int maxUtf16) +std::u16string utf8ToUtf16(std::string_view utf8) { - uint16_t *p = utf16; uint32_t codepoint; uint32_t state = 0; - int nIn = 0; - int nOut = 0; - while (*utf8 && nIn < maxUtf8 && nOut < maxUtf16 - 1) { - decodeUtf8(&state, &codepoint, *utf8); + if (isUtf8WithBom(utf8)) { + utf8 = utf8.substr(3); + } + std::u16string utf16; + for (auto c : utf8) { + decodeUtf8(&state, &codepoint, c); if (state == UTF8_ACCEPT) { if (codepoint < 0x10000) { - *p++ = (uint16_t)codepoint; - nOut++; + utf16.push_back((uint16_t)codepoint); } else if (codepoint <= UCS4_MAX) { - *p++ = (uint16_t)(0xD7C0 + (codepoint >> 10)); - *p++ = (uint16_t)(0xDC00 + (codepoint & 0x3FF)); - nOut += 2; + utf16.push_back((uint16_t)(0xD7C0 + (codepoint >> 10))); + utf16.push_back((uint16_t)(0xDC00 + (codepoint & 0x3FF))); } else { - *p++ = REPLACEMENT_CHAR; - nOut++; + utf16.push_back(REPLACEMENT_CHAR); state = 0; } } else if (state == UTF8_REJECT) { - *p++ = REPLACEMENT_CHAR; // invalid byte for this position - nOut++; + utf16.push_back(REPLACEMENT_CHAR); // invalid byte for this position } - utf8++; - nIn++; } // replace any trailing bytes too short for a valid UTF-8 with a replacement char - if (state != UTF8_ACCEPT && state != UTF8_REJECT && nOut < maxUtf16 - 1) { - *p++ = REPLACEMENT_CHAR; - nOut++; - } - if (nOut > maxUtf16 - 1) { - nOut = maxUtf16 - 1; - } - utf16[nOut] = 0; - return nOut; -} - -// Allocate utf16 string and convert utf8 into it. -uint16_t *utf8ToUtf16(const char *utf8, int *len) -{ - if (isUtf8WithBom(utf8)) { - utf8 += 3; - } - int n = utf8CountUtf16CodeUnits(utf8); - if (len) { - *len = n; + if (state != UTF8_ACCEPT && state != UTF8_REJECT) { + utf16.push_back(REPLACEMENT_CHAR); } - uint16_t *utf16 = (uint16_t *)gmallocn(n + 1, sizeof(uint16_t)); - utf8ToUtf16(utf8, INT_MAX, utf16, n + 1); return utf16; } -std::string utf8ToUtf16WithBom(const std::string &utf8) +std::string utf8ToUtf16WithBom(std::string_view utf8) { if (utf8.empty()) { return {}; } - int tmp_length; // Number of UTF-16 symbols. - char *tmp_str = (char *)utf8ToUtf16(utf8.c_str(), &tmp_length); + std::u16string utf16 = utf8ToUtf16(utf8); + char *tmp_str = (char *)utf16.data(); #ifndef WORDS_BIGENDIAN - for (int i = 0; i < tmp_length; i++) { + for (size_t i = 0; i < utf16.size(); i++) { std::swap(tmp_str[i * 2], tmp_str[i * 2 + 1]); } #endif std::string result(unicodeByteOrderMark); - result.append(tmp_str, tmp_length * 2); - gfree(tmp_str); + result.append(tmp_str, utf16.size() * 2); return result; } diff --git a/poppler/UTF.h b/poppler/UTF.h index 4486560fa..1eb2d50d7 100644 --- a/poppler/UTF.h +++ b/poppler/UTF.h @@ -10,7 +10,7 @@ // Copyright (C) 2018 Nelson Benítez León // Copyright (C) 2019-2022, 2024 Albert Astals Cid // Copyright (C) 2021 Georgiy Sgibnev . Work sponsored by lab50.net. -// Copyright (C) 2023, 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela +// Copyright (C) 2023-2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // Copyright (C) 2023 Even Rouault // Copyright (C) 2023, 2024 Oliver Sander // @@ -79,34 +79,23 @@ inline bool hasUnicodeByteOrderMarkAndLengthIsEven(const std::string &s) // is a unicode whitespace character bool UnicodeIsWhitespace(Unicode ucs4); -// Count number of UCS-4 characters required to convert a UTF-8 string to -// UCS-4 (excluding terminating NULL). -int POPPLER_PRIVATE_EXPORT utf8CountUCS4(const char *utf8); - // Convert a UTF-8 string to a UCS-4 // utf8 - utf8 bytes // ucs4_out - if not NULL, allocates and returns UCS-4 string. Free with gfree. // returns number of UCS-4 characters -int POPPLER_PRIVATE_EXPORT utf8ToUCS4(const char *utf8, Unicode **ucs4_out); +std::vector POPPLER_PRIVATE_EXPORT utf8ToUCS4(std::string_view utf8); // Count number of UTF-16 code units required to convert a UTF-8 string // (excluding terminating NULL). Each invalid byte is counted as a // code point since the UTF-8 conversion functions will replace it with // REPLACEMENT_CHAR. -int POPPLER_PRIVATE_EXPORT utf8CountUtf16CodeUnits(const char *utf8); +int POPPLER_PRIVATE_EXPORT utf8CountUtf16CodeUnits(std::string_view utf8); // Convert UTF-8 to UTF-16 // utf8 - UTF-8 string to convert. If not null terminated, ensure // maxUtf8 is set the the exact number of bytes to convert. -// maxUtf8 - Maximum number of UTF-8 bytes to convert. Conversion stops when -// either this count is reached or a null is encountered. -// utf16 - Output buffer to write UTF-16 to. Output will always be null terminated. -// maxUtf16 - Maximum size of output buffer including space for null. -// Returns number of UTF-16 code units written (excluding NULL). -int POPPLER_PRIVATE_EXPORT utf8ToUtf16(const char *utf8, int maxUtf8, uint16_t *utf16, int maxUtf16); - -// Allocate utf16 string and convert utf8 into it. -uint16_t POPPLER_PRIVATE_EXPORT *utf8ToUtf16(const char *utf8, int *len = nullptr); +// Returns utf16 string +std::u16string POPPLER_PRIVATE_EXPORT utf8ToUtf16(std::string_view utf8); inline bool isUtf8WithBom(std::string_view str) { @@ -123,7 +112,7 @@ inline bool isUtf8WithBom(std::string_view str) // The caller owns the returned pointer. // utf8 - UTF-8 string to convert. An empty string is acceptable. // Returns a big endian UTF-16 string with BOM or an empty string without BOM. -std::string POPPLER_PRIVATE_EXPORT utf8ToUtf16WithBom(const std::string &utf8); +std::string POPPLER_PRIVATE_EXPORT utf8ToUtf16WithBom(std::string_view utf8); // Count number of UTF-8 bytes required to convert a UTF-16 string to // UTF-8 (excluding terminating NULL). diff --git a/qt5/src/poppler-form.cc b/qt5/src/poppler-form.cc index c367c1eeb..bf3a6037b 100644 --- a/qt5/src/poppler-form.cc +++ b/qt5/src/poppler-form.cc @@ -167,7 +167,7 @@ void FormField::setName(const QString &name) const QString FormField::fullyQualifiedName() const { QString name; - if (GooString *goo = m_formData->fm->getFullyQualifiedName()) { + if (const GooString *goo = m_formData->fm->getFullyQualifiedName()) { name = UnicodeParsedString(goo); } return name; diff --git a/qt5/src/poppler-optcontent-private.h b/qt5/src/poppler-optcontent-private.h index de08f8f63..0b1046d06 100644 --- a/qt5/src/poppler-optcontent-private.h +++ b/qt5/src/poppler-optcontent-private.h @@ -4,6 +4,7 @@ * Copyright (C) 2008, Pino Toscano * Copyright (C) 2016, 2018, 2019, 2021, Albert Astals Cid * Copyright (C) 2017, Hubert Figuière + * Copyright (C) 2025, g10 Code GmbH, Author: Sune Stolborg Vuorela * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/qt5/src/poppler-optcontent.cc b/qt5/src/poppler-optcontent.cc index 82946669f..91b3e2d3b 100644 --- a/qt5/src/poppler-optcontent.cc +++ b/qt5/src/poppler-optcontent.cc @@ -8,6 +8,7 @@ * Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, . Work sponsored by the LiMux project of the city of Munich * Copyright (C) 2018 Adam Reichold * Copyright (C) 2019, 2020 Oliver Sander + * Copyright (C) 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/qt5/src/poppler-optcontent.h b/qt5/src/poppler-optcontent.h index a886a8876..017303761 100644 --- a/qt5/src/poppler-optcontent.h +++ b/qt5/src/poppler-optcontent.h @@ -4,6 +4,7 @@ * Copyright (C) 2008, Pino Toscano * Copyright (C) 2013, Anthony Granger * Copyright (C) 2016, 2021, Albert Astals Cid + * Copyright (C) 2025, g10 Code GmbH, Author: Sune Stolborg Vuorela * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/qt5/src/poppler-private.cc b/qt5/src/poppler-private.cc index 2a47811dc..c26dd35ca 100644 --- a/qt5/src/poppler-private.cc +++ b/qt5/src/poppler-private.cc @@ -125,10 +125,8 @@ QString UnicodeParsedString(const std::string &s1) if (hasUnicodeByteOrderMark(s1) || hasUnicodeByteOrderMarkLE(s1)) { return QString::fromUtf16(reinterpret_cast(s1.c_str()), s1.size() / 2); } else { - int stringLength; - const char *cString = pdfDocEncodingToUTF16(s1, &stringLength); - auto result = QString::fromUtf16(reinterpret_cast(cString), stringLength / 2); - delete[] cString; + std::string cString = pdfDocEncodingToUTF16(s1); + auto result = QString::fromUtf16(reinterpret_cast(cString.c_str()), cString.size() / 2); return result; } } diff --git a/qt5/tests/check_utf_conversion.cpp b/qt5/tests/check_utf_conversion.cpp index 05ef519e5..99efc4898 100644 --- a/qt5/tests/check_utf_conversion.cpp +++ b/qt5/tests/check_utf_conversion.cpp @@ -22,21 +22,6 @@ private slots: void testUnicodeLittleEndian(); }; -static bool compare(const char *a, const char *b) -{ - return strcmp(a, b) == 0; -} - -static bool compare(const uint16_t *a, const uint16_t *b) -{ - while (*a && *b) { - if (*a++ != *b++) { - return false; - } - } - return *a == *b; -} - static bool compare(const Unicode *a, const char *b, int len) { for (int i = 0; i < len; i++) { @@ -80,43 +65,35 @@ void TestUTFConversion::testUTF_data() void TestUTFConversion::testUTF() { std::string utf8String; - uint16_t utf16Buf[1000]; - uint16_t *utf16String; int len; QFETCH(QString, s); - QByteArray str = s.toUtf8(); + const std::string str = s.toStdString(); // UTF-8 to UTF-16 len = utf8CountUtf16CodeUnits(str); QCOMPARE(len, s.size()); // QString size() returns number of code units, not code points - Q_ASSERT(len < (int)sizeof(utf16Buf)); // if this fails, make utf16Buf larger - len = utf8ToUtf16(str, INT_MAX, utf16Buf, sizeof(utf16Buf)); - QVERIFY(compare(utf16Buf, s.utf16())); + std::u16string utf16String = utf8ToUtf16(str); + QCOMPARE(utf16String, s.toStdU16String()); QCOMPARE(len, s.size()); - utf16String = utf8ToUtf16(str); - QVERIFY(compare(utf16String, s.utf16())); - free(utf16String); - - std::string sUtf8(str); - std::string gsUtf16_a(utf8ToUtf16WithBom(sUtf8)); + std::string gsUtf16_a(utf8ToUtf16WithBom(str)); std::unique_ptr gsUtf16_b(Poppler::QStringToUnicodeGooString(s)); QCOMPARE(gsUtf16_b->cmp(gsUtf16_a), 0); // UTF-16 to UTF-8 len = utf16CountUtf8Bytes(s.utf16()); - QCOMPARE(len, (int)strlen(str)); + QCOMPARE(len, str.size()); utf8String = utf16ToUtf8(s.utf16(), INT_MAX); - QVERIFY(compare(utf8String.c_str(), str)); - QCOMPARE(len, (int)strlen(str)); + QCOMPARE(utf8String, str); + QCOMPARE(len, str.size()); utf8String = utf16ToUtf8(s.utf16()); - QVERIFY(compare(utf8String.c_str(), str)); + QCOMPARE(utf8String, str); } void TestUTFConversion::testUnicodeToAscii7() diff --git a/qt6/src/poppler-form.cc b/qt6/src/poppler-form.cc index 8f920afa3..8f4687302 100644 --- a/qt6/src/poppler-form.cc +++ b/qt6/src/poppler-form.cc @@ -167,7 +167,7 @@ void FormField::setName(const QString &name) const QString FormField::fullyQualifiedName() const { QString name; - if (GooString *goo = m_formData->fm->getFullyQualifiedName()) { + if (const GooString *goo = m_formData->fm->getFullyQualifiedName()) { name = UnicodeParsedString(goo); } return name; diff --git a/qt6/src/poppler-optcontent-private.h b/qt6/src/poppler-optcontent-private.h index de08f8f63..0b1046d06 100644 --- a/qt6/src/poppler-optcontent-private.h +++ b/qt6/src/poppler-optcontent-private.h @@ -4,6 +4,7 @@ * Copyright (C) 2008, Pino Toscano * Copyright (C) 2016, 2018, 2019, 2021, Albert Astals Cid * Copyright (C) 2017, Hubert Figuière + * Copyright (C) 2025, g10 Code GmbH, Author: Sune Stolborg Vuorela * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/qt6/src/poppler-optcontent.cc b/qt6/src/poppler-optcontent.cc index 16975606f..08acc0915 100644 --- a/qt6/src/poppler-optcontent.cc +++ b/qt6/src/poppler-optcontent.cc @@ -8,6 +8,7 @@ * Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, . Work sponsored by the LiMux project of the city of Munich * Copyright (C) 2018 Adam Reichold * Copyright (C) 2019, 2020 Oliver Sander + * Copyright (C) 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/qt6/src/poppler-optcontent.h b/qt6/src/poppler-optcontent.h index 25336ca2d..8e4334f60 100644 --- a/qt6/src/poppler-optcontent.h +++ b/qt6/src/poppler-optcontent.h @@ -4,6 +4,7 @@ * Copyright (C) 2008, Pino Toscano * Copyright (C) 2013, Anthony Granger * Copyright (C) 2016, 2021, Albert Astals Cid + * Copyright (C) 2025, g10 Code GmbH, Author: Sune Stolborg Vuorela * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/qt6/src/poppler-private.cc b/qt6/src/poppler-private.cc index 9eddd961e..4ed3a3fef 100644 --- a/qt6/src/poppler-private.cc +++ b/qt6/src/poppler-private.cc @@ -125,10 +125,8 @@ QString UnicodeParsedString(const std::string &s1) if (hasUnicodeByteOrderMark(s1) || hasUnicodeByteOrderMarkLE(s1)) { return QString::fromUtf16(reinterpret_cast(s1.c_str()), s1.size() / 2); } else { - int stringLength; - const char *cString = pdfDocEncodingToUTF16(s1, &stringLength); - auto result = QString::fromUtf16(reinterpret_cast(cString), stringLength / 2); - delete[] cString; + std::string cString = pdfDocEncodingToUTF16(s1); + auto result = QString::fromUtf16(reinterpret_cast(cString.c_str()), cString.size() / 2); return result; } } diff --git a/qt6/tests/check_utf_conversion.cpp b/qt6/tests/check_utf_conversion.cpp index 53fe4bec3..831f002ee 100644 --- a/qt6/tests/check_utf_conversion.cpp +++ b/qt6/tests/check_utf_conversion.cpp @@ -21,21 +21,6 @@ private slots: void testUnicodeLittleEndian(); }; -static bool compare(const char *a, const char *b) -{ - return strcmp(a, b) == 0; -} - -static bool compare(const uint16_t *a, const uint16_t *b) -{ - while (*a && *b) { - if (*a++ != *b++) { - return false; - } - } - return *a == *b; -} - static bool compare(const Unicode *a, const char *b, int len) { for (int i = 0; i < len; i++) { @@ -78,43 +63,35 @@ void TestUTFConversion::testUTF_data() void TestUTFConversion::testUTF() { std::string utf8String; - uint16_t utf16Buf[1000]; - uint16_t *utf16String; int len; QFETCH(QString, s); - QByteArray str = s.toUtf8().constData(); + const std::string str = s.toStdString(); // UTF-8 to UTF-16 len = utf8CountUtf16CodeUnits(str); QCOMPARE(len, s.size()); // QString size() returns number of code units, not code points - Q_ASSERT(len < (int)sizeof(utf16Buf)); // if this fails, make utf16Buf larger - len = utf8ToUtf16(str, INT_MAX, utf16Buf, sizeof(utf16Buf)); - QVERIFY(compare(utf16Buf, s.utf16())); + std::u16string utf16String = utf8ToUtf16(str); + QCOMPARE(utf16String, s.toStdU16String()); QCOMPARE(len, s.size()); - utf16String = utf8ToUtf16(str); - QVERIFY(compare(utf16String, s.utf16())); - free(utf16String); - - std::string sUtf8(str); - std::string gsUtf16_a(utf8ToUtf16WithBom(sUtf8)); + std::string gsUtf16_a(utf8ToUtf16WithBom(str)); std::unique_ptr gsUtf16_b(Poppler::QStringToUnicodeGooString(s)); QCOMPARE(gsUtf16_b->cmp(gsUtf16_a), 0); // UTF-16 to UTF-8 len = utf16CountUtf8Bytes(s.utf16()); - QCOMPARE(len, (int)strlen(str)); + QCOMPARE(len, str.size()); utf8String = utf16ToUtf8(s.utf16(), INT_MAX); - QVERIFY(compare(utf8String.c_str(), str)); - QCOMPARE(len, (int)strlen(str)); + QCOMPARE(utf8String, str); + QCOMPARE(len, str.size()); utf8String = utf16ToUtf8(s.utf16()); - QVERIFY(compare(utf8String.c_str(), str)); + QCOMPARE(utf8String, str); } void TestUTFConversion::testUnicodeToAscii7() diff --git a/utils/Win32Console.cc b/utils/Win32Console.cc index 181d3bb70..69a6c3f85 100644 --- a/utils/Win32Console.cc +++ b/utils/Win32Console.cc @@ -5,6 +5,7 @@ // This file is licensed under the GPLv2 or later // // Copyright (C) 2017, 2024 Adrian Johnson +// Copyright (C) 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -25,7 +26,6 @@ static const int BUF_SIZE = 4096; static int bufLen = 0; static char buf[BUF_SIZE]; -static wchar_t wbuf[BUF_SIZE]; static bool stdoutIsConsole = true; static bool stderrIsConsole = true; static HANDLE consoleHandle = nullptr; @@ -49,8 +49,8 @@ static void flush(bool all = false) } if (nchars > 0) { - DWORD wlen = utf8ToUtf16(buf, nchars, (uint16_t *)wbuf, BUF_SIZE); - WriteConsoleW(consoleHandle, wbuf, wlen, &wlen, nullptr); + std::u16string u16string = utf8ToUtf16(std::string_view { buf, nchars }); + WriteConsoleW(consoleHandle, u16string.data(), u16string.size(), nullptr, nullptr); if (nchars < bufLen) { memmove(buf, buf + nchars, bufLen - nchars); bufLen -= nchars; @@ -133,7 +133,6 @@ Win32Console::Win32Console(int *argc, char **argv[]) bufLen = 0; buf[0] = 0; - wbuf[0] = 0; // check if stdout or stderr redirected // GetFileType() returns CHAR for console and special devices COMx, PRN, CON, NUL etc diff --git a/utils/pdfinfo.cc b/utils/pdfinfo.cc index 2a26a38da..41cf098d6 100644 --- a/utils/pdfinfo.cc +++ b/utils/pdfinfo.cc @@ -129,11 +129,11 @@ static void printTextString(const GooString *s, const UnicodeMap *uMap) printStdTextString(s->toStr(), uMap); } -static void printUCS4String(const Unicode *u, int len, const UnicodeMap *uMap) +static void printUCS4String(const std::vector &u, const UnicodeMap *uMap) { char buf[8]; - for (int i = 0; i < len; i++) { - int n = uMap->mapUnicode(u[i], buf, sizeof(buf)); + for (auto i : u) { + int n = uMap->mapUnicode(i, buf, sizeof(buf)); fwrite(buf, 1, n, stdout); } } @@ -701,15 +701,12 @@ static void printCustomInfo(PDFDoc *doc, const UnicodeMap *uMap) Object obj = dict->lookup(key.c_str()); if (obj.isString()) { // print key - Unicode *u; - int len = utf8ToUCS4(key.c_str(), &u); - printUCS4String(u, len, uMap); + std::vector u = utf8ToUCS4(key); + printUCS4String(u, uMap); fputs(":", stdout); - while (len < 16) { + for (size_t i = u.size(); i < 16; i++) { fputs(" ", stdout); - len++; } - gfree(u); // print value GooString val_str(obj.getString());