Compare commits

..

No commits in common. "master" and "v1.5.1" have entirely different histories.

31 changed files with 965 additions and 3113 deletions

View File

@ -1,44 +1,6 @@
Changes in PDFio Changes in PDFio
================ ================
v1.6.0 - YYYY-MM-DD
-------------------
- Added generation of XMP metadata when writing PDFs (Issue #103)
- Added "standard" `PDFIO_CS_CGATS001` color space for non-device CMYK
(Issue #104)
- Added CMYK JPEG support with embedded ICC profiles or using the CGATS001
profile (Issue #104)
- Added `pdfioFileAddOutputIntent` function to adding output intent information
to a PDF file (Issue #104)
- Added `pdfioFileCreateFontObjFromData` function for embedding fonts in
memory (Issue #120)
- Added `pdfioFileGetLanguage` and `pdfioFileSetLanguage` functions for getting
and setting the default/primary language of a PDF file (Issue #124)
- Now add default grayscale, RGB, and CMYK profile resources to pages as needed
(Issue #104)
v1.5.3 - YYYY-MM-DD
-------------------
- Fixed decryption of PDF files "protected" by 40-bit RC4 (Issue #42)
- Fixed decryption of UTF-16 strings (Issue #42)
v1.5.2 - 2025-04-12
-------------------
- Updated maximum allowed PDF string size to 64k (Issue #117)
- Updated dictionary reading code to discard duplicate key/value pairs with a
warning message (Issue #118)
- Fixed form detection in `pdfioinfo` example code (Issue #114)
- Fixed parsing of certain date/time values (Issue #115)
- Fixed support for empty name values (Issue #116)
- Fixed range checking in `pdfioImageGetBytesPerLine` (Issue #121)
v1.5.1 - 2025-03-28 v1.5.1 - 2025-03-28
------------------- -------------------

203
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for pdfio 1.6.0. # Generated by GNU Autoconf 2.71 for pdfio 1.5.1.
# #
# Report bugs to <https://github.com/michaelrsweet/pdfio/issues>. # Report bugs to <https://github.com/michaelrsweet/pdfio/issues>.
# #
@ -610,8 +610,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='pdfio' PACKAGE_NAME='pdfio'
PACKAGE_TARNAME='pdfio' PACKAGE_TARNAME='pdfio'
PACKAGE_VERSION='1.6.0' PACKAGE_VERSION='1.5.1'
PACKAGE_STRING='pdfio 1.6.0' PACKAGE_STRING='pdfio 1.5.1'
PACKAGE_BUGREPORT='https://github.com/michaelrsweet/pdfio/issues' PACKAGE_BUGREPORT='https://github.com/michaelrsweet/pdfio/issues'
PACKAGE_URL='https://www.msweet.org/pdfio' PACKAGE_URL='https://www.msweet.org/pdfio'
@ -1295,7 +1295,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures pdfio 1.6.0 to adapt to many kinds of systems. \`configure' configures pdfio 1.5.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1361,7 +1361,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of pdfio 1.6.0:";; short | recursive ) echo "Configuration of pdfio 1.5.1:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1460,7 +1460,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
pdfio configure 1.6.0 pdfio configure 1.5.1
generated by GNU Autoconf 2.71 generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc. Copyright (C) 2021 Free Software Foundation, Inc.
@ -1513,6 +1513,39 @@ fi
} # ac_fn_c_try_compile } # ac_fn_c_try_compile
# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists and can be compiled using the include files in
# INCLUDES, setting the cache variable VAR accordingly.
ac_fn_c_check_header_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
printf %s "checking for $2... " >&6; }
if eval test \${$3+y}
then :
printf %s "(cached) " >&6
else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
eval "$3=yes"
else $as_nop
eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
eval ac_res=\$$3
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_header_compile
# ac_fn_c_try_link LINENO # ac_fn_c_try_link LINENO
# ----------------------- # -----------------------
# Try to link conftest.$ac_ext, and return whether this succeeded. # Try to link conftest.$ac_ext, and return whether this succeeded.
@ -1559,101 +1592,6 @@ fi
as_fn_set_status $ac_retval as_fn_set_status $ac_retval
} # ac_fn_c_try_link } # ac_fn_c_try_link
# ac_fn_c_check_func LINENO FUNC VAR
# ----------------------------------
# Tests whether FUNC exists, setting the cache variable VAR accordingly
ac_fn_c_check_func ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
printf %s "checking for $2... " >&6; }
if eval test \${$3+y}
then :
printf %s "(cached) " >&6
else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
For example, HP-UX 11i <limits.h> declares gettimeofday. */
#define $2 innocuous_$2
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $2 (); below. */
#include <limits.h>
#undef $2
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char $2 ();
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined __stub_$2 || defined __stub___$2
choke me
#endif
int
main (void)
{
return $2 ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"
then :
eval "$3=yes"
else $as_nop
eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
eval ac_res=\$$3
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_func
# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists and can be compiled using the include files in
# INCLUDES, setting the cache variable VAR accordingly.
ac_fn_c_check_header_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
printf %s "checking for $2... " >&6; }
if eval test \${$3+y}
then :
printf %s "(cached) " >&6
else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
eval "$3=yes"
else $as_nop
eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
eval ac_res=\$$3
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_header_compile
ac_configure_args_raw= ac_configure_args_raw=
for ac_arg for ac_arg
do do
@ -1678,7 +1616,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by pdfio $as_me 1.6.0, which was It was created by pdfio $as_me 1.5.1, which was
generated by GNU Autoconf 2.71. Invocation command line was generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw $ $0$ac_configure_args_raw
@ -2434,9 +2372,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
PDFIO_VERSION="1.6.0" PDFIO_VERSION="1.5.1"
PDFIO_VERSION_MAJOR="`echo 1.6.0 | awk -F. '{print $1}'`" PDFIO_VERSION_MAJOR="`echo 1.5.1 | awk -F. '{print $1}'`"
PDFIO_VERSION_MINOR="`echo 1.6.0 | awk -F. '{printf("%d\n",$2);}'`" PDFIO_VERSION_MINOR="`echo 1.5.1 | awk -F. '{printf("%d\n",$2);}'`"
@ -3939,56 +3877,6 @@ INSTALL="$(pwd)/install-sh"
printf "%s\n" "using $INSTALL" >&6; } printf "%s\n" "using $INSTALL" >&6; }
ac_fn_c_check_func "$LINENO" "timegm" "ac_cv_func_timegm"
if test "x$ac_cv_func_timegm" = xyes
then :
printf "%s\n" "#define HAVE_TIMEGM 1" >>confdefs.h
CPPFLAGS="-DHAVE_TIMEGM=1 $CPPFLAGS"
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tm_gmtoff member in tm structure" >&5
printf %s "checking for tm_gmtoff member in tm structure... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <time.h>
int
main (void)
{
struct tm t;
int o = t.tm_gmtoff;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
printf "%s\n" "#define HAVE_TM_GMTOFF 1" >>confdefs.h
CPPFLAGS="-DHAVE_TM_GMTOFF=1 $CPPFLAGS"
else $as_nop
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
if test -n "$ac_tool_prefix"; then if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
@ -4110,6 +3998,7 @@ PKGCONFIG_REQUIRES="zlib"
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib via pkg-config" >&5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib via pkg-config" >&5
printf %s "checking for zlib via pkg-config... " >&6; } printf %s "checking for zlib via pkg-config... " >&6; }
ac_header= ac_cache= ac_header= ac_cache=
for ac_item in $ac_header_c_list for ac_item in $ac_header_c_list
do do
@ -5099,7 +4988,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by pdfio $as_me 1.6.0, which was This file was extended by pdfio $as_me 1.5.1, which was
generated by GNU Autoconf 2.71. Invocation command line was generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -5155,7 +5044,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped' ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\ ac_cs_version="\\
pdfio config.status 1.6.0 pdfio config.status 1.5.1
configured by $0, generated by GNU Autoconf 2.71, configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@ -21,7 +21,7 @@ AC_PREREQ([2.70])
dnl Package name and version... dnl Package name and version...
AC_INIT([pdfio], [1.6.0], [https://github.com/michaelrsweet/pdfio/issues], [pdfio], [https://www.msweet.org/pdfio]) AC_INIT([pdfio], [1.5.1], [https://github.com/michaelrsweet/pdfio/issues], [pdfio], [https://www.msweet.org/pdfio])
PDFIO_VERSION="AC_PACKAGE_VERSION" PDFIO_VERSION="AC_PACKAGE_VERSION"
PDFIO_VERSION_MAJOR="`echo AC_PACKAGE_VERSION | awk -F. '{print $1}'`" PDFIO_VERSION_MAJOR="`echo AC_PACKAGE_VERSION | awk -F. '{print $1}'`"
@ -88,27 +88,6 @@ AC_SUBST([INSTALL])
AC_MSG_RESULT([using $INSTALL]) AC_MSG_RESULT([using $INSTALL])
dnl Check for date/time functionality...
AC_CHECK_FUNC([timegm], [
AC_DEFINE([HAVE_TIMEGM], [1], [Do we have the timegm function?])
CPPFLAGS="-DHAVE_TIMEGM=1 $CPPFLAGS"
])
AC_MSG_CHECKING([for tm_gmtoff member in tm structure])
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([[#include <time.h>]], [[
struct tm t;
int o = t.tm_gmtoff;
]])
], [
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_TM_GMTOFF], [1], [Have tm_gmtoff member in struct tm?])
CPPFLAGS="-DHAVE_TM_GMTOFF=1 $CPPFLAGS"
], [
AC_MSG_RESULT([no])
])
dnl Check for pkg-config, which is used for some other tests later on... dnl Check for pkg-config, which is used for some other tests later on...
AC_PATH_TOOL([PKGCONFIG], [pkg-config]) AC_PATH_TOOL([PKGCONFIG], [pkg-config])

View File

@ -1,4 +1,4 @@
.TH pdfio 3 "pdf read/write library" "2025-04-13" "pdf read/write library" .TH pdfio 3 "pdf read/write library" "2025-03-06" "pdf read/write library"
.SH NAME .SH NAME
pdfio \- pdf read/write library pdfio \- pdf read/write library
.SH Introduction .SH Introduction
@ -1047,26 +1047,11 @@ The pdfioinfo.c example program opens a PDF file and prints the title, author, c
{ {
const char *filename; // PDF filename const char *filename; // PDF filename
pdfio_file_t *pdf; // PDF file pdfio_file_t *pdf; // PDF file
pdfio_dict_t *catalog; // Catalog dictionary const char *author; // Author name
const char *author, // Author name time_t creation_date; // Creation date
*creator, // Creator name struct tm *creation_tm; // Creation date/time information
*producer, // Producer name char creation_text[256]; // Creation date/time as a string
*title; // Title const char *title; // Title
time_t creation_date, // Creation date
modification_date; // Modification date
struct tm *creation_tm, // Creation date/time information
*modification_tm; // Modification date/time information
char creation_text[256], // Creation date/time as a string
modification_text[256], // Modification date/time human fmt string
range_text[255]; // Page range text
size_t num_pages; // PDF number of pages
bool has_acroform; // Does the file have an AcroForm?
pdfio_obj_t *page; // Object
pdfio_dict_t *page_dict; // Object dictionary
size_t cur, // Current page index
prev; // Previous page index
pdfio_rect_t cur_box, // Current MediaBox
prev_box; // Previous MediaBox
// Get the filename from the command\-line... // Get the filename from the command\-line...
@ -1079,19 +1064,13 @@ The pdfioinfo.c example program opens a PDF file and prints the title, author, c
filename = argv[1]; filename = argv[1];
// Open the PDF file with the default callbacks... // Open the PDF file with the default callbacks...
pdf = pdfioFileOpen(filename, /*password_cb*/NULL, pdf = pdfioFileOpen(filename, /*password_cb*/NULL, /*password_cbdata*/NULL,
/*password_cbdata*/NULL, /*error_cb*/NULL, /*error_cb*/NULL, /*error_cbdata*/NULL);
/*error_cbdata*/NULL);
if (pdf == NULL) if (pdf == NULL)
return (1); return (1);
// Get the title, author, etc... // Get the title and author...
catalog = pdfioFileGetCatalog(pdf);
author = pdfioFileGetAuthor(pdf); author = pdfioFileGetAuthor(pdf);
creator = pdfioFileGetCreator(pdf);
has_acroform = pdfioDictGetType(catalog, "AcroForm") != PDFIO_VALTYPE_NONE;
num_pages = pdfioFileGetNumPages(pdf);
producer = pdfioFileGetProducer(pdf);
title = pdfioFileGetTitle(pdf); title = pdfioFileGetTitle(pdf);
// Get the creation date and convert to a string... // Get the creation date and convert to a string...
@ -1105,76 +1084,12 @@ The pdfioinfo.c example program opens a PDF file and prints the title, author, c
snprintf(creation_text, sizeof(creation_text), "\-\- not set \-\-"); snprintf(creation_text, sizeof(creation_text), "\-\- not set \-\-");
} }
// Get the modification date and convert to a string...
if ((modification_date = pdfioFileGetModificationDate(pdf)) > 0)
{
modification_tm = localtime(&modification_date);
strftime(modification_text, sizeof(modification_text), "%c", modification_tm);
}
else
{
snprintf(modification_text, sizeof(modification_text), "\-\- not set \-\-");
}
// Print file information to stdout... // Print file information to stdout...
printf("%s:\\n", filename); printf("%s:\\n", filename);
printf(" Title: %s\\n", title ? title : "\-\- not set \-\-"); printf(" Title: %s\\n", title ? title : "\-\- not set \-\-");
printf(" Author: %s\\n", author ? author : "\-\- not set \-\-"); printf(" Author: %s\\n", author ? author : "\-\- not set \-\-");
printf(" Creator: %s\\n", creator ? creator : "\-\- not set \-\-");
printf(" Producer: %s\\n", producer ? producer : "\-\- not set \-\-");
printf(" Created On: %s\\n", creation_text); printf(" Created On: %s\\n", creation_text);
printf(" Modified On: %s\\n", modification_text); printf(" Number Pages: %u\\n", (unsigned)pdfioFileGetNumPages(pdf));
printf(" Version: %s\\n", pdfioFileGetVersion(pdf));
printf(" AcroForm: %s\\n", has_acroform ? "Yes" : "No");
printf(" Number of Pages: %u\\n", (unsigned)num_pages);
// Report the MediaBox for all of the pages
prev_box.x1 = prev_box.x2 = prev_box.y1 = prev_box.y2 = 0.0;
for (cur = 0, prev = 0; cur < num_pages; cur ++)
{
// Find the MediaBox for this page in the page tree...
for (page = pdfioFileGetPage(pdf, cur);
page != NULL;
page = pdfioDictGetObj(page_dict, "Parent"))
{
cur_box.x1 = cur_box.x2 = cur_box.y1 = cur_box.y2 = 0.0;
page_dict = pdfioObjGetDict(page);
if (pdfioDictGetRect(page_dict, "MediaBox", &cur_box))
break;
}
// If this MediaBox is different from the previous one, show the range of
// pages that have that size...
if (cur == 0 ||
fabs(cur_box.x1 \- prev_box.x1) > 0.01 ||
fabs(cur_box.y1 \- prev_box.y1) > 0.01 ||
fabs(cur_box.x2 \- prev_box.x2) > 0.01 ||
fabs(cur_box.y2 \- prev_box.y2) > 0.01)
{
if (cur > prev)
{
snprintf(range_text, sizeof(range_text), "Pages %u\-%u",
(unsigned)(prev + 1), (unsigned)cur);
printf("%16s: [%g %g %g %g]\\n", range_text,
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
}
// Start a new series of pages with the new size...
prev = cur;
prev_box = cur_box;
}
}
// Show the last range as needed...
if (cur > prev)
{
snprintf(range_text, sizeof(range_text), "Pages %u\-%u",
(unsigned)(prev + 1), (unsigned)cur);
printf("%16s: [%g %g %g %g]\\n", range_text,
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
}
// Close the PDF file... // Close the PDF file...
pdfioFileClose(pdf); pdfioFileClose(pdf);
@ -2449,10 +2364,6 @@ PDFIO_CS_ADOBE
.br .br
AdobeRGB 1998 AdobeRGB 1998
.TP 5 .TP 5
PDFIO_CS_CGATS001
.br
CGATS001 (CMYK)
.TP 5
PDFIO_CS_P3_D65 PDFIO_CS_P3_D65
.br .br
Display P3 Display P3
@ -2481,7 +2392,7 @@ PDFIO_ENCRYPTION_RC4_128
.TP 5 .TP 5
PDFIO_ENCRYPTION_RC4_40 PDFIO_ENCRYPTION_RC4_40
.br .br
40-bit RC4 encryption (PDF 1.3, reading only) 40-bit RC4 encryption (PDF 1.3)
.SS pdfio_filter_e .SS pdfio_filter_e
Compression/decompression filters for streams Compression/decompression filters for streams
.TP 5 .TP 5
@ -2842,8 +2753,7 @@ pdfio_array_t * pdfioArrayCreateColorFromStandard (
.fi .fi
.PP .PP
This function creates a color array for a standard \fBPDFIO_CS_\fR enumerated color space. This function creates a color array for a standard \fBPDFIO_CS_\fR enumerated color space.
The "num_colors" argument must be \fB1\fR for grayscale, \fB3\fR for RGB color, and The "num_colors" argument must be \fB1\fR for grayscale and \fB3\fR for RGB color.
\fB4\fR for CMYK color.
.SS pdfioArrayGetArray .SS pdfioArrayGetArray
Get an array value from an array. Get an array value from an array.
.PP .PP
@ -2952,8 +2862,6 @@ bool pdfioArrayRemove (
size_t n size_t n
); );
.fi .fi
.PP
.SS pdfioContentClip .SS pdfioContentClip
Clip output to the current path. Clip output to the current path.
.PP .PP
@ -3090,8 +2998,6 @@ bool pdfioContentPathEnd (
pdfio_stream_t *st pdfio_stream_t *st
); );
.fi .fi
.PP
.SS pdfioContentPathLineTo .SS pdfioContentPathLineTo
Add a straight line to the current path. Add a straight line to the current path.
.PP .PP
@ -3432,8 +3338,6 @@ double pdfioContentTextMeasure (
This function measures the given text string "s" and returns its width based This function measures the given text string "s" and returns its width based
on "size". The text string must always use the UTF-8 (Unicode) encoding but on "size". The text string must always use the UTF-8 (Unicode) encoding but
any control characters (such as newlines) are ignored. any control characters (such as newlines) are ignored.
.SS pdfioContentTextMoveLine .SS pdfioContentTextMoveLine
Move to the next line and offset. Move to the next line and offset.
.PP .PP
@ -3462,8 +3366,6 @@ bool pdfioContentTextNewLine (
pdfio_stream_t *st pdfio_stream_t *st
); );
.fi .fi
.PP
.SS pdfioContentTextNewLineShow .SS pdfioContentTextNewLineShow
Move to the next line and show text. Move to the next line and show text.
.PP .PP
@ -3481,8 +3383,6 @@ This function moves to the next line and then shows some text with optional
word and character spacing in a PDF content stream. The "unicode" argument word and character spacing in a PDF content stream. The "unicode" argument
specifies that the current font maps to full Unicode. The "s" argument specifies that the current font maps to full Unicode. The "s" argument
specifies a UTF-8 encoded string. specifies a UTF-8 encoded string.
.SS pdfioContentTextNewLineShowf .SS pdfioContentTextNewLineShowf
Show formatted text. Show formatted text.
.PP .PP
@ -3501,8 +3401,6 @@ This function moves to the next line and shows some formatted text with
optional word and character spacing in a PDF content stream. The "unicode" optional word and character spacing in a PDF content stream. The "unicode"
argument specifies that the current font maps to full Unicode. The "format" argument specifies that the current font maps to full Unicode. The "format"
argument specifies a UTF-8 encoded \fBprintf\fR-style format string. argument specifies a UTF-8 encoded \fBprintf\fR-style format string.
.SS pdfioContentTextShow .SS pdfioContentTextShow
Show text. Show text.
.PP .PP
@ -3553,8 +3451,6 @@ bool pdfioDictClear (
const char *key const char *key
); );
.fi .fi
.PP
.SS pdfioDictCopy .SS pdfioDictCopy
Copy a dictionary to a PDF file. Copy a dictionary to a PDF file.
.PP .PP
@ -3627,8 +3523,6 @@ const char * pdfioDictGetKey (
size_t n size_t n
); );
.fi .fi
.PP
.SS pdfioDictGetName .SS pdfioDictGetName
Get a key name value from a dictionary. Get a key name value from a dictionary.
.PP .PP
@ -3646,8 +3540,6 @@ size_t pdfioDictGetNumPairs (
pdfio_dict_t *dict pdfio_dict_t *dict
); );
.fi .fi
.PP
.SS pdfioDictGetNumber .SS pdfioDictGetNumber
Get a key number value from a dictionary. Get a key number value from a dictionary.
.PP .PP
@ -3720,8 +3612,6 @@ function "cb":
The iteration continues as long as the callback returns \fBtrue\fR or all keys The iteration continues as long as the callback returns \fBtrue\fR or all keys
have been iterated. have been iterated.
.SS pdfioDictSetArray .SS pdfioDictSetArray
Set a key array in a dictionary. Set a key array in a dictionary.
.PP .PP
@ -3843,39 +3733,6 @@ bool pdfioDictSetStringf (
... ...
); );
.fi .fi
.SS pdfioFileAddOutputIntent
Add an OutputIntent to a file.
.PP
.nf
void pdfioFileAddOutputIntent (
pdfio_file_t *pdf,
const char *subtype,
const char *condition,
const char *cond_id,
const char *reg_name,
const char *info,
pdfio_obj_t *profile
);
.fi
.PP
This function adds an OutputIntent dictionary to the PDF file catalog.
The "subtype" argument specifies the intent subtype and is typically
"GTS_PDFX" for PDF/X, "GTS_PDFA1" for PDF/A, or "ISO_PDFE1" for PDF/E.
Passing \fBNULL\fR defaults the subtype to "GTS_PDFA1".
.PP
The "condition" argument specifies a short name for the output intent, while
the "info" argument specifies a longer description for the output intent.
Both can be \fBNULL\fR to omit this information.
.PP
The "cond_id" argument specifies a unique identifier such as a registration
("CGATS001") or color space name ("sRGB"). The "reg_name" argument provides
a URL for the identifier.
.PP
The "profile" argument specifies an ICC profile object for the output
condition. If \fBNULL\fR, the PDF consumer will attempt to look up the correct
profile using the "cond_id" value.
.SS pdfioFileClose .SS pdfioFileClose
Close a PDF file and free all memory used for it. Close a PDF file and free all memory used for it.
.PP .PP
@ -3969,27 +3826,8 @@ specifies the font nane:
Aside from "Symbol" and "Zapf-Dingbats", Base fonts use the Windows CP1252 Aside from "Symbol" and "Zapf-Dingbats", Base fonts use the Windows CP1252
(ISO-8859-1 with additional characters such as the Euro symbol) subset of (ISO-8859-1 with additional characters such as the Euro symbol) subset of
Unicode. Unicode.
.SS pdfioFileCreateFontObjFromData
Add a font in memory to a PDF file.
.PP
.nf
pdfio_obj_t * pdfioFileCreateFontObjFromData (
pdfio_file_t *pdf,
const void *data,
size_t datasize,
bool unicode
);
.fi
.PP
This function embeds TrueType/OpenType font data into a PDF file. The
"unicode" parameter controls whether the font is encoded for two-byte
characters (potentially full Unicode, but more typically a subset)
or to only support the Windows CP1252 (ISO-8859-1 with additional
characters such as the Euro symbol) subset of Unicode.
.SS pdfioFileCreateFontObjFromFile .SS pdfioFileCreateFontObjFromFile
Add a font file to a PDF file. Add a font object to a PDF file.
.PP .PP
.nf .nf
pdfio_obj_t * pdfioFileCreateFontObjFromFile ( pdfio_obj_t * pdfioFileCreateFontObjFromFile (
@ -3999,7 +3837,7 @@ pdfio_obj_t * pdfioFileCreateFontObjFromFile (
); );
.fi .fi
.PP .PP
This function embeds a TrueType/OpenType font file into a PDF file. The This function embeds a TrueType/OpenType font into a PDF file. The
"unicode" parameter controls whether the font is encoded for two-byte "unicode" parameter controls whether the font is encoded for two-byte
characters (potentially full Unicode, but more typically a subset) characters (potentially full Unicode, but more typically a subset)
or to only support the Windows CP1252 (ISO-8859-1 with additional or to only support the Windows CP1252 (ISO-8859-1 with additional
@ -4088,8 +3926,6 @@ pdfio_obj_t * pdfioFileCreateNameObj (
.PP .PP
This function creates a new object with a name value in a PDF file. This function creates a new object with a name value in a PDF file.
You must call \fIpdfioObjClose\fR to write the object to the file. You must call \fIpdfioObjClose\fR to write the object to the file.
.SS pdfioFileCreateNumberObj .SS pdfioFileCreateNumberObj
Create a new object in a PDF file containing a number. Create a new object in a PDF file containing a number.
.PP .PP
@ -4102,8 +3938,6 @@ pdfio_obj_t * pdfioFileCreateNumberObj (
.PP .PP
This function creates a new object with a number value in a PDF file. This function creates a new object with a number value in a PDF file.
You must call \fIpdfioObjClose\fR to write the object to the file. You must call \fIpdfioObjClose\fR to write the object to the file.
.SS pdfioFileCreateObj .SS pdfioFileCreateObj
Create a new object in a PDF file. Create a new object in a PDF file.
.PP .PP
@ -4182,8 +4016,6 @@ pdfio_obj_t * pdfioFileCreateStringObj (
.PP .PP
This function creates a new object with a string value in a PDF file. This function creates a new object with a string value in a PDF file.
You must call \fIpdfioObjClose\fR to write the object to the file. You must call \fIpdfioObjClose\fR to write the object to the file.
.SS pdfioFileCreateTemporary .SS pdfioFileCreateTemporary
.PP .PP
@ -4260,21 +4092,6 @@ const char * pdfioFileGetKeywords (
pdfio_file_t *pdf pdfio_file_t *pdf
); );
.fi .fi
.SS pdfioFileGetLanguage
Get the language metadata for a PDF file.
.PP
.nf
const char * pdfioFileGetLanguage (
pdfio_file_t *pdf
);
.fi
.PP
This function gets the (primary/default) language metadata, if any, for a PDF
file. The returned string is an IETF BCP 47 language tag of the form
"lang-REGION". For example, the string "en-CA" specifies Canadian English
and the string "fr-CA" specifies Canadian French.
.SS pdfioFileGetModificationDate .SS pdfioFileGetModificationDate
Get the most recent modification date for a PDF file. Get the most recent modification date for a PDF file.
.PP .PP
@ -4430,22 +4247,6 @@ void pdfioFileSetKeywords (
const char *value const char *value
); );
.fi .fi
.SS pdfioFileSetLanguage
Set the language metadata for a PDF file.
.PP
.nf
void pdfioFileSetLanguage (
pdfio_file_t *pdf,
const char *value
);
.fi
.PP
This function sets the (primary/default) language metadata for a PDF file.
The "value" argument is an IETF BCP 47 language tag string of the form
"lang-REGION". For example, the string "en-CA" specifies Canadian English
and the string "fr-CA" specifies Canadian French.
.SS pdfioFileSetModificationDate .SS pdfioFileSetModificationDate
Set the modification date for a PDF file. Set the modification date for a PDF file.
.PP .PP
@ -4588,8 +4389,6 @@ const char * pdfioObjGetName (
pdfio_obj_t *obj pdfio_obj_t *obj
); );
.fi .fi
.PP
.SS pdfioObjGetNumber .SS pdfioObjGetNumber
Get the object's number. Get the object's number.
.PP .PP
@ -4791,11 +4590,6 @@ bool pdfioStreamPrintf (
... ...
); );
.fi .fi
.PP
This function writes a formatted string to a stream. In addition to the
standard \fBprintf\fR format characters, you can use "%H" to format a HTML/XML
string value, "%N" to format a PDF name value ("/Name"), and "%S" to format
a PDF string ("(String)") value.
.SS pdfioStreamPutChar .SS pdfioStreamPutChar
Write a single character to a stream. Write a single character to a stream.
.PP .PP

View File

@ -1,13 +1,13 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-US"> <html lang="en-US">
<head> <head>
<title>PDFio Programming Manual v1.6.0</title> <title>PDFio Programming Manual v1.5.0</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta name="generator" content="codedoc v3.8"> <meta name="generator" content="codedoc v3.8">
<meta name="author" content="Michael R Sweet"> <meta name="author" content="Michael R Sweet">
<meta name="language" content="en-US"> <meta name="language" content="en-US">
<meta name="copyright" content="Copyright © 2021-2025 by Michael R Sweet"> <meta name="copyright" content="Copyright © 2021-2025 by Michael R Sweet">
<meta name="version" content="1.6.0"> <meta name="version" content="1.5.0">
<style type="text/css"><!-- <style type="text/css"><!--
body { body {
background: white; background: white;
@ -251,7 +251,7 @@ span.string {
<body> <body>
<div class="header"> <div class="header">
<p><img class="title" src="pdfio-512.png"></p> <p><img class="title" src="pdfio-512.png"></p>
<h1 class="title">PDFio Programming Manual v1.6.0</h1> <h1 class="title">PDFio Programming Manual v1.5.0</h1>
<p>Michael R Sweet</p> <p>Michael R Sweet</p>
<p>Copyright © 2021-2025 by Michael R Sweet</p> <p>Copyright © 2021-2025 by Michael R Sweet</p>
</div> </div>
@ -395,12 +395,10 @@ span.string {
<li><a href="#pdfioDictSetRect">pdfioDictSetRect</a></li> <li><a href="#pdfioDictSetRect">pdfioDictSetRect</a></li>
<li><a href="#pdfioDictSetString">pdfioDictSetString</a></li> <li><a href="#pdfioDictSetString">pdfioDictSetString</a></li>
<li><a href="#pdfioDictSetStringf">pdfioDictSetStringf</a></li> <li><a href="#pdfioDictSetStringf">pdfioDictSetStringf</a></li>
<li><a href="#pdfioFileAddOutputIntent">pdfioFileAddOutputIntent</a></li>
<li><a href="#pdfioFileClose">pdfioFileClose</a></li> <li><a href="#pdfioFileClose">pdfioFileClose</a></li>
<li><a href="#pdfioFileCreate">pdfioFileCreate</a></li> <li><a href="#pdfioFileCreate">pdfioFileCreate</a></li>
<li><a href="#pdfioFileCreateArrayObj">pdfioFileCreateArrayObj</a></li> <li><a href="#pdfioFileCreateArrayObj">pdfioFileCreateArrayObj</a></li>
<li><a href="#pdfioFileCreateFontObjFromBase">pdfioFileCreateFontObjFromBase</a></li> <li><a href="#pdfioFileCreateFontObjFromBase">pdfioFileCreateFontObjFromBase</a></li>
<li><a href="#pdfioFileCreateFontObjFromData">pdfioFileCreateFontObjFromData</a></li>
<li><a href="#pdfioFileCreateFontObjFromFile">pdfioFileCreateFontObjFromFile</a></li> <li><a href="#pdfioFileCreateFontObjFromFile">pdfioFileCreateFontObjFromFile</a></li>
<li><a href="#pdfioFileCreateICCObjFromData">pdfioFileCreateICCObjFromData</a></li> <li><a href="#pdfioFileCreateICCObjFromData">pdfioFileCreateICCObjFromData</a></li>
<li><a href="#pdfioFileCreateICCObjFromFile">pdfioFileCreateICCObjFromFile</a></li> <li><a href="#pdfioFileCreateICCObjFromFile">pdfioFileCreateICCObjFromFile</a></li>
@ -420,7 +418,6 @@ span.string {
<li><a href="#pdfioFileGetCreator">pdfioFileGetCreator</a></li> <li><a href="#pdfioFileGetCreator">pdfioFileGetCreator</a></li>
<li><a href="#pdfioFileGetID">pdfioFileGetID</a></li> <li><a href="#pdfioFileGetID">pdfioFileGetID</a></li>
<li><a href="#pdfioFileGetKeywords">pdfioFileGetKeywords</a></li> <li><a href="#pdfioFileGetKeywords">pdfioFileGetKeywords</a></li>
<li><a href="#pdfioFileGetLanguage">pdfioFileGetLanguage</a></li>
<li><a href="#pdfioFileGetModificationDate">pdfioFileGetModificationDate</a></li> <li><a href="#pdfioFileGetModificationDate">pdfioFileGetModificationDate</a></li>
<li><a href="#pdfioFileGetName">pdfioFileGetName</a></li> <li><a href="#pdfioFileGetName">pdfioFileGetName</a></li>
<li><a href="#pdfioFileGetNumObjs">pdfioFileGetNumObjs</a></li> <li><a href="#pdfioFileGetNumObjs">pdfioFileGetNumObjs</a></li>
@ -437,7 +434,6 @@ span.string {
<li><a href="#pdfioFileSetCreationDate">pdfioFileSetCreationDate</a></li> <li><a href="#pdfioFileSetCreationDate">pdfioFileSetCreationDate</a></li>
<li><a href="#pdfioFileSetCreator">pdfioFileSetCreator</a></li> <li><a href="#pdfioFileSetCreator">pdfioFileSetCreator</a></li>
<li><a href="#pdfioFileSetKeywords">pdfioFileSetKeywords</a></li> <li><a href="#pdfioFileSetKeywords">pdfioFileSetKeywords</a></li>
<li><a href="#pdfioFileSetLanguage">pdfioFileSetLanguage</a></li>
<li><a href="#pdfioFileSetModificationDate">pdfioFileSetModificationDate</a></li> <li><a href="#pdfioFileSetModificationDate">pdfioFileSetModificationDate</a></li>
<li><a href="#pdfioFileSetPermissions">pdfioFileSetPermissions</a></li> <li><a href="#pdfioFileSetPermissions">pdfioFileSetPermissions</a></li>
<li><a href="#pdfioFileSetSubject">pdfioFileSetSubject</a></li> <li><a href="#pdfioFileSetSubject">pdfioFileSetSubject</a></li>
@ -1169,26 +1165,11 @@ main(<span class="reserved">int</span> argc, <span clas
{ {
<span class="reserved">const</span> <span class="reserved">char</span> *filename; <span class="comment">// PDF filename</span> <span class="reserved">const</span> <span class="reserved">char</span> *filename; <span class="comment">// PDF filename</span>
pdfio_file_t *pdf; <span class="comment">// PDF file</span> pdfio_file_t *pdf; <span class="comment">// PDF file</span>
pdfio_dict_t *catalog; <span class="comment">// Catalog dictionary</span> <span class="reserved">const</span> <span class="reserved">char</span> *author; <span class="comment">// Author name</span>
<span class="reserved">const</span> <span class="reserved">char</span> *author, <span class="comment">// Author name</span> time_t creation_date; <span class="comment">// Creation date</span>
*creator, <span class="comment">// Creator name</span> <span class="reserved">struct</span> tm *creation_tm; <span class="comment">// Creation date/time information</span>
*producer, <span class="comment">// Producer name</span> <span class="reserved">char</span> creation_text[<span class="number">256</span>]; <span class="comment">// Creation date/time as a string</span>
*title; <span class="comment">// Title</span> <span class="reserved">const</span> <span class="reserved">char</span> *title; <span class="comment">// Title</span>
time_t creation_date, <span class="comment">// Creation date</span>
modification_date; <span class="comment">// Modification date</span>
<span class="reserved">struct</span> tm *creation_tm, <span class="comment">// Creation date/time information</span>
*modification_tm; <span class="comment">// Modification date/time information</span>
<span class="reserved">char</span> creation_text[<span class="number">256</span>], <span class="comment">// Creation date/time as a string</span>
modification_text[<span class="number">256</span>], <span class="comment">// Modification date/time human fmt string</span>
range_text[<span class="number">255</span>]; <span class="comment">// Page range text</span>
size_t num_pages; <span class="comment">// PDF number of pages</span>
<span class="reserved">bool</span> has_acroform; <span class="comment">// Does the file have an AcroForm?</span>
pdfio_obj_t *page; <span class="comment">// Object</span>
pdfio_dict_t *page_dict; <span class="comment">// Object dictionary</span>
size_t cur, <span class="comment">// Current page index</span>
prev; <span class="comment">// Previous page index</span>
pdfio_rect_t cur_box, <span class="comment">// Current MediaBox</span>
prev_box; <span class="comment">// Previous MediaBox</span>
<span class="comment">// Get the filename from the command-line...</span> <span class="comment">// Get the filename from the command-line...</span>
@ -1201,19 +1182,13 @@ main(<span class="reserved">int</span> argc, <span clas
filename = argv[<span class="number">1</span>]; filename = argv[<span class="number">1</span>];
<span class="comment">// Open the PDF file with the default callbacks...</span> <span class="comment">// Open the PDF file with the default callbacks...</span>
pdf = pdfioFileOpen(filename, <span class="comment">/*password_cb*/</span>NULL, pdf = pdfioFileOpen(filename, <span class="comment">/*password_cb*/</span>NULL, <span class="comment">/*password_cbdata*/</span>NULL,
<span class="comment">/*password_cbdata*/</span>NULL, <span class="comment">/*error_cb*/</span>NULL, <span class="comment">/*error_cb*/</span>NULL, <span class="comment">/*error_cbdata*/</span>NULL);
<span class="comment">/*error_cbdata*/</span>NULL);
<span class="reserved">if</span> (pdf == NULL) <span class="reserved">if</span> (pdf == NULL)
<span class="reserved">return</span> (<span class="number">1</span>); <span class="reserved">return</span> (<span class="number">1</span>);
<span class="comment">// Get the title, author, etc...</span> <span class="comment">// Get the title and author...</span>
catalog = pdfioFileGetCatalog(pdf);
author = pdfioFileGetAuthor(pdf); author = pdfioFileGetAuthor(pdf);
creator = pdfioFileGetCreator(pdf);
has_acroform = pdfioDictGetType(catalog, <span class="string">&quot;AcroForm&quot;</span>) != PDFIO_VALTYPE_NONE;
num_pages = pdfioFileGetNumPages(pdf);
producer = pdfioFileGetProducer(pdf);
title = pdfioFileGetTitle(pdf); title = pdfioFileGetTitle(pdf);
<span class="comment">// Get the creation date and convert to a string...</span> <span class="comment">// Get the creation date and convert to a string...</span>
@ -1227,76 +1202,12 @@ main(<span class="reserved">int</span> argc, <span clas
snprintf(creation_text, <span class="reserved">sizeof</span>(creation_text), <span class="string">&quot;-- not set --&quot;</span>); snprintf(creation_text, <span class="reserved">sizeof</span>(creation_text), <span class="string">&quot;-- not set --&quot;</span>);
} }
<span class="comment">// Get the modification date and convert to a string...</span>
<span class="reserved">if</span> ((modification_date = pdfioFileGetModificationDate(pdf)) &gt; <span class="number">0</span>)
{
modification_tm = localtime(&amp;modification_date);
strftime(modification_text, <span class="reserved">sizeof</span>(modification_text), <span class="string">&quot;%c&quot;</span>, modification_tm);
}
<span class="reserved">else</span>
{
snprintf(modification_text, <span class="reserved">sizeof</span>(modification_text), <span class="string">&quot;-- not set --&quot;</span>);
}
<span class="comment">// Print file information to stdout...</span> <span class="comment">// Print file information to stdout...</span>
printf(<span class="string">&quot;%s:\n&quot;</span>, filename); printf(<span class="string">&quot;%s:\n&quot;</span>, filename);
printf(<span class="string">&quot; Title: %s\n&quot;</span>, title ? title : <span class="string">&quot;-- not set --&quot;</span>); printf(<span class="string">&quot; Title: %s\n&quot;</span>, title ? title : <span class="string">&quot;-- not set --&quot;</span>);
printf(<span class="string">&quot; Author: %s\n&quot;</span>, author ? author : <span class="string">&quot;-- not set --&quot;</span>); printf(<span class="string">&quot; Author: %s\n&quot;</span>, author ? author : <span class="string">&quot;-- not set --&quot;</span>);
printf(<span class="string">&quot; Creator: %s\n&quot;</span>, creator ? creator : <span class="string">&quot;-- not set --&quot;</span>);
printf(<span class="string">&quot; Producer: %s\n&quot;</span>, producer ? producer : <span class="string">&quot;-- not set --&quot;</span>);
printf(<span class="string">&quot; Created On: %s\n&quot;</span>, creation_text); printf(<span class="string">&quot; Created On: %s\n&quot;</span>, creation_text);
printf(<span class="string">&quot; Modified On: %s\n&quot;</span>, modification_text); printf(<span class="string">&quot; Number Pages: %u\n&quot;</span>, (<span class="reserved">unsigned</span>)pdfioFileGetNumPages(pdf));
printf(<span class="string">&quot; Version: %s\n&quot;</span>, pdfioFileGetVersion(pdf));
printf(<span class="string">&quot; AcroForm: %s\n&quot;</span>, has_acroform ? <span class="string">&quot;Yes&quot;</span> : <span class="string">&quot;No&quot;</span>);
printf(<span class="string">&quot; Number of Pages: %u\n&quot;</span>, (<span class="reserved">unsigned</span>)num_pages);
<span class="comment">// Report the MediaBox for all of the pages</span>
prev_box.x1 = prev_box.x2 = prev_box.y1 = prev_box.y2 = <span class="number">0.0</span>;
<span class="reserved">for</span> (cur = <span class="number">0</span>, prev = <span class="number">0</span>; cur &lt; num_pages; cur ++)
{
<span class="comment">// Find the MediaBox for this page in the page tree...</span>
<span class="reserved">for</span> (page = pdfioFileGetPage(pdf, cur);
page != NULL;
page = pdfioDictGetObj(page_dict, <span class="string">&quot;Parent&quot;</span>))
{
cur_box.x1 = cur_box.x2 = cur_box.y1 = cur_box.y2 = <span class="number">0.0</span>;
page_dict = pdfioObjGetDict(page);
<span class="reserved">if</span> (pdfioDictGetRect(page_dict, <span class="string">&quot;MediaBox&quot;</span>, &amp;cur_box))
<span class="reserved">break</span>;
}
<span class="comment">// If this MediaBox is different from the previous one, show the range of</span>
<span class="comment">// pages that have that size...</span>
<span class="reserved">if</span> (cur == <span class="number">0</span> ||
fabs(cur_box.x1 - prev_box.x1) &gt; <span class="number">0.01</span> ||
fabs(cur_box.y1 - prev_box.y1) &gt; <span class="number">0.01</span> ||
fabs(cur_box.x2 - prev_box.x2) &gt; <span class="number">0.01</span> ||
fabs(cur_box.y2 - prev_box.y2) &gt; <span class="number">0.01</span>)
{
<span class="reserved">if</span> (cur &gt; prev)
{
snprintf(range_text, <span class="reserved">sizeof</span>(range_text), <span class="string">&quot;Pages %u-%u&quot;</span>,
(<span class="reserved">unsigned</span>)(prev + <span class="number">1</span>), (<span class="reserved">unsigned</span>)cur);
printf(<span class="string">&quot;%16s: [%g %g %g %g]\n&quot;</span>, range_text,
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
}
<span class="comment">// Start a new series of pages with the new size...</span>
prev = cur;
prev_box = cur_box;
}
}
<span class="comment">// Show the last range as needed...</span>
<span class="reserved">if</span> (cur &gt; prev)
{
snprintf(range_text, <span class="reserved">sizeof</span>(range_text), <span class="string">&quot;Pages %u-%u&quot;</span>,
(<span class="reserved">unsigned</span>)(prev + <span class="number">1</span>), (<span class="reserved">unsigned</span>)cur);
printf(<span class="string">&quot;%16s: [%g %g %g %g]\n&quot;</span>, range_text,
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
}
<span class="comment">// Close the PDF file...</span> <span class="comment">// Close the PDF file...</span>
pdfioFileClose(pdf); pdfioFileClose(pdf);
@ -2598,7 +2509,7 @@ dd-&gt;y = row_y - row-&gt;height;
<tr><th>pdf</th> <tr><th>pdf</th>
<td class="description">PDF file</td></tr> <td class="description">PDF file</td></tr>
<tr><th>num_colors</th> <tr><th>num_colors</th>
<td class="description">Number of colors (1, 3, or 4)</td></tr> <td class="description">Number of colors (1 or 3)</td></tr>
<tr><th>cs</th> <tr><th>cs</th>
<td class="description">Color space enumeration</td></tr> <td class="description">Color space enumeration</td></tr>
</tbody></table> </tbody></table>
@ -2606,8 +2517,7 @@ dd-&gt;y = row_y - row-&gt;height;
<p class="description">Color array</p> <p class="description">Color array</p>
<h4 class="discussion">Discussion</h4> <h4 class="discussion">Discussion</h4>
<p class="discussion">This function creates a color array for a standard <code>PDFIO_CS_</code> enumerated color space. <p class="discussion">This function creates a color array for a standard <code>PDFIO_CS_</code> enumerated color space.
The &quot;num_colors&quot; argument must be <code>1</code> for grayscale, <code>3</code> for RGB color, and The &quot;num_colors&quot; argument must be <code>1</code> for grayscale and <code>3</code> for RGB color.</p>
<code>4</code> for CMYK color.</p>
<h3 class="function"><a id="pdfioArrayGetArray">pdfioArrayGetArray</a></h3> <h3 class="function"><a id="pdfioArrayGetArray">pdfioArrayGetArray</a></h3>
<p class="description">Get an array value from an array.</p> <p class="description">Get an array value from an array.</p>
<p class="code"> <p class="code">
@ -2751,7 +2661,7 @@ size_t pdfioArrayGetSize(<a href="#pdfio_array_t">pdfio_array_t</a> *a);</p>
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description">Value type</p> <p class="description">Value type</p>
<h3 class="function"><span class="info">&#160;PDFio v1.4&#160;</span><a id="pdfioArrayRemove">pdfioArrayRemove</a></h3> <h3 class="function"><a id="pdfioArrayRemove">pdfioArrayRemove</a></h3>
<p class="description">Remove an array entry.</p> <p class="description">Remove an array entry.</p>
<p class="code"> <p class="code">
<span class="reserved">bool</span> pdfioArrayRemove(<a href="#pdfio_array_t">pdfio_array_t</a> *a, size_t n);</p> <span class="reserved">bool</span> pdfioArrayRemove(<a href="#pdfio_array_t">pdfio_array_t</a> *a, size_t n);</p>
@ -2956,7 +2866,7 @@ using the <a href="#pdfioPageDictAddImage"><code>pdfioPageDictAddImage</code></a
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p> <p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h3 class="function"><span class="info">&#160;PDFio v1.1&#160;</span><a id="pdfioContentPathEnd">pdfioContentPathEnd</a></h3> <h3 class="function"><a id="pdfioContentPathEnd">pdfioContentPathEnd</a></h3>
<p class="description">Clear the current path.</p> <p class="description">Clear the current path.</p>
<p class="code"> <p class="code">
<span class="reserved">bool</span> pdfioContentPathEnd(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);</p> <span class="reserved">bool</span> pdfioContentPathEnd(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);</p>
@ -3446,7 +3356,7 @@ are 0, a solid line is drawn.</p>
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p> <p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h3 class="function"><span class="info">&#160;PDFio v1.2&#160;</span><a id="pdfioContentTextMeasure">pdfioContentTextMeasure</a></h3> <h3 class="function"><a id="pdfioContentTextMeasure">pdfioContentTextMeasure</a></h3>
<p class="description">Measure a text string and return its width.</p> <p class="description">Measure a text string and return its width.</p>
<p class="code"> <p class="code">
<span class="reserved">double</span> pdfioContentTextMeasure(<a href="#pdfio_obj_t">pdfio_obj_t</a> *font, <span class="reserved">const</span> <span class="reserved">char</span> *s, <span class="reserved">double</span> size);</p> <span class="reserved">double</span> pdfioContentTextMeasure(<a href="#pdfio_obj_t">pdfio_obj_t</a> *font, <span class="reserved">const</span> <span class="reserved">char</span> *s, <span class="reserved">double</span> size);</p>
@ -3464,9 +3374,7 @@ are 0, a solid line is drawn.</p>
<h4 class="discussion">Discussion</h4> <h4 class="discussion">Discussion</h4>
<p class="discussion">This function measures the given text string &quot;s&quot; and returns its width based <p class="discussion">This function measures the given text string &quot;s&quot; and returns its width based
on &quot;size&quot;. The text string must always use the UTF-8 (Unicode) encoding but on &quot;size&quot;. The text string must always use the UTF-8 (Unicode) encoding but
any control characters (such as newlines) are ignored. any control characters (such as newlines) are ignored.</p>
</p>
<h3 class="function"><a id="pdfioContentTextMoveLine">pdfioContentTextMoveLine</a></h3> <h3 class="function"><a id="pdfioContentTextMoveLine">pdfioContentTextMoveLine</a></h3>
<p class="description">Move to the next line and offset.</p> <p class="description">Move to the next line and offset.</p>
<p class="code"> <p class="code">
@ -3497,7 +3405,7 @@ any control characters (such as newlines) are ignored.
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p> <p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h3 class="function"><span class="info">&#160;PDFio v1.2&#160;</span><a id="pdfioContentTextNewLine">pdfioContentTextNewLine</a></h3> <h3 class="function"><a id="pdfioContentTextNewLine">pdfioContentTextNewLine</a></h3>
<p class="description">Move to the next line.</p> <p class="description">Move to the next line.</p>
<p class="code"> <p class="code">
<span class="reserved">bool</span> pdfioContentTextNewLine(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);</p> <span class="reserved">bool</span> pdfioContentTextNewLine(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);</p>
@ -3508,7 +3416,7 @@ any control characters (such as newlines) are ignored.
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p> <p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h3 class="function"><span class="info">&#160;PDFio v1.2&#160;</span><a id="pdfioContentTextNewLineShow">pdfioContentTextNewLineShow</a></h3> <h3 class="function"><a id="pdfioContentTextNewLineShow">pdfioContentTextNewLineShow</a></h3>
<p class="description">Move to the next line and show text.</p> <p class="description">Move to the next line and show text.</p>
<p class="code"> <p class="code">
<span class="reserved">bool</span> pdfioContentTextNewLineShow(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, <span class="reserved">double</span> ws, <span class="reserved">double</span> cs, <span class="reserved">bool</span> unicode, <span class="reserved">const</span> <span class="reserved">char</span> *s);</p> <span class="reserved">bool</span> pdfioContentTextNewLineShow(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, <span class="reserved">double</span> ws, <span class="reserved">double</span> cs, <span class="reserved">bool</span> unicode, <span class="reserved">const</span> <span class="reserved">char</span> *s);</p>
@ -3531,10 +3439,8 @@ any control characters (such as newlines) are ignored.
<p class="discussion">This function moves to the next line and then shows some text with optional <p class="discussion">This function moves to the next line and then shows some text with optional
word and character spacing in a PDF content stream. The &quot;unicode&quot; argument word and character spacing in a PDF content stream. The &quot;unicode&quot; argument
specifies that the current font maps to full Unicode. The &quot;s&quot; argument specifies that the current font maps to full Unicode. The &quot;s&quot; argument
specifies a UTF-8 encoded string. specifies a UTF-8 encoded string.</p>
<h3 class="function"><a id="pdfioContentTextNewLineShowf">pdfioContentTextNewLineShowf</a></h3>
</p>
<h3 class="function"><span class="info">&#160;PDFio v1.2&#160;</span><a id="pdfioContentTextNewLineShowf">pdfioContentTextNewLineShowf</a></h3>
<p class="description">Show formatted text.</p> <p class="description">Show formatted text.</p>
<p class="code"> <p class="code">
<span class="reserved">bool</span> pdfioContentTextNewLineShowf(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, <span class="reserved">double</span> ws, <span class="reserved">double</span> cs, <span class="reserved">bool</span> unicode, <span class="reserved">const</span> <span class="reserved">char</span> *format, ...);</p> <span class="reserved">bool</span> pdfioContentTextNewLineShowf(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, <span class="reserved">double</span> ws, <span class="reserved">double</span> cs, <span class="reserved">bool</span> unicode, <span class="reserved">const</span> <span class="reserved">char</span> *format, ...);</p>
@ -3559,9 +3465,7 @@ specifies a UTF-8 encoded string.
<p class="discussion">This function moves to the next line and shows some formatted text with <p class="discussion">This function moves to the next line and shows some formatted text with
optional word and character spacing in a PDF content stream. The &quot;unicode&quot; optional word and character spacing in a PDF content stream. The &quot;unicode&quot;
argument specifies that the current font maps to full Unicode. The &quot;format&quot; argument specifies that the current font maps to full Unicode. The &quot;format&quot;
argument specifies a UTF-8 encoded <code>printf</code>-style format string. argument specifies a UTF-8 encoded <code>printf</code>-style format string.</p>
</p>
<h3 class="function"><a id="pdfioContentTextShow">pdfioContentTextShow</a></h3> <h3 class="function"><a id="pdfioContentTextShow">pdfioContentTextShow</a></h3>
<p class="description">Show text.</p> <p class="description">Show text.</p>
<p class="code"> <p class="code">
@ -3624,7 +3528,7 @@ argument specifies an array of UTF-8 encoded strings.</p>
<p class="discussion">This function shows some formatted text in a PDF content stream. The <p class="discussion">This function shows some formatted text in a PDF content stream. The
&quot;unicode&quot; argument specifies that the current font maps to full Unicode. &quot;unicode&quot; argument specifies that the current font maps to full Unicode.
The &quot;format&quot; argument specifies a UTF-8 encoded <code>printf</code>-style format string.</p> The &quot;format&quot; argument specifies a UTF-8 encoded <code>printf</code>-style format string.</p>
<h3 class="function"><span class="info">&#160;PDFio v1.4&#160;</span><a id="pdfioDictClear">pdfioDictClear</a></h3> <h3 class="function"><a id="pdfioDictClear">pdfioDictClear</a></h3>
<p class="description">Remove a key/value pair from a dictionary.</p> <p class="description">Remove a key/value pair from a dictionary.</p>
<p class="code"> <p class="code">
<span class="reserved">bool</span> pdfioDictClear(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, <span class="reserved">const</span> <span class="reserved">char</span> *key);</p> <span class="reserved">bool</span> pdfioDictClear(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, <span class="reserved">const</span> <span class="reserved">char</span> *key);</p>
@ -3728,7 +3632,7 @@ time_t pdfioDictGetDate(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, <span cl
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description">Value</p> <p class="description">Value</p>
<h3 class="function"><span class="info">&#160;PDFio v1.4&#160;</span><a id="pdfioDictGetKey">pdfioDictGetKey</a></h3> <h3 class="function"><a id="pdfioDictGetKey">pdfioDictGetKey</a></h3>
<p class="description">Get the key for the specified pair.</p> <p class="description">Get the key for the specified pair.</p>
<p class="code"> <p class="code">
<span class="reserved">const</span> <span class="reserved">char</span> *pdfioDictGetKey(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, size_t n);</p> <span class="reserved">const</span> <span class="reserved">char</span> *pdfioDictGetKey(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, size_t n);</p>
@ -3754,7 +3658,7 @@ time_t pdfioDictGetDate(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, <span cl
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description">Value</p> <p class="description">Value</p>
<h3 class="function"><span class="info">&#160;PDFio v1.4&#160;</span><a id="pdfioDictGetNumPairs">pdfioDictGetNumPairs</a></h3> <h3 class="function"><a id="pdfioDictGetNumPairs">pdfioDictGetNumPairs</a></h3>
<p class="description">Get the number of key/value pairs in a dictionary.</p> <p class="description">Get the number of key/value pairs in a dictionary.</p>
<p class="code"> <p class="code">
size_t pdfioDictGetNumPairs(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict);</p> size_t pdfioDictGetNumPairs(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict);</p>
@ -3832,7 +3736,7 @@ size_t pdfioDictGetNumPairs(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict);</p>
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description">Value type</p> <p class="description">Value type</p>
<h3 class="function"><span class="info">&#160;PDFio v1.1&#160;</span><a id="pdfioDictIterateKeys">pdfioDictIterateKeys</a></h3> <h3 class="function"><a id="pdfioDictIterateKeys">pdfioDictIterateKeys</a></h3>
<p class="description">Iterate the keys in a dictionary.</p> <p class="description">Iterate the keys in a dictionary.</p>
<p class="code"> <p class="code">
<span class="reserved">void</span> pdfioDictIterateKeys(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, <a href="#pdfio_dict_cb_t">pdfio_dict_cb_t</a> cb, <span class="reserved">void</span> *cb_data);</p> <span class="reserved">void</span> pdfioDictIterateKeys(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, <a href="#pdfio_dict_cb_t">pdfio_dict_cb_t</a> cb, <span class="reserved">void</span> *cb_data);</p>
@ -3859,9 +3763,7 @@ my_dict_cb(pdfio_dict_t *dict, const char *key, void *cb_data)
</pre> </pre>
The iteration continues as long as the callback returns <code>true</code> or all keys The iteration continues as long as the callback returns <code>true</code> or all keys
have been iterated. have been iterated.</p>
</p>
<h3 class="function"><a id="pdfioDictSetArray">pdfioDictSetArray</a></h3> <h3 class="function"><a id="pdfioDictSetArray">pdfioDictSetArray</a></h3>
<p class="description">Set a key array in a dictionary.</p> <p class="description">Set a key array in a dictionary.</p>
<p class="code"> <p class="code">
@ -4044,46 +3946,6 @@ have been iterated.
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p> <p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h3 class="function"><span class="info">&#160;PDFio 1.6&#160;</span><a id="pdfioFileAddOutputIntent">pdfioFileAddOutputIntent</a></h3>
<p class="description">Add an OutputIntent to a file.</p>
<p class="code">
<span class="reserved">void</span> pdfioFileAddOutputIntent(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *subtype, <span class="reserved">const</span> <span class="reserved">char</span> *condition, <span class="reserved">const</span> <span class="reserved">char</span> *cond_id, <span class="reserved">const</span> <span class="reserved">char</span> *reg_name, <span class="reserved">const</span> <span class="reserved">char</span> *info, <a href="#pdfio_obj_t">pdfio_obj_t</a> *profile);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>pdf</th>
<td class="description">PDF file</td></tr>
<tr><th>subtype</th>
<td class="description">Intent subtype (standard)</td></tr>
<tr><th>condition</th>
<td class="description">Condition name or <code>NULL</code> for none</td></tr>
<tr><th>cond_id</th>
<td class="description">Identifier such as registration name or <code>NULL</code> for none</td></tr>
<tr><th>reg_name</th>
<td class="description">Registry URL or <code>NULL</code> for none</td></tr>
<tr><th>info</th>
<td class="description">Description or <code>NULL</code> for none</td></tr>
<tr><th>profile</th>
<td class="description">ICC profile object or <code>NULL</code> for none</td></tr>
</tbody></table>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function adds an OutputIntent dictionary to the PDF file catalog.
The &quot;subtype&quot; argument specifies the intent subtype and is typically
&quot;GTS_PDFX&quot; for PDF/X, &quot;GTS_PDFA1&quot; for PDF/A, or &quot;ISO_PDFE1&quot; for PDF/E.
Passing <code>NULL</code> defaults the subtype to &quot;GTS_PDFA1&quot;.<br>
<br>
The &quot;condition&quot; argument specifies a short name for the output intent, while
the &quot;info&quot; argument specifies a longer description for the output intent.
Both can be <code>NULL</code> to omit this information.<br>
<br>
The &quot;cond_id&quot; argument specifies a unique identifier such as a registration
(&quot;CGATS001&quot;) or color space name (&quot;sRGB&quot;). The &quot;reg_name&quot; argument provides
a URL for the identifier.<br>
<br>
The &quot;profile&quot; argument specifies an ICC profile object for the output
condition. If <code>NULL</code>, the PDF consumer will attempt to look up the correct
profile using the &quot;cond_id&quot; value.
</p>
<h3 class="function"><a id="pdfioFileClose">pdfioFileClose</a></h3> <h3 class="function"><a id="pdfioFileClose">pdfioFileClose</a></h3>
<p class="description">Close a PDF file and free all memory used for it.</p> <p class="description">Close a PDF file and free all memory used for it.</p>
<p class="code"> <p class="code">
@ -4196,33 +4058,8 @@ specifies the font nane:
<p class="discussion">Aside from &quot;Symbol&quot; and &quot;Zapf-Dingbats&quot;, Base fonts use the Windows CP1252 <p class="discussion">Aside from &quot;Symbol&quot; and &quot;Zapf-Dingbats&quot;, Base fonts use the Windows CP1252
(ISO-8859-1 with additional characters such as the Euro symbol) subset of (ISO-8859-1 with additional characters such as the Euro symbol) subset of
Unicode.</p> Unicode.</p>
<h3 class="function"><span class="info">&#160;PDFio v1.6&#160;</span><a id="pdfioFileCreateFontObjFromData">pdfioFileCreateFontObjFromData</a></h3>
<p class="description">Add a font in memory to a PDF file.</p>
<p class="code">
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateFontObjFromData(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">void</span> *data, size_t datasize, <span class="reserved">bool</span> unicode);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>pdf</th>
<td class="description">PDF file</td></tr>
<tr><th>data</th>
<td class="description">Font data in memory</td></tr>
<tr><th>datasize</th>
<td class="description">Size of font in memory</td></tr>
<tr><th>unicode</th>
<td class="description">Force Unicode</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">Font object</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function embeds TrueType/OpenType font data into a PDF file. The
&quot;unicode&quot; parameter controls whether the font is encoded for two-byte
characters (potentially full Unicode, but more typically a subset)
or to only support the Windows CP1252 (ISO-8859-1 with additional
characters such as the Euro symbol) subset of Unicode.
</p>
<h3 class="function"><a id="pdfioFileCreateFontObjFromFile">pdfioFileCreateFontObjFromFile</a></h3> <h3 class="function"><a id="pdfioFileCreateFontObjFromFile">pdfioFileCreateFontObjFromFile</a></h3>
<p class="description">Add a font file to a PDF file.</p> <p class="description">Add a font object to a PDF file.</p>
<p class="code"> <p class="code">
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateFontObjFromFile(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *filename, <span class="reserved">bool</span> unicode);</p> <a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateFontObjFromFile(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *filename, <span class="reserved">bool</span> unicode);</p>
<h4 class="parameters">Parameters</h4> <h4 class="parameters">Parameters</h4>
@ -4237,7 +4074,7 @@ characters such as the Euro symbol) subset of Unicode.
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description">Font object</p> <p class="description">Font object</p>
<h4 class="discussion">Discussion</h4> <h4 class="discussion">Discussion</h4>
<p class="discussion">This function embeds a TrueType/OpenType font file into a PDF file. The <p class="discussion">This function embeds a TrueType/OpenType font into a PDF file. The
&quot;unicode&quot; parameter controls whether the font is encoded for two-byte &quot;unicode&quot; parameter controls whether the font is encoded for two-byte
characters (potentially full Unicode, but more typically a subset) characters (potentially full Unicode, but more typically a subset)
or to only support the Windows CP1252 (ISO-8859-1 with additional or to only support the Windows CP1252 (ISO-8859-1 with additional
@ -4338,7 +4175,7 @@ image on the page.<br>
Note: Currently PNG support is limited to grayscale, RGB, or indexed files Note: Currently PNG support is limited to grayscale, RGB, or indexed files
without interlacing or alpha. Transparency (masking) based on color/index without interlacing or alpha. Transparency (masking) based on color/index
is supported.</blockquote> is supported.</blockquote>
<h3 class="function"><span class="info">&#160;PDFio v1.4&#160;</span><a id="pdfioFileCreateNameObj">pdfioFileCreateNameObj</a></h3> <h3 class="function"><a id="pdfioFileCreateNameObj">pdfioFileCreateNameObj</a></h3>
<p class="description">Create a new object in a PDF file containing a name.</p> <p class="description">Create a new object in a PDF file containing a name.</p>
<p class="code"> <p class="code">
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateNameObj(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *name);</p> <a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateNameObj(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *name);</p>
@ -4353,10 +4190,8 @@ is supported.</blockquote>
<p class="description">New object</p> <p class="description">New object</p>
<h4 class="discussion">Discussion</h4> <h4 class="discussion">Discussion</h4>
<p class="discussion">This function creates a new object with a name value in a PDF file. <p class="discussion">This function creates a new object with a name value in a PDF file.
You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file. You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file.</p>
<h3 class="function"><a id="pdfioFileCreateNumberObj">pdfioFileCreateNumberObj</a></h3>
</p>
<h3 class="function"><span class="info">&#160;PDFio v1.2&#160;</span><a id="pdfioFileCreateNumberObj">pdfioFileCreateNumberObj</a></h3>
<p class="description">Create a new object in a PDF file containing a number.</p> <p class="description">Create a new object in a PDF file containing a number.</p>
<p class="code"> <p class="code">
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateNumberObj(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">double</span> number);</p> <a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateNumberObj(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">double</span> number);</p>
@ -4371,9 +4206,7 @@ You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write t
<p class="description">New object</p> <p class="description">New object</p>
<h4 class="discussion">Discussion</h4> <h4 class="discussion">Discussion</h4>
<p class="discussion">This function creates a new object with a number value in a PDF file. <p class="discussion">This function creates a new object with a number value in a PDF file.
You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file. You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file.</p>
</p>
<h3 class="function"><a id="pdfioFileCreateObj">pdfioFileCreateObj</a></h3> <h3 class="function"><a id="pdfioFileCreateObj">pdfioFileCreateObj</a></h3>
<p class="description">Create a new object in a PDF file.</p> <p class="description">Create a new object in a PDF file.</p>
<p class="code"> <p class="code">
@ -4454,7 +4287,7 @@ stored as indirect object references.</blockquote>
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description">Contents stream</p> <p class="description">Contents stream</p>
<h3 class="function"><span class="info">&#160;PDFio v1.2&#160;</span><a id="pdfioFileCreateStringObj">pdfioFileCreateStringObj</a></h3> <h3 class="function"><a id="pdfioFileCreateStringObj">pdfioFileCreateStringObj</a></h3>
<p class="description">Create a new object in a PDF file containing a string.</p> <p class="description">Create a new object in a PDF file containing a string.</p>
<p class="code"> <p class="code">
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateStringObj(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *string);</p> <a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateStringObj(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *string);</p>
@ -4469,9 +4302,7 @@ stored as indirect object references.</blockquote>
<p class="description">New object</p> <p class="description">New object</p>
<h4 class="discussion">Discussion</h4> <h4 class="discussion">Discussion</h4>
<p class="discussion">This function creates a new object with a string value in a PDF file. <p class="discussion">This function creates a new object with a string value in a PDF file.
You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file. You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file.</p>
</p>
<h3 class="function"><a id="pdfioFileCreateTemporary">pdfioFileCreateTemporary</a></h3> <h3 class="function"><a id="pdfioFileCreateTemporary">pdfioFileCreateTemporary</a></h3>
<p class="description"></p> <p class="description"></p>
<p class="code"> <p class="code">
@ -4594,24 +4425,6 @@ time_t pdfioFileGetCreationDate(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf);<
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description">Keywords string or <code>NULL</code> for none</p> <p class="description">Keywords string or <code>NULL</code> for none</p>
<h3 class="function"><span class="info">&#160;PDFio 1.6&#160;</span><a id="pdfioFileGetLanguage">pdfioFileGetLanguage</a></h3>
<p class="description">Get the language metadata for a PDF file.</p>
<p class="code">
<span class="reserved">const</span> <span class="reserved">char</span> *pdfioFileGetLanguage(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>pdf</th>
<td class="description">PDF file</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">Language or <code>NULL</code> for none</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function gets the (primary/default) language metadata, if any, for a PDF
file. The returned string is an IETF BCP 47 language tag of the form
&quot;lang-REGION&quot;. For example, the string &quot;en-CA&quot; specifies Canadian English
and the string &quot;fr-CA&quot; specifies Canadian French.
</p>
<h3 class="function"><a id="pdfioFileGetModificationDate">pdfioFileGetModificationDate</a></h3> <h3 class="function"><a id="pdfioFileGetModificationDate">pdfioFileGetModificationDate</a></h3>
<p class="description">Get the most recent modification date for a PDF file.</p> <p class="description">Get the most recent modification date for a PDF file.</p>
<p class="code"> <p class="code">
@ -4818,24 +4631,6 @@ writes error messages to <code>stderr</code>.</p>
<tr><th>value</th> <tr><th>value</th>
<td class="description">Value</td></tr> <td class="description">Value</td></tr>
</tbody></table> </tbody></table>
<h3 class="function"><span class="info">&#160;PDFio 1.6&#160;</span><a id="pdfioFileSetLanguage">pdfioFileSetLanguage</a></h3>
<p class="description">Set the language metadata for a PDF file.</p>
<p class="code">
<span class="reserved">void</span> pdfioFileSetLanguage(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *value);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>pdf</th>
<td class="description">PDF file</td></tr>
<tr><th>value</th>
<td class="description">Value</td></tr>
</tbody></table>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function sets the (primary/default) language metadata for a PDF file.
The &quot;value&quot; argument is an IETF BCP 47 language tag string of the form
&quot;lang-REGION&quot;. For example, the string &quot;en-CA&quot; specifies Canadian English
and the string &quot;fr-CA&quot; specifies Canadian French.
</p>
<h3 class="function"><a id="pdfioFileSetModificationDate">pdfioFileSetModificationDate</a></h3> <h3 class="function"><a id="pdfioFileSetModificationDate">pdfioFileSetModificationDate</a></h3>
<p class="description">Set the modification date for a PDF file.</p> <p class="description">Set the modification date for a PDF file.</p>
<p class="code"> <p class="code">
@ -4907,7 +4702,7 @@ size_t pdfioImageGetBytesPerLine(<a href="#pdfio_obj_t">pdfio_obj_t</a> *obj);</
<td class="description">Image object</td></tr> <td class="description">Image object</td></tr>
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description">Number of bytes per line or <code>0</code> on error</p> <p class="description">Number of bytes per line</p>
<h3 class="function"><a id="pdfioImageGetHeight">pdfioImageGetHeight</a></h3> <h3 class="function"><a id="pdfioImageGetHeight">pdfioImageGetHeight</a></h3>
<p class="description">Get the height of an image object.</p> <p class="description">Get the height of an image object.</p>
<p class="code"> <p class="code">
@ -5012,7 +4807,7 @@ size_t pdfioObjGetLength(<a href="#pdfio_obj_t">pdfio_obj_t</a> *obj);</p>
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description">Length in bytes or <code>0</code> for none</p> <p class="description">Length in bytes or <code>0</code> for none</p>
<h3 class="function"><span class="info">&#160;PDFio v1.4&#160;</span><a id="pdfioObjGetName">pdfioObjGetName</a></h3> <h3 class="function"><a id="pdfioObjGetName">pdfioObjGetName</a></h3>
<p class="description">Get the name value associated with an object.</p> <p class="description">Get the name value associated with an object.</p>
<p class="code"> <p class="code">
<span class="reserved">const</span> <span class="reserved">char</span> *pdfioObjGetName(<a href="#pdfio_obj_t">pdfio_obj_t</a> *obj);</p> <span class="reserved">const</span> <span class="reserved">char</span> *pdfioObjGetName(<a href="#pdfio_obj_t">pdfio_obj_t</a> *obj);</p>
@ -5286,11 +5081,6 @@ ssize_t pdfioStreamPeek(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, <span
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p> <p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function writes a formatted string to a stream. In addition to the
standard <code>printf</code> format characters, you can use &quot;%H&quot; to format a HTML/XML
string value, &quot;%N&quot; to format a PDF name value (&quot;/Name&quot;), and &quot;%S&quot; to format
a PDF string (&quot;(String)&quot;) value.</p>
<h3 class="function"><a id="pdfioStreamPutChar">pdfioStreamPutChar</a></h3> <h3 class="function"><a id="pdfioStreamPutChar">pdfioStreamPutChar</a></h3>
<p class="description">Write a single character to a stream.</p> <p class="description">Write a single character to a stream.</p>
<p class="code"> <p class="code">
@ -5514,7 +5304,6 @@ typedef enum <a href="#pdfio_valtype_e">pdfio_valtype_e</a> pdfio_valtype_t;
<h4 class="constants">Constants</h4> <h4 class="constants">Constants</h4>
<table class="list"><tbody> <table class="list"><tbody>
<tr><th>PDFIO_CS_ADOBE </th><td class="description">AdobeRGB 1998</td></tr> <tr><th>PDFIO_CS_ADOBE </th><td class="description">AdobeRGB 1998</td></tr>
<tr><th>PDFIO_CS_CGATS001 </th><td class="description">CGATS001 (CMYK)</td></tr>
<tr><th>PDFIO_CS_P3_D65 </th><td class="description">Display P3</td></tr> <tr><th>PDFIO_CS_P3_D65 </th><td class="description">Display P3</td></tr>
<tr><th>PDFIO_CS_SRGB </th><td class="description">sRGB</td></tr> <tr><th>PDFIO_CS_SRGB </th><td class="description">sRGB</td></tr>
</tbody></table> </tbody></table>
@ -5525,7 +5314,7 @@ typedef enum <a href="#pdfio_valtype_e">pdfio_valtype_e</a> pdfio_valtype_t;
<tr><th>PDFIO_ENCRYPTION_AES_128 </th><td class="description">128-bit AES encryption (PDF 1.6)</td></tr> <tr><th>PDFIO_ENCRYPTION_AES_128 </th><td class="description">128-bit AES encryption (PDF 1.6)</td></tr>
<tr><th>PDFIO_ENCRYPTION_NONE </th><td class="description">No encryption</td></tr> <tr><th>PDFIO_ENCRYPTION_NONE </th><td class="description">No encryption</td></tr>
<tr><th>PDFIO_ENCRYPTION_RC4_128 </th><td class="description">128-bit RC4 encryption (PDF 1.4)</td></tr> <tr><th>PDFIO_ENCRYPTION_RC4_128 </th><td class="description">128-bit RC4 encryption (PDF 1.4)</td></tr>
<tr><th>PDFIO_ENCRYPTION_RC4_40 </th><td class="description">40-bit RC4 encryption (PDF 1.3, reading only)</td></tr> <tr><th>PDFIO_ENCRYPTION_RC4_40 </th><td class="description">40-bit RC4 encryption (PDF 1.3)</td></tr>
</tbody></table> </tbody></table>
<h3 class="enumeration"><a id="pdfio_filter_e">pdfio_filter_e</a></h3> <h3 class="enumeration"><a id="pdfio_filter_e">pdfio_filter_e</a></h3>
<p class="description">Compression/decompression filters for streams</p> <p class="description">Compression/decompression filters for streams</p>

View File

@ -889,26 +889,11 @@ main(int argc, // I - Number of command-line arguments
{ {
const char *filename; // PDF filename const char *filename; // PDF filename
pdfio_file_t *pdf; // PDF file pdfio_file_t *pdf; // PDF file
pdfio_dict_t *catalog; // Catalog dictionary const char *author; // Author name
const char *author, // Author name time_t creation_date; // Creation date
*creator, // Creator name struct tm *creation_tm; // Creation date/time information
*producer, // Producer name char creation_text[256]; // Creation date/time as a string
*title; // Title const char *title; // Title
time_t creation_date, // Creation date
modification_date; // Modification date
struct tm *creation_tm, // Creation date/time information
*modification_tm; // Modification date/time information
char creation_text[256], // Creation date/time as a string
modification_text[256], // Modification date/time human fmt string
range_text[255]; // Page range text
size_t num_pages; // PDF number of pages
bool has_acroform; // Does the file have an AcroForm?
pdfio_obj_t *page; // Object
pdfio_dict_t *page_dict; // Object dictionary
size_t cur, // Current page index
prev; // Previous page index
pdfio_rect_t cur_box, // Current MediaBox
prev_box; // Previous MediaBox
// Get the filename from the command-line... // Get the filename from the command-line...
@ -921,19 +906,13 @@ main(int argc, // I - Number of command-line arguments
filename = argv[1]; filename = argv[1];
// Open the PDF file with the default callbacks... // Open the PDF file with the default callbacks...
pdf = pdfioFileOpen(filename, /*password_cb*/NULL, pdf = pdfioFileOpen(filename, /*password_cb*/NULL, /*password_cbdata*/NULL,
/*password_cbdata*/NULL, /*error_cb*/NULL, /*error_cb*/NULL, /*error_cbdata*/NULL);
/*error_cbdata*/NULL);
if (pdf == NULL) if (pdf == NULL)
return (1); return (1);
// Get the title, author, etc... // Get the title and author...
catalog = pdfioFileGetCatalog(pdf);
author = pdfioFileGetAuthor(pdf); author = pdfioFileGetAuthor(pdf);
creator = pdfioFileGetCreator(pdf);
has_acroform = pdfioDictGetType(catalog, "AcroForm") != PDFIO_VALTYPE_NONE;
num_pages = pdfioFileGetNumPages(pdf);
producer = pdfioFileGetProducer(pdf);
title = pdfioFileGetTitle(pdf); title = pdfioFileGetTitle(pdf);
// Get the creation date and convert to a string... // Get the creation date and convert to a string...
@ -947,76 +926,12 @@ main(int argc, // I - Number of command-line arguments
snprintf(creation_text, sizeof(creation_text), "-- not set --"); snprintf(creation_text, sizeof(creation_text), "-- not set --");
} }
// Get the modification date and convert to a string...
if ((modification_date = pdfioFileGetModificationDate(pdf)) > 0)
{
modification_tm = localtime(&modification_date);
strftime(modification_text, sizeof(modification_text), "%c", modification_tm);
}
else
{
snprintf(modification_text, sizeof(modification_text), "-- not set --");
}
// Print file information to stdout... // Print file information to stdout...
printf("%s:\n", filename); printf("%s:\n", filename);
printf(" Title: %s\n", title ? title : "-- not set --"); printf(" Title: %s\n", title ? title : "-- not set --");
printf(" Author: %s\n", author ? author : "-- not set --"); printf(" Author: %s\n", author ? author : "-- not set --");
printf(" Creator: %s\n", creator ? creator : "-- not set --");
printf(" Producer: %s\n", producer ? producer : "-- not set --");
printf(" Created On: %s\n", creation_text); printf(" Created On: %s\n", creation_text);
printf(" Modified On: %s\n", modification_text); printf(" Number Pages: %u\n", (unsigned)pdfioFileGetNumPages(pdf));
printf(" Version: %s\n", pdfioFileGetVersion(pdf));
printf(" AcroForm: %s\n", has_acroform ? "Yes" : "No");
printf(" Number of Pages: %u\n", (unsigned)num_pages);
// Report the MediaBox for all of the pages
prev_box.x1 = prev_box.x2 = prev_box.y1 = prev_box.y2 = 0.0;
for (cur = 0, prev = 0; cur < num_pages; cur ++)
{
// Find the MediaBox for this page in the page tree...
for (page = pdfioFileGetPage(pdf, cur);
page != NULL;
page = pdfioDictGetObj(page_dict, "Parent"))
{
cur_box.x1 = cur_box.x2 = cur_box.y1 = cur_box.y2 = 0.0;
page_dict = pdfioObjGetDict(page);
if (pdfioDictGetRect(page_dict, "MediaBox", &cur_box))
break;
}
// If this MediaBox is different from the previous one, show the range of
// pages that have that size...
if (cur == 0 ||
fabs(cur_box.x1 - prev_box.x1) > 0.01 ||
fabs(cur_box.y1 - prev_box.y1) > 0.01 ||
fabs(cur_box.x2 - prev_box.x2) > 0.01 ||
fabs(cur_box.y2 - prev_box.y2) > 0.01)
{
if (cur > prev)
{
snprintf(range_text, sizeof(range_text), "Pages %u-%u",
(unsigned)(prev + 1), (unsigned)cur);
printf("%16s: [%g %g %g %g]\n", range_text,
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
}
// Start a new series of pages with the new size...
prev = cur;
prev_box = cur_box;
}
}
// Show the last range as needed...
if (cur > prev)
{
snprintf(range_text, sizeof(range_text), "Pages %u-%u",
(unsigned)(prev + 1), (unsigned)cur);
printf("%16s: [%g %g %g %g]\n", range_text,
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
}
// Close the PDF file... // Close the PDF file...
pdfioFileClose(pdf); pdfioFileClose(pdf);

View File

@ -68,7 +68,7 @@ main(int argc, // I - Number of command-line arguments
catalog = pdfioFileGetCatalog(pdf); catalog = pdfioFileGetCatalog(pdf);
author = pdfioFileGetAuthor(pdf); author = pdfioFileGetAuthor(pdf);
creator = pdfioFileGetCreator(pdf); creator = pdfioFileGetCreator(pdf);
has_acroform = pdfioDictGetType(catalog, "AcroForm") != PDFIO_VALTYPE_NONE; has_acroform = pdfioDictGetObj(catalog, "AcroForm") != NULL ? true : false;
num_pages = pdfioFileGetNumPages(pdf); num_pages = pdfioFileGetNumPages(pdf);
producer = pdfioFileGetProducer(pdf); producer = pdfioFileGetProducer(pdf);
title = pdfioFileGetTitle(pdf); title = pdfioFileGetTitle(pdf);

View File

@ -32,11 +32,11 @@ if test $(grep AC_INIT configure.ac | awk '{print $2}') != "[$version],"; then
status=1 status=1
fi fi
if test $(head -5 CHANGES.md | tail -1 | awk '{print $1}') != "v$version"; then if test $(head -4 CHANGES.md | tail -1 | awk '{print $1}') != "v$version"; then
echo "Still need to update CHANGES.md version number." echo "Still need to update CHANGES.md version number."
status=1 status=1
fi fi
if test $(head -5 CHANGES.md | tail -1 | awk '{print $3}') = "YYYY-MM-DD"; then if test $(head -4 CHANGES.md | tail -1 | awk '{print $3}') = "YYYY-MM-DD"; then
echo "Still need to update CHANGES.md release date." echo "Still need to update CHANGES.md release date."
status=1 status=1
fi fi

View File

@ -640,8 +640,6 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
// //
// 'pdfioArrayRemove()' - Remove an array entry. // 'pdfioArrayRemove()' - Remove an array entry.
// //
// @since PDFio v1.4@
//
bool // O - `true` on success, `false` otherwise bool // O - `true` on success, `false` otherwise
pdfioArrayRemove(pdfio_array_t *a, // I - Array pdfioArrayRemove(pdfio_array_t *a, // I - Array

View File

@ -1,532 +0,0 @@
/* CGATS001Compat-v2-micro.icc */
static unsigned char CGATS001Compat_v2_micro_icc[] = {
0,0,33,16,65,68,66,69,2,16,0,0,115,99,110,114,
67,77,89,75,76,97,98,32,7,230,0,12,0,7,0,22,
0,16,0,42,97,99,115,112,77,83,70,84,0,0,0,0,
115,97,119,115,99,116,114,108,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,246,214,0,1,0,0,0,0,211,45,
104,97,110,100,195,103,209,209,26,217,105,182,62,57,156,48,
22,179,165,88,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,4,100,101,115,99,0,0,0,180,0,0,0,95,
99,112,114,116,0,0,0,208,0,0,0,12,119,116,112,116,
0,0,0,220,0,0,0,20,65,50,66,48,0,0,0,240,
0,0,32,32,100,101,115,99,0,0,0,0,0,0,0,5,
117,67,77,89,0,0,0,0,0,0,0,0,0,0,0,0,
116,101,120,116,0,0,0,0,67,67,48,0,88,89,90,32,
0,0,0,0,0,0,246,214,0,1,0,0,0,0,211,45,
109,102,116,50,0,0,0,0,4,3,6,0,0,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
0,48,0,2,0,0,10,35,16,0,22,155,28,150,35,8,
41,37,47,68,53,83,59,90,65,90,71,78,77,74,83,48,
89,25,94,245,100,188,106,133,112,43,117,193,123,79,128,187,
134,23,139,107,144,166,149,206,154,244,160,21,165,30,170,40,
175,51,180,64,185,71,190,81,195,91,200,103,205,100,210,85,
215,65,220,33,224,252,229,190,234,87,238,218,243,138,248,23,
252,104,255,255,0,0,8,214,13,206,19,98,24,129,30,6,
35,77,40,160,46,0,51,86,56,193,62,41,67,165,73,37,
78,162,84,51,89,175,95,46,100,173,106,10,111,107,116,191,
121,244,127,36,132,82,137,98,142,111,147,127,152,147,157,151,
162,172,167,211,173,14,178,88,183,186,189,52,194,199,200,90,
205,244,211,154,217,72,223,1,228,146,234,19,239,215,245,132,
251,7,255,255,0,0,9,30,14,44,19,200,24,222,30,99,
35,150,40,200,45,246,51,35,56,84,61,138,66,209,72,33,
77,126,82,234,88,89,93,211,99,74,104,190,110,47,115,148,
120,237,126,59,131,126,136,180,141,231,147,29,152,90,157,169,
163,18,168,158,174,79,180,41,186,39,192,69,198,114,204,164,
210,199,216,201,222,161,228,73,233,160,238,170,243,244,248,186,
252,225,255,255,0,0,8,135,13,57,18,115,23,60,28,123,
33,106,38,94,43,92,48,99,53,110,58,133,63,163,68,202,
73,244,79,35,84,77,89,109,94,139,99,158,104,170,109,176,
114,172,119,156,124,135,129,112,134,74,139,35,143,254,148,223,
153,201,158,194,163,209,168,251,174,67,179,163,185,36,190,202,
196,145,202,125,208,133,214,166,220,240,227,93,234,118,241,193,
249,40,255,255,255,0,128,0,128,0,214,110,127,181,126,251,
173,86,127,150,126,88,131,53,127,186,126,83,86,78,128,50,
126,192,31,100,129,254,128,28,251,120,125,171,146,104,211,247,
125,155,142,161,171,46,125,194,139,106,129,32,126,37,136,221,
84,57,126,196,134,230,28,170,128,62,134,99,248,103,123,237,
165,11,209,76,123,249,158,148,168,209,124,68,152,192,127,22,
124,213,147,218,82,110,125,139,143,116,26,73,126,145,140,106,
245,211,122,201,183,251,206,211,122,205,174,205,166,160,123,35,
166,133,125,42,123,200,159,52,80,217,124,141,151,243,24,82,
125,10,144,4,243,199,122,9,203,97,204,207,121,247,191,95,
164,205,122,74,180,169,123,179,123,1,171,70,79,144,123,201,
163,159,22,200,123,191,143,103,242,42,121,140,223,132,203,50,
121,98,208,125,163,73,121,169,195,108,122,115,122,107,184,86,
78,150,123,56,174,96,21,158,122,200,142,157,227,233,142,168,
125,57,191,208,140,54,124,173,154,204,138,30,124,141,116,50,
136,124,124,247,74,84,135,121,125,199,20,34,137,177,127,236,
224,239,140,172,141,230,189,193,138,73,138,227,152,241,136,91,
136,116,114,87,134,238,134,171,72,129,134,18,133,143,18,45,
135,202,133,165,222,108,139,13,159,8,187,88,136,200,153,179,
150,192,134,245,148,251,112,129,133,173,145,24,70,249,132,229,
142,34,16,97,134,27,137,235,220,58,137,245,176,93,185,57,
135,184,168,203,148,204,133,239,161,238,110,212,132,170,155,243,
69,169,131,235,151,169,15,9,132,165,138,43,218,113,137,45,
194,46,183,137,134,242,184,87,147,63,133,43,175,95,109,144,
131,243,167,166,68,161,131,41,161,166,14,7,131,135,137,124,
217,12,136,152,212,229,182,53,134,99,200,164,145,250,132,152,
189,153,108,133,131,103,180,155,67,209,130,165,170,33,13,68,
130,183,136,248,201,213,157,235,123,46,169,121,153,123,122,234,
136,53,149,117,123,19,101,12,146,14,123,193,62,13,143,191,
124,214,9,84,144,204,127,187,199,84,156,73,138,107,167,205,
151,198,136,7,134,185,147,217,134,42,99,150,144,153,132,246,
60,167,142,98,132,135,8,113,142,126,132,36,197,113,154,202,
153,237,165,235,150,98,149,123,132,247,146,119,145,165,98,4,
143,82,142,167,59,93,141,42,140,19,7,182,140,158,133,55,
195,166,153,193,169,229,164,50,149,94,163,134,131,66,145,135,
157,217,96,149,142,92,153,26,58,81,140,51,150,79,7,25,
139,41,132,204,194,42,153,10,186,48,162,214,148,166,177,236,
129,253,144,210,170,123,95,138,141,175,164,116,57,139,139,110,
159,13,6,174,138,21,132,132,192,255,152,123,203,106,161,198,
148,25,193,44,128,245,144,72,184,9,94,179,141,45,177,103,
56,235,138,244,165,100,6,89,137,77,132,75,177,37,173,245,
122,2,147,243,167,169,121,209,117,242,161,206,122,23,85,235,
156,180,122,225,49,88,150,201,124,2,0,239,149,92,127,195,
175,57,172,141,135,237,146,202,166,25,133,179,116,224,160,67,
132,66,84,210,155,60,131,120,48,93,152,11,131,193,0,226,
147,96,128,133,173,202,171,58,150,19,145,79,164,217,146,68,
115,118,159,2,143,29,83,154,154,5,140,217,47,124,150,201,
140,54,0,206,145,182,128,139,172,145,170,52,164,133,144,19,
163,219,159,13,114,58,158,5,154,89,82,143,152,241,150,198,
46,202,149,168,148,235,0,217,144,85,128,147,171,106,169,130,
179,137,143,32,163,20,172,85,113,80,157,63,162,160,81,202,
152,62,161,248,46,73,148,212,155,139,0,219,143,72,128,148,
170,119,169,1,195,84,142,87,162,131,186,91,112,151,156,179,
178,242,81,58,151,186,174,21,45,236,148,82,159,13,0,222,
142,134,128,150,154,49,190,221,121,79,127,198,182,195,121,6,
100,136,175,54,121,74,71,42,168,146,122,23,36,45,165,99,
123,14,0,0,143,153,128,0,152,249,189,121,134,22,127,13,
181,72,132,75,99,211,173,165,130,235,70,115,166,244,130,111,
35,202,163,124,130,239,0,0,142,213,128,0,152,46,188,21,
146,252,126,42,179,238,143,148,98,240,172,64,140,239,69,182,
165,143,139,90,35,118,161,226,138,239,0,0,142,33,128,0,
151,95,187,20,156,183,125,105,178,222,152,248,98,53,171,44,
148,44,69,34,164,102,145,119,35,60,160,141,143,228,0,0,
141,150,128,0,150,186,186,65,173,194,124,235,177,250,167,108,
97,205,170,70,162,133,68,210,163,131,159,209,35,33,159,106,
150,67,0,0,141,57,128,0,150,10,185,176,188,68,124,138,
177,69,180,40,97,126,169,128,174,82,68,159,162,198,170,52,
35,38,158,179,151,196,0,0,140,230,128,0,132,180,208,159,
120,243,108,190,198,205,120,107,83,203,189,201,120,144,56,144,
181,241,121,63,22,242,178,158,122,81,0,0,137,249,128,0,
132,84,206,246,132,213,108,102,197,80,130,218,83,105,188,24,
129,168,56,75,180,0,129,93,23,73,176,8,130,10,0,0,
138,37,128,0,132,67,205,78,144,147,108,56,195,164,141,107,
83,48,186,79,139,41,56,52,178,35,138,58,23,180,173,196,
137,41,0,0,138,73,128,0,132,35,203,251,156,155,108,55,
194,41,152,56,83,60,184,196,149,21,56,85,176,133,148,4,
24,42,171,234,144,154,0,0,138,101,128,0,131,240,202,242,
168,242,108,66,193,0,163,54,83,110,183,140,159,100,56,150,
175,80,157,234,24,158,170,120,144,165,0,0,138,121,128,0,
131,190,202,18,181,197,108,88,192,13,174,136,83,181,182,138,
170,24,56,250,174,76,165,33,25,38,169,99,145,1,0,0,
138,136,128,0,235,21,120,95,117,172,198,143,121,103,118,146,
160,155,122,106,119,154,120,244,123,117,120,218,78,61,124,157,
122,46,24,103,126,52,123,43,231,220,117,150,135,222,195,241,
118,230,133,232,158,88,120,46,132,101,118,244,121,124,131,68,
76,100,122,195,129,102,22,11,123,166,130,96,228,245,115,130,
154,56,193,46,116,236,149,151,155,232,118,93,145,116,116,232,
119,221,141,248,74,174,121,54,138,229,19,252,121,133,135,196,
226,139,114,5,172,159,190,208,115,112,165,140,153,177,116,238,
158,247,114,251,118,134,153,19,73,38,119,231,148,52,18,94,
119,220,139,241,224,194,113,11,191,52,189,12,114,105,181,200,
151,244,115,224,172,209,113,127,117,135,164,211,71,234,118,225,
158,108,17,36,118,168,139,151,223,129,112,120,210,33,187,195,
113,192,198,94,150,146,115,32,187,38,112,68,116,200,177,102,
70,235,118,28,168,223,16,59,117,202,138,249,209,115,134,135,
115,123,177,87,133,101,116,211,143,52,132,136,118,40,106,212,
131,237,119,166,66,203,131,210,121,44,13,68,133,161,122,166,
207,74,132,21,132,44,175,136,131,38,130,252,141,102,130,108,
130,15,105,23,129,246,129,111,65,44,129,242,129,3,11,242,
131,47,128,187,204,230,130,32,148,250,173,11,129,68,145,118,
139,42,128,171,142,60,103,60,128,104,139,143,63,171,128,112,
137,123,10,160,129,38,133,169,202,204,128,181,165,229,170,253,
127,222,160,68,137,59,127,80,154,224,101,154,127,25,150,30,
62,106,127,39,146,206,9,181,127,147,134,144,201,66,127,194,
183,38,169,111,126,232,175,109,135,176,126,82,167,231,100,77,
126,40,161,100,61,104,126,40,156,138,9,4,126,105,134,24,
200,52,127,42,201,23,168,66,126,72,191,65,134,106,125,151,
181,160,99,54,125,111,173,200,60,152,125,113,164,221,8,120,
125,143,133,186,184,173,149,106,113,228,156,34,146,61,115,98,
125,114,143,136,116,221,92,54,141,74,118,127,54,161,140,45,
120,8,3,238,139,88,123,49,182,255,147,72,129,49,154,137,
144,64,128,123,123,227,141,162,127,240,90,199,139,126,127,190,
53,89,138,93,127,196,3,128,136,228,128,74,181,64,145,117,
144,98,152,169,142,132,141,169,122,46,139,240,139,55,89,77,
137,236,137,71,52,47,136,204,136,38,3,22,134,234,130,22,
179,141,144,32,160,3,151,4,141,51,155,112,120,129,138,173,
151,29,87,228,136,172,147,114,51,37,135,135,145,82,2,193,
133,95,129,221,178,73,143,62,175,217,149,185,140,83,169,123,
119,61,137,196,163,94,86,209,135,201,158,101,50,96,134,132,
153,234,2,137,132,59,129,182,177,102,142,167,192,110,148,187,
139,188,184,74,118,48,137,28,176,117,85,236,135,30,170,208,
49,180,133,217,160,46,2,88,131,104,129,150,161,39,165,31,
112,232,135,104,160,39,114,94,107,178,155,186,115,225,77,78,
151,243,117,130,41,135,150,141,118,177,0,66,137,171,126,52,
160,0,163,78,126,58,134,90,158,94,125,202,106,159,153,235,
126,68,76,76,150,41,126,114,40,187,148,150,126,116,0,60,
135,218,127,249,158,179,161,163,140,195,132,230,156,194,138,139,
105,69,152,84,136,161,75,40,148,163,135,100,39,242,146,245,
134,224,0,50,134,74,128,34,157,132,160,84,154,226,131,173,
155,126,151,25,104,13,151,13,147,166,74,49,147,72,145,0,
39,88,145,123,143,118,0,46,133,35,128,31,156,138,159,124,
169,118,130,195,154,160,164,33,103,23,150,32,159,51,73,88,
146,97,155,208,38,210,144,100,150,43,0,40,132,62,128,27,
155,211,158,242,184,169,130,0,154,13,177,217,102,77,149,124,
171,165,72,175,145,184,167,171,38,95,143,176,153,237,0,36,
131,152,128,24,139,20,181,218,112,19,115,151,175,83,113,97,
90,95,169,85,114,209,62,89,164,67,116,78,27,220,162,240,
117,20,0,0,132,76,128,0,138,120,180,61,125,106,115,25,
173,150,124,255,89,217,167,107,124,81,61,228,162,62,124,151,
27,203,160,109,125,6,0,0,131,187,128,0,137,192,178,136,
137,145,114,53,171,233,135,226,88,255,165,185,134,144,61,56,
160,141,133,174,27,150,158,104,133,23,0,0,131,37,128,0,
136,247,177,65,150,121,113,106,170,160,145,137,88,50,164,101,
144,140,60,162,159,30,142,229,27,110,156,173,140,81,0,0,
130,194,128,0,136,101,176,88,163,151,112,222,169,174,159,42,
87,167,163,100,155,105,60,52,158,16,153,106,27,92,155,60,
144,208,0,0,130,140,128,0,135,225,175,208,177,149,112,130,
169,4,171,225,87,60,162,144,167,47,59,221,157,49,163,199,
27,68,154,81,146,112,0,0,130,90,128,0,118,47,199,165,
111,81,96,137,191,214,112,85,73,93,184,132,113,146,47,37,
178,156,114,188,14,114,176,12,115,215,0,0,129,66,128,0,
118,37,198,9,123,103,96,145,189,252,122,224,73,95,182,83,
122,140,47,79,176,27,122,242,15,16,173,6,123,149,0,0,
129,65,128,0,118,26,196,25,134,225,96,81,188,12,133,19,
73,32,180,78,131,219,47,67,173,249,131,127,15,152,170,90,
131,15,0,0,129,64,128,0,117,232,194,153,146,128,96,44,
186,112,143,187,72,249,178,157,141,124,47,72,172,34,141,8,
16,17,168,31,136,88,0,0,129,63,128,0,117,180,193,153,
158,127,96,36,185,65,154,198,72,250,177,80,152,1,47,90,
170,197,151,16,16,120,166,98,139,34,0,0,129,63,128,0,
117,138,192,236,171,6,96,44,184,93,166,88,73,12,176,73,
163,22,47,127,169,175,158,184,16,201,165,41,139,89,0,0,
129,62,128,0,215,58,112,125,107,98,182,48,114,183,110,9,
147,81,116,191,112,146,110,79,118,168,115,18,69,242,120,110,
117,99,17,41,122,4,118,21,212,37,109,25,125,61,179,174,
111,175,125,19,145,41,114,6,125,27,108,110,116,58,125,82,
68,67,118,17,125,118,15,115,119,100,124,211,209,76,106,99,
143,18,176,232,109,33,140,81,142,189,111,175,137,216,106,111,
114,31,135,215,66,173,115,252,133,236,14,12,117,65,131,106,
206,240,104,112,160,225,174,148,107,62,155,216,140,130,109,225,
150,255,104,143,112,110,146,160,65,64,114,73,142,92,12,238,
115,154,136,44,205,74,103,27,178,184,172,233,105,229,171,138,
138,211,108,132,164,100,103,24,111,33,157,249,64,30,112,232,
153,0,12,32,114,96,136,51,204,67,102,85,196,179,171,201,
105,11,187,103,137,134,107,139,178,19,101,232,110,39,169,242,
63,37,113,29,163,2,11,134,113,150,135,202,191,51,125,253,
105,204,162,88,126,40,108,203,130,244,126,117,111,124,96,224,
126,227,114,20,58,181,127,161,116,87,6,250,129,135,117,232,
189,59,122,243,122,101,160,121,123,114,122,237,129,38,123,241,
123,66,95,70,124,136,123,210,57,87,125,61,124,104,6,56,
126,240,124,161,186,231,120,104,138,147,158,7,121,10,136,216,
126,247,121,180,135,50,93,119,122,128,133,202,55,236,123,44,
132,147,5,122,125,75,129,223,184,229,118,148,155,6,156,7,
119,69,151,69,125,15,119,255,147,122,91,227,120,220,144,16,
54,189,121,122,141,190,4,240,123,230,131,75,183,122,117,78,
171,160,154,140,117,255,165,231,123,150,118,180,160,18,90,158,
119,159,154,248,53,206,120,29,151,54,4,139,123,11,131,18,
182,151,116,140,188,154,153,124,117,45,180,249,122,105,117,198,
173,42,89,148,118,175,166,195,52,247,119,27,159,91,4,58,
122,75,130,219,168,10,140,102,104,152,142,157,138,129,107,167,
114,84,137,23,110,98,83,5,136,13,112,248,46,178,136,50,
114,232,0,0,134,1,119,195,166,152,137,165,119,142,140,252,
136,21,120,113,112,187,134,199,121,68,81,165,133,209,122,43,
45,147,133,199,122,111,0,0,131,203,125,115,164,228,135,58,
134,91,139,30,133,208,133,102,111,24,132,156,132,87,80,93,
131,190,131,134,44,163,131,149,130,248,0,0,129,242,128,0,
163,51,133,129,149,157,137,135,132,33,146,220,109,118,130,247,
143,243,78,252,130,37,141,109,43,168,129,222,139,252,0,0,
128,80,128,0,162,3,132,83,164,223,136,69,130,249,160,109,
108,52,129,194,155,194,77,229,128,243,151,242,42,242,128,117,
148,112,0,0,128,0,128,0,161,66,131,152,180,173,135,81,
130,59,174,155,107,41,128,225,168,60,77,1,128,10,163,180,
42,74,127,120,154,175,0,0,128,0,128,0,145,188,155,172,
103,193,122,194,152,25,106,174,97,34,149,28,109,90,68,88,
146,185,111,205,33,58,147,6,113,3,0,0,128,158,125,23,
144,178,153,85,117,117,121,161,149,241,118,113,96,7,146,235,
119,201,67,104,144,128,120,192,32,163,144,90,120,208,0,0,
128,83,127,160,143,100,151,24,131,16,120,32,147,209,130,146,
94,175,144,218,130,3,66,85,142,130,129,188,32,1,142,10,
128,235,0,0,128,0,128,0,142,45,149,108,144,194,118,226,
146,54,142,170,93,120,143,61,140,135,65,117,140,210,138,222,
31,136,140,18,137,181,0,0,128,0,128,0,141,62,148,80,
158,204,117,254,145,26,155,76,92,129,142,10,151,180,64,146,
139,158,149,70,31,15,138,141,145,227,0,0,128,0,128,0,
140,159,147,161,173,59,117,64,144,98,168,119,91,182,141,51,
163,160,63,227,138,184,160,184,30,155,137,127,148,146,0,0,
128,0,128,0,124,171,172,10,102,190,103,126,167,39,105,111,
80,11,162,201,107,245,53,57,159,120,110,24,19,165,158,208,
111,20,0,0,128,0,128,0,123,249,170,24,116,224,102,230,
165,24,117,140,79,132,160,128,117,94,52,226,156,255,118,88,
19,187,155,193,119,9,0,0,128,0,128,0,123,42,167,228,
127,253,101,234,162,244,127,85,78,167,158,94,127,12,52,67,
154,215,126,238,19,159,153,39,127,38,0,0,128,0,128,0,
122,87,166,68,140,182,101,22,161,89,139,59,77,209,156,183,
137,52,51,180,153,17,136,91,19,135,150,246,134,122,0,0,
128,0,128,0,121,194,165,30,152,238,100,130,160,44,150,73,
77,54,155,119,147,192,51,58,151,189,146,136,19,131,149,48,
139,58,0,0,128,0,128,0,121,80,164,119,166,54,100,51,
159,99,162,165,76,201,154,118,159,46,50,220,150,162,156,195,
19,98,147,245,141,27,0,0,128,0,128,0,104,127,189,181,
101,120,84,142,183,253,103,201,62,206,178,149,106,4,37,57,
175,32,107,133,7,201,168,185,110,103,0,0,128,0,128,0,
104,19,188,17,113,56,84,117,181,220,113,249,62,221,175,253,
114,239,37,150,172,20,115,158,8,71,165,174,118,13,0,0,
128,0,128,0,103,206,185,191,124,128,84,14,179,133,124,35,
62,146,173,145,124,7,37,152,169,115,124,23,8,149,163,10,
125,3,0,0,128,0,128,0,103,132,183,243,135,237,83,215,
177,160,134,186,62,83,171,151,133,157,37,151,167,69,133,155,
8,210,160,225,134,24,0,0,128,0,128,0,103,71,182,193,
147,197,83,203,176,53,145,186,62,65,170,12,143,228,37,150,
165,157,143,124,9,4,159,47,134,25,0,0,128,0,128,0,
103,34,182,5,159,118,83,218,175,42,156,247,62,66,168,216,
154,228,37,162,164,81,151,207,9,28,157,237,134,41,0,0,
128,0,128,0,195,134,104,39,97,50,165,143,107,98,101,100,
133,177,110,87,105,86,99,107,113,26,109,23,61,117,115,78,
112,105,10,197,118,146,113,155,192,120,99,196,114,159,163,37,
103,127,116,32,131,159,106,221,117,164,97,161,109,247,119,42,
59,237,112,35,120,108,9,208,115,227,120,197,189,150,96,56,
131,182,160,101,100,60,130,212,129,66,103,227,130,4,95,178,
107,69,129,80,58,117,109,94,128,220,8,252,114,54,127,181,
187,44,93,116,149,0,158,28,97,167,145,220,127,29,101,119,
142,191,93,247,105,0,139,222,57,48,106,248,136,228,8,98,
114,207,133,15,185,130,91,150,166,49,156,129,95,216,160,239,
125,137,99,178,155,159,92,152,103,80,150,226,56,49,105,27,
147,108,7,231,114,249,133,88,184,132,90,105,183,86,155,115,
94,161,175,238,124,98,98,101,168,131,91,140,105,1,162,44,
55,84,103,155,156,250,7,143,115,57,133,29,173,93,116,242,
96,48,147,55,118,74,100,152,118,92,119,176,104,140,86,142,
121,30,108,57,50,50,122,128,111,45,2,87,126,109,114,86,
171,85,112,240,112,28,145,91,114,194,114,35,116,164,116,109,
115,251,85,28,118,12,117,186,49,17,119,53,119,0,2,43,
125,195,121,110,168,240,109,150,128,2,142,230,111,169,127,232,
114,129,113,144,127,187,83,92,115,109,127,135,47,194,116,98,
127,74,1,226,125,94,127,32,166,228,106,254,143,238,140,233,
109,54,141,221,112,164,111,63,139,156,81,229,113,51,137,125,
46,184,113,233,136,69,1,188,125,70,129,22,165,119,105,58,
159,231,139,118,107,126,155,238,111,59,109,141,151,183,80,175,
111,144,148,16,45,231,112,10,145,123,1,153,125,77,129,20,
164,153,104,24,176,2,138,114,106,82,170,42,110,35,111,42,
164,16,79,186,110,75,159,42,45,29,110,151,153,133,1,123,
125,127,129,0,151,185,130,155,95,107,128,155,130,26,99,200,
102,131,129,250,103,171,73,25,130,36,107,48,37,224,131,72,
109,106,0,0,128,15,119,32,150,37,126,232,109,252,126,233,
126,222,112,71,100,238,126,239,114,85,71,211,127,49,116,50,
36,254,127,224,117,40,0,0,128,0,125,1,148,89,123,191,
124,214,124,252,123,247,125,43,99,88,124,49,125,116,70,157,
124,147,125,171,36,61,124,241,125,162,0,0,128,0,128,0,
146,160,121,84,139,48,123,96,121,170,138,25,97,182,121,248,
136,132,69,80,122,100,134,203,35,88,122,135,134,48,0,0,
128,0,128,0,145,107,119,175,153,210,122,36,120,16,150,250,
96,132,120,91,147,207,68,71,120,200,145,64,34,188,120,174,
142,195,0,0,128,0,128,0,144,162,120,93,168,186,121,57,
120,129,164,90,95,144,120,148,159,155,67,117,120,204,156,88,
34,21,119,83,148,183,0,0,128,0,128,0,130,198,145,99,
94,162,109,209,143,77,98,193,86,12,141,196,102,123,58,184,
140,221,105,176,24,115,141,200,107,28,0,0,128,0,124,73,
129,132,142,31,107,235,108,146,140,92,110,64,84,240,138,218,
113,211,57,230,137,229,115,138,24,36,138,59,114,239,0,0,
128,0,127,132,128,22,139,40,121,37,107,6,137,153,122,194,
83,165,136,48,123,82,56,243,135,70,123,12,23,189,135,58,
123,75,0,0,128,0,128,0,126,190,136,215,135,50,105,197,
135,98,134,150,82,127,133,248,133,151,56,76,132,242,133,17,
23,130,132,161,132,185,0,0,128,0,128,0,125,190,135,83,
147,232,104,226,133,228,145,251,81,131,132,98,143,208,55,90,
131,82,142,43,23,27,130,174,140,195,0,0,128,0,128,0,
125,14,134,79,161,162,104,29,132,220,158,145,80,187,131,56,
154,254,54,173,130,12,153,42,22,191,129,62,143,48,0,0,
128,0,128,0,110,138,161,103,93,113,91,64,158,36,97,61,
69,98,155,115,100,180,43,134,154,24,103,87,11,238,152,5,
105,90,0,0,128,0,127,174,109,133,158,164,105,164,90,112,
155,103,107,227,68,195,152,129,109,252,43,62,150,221,111,137,
12,25,148,105,113,67,0,0,128,0,128,0,108,132,155,200,
117,179,89,77,152,172,118,164,67,211,149,207,119,119,42,162,
148,24,120,5,12,19,145,67,121,90,0,0,128,0,128,0,
107,134,153,143,129,221,88,92,150,130,129,173,66,235,147,154,
129,73,42,24,145,180,129,15,12,0,142,157,128,215,0,0,
128,0,128,0,106,209,152,11,143,26,87,176,149,0,141,197,
66,62,146,3,140,0,41,140,143,253,139,52,12,1,140,140,
133,216,0,0,128,0,128,0,106,74,151,18,154,199,87,83,
147,243,152,208,65,214,144,186,150,118,41,61,142,132,149,10,
11,233,139,8,136,14,0,0,128,0,128,0,90,217,179,10,
91,159,72,146,175,35,94,239,52,17,171,191,97,242,26,122,
171,135,99,103,2,147,158,4,105,195,0,0,128,0,128,0,
89,242,176,188,102,234,72,22,172,122,104,233,51,223,168,163,
106,202,26,208,167,186,107,134,3,13,154,120,113,121,0,0,
128,0,128,0,89,104,173,222,113,237,71,119,169,158,114,221,
51,113,165,180,115,185,26,205,164,114,115,225,3,91,151,84,
119,101,0,0,128,0,128,0,88,225,171,136,125,19,71,16,
167,63,125,46,51,16,163,58,125,29,26,204,161,154,125,2,
3,150,148,166,126,188,0,0,128,0,128,0,88,127,169,250,
136,100,70,230,165,137,135,210,50,233,161,96,135,19,26,190,
159,136,135,59,3,199,146,155,130,61,0,0,128,0,128,0,
88,66,168,239,147,235,70,221,164,67,146,236,50,224,159,237,
145,204,26,206,157,221,143,133,3,222,145,7,130,157,0,0,
128,0,128,0,176,156,94,195,87,72,149,115,98,233,92,217,
120,99,102,205,98,34,88,182,106,104,103,28,53,1,108,159,
107,102,5,152,118,139,109,251,173,120,88,199,104,44,147,0,
93,173,107,60,118,78,98,35,110,48,86,244,102,42,113,1,
51,155,104,36,115,88,5,62,119,36,117,123,170,129,83,218,
120,230,144,69,89,66,121,155,116,3,94,37,122,79,85,27,
98,129,123,12,50,72,100,77,123,164,4,235,119,176,124,186,
167,244,79,239,137,125,142,8,85,186,136,49,114,1,90,231,
134,220,83,144,95,120,133,94,49,50,97,23,132,122,4,171,
120,27,130,105,166,29,76,244,153,245,140,119,83,4,150,99,
112,161,88,98,146,223,82,98,93,18,143,209,48,103,94,148,
141,222,4,128,120,101,131,11,165,1,75,27,170,73,139,111,
81,61,164,132,111,168,86,158,159,0,81,141,91,86,154,125,
47,181,92,180,151,6,4,90,120,165,130,241,156,106,106,192,
86,220,132,107,109,76,92,113,105,223,111,205,97,148,76,63,
114,46,102,77,41,113,115,222,105,208,0,133,127,32,112,194,
154,6,101,52,102,67,130,120,104,112,105,168,104,51,107,92,
108,201,74,235,109,253,111,166,40,136,111,123,113,155,0,121,
127,52,119,248,151,123,96,136,117,195,127,250,100,52,119,22,
102,27,103,124,120,55,73,62,106,97,121,62,39,94,107,182,
121,207,0,101,127,85,125,231,149,85,92,216,133,116,125,254,
96,208,133,45,100,78,100,86,131,234,71,229,103,88,131,7,
38,123,104,160,130,168,0,90,127,104,128,21,147,206,90,13,
148,102,124,145,94,51,145,245,98,253,97,219,143,75,70,199,
100,234,141,18,37,213,102,40,139,156,0,82,127,118,128,55,
146,221,88,74,163,183,123,146,92,123,159,112,97,255,96,28,
154,247,69,241,99,40,151,144,37,38,100,94,147,151,0,74,
127,132,128,50,136,83,119,164,86,119,114,249,120,152,91,224,
90,200,121,197,96,207,63,24,123,14,101,47,28,228,124,239,
103,177,0,0,128,0,118,153,134,86,114,117,100,134,113,39,
116,9,104,12,89,55,117,132,107,62,61,232,118,232,110,10,
28,63,120,131,111,111,0,0,128,0,124,173,132,83,110,13,
114,153,111,34,112,8,116,89,87,166,113,196,117,216,60,195,
115,69,119,23,27,177,116,190,119,163,0,0,128,0,128,0,
130,119,106,149,129,11,109,119,108,205,130,35,86,4,110,179,
128,158,59,134,112,55,128,143,26,244,113,202,129,140,0,0,
128,0,128,0,129,36,103,242,142,177,108,51,106,79,140,179,
84,214,108,70,139,126,58,135,109,187,138,52,26,128,111,130,
137,83,0,0,128,0,128,0,128,71,102,62,157,11,107,73,
104,167,154,28,83,238,106,146,150,196,57,196,107,241,148,173,
25,237,109,244,142,180,0,0,128,0,128,0,116,102,133,188,
85,206,97,9,133,77,90,232,74,225,133,71,95,143,48,197,
133,211,99,100,15,223,135,31,101,112,0,0,128,0,123,165,
114,183,129,2,98,152,95,147,129,17,102,24,73,174,129,44,
105,65,47,247,129,153,107,201,15,177,130,194,109,55,0,0,
128,0,127,79,113,14,124,224,111,119,93,220,125,64,113,115,
72,73,125,135,115,40,46,243,125,235,116,107,15,86,127,106,
117,126,0,0,128,0,128,0,111,138,121,149,124,88,92,114,
122,42,124,241,71,9,122,128,125,56,46,66,122,185,125,99,
15,42,124,159,125,207,0,0,128,0,128,0,110,95,119,23,
138,202,91,117,119,207,138,10,70,19,120,28,137,0,45,94,
120,38,135,245,14,222,122,140,135,102,0,0,128,0,128,0,
109,149,121,89,150,108,90,170,121,119,148,158,69,84,118,115,
146,87,44,190,118,78,145,129,14,137,120,225,137,87,0,0,
128,0,128,0,96,221,149,113,84,82,79,24,147,218,89,8,
58,133,146,240,93,68,32,234,148,5,96,5,5,223,142,72,
100,242,0,0,128,0,127,76,95,109,145,55,96,1,77,234,
143,234,99,97,57,154,142,232,102,93,32,131,143,118,104,29,
6,7,138,144,108,199,0,0,128,0,128,0,94,36,141,70,
107,194,76,143,140,50,109,216,56,136,139,63,111,156,31,218,
139,127,112,111,5,254,135,60,116,52,0,0,128,0,128,0,
92,237,138,30,122,85,75,113,137,51,120,146,55,133,136,57,
121,39,31,91,136,14,123,110,5,246,132,117,123,118,0,0,
128,0,128,0,91,246,135,172,131,111,74,141,134,231,131,84,
54,186,133,222,130,234,30,202,133,72,130,209,6,11,130,149,
129,136,0,0,128,0,128,0,91,71,134,25,143,189,74,30,
133,105,142,218,54,108,132,29,141,96,30,192,131,24,140,170,
6,8,129,66,132,20,0,0,128,0,128,0,77,84,167,52,
81,238,60,225,164,229,86,29,41,102,163,178,89,171,15,187,
165,245,91,30,0,0,143,192,102,232,0,0,128,0,128,0,
76,0,163,132,92,179,59,195,161,83,95,199,40,139,159,206,
98,84,15,179,160,234,99,35,0,0,141,58,110,94,0,0,
128,0,128,0,75,38,159,158,103,107,58,198,157,140,105,113,
39,202,155,249,107,4,15,139,156,80,107,83,0,0,138,237,
113,76,0,0,128,0,128,0,74,77,156,103,114,86,58,10,
154,119,115,117,39,52,152,188,116,26,15,133,152,85,116,52,
0,33,136,220,120,138,0,0,128,0,128,0,73,149,153,242,
125,109,57,132,152,31,125,200,38,211,150,60,125,178,15,95,
149,64,125,240,0,63,135,71,127,146,0,0,128,0,128,0,
73,42,152,77,136,216,57,58,150,125,136,168,38,173,148,107,
136,30,15,114,147,1,134,175,0,80,134,33,128,54,0,0,
128,0,128,0,158,251,83,213,77,213,134,82,88,228,84,162,
107,209,93,194,91,44,78,135,98,47,97,81,44,208,100,17,
102,124,1,123,125,128,107,25,155,163,75,156,94,40,131,186,
81,193,98,171,105,163,87,113,102,252,76,186,92,94,107,9,
43,127,94,109,110,93,1,148,125,85,114,218,152,136,68,110,
110,104,128,251,75,123,112,169,103,104,81,210,114,214,74,252,
87,33,116,232,42,89,89,132,118,188,1,168,125,50,122,87,
149,187,62,95,127,39,126,199,70,68,127,37,101,151,77,45,
126,223,73,179,82,194,126,247,41,128,85,129,127,2,1,184,
125,23,128,57,147,155,57,144,141,195,125,55,66,42,139,246,
100,109,73,147,138,142,72,188,79,81,137,33,40,239,82,91,
136,147,1,196,125,4,129,50,146,51,54,15,157,180,124,41,
63,34,153,134,99,178,70,225,149,233,72,51,76,186,147,48,
40,130,79,242,145,93,1,205,124,245,129,56,140,172,95,13,
78,0,118,82,98,194,84,136,93,217,102,97,90,197,66,68,
105,148,96,126,32,220,108,22,100,131,0,0,128,0,112,38,
137,166,87,69,92,206,116,43,92,3,97,107,92,39,96,73,
101,193,64,246,99,194,105,173,32,26,102,123,108,69,0,0,
128,0,119,103,134,217,80,99,107,214,113,151,85,234,110,117,
90,18,90,193,112,228,63,85,94,121,115,18,31,23,97,180,
116,108,0,0,128,0,125,112,132,131,74,171,122,184,111,150,
80,207,123,118,88,87,86,26,124,13,62,35,89,237,124,145,
30,107,94,103,125,47,0,0,128,0,127,202,130,209,70,47,
137,129,110,40,76,204,136,111,87,33,82,108,135,54,61,36,
86,56,134,85,29,248,92,10,133,252,0,0,128,0,128,0,
129,180,66,231,151,227,109,43,73,215,149,17,86,72,79,164,
146,42,60,121,83,93,144,56,29,122,90,173,141,217,0,0,
128,0,128,0,122,59,107,13,78,9,101,239,109,128,84,51,
79,94,111,248,90,17,53,66,114,34,95,58,20,89,117,114,
98,63,0,0,128,0,118,48,119,113,99,183,91,125,99,224,
103,9,96,10,77,191,105,251,100,71,52,13,108,44,103,232,
19,212,112,104,105,245,0,0,128,0,124,88,117,9,93,44,
105,29,97,175,97,41,107,247,76,39,100,134,110,150,50,241,
102,174,112,192,19,113,108,243,114,23,0,0,128,0,128,0,
114,243,87,180,118,223,95,234,92,47,120,23,74,129,95,218,
121,16,49,195,97,217,121,223,18,225,106,136,122,228,0,0,
128,0,128,0,113,120,83,101,132,147,94,155,88,59,132,58,
73,87,92,22,131,141,48,207,93,197,131,35,18,148,104,170,
130,227,0,0,128,0,128,0,112,124,80,47,145,214,93,175,
85,72,144,47,72,123,89,48,142,34,48,28,90,139,141,35,
18,32,103,124,136,248,0,0,128,0,128,0,103,70,120,84,
77,117,84,232,121,161,83,63,64,11,123,28,88,172,38,210,
124,209,92,243,8,233,127,70,96,200,0,0,128,0,123,34,
100,213,113,135,89,167,83,25,115,126,94,24,62,167,117,48,
98,36,37,231,118,126,101,44,8,193,123,161,104,123,0,0,
128,0,127,24,98,194,107,80,102,30,81,34,109,203,105,23,
61,29,111,188,107,190,36,205,112,158,109,148,8,119,120,180,
112,173,0,0,128,0,128,0,96,242,102,12,114,156,79,130,
104,236,116,47,59,191,107,0,117,116,36,18,107,82,118,75,
8,91,118,101,120,166,0,0,128,0,128,0,95,146,97,206,
130,67,78,97,101,12,129,141,58,188,103,46,129,182,35,42,
103,31,127,144,8,40,116,175,127,220,0,0,128,0,128,0,
94,161,94,147,139,177,77,129,98,16,138,232,57,241,100,48,
137,174,34,137,99,241,137,147,7,229,115,133,132,115,0,0,
128,0,128,0,84,37,135,119,75,195,67,155,135,178,81,48,
48,13,136,148,86,4,22,132,139,57,88,202,1,153,133,28,
97,193,0,0,128,0,126,220,82,13,129,47,86,229,65,224,
129,244,91,44,46,166,130,201,94,217,21,210,132,77,96,184,
1,163,129,218,105,124,0,0,128,0,128,0,80,85,123,60,
98,71,64,40,124,97,101,75,45,71,125,64,103,204,20,248,
126,25,104,210,1,154,127,79,110,152,0,0,128,0,128,0,
78,197,118,17,114,119,62,180,119,146,116,238,44,4,120,106,
118,37,20,83,121,5,113,106,1,147,125,213,117,185,0,0,
128,0,128,0,77,131,113,206,121,100,61,140,115,179,122,30,
43,13,116,126,122,121,19,183,117,62,122,187,1,164,125,57,
126,172,0,0,128,0,128,0,76,158,110,125,133,67,60,216,
112,196,133,20,42,153,113,118,132,123,19,130,114,86,132,73,
1,142,125,96,129,13,0,0,128,0,128,0,64,153,153,69,
72,171,49,169,152,158,77,168,30,160,153,228,81,115,6,90,
154,60,83,247,0,0,130,209,102,37,0,0,128,0,128,0,
62,163,147,140,82,227,47,151,147,139,86,215,28,182,148,160,
89,168,5,183,147,71,91,203,0,0,128,103,109,199,0,0,
128,0,128,0,61,68,141,206,93,80,46,3,142,29,96,44,
27,97,143,2,98,7,5,78,141,29,99,223,0,0,128,0,
117,60,0,0,128,0,128,0,59,244,136,146,104,3,44,191,
137,80,105,212,26,96,137,238,106,205,5,45,136,30,108,152,
0,0,128,0,123,80,0,0,128,0,128,0,58,216,132,48,
114,233,43,191,133,110,115,203,25,174,133,218,116,14,4,250,
132,101,118,30,0,0,128,0,127,34,0,0,128,0,128,0,
58,13,128,170,126,39,42,253,130,99,126,61,25,57,130,182,
126,10,4,241,129,178,126,213,0,0,128,0,128,0,0,0,
128,0,128,0,0,0,255,255,0,0,255,255,0,0,255,255
};

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
// //
// Public content header file for PDFio. // Public content header file for PDFio.
// //
// Copyright © 2021-2025 by Michael R Sweet. // Copyright © 2021-2023 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -23,8 +23,7 @@ typedef enum pdfio_cs_e // Standard color spaces
{ {
PDFIO_CS_ADOBE, // AdobeRGB 1998 PDFIO_CS_ADOBE, // AdobeRGB 1998
PDFIO_CS_P3_D65, // Display P3 PDFIO_CS_P3_D65, // Display P3
PDFIO_CS_SRGB, // sRGB PDFIO_CS_SRGB // sRGB
PDFIO_CS_CGATS001 // CGATS001 (CMYK)
} pdfio_cs_t; } pdfio_cs_t;
typedef enum pdfio_linecap_e // Line capping modes typedef enum pdfio_linecap_e // Line capping modes
@ -128,9 +127,7 @@ extern bool pdfioContentTextShowf(pdfio_stream_t *st, bool unicode, const char
extern bool pdfioContentTextShowJustified(pdfio_stream_t *st, bool unicode, size_t num_fragments, const double *offsets, const char * const *fragments) _PDFIO_PUBLIC; extern bool pdfioContentTextShowJustified(pdfio_stream_t *st, bool unicode, size_t num_fragments, const double *offsets, const char * const *fragments) _PDFIO_PUBLIC;
// Resource helpers... // Resource helpers...
extern void pdfioFileAddOutputIntent(pdfio_file_t *pdf, const char *subtype, const char *condition, const char *cond_id, const char *reg_name, const char *info, pdfio_obj_t *profile) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateFontObjFromBase(pdfio_file_t *pdf, const char *name) _PDFIO_PUBLIC; extern pdfio_obj_t *pdfioFileCreateFontObjFromBase(pdfio_file_t *pdf, const char *name) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateFontObjFromData(pdfio_file_t *pdf, const void *data, size_t datasize, bool unicode) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateFontObjFromFile(pdfio_file_t *pdf, const char *filename, bool unicode) _PDFIO_PUBLIC; extern pdfio_obj_t *pdfioFileCreateFontObjFromFile(pdfio_file_t *pdf, const char *filename, bool unicode) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateICCObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t datalen, size_t num_colors) _PDFIO_PUBLIC; extern pdfio_obj_t *pdfioFileCreateICCObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t datalen, size_t num_colors) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateICCObjFromFile(pdfio_file_t *pdf, const char *filename, size_t num_colors) _PDFIO_PUBLIC; extern pdfio_obj_t *pdfioFileCreateICCObjFromFile(pdfio_file_t *pdf, const char *filename, size_t num_colors) _PDFIO_PUBLIC;

View File

@ -409,6 +409,13 @@ _pdfioCryptoMakeReader(
uint8_t data[21]; // Key data uint8_t data[21]; // Key data
_pdfio_md5_t md5; // MD5 state _pdfio_md5_t md5; // MD5 state
uint8_t digest[16]; // MD5 digest value uint8_t digest[16]; // MD5 digest value
#if PDFIO_OBJ_CRYPT
pdfio_array_t *id_array; // Object ID array
unsigned char *id_value; // Object ID value
size_t id_len; // Length of object ID
uint8_t temp_key[16]; // File key for object
#endif // PDFIO_OBJ_CRYPT
uint8_t *file_key; // Computed file key to use
PDFIO_DEBUG("_pdfioCryptoMakeReader(pdf=%p, obj=%p(%d), ctx=%p, iv=%p, ivlen=%p(%d))\n", pdf, obj, (int)obj->number, ctx, iv, ivlen, (int)*ivlen); PDFIO_DEBUG("_pdfioCryptoMakeReader(pdf=%p, obj=%p(%d), ctx=%p, iv=%p, ivlen=%p(%d))\n", pdf, obj, (int)obj->number, ctx, iv, ivlen, (int)*ivlen);
@ -420,6 +427,60 @@ _pdfioCryptoMakeReader(
return (NULL); return (NULL);
} }
#if PDFIO_OBJ_CRYPT
if ((id_array = pdfioDictGetArray(pdfioObjGetDict(obj), "ID")) != NULL)
{
// Object has its own ID that will get used for encryption...
_pdfio_md5_t md5; // MD5 context
uint8_t file_digest[16]; // MD5 digest of file ID and pad
uint8_t user_pad[32], // Padded user password
own_user_key[32], // Calculated user key
pdf_user_key[32]; // Decrypted user key
PDFIO_DEBUG("_pdfioCryptoMakeReader: Per-object file ID.\n");
if ((id_value = pdfioArrayGetBinary(id_array, 0, &id_len)) == NULL)
{
*ivlen = 0;
return (NULL);
}
_pdfioCryptoMD5Init(&md5);
_pdfioCryptoMD5Append(&md5, pdf_passpad, 32);
_pdfioCryptoMD5Append(&md5, id_value, id_len);
_pdfioCryptoMD5Finish(&md5, file_digest);
make_owner_key(pdf->encryption, pdf->password, pdf->owner_key, user_pad);
make_file_key(pdf->encryption, pdf->permissions, id_value, id_len, user_pad, pdf->owner_key, temp_key);
make_user_key(id_value, id_len, own_user_key);
if (memcmp(own_user_key, pdf->user_key, sizeof(own_user_key)))
{
PDFIO_DEBUG("_pdfioCryptoMakeReader: Not user password, trying owner password.\n");
make_file_key(pdf->encryption, pdf->permissions, id_value, id_len, pdf->password, pdf->owner_key, temp_key);
make_user_key(id_value, id_len, own_user_key);
memcpy(pdf_user_key, pdf->user_key, sizeof(pdf_user_key));
decrypt_user_key(pdf->encryption, temp_key, pdf_user_key);
if (memcmp(pdf->password, pdf_user_key, 32) && memcmp(own_user_key, pdf_user_key, 16))
{
_pdfioFileError(pdf, "Unable to unlock file.");
*ivlen = 0;
return (NULL);
}
}
file_key = temp_key;
}
else
#endif // PDFIO_OBJ_CRYPT
{
// Use the default file key...
file_key = pdf->file_key;
}
switch (pdf->encryption) switch (pdf->encryption)
{ {
default : default :
@ -429,20 +490,20 @@ _pdfioCryptoMakeReader(
case PDFIO_ENCRYPTION_RC4_40 : case PDFIO_ENCRYPTION_RC4_40 :
// Copy the key data for the MD5 hash. // Copy the key data for the MD5 hash.
memcpy(data, pdf->file_key, 5); memcpy(data, file_key, 16);
data[5] = (uint8_t)obj->number; data[16] = (uint8_t)obj->number;
data[6] = (uint8_t)(obj->number >> 8); data[17] = (uint8_t)(obj->number >> 8);
data[7] = (uint8_t)(obj->number >> 16); data[18] = (uint8_t)(obj->number >> 16);
data[8] = (uint8_t)obj->generation; data[19] = (uint8_t)obj->generation;
data[9] = (uint8_t)(obj->generation >> 8); data[20] = (uint8_t)(obj->generation >> 8);
// Hash it... // Hash it...
_pdfioCryptoMD5Init(&md5); _pdfioCryptoMD5Init(&md5);
_pdfioCryptoMD5Append(&md5, data, 10); _pdfioCryptoMD5Append(&md5, data, sizeof(data));
_pdfioCryptoMD5Finish(&md5, digest); _pdfioCryptoMD5Finish(&md5, digest);
// Initialize the RC4 context using 80 bits of the digest... // Initialize the RC4 context using 40 bits of the digest...
_pdfioCryptoRC4Init(&ctx->rc4, digest, 10); _pdfioCryptoRC4Init(&ctx->rc4, digest, 5);
*ivlen = 0; *ivlen = 0;
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt); return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
@ -456,7 +517,7 @@ _pdfioCryptoMakeReader(
case PDFIO_ENCRYPTION_RC4_128 : case PDFIO_ENCRYPTION_RC4_128 :
// Copy the key data for the MD5 hash. // Copy the key data for the MD5 hash.
memcpy(data, pdf->file_key, 16); memcpy(data, file_key, 16);
data[16] = (uint8_t)obj->number; data[16] = (uint8_t)obj->number;
data[17] = (uint8_t)(obj->number >> 8); data[17] = (uint8_t)(obj->number >> 8);
data[18] = (uint8_t)(obj->number >> 16); data[18] = (uint8_t)(obj->number >> 16);

View File

@ -20,8 +20,6 @@ static int compare_pairs(_pdfio_pair_t *a, _pdfio_pair_t *b);
// //
// 'pdfioDictClear()' - Remove a key/value pair from a dictionary. // 'pdfioDictClear()' - Remove a key/value pair from a dictionary.
// //
// @since PDFio v1.4@
//
bool // O - `true` if cleared, `false` otherwise bool // O - `true` if cleared, `false` otherwise
pdfioDictClear(pdfio_dict_t *dict, // I - Dictionary pdfioDictClear(pdfio_dict_t *dict, // I - Dictionary
@ -347,8 +345,6 @@ pdfioDictGetDict(pdfio_dict_t *dict, // I - Dictionary
// //
// 'pdfioDictGetKey()' - Get the key for the specified pair. // 'pdfioDictGetKey()' - Get the key for the specified pair.
// //
// @since PDFio v1.4@
//
const char * // O - Key for specified pair const char * // O - Key for specified pair
pdfioDictGetKey(pdfio_dict_t *dict, // I - Dictionary pdfioDictGetKey(pdfio_dict_t *dict, // I - Dictionary
@ -379,8 +375,6 @@ pdfioDictGetName(pdfio_dict_t *dict, // I - Dictionary
// //
// 'pdfioDictGetNumPairs()' - Get the number of key/value pairs in a dictionary. // 'pdfioDictGetNumPairs()' - Get the number of key/value pairs in a dictionary.
// //
// @since PDFio v1.4@
//
size_t // O - Number of pairs size_t // O - Number of pairs
pdfioDictGetNumPairs(pdfio_dict_t *dict)// I - Dictionary pdfioDictGetNumPairs(pdfio_dict_t *dict)// I - Dictionary
@ -471,12 +465,127 @@ pdfioDictGetString(pdfio_dict_t *dict, // I - Dictionary
else if (value && value->type == PDFIO_VALTYPE_BINARY && value->value.binary.datalen < 4096) else if (value && value->type == PDFIO_VALTYPE_BINARY && value->value.binary.datalen < 4096)
{ {
// Convert binary string to regular string... // Convert binary string to regular string...
char temp[4096]; // Temporary UTF-8 string char temp[4096], // Temporary string
*tempptr; // Pointer into temporary string
unsigned char *dataptr; // Pointer into the data string
if (!(value->value.binary.datalen & 1) && (!memcmp(value->value.binary.data, "\376\377", 2) || !memcmp(value->value.binary.data, "\377\376", 2))) if (!(value->value.binary.datalen & 1) && !memcmp(value->value.binary.data, "\376\377", 2))
{ {
// Copy UTF-16... // Copy UTF-16 BE
_pdfio_utf16cpy(temp, value->value.binary.data, value->value.binary.datalen, sizeof(temp)); int ch; // Unicode character
size_t remaining; // Remaining bytes
for (dataptr = value->value.binary.data + 2, remaining = value->value.binary.datalen - 2, tempptr = temp; remaining > 1 && tempptr < (temp + sizeof(temp) - 5); dataptr += 2, remaining -= 2)
{
ch = (dataptr[0] << 8) | dataptr[1];
if (ch >= 0xd800 && ch <= 0xdbff && remaining > 3)
{
// Multi-word UTF-16 char...
int lch; // Lower bits
lch = (dataptr[2] << 8) | dataptr[3];
if (lch < 0xdc00 || lch >= 0xdfff)
break;
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
dataptr += 2;
remaining -= 2;
}
else if (ch >= 0xfffe)
{
continue;
}
if (ch < 128)
{
// ASCII
*tempptr++ = (char)ch;
}
else if (ch < 4096)
{
// 2-byte UTF-8
*tempptr++ = (char)(0xc0 | (ch >> 6));
*tempptr++ = (char)(0x80 | (ch & 0x3f));
}
else if (ch < 65536)
{
// 3-byte UTF-8
*tempptr++ = (char)(0xe0 | (ch >> 12));
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
*tempptr++ = (char)(0x80 | (ch & 0x3f));
}
else
{
// 4-byte UTF-8
*tempptr++ = (char)(0xe0 | (ch >> 18));
*tempptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
*tempptr++ = (char)(0x80 | (ch & 0x3f));
}
}
*tempptr = '\0';
}
else if (!(value->value.binary.datalen & 1) && !memcmp(value->value.binary.data, "\377\376", 2))
{
// Copy UTF-16 LE
int ch; // Unicode character
size_t remaining; // Remaining bytes
for (dataptr = value->value.binary.data + 2, remaining = value->value.binary.datalen - 2, tempptr = temp; remaining > 1 && tempptr < (temp + sizeof(temp) - 5); dataptr += 2, remaining -= 2)
{
ch = (dataptr[1] << 8) | dataptr[0];
if (ch >= 0xd800 && ch <= 0xdbff && remaining > 3)
{
// Multi-word UTF-16 char...
int lch; // Lower bits
lch = (dataptr[3] << 8) | dataptr[2];
if (lch < 0xdc00 || lch >= 0xdfff)
break;
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
dataptr += 2;
remaining -= 2;
}
else if (ch >= 0xfffe)
{
continue;
}
if (ch < 128)
{
// ASCII
*tempptr++ = (char)ch;
}
else if (ch < 4096)
{
// 2-byte UTF-8
*tempptr++ = (char)(0xc0 | (ch >> 6));
*tempptr++ = (char)(0x80 | (ch & 0x3f));
}
else if (ch < 65536)
{
// 3-byte UTF-8
*tempptr++ = (char)(0xe0 | (ch >> 12));
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
*tempptr++ = (char)(0x80 | (ch & 0x3f));
}
else
{
// 4-byte UTF-8
*tempptr++ = (char)(0xe0 | (ch >> 18));
*tempptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
*tempptr++ = (char)(0x80 | (ch & 0x3f));
}
}
*tempptr = '\0';
} }
else else
{ {
@ -568,8 +677,6 @@ _pdfioDictGetValue(pdfio_dict_t *dict, // I - Dictionary
// The iteration continues as long as the callback returns `true` or all keys // The iteration continues as long as the callback returns `true` or all keys
// have been iterated. // have been iterated.
// //
// @since PDFio v1.1@
//
void void
pdfioDictIterateKeys( pdfioDictIterateKeys(
@ -630,6 +737,11 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
_pdfioFileError(pdf, "Invalid dictionary contents."); _pdfioFileError(pdf, "Invalid dictionary contents.");
break; break;
} }
else if (_pdfioDictGetValue(dict, key + 1))
{
_pdfioFileError(pdf, "Duplicate dictionary key '%s'.", key + 1);
return (NULL);
}
// Then get the next value... // Then get the next value...
PDFIO_DEBUG("_pdfioDictRead: Reading value for '%s'.\n", key + 1); PDFIO_DEBUG("_pdfioDictRead: Reading value for '%s'.\n", key + 1);
@ -639,15 +751,8 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
_pdfioFileError(pdf, "Missing value for dictionary key '%s'.", key + 1); _pdfioFileError(pdf, "Missing value for dictionary key '%s'.", key + 1);
break; break;
} }
else if (_pdfioDictGetValue(dict, key + 1))
{ if (!_pdfioDictSetValue(dict, pdfioStringCreate(pdf, key + 1), &value))
// Issue 118: Discard duplicate key/value pairs, in the future this will
// be a warning message...
_pdfioFileError(pdf, "WARNING: Discarding value for duplicate dictionary key '%s'.", key + 1);
_pdfioValueDelete(&value);
continue;
}
else if (!_pdfioDictSetValue(dict, pdfioStringCreate(pdf, key + 1), &value))
break; break;
PDFIO_DEBUG("_pdfioDictRead: Set %s.\n", key); PDFIO_DEBUG("_pdfioDictRead: Set %s.\n", key);

View File

@ -8,7 +8,6 @@
// //
#include "pdfio-private.h" #include "pdfio-private.h"
#include "pdfio-content.h"
#ifndef O_BINARY #ifndef O_BINARY
# define O_BINARY 0 # define O_BINARY 0
#endif // !O_BINARY #endif // !O_BINARY
@ -22,13 +21,11 @@ static pdfio_obj_t *add_obj(pdfio_file_t *pdf, size_t number, unsigned short gen
static int compare_objmaps(_pdfio_objmap_t *a, _pdfio_objmap_t *b); static int compare_objmaps(_pdfio_objmap_t *a, _pdfio_objmap_t *b);
static pdfio_file_t *create_common(const char *filename, int fd, pdfio_output_cb_t output_cb, void *output_cbdata, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_cbdata); static pdfio_file_t *create_common(const char *filename, int fd, pdfio_output_cb_t output_cb, void *output_cbdata, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_cbdata);
static const char *get_info_string(pdfio_file_t *pdf, const char *key); static const char *get_info_string(pdfio_file_t *pdf, const char *key);
static char *get_iso_date(time_t t, char *buffer, size_t bufsize);
static struct lconv *get_lconv(void); static struct lconv *get_lconv(void);
static bool load_obj_stream(pdfio_obj_t *obj); static bool load_obj_stream(pdfio_obj_t *obj);
static bool load_pages(pdfio_file_t *pdf, pdfio_obj_t *obj, size_t depth); static bool load_pages(pdfio_file_t *pdf, pdfio_obj_t *obj, size_t depth);
static bool load_xref(pdfio_file_t *pdf, off_t xref_offset, pdfio_password_cb_t password_cb, void *password_data); static bool load_xref(pdfio_file_t *pdf, off_t xref_offset, pdfio_password_cb_t password_cb, void *password_data);
static bool repair_xref(pdfio_file_t *pdf, pdfio_password_cb_t password_cb, void *password_data); static bool repair_xref(pdfio_file_t *pdf, pdfio_password_cb_t password_cb, void *password_data);
static bool write_metadata(pdfio_file_t *pdf);
static bool write_pages(pdfio_file_t *pdf); static bool write_pages(pdfio_file_t *pdf);
static bool write_trailer(pdfio_file_t *pdf); static bool write_trailer(pdfio_file_t *pdf);
@ -113,8 +110,6 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file
{ {
bool ret = true; // Return value bool ret = true; // Return value
size_t i; // Looping var size_t i; // Looping var
_pdfio_strbuf_t *current, // Current string buffer
*next; // Next string buffer
// Range check input // Range check input
@ -126,11 +121,7 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file
{ {
ret = false; ret = false;
// Add default OutputIntent for PDF/A CMYK printing... if (pdfioObjClose(pdf->info_obj) && write_pages(pdf) && pdfioObjClose(pdf->root_obj) && write_trailer(pdf))
pdfioFileAddOutputIntent(pdf, /*subtype*/"GTS_PDFA1", /*condition*/"CMYK", /*cond_id*/"CGATS001", /*reg_name*/NULL, /*info*/"CMYK Printing", /*profile*/NULL);
// Close and write out the last bits...
if (write_metadata(pdf) && pdfioObjClose(pdf->info_obj) && write_pages(pdf) && pdfioObjClose(pdf->root_obj) && write_trailer(pdf))
ret = _pdfioFileFlush(pdf); ret = _pdfioFileFlush(pdf);
} }
@ -161,12 +152,6 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file
free(pdf->strings[i]); free(pdf->strings[i]);
free(pdf->strings); free(pdf->strings);
for (current = pdf->strbuffers; current; current = next)
{
next = current->next;
free(current);
}
free(pdf); free(pdf);
return (ret); return (ret);
@ -267,8 +252,6 @@ pdfioFileCreateArrayObj(
// This function creates a new object with a name value in a PDF file. // This function creates a new object with a name value in a PDF file.
// You must call @link pdfioObjClose@ to write the object to the file. // You must call @link pdfioObjClose@ to write the object to the file.
// //
// @since PDFio v1.4@
//
pdfio_obj_t * // O - New object pdfio_obj_t * // O - New object
pdfioFileCreateNameObj( pdfioFileCreateNameObj(
@ -298,8 +281,6 @@ pdfioFileCreateNameObj(
// This function creates a new object with a number value in a PDF file. // This function creates a new object with a number value in a PDF file.
// You must call @link pdfioObjClose@ to write the object to the file. // You must call @link pdfioObjClose@ to write the object to the file.
// //
// @since PDFio v1.2@
//
pdfio_obj_t * // O - New object pdfio_obj_t * // O - New object
pdfioFileCreateNumberObj( pdfioFileCreateNumberObj(
@ -485,9 +466,8 @@ pdfioFileCreatePage(pdfio_file_t *pdf, // I - PDF file
pdfioDictSetObj(dict, "Parent", pdf->pages_obj); pdfioDictSetObj(dict, "Parent", pdf->pages_obj);
pdfioPageDictAddColorSpace(dict, "DefaultGray", pdfioArrayCreateColorFromStandard(pdf, 1, PDFIO_CS_SRGB)); if (!_pdfioDictGetValue(dict, "Resources"))
pdfioPageDictAddColorSpace(dict, "DefaultRGB", pdfioArrayCreateColorFromStandard(pdf, 3, PDFIO_CS_SRGB)); pdfioDictSetDict(dict, "Resources", pdfioDictCreate(pdf));
pdfioPageDictAddColorSpace(dict, "DefaultCMYK", pdfioArrayCreateColorFromStandard(pdf, 4, PDFIO_CS_CGATS001));
if (!_pdfioDictGetValue(dict, "Type")) if (!_pdfioDictGetValue(dict, "Type"))
pdfioDictSetName(dict, "Type", "Page"); pdfioDictSetName(dict, "Type", "Page");
@ -530,8 +510,6 @@ pdfioFileCreatePage(pdfio_file_t *pdf, // I - PDF file
// This function creates a new object with a string value in a PDF file. // This function creates a new object with a string value in a PDF file.
// You must call @link pdfioObjClose@ to write the object to the file. // You must call @link pdfioObjClose@ to write the object to the file.
// //
// @since PDFio v1.2@
//
pdfio_obj_t * // O - New object pdfio_obj_t * // O - New object
pdfioFileCreateStringObj( pdfioFileCreateStringObj(
@ -838,24 +816,6 @@ pdfioFileGetKeywords(pdfio_file_t *pdf) // I - PDF file
} }
//
// 'pdfioFileGetLanguage()' - Get the language metadata for a PDF file.
//
// This function gets the (primary/default) language metadata, if any, for a PDF
// file. The returned string is an IETF BCP 47 language tag of the form
// "lang-REGION". For example, the string "en-CA" specifies Canadian English
// and the string "fr-CA" specifies Canadian French.
//
// @since PDFio 1.6@
//
const char * // O - Language or `NULL` for none
pdfioFileGetLanguage(pdfio_file_t *pdf) // I - PDF file
{
return (pdfioDictGetString(pdfioFileGetCatalog(pdf), "Lang"));
}
// //
// 'pdfioFileGetModificationDate()' - Get the most recent modification date for a PDF file. // 'pdfioFileGetModificationDate()' - Get the most recent modification date for a PDF file.
// //
@ -1196,26 +1156,6 @@ pdfioFileSetKeywords(
} }
//
// 'pdfioFileSetLanguage()' - Set the language metadata for a PDF file.
//
// This function sets the (primary/default) language metadata for a PDF file.
// The "value" argument is an IETF BCP 47 language tag string of the form
// "lang-REGION". For example, the string "en-CA" specifies Canadian English
// and the string "fr-CA" specifies Canadian French.
//
// @since PDFio 1.6@
//
void
pdfioFileSetLanguage(
pdfio_file_t *pdf, // I - PDF file
const char *value) // I - Value
{
pdfioDictSetString(pdfioFileGetCatalog(pdf), "Lang", value);
}
// //
// 'pdfioFileSetModificationDate()' - Set the modification date for a PDF file. // 'pdfioFileSetModificationDate()' - Set the modification date for a PDF file.
// //
@ -1582,32 +1522,6 @@ get_info_string(pdfio_file_t *pdf, // I - PDF file
} }
//
// 'get_iso_date()' - Convert a time_t value to an ISO 8601 date/time value.
//
static char * // O - Date string
get_iso_date(time_t t, // I - Time value in seconds
char *buffer, // I - Date buffer
size_t bufsize) // I - Size of date buffer
{
struct tm d; // Date values
// Convert time to UTC date
#if _WIN32
gmtime_s(&d, &t);
#else
gmtime_r(&t, &d);
#endif // _WIN32
// Format the string and return...
snprintf(buffer, bufsize, "%04d-%02d-%02dT%02d:%02d:%02dZ", d.tm_year + 1900, d.tm_mon + 1, d.tm_mday, d.tm_hour, d.tm_min, d.tm_sec);
return (buffer);
}
// //
// 'get_lconv()' - Get any locale-specific numeric information. // 'get_lconv()' - Get any locale-specific numeric information.
// //
@ -2296,9 +2210,6 @@ repair_xref(
pdfio_obj_t *sobjs[16384]; // Object streams to load pdfio_obj_t *sobjs[16384]; // Object streams to load
// Let caller know something is wrong...
_pdfioFileError(pdf, "WARNING: Cross-reference table is damaged, attempting to rebuild.");
// Read from the beginning of the file, looking for // Read from the beginning of the file, looking for
if ((line_offset = _pdfioFileSeek(pdf, 0, SEEK_SET)) < 0) if ((line_offset = _pdfioFileSeek(pdf, 0, SEEK_SET)) < 0)
return (false); return (false);
@ -2432,89 +2343,6 @@ repair_xref(
} }
//
// 'write_metadata()' - Write an XMP metadata stream.
//
static bool // O - `true` on success, `false` on failure
write_metadata(pdfio_file_t *pdf) // I - PDF file
{
pdfio_dict_t *dict; // XMP object dictionary
pdfio_obj_t *obj; // XMP object
pdfio_stream_t *st; // XMP stream
bool status = true; // Write status
const char *value; // Value from info dictionary
time_t t; // Date/time value in seconds
char d[64]; // Date/time string (ISO 8601)
// Create the Metadata object...
if ((dict = pdfioDictCreate(pdf)) == NULL)
return (false);
pdfioDictSetName(dict, "Type", "Metadata");
pdfioDictSetName(dict, "Subtype", "XML");
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
return (false);
// Write the XMP stream...
if ((st = pdfioObjCreateStream(obj, PDFIO_FILTER_NONE)) == NULL)
return (false);
status &= pdfioStreamPuts(st, "<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n");
status &= pdfioStreamPuts(st, "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n");
status &= pdfioStreamPuts(st, " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n");
status &= pdfioStreamPuts(st, " <rdf:Description rdf:about=\"\" xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n");
t = pdfioFileGetCreationDate(pdf);
status &= pdfioStreamPrintf(st, " <xmp:CreateDate>%H</xmp:CreateDate>\n", get_iso_date(t, d, sizeof(d)));
if ((value = pdfioFileGetCreator(pdf)) != NULL)
status &= pdfioStreamPrintf(st, " <xmp:CreatorTool>%H</xmp:CreatorTool>\n", value);
status &= pdfioStreamPrintf(st, " <xmp:MetadataDate>%H</xmp:MetadataDate>\n", d);
if ((t = pdfioFileGetModificationDate(pdf)) > 0)
status &= pdfioStreamPrintf(st, " <xmp:ModifyDate>%H</xmp:ModifyDate>\n", get_iso_date(t, d, sizeof(d)));
status &= pdfioStreamPuts(st, " </rdf:Description>\n");
status &= pdfioStreamPuts(st, " <rdf:Description rdf:about=\"\" xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n");
status &= pdfioStreamPrintf(st, " <pdf:Producer>%H</pdf:Producer>\n", pdfioFileGetProducer(pdf));
if ((value = pdfioFileGetKeywords(pdf)) != NULL)
status &= pdfioStreamPrintf(st, " <pdf:Keywords>%H</pdf:Keywords>\n", value);
status &= pdfioStreamPuts(st, " </rdf:Description>\n");
status &= pdfioStreamPuts(st, " <rdf:Description rdf:about=\"\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n");
status &= pdfioStreamPrintf(st, " <dc:format>application/pdf</dc:format>\n");
if ((value = pdfioFileGetTitle(pdf)) != NULL)
status &= pdfioStreamPrintf(st, " <dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">%H</rdf:li></rdf:Alt></dc:title>\n", value);
if ((value = pdfioFileGetAuthor(pdf)) != NULL)
status &= pdfioStreamPrintf(st, " <dc:creator><rdf:Seq><rdf:li>%H</rdf:li></rdf:Seq></dc:creator>\n", value);
if ((value = pdfioFileGetSubject(pdf)) != NULL)
status &= pdfioStreamPrintf(st, " <dc:description><rdf:Alt><rdf:li xml:lang=\"x-default\">%H</rdf:li></rdf:Alt></dc:description>\n", value);
status &= pdfioStreamPuts(st, " </rdf:Description>\n");
// TODO: Need a better way to choose the output profile - something that lets
// us choose the base PDF version and PDF/A, PDF/E, PDF/X, etc.
#if 0
status &= pdfioStreamPuts(st, " <rdf:Description rdf:about=\"\" xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n");
status &= pdfioStreamPuts(st, " <pdfaid:conformance>A</pdfaid:conformance>\n");
status &= pdfioStreamPuts(st, " <pdfaid:part>1</pdfaid:part>\n");
status &= pdfioStreamPuts(st, " </rdf:Description>\n");
#endif // 0
status &= pdfioStreamPuts(st, " </rdf:RDF>\n");
status &= pdfioStreamPuts(st, "</x:xmpmeta>\n");
status &= pdfioStreamPuts(st, "<?xpacket end=\"r\"?>\n");
status &= pdfioStreamClose(st);
if (!status)
return (false);
// If we get this far, add the Metadata key/value to the catalog/root object.
return (pdfioDictSetObj(pdfioFileGetCatalog(pdf), "Metadata", obj));
}
// //
// 'write_pages()' - Write the PDF pages objects. // 'write_pages()' - Write the PDF pages objects.
// //

View File

@ -330,8 +330,6 @@ pdfioObjGetLength(pdfio_obj_t *obj) // I - Object
// //
// 'pdfioObjGetName()' - Get the name value associated with an object. // 'pdfioObjGetName()' - Get the name value associated with an object.
// //
// @since PDFio v1.4@
//
const char * // O - Dictionary or `NULL` on error const char * // O - Dictionary or `NULL` on error
pdfioObjGetName(pdfio_obj_t *obj) // I - Object pdfioObjGetName(pdfio_obj_t *obj) // I - Object

View File

@ -94,7 +94,6 @@
// //
# define PDFIO_MAX_DEPTH 32 // Maximum nesting depth for values # define PDFIO_MAX_DEPTH 32 // Maximum nesting depth for values
# define PDFIO_MAX_STRING 65536 // Maximum length of string
typedef void (*_pdfio_extfree_t)(void *); typedef void (*_pdfio_extfree_t)(void *);
// Extension data free function // Extension data free function
@ -225,14 +224,6 @@ typedef struct _pdfio_objmap_s // PDF object map
size_t src_number; // Source object number size_t src_number; // Source object number
} _pdfio_objmap_t; } _pdfio_objmap_t;
typedef struct _pdfio_strbuf_s // PDF string buffer
{
struct _pdfio_strbuf_s *next; // Next string buffer
bool bufused; // Is this string buffer being used?
char buffer[PDFIO_MAX_STRING + 32];
// String buffer
} _pdfio_strbuf_t;
struct _pdfio_file_s // PDF file structure struct _pdfio_file_s // PDF file structure
{ {
char *filename; // Filename char *filename; // Filename
@ -267,8 +258,7 @@ struct _pdfio_file_s // PDF file structure
pdfio_obj_t *info_obj; // Information object pdfio_obj_t *info_obj; // Information object
pdfio_obj_t *pages_obj; // Root pages object pdfio_obj_t *pages_obj; // Root pages object
pdfio_obj_t *encrypt_obj; // De/Encryption object/dictionary pdfio_obj_t *encrypt_obj; // De/Encryption object/dictionary
pdfio_obj_t *cgats001_obj, // CGATS001 ICC profile object pdfio_obj_t *cp1252_obj, // CP1252 font encoding object
*cp1252_obj, // CP1252 font encoding object
*unicode_obj; // Unicode font encoding object *unicode_obj; // Unicode font encoding object
pdfio_array_t *id_array; // ID array pdfio_array_t *id_array; // ID array
@ -293,7 +283,6 @@ struct _pdfio_file_s // PDF file structure
size_t num_strings, // Number of strings size_t num_strings, // Number of strings
alloc_strings; // Allocated strings alloc_strings; // Allocated strings
char **strings; // Nul-terminated strings char **strings; // Nul-terminated strings
_pdfio_strbuf_t *strbuffers; // String buffers
}; };
struct _pdfio_obj_s // Object struct _pdfio_obj_s // Object
@ -340,7 +329,6 @@ struct _pdfio_stream_s // Stream
extern size_t _pdfio_strlcpy(char *dst, const char *src, size_t dstsize) _PDFIO_INTERNAL; extern size_t _pdfio_strlcpy(char *dst, const char *src, size_t dstsize) _PDFIO_INTERNAL;
extern double _pdfio_strtod(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL; extern double _pdfio_strtod(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
extern void _pdfio_utf16cpy(char *dst, const unsigned char *src, size_t srclen, size_t dstsize) _PDFIO_INTERNAL;
extern ssize_t _pdfio_vsnprintf(pdfio_file_t *pdf, char *buffer, size_t bufsize, const char *format, va_list ap) _PDFIO_INTERNAL; extern ssize_t _pdfio_vsnprintf(pdfio_file_t *pdf, char *buffer, size_t bufsize, const char *format, va_list ap) _PDFIO_INTERNAL;
extern bool _pdfioArrayDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_array_t *a, size_t depth) _PDFIO_INTERNAL; extern bool _pdfioArrayDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_array_t *a, size_t depth) _PDFIO_INTERNAL;
@ -402,8 +390,6 @@ extern bool _pdfioObjWriteHeader(pdfio_obj_t *obj) _PDFIO_INTERNAL;
extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, size_t cbsize, pdfio_filter_t compression) _PDFIO_INTERNAL; extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, size_t cbsize, pdfio_filter_t compression) _PDFIO_INTERNAL;
extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL; extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL;
extern char *_pdfioStringAllocBuffer(pdfio_file_t *pdf);
extern void _pdfioStringFreeBuffer(pdfio_file_t *pdf, char *buffer);
extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL; extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
extern void _pdfioTokenClear(_pdfio_token_t *tb) _PDFIO_INTERNAL; extern void _pdfioTokenClear(_pdfio_token_t *tb) _PDFIO_INTERNAL;

View File

@ -690,9 +690,8 @@ pdfioStreamPeek(pdfio_stream_t *st, // I - Stream
// 'pdfioStreamPrintf()' - Write a formatted string to a stream. // 'pdfioStreamPrintf()' - Write a formatted string to a stream.
// //
// This function writes a formatted string to a stream. In addition to the // This function writes a formatted string to a stream. In addition to the
// standard `printf` format characters, you can use "%H" to format a HTML/XML // standard `printf` format characters, you can use "%N" to format a PDF name
// string value, "%N" to format a PDF name value ("/Name"), and "%S" to format // value ("/Name") and "%S" to format a PDF string ("(String)") value.
// a PDF string ("(String)") value.
// //
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure

View File

@ -158,89 +158,6 @@ _pdfio_strtod(pdfio_file_t *pdf, // I - PDF file
} }
//
// '_pdfio_utf16cpy()' - Convert UTF-16 to UTF-8.
//
void
_pdfio_utf16cpy(
char *dst, // I - Destination buffer for UTF-8
const unsigned char *src, // I - Source UTF-16
size_t srclen, // I - Length of UTF-16
size_t dstsize) // I - Destination buffer size
{
char *dstptr = dst, // Pointer into buffer
*dstend = dst + dstsize - 5; // End of buffer
int ch; // Unicode character
bool is_be = !memcmp(src, "\376\377", 2);
// Big-endian strings?
// Loop through the UTF-16 string, converting to Unicode then UTF-8...
for (src += 2, srclen -= 2; srclen > 1 && dstptr < dstend; src += 2, srclen -= 2)
{
// Initial character...
if (is_be)
ch = (src[0] << 8) | src[1];
else
ch = (src[1] << 8) | src[0];
if (ch >= 0xd800 && ch <= 0xdbff && srclen > 3)
{
// Multi-word UTF-16 char...
int lch; // Lower bits
if (is_be)
lch = (src[2] << 8) | src[3];
else
lch = (src[3] << 8) | src[2];
if (lch < 0xdc00 || lch >= 0xdfff)
break;
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
src += 2;
srclen -= 2;
}
else if (ch >= 0xfffe)
{
continue;
}
// Convert Unicode to UTF-8...
if (ch < 128)
{
// ASCII
*dstptr++ = (char)ch;
}
else if (ch < 4096)
{
// 2-byte UTF-8
*dstptr++ = (char)(0xc0 | (ch >> 6));
*dstptr++ = (char)(0x80 | (ch & 0x3f));
}
else if (ch < 65536)
{
// 3-byte UTF-8
*dstptr++ = (char)(0xe0 | (ch >> 12));
*dstptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
*dstptr++ = (char)(0x80 | (ch & 0x3f));
}
else
{
// 4-byte UTF-8
*dstptr++ = (char)(0xe0 | (ch >> 18));
*dstptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
*dstptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
*dstptr++ = (char)(0x80 | (ch & 0x3f));
}
}
// Nul-terminate the UTF-8 string...
*dstptr = '\0';
}
// //
// '_pdfio_vsnprintf()' - Format a string. // '_pdfio_vsnprintf()' - Format a string.
// //
@ -486,59 +403,6 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
} }
break; break;
case 'H' : // XML/HTML string
if ((s = va_arg(ap, char *)) == NULL)
s = "(null)";
// Loop through the literal string...
while (*s)
{
// Escape special characters
if (*s == '&')
{
// &amp;
if (bufptr < bufend)
{
_pdfio_strlcpy(bufptr, "&amp;", (size_t)(bufend - bufptr + 1));
bufptr += strlen(bufptr);
}
bytes += 5;
}
else if (*s == '<')
{
// &lt;
if (bufptr < bufend)
{
_pdfio_strlcpy(bufptr, "&lt;", (size_t)(bufend - bufptr + 1));
bufptr += strlen(bufptr);
}
bytes += 4;
}
else if (*s == '>')
{
// &gt;
if (bufptr < bufend)
{
_pdfio_strlcpy(bufptr, "&gt;", (size_t)(bufend - bufptr + 1));
bufptr += strlen(bufptr);
}
bytes += 4;
}
else
{
// Literal character...
if (bufptr < bufend)
*bufptr++ = *s;
bytes ++;
}
s ++;
}
break;
case 'S' : // PDF string case 'S' : // PDF string
if ((s = va_arg(ap, char *)) == NULL) if ((s = va_arg(ap, char *)) == NULL)
s = "(null)"; s = "(null)";
@ -668,41 +532,6 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
} }
//
// '_pdfioStringAllocBuffer()' - Allocate a string buffer.
//
char * // O - Buffer or `NULL` on error
_pdfioStringAllocBuffer(
pdfio_file_t *pdf) // I - PDF file
{
_pdfio_strbuf_t *current; // Current string buffer
// See if we have an available string buffer...
for (current = pdf->strbuffers; current; current = current->next)
{
if (!current->bufused)
{
current->bufused = true;
return (current->buffer);
}
}
// Didn't find one, allocate a new one...
if ((current = calloc(1, sizeof(_pdfio_strbuf_t))) == NULL)
return (NULL);
// Add to the linked list of string buffers...
current->next = pdf->strbuffers;
current->bufused = true;
pdf->strbuffers = current;
return (current->buffer);
}
// //
// 'pdfioStringCreate()' - Create a durable literal string. // 'pdfioStringCreate()' - Create a durable literal string.
// //
@ -813,29 +642,6 @@ pdfioStringCreatef(
} }
//
// '_pdfioStringFreeBuffer()' - Free a string buffer.
//
void
_pdfioStringFreeBuffer(
pdfio_file_t *pdf, // I - PDF file
char *buffer) // I - String buffer
{
_pdfio_strbuf_t *current; // Current string buffer
for (current = pdf->strbuffers; current; current = current->next)
{
if (current->buffer == buffer)
{
current->bufused = false;
break;
}
}
}
// //
// '_pdfioStringIsAllocated()' - Check whether a string has been allocated. // '_pdfioStringIsAllocated()' - Check whether a string has been allocated.
// //

View File

@ -1,7 +1,7 @@
// //
// PDF token parsing functions for PDFio. // PDF token parsing functions for PDFio.
// //
// Copyright © 2021-2025 by Michael R Sweet. // Copyright © 2021-2023 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -528,6 +528,13 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
return (false); return (false);
} }
} }
if (bufptr == (buffer + 1))
{
_pdfioFileError(tb->pdf, "Empty name.");
*bufptr = '\0';
return (false);
}
break; break;
case '<' : // Potential hex string case '<' : // Potential hex string

View File

@ -125,7 +125,7 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
_pdfio_crypto_ctx_t ctx; // Decryption context _pdfio_crypto_ctx_t ctx; // Decryption context
_pdfio_crypto_cb_t cb; // Decryption callback _pdfio_crypto_cb_t cb; // Decryption callback
size_t ivlen; // Number of initialization vector bytes size_t ivlen; // Number of initialization vector bytes
uint8_t *temp = NULL; // Temporary buffer for decryption uint8_t temp[32768]; // Temporary buffer for decryption
size_t templen; // Number of actual data bytes size_t templen; // Number of actual data bytes
time_t timeval; // Date/time value time_t timeval; // Date/time value
@ -152,16 +152,11 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
case PDFIO_VALTYPE_BINARY : case PDFIO_VALTYPE_BINARY :
// Decrypt the binary string... // Decrypt the binary string...
if (v->value.binary.datalen > PDFIO_MAX_STRING) if (v->value.binary.datalen > (sizeof(temp) - 32))
{ {
_pdfioFileError(pdf, "Unable to read encrypted binary string - too long."); _pdfioFileError(pdf, "Unable to read encrypted binary string - too long.");
return (false); return (false);
} }
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL)
{
_pdfioFileError(pdf, "Unable to read encrypted binary string - out of memory.");
return (false);
}
ivlen = v->value.binary.datalen; ivlen = v->value.binary.datalen;
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL) if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL)
@ -172,59 +167,29 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
// Copy the decrypted string back to the value and adjust the length... // Copy the decrypted string back to the value and adjust the length...
memcpy(v->value.binary.data, temp, templen); memcpy(v->value.binary.data, temp, templen);
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128 && temp[templen - 1] <= templen) if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128)
v->value.binary.datalen = templen - temp[templen - 1]; v->value.binary.datalen = templen - temp[templen - 1];
else else
v->value.binary.datalen = templen; v->value.binary.datalen = templen;
_pdfioStringFreeBuffer(pdf, (char *)temp);
break; break;
case PDFIO_VALTYPE_STRING : case PDFIO_VALTYPE_STRING :
// Decrypt regular string... // Decrypt regular string...
templen = strlen(v->value.string); templen = strlen(v->value.string);
if (templen > (PDFIO_MAX_STRING - 1)) if (templen > (sizeof(temp) - 33))
{ {
_pdfioFileError(pdf, "Unable to read encrypted string - too long."); _pdfioFileError(pdf, "Unable to read encrypted string - too long.");
return (false); return (false);
} }
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL)
{
_pdfioFileError(pdf, "Unable to read encrypted binary string - out of memory.");
return (false);
}
ivlen = templen; ivlen = templen;
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, (uint8_t *)v->value.string, &ivlen)) == NULL) if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, (uint8_t *)v->value.string, &ivlen)) == NULL)
return (false); return (false);
templen = (cb)(&ctx, temp, (uint8_t *)v->value.string + ivlen, templen - ivlen); templen = (cb)(&ctx, temp, (uint8_t *)v->value.string + ivlen, templen - ivlen);
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128 && temp[templen - 1] <= templen)
templen -= temp[templen - 1];
temp[templen] = '\0'; temp[templen] = '\0';
if ((templen & 1) == 0 && (!memcmp(temp, "\376\377", 2) || !memcmp(temp, "\377\376", 2))) if ((timeval = get_date_time((char *)temp)) != 0)
{
// Convert UTF-16 to UTF-8...
char utf8[4096]; // Temporary string
_pdfio_utf16cpy(utf8, temp, templen, sizeof(utf8));
if ((timeval = get_date_time((char *)utf8)) != 0)
{
// Change the type to date...
v->type = PDFIO_VALTYPE_DATE;
v->value.date = timeval;
}
else
{
// Copy the decrypted string back to the value...
v->value.string = pdfioStringCreate(pdf, utf8);
}
}
else if ((timeval = get_date_time((char *)temp)) != 0)
{ {
// Change the type to date... // Change the type to date...
v->type = PDFIO_VALTYPE_DATE; v->type = PDFIO_VALTYPE_DATE;
@ -235,8 +200,6 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
// Copy the decrypted string back to the value... // Copy the decrypted string back to the value...
v->value.string = pdfioStringCreate(pdf, (char *)temp); v->value.string = pdfioStringCreate(pdf, (char *)temp);
} }
_pdfioStringFreeBuffer(pdf, (char *)temp);
break; break;
} }
@ -337,9 +300,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
_pdfio_value_t *v, // I - Value _pdfio_value_t *v, // I - Value
size_t depth) // I - Depth of value size_t depth) // I - Depth of value
{ {
_pdfio_value_t *ret = NULL; // Return value char token[32768]; // Token buffer
char *token = _pdfioStringAllocBuffer(pdf);
// Token buffer
time_t timeval; // Date/time value time_t timeval; // Date/time value
#ifdef DEBUG #ifdef DEBUG
static const char * const valtypes[] = static const char * const valtypes[] =
@ -361,11 +322,8 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
PDFIO_DEBUG("_pdfioValueRead(pdf=%p, obj=%p, v=%p)\n", pdf, obj, v); PDFIO_DEBUG("_pdfioValueRead(pdf=%p, obj=%p, v=%p)\n", pdf, obj, v);
if (!token) if (!_pdfioTokenGet(tb, token, sizeof(token)))
goto done; return (NULL);
if (!_pdfioTokenGet(tb, token, PDFIO_MAX_STRING))
goto done;
if (!strcmp(token, "[")) if (!strcmp(token, "["))
{ {
@ -373,14 +331,12 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
if (depth >= PDFIO_MAX_DEPTH) if (depth >= PDFIO_MAX_DEPTH)
{ {
_pdfioFileError(pdf, "Too many nested arrays."); _pdfioFileError(pdf, "Too many nested arrays.");
goto done; return (NULL);
} }
v->type = PDFIO_VALTYPE_ARRAY; v->type = PDFIO_VALTYPE_ARRAY;
if ((v->value.array = _pdfioArrayRead(pdf, obj, tb, depth + 1)) == NULL) if ((v->value.array = _pdfioArrayRead(pdf, obj, tb, depth + 1)) == NULL)
goto done; return (NULL);
ret = v;
} }
else if (!strcmp(token, "<<")) else if (!strcmp(token, "<<"))
{ {
@ -388,34 +344,29 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
if (depth >= PDFIO_MAX_DEPTH) if (depth >= PDFIO_MAX_DEPTH)
{ {
_pdfioFileError(pdf, "Too many nested dictionaries."); _pdfioFileError(pdf, "Too many nested dictionaries.");
goto done; return (NULL);
} }
v->type = PDFIO_VALTYPE_DICT; v->type = PDFIO_VALTYPE_DICT;
if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL) if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL)
goto done; return (NULL);
ret = v;
} }
else if ((timeval = get_date_time(token + 1)) != 0) else if (!strncmp(token, "(D:", 3) && (timeval = get_date_time(token + 1)) != 0)
{ {
v->type = PDFIO_VALTYPE_DATE; v->type = PDFIO_VALTYPE_DATE;
v->value.date = timeval; v->value.date = timeval;
ret = v;
} }
else if (token[0] == '(') else if (token[0] == '(')
{ {
// String // String
v->type = PDFIO_VALTYPE_STRING; v->type = PDFIO_VALTYPE_STRING;
v->value.string = pdfioStringCreate(pdf, token + 1); v->value.string = pdfioStringCreate(pdf, token + 1);
ret = v;
} }
else if (token[0] == '/') else if (token[0] == '/')
{ {
// Name // Name
v->type = PDFIO_VALTYPE_NAME; v->type = PDFIO_VALTYPE_NAME;
v->value.name = pdfioStringCreate(pdf, token + 1); v->value.name = pdfioStringCreate(pdf, token + 1);
ret = v;
} }
else if (token[0] == '<') else if (token[0] == '<')
{ {
@ -428,7 +379,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
if ((v->value.binary.data = (unsigned char *)malloc(v->value.binary.datalen)) == NULL) if ((v->value.binary.data = (unsigned char *)malloc(v->value.binary.datalen)) == NULL)
{ {
_pdfioFileError(pdf, "Out of memory for hex string."); _pdfioFileError(pdf, "Out of memory for hex string.");
goto done; return (NULL);
} }
// Convert hex to binary... // Convert hex to binary...
@ -455,8 +406,6 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
*dataptr++ = (unsigned char)d; *dataptr++ = (unsigned char)d;
} }
ret = v;
} }
else if (strchr("0123456789-+.", token[0]) != NULL) else if (strchr("0123456789-+.", token[0]) != NULL)
{ {
@ -544,8 +493,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
PDFIO_DEBUG("_pdfioValueRead: Returning indirect value %lu %u R.\n", (unsigned long)v->value.indirect.number, v->value.indirect.generation); PDFIO_DEBUG("_pdfioValueRead: Returning indirect value %lu %u R.\n", (unsigned long)v->value.indirect.number, v->value.indirect.generation);
ret = v; return (v);
goto done;
} }
} }
} }
@ -553,41 +501,27 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
// If we get here, we have a number... // If we get here, we have a number...
v->type = PDFIO_VALTYPE_NUMBER; v->type = PDFIO_VALTYPE_NUMBER;
v->value.number = _pdfio_strtod(pdf, token); v->value.number = _pdfio_strtod(pdf, token);
ret = v;
} }
else if (!strcmp(token, "true") || !strcmp(token, "false")) else if (!strcmp(token, "true") || !strcmp(token, "false"))
{ {
// Boolean value // Boolean value
v->type = PDFIO_VALTYPE_BOOLEAN; v->type = PDFIO_VALTYPE_BOOLEAN;
v->value.boolean = !strcmp(token, "true"); v->value.boolean = !strcmp(token, "true");
ret = v;
} }
else if (!strcmp(token, "null")) else if (!strcmp(token, "null"))
{ {
// null value // null value
v->type = PDFIO_VALTYPE_NULL; v->type = PDFIO_VALTYPE_NULL;
ret = v;
} }
else else
{ {
_pdfioFileError(pdf, "Unexpected '%s' token seen.", token); _pdfioFileError(pdf, "Unexpected '%s' token seen.", token);
}
done:
if (token)
_pdfioStringFreeBuffer(pdf, token);
if (ret)
{
PDFIO_DEBUG("_pdfioValueRead: Returning %s value.\n", valtypes[ret->type]);
return (ret);
}
else
{
PDFIO_DEBUG("_pdfioValueRead: Returning NULL.\n");
return (NULL); return (NULL);
} }
PDFIO_DEBUG("_pdfioValueRead: Returning %s value.\n", valtypes[v->type]);
return (v);
} }
@ -612,10 +546,8 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
case PDFIO_VALTYPE_BINARY : case PDFIO_VALTYPE_BINARY :
{ {
size_t databytes; // Bytes to write size_t databytes; // Bytes to write
uint8_t *temp = NULL, // Temporary buffer for encryption uint8_t temp[32768], // Temporary buffer for encryption
*dataptr; // Pointer into data *dataptr; // Pointer into data
bool ret = false; // Return value
if (obj && pdf->encryption) if (obj && pdf->encryption)
{ {
@ -624,16 +556,11 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
_pdfio_crypto_cb_t cb; // Encryption callback _pdfio_crypto_cb_t cb; // Encryption callback
size_t ivlen; // Number of initialization vector bytes size_t ivlen; // Number of initialization vector bytes
if (v->value.binary.datalen > PDFIO_MAX_STRING) if (v->value.binary.datalen > (sizeof(temp) - 32))
{ {
_pdfioFileError(pdf, "Unable to write encrypted binary string - too long."); _pdfioFileError(pdf, "Unable to write encrypted binary string - too long.");
return (false); return (false);
} }
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL)
{
_pdfioFileError(pdf, "Unable to write encrypted binary string - out of memory.");
return (false);
}
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen); cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
databytes = (cb)(&ctx, temp + ivlen, v->value.binary.data, v->value.binary.datalen) + ivlen; databytes = (cb)(&ctx, temp + ivlen, v->value.binary.data, v->value.binary.datalen) + ivlen;
@ -646,25 +573,18 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
} }
if (!_pdfioFilePuts(pdf, "<")) if (!_pdfioFilePuts(pdf, "<"))
goto bindone; return (false);
for (; databytes > 1; databytes -= 2, dataptr += 2) for (; databytes > 1; databytes -= 2, dataptr += 2)
{ {
if (!_pdfioFilePrintf(pdf, "%02X%02X", dataptr[0], dataptr[1])) if (!_pdfioFilePrintf(pdf, "%02X%02X", dataptr[0], dataptr[1]))
goto bindone; return (false);
} }
if (databytes > 0 && !_pdfioFilePrintf(pdf, "%02X", dataptr[0])) if (databytes > 0)
goto bindone; return (_pdfioFilePrintf(pdf, "%02X>", dataptr[0]));
else
ret = _pdfioFilePuts(pdf, ">"); return (_pdfioFilePuts(pdf, ">"));
bindone:
if (temp)
_pdfioStringFreeBuffer(pdf, (char *)temp);
return (ret);
} }
case PDFIO_VALTYPE_BOOLEAN : case PDFIO_VALTYPE_BOOLEAN :
@ -689,7 +609,7 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
if (obj && pdf->encryption) if (obj && pdf->encryption)
{ {
// Write encrypted string... // Write encrypted string...
uint8_t temp[64], // Encrypted bytes uint8_t temp[32768], // Encrypted bytes
*tempptr; // Pointer into encrypted bytes *tempptr; // Pointer into encrypted bytes
_pdfio_crypto_ctx_t ctx; // Encryption context _pdfio_crypto_ctx_t ctx; // Encryption context
_pdfio_crypto_cb_t cb; // Encryption callback _pdfio_crypto_cb_t cb; // Encryption callback
@ -740,7 +660,7 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
if (obj && pdf->encryption) if (obj && pdf->encryption)
{ {
// Write encrypted string... // Write encrypted string...
uint8_t *temp = NULL, // Encrypted bytes uint8_t temp[32768], // Encrypted bytes
*tempptr; // Pointer into encrypted bytes *tempptr; // Pointer into encrypted bytes
_pdfio_crypto_ctx_t ctx; // Encryption context _pdfio_crypto_ctx_t ctx; // Encryption context
_pdfio_crypto_cb_t cb; // Encryption callback _pdfio_crypto_cb_t cb; // Encryption callback
@ -748,41 +668,29 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
// Length of value // Length of value
ivlen, // Number of initialization vector bytes ivlen, // Number of initialization vector bytes
tempbytes; // Number of output bytes tempbytes; // Number of output bytes
bool ret = false; // Return value
if (len > PDFIO_MAX_STRING) if (len > (sizeof(temp) - 32))
{ {
_pdfioFileError(pdf, "Unable to write encrypted string - too long."); _pdfioFileError(pdf, "Unable to write encrypted string - too long.");
return (false); return (false);
} }
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL)
{
_pdfioFileError(pdf, "Unable to write encrypted string - out of memory.");
return (false);
}
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen); cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)v->value.string, len) + ivlen; tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)v->value.string, len) + ivlen;
if (!_pdfioFilePuts(pdf, "<")) if (!_pdfioFilePuts(pdf, "<"))
goto strdone; return (false);
for (tempptr = temp; tempbytes > 1; tempbytes -= 2, tempptr += 2) for (tempptr = temp; tempbytes > 1; tempbytes -= 2, tempptr += 2)
{ {
if (!_pdfioFilePrintf(pdf, "%02X%02X", tempptr[0], tempptr[1])) if (!_pdfioFilePrintf(pdf, "%02X%02X", tempptr[0], tempptr[1]))
goto strdone; return (false);
} }
if (tempbytes > 0 && !_pdfioFilePrintf(pdf, "%02X", *tempptr)) if (tempbytes > 0)
goto strdone; return (_pdfioFilePrintf(pdf, "%02X>", *tempptr));
else
ret = _pdfioFilePuts(pdf, ">"); return (_pdfioFilePuts(pdf, ">"));
strdone :
_pdfioStringFreeBuffer(pdf, (char *)temp);
return (ret);
} }
else else
{ {
@ -799,59 +707,31 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
// 'get_date_time()' - Convert PDF date/time value to time_t. // 'get_date_time()' - Convert PDF date/time value to time_t.
// //
static time_t // O - Time in seconds or `0` for none static time_t // O - Time in seconds
get_date_time(const char *s) // I - PDF date/time value get_date_time(const char *s) // I - PDF date/time value
{ {
int i; // Looping var int i; // Looping var
struct tm dateval; // Date value struct tm dateval; // Date value
int offset = 0; // Date offset in seconds int offset; // Date offset
time_t t; // Time value
PDFIO_DEBUG("get_date_time(s=\"%s\")\n", s); PDFIO_DEBUG("get_date_time(s=\"%s\")\n", s);
// Possible date value of the form: // Possible date value of the form:
// //
// D:YYYYMMDDhhmmssZ // (D:YYYYMMDDhhmmssZ)
// D:YYYYMMDDhhmmss+HH'mm // (D:YYYYMMDDhhmmss+HH'mm)
// D:YYYYMMDDhhmmss-HH'mm // (D:YYYYMMDDhhmmss-HH'mm)
// //
if (strncmp(s, "D:", 2))
return (0);
for (i = 2; i < 16; i ++) for (i = 2; i < 16; i ++)
{ {
// Look for date/time digits...
if (!isdigit(s[i] & 255) || !s[i]) if (!isdigit(s[i] & 255) || !s[i])
break; break;
} }
if (i < 6 || (i & 1)) if (i >= 16)
{ {
// Short year or missing digit...
return (0);
}
memset(&dateval, 0, sizeof(dateval));
dateval.tm_year = (s[2] - '0') * 1000 + (s[3] - '0') * 100 + (s[4] - '0') * 10 + s[5] - '0' - 1900;
if (i > 6)
dateval.tm_mon = (s[6] - '0') * 10 + s[7] - '0' - 1;
if (i > 8)
dateval.tm_mday = (s[8] - '0') * 10 + s[9] - '0';
else
dateval.tm_mday = 1;
if (i > 10)
dateval.tm_hour = (s[10] - '0') * 10 + s[11] - '0';
if (i > 12)
dateval.tm_min = (s[12] - '0') * 10 + s[13] - '0';
if (i > 14)
dateval.tm_sec = (s[14] - '0') * 10 + s[15] - '0';
if (i >= 16 && s[i])
{
// Get zone info...
if (s[i] == 'Z') if (s[i] == 'Z')
{ {
// UTC... // UTC...
@ -862,20 +742,14 @@ get_date_time(const char *s) // I - PDF date/time value
// Timezone offset from UTC... // Timezone offset from UTC...
if (isdigit(s[i + 1] & 255) && isdigit(s[i + 2] & 255) && s[i + 3] == '\'' && isdigit(s[i + 4] & 255) && isdigit(s[i + 5] & 255)) if (isdigit(s[i + 1] & 255) && isdigit(s[i + 2] & 255) && s[i + 3] == '\'' && isdigit(s[i + 4] & 255) && isdigit(s[i + 5] & 255))
{ {
offset = (s[i + 1] - '0') * 36000 + (s[i + 2] - '0') * 3600 + (s[i + 4] - '0') * 600 + (s[i + 5] - '0') * 60;
if (s[i] == '-')
offset = -offset;
i += 6; i += 6;
// Accept trailing quote, per PDF spec...
if (s[i] == '\'') if (s[i] == '\'')
i ++; i ++;
} }
} }
else else if (!s[i])
{ {
// Random zone info, invalid date string... // Missing zone info, invalid date string...
return (0); return (0);
} }
} }
@ -886,31 +760,26 @@ get_date_time(const char *s) // I - PDF date/time value
return (0); return (0);
} }
// Convert date value to time_t... // Date value...
#if _WIN32 memset(&dateval, 0, sizeof(dateval));
if ((t = _mkgmtime(&dateval)) <= 0)
return (0);
#elif defined(HAVE_TIMEGM) dateval.tm_year = (s[2] - '0') * 1000 + (s[3] - '0') * 100 + (s[4] - '0') * 10 + s[5] - '0' - 1900;
if ((t = timegm(&dateval)) <= 0) dateval.tm_mon = (s[6] - '0') * 10 + s[7] - '0' - 1;
return (0); dateval.tm_mday = (s[8] - '0') * 10 + s[9] - '0';
dateval.tm_hour = (s[10] - '0') * 10 + s[11] - '0';
dateval.tm_min = (s[12] - '0') * 10 + s[13] - '0';
dateval.tm_sec = (s[14] - '0') * 10 + s[15] - '0';
#else if (s[16] == 'Z')
if ((t = mktime(&dateval)) <= 0) {
return (0); offset = 0;
}
else
{
offset = (s[17] - '0') * 600 + (s[18] - '0') * 60 + (s[19] - '0') * 10 + s[20] - '0';
if (s[16] == '-')
offset = -offset;
}
# if defined(HAVE_TM_GMTOFF) return (mktime(&dateval) + offset);
// Adjust the time value using the "tm_gmtoff" and "tm_isdst" members. As
// noted by M-HT on Github, this DST hack will fail in timezones where the
// DST offset is not one hour, such as Australia/Lord_Howe. Fortunately,
// this is unusual and most systems support the "timegm" function...
t += dateval.tm_gmtoff - 3600 * dateval.tm_isdst;
# else
// Adjust the time value using the even more legacy "timezone" variable,
// which also reflects any DST offset...
t += timezone;
# endif // HAVE_TM_GMTOFF
#endif // _WIN32
return (t - offset);
} }

10
pdfio.h
View File

@ -23,9 +23,9 @@ extern "C" {
// Version numbers... // Version numbers...
// //
# define PDFIO_VERSION "1.6.0" # define PDFIO_VERSION "1.5.1"
# define PDFIO_VERSION_MAJOR 1 # define PDFIO_VERSION_MAJOR 1
# define PDFIO_VERSION_MINOR 6 # define PDFIO_VERSION_MINOR 5
// //
@ -46,7 +46,7 @@ extern "C" {
// //
# if _WIN32 # if _WIN32
typedef __int64 ssize_t; // POSIX type not present on Windows @private@ typedef __int64 ssize_t; // POSIX type not present on Windows... @private@
# endif // _WIN32 # endif // _WIN32
typedef struct _pdfio_array_s pdfio_array_t; typedef struct _pdfio_array_s pdfio_array_t;
@ -62,7 +62,7 @@ typedef bool (*pdfio_error_cb_t)(pdfio_file_t *pdf, const char *message, void *d
typedef enum pdfio_encryption_e // PDF encryption modes typedef enum pdfio_encryption_e // PDF encryption modes
{ {
PDFIO_ENCRYPTION_NONE = 0, // No encryption PDFIO_ENCRYPTION_NONE = 0, // No encryption
PDFIO_ENCRYPTION_RC4_40, // 40-bit RC4 encryption (PDF 1.3, reading only) PDFIO_ENCRYPTION_RC4_40, // 40-bit RC4 encryption (PDF 1.3)
PDFIO_ENCRYPTION_RC4_128, // 128-bit RC4 encryption (PDF 1.4) PDFIO_ENCRYPTION_RC4_128, // 128-bit RC4 encryption (PDF 1.4)
PDFIO_ENCRYPTION_AES_128, // 128-bit AES encryption (PDF 1.6) PDFIO_ENCRYPTION_AES_128, // 128-bit AES encryption (PDF 1.6)
PDFIO_ENCRYPTION_AES_256 // 256-bit AES encryption (PDF 2.0) @exclude all@ PDFIO_ENCRYPTION_AES_256 // 256-bit AES encryption (PDF 2.0) @exclude all@
@ -201,7 +201,6 @@ extern time_t pdfioFileGetCreationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
extern const char *pdfioFileGetCreator(pdfio_file_t *pdf) _PDFIO_PUBLIC; extern const char *pdfioFileGetCreator(pdfio_file_t *pdf) _PDFIO_PUBLIC;
extern pdfio_array_t *pdfioFileGetID(pdfio_file_t *pdf) _PDFIO_PUBLIC; extern pdfio_array_t *pdfioFileGetID(pdfio_file_t *pdf) _PDFIO_PUBLIC;
extern const char *pdfioFileGetKeywords(pdfio_file_t *pdf) _PDFIO_PUBLIC; extern const char *pdfioFileGetKeywords(pdfio_file_t *pdf) _PDFIO_PUBLIC;
extern const char *pdfioFileGetLanguage(pdfio_file_t *pdf) _PDFIO_PUBLIC;
extern time_t pdfioFileGetModificationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC; extern time_t pdfioFileGetModificationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
extern const char *pdfioFileGetName(pdfio_file_t *pdf) _PDFIO_PUBLIC; extern const char *pdfioFileGetName(pdfio_file_t *pdf) _PDFIO_PUBLIC;
extern size_t pdfioFileGetNumObjs(pdfio_file_t *pdf) _PDFIO_PUBLIC; extern size_t pdfioFileGetNumObjs(pdfio_file_t *pdf) _PDFIO_PUBLIC;
@ -218,7 +217,6 @@ extern void pdfioFileSetAuthor(pdfio_file_t *pdf, const char *value) _PDFIO_PUB
extern void pdfioFileSetCreationDate(pdfio_file_t *pdf, time_t value) _PDFIO_PUBLIC; extern void pdfioFileSetCreationDate(pdfio_file_t *pdf, time_t value) _PDFIO_PUBLIC;
extern void pdfioFileSetCreator(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC; extern void pdfioFileSetCreator(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
extern void pdfioFileSetKeywords(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC; extern void pdfioFileSetKeywords(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
extern void pdfioFileSetLanguage(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
extern void pdfioFileSetModificationDate(pdfio_file_t *pdf, time_t value) _PDFIO_PUBLIC; extern void pdfioFileSetModificationDate(pdfio_file_t *pdf, time_t value) _PDFIO_PUBLIC;
extern bool pdfioFileSetPermissions(pdfio_file_t *pdf, pdfio_permission_t permissions, pdfio_encryption_t encryption, const char *owner_password, const char *user_password) _PDFIO_PUBLIC; extern bool pdfioFileSetPermissions(pdfio_file_t *pdf, pdfio_permission_t permissions, pdfio_encryption_t encryption, const char *owner_password, const char *user_password) _PDFIO_PUBLIC;
extern void pdfioFileSetSubject(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC; extern void pdfioFileSetSubject(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;

View File

@ -1,78 +1,20 @@
LIBRARY pdfio1 LIBRARY pdfio1
VERSION 1.6 VERSION 1.5
EXPORTS EXPORTS
_pdfioArrayDebug
_pdfioArrayDecrypt
_pdfioArrayDelete
_pdfioArrayGetValue
_pdfioArrayRead
_pdfioArrayWrite
_pdfioCryptoAESDecrypt _pdfioCryptoAESDecrypt
_pdfioCryptoAESEncrypt _pdfioCryptoAESEncrypt
_pdfioCryptoAESInit _pdfioCryptoAESInit
_pdfioCryptoLock
_pdfioCryptoMD5Append _pdfioCryptoMD5Append
_pdfioCryptoMD5Finish _pdfioCryptoMD5Finish
_pdfioCryptoMD5Init _pdfioCryptoMD5Init
_pdfioCryptoMakeRandom
_pdfioCryptoMakeReader
_pdfioCryptoMakeWriter
_pdfioCryptoRC4Crypt _pdfioCryptoRC4Crypt
_pdfioCryptoRC4Init _pdfioCryptoRC4Init
_pdfioCryptoSHA256Append _pdfioCryptoSHA256Append
_pdfioCryptoSHA256Finish _pdfioCryptoSHA256Finish
_pdfioCryptoSHA256Init _pdfioCryptoSHA256Init
_pdfioCryptoUnlock
_pdfioDictDebug
_pdfioDictDecrypt
_pdfioDictDelete
_pdfioDictGetValue
_pdfioDictRead
_pdfioDictSetValue
_pdfioDictWrite
_pdfioFileAddMappedObj
_pdfioFileAddPage
_pdfioFileConsume
_pdfioFileCreateObj
_pdfioFileDefaultError
_pdfioFileError
_pdfioFileFindMappedObj
_pdfioFileFlush
_pdfioFileGetChar
_pdfioFileGets
_pdfioFilePeek
_pdfioFilePrintf
_pdfioFilePuts
_pdfioFileRead
_pdfioFileSeek
_pdfioFileTell
_pdfioFileWrite
_pdfioObjDelete
_pdfioObjGetExtension
_pdfioObjLoad
_pdfioObjSetExtension
_pdfioObjWriteHeader
_pdfioStreamCreate
_pdfioStreamOpen
_pdfioStringAllocBuffer
_pdfioStringFreeBuffer
_pdfioStringIsAllocated
_pdfioTokenClear
_pdfioTokenFlush
_pdfioTokenGet
_pdfioTokenInit _pdfioTokenInit
_pdfioTokenPush
_pdfioTokenRead
_pdfioValueCopy
_pdfioValueDebug _pdfioValueDebug
_pdfioValueDecrypt
_pdfioValueDelete
_pdfioValueRead _pdfioValueRead
_pdfioValueWrite
_pdfio_strlcpy
_pdfio_strtod
_pdfio_utf16cpy
_pdfio_vsnprintf
pdfioArrayAppendArray pdfioArrayAppendArray
pdfioArrayAppendBinary pdfioArrayAppendBinary
pdfioArrayAppendBoolean pdfioArrayAppendBoolean
@ -187,12 +129,10 @@ pdfioDictSetObj
pdfioDictSetRect pdfioDictSetRect
pdfioDictSetString pdfioDictSetString
pdfioDictSetStringf pdfioDictSetStringf
pdfioFileAddOutputIntent
pdfioFileClose pdfioFileClose
pdfioFileCreate pdfioFileCreate
pdfioFileCreateArrayObj pdfioFileCreateArrayObj
pdfioFileCreateFontObjFromBase pdfioFileCreateFontObjFromBase
pdfioFileCreateFontObjFromData
pdfioFileCreateFontObjFromFile pdfioFileCreateFontObjFromFile
pdfioFileCreateICCObjFromData pdfioFileCreateICCObjFromData
pdfioFileCreateICCObjFromFile pdfioFileCreateICCObjFromFile
@ -212,7 +152,6 @@ pdfioFileGetCreationDate
pdfioFileGetCreator pdfioFileGetCreator
pdfioFileGetID pdfioFileGetID
pdfioFileGetKeywords pdfioFileGetKeywords
pdfioFileGetLanguage
pdfioFileGetModificationDate pdfioFileGetModificationDate
pdfioFileGetName pdfioFileGetName
pdfioFileGetNumObjs pdfioFileGetNumObjs
@ -229,7 +168,6 @@ pdfioFileSetAuthor
pdfioFileSetCreationDate pdfioFileSetCreationDate
pdfioFileSetCreator pdfioFileSetCreator
pdfioFileSetKeywords pdfioFileSetKeywords
pdfioFileSetLanguage
pdfioFileSetModificationDate pdfioFileSetModificationDate
pdfioFileSetPermissions pdfioFileSetPermissions
pdfioFileSetSubject pdfioFileSetSubject

View File

@ -3,7 +3,7 @@
<metadata> <metadata>
<id>pdfio_native</id> <id>pdfio_native</id>
<title>PDFio Library for VS2019+</title> <title>PDFio Library for VS2019+</title>
<version>1.6.0</version> <version>1.5.1</version>
<authors>Michael R Sweet</authors> <authors>Michael R Sweet</authors>
<owners>michaelrsweet</owners> <owners>michaelrsweet</owners>
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl> <projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
@ -16,7 +16,7 @@
<copyright>Copyright © 2019-2025 by Michael R Sweet</copyright> <copyright>Copyright © 2019-2025 by Michael R Sweet</copyright>
<tags>pdf file native</tags> <tags>pdf file native</tags>
<dependencies> <dependencies>
<dependency id="pdfio_native.redist" version="1.6.0" /> <dependency id="pdfio_native.redist" version="1.5.1" />
<dependency id="libpng_native.redist" version="1.6.30" /> <dependency id="libpng_native.redist" version="1.6.30" />
<dependency id="zlib_native.redist" version="1.2.11" /> <dependency id="zlib_native.redist" version="1.2.11" />
</dependencies> </dependencies>

View File

@ -3,7 +3,7 @@
<metadata> <metadata>
<id>pdfio_native.redist</id> <id>pdfio_native.redist</id>
<title>PDFio Library for VS2019+</title> <title>PDFio Library for VS2019+</title>
<version>1.6.0</version> <version>1.5.1</version>
<authors>Michael R Sweet</authors> <authors>Michael R Sweet</authors>
<owners>michaelrsweet</owners> <owners>michaelrsweet</owners>
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl> <projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>

View File

@ -1,5 +0,0 @@
https://github.com/saucecontrol/Compact-ICC-Profiles
All profiles in this collection are released to the public domain under the
Creative Commons CC0 license. They are free from restrictions on distribution
and use to the extent allowed by law.

View File

@ -1399,18 +1399,18 @@ read_unit_file(const char *filename, // I - File to read
} }
fputs("pdfioDictGetString(Lang): ", stdout); fputs("pdfioDictGetString(Lang): ", stdout);
if ((s = pdfioDictGetString(catalog, "Lang")) != NULL && !strcmp(s, "en-CA")) if ((s = pdfioDictGetString(catalog, "Lang")) != NULL && !strcmp(s, "en"))
{ {
puts("PASS"); puts("PASS");
} }
else if (s) else if (s)
{ {
printf("FAIL (got '%s', expected 'en-CA')\n", s); printf("FAIL (got '%s', expected 'en')\n", s);
return (1); return (1);
} }
else else
{ {
puts("FAIL (got NULL, expected 'en-CA')"); puts("FAIL (got NULL, expected 'en')");
return (1); return (1);
} }
@ -3555,6 +3555,7 @@ write_unit_file(
// Set some catalog values... // Set some catalog values...
pdfioDictSetName(catalog, "PageLayout", "SinglePage"); pdfioDictSetName(catalog, "PageLayout", "SinglePage");
pdfioDictSetName(catalog, "PageMode", "UseThumbs"); pdfioDictSetName(catalog, "PageMode", "UseThumbs");
pdfioDictSetString(catalog, "Lang", "en");
// Set info values... // Set info values...
fputs("pdfioFileGet/SetAuthor: ", stdout); fputs("pdfioFileGet/SetAuthor: ", stdout);
@ -3608,23 +3609,6 @@ write_unit_file(
return (1); return (1);
} }
fputs("pdfioFileGet/SetLanguage: ", stdout);
pdfioFileSetLanguage(outpdf, "en-CA");
if ((s = pdfioFileGetLanguage(outpdf)) != NULL && !strcmp(s, "en-CA"))
{
puts("PASS");
}
else if (s)
{
printf("FAIL (got '%s', expected 'en-CA')\n", s);
return (1);
}
else
{
puts("FAIL (got NULL, expected 'en-CA')");
return (1);
}
fputs("pdfioFileGet/SetSubject: ", stdout); fputs("pdfioFileGet/SetSubject: ", stdout);
pdfioFileSetSubject(outpdf, "Unit test document"); pdfioFileSetSubject(outpdf, "Unit test document");
if ((s = pdfioFileGetSubject(outpdf)) != NULL && !strcmp(s, "Unit test document")) if ((s = pdfioFileGetSubject(outpdf)) != NULL && !strcmp(s, "Unit test document"))

View File

@ -3,7 +3,7 @@
// //
// https://github.com/michaelrsweet/ttf // https://github.com/michaelrsweet/ttf
// //
// Copyright © 2018-2025 by Michael R Sweet. // Copyright © 2018-2024 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -14,10 +14,6 @@
// //
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include "ttf.h" #include "ttf.h"
@ -85,13 +81,9 @@ test_font(const char *filename) // I - Font filename
int i, // Looping var int i, // Looping var
errors = 0; // Number of errors errors = 0; // Number of errors
ttf_t *font; // Font ttf_t *font; // Font
struct stat fileinfo; // Font file information
FILE *fp = NULL; // File pointer
void *data = NULL; // Memory buffer for font file
const char *value; // Font (string) value const char *value; // Font (string) value
int intvalue; // Font (integer) value int intvalue; // Font (integer) value
float realvalue; // Font (real) value float realvalue; // Font (real) value
char psname[1024]; // Postscript font name
ttf_rect_t bounds; // Bounds ttf_rect_t bounds; // Bounds
ttf_rect_t extents; // Extents ttf_rect_t extents; // Extents
size_t num_fonts; // Number of fonts size_t num_fonts; // Number of fonts
@ -228,9 +220,6 @@ test_font(const char *filename) // I - Font filename
if ((value = ttfGetPostScriptName(font)) != NULL) if ((value = ttfGetPostScriptName(font)) != NULL)
{ {
printf("PASS (%s)\n", value); printf("PASS (%s)\n", value);
strncpy(psname, value, sizeof(psname) - 1);
psname[sizeof(psname) - 1] = '\0';
} }
else else
{ {
@ -311,86 +300,6 @@ test_font(const char *filename) // I - Font filename
puts("PASS (false)"); puts("PASS (false)");
ttfDelete(font); ttfDelete(font);
font = NULL;
// Now copy the font to memory and open it that way...
printf("fopen(\"%s\", \"rb\"): ", filename);
if ((fp = fopen(filename, "rb")) == NULL)
{
printf("FAIL (%s)\n", strerror(errno));
errors ++;
}
else
{
printf("PASS (%d)\n", fileno(fp));
printf("fstat(%d): ", fileno(fp));
if (fstat(fileno(fp), &fileinfo))
{
printf("FAIL (%s)\n", strerror(errno));
errors ++;
}
else
{
printf("PASS (%lu bytes)\n", (unsigned long)fileinfo.st_size);
fputs("malloc(): ", stdout);
if ((data = malloc((size_t)fileinfo.st_size)) == NULL)
{
printf("FAIL (%s)\n", strerror(errno));
errors ++;
}
else
{
puts("PASS");
fputs("fread(): ", stdout);
if (fread(data, (size_t)fileinfo.st_size, 1, fp) != 1)
{
printf("FAIL (%s)\n", strerror(errno));
errors ++;
}
else
{
puts("PASS");
fputs("ttfCreateData(): ", stdout);
if ((font = ttfCreateData(data, (size_t)fileinfo.st_size, /*idx*/0, error_cb, /*err_data*/NULL)) == NULL)
{
puts("FAIL");
errors ++;
}
else
{
puts("PASS");
fputs("ttfGetPostScriptName: ", stdout);
if ((value = ttfGetPostScriptName(font)) != NULL)
{
if (!strcmp(value, psname))
{
printf("PASS (%s)\n", value);
}
else
{
printf("FAIL (got \"%s\", expected \"%s\")\n", value, psname);
errors ++;
}
}
else
{
puts("FAIL");
errors ++;
}
}
}
}
}
if (fp)
fclose(fp);
free(data);
ttfDelete(font);
}
return (errors); return (errors);
} }

564
ttf.c
View File

@ -177,19 +177,9 @@ typedef struct _ttf_off_names_s // OFF/TTF naming table
unsigned storage_size; // Size of storage area unsigned storage_size; // Size of storage area
} _ttf_off_names_t; } _ttf_off_names_t;
typedef size_t (*_ttf_read_cb_t)(ttf_t *font, void *buffer, size_t bytes);
// Font read callback, returns number of bytes read
typedef bool (*_ttf_seek_cb_t)(ttf_t *font, size_t offset);
// Font seek callback, returns `true` on success
struct _ttf_s struct _ttf_s
{ {
_ttf_read_cb_t read_cb; // Read callback int fd; // File descriptor
_ttf_seek_cb_t seek_cb; // Seek callback
int file_fd; // File descriptor for ttfCreate
const char *data; // Font data for ttfCreateData
size_t data_size; // Size of font data for ttfCreateData
size_t data_offset; // Offset within input
size_t idx; // Font number in file size_t idx; // Font number in file
ttf_err_cb_t err_cb; // Error callback, if any ttf_err_cb_t err_cb; // Error callback, if any
void *err_data; // Error callback data void *err_data; // Error callback data
@ -292,12 +282,7 @@ typedef struct _ttf_off_post_s // PostScript information
// //
static char *copy_name(ttf_t *font, unsigned name_id); static char *copy_name(ttf_t *font, unsigned name_id);
static ttf_t *create_font(const char *filename, const void *data, size_t datasize, size_t idx, ttf_err_cb_t err_cb, void *err_data);
static void errorf(ttf_t *font, const char *message, ...) TTF_FORMAT_ARGS(2,3); static void errorf(ttf_t *font, const char *message, ...) TTF_FORMAT_ARGS(2,3);
static size_t fd_read_cb(ttf_t *font, void *buffer, size_t bytes);
static bool fd_seek_cb(ttf_t *font, size_t offset);
static size_t mem_read_cb(ttf_t *font, void *buffer, size_t bytes);
static bool mem_seek_cb(ttf_t *font, size_t offset);
static bool read_cmap(ttf_t *font); static bool read_cmap(ttf_t *font);
static bool read_head(ttf_t *font, _ttf_off_head_t *head); static bool read_head(ttf_t *font, _ttf_off_head_t *head);
static bool read_hhea(ttf_t *font, _ttf_off_hhea_t *hhea); static bool read_hhea(ttf_t *font, _ttf_off_hhea_t *hhea);
@ -344,6 +329,15 @@ ttfCreate(const char *filename, // I - Filename
ttf_err_cb_t err_cb, // I - Error callback or `NULL` to log to stderr ttf_err_cb_t err_cb, // I - Error callback or `NULL` to log to stderr
void *err_data) // I - Error callback data void *err_data) // I - Error callback data
{ {
ttf_t *font = NULL; // New font object
size_t i; // Looping var
_ttf_metric_t *widths = NULL; // Glyph metrics
_ttf_off_head_t head; // head table
_ttf_off_hhea_t hhea; // hhea table
_ttf_off_os_2_t os_2; // OS/2 table
_ttf_off_post_t post; // PostScript table
TTF_DEBUG("ttfCreate(filename=\"%s\", idx=%u, err_cb=%p, err_data=%p)\n", filename, (unsigned)idx, err_cb, err_data); TTF_DEBUG("ttfCreate(filename=\"%s\", idx=%u, err_cb=%p, err_data=%p)\n", filename, (unsigned)idx, err_cb, err_data);
// Range check input.. // Range check input..
@ -353,57 +347,178 @@ ttfCreate(const char *filename, // I - Filename
return (NULL); return (NULL);
} }
// Open and return the font... // Allocate memory...
return (create_font(filename, /*data*/NULL, /*datasize*/0, idx, err_cb, err_data)); if ((font = (ttf_t *)calloc(1, sizeof(ttf_t))) == NULL)
}
//
// 'ttfCreateData()' - Create a new font object from a memory buffer.
//
// This function creates a new font object from a memory buffer. The "data"
// argument specifies a pointer to the first byte of data and the "datasize"
// argument specifies the length of the memory buffer in bytes.
//
// > Note: The caller is responsible for ensuring that the memory buffer is
// > available until the font object is deleted with @link ttfDelete@.
//
// The "idx" argument specifies the font to load from a collection - the first
// font is number `0`. Once created, you can call the @link ttfGetNumFonts@
// function to determine whether the loaded font file is a collection with more
// than one font.
//
// The "err_cb" and "err_data" arguments specify a callback function and data
// pointer for receiving error messages. If `NULL`, errors are sent to the
// `stderr` file. The callback function receives the data pointer and a text
// message string, for example:
//
// ```
// void my_err_cb(void *err_data, const char *message)
// {
// fprintf(stderr, "ERROR: %s\n", message);
// }
// ```
//
ttf_t * // O - New font object
ttfCreateData(const void *data, // I - Buffer
size_t datasize, // I - Size of buffer in bytes
size_t idx, // I - Font number to create in collection (0-based)
ttf_err_cb_t err_cb, // I - Error callback or `NULL` to log to stderr
void *err_data) // I - Error callback data
{
TTF_DEBUG("ttfCreateData(data=%p, datasize=%lu, idx=%u, err_cb=%p, err_data=%p)\n", data, (unsigned long)datasize, (unsigned)idx, err_cb, err_data);
// Range check input..
if (!data || datasize == 0)
{
errno = EINVAL;
return (NULL); return (NULL);
font->idx = idx;
font->err_cb = err_cb;
font->err_data = err_data;
// Open the font file...
if ((font->fd = open(filename, O_RDONLY | O_BINARY)) < 0)
{
errorf(font, "Unable to open '%s': %s", filename, strerror(errno));
goto error;
} }
// Open and return the font... TTF_DEBUG("ttfCreate: fd=%d\n", font->fd);
return (create_font(/*filename*/NULL, data, datasize, idx, err_cb, err_data));
// Read the table of contents and the identifying names...
if (!read_table(font))
goto error;
TTF_DEBUG("ttfCreate: num_entries=%d\n", font->table.num_entries);
if (!read_names(font))
goto error;
TTF_DEBUG("ttfCreate: num_names=%d\n", font->names.num_names);
// Copy key font meta data strings...
font->copyright = copy_name(font, TTF_OFF_Copyright);
font->family = copy_name(font, TTF_OFF_FontFamily);
font->postscript_name = copy_name(font, TTF_OFF_PostScriptName);
font->version = copy_name(font, TTF_OFF_FontVersion);
if (read_post(font, &post))
{
font->italic_angle = post.italicAngle;
font->is_fixed = post.isFixedPitch != 0;
}
TTF_DEBUG("ttfCreate: copyright=\"%s\"\n", font->copyright);
TTF_DEBUG("ttfCreate: family=\"%s\"\n", font->family);
TTF_DEBUG("ttfCreate: postscript_name=\"%s\"\n", font->postscript_name);
TTF_DEBUG("ttfCreate: version=\"%s\"\n", font->version);
TTF_DEBUG("ttfCreate: italic_angle=%g\n", font->italic_angle);
TTF_DEBUG("ttfCreate: is_fixed=%s\n", font->is_fixed ? "true" : "false");
if (!read_cmap(font))
goto error;
if (!read_head(font, &head))
goto error;
font->units = (float)head.unitsPerEm;
font->x_max = head.xMax;
font->x_min = head.xMin;
font->y_max = head.yMax;
font->y_min = head.yMin;
if (head.macStyle & TTF_OFF_macStyle_Italic)
{
if (font->postscript_name && strstr(font->postscript_name, "Oblique"))
font->style = TTF_STYLE_OBLIQUE;
else
font->style = TTF_STYLE_ITALIC;
}
else
font->style = TTF_STYLE_NORMAL;
if (!read_hhea(font, &hhea))
goto error;
font->ascent = hhea.ascender;
font->descent = hhea.descender;
if (read_maxp(font) < 0)
goto error;
if (hhea.numberOfHMetrics > 0)
{
if ((widths = read_hmtx(font, &hhea)) == NULL)
goto error;
}
else
{
errorf(font, "Number of horizontal metrics is 0.");
goto error;
}
if (read_os_2(font, &os_2))
{
// Copy key values from OS/2 table...
static const ttf_stretch_t stretches[] =
{
TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed
TTF_STRETCH_EXTRA_CONDENSED, // extra-condensed
TTF_STRETCH_CONDENSED, // condensed
TTF_STRETCH_SEMI_CONDENSED, // semi-condensed
TTF_STRETCH_NORMAL, // normal
TTF_STRETCH_SEMI_EXPANDED, // semi-expanded
TTF_STRETCH_EXPANDED, // expanded
TTF_STRETCH_EXTRA_EXPANDED, // extra-expanded
TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded
};
if (os_2.usWidthClass >= 1 && os_2.usWidthClass <= (int)(sizeof(stretches) / sizeof(stretches[0])))
font->stretch = stretches[os_2.usWidthClass - 1];
font->weight = (short)os_2.usWeightClass;
font->cap_height = os_2.sCapHeight;
font->x_height = os_2.sxHeight;
}
else
{
// Default key values since there isn't an OS/2 table...
TTF_DEBUG("ttfCreate: Unable to read OS/2 table.\n");
font->weight = 400;
}
if (font->cap_height == 0)
font->cap_height = font->ascent;
if (font->x_height == 0)
font->x_height = 3 * font->ascent / 5;
// Build a sparse glyph widths table...
font->min_char = -1;
for (i = 0; i < font->num_cmap; i ++)
{
if (font->cmap[i] >= 0)
{
int bin = (int)i / 256, // Sub-array bin
glyph = font->cmap[i]; // Glyph index
// Update min/max...
if (font->min_char < 0)
font->min_char = (int)i;
font->max_char = (int)i;
// Allocate a sub-array as needed...
if (!font->widths[bin])
font->widths[bin] = (_ttf_metric_t *)calloc(256, sizeof(_ttf_metric_t));
// Copy the width of the specified glyph or the last one if we are past
// the end of the table...
if (glyph >= hhea.numberOfHMetrics)
font->widths[bin][i & 255] = widths[hhea.numberOfHMetrics - 1];
else
font->widths[bin][i & 255] = widths[glyph];
}
#ifdef DEBUG
if (i >= ' ' && i < 127 && font->widths[0])
TTF_DEBUG("ttfCreate: width['%c']=%d(%d)\n", (char)i, font->widths[0][i].width, font->widths[0][i].left_bearing);
#endif // DEBUG
}
// Cleanup and return the font...
free(widths);
return (font);
// If we get here something bad happened...
error:
free(widths);
ttfDelete(font);
return (NULL);
} }
@ -422,8 +537,8 @@ ttfDelete(ttf_t *font) // I - Font
return; return;
// Close the font file... // Close the font file...
if (font->file_fd >= 0) if (font->fd >= 0)
close(font->file_fd); close(font->fd);
// Free all memory used... // Free all memory used...
free(font->copyright); free(font->copyright);
@ -928,219 +1043,6 @@ copy_name(ttf_t *font, // I - Font
} }
//
// 'create_font()' - Create a font object from the file or data.
//
static ttf_t *
create_font(const char *filename, // I - Filename of `NULL`
const void *data, // I - Data pointer or `NULL`
size_t datasize, // I - Size of data or 0
size_t idx, // I - Font index
ttf_err_cb_t err_cb, // I - Error callback function
void *err_data) // I - Error callback data
{
ttf_t *font = NULL; // New font object
size_t i; // Looping var
_ttf_metric_t *widths = NULL; // Glyph metrics
_ttf_off_head_t head; // head table
_ttf_off_hhea_t hhea; // hhea table
_ttf_off_os_2_t os_2; // OS/2 table
_ttf_off_post_t post; // PostScript table
TTF_DEBUG("create_font(filename=\"%s\", data=%p, datasize=%lu, idx=%u, err_cb=%p, err_data=%p)\n", filename, data, (unsigned long)datasize, (unsigned)idx, err_cb, err_data);
// Allocate memory...
if ((font = (ttf_t *)calloc(1, sizeof(ttf_t))) == NULL)
return (NULL);
font->idx = idx;
font->err_cb = err_cb;
font->err_data = err_data;
if (filename)
{
// Open the font file...
if ((font->file_fd = open(filename, O_RDONLY | O_BINARY)) < 0)
{
errorf(font, "Unable to open '%s': %s", filename, strerror(errno));
goto error;
}
TTF_DEBUG("create_font: file_fd=%d\n", font->file_fd);
font->read_cb = fd_read_cb;
font->seek_cb = fd_seek_cb;
}
else
{
// Read from memory...
font->file_fd = -1;
font->data = (const char *)data;
font->data_size = datasize;
font->read_cb = mem_read_cb;
font->seek_cb = mem_seek_cb;
}
// Read the table of contents and the identifying names...
if (!read_table(font))
goto error;
TTF_DEBUG("create_font: num_entries=%d\n", font->table.num_entries);
if (!read_names(font))
goto error;
TTF_DEBUG("create_font: num_names=%d\n", font->names.num_names);
// Copy key font meta data strings...
font->copyright = copy_name(font, TTF_OFF_Copyright);
font->family = copy_name(font, TTF_OFF_FontFamily);
font->postscript_name = copy_name(font, TTF_OFF_PostScriptName);
font->version = copy_name(font, TTF_OFF_FontVersion);
if (read_post(font, &post))
{
font->italic_angle = post.italicAngle;
font->is_fixed = post.isFixedPitch != 0;
}
TTF_DEBUG("create_font: copyright=\"%s\"\n", font->copyright);
TTF_DEBUG("create_font: family=\"%s\"\n", font->family);
TTF_DEBUG("create_font: postscript_name=\"%s\"\n", font->postscript_name);
TTF_DEBUG("create_font: version=\"%s\"\n", font->version);
TTF_DEBUG("create_font: italic_angle=%g\n", font->italic_angle);
TTF_DEBUG("create_font: is_fixed=%s\n", font->is_fixed ? "true" : "false");
if (!read_cmap(font))
goto error;
if (!read_head(font, &head))
goto error;
font->units = (float)head.unitsPerEm;
font->x_max = head.xMax;
font->x_min = head.xMin;
font->y_max = head.yMax;
font->y_min = head.yMin;
if (head.macStyle & TTF_OFF_macStyle_Italic)
{
if (font->postscript_name && strstr(font->postscript_name, "Oblique"))
font->style = TTF_STYLE_OBLIQUE;
else
font->style = TTF_STYLE_ITALIC;
}
else
font->style = TTF_STYLE_NORMAL;
if (!read_hhea(font, &hhea))
goto error;
font->ascent = hhea.ascender;
font->descent = hhea.descender;
if (read_maxp(font) < 0)
goto error;
if (hhea.numberOfHMetrics > 0)
{
if ((widths = read_hmtx(font, &hhea)) == NULL)
goto error;
}
else
{
errorf(font, "Number of horizontal metrics is 0.");
goto error;
}
if (read_os_2(font, &os_2))
{
// Copy key values from OS/2 table...
static const ttf_stretch_t stretches[] =
{
TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed
TTF_STRETCH_EXTRA_CONDENSED, // extra-condensed
TTF_STRETCH_CONDENSED, // condensed
TTF_STRETCH_SEMI_CONDENSED, // semi-condensed
TTF_STRETCH_NORMAL, // normal
TTF_STRETCH_SEMI_EXPANDED, // semi-expanded
TTF_STRETCH_EXPANDED, // expanded
TTF_STRETCH_EXTRA_EXPANDED, // extra-expanded
TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded
};
if (os_2.usWidthClass >= 1 && os_2.usWidthClass <= (int)(sizeof(stretches) / sizeof(stretches[0])))
font->stretch = stretches[os_2.usWidthClass - 1];
font->weight = (short)os_2.usWeightClass;
font->cap_height = os_2.sCapHeight;
font->x_height = os_2.sxHeight;
}
else
{
// Default key values since there isn't an OS/2 table...
TTF_DEBUG("create_font: Unable to read OS/2 table.\n");
font->weight = 400;
}
if (font->cap_height == 0)
font->cap_height = font->ascent;
if (font->x_height == 0)
font->x_height = 3 * font->ascent / 5;
// Build a sparse glyph widths table...
font->min_char = -1;
for (i = 0; i < font->num_cmap; i ++)
{
if (font->cmap[i] >= 0)
{
int bin = (int)i / 256, // Sub-array bin
glyph = font->cmap[i]; // Glyph index
// Update min/max...
if (font->min_char < 0)
font->min_char = (int)i;
font->max_char = (int)i;
// Allocate a sub-array as needed...
if (!font->widths[bin])
font->widths[bin] = (_ttf_metric_t *)calloc(256, sizeof(_ttf_metric_t));
// Copy the width of the specified glyph or the last one if we are past
// the end of the table...
if (glyph >= hhea.numberOfHMetrics)
font->widths[bin][i & 255] = widths[hhea.numberOfHMetrics - 1];
else
font->widths[bin][i & 255] = widths[glyph];
}
#ifdef DEBUG
if (i >= ' ' && i < 127 && font->widths[0])
TTF_DEBUG("create_font: width['%c']=%d(%d)\n", (char)i, font->widths[0][i].width, font->widths[0][i].left_bearing);
#endif // DEBUG
}
// Cleanup and return the font...
free(widths);
return (font);
// If we get here something bad happened...
error:
free(widths);
ttfDelete(font);
return (NULL);
}
// //
// 'errorf()' - Show an error message. // 'errorf()' - Show an error message.
// //
@ -1168,85 +1070,9 @@ errorf(ttf_t *font, // I - Font
} }
// /*
// 'fd_read_cb()' - Read from a file. * 'read_cmap()' - Read the cmap table, getting the Unicode mapping table.
// */
static size_t // O - Number of bytes read
fd_read_cb(ttf_t *font, // I - Font
void *buffer, // I - Read buffer
size_t bytes) // I - Number of bytes to read
{
ssize_t rbytes; // Bytes read
if ((rbytes = read(font->file_fd, buffer, bytes)) < 0)
return (0);
return ((size_t)rbytes);
}
//
// 'fd_seek_cb()' - Seek in a file.
//
static bool // O - `true` on success, `false` on failure
fd_seek_cb(ttf_t *font, // I - Font
size_t offset) // I - Offset in data
{
return (lseek(font->file_fd, offset, SEEK_SET) == offset);
}
//
// 'mem_read_cb()' - Read from a memory buffer.
//
static size_t // O - Number of bytes read
mem_read_cb(ttf_t *font, // I - Font
void *buffer, // I - Read buffer
size_t bytes) // I - Number of bytes to read
{
size_t rbytes; // Bytes to copy
if (font->data_offset >= font->data_size)
return (0);
if ((rbytes = font->data_size - font->data_offset) > bytes)
rbytes = bytes;
memcpy(buffer, font->data + font->data_offset, rbytes);
font->data_offset += rbytes;
return (rbytes);
}
//
// 'mem_seek_cb()' - Seek in a memory buffer.
//
static bool // O - `true` on success, `false` on error
mem_seek_cb(ttf_t *font, // I - Font
size_t offset) // I - Offset in data
{
if (offset >= font->data_size)
{
errno = ENXIO;
return (false);
}
font->data_offset = offset;
return (true);
}
//
// 'read_cmap()' - Read the cmap table, getting the Unicode mapping table.
//
static bool // O - `true` on success, `false` on error static bool // O - `true` on success, `false` on error
read_cmap(ttf_t *font) // I - Font read_cmap(ttf_t *font) // I - Font
@ -1393,7 +1219,7 @@ read_cmap(ttf_t *font) // I - Font
return (false); return (false);
} }
if ((font->read_cb)(font, bmap, font->num_cmap) != font->num_cmap) if (read(font->fd, bmap, font->num_cmap) != (ssize_t)font->num_cmap)
{ {
errorf(font, "Unable to read cmap table length at offset %u.", coffset); errorf(font, "Unable to read cmap table length at offset %u.", coffset);
return (false); return (false);
@ -1820,9 +1646,9 @@ read_hhea(ttf_t *font, // I - Font
} }
// /*
// 'read_hmtx()' - Read the horizontal metrics from the font. * 'read_hmtx()' - Read the horizontal metrics from the font.
// */
static _ttf_metric_t * // O - Array of glyph metrics static _ttf_metric_t * // O - Array of glyph metrics
read_hmtx(ttf_t *font, // I - Font read_hmtx(ttf_t *font, // I - Font
@ -1948,7 +1774,7 @@ read_names(ttf_t *font) // I - Font
length -= (unsigned)offset; length -= (unsigned)offset;
if ((font->read_cb)(font, font->names.storage, length) == 0) if (read(font->fd, font->names.storage, length) < 0)
{ {
errorf(font, "Unable to read name table: %s", strerror(errno)); errorf(font, "Unable to read name table: %s", strerror(errno));
return (false); return (false);
@ -1997,7 +1823,7 @@ read_os_2(ttf_t *font, // I - Font
/* yStrikeoutOffset */ read_short(font); /* yStrikeoutOffset */ read_short(font);
/* sFamilyClass */ read_short(font); /* sFamilyClass */ read_short(font);
/* panose[10] */ /* panose[10] */
if ((font->read_cb)(font, panose, sizeof(panose)) != sizeof(panose)) if (read(font->fd, panose, sizeof(panose)) != (ssize_t)sizeof(panose))
return (false); return (false);
/* ulUnicodeRange1 */ read_ulong(font); /* ulUnicodeRange1 */ read_ulong(font);
/* ulUnicodeRange2 */ read_ulong(font); /* ulUnicodeRange2 */ read_ulong(font);
@ -2059,7 +1885,7 @@ read_short(ttf_t *font) // I - Font
unsigned char buffer[2]; // Read buffer unsigned char buffer[2]; // Read buffer
if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer)) if (read(font->fd, buffer, sizeof(buffer)) != sizeof(buffer))
return (EOF); return (EOF);
else if (buffer[0] & 0x80) else if (buffer[0] & 0x80)
return (((buffer[0] << 8) | buffer[1]) - 65536); return (((buffer[0] << 8) | buffer[1]) - 65536);
@ -2132,7 +1958,7 @@ read_table(ttf_t *font) // I - Font
TTF_DEBUG("read_table: Offset for font %u is %u.\n", (unsigned)font->idx, temp); TTF_DEBUG("read_table: Offset for font %u is %u.\n", (unsigned)font->idx, temp);
if (!(font->seek_cb)(font, temp + 4)) if (lseek(font->fd, temp + 4, SEEK_SET) < 0)
{ {
errorf(font, "Unable to seek to font %u: %s", (unsigned)font->idx, strerror(errno)); errorf(font, "Unable to seek to font %u: %s", (unsigned)font->idx, strerror(errno));
return (false); return (false);
@ -2208,7 +2034,7 @@ read_ulong(ttf_t *font) // I - Font
unsigned char buffer[4]; // Read buffer unsigned char buffer[4]; // Read buffer
if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer)) if (read(font->fd, buffer, sizeof(buffer)) != sizeof(buffer))
return ((unsigned)EOF); return ((unsigned)EOF);
else else
return ((unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3])); return ((unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]));
@ -2225,7 +2051,7 @@ read_ushort(ttf_t *font) // I - Font
unsigned char buffer[2]; // Read buffer unsigned char buffer[2]; // Read buffer
if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer)) if (read(font->fd, buffer, sizeof(buffer)) != sizeof(buffer))
return (EOF); return (EOF);
else else
return ((buffer[0] << 8) | buffer[1]); return ((buffer[0] << 8) | buffer[1]);
@ -2252,7 +2078,7 @@ seek_table(ttf_t *font, // I - Font
if (current->tag == tag) if (current->tag == tag)
{ {
// Found it, seek and return... // Found it, seek and return...
if ((font->seek_cb)(font, current->offset + offset)) if (lseek(font->fd, current->offset + offset, SEEK_SET) == (current->offset + offset))
{ {
// Successful seek... // Successful seek...
return (current->length - offset); return (current->length - offset);

3
ttf.h
View File

@ -3,7 +3,7 @@
// //
// https://github.com/michaelrsweet/ttf // https://github.com/michaelrsweet/ttf
// //
// Copyright © 2018-2025 by Michael R Sweet. // Copyright © 2018-2024 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -81,7 +81,6 @@ typedef struct ttf_rect_s // Bounding rectangle
// //
extern ttf_t *ttfCreate(const char *filename, size_t idx, ttf_err_cb_t err_cb, void *err_data); extern ttf_t *ttfCreate(const char *filename, size_t idx, ttf_err_cb_t err_cb, void *err_data);
extern ttf_t *ttfCreateData(const void *data, size_t data_size, size_t idx, ttf_err_cb_t err_cb, void *err_data);
extern void ttfDelete(ttf_t *font); extern void ttfDelete(ttf_t *font);
extern int ttfGetAscent(ttf_t *font); extern int ttfGetAscent(ttf_t *font);
extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds); extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds);