mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-24 19:30:10 +01:00
pdf: ensure filenames are correctly encoded
This commit is contained in:
parent
a4d8eb98ba
commit
895b249b0a
4 changed files with 123 additions and 8 deletions
|
|
@ -437,6 +437,71 @@ cairo_pdf_interchange_write_dest (cairo_pdf_surface_t *surface,
|
|||
return status;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_utf8_to_pdf_utf8_hexstring (const char *utf8, char **str_out)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
unsigned char *p;
|
||||
cairo_bool_t ascii;
|
||||
char *str;
|
||||
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
|
||||
ascii = TRUE;
|
||||
p = (unsigned char *)utf8;
|
||||
len = 0;
|
||||
while (*p) {
|
||||
if (*p < 32 || *p > 126) {
|
||||
ascii = FALSE;
|
||||
}
|
||||
if (*p == '(' || *p == ')' || *p == '\\')
|
||||
len += 2;
|
||||
else
|
||||
len++;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (ascii) {
|
||||
str = _cairo_malloc (len + 3);
|
||||
if (str == NULL)
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
str[0] = '(';
|
||||
p = (unsigned char *)utf8;
|
||||
i = 1;
|
||||
while (*p) {
|
||||
if (*p == '(' || *p == ')' || *p == '\\')
|
||||
str[i++] = '\\';
|
||||
str[i++] = *p;
|
||||
p++;
|
||||
}
|
||||
str[i++] = ')';
|
||||
str[i++] = 0;
|
||||
} else {
|
||||
str = _cairo_malloc (len*2 + 3);
|
||||
if (str == NULL)
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
str[0] = '<';
|
||||
p = (unsigned char *)utf8;
|
||||
i = 1;
|
||||
while (*p) {
|
||||
if (*p == '\\') {
|
||||
snprintf(str + i, 3, "%02x", '\\');
|
||||
i += 2;
|
||||
}
|
||||
snprintf(str + i, 3, "%02x", *p);
|
||||
i += 2;
|
||||
p++;
|
||||
}
|
||||
str[i++] = '>';
|
||||
str[i++] = 0;
|
||||
}
|
||||
*str_out = str;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
cairo_pdf_interchange_write_link_action (cairo_pdf_surface_t *surface,
|
||||
cairo_link_attrs_t *link_attrs)
|
||||
|
|
@ -469,12 +534,42 @@ cairo_pdf_interchange_write_link_action (cairo_pdf_surface_t *surface,
|
|||
dest);
|
||||
free (dest);
|
||||
} else if (link_attrs->link_type == TAG_LINK_FILE) {
|
||||
/* According to "Developing with PDF", Leonard Rosenthol, 2013,
|
||||
* The F key is encoded in the "standard encoding for the
|
||||
* platform on which the document is being viewed. For most
|
||||
* modern operating systems, that's UTF-8"
|
||||
*
|
||||
* As we don't know the target platform, we assume UTF-8. The
|
||||
* F key may contain multi-byte encodings using the hex
|
||||
* encoding.
|
||||
*
|
||||
* For PDF 1.7 we also include the UF key which uses the
|
||||
* standard PDF UTF-16BE strings.
|
||||
*/
|
||||
status = _cairo_utf8_to_pdf_utf8_hexstring (link_attrs->file, &dest);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
_cairo_output_stream_printf (surface->object_stream.stream,
|
||||
" /A <<\n"
|
||||
" /Type /Action\n"
|
||||
" /S /GoToR\n"
|
||||
" /F (%s)\n",
|
||||
link_attrs->file);
|
||||
" /F %s\n",
|
||||
dest);
|
||||
free (dest);
|
||||
|
||||
if (surface->pdf_version >= CAIRO_PDF_VERSION_1_7)
|
||||
{
|
||||
status = _cairo_utf8_to_pdf_string (link_attrs->file, &dest);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
_cairo_output_stream_printf (surface->object_stream.stream,
|
||||
" /UF %s\n",
|
||||
dest);
|
||||
free (dest);
|
||||
}
|
||||
|
||||
if (link_attrs->dest) {
|
||||
status = _cairo_utf8_to_pdf_string (link_attrs->dest, &dest);
|
||||
if (unlikely (status))
|
||||
|
|
@ -487,13 +582,13 @@ cairo_pdf_interchange_write_link_action (cairo_pdf_surface_t *surface,
|
|||
} else {
|
||||
if (link_attrs->has_pos) {
|
||||
_cairo_output_stream_printf (surface->object_stream.stream,
|
||||
" /D [%d %f %f 0]\n",
|
||||
" /D [%d /XYZ %f %f 0]\n",
|
||||
link_attrs->page,
|
||||
link_attrs->pos.x,
|
||||
link_attrs->pos.y);
|
||||
} else {
|
||||
_cairo_output_stream_printf (surface->object_stream.stream,
|
||||
" /D [%d null null 0]\n",
|
||||
" /D [%d /XYZ null null 0]\n",
|
||||
link_attrs->page);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,7 +209,9 @@ _cairo_pdf_surface_get_extents (void *abstract_surface,
|
|||
static const cairo_pdf_version_t _cairo_pdf_versions[] =
|
||||
{
|
||||
CAIRO_PDF_VERSION_1_4,
|
||||
CAIRO_PDF_VERSION_1_5
|
||||
CAIRO_PDF_VERSION_1_5,
|
||||
CAIRO_PDF_VERSION_1_6,
|
||||
CAIRO_PDF_VERSION_1_7
|
||||
};
|
||||
|
||||
#define CAIRO_PDF_VERSION_LAST ARRAY_LENGTH (_cairo_pdf_versions)
|
||||
|
|
@ -218,6 +220,8 @@ static const char * _cairo_pdf_version_strings[CAIRO_PDF_VERSION_LAST] =
|
|||
{
|
||||
"PDF 1.4",
|
||||
"PDF 1.5"
|
||||
"PDF 1.6"
|
||||
"PDF 1.7"
|
||||
};
|
||||
|
||||
static const char *_cairo_pdf_supported_mime_types[] =
|
||||
|
|
@ -497,7 +501,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
|
|||
}
|
||||
|
||||
surface->struct_tree_root.id = 0;
|
||||
surface->pdf_version = CAIRO_PDF_VERSION_1_5;
|
||||
surface->pdf_version = CAIRO_PDF_VERSION_1_7;
|
||||
surface->compress_streams = TRUE;
|
||||
surface->pdf_stream.active = FALSE;
|
||||
surface->pdf_stream.old_output = NULL;
|
||||
|
|
@ -2635,10 +2639,16 @@ _cairo_pdf_surface_start_page (void *abstract_surface)
|
|||
case CAIRO_PDF_VERSION_1_4:
|
||||
version = "1.4";
|
||||
break;
|
||||
default:
|
||||
case CAIRO_PDF_VERSION_1_5:
|
||||
version = "1.5";
|
||||
break;
|
||||
case CAIRO_PDF_VERSION_1_6:
|
||||
version = "1.6";
|
||||
break;
|
||||
default:
|
||||
case CAIRO_PDF_VERSION_1_7:
|
||||
version = "1.7";
|
||||
break;
|
||||
}
|
||||
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ CAIRO_BEGIN_DECLS
|
|||
* cairo_pdf_version_t:
|
||||
* @CAIRO_PDF_VERSION_1_4: The version 1.4 of the PDF specification. (Since 1.10)
|
||||
* @CAIRO_PDF_VERSION_1_5: The version 1.5 of the PDF specification. (Since 1.10)
|
||||
* @CAIRO_PDF_VERSION_1_6: The version 1.6 of the PDF specification. (Since 1.18)
|
||||
* @CAIRO_PDF_VERSION_1_7: The version 1.7 of the PDF specification. (Since 1.18)
|
||||
*
|
||||
* #cairo_pdf_version_t is used to describe the version number of the PDF
|
||||
* specification that a generated PDF file will conform to.
|
||||
|
|
@ -55,7 +57,9 @@ CAIRO_BEGIN_DECLS
|
|||
**/
|
||||
typedef enum _cairo_pdf_version {
|
||||
CAIRO_PDF_VERSION_1_4,
|
||||
CAIRO_PDF_VERSION_1_5
|
||||
CAIRO_PDF_VERSION_1_5,
|
||||
CAIRO_PDF_VERSION_1_6,
|
||||
CAIRO_PDF_VERSION_1_7
|
||||
} cairo_pdf_version_t;
|
||||
|
||||
cairo_public cairo_surface_t *
|
||||
|
|
|
|||
|
|
@ -358,6 +358,12 @@ draw_cover (cairo_surface_t *surface, cairo_t *cr)
|
|||
cairo_show_text (cr, "link to page section 3.3");
|
||||
cairo_tag_end (cr, CAIRO_TAG_LINK);
|
||||
|
||||
/* Create link to external file */
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, "file='foo.pdf' page=1");
|
||||
cairo_move_to (cr, PAGE_WIDTH/3, 4.4*PAGE_HEIGHT/5);
|
||||
cairo_show_text (cr, "link file 'foo.pdf'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_LINK);
|
||||
|
||||
draw_page_num (surface, cr, "cover", 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue