|
|
3f5d08 |
From 44505cb397c46baa7dd4a0456f737f36e6d19ad0 Mon Sep 17 00:00:00 2001
|
|
|
3f5d08 |
From: Christian Persch <chpe@src.gnome.org>
|
|
|
3f5d08 |
Date: Tue, 1 Jan 2019 18:16:18 +0100
|
|
|
3f5d08 |
Subject: [PATCH] glib: Fix named destinations
|
|
|
3f5d08 |
MIME-Version: 1.0
|
|
|
3f5d08 |
Content-Type: text/plain; charset=UTF-8
|
|
|
3f5d08 |
Content-Transfer-Encoding: 8bit
|
|
|
3f5d08 |
|
|
|
3f5d08 |
Named destinations may be described by bytestrings, containing
|
|
|
3f5d08 |
embedded NULs and not being NUL terminated. That means they cannot
|
|
|
3f5d08 |
be exposed directly as char*.
|
|
|
3f5d08 |
|
|
|
3f5d08 |
The alternatives are to escape the string from the internal representation
|
|
|
3f5d08 |
when exposing it in the API (e.g. in PopplerDest.named_dest), or to
|
|
|
3f5d08 |
add parallel API exposing it as GString, or GBytes. This patch chooses
|
|
|
3f5d08 |
the first option, since the presence of these named destionations in the
|
|
|
3f5d08 |
public, not sealed, PopplerDest struct means that the second option would
|
|
|
3f5d08 |
need more API additions. The chosen option is simpler, and does not
|
|
|
3f5d08 |
need the API users to adapt unless they create the named dest strings
|
|
|
3f5d08 |
themselves, or consume them in ways other than calling poppler APIs.
|
|
|
3f5d08 |
|
|
|
3f5d08 |
The escaping scheme chosen simply replaces embedded NUL with "\0" and
|
|
|
3f5d08 |
escapes a literal backslash with "\\". This is a minimal ABI change in
|
|
|
3f5d08 |
that some strings that previously worked unchanged as destinations
|
|
|
3f5d08 |
(those containing backslash) now don't work, but on the other hand,
|
|
|
3f5d08 |
previously it was impossible to use any destinations containing embedded
|
|
|
3f5d08 |
NULs.
|
|
|
3f5d08 |
|
|
|
3f5d08 |
Add poppler_named_dest_{from,to}_bytestring() to perform that
|
|
|
3f5d08 |
conversion, and clarify the documentation for when you need them.
|
|
|
3f5d08 |
|
|
|
3f5d08 |
Based on a patch by José Aliste <jaliste@src.gnome.org>.
|
|
|
3f5d08 |
|
|
|
3f5d08 |
https://gitlab.freedesktop.org/poppler/poppler/issues/631
|
|
|
3f5d08 |
---
|
|
|
3f5d08 |
glib/demo/utils.c | 2 -
|
|
|
3f5d08 |
glib/poppler-action.cc | 5 +-
|
|
|
3f5d08 |
glib/poppler-action.h | 16 +++
|
|
|
3f5d08 |
glib/poppler-document.cc | 151 ++++++++++++++++++++++++----
|
|
|
3f5d08 |
glib/reference/poppler-sections.txt | 2 +
|
|
|
3f5d08 |
5 files changed, 154 insertions(+), 22 deletions(-)
|
|
|
3f5d08 |
|
|
|
3f5d08 |
diff --git a/glib/demo/utils.c b/glib/demo/utils.c
|
|
|
3f5d08 |
index 6bf61614..38bde147 100644
|
|
|
3f5d08 |
--- a/glib/demo/utils.c
|
|
|
3f5d08 |
+++ b/glib/demo/utils.c
|
|
|
3f5d08 |
@@ -151,8 +151,6 @@ pgd_action_view_add_destination (GtkWidget *action_view,
|
|
|
3f5d08 |
pgd_table_add_property (table, "Zoom:", str, row);
|
|
|
3f5d08 |
g_free (str);
|
|
|
3f5d08 |
} else {
|
|
|
3f5d08 |
- pgd_table_add_property (table, "Named Dest:", dest->named_dest, row);
|
|
|
3f5d08 |
-
|
|
|
3f5d08 |
if (document && !remote) {
|
|
|
3f5d08 |
PopplerDest *new_dest;
|
|
|
3f5d08 |
|
|
|
3f5d08 |
diff --git a/glib/poppler-action.cc b/glib/poppler-action.cc
|
|
|
3f5d08 |
index 9af67571..7e0bc031 100644
|
|
|
3f5d08 |
--- a/glib/poppler-action.cc
|
|
|
3f5d08 |
+++ b/glib/poppler-action.cc
|
|
|
3f5d08 |
@@ -328,7 +328,8 @@ dest_new_named (const GooString *named_dest)
|
|
|
3f5d08 |
}
|
|
|
3f5d08 |
|
|
|
3f5d08 |
dest->type = POPPLER_DEST_NAMED;
|
|
|
3f5d08 |
- dest->named_dest = g_strdup (named_dest->getCString ());
|
|
|
3f5d08 |
+ dest->named_dest = poppler_named_dest_from_bytestring((const guint8*)named_dest->getCString (),
|
|
|
3f5d08 |
+ named_dest->getLength ());
|
|
|
3f5d08 |
|
|
|
3f5d08 |
return dest;
|
|
|
3f5d08 |
}
|
|
|
3f5d08 |
diff --git a/glib/poppler-action.h b/glib/poppler-action.h
|
|
|
3f5d08 |
index 13468f79..93a026be 100644
|
|
|
3f5d08 |
--- a/glib/poppler-action.h
|
|
|
3f5d08 |
+++ b/glib/poppler-action.h
|
|
|
3f5d08 |
@@ -164,6 +164,14 @@ typedef struct _PopplerActionJavascript PopplerActionJavascript;
|
|
|
3f5d08 |
* @change_zoom: whether scale factor should be changed
|
|
|
3f5d08 |
*
|
|
|
3f5d08 |
* Data structure for holding a destination
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * Note that @named_dest is the string representation of the named
|
|
|
3f5d08 |
+ * destination. This is the right form to pass to poppler functions,
|
|
|
3f5d08 |
+ * e.g. poppler_document_find_dest(), but to get the destination as
|
|
|
3f5d08 |
+ * it appears in the PDF itself, you need to convert it to a bytestring
|
|
|
3f5d08 |
+ * with poppler_named_dest_to_bytestring() first.
|
|
|
3f5d08 |
+ * Also note that @named_dest does not have a defined encoding and
|
|
|
3f5d08 |
+ * is not in a form suitable to be displayed to the user.
|
|
|
3f5d08 |
*/
|
|
|
3f5d08 |
struct _PopplerDest
|
|
|
3f5d08 |
{
|
|
|
3f5d08 |
@@ -317,6 +325,12 @@ void poppler_dest_free (PopplerDest *dest);
|
|
|
3f5d08 |
void poppler_dest_free (PopplerDest *dest);
|
|
|
3f5d08 |
PopplerDest *poppler_dest_copy (PopplerDest *dest);
|
|
|
3f5d08 |
|
|
|
3f5d08 |
+char *poppler_named_dest_from_bytestring (const guint8 *data,
|
|
|
3f5d08 |
+ gsize length);
|
|
|
3f5d08 |
+
|
|
|
3f5d08 |
+guint8 *poppler_named_dest_to_bytestring (const char *named_dest,
|
|
|
3f5d08 |
+ gsize *length);
|
|
|
3f5d08 |
+
|
|
|
3f5d08 |
G_END_DECLS
|
|
|
3f5d08 |
|
|
|
3f5d08 |
#endif /* __POPPLER_GLIB_H__ */
|
|
|
3f5d08 |
diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
|
|
|
3f5d08 |
index a9b4103d..d97d1448 100644
|
|
|
3f5d08 |
--- a/glib/poppler-document.cc
|
|
|
3f5d08 |
+++ b/glib/poppler-document.cc
|
|
|
3f5d08 |
@@ -680,41 +680,154 @@ poppler_document_get_attachments (PopplerDocument *document)
|
|
|
3f5d08 |
return g_list_reverse (retval);
|
|
|
3f5d08 |
}
|
|
|
3f5d08 |
|
|
|
3f5d08 |
+/**
|
|
|
3f5d08 |
+ * poppler_named_dest_from_bytestring:
|
|
|
3f5d08 |
+ * @data: (array length=length): the bytestring data
|
|
|
3f5d08 |
+ * @length: the bytestring length
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * Converts a bytestring into a zero-terminated string suitable to
|
|
|
3f5d08 |
+ * pass to poppler_document_find_dest().
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * Note that the returned string has no defined encoding and is not
|
|
|
3f5d08 |
+ * suitable for display to the user.
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * The returned data must be freed using g_free().
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * Returns: (transfer full): the named dest
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * Since: 0.73
|
|
|
3f5d08 |
+ */
|
|
|
3f5d08 |
+char *
|
|
|
3f5d08 |
+poppler_named_dest_from_bytestring (const guint8 *data,
|
|
|
3f5d08 |
+ gsize length)
|
|
|
3f5d08 |
+{
|
|
|
3f5d08 |
+ const guint8 *p, *pend;
|
|
|
3f5d08 |
+ char *dest, *q;
|
|
|
3f5d08 |
+
|
|
|
3f5d08 |
+ g_return_val_if_fail (length != 0 || data != NULL, NULL);
|
|
|
3f5d08 |
+ /* Each source byte needs maximally 2 destination chars (\\ or \0) */
|
|
|
3f5d08 |
+ q = dest = (gchar *)g_malloc (length * 2 + 1);
|
|
|
3f5d08 |
+
|
|
|
3f5d08 |
+ pend = data + length;
|
|
|
3f5d08 |
+ for (p = data; p < pend; ++p) {
|
|
|
3f5d08 |
+ switch (*p) {
|
|
|
3f5d08 |
+ case '\0':
|
|
|
3f5d08 |
+ *q++ = '\\';
|
|
|
3f5d08 |
+ *q++ = '0';
|
|
|
3f5d08 |
+ break;
|
|
|
3f5d08 |
+ case '\\':
|
|
|
3f5d08 |
+ *q++ = '\\';
|
|
|
3f5d08 |
+ *q++ = '\\';
|
|
|
3f5d08 |
+ break;
|
|
|
3f5d08 |
+ default:
|
|
|
3f5d08 |
+ *q++ = *p;
|
|
|
3f5d08 |
+ break;
|
|
|
3f5d08 |
+ }
|
|
|
3f5d08 |
+ }
|
|
|
3f5d08 |
+
|
|
|
3f5d08 |
+ *q = 0; /* zero terminate */
|
|
|
3f5d08 |
+ return dest;
|
|
|
3f5d08 |
+}
|
|
|
3f5d08 |
+
|
|
|
3f5d08 |
+/**
|
|
|
3f5d08 |
+ * poppler_named_dest_to_bytestring:
|
|
|
3f5d08 |
+ * @name: the named dest string
|
|
|
3f5d08 |
+ * @length: (out): a location to store the length of the returned bytestring
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * Converts a named dest string (e.g. from #PopplerDest.named_dest) into a
|
|
|
3f5d08 |
+ * bytestring, inverting the transformation of
|
|
|
3f5d08 |
+ * poppler_named_dest_from_bytestring().
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * Note that the returned data is not zero terminated and may also
|
|
|
3f5d08 |
+ * contains embedded NUL bytes.
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * If @name is not a valid named dest string, returns %NULL.
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * The returned data must be freed using g_free().
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * Returns: (array length=length) (transfer full) (nullable): a new bytestring,
|
|
|
3f5d08 |
+ * or %NULL
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * Since: 0.73
|
|
|
3f5d08 |
+ */
|
|
|
3f5d08 |
+guint8 *
|
|
|
3f5d08 |
+poppler_named_dest_to_bytestring (const char *name,
|
|
|
3f5d08 |
+ gsize *length)
|
|
|
3f5d08 |
+{
|
|
|
3f5d08 |
+ const char *p;
|
|
|
3f5d08 |
+ guint8 *data, *q;
|
|
|
3f5d08 |
+ gsize len;
|
|
|
3f5d08 |
+
|
|
|
3f5d08 |
+ g_return_val_if_fail (name != NULL, NULL);
|
|
|
3f5d08 |
+ g_return_val_if_fail (length != NULL, NULL);
|
|
|
3f5d08 |
+
|
|
|
3f5d08 |
+ len = strlen (name);
|
|
|
3f5d08 |
+ q = data = (guint8*) g_malloc (len);
|
|
|
3f5d08 |
+ for (p = name; *p; ++p) {
|
|
|
3f5d08 |
+ if (*p == '\\') {
|
|
|
3f5d08 |
+ p++;
|
|
|
3f5d08 |
+ len--;
|
|
|
3f5d08 |
+ if (*p == '0')
|
|
|
3f5d08 |
+ *q++ = '\0';
|
|
|
3f5d08 |
+ else if (*p == '\\')
|
|
|
3f5d08 |
+ *q++ = '\\';
|
|
|
3f5d08 |
+ else
|
|
|
3f5d08 |
+ goto invalid;
|
|
|
3f5d08 |
+ } else {
|
|
|
3f5d08 |
+ *q++ = *p;
|
|
|
3f5d08 |
+ }
|
|
|
3f5d08 |
+ }
|
|
|
3f5d08 |
+
|
|
|
3f5d08 |
+ *length = len;
|
|
|
3f5d08 |
+ return data;
|
|
|
3f5d08 |
+
|
|
|
3f5d08 |
+invalid:
|
|
|
3f5d08 |
+ g_free(data);
|
|
|
3f5d08 |
+ *length = 0;
|
|
|
3f5d08 |
+ return NULL;
|
|
|
3f5d08 |
+}
|
|
|
3f5d08 |
+
|
|
|
3f5d08 |
/**
|
|
|
3f5d08 |
* poppler_document_find_dest:
|
|
|
3f5d08 |
* @document: A #PopplerDocument
|
|
|
3f5d08 |
* @link_name: a named destination
|
|
|
3f5d08 |
*
|
|
|
3f5d08 |
- * Finds named destination @link_name in @document
|
|
|
3f5d08 |
+ * Creates a #PopplerDest for the named destination @link_name in @document.
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * Note that named destinations are bytestrings, not string. That means that
|
|
|
3f5d08 |
+ * unless @link_name was returned by a poppler function (e.g. is
|
|
|
3f5d08 |
+ * #PopplerDest.named_dest), it needs to be converted to string
|
|
|
3f5d08 |
+ * using poppler_named_dest_from_bytestring() before being passed to this
|
|
|
3f5d08 |
+ * function.
|
|
|
3f5d08 |
*
|
|
|
3f5d08 |
- * Return value: The #PopplerDest destination or %NULL if
|
|
|
3f5d08 |
- * @link_name is not a destination. Returned value must
|
|
|
3f5d08 |
- * be freed with #poppler_dest_free
|
|
|
3f5d08 |
+ * The returned value must be freed with poppler_dest_free().
|
|
|
3f5d08 |
+ *
|
|
|
3f5d08 |
+ * Return value: (transfer full): a new #PopplerDest destination, or %NULL if
|
|
|
3f5d08 |
+ * @link_name is not a destination.
|
|
|
3f5d08 |
**/
|
|
|
3f5d08 |
PopplerDest *
|
|
|
3f5d08 |
poppler_document_find_dest (PopplerDocument *document,
|
|
|
3f5d08 |
const gchar *link_name)
|
|
|
3f5d08 |
{
|
|
|
3f5d08 |
- PopplerDest *dest = NULL;
|
|
|
3f5d08 |
- LinkDest *link_dest = NULL;
|
|
|
3f5d08 |
- GooString *g_link_name;
|
|
|
3f5d08 |
+ g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), NULL);
|
|
|
3f5d08 |
+ g_return_val_if_fail (link_name != NULL, NULL);
|
|
|
3f5d08 |
|
|
|
3f5d08 |
- g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), NULL);
|
|
|
3f5d08 |
- g_return_val_if_fail (link_name != NULL, NULL);
|
|
|
3f5d08 |
+ gsize len;
|
|
|
3f5d08 |
+ guint8* data = poppler_named_dest_to_bytestring (link_name, &len;;
|
|
|
3f5d08 |
+ if (data == NULL)
|
|
|
3f5d08 |
+ return NULL;
|
|
|
3f5d08 |
|
|
|
3f5d08 |
- g_link_name = new GooString (link_name);
|
|
|
3f5d08 |
+ GooString g_link_name ((const char*)data, (int)len);
|
|
|
3f5d08 |
+ g_free (data);
|
|
|
3f5d08 |
|
|
|
3f5d08 |
- if (g_link_name) {
|
|
|
3f5d08 |
- link_dest = document->doc->findDest (g_link_name);
|
|
|
3f5d08 |
- delete g_link_name;
|
|
|
3f5d08 |
- }
|
|
|
3f5d08 |
+ LinkDest *link_dest = document->doc->findDest (&g_link_name);
|
|
|
3f5d08 |
+ if (link_dest == NULL)
|
|
|
3f5d08 |
+ return NULL;
|
|
|
3f5d08 |
|
|
|
3f5d08 |
- if (link_dest) {
|
|
|
3f5d08 |
- dest = _poppler_dest_new_goto (document, link_dest);
|
|
|
3f5d08 |
- delete link_dest;
|
|
|
3f5d08 |
- }
|
|
|
3f5d08 |
+ PopplerDest *dest = _poppler_dest_new_goto (document, link_dest);
|
|
|
3f5d08 |
+ delete link_dest;
|
|
|
3f5d08 |
|
|
|
3f5d08 |
- return dest;
|
|
|
3f5d08 |
+ return dest;
|
|
|
3f5d08 |
}
|
|
|
3f5d08 |
|
|
|
3f5d08 |
char *_poppler_goo_string_to_utf8(GooString *s)
|
|
|
3f5d08 |
diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt
|
|
|
3f5d08 |
index 6c15f773..39985553 100644
|
|
|
3f5d08 |
--- a/glib/reference/poppler-sections.txt
|
|
|
3f5d08 |
+++ b/glib/reference/poppler-sections.txt
|
|
|
3f5d08 |
@@ -735,6 +735,8 @@ poppler_text_span_get_type
|
|
|
3f5d08 |
poppler_get_backend
|
|
|
3f5d08 |
poppler_get_version
|
|
|
3f5d08 |
poppler_date_parse
|
|
|
3f5d08 |
+poppler_named_dest_from_bytestring
|
|
|
3f5d08 |
+poppler_named_dest_to_bytestring
|
|
|
3f5d08 |
poppler_color_new
|
|
|
3f5d08 |
poppler_color_copy
|
|
|
3f5d08 |
poppler_color_free
|
|
|
3f5d08 |
--
|
|
|
3f5d08 |
2.26.2
|
|
|
3f5d08 |
|