mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-07-15 13:29:56 +02:00
Compare commits
42 Commits
927452d1eb
...
v1.3.0
Author | SHA1 | Date | |
---|---|---|---|
0c1122b689 | |||
d4f8dd46b5 | |||
986c5f0438 | |||
a81907bdb9 | |||
63a7a2cdbd | |||
f040cc41c2 | |||
23883268e3 | |||
a1e14503fd | |||
0766869ad1 | |||
6c1db141a1 | |||
b117959725 | |||
e882622233 | |||
c13b5a5e90 | |||
cd1406e158 | |||
59deee020a | |||
476013706e | |||
a43a9d9e32 | |||
abc69b3361 | |||
83bfb135c6 | |||
2dfb560f8b | |||
7330cc35ba | |||
5d760e7315 | |||
2a85baaf81 | |||
2b92044504 | |||
f4aa951165 | |||
038fd8686b | |||
7084105dc4 | |||
9f06f22281 | |||
cb6b493df6 | |||
2753a82eb9 | |||
ddb8ddff9c | |||
c992b2ba89 | |||
ed723a46dc | |||
6906a9a708 | |||
6a381a55fe | |||
fc3580a948 | |||
6b5c30b4be | |||
a0cdb261ff | |||
34dbf6c2fe | |||
86d842167a | |||
16c8b830b8 | |||
7ff051fc8b |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -60,3 +60,5 @@ jobs:
|
|||||||
run: nuget restore pdfio.sln
|
run: nuget restore pdfio.sln
|
||||||
- name: Build PDFio
|
- name: Build PDFio
|
||||||
run: msbuild pdfio.sln
|
run: msbuild pdfio.sln
|
||||||
|
- name: Test PDFio
|
||||||
|
run: .\runtests.bat x64\Debug
|
||||||
|
34
CHANGES.md
34
CHANGES.md
@ -2,11 +2,39 @@ Changes in PDFio
|
|||||||
================
|
================
|
||||||
|
|
||||||
|
|
||||||
v1.2.0 (Month DD, YYYY)
|
v1.3.0 (June 28, 2024)
|
||||||
-----------------------
|
----------------------
|
||||||
|
|
||||||
|
- Added `pdfioFileGetCatalog` API for accessing the root/catalog object of a
|
||||||
|
PDF file (Issue #67)
|
||||||
|
- Updated number support to avoid locale issues (Issue #61)
|
||||||
|
- Updated the PDFio private header to allow compilation with MingW; note that
|
||||||
|
MingW is NOT a supported toolchain for PDFio (Issue #66)
|
||||||
|
- Optimized string pool code.
|
||||||
|
|
||||||
|
|
||||||
|
v1.2.0 (January 24, 2024)
|
||||||
|
-------------------------
|
||||||
|
|
||||||
- Added `pdfioContentTextMeasure` function (Issue #17)
|
|
||||||
- Now use autoconf to configure the PDFio sources (Issue #54)
|
- Now use autoconf to configure the PDFio sources (Issue #54)
|
||||||
|
- Added `pdfioFileCreateNumberObj` and `pdfioFileCreateStringObj` functions
|
||||||
|
(Issue #14)
|
||||||
|
- Added `pdfioContentTextMeasure` function (Issue #17)
|
||||||
|
- Added `pdfioContentTextNewLineShow` and `pdfioContentTextNewLineShowf`
|
||||||
|
functions (Issue #24)
|
||||||
|
- Renamed `pdfioContentTextNextLine` to `pdfioContentTextNewLine`.
|
||||||
|
- Updated the maximum number of object streams in a single file from 4096 to
|
||||||
|
8192 (Issue #58)
|
||||||
|
- Updated the token reading code to protect against some obvious abuses of the
|
||||||
|
PDF format.
|
||||||
|
- Updated the xref reading code to protect against loops.
|
||||||
|
- Updated the object handling code to use a binary insertion algorithm -
|
||||||
|
provides a significant (~800x) improvement in open times.
|
||||||
|
- Fixed handling of encrypted PDFs with per-object file IDs (Issue #42)
|
||||||
|
- Fixed handling of of trailer dictionaries that started immediately after the
|
||||||
|
"trailer" keyword (Issue #58)
|
||||||
|
- Fixed handling of invalid, but common, PDF files with a generation number of
|
||||||
|
65536 in the xref table (Issue #59)
|
||||||
|
|
||||||
|
|
||||||
v1.1.4 (December 3, 2023)
|
v1.1.4 (December 3, 2023)
|
||||||
|
@ -43,14 +43,17 @@ Contents
|
|||||||
Build System
|
Build System
|
||||||
------------
|
------------
|
||||||
|
|
||||||
The build system uses a simple POSIX makefile to build a static or shared
|
The build system uses [GNU autoconf][AUTOCONF] to create a simple POSIX makefile
|
||||||
library. To improve portability, makefiles *must not* make use of features
|
to build static and/or shared libraries. To improve portability, makefiles
|
||||||
unique to GNU make. See the [Makefile Guidelines](#makefile-guidelines) section
|
*must not* make use of features unique to GNU make. See the
|
||||||
for a description of the allowed make features and makefile guidelines.
|
[Makefile Guidelines](#makefile-guidelines) section for a description of the
|
||||||
|
allowed make features and makefile guidelines.
|
||||||
|
|
||||||
An Xcode project is provided for macOS/iOS developers, and a Visual Studio
|
An Xcode project is provided for macOS/iOS developers, and a Visual Studio
|
||||||
solution and projects for Windows developers.
|
solution and projects for Windows developers.
|
||||||
|
|
||||||
|
[AUTOCONF]: https://www.gnu.org/software/autoconf/
|
||||||
|
|
||||||
|
|
||||||
Version Numbering
|
Version Numbering
|
||||||
-----------------
|
-----------------
|
||||||
@ -373,14 +376,15 @@ The following variables are defined in the makefile:
|
|||||||
- `CC`; the C compiler command,
|
- `CC`; the C compiler command,
|
||||||
- `CFLAGS`; options for the C compiler,
|
- `CFLAGS`; options for the C compiler,
|
||||||
- `CODESIGN_IDENTITY`: the code signing identity,
|
- `CODESIGN_IDENTITY`: the code signing identity,
|
||||||
- `COMMONFLAGS`; common compiler optimization options,
|
|
||||||
- `CPPFLAGS`; options for the C preprocessor,
|
- `CPPFLAGS`; options for the C preprocessor,
|
||||||
- `DESTDIR`/`DSTROOT`: the destination root directory when installing.
|
- `DESTDIR`/`DSTROOT`: the destination root directory when installing.
|
||||||
- `DSO`; the shared library building command,
|
- `DSO`; the shared library building command,
|
||||||
- `DSOFLAGS`; options for the shared library building command,
|
- `DSOFLAGS`; options for the shared library building command,
|
||||||
- `DSONAME`: the root name of the shared library
|
|
||||||
- `LDFLAGS`; options for the linker,
|
- `LDFLAGS`; options for the linker,
|
||||||
|
- `LIBPDFIO`: the name of the primary (shared or static) library
|
||||||
|
- `LIBPDFIO_STATIC`: the name of the secondary (static) library
|
||||||
- `LIBS`; libraries for all programs,
|
- `LIBS`; libraries for all programs,
|
||||||
|
- `OPTIM`; common compiler optimization options,
|
||||||
- `prefix`; the installation prefix directory,
|
- `prefix`; the installation prefix directory,
|
||||||
- `RANLIB`; the static library indexing command,
|
- `RANLIB`; the static library indexing command,
|
||||||
- `SHELL`; the sh (POSIX shell) command,
|
- `SHELL`; the sh (POSIX shell) command,
|
||||||
@ -389,12 +393,7 @@ The following variables are defined in the makefile:
|
|||||||
The following standard targets are defined in the makefile:
|
The following standard targets are defined in the makefile:
|
||||||
|
|
||||||
- `all`; creates the static library and unit test program.
|
- `all`; creates the static library and unit test program.
|
||||||
- `all-shared`; creates a shared library appropriate for the local system.
|
|
||||||
- `clean`; removes all target programs libraries, documentation files, and
|
- `clean`; removes all target programs libraries, documentation files, and
|
||||||
object files,
|
object files,
|
||||||
- `debug`: creates a clean build of the static library and unit test program
|
|
||||||
with debug printfs and the clang address sanitizer enabled.
|
|
||||||
- `install`; installs all distribution files in their corresponding locations.
|
- `install`; installs all distribution files in their corresponding locations.
|
||||||
- `install-shared`; same as `install` but also installs the shared library.
|
|
||||||
- `macos`; same as `all` but creates a Universal Binary (X64 + ARM64).
|
|
||||||
- `test`; runs the unit test program, building it as needed.
|
- `test`; runs the unit test program, building it as needed.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Makefile for PDFio.
|
# Makefile for PDFio.
|
||||||
#
|
#
|
||||||
# Copyright © 2021-2023 by Michael R Sweet.
|
# Copyright © 2021-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.
|
||||||
@ -163,7 +163,9 @@ install: $(TARGETS)
|
|||||||
# Test everything
|
# Test everything
|
||||||
test: testpdfio testttf
|
test: testpdfio testttf
|
||||||
./testttf 2>test.log
|
./testttf 2>test.log
|
||||||
./testpdfio 2>test.log
|
./testpdfio 2>>test.log
|
||||||
|
LANG=fr_FR.UTF-8 ./testpdfio 2>>test.log
|
||||||
|
|
||||||
|
|
||||||
valgrind: testpdfio
|
valgrind: testpdfio
|
||||||
valgrind --leak-check=full ./testpdfio
|
valgrind --leak-check=full ./testpdfio
|
||||||
@ -172,6 +174,7 @@ valgrind: testpdfio
|
|||||||
# pdfio library
|
# pdfio library
|
||||||
libpdfio.a: $(LIBOBJS)
|
libpdfio.a: $(LIBOBJS)
|
||||||
echo Archiving $@...
|
echo Archiving $@...
|
||||||
|
$(RM) $@
|
||||||
$(AR) $(ARFLAGS) $@ $(LIBOBJS)
|
$(AR) $(ARFLAGS) $@ $(LIBOBJS)
|
||||||
$(RANLIB) $@
|
$(RANLIB) $@
|
||||||
|
|
||||||
@ -226,7 +229,7 @@ ttf.o: ttf.h
|
|||||||
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
||||||
DOCFLAGS = \
|
DOCFLAGS = \
|
||||||
--author "Michael R Sweet" \
|
--author "Michael R Sweet" \
|
||||||
--copyright "Copyright (c) 2021-2023 by Michael R Sweet" \
|
--copyright "Copyright (c) 2021-2024 by Michael R Sweet" \
|
||||||
--docversion $(PDFIO_VERSION)
|
--docversion $(PDFIO_VERSION)
|
||||||
|
|
||||||
.PHONY: doc
|
.PHONY: doc
|
||||||
|
2
NOTICE
2
NOTICE
@ -1,6 +1,6 @@
|
|||||||
PDFio - PDF Read/Write Library
|
PDFio - PDF Read/Write Library
|
||||||
|
|
||||||
Copyright © 2021-2023 by Michael R Sweet.
|
Copyright © 2021-2024 by Michael R Sweet.
|
||||||
|
|
||||||
(Optional) Exceptions to the Apache 2.0 License:
|
(Optional) Exceptions to the Apache 2.0 License:
|
||||||
================================================
|
================================================
|
||||||
|
@ -89,7 +89,7 @@ generates a static library that will be installed under "/usr/local" with:
|
|||||||
Legal Stuff
|
Legal Stuff
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
PDFio is Copyright © 2021-2023 by Michael R Sweet.
|
PDFio is Copyright © 2021-2024 by Michael R Sweet.
|
||||||
|
|
||||||
This software is licensed under the Apache License Version 2.0 with an
|
This software is licensed under the Apache License Version 2.0 with an
|
||||||
(optional) exception to allow linking against GPL2/LGPL2 software. See the
|
(optional) exception to allow linking against GPL2/LGPL2 software. See the
|
||||||
|
@ -54,7 +54,7 @@ starting at 0. A feature release has a "PATCH" value of 0, for example:
|
|||||||
1.1.0
|
1.1.0
|
||||||
2.0.0
|
2.0.0
|
||||||
|
|
||||||
Beta releases and release candidates are *not* prodution releases and use
|
Beta releases and release candidates are *not* production releases and use
|
||||||
semantic version numbers of the form:
|
semantic version numbers of the form:
|
||||||
|
|
||||||
MAJOR.MINORbNUMBER
|
MAJOR.MINORbNUMBER
|
||||||
|
29
configure
vendored
29
configure
vendored
@ -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.2.0.
|
# Generated by GNU Autoconf 2.71 for pdfio 1.3.0.
|
||||||
#
|
#
|
||||||
# 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.2.0'
|
PACKAGE_VERSION='1.3.0'
|
||||||
PACKAGE_STRING='pdfio 1.2.0'
|
PACKAGE_STRING='pdfio 1.3.0'
|
||||||
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'
|
||||||
|
|
||||||
@ -1293,7 +1293,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.2.0 to adapt to many kinds of systems.
|
\`configure' configures pdfio 1.3.0 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@ -1359,7 +1359,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.2.0:";;
|
short | recursive ) echo "Configuration of pdfio 1.3.0:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@ -1456,7 +1456,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.2.0
|
pdfio configure 1.3.0
|
||||||
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.
|
||||||
@ -1612,7 +1612,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.2.0, which was
|
It was created by pdfio $as_me 1.3.0, 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
|
||||||
@ -2368,9 +2368,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
PDFIO_VERSION="1.2.0"
|
PDFIO_VERSION="1.3.0"
|
||||||
PDFIO_VERSION_MAJOR="`echo 1.2.0 | awk -F. '{print $1}'`"
|
PDFIO_VERSION_MAJOR="`echo 1.3.0 | awk -F. '{print $1}'`"
|
||||||
PDFIO_VERSION_MINOR="`echo 1.2.0 | awk -F. '{printf("%d\n",$2);}'`"
|
PDFIO_VERSION_MINOR="`echo 1.3.0 | awk -F. '{printf("%d\n",$2);}'`"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -4024,13 +4024,13 @@ then :
|
|||||||
printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
|
printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
|
||||||
|
|
||||||
fi
|
fi
|
||||||
if $PKCONFIG --exists zlib
|
if $PKGCONFIG --exists zlib
|
||||||
then :
|
then :
|
||||||
|
|
||||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||||
printf "%s\n" "yes" >&6; }
|
printf "%s\n" "yes" >&6; }
|
||||||
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
|
||||||
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
||||||
|
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
||||||
|
|
||||||
else $as_nop
|
else $as_nop
|
||||||
|
|
||||||
@ -4093,6 +4093,7 @@ then :
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
PKGCONFIG_REQUIRES=""
|
||||||
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
|
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
@ -4934,7 +4935,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.2.0, which was
|
This file was extended by pdfio $as_me 1.3.0, 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
|
||||||
@ -4990,7 +4991,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.2.0
|
pdfio config.status 1.3.0
|
||||||
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\\"
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
dnl
|
dnl
|
||||||
dnl Configuration script for PDFio
|
dnl Configuration script for PDFio
|
||||||
dnl
|
dnl
|
||||||
dnl Copyright © 2023 by Michael R Sweet
|
dnl Copyright © 2023-2024 by Michael R Sweet
|
||||||
dnl
|
dnl
|
||||||
dnl Licensed under Apache License v2.0. See the file "LICENSE" for more
|
dnl Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
dnl information.
|
dnl information.
|
||||||
@ -21,7 +21,7 @@ AC_PREREQ([2.70])
|
|||||||
|
|
||||||
|
|
||||||
dnl Package name and version...
|
dnl Package name and version...
|
||||||
AC_INIT([pdfio], [1.2.0], [https://github.com/michaelrsweet/pdfio/issues], [pdfio], [https://www.msweet.org/pdfio])
|
AC_INIT([pdfio], [1.3.0], [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}'`"
|
||||||
@ -103,10 +103,10 @@ AC_SUBST([PKGCONFIG_REQUIRES])
|
|||||||
|
|
||||||
dnl ZLIB
|
dnl ZLIB
|
||||||
AC_MSG_CHECKING([for zlib via pkg-config])
|
AC_MSG_CHECKING([for zlib via pkg-config])
|
||||||
AS_IF([$PKCONFIG --exists zlib], [
|
AS_IF([$PKGCONFIG --exists zlib], [
|
||||||
AC_MSG_RESULT([yes])
|
AC_MSG_RESULT([yes])
|
||||||
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
|
||||||
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
||||||
|
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
||||||
],[
|
],[
|
||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
AC_CHECK_HEADER([zlib.h])
|
AC_CHECK_HEADER([zlib.h])
|
||||||
@ -116,6 +116,7 @@ AS_IF([$PKCONFIG --exists zlib], [
|
|||||||
AC_MSG_ERROR([Sorry, this software requires zlib 1.1 or higher.])
|
AC_MSG_ERROR([Sorry, this software requires zlib 1.1 or higher.])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
PKGCONFIG_REQUIRES=""
|
||||||
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
|
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
|
||||||
])
|
])
|
||||||
|
|
||||||
|
230
doc/pdfio.3
230
doc/pdfio.3
@ -1,4 +1,4 @@
|
|||||||
.TH pdfio 3 "pdf read/write library" "2023-12-04" "pdf read/write library"
|
.TH pdfio 3 "pdf read/write library" "2024-06-24" "pdf read/write library"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
pdfio \- pdf read/write library
|
pdfio \- pdf read/write library
|
||||||
.SH Introduction
|
.SH Introduction
|
||||||
@ -34,7 +34,7 @@ PDFio is
|
|||||||
.I not
|
.I not
|
||||||
concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.
|
concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.
|
||||||
.PP
|
.PP
|
||||||
PDFio is Copyright \[co] 2021\-2023 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
PDFio is Copyright \[co] 2021\-2024 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
||||||
.SS Requirements
|
.SS Requirements
|
||||||
.PP
|
.PP
|
||||||
PDFio requires the following to build the software:
|
PDFio requires the following to build the software:
|
||||||
@ -46,6 +46,10 @@ A C99 compiler such as Clang, GCC, or MS Visual C
|
|||||||
.PP
|
.PP
|
||||||
A POSIX\-compliant make program
|
A POSIX\-compliant make program
|
||||||
|
|
||||||
|
.IP \(bu 5
|
||||||
|
.PP
|
||||||
|
A POSIX\-compliant sh program
|
||||||
|
|
||||||
.IP \(bu 5
|
.IP \(bu 5
|
||||||
.PP
|
.PP
|
||||||
ZLIB (https://www.zlib.net) 1.0 or higher
|
ZLIB (https://www.zlib.net) 1.0 or higher
|
||||||
@ -55,10 +59,11 @@ ZLIB (https://www.zlib.net) 1.0 or higher
|
|||||||
IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.
|
IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.
|
||||||
.SS Installing pdfio
|
.SS Installing pdfio
|
||||||
.PP
|
.PP
|
||||||
PDFio comes with a portable makefile that will work on any POSIX\-compliant system with ZLIB installed. To make it, run:
|
PDFio comes with a configure script that creates a portable makefile that will work on any POSIX\-compliant system with ZLIB installed. To make it, run:
|
||||||
.nf
|
.nf
|
||||||
|
|
||||||
make all
|
\./configure
|
||||||
|
make
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
To test it, run:
|
To test it, run:
|
||||||
@ -70,78 +75,28 @@ To test it, run:
|
|||||||
To install it, run:
|
To install it, run:
|
||||||
.nf
|
.nf
|
||||||
|
|
||||||
make install
|
sudo make install
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
If you want a shared library, run:
|
If you want a shared library, run:
|
||||||
.nf
|
.nf
|
||||||
|
|
||||||
make all\-shared
|
\./configure \-\-enable\-shared
|
||||||
make install\-shared
|
make
|
||||||
|
sudo make install
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
The default installation location is "/usr/local". Pass the prefix variable to make to install it to another location:
|
The default installation location is "/usr/local". Pass the \-\-prefix option to make to install it to another location:
|
||||||
.nf
|
.nf
|
||||||
|
|
||||||
make install prefix=/some/other/directory
|
\./configure \-\-prefix=/some/other/directory
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
The makefile installs the pdfio header to "${prefix}/include", the library to "${prefix}/lib", the pkg\-config file to "${prefix}/lib/pkgconfig", the man page to "${prefix}/share/man/man3", and the documentation to "${prefix}/share/doc/pdfio".
|
Other configure options can be found using the \-\-help option:
|
||||||
.PP
|
.nf
|
||||||
The makefile supports the following variables that can be specified in the make command or as environment variables:
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
AR: the library archiver (default "ar")
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
ARFLAGS: options for the library archiver (default "cr")
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
CC: the C compiler (default "cc")
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
CFLAGS: options for the C compiler (default "")
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
CODESIGN_IDENTITY: the identity to use when code signing the shared library on macOS (default "Developer ID")
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
COMMONFLAGS: options for the C compiler and linker (typically architecture and optimization options, default is "\-Os \-g")
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
CPPFLAGS: options for the C preprocessor (default "")
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
DESTDIR and DSTROOT: specifies a root directory when installing (default is "", specify only one)
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
DSOFLAGS: options for the C compiler when linking the shared library (default "")
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
LDFLAGS: options for the C compiler when linking the test programs (default "")
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
LIBS: library options when linking the test programs (default "\-lz")
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
RANLIB: program that generates a table\-of\-contents in a library (default "ranlib")
|
|
||||||
|
|
||||||
.IP \(bu 5
|
|
||||||
.PP
|
|
||||||
prefix: specifies the installation directory (default "/usr/local")
|
|
||||||
|
|
||||||
|
|
||||||
|
\./configure \-\-help
|
||||||
|
.fi
|
||||||
.SS Visual Studio Project
|
.SS Visual Studio Project
|
||||||
.PP
|
.PP
|
||||||
The Visual Studio solution ("pdfio.sln") is provided for Windows developers and generates both a static library and DLL.
|
The Visual Studio solution ("pdfio.sln") is provided for Windows developers and generates both a static library and DLL.
|
||||||
@ -152,12 +107,6 @@ There is also an Xcode project ("pdfio.xcodeproj") you can use on macOS which ge
|
|||||||
|
|
||||||
sudo xcodebuild install
|
sudo xcodebuild install
|
||||||
.fi
|
.fi
|
||||||
.PP
|
|
||||||
You can reproduce this with the makefile using:
|
|
||||||
.nf
|
|
||||||
|
|
||||||
sudo make macos install
|
|
||||||
.fi
|
|
||||||
.SS Detecting PDFio
|
.SS Detecting PDFio
|
||||||
.PP
|
.PP
|
||||||
PDFio can be detected using the pkg\-config command, for example:
|
PDFio can be detected using the pkg\-config command, for example:
|
||||||
@ -218,10 +167,25 @@ pdfio_stream_t: An object stream
|
|||||||
You open an existing PDF file using the pdfioFileOpen function:
|
You open an existing PDF file using the pdfioFileOpen function:
|
||||||
.nf
|
.nf
|
||||||
|
|
||||||
pdfio_file_t *pdf = pdfioFileOpen("myinputfile.pdf", error_cb, error_data);
|
pdfio_file_t *pdf = pdfioFileOpen("myinputfile.pdf", password_cb, password_data,
|
||||||
|
error_cb, error_data);
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
where the three arguments to the function are the filename ("myinputfile.pdf"), an optional error callback function (error_cb), and an optional pointer value for the error callback function (error_data). The error callback is called for both errors and warnings and accepts the pdfio_file_t pointer, a message string, and the callback pointer value, for example:
|
where the five arguments to the function are the filename ("myinputfile.pdf"), an optional password callback function (password_cb) and data pointer value (password_data), and an optional error callback function (error_cb) and data pointer value (error_data). The password callback is called for encrypted PDF files that are not using the default password, for example:
|
||||||
|
.nf
|
||||||
|
|
||||||
|
const char *
|
||||||
|
password_cb(void *data, const char *filename)
|
||||||
|
{
|
||||||
|
(void)data; // This callback doesn't use the data pointer
|
||||||
|
(void)filename; // This callback doesn't use the filename
|
||||||
|
|
||||||
|
// Return a password string for the file...
|
||||||
|
return ("Password42");
|
||||||
|
}
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
The error callback is called for both errors and warnings and accepts the pdfio_file_t pointer, a message string, and the callback pointer value, for example:
|
||||||
.nf
|
.nf
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -400,7 +364,7 @@ The PDF content helper functions provide additional functions for writing specif
|
|||||||
When you are done writing the stream, call pdfioStreamCLose to close both the stream and the object.
|
When you are done writing the stream, call pdfioStreamCLose to close both the stream and the object.
|
||||||
.SS PDF Content Helper Functions
|
.SS PDF Content Helper Functions
|
||||||
.PP
|
.PP
|
||||||
PDFio includes many helper functions for embedding or writing specific kinds of content to a PDF file. These functions can be roughly grouped into ??? categories:
|
PDFio includes many helper functions for embedding or writing specific kinds of content to a PDF file. These functions can be roughly grouped into five categories:
|
||||||
.IP \(bu 5
|
.IP \(bu 5
|
||||||
.PP
|
.PP
|
||||||
Color Space Functions
|
Color Space Functions
|
||||||
@ -552,6 +516,7 @@ will embed an OpenSans Regular TrueType font using the Windows CP1252 subset of
|
|||||||
will embed the NotoSansJP Regular OpenType font with full support for Unicode.
|
will embed the NotoSansJP Regular OpenType font with full support for Unicode.
|
||||||
.PP
|
.PP
|
||||||
Note: Not all fonts support Unicode.
|
Note: Not all fonts support Unicode.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
Image Object Functions
|
Image Object Functions
|
||||||
.PP
|
.PP
|
||||||
@ -799,7 +764,15 @@ pdfioContentTextMoveTo moves within the current line in a text block
|
|||||||
|
|
||||||
.IP \(bu 5
|
.IP \(bu 5
|
||||||
.PP
|
.PP
|
||||||
pdfioContentTextNextLine moves to the beginning of the next line in a text block
|
pdfioContentTextNewLine moves to the beginning of the next line in a text block
|
||||||
|
|
||||||
|
.IP \(bu 5
|
||||||
|
.PP
|
||||||
|
pdfioContentTextNewLineShow moves to the beginning of the next line in a text block and shows literal text with optional word and character spacing
|
||||||
|
|
||||||
|
.IP \(bu 5
|
||||||
|
.PP
|
||||||
|
pdfioContentTextNewLineShowf moves to the beginning of the next line in a text block and shows formatted text with optional word and character spacing
|
||||||
|
|
||||||
.IP \(bu 5
|
.IP \(bu 5
|
||||||
.PP
|
.PP
|
||||||
@ -839,7 +812,7 @@ PDFIO_ENCRYPTION_AES_128
|
|||||||
.TP 5
|
.TP 5
|
||||||
PDFIO_ENCRYPTION_AES_256
|
PDFIO_ENCRYPTION_AES_256
|
||||||
.br
|
.br
|
||||||
256-bit AES encryption (PDF 2.0)
|
256-bit AES encryption (PDF 2.0)
|
||||||
.TP 5
|
.TP 5
|
||||||
PDFIO_ENCRYPTION_NONE
|
PDFIO_ENCRYPTION_NONE
|
||||||
.br
|
.br
|
||||||
@ -1808,14 +1781,49 @@ bool pdfioContentTextMoveTo (
|
|||||||
double ty
|
double ty
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
.SS pdfioContentTextNextLine
|
.SS pdfioContentTextNewLine
|
||||||
Move to the next line.
|
Move to the next line.
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
bool pdfioContentTextNextLine (
|
bool pdfioContentTextNewLine (
|
||||||
pdfio_stream_t *st
|
pdfio_stream_t *st
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
|
.SS pdfioContentTextNewLineShow
|
||||||
|
Move to the next line and show text.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
bool pdfioContentTextNewLineShow (
|
||||||
|
pdfio_stream_t *st,
|
||||||
|
double ws,
|
||||||
|
double cs,
|
||||||
|
bool unicode,
|
||||||
|
const char *s
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
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
|
||||||
|
specifies that the current font maps to full Unicode. The "s" argument
|
||||||
|
specifies a UTF-8 encoded string.
|
||||||
|
.SS pdfioContentTextNewLineShowf
|
||||||
|
Show formatted text.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
bool pdfioContentTextNewLineShowf (
|
||||||
|
pdfio_stream_t *st,
|
||||||
|
double ws,
|
||||||
|
double cs,
|
||||||
|
bool unicode,
|
||||||
|
const char *format,
|
||||||
|
...
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
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"
|
||||||
|
argument specifies that the current font maps to full Unicode. The "format"
|
||||||
|
argument specifies a UTF-8 encoded \fBprintf\fR-style format string.
|
||||||
.SS pdfioContentTextShow
|
.SS pdfioContentTextShow
|
||||||
Show text.
|
Show text.
|
||||||
.PP
|
.PP
|
||||||
@ -2140,7 +2148,7 @@ pdfio_file_t * pdfioFileCreate (
|
|||||||
pdfio_rect_t *media_box,
|
pdfio_rect_t *media_box,
|
||||||
pdfio_rect_t *crop_box,
|
pdfio_rect_t *crop_box,
|
||||||
pdfio_error_cb_t error_cb,
|
pdfio_error_cb_t error_cb,
|
||||||
void *error_data
|
void *error_cbdata
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
@ -2154,7 +2162,7 @@ The "media_box" and "crop_box" arguments specify the default MediaBox and
|
|||||||
CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size
|
CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size
|
||||||
of 8.27x11in (the intersection of US Letter and ISO A4) is used.
|
of 8.27x11in (the intersection of US Letter and ISO A4) is used.
|
||||||
.PP
|
.PP
|
||||||
The "error_cb" and "error_data" arguments specify an error handler callback
|
The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||||
and its data pointer - if \fBNULL\fR the default error handler is used that
|
and its data pointer - if \fBNULL\fR the default error handler is used that
|
||||||
writes error messages to \fBstderr\fR.
|
writes error messages to \fBstderr\fR.
|
||||||
.SS pdfioFileCreateArrayObj
|
.SS pdfioFileCreateArrayObj
|
||||||
@ -2290,6 +2298,18 @@ 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
|
||||||
.IP 5
|
.IP 5
|
||||||
is supported.
|
is supported.
|
||||||
|
.SS pdfioFileCreateNumberObj
|
||||||
|
Create a new object in a PDF file containing a number.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
pdfio_obj_t * pdfioFileCreateNumberObj (
|
||||||
|
pdfio_file_t *pdf,
|
||||||
|
double number
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
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.
|
||||||
.SS pdfioFileCreateObj
|
.SS pdfioFileCreateObj
|
||||||
Create a new object in a PDF file.
|
Create a new object in a PDF file.
|
||||||
.PP
|
.PP
|
||||||
@ -2305,23 +2325,23 @@ Create a PDF file through an output callback.
|
|||||||
.nf
|
.nf
|
||||||
pdfio_file_t * pdfioFileCreateOutput (
|
pdfio_file_t * pdfioFileCreateOutput (
|
||||||
pdfio_output_cb_t output_cb,
|
pdfio_output_cb_t output_cb,
|
||||||
void *output_ctx,
|
void *output_cbdata,
|
||||||
const char *version,
|
const char *version,
|
||||||
pdfio_rect_t *media_box,
|
pdfio_rect_t *media_box,
|
||||||
pdfio_rect_t *crop_box,
|
pdfio_rect_t *crop_box,
|
||||||
pdfio_error_cb_t error_cb,
|
pdfio_error_cb_t error_cb,
|
||||||
void *error_data
|
void *error_cbdata
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
This function creates a new PDF file that is streamed though an output
|
This function creates a new PDF file that is streamed though an output
|
||||||
callback. The "output_cb" and "output_ctx" arguments specify the output
|
callback. The "output_cb" and "output_cbdata" arguments specify the output
|
||||||
callback and its context pointer which is called whenever data needs to be
|
callback and its data pointer which is called whenever data needs to be
|
||||||
written:
|
written:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
ssize_t
|
ssize_t
|
||||||
output_cb(void *output_ctx, const void *buffer, size_t bytes)
|
output_cb(void *output_cbdata, const void *buffer, size_t bytes)
|
||||||
{
|
{
|
||||||
// Write buffer to output and return the number of bytes written
|
// Write buffer to output and return the number of bytes written
|
||||||
}
|
}
|
||||||
@ -2335,7 +2355,7 @@ The "media_box" and "crop_box" arguments specify the default MediaBox and
|
|||||||
CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size
|
CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size
|
||||||
of 8.27x11in (the intersection of US Letter and ISO A4) is used.
|
of 8.27x11in (the intersection of US Letter and ISO A4) is used.
|
||||||
.PP
|
.PP
|
||||||
The "error_cb" and "error_data" arguments specify an error handler callback
|
The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||||
and its data pointer - if \fBNULL\fR the default error handler is used that
|
and its data pointer - if \fBNULL\fR the default error handler is used that
|
||||||
writes error messages to \fBstderr\fR.
|
writes error messages to \fBstderr\fR.
|
||||||
.PP
|
.PP
|
||||||
@ -2354,6 +2374,18 @@ pdfio_stream_t * pdfioFileCreatePage (
|
|||||||
pdfio_dict_t *dict
|
pdfio_dict_t *dict
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
|
.SS pdfioFileCreateStringObj
|
||||||
|
Create a new object in a PDF file containing a string.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
pdfio_obj_t * pdfioFileCreateStringObj (
|
||||||
|
pdfio_file_t *pdf,
|
||||||
|
const char *string
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
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.
|
||||||
.SS pdfioFileCreateTemporary
|
.SS pdfioFileCreateTemporary
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
@ -2365,7 +2397,7 @@ pdfio_file_t * pdfioFileCreateTemporary (
|
|||||||
pdfio_rect_t *media_box,
|
pdfio_rect_t *media_box,
|
||||||
pdfio_rect_t *crop_box,
|
pdfio_rect_t *crop_box,
|
||||||
pdfio_error_cb_t error_cb,
|
pdfio_error_cb_t error_cb,
|
||||||
void *error_data
|
void *error_cbdata
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
.SS pdfioFileFindObj
|
.SS pdfioFileFindObj
|
||||||
@ -2388,6 +2420,16 @@ const char * pdfioFileGetAuthor (
|
|||||||
pdfio_file_t *pdf
|
pdfio_file_t *pdf
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
|
.SS pdfioFileGetCatalog
|
||||||
|
Get the document catalog dictionary.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
pdfio_dict_t * pdfioFileGetCatalog (
|
||||||
|
pdfio_file_t *pdf
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
|
||||||
.SS pdfioFileGetCreationDate
|
.SS pdfioFileGetCreationDate
|
||||||
Get the creation date for a PDF file.
|
Get the creation date for a PDF file.
|
||||||
.PP
|
.PP
|
||||||
@ -2513,22 +2555,22 @@ Open a PDF file for reading.
|
|||||||
pdfio_file_t * pdfioFileOpen (
|
pdfio_file_t * pdfioFileOpen (
|
||||||
const char *filename,
|
const char *filename,
|
||||||
pdfio_password_cb_t password_cb,
|
pdfio_password_cb_t password_cb,
|
||||||
void *password_data,
|
void *password_cbdata,
|
||||||
pdfio_error_cb_t error_cb,
|
pdfio_error_cb_t error_cb,
|
||||||
void *error_data
|
void *error_cbdata
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
This function opens an existing PDF file. The "filename" argument specifies
|
This function opens an existing PDF file. The "filename" argument specifies
|
||||||
the name of the PDF file to create.
|
the name of the PDF file to create.
|
||||||
.PP
|
.PP
|
||||||
The "password_cb" and "password_data" arguments specify a password callback
|
The "password_cb" and "password_cbdata" arguments specify a password callback
|
||||||
and its data pointer for PDF files that use one of the standard Adobe
|
and its data pointer for PDF files that use one of the standard Adobe
|
||||||
"security" handlers. The callback returns a password string or \fBNULL\fR to
|
"security" handlers. The callback returns a password string or \fBNULL\fR to
|
||||||
cancel the open. If \fBNULL\fR is specified for the callback function and the
|
cancel the open. If \fBNULL\fR is specified for the callback function and the
|
||||||
PDF file requires a password, the open will always fail.
|
PDF file requires a password, the open will always fail.
|
||||||
.PP
|
.PP
|
||||||
The "error_cb" and "error_data" arguments specify an error handler callback
|
The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||||
and its data pointer - if \fBNULL\fR the default error handler is used that
|
and its data pointer - if \fBNULL\fR the default error handler is used that
|
||||||
writes error messages to \fBstderr\fR.
|
writes error messages to \fBstderr\fR.
|
||||||
.SS pdfioFileSetAuthor
|
.SS pdfioFileSetAuthor
|
||||||
@ -3050,15 +3092,9 @@ PDF value types
|
|||||||
.nf
|
.nf
|
||||||
typedef enum pdfio_valtype_e pdfio_valtype_t;
|
typedef enum pdfio_valtype_e pdfio_valtype_t;
|
||||||
.fi
|
.fi
|
||||||
.SS state_t[4][4]
|
|
||||||
4x4 AES state table
|
|
||||||
.PP
|
|
||||||
.nf
|
|
||||||
typedef uint8_t state_t[4][4];
|
|
||||||
.fi
|
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
.PP
|
.PP
|
||||||
Michael R Sweet
|
Michael R Sweet
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
.PP
|
.PP
|
||||||
Copyright (c) 2021-2023 by Michael R Sweet
|
Copyright (c) 2021-2024 by Michael R Sweet
|
||||||
|
543
doc/pdfio.html
543
doc/pdfio.html
File diff suppressed because it is too large
Load Diff
92
doc/pdfio.md
92
doc/pdfio.md
@ -15,7 +15,7 @@ goals of pdfio are:
|
|||||||
PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF
|
PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF
|
||||||
RIP or viewer could be written using it.
|
RIP or viewer could be written using it.
|
||||||
|
|
||||||
PDFio is Copyright © 2021-2023 by Michael R Sweet and is licensed under the
|
PDFio is Copyright © 2021-2024 by Michael R Sweet and is licensed under the
|
||||||
Apache License Version 2.0 with an (optional) exception to allow linking against
|
Apache License Version 2.0 with an (optional) exception to allow linking against
|
||||||
GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
||||||
|
|
||||||
@ -27,6 +27,7 @@ PDFio requires the following to build the software:
|
|||||||
|
|
||||||
- A C99 compiler such as Clang, GCC, or MS Visual C
|
- A C99 compiler such as Clang, GCC, or MS Visual C
|
||||||
- A POSIX-compliant `make` program
|
- A POSIX-compliant `make` program
|
||||||
|
- A POSIX-compliant `sh` program
|
||||||
- ZLIB (<https://www.zlib.net>) 1.0 or higher
|
- ZLIB (<https://www.zlib.net>) 1.0 or higher
|
||||||
|
|
||||||
IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.
|
IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.
|
||||||
@ -35,10 +36,11 @@ IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.
|
|||||||
Installing pdfio
|
Installing pdfio
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
PDFio comes with a portable makefile that will work on any POSIX-compliant
|
PDFio comes with a configure script that creates a portable makefile that will
|
||||||
system with ZLIB installed. To make it, run:
|
work on any POSIX-compliant system with ZLIB installed. To make it, run:
|
||||||
|
|
||||||
make all
|
./configure
|
||||||
|
make
|
||||||
|
|
||||||
To test it, run:
|
To test it, run:
|
||||||
|
|
||||||
@ -46,45 +48,22 @@ To test it, run:
|
|||||||
|
|
||||||
To install it, run:
|
To install it, run:
|
||||||
|
|
||||||
make install
|
sudo make install
|
||||||
|
|
||||||
If you want a shared library, run:
|
If you want a shared library, run:
|
||||||
|
|
||||||
make all-shared
|
./configure --enable-shared
|
||||||
make install-shared
|
make
|
||||||
|
sudo make install
|
||||||
|
|
||||||
The default installation location is "/usr/local". Pass the `prefix` variable
|
The default installation location is "/usr/local". Pass the `--prefix` option
|
||||||
to make to install it to another location:
|
to make to install it to another location:
|
||||||
|
|
||||||
make install prefix=/some/other/directory
|
./configure --prefix=/some/other/directory
|
||||||
|
|
||||||
The makefile installs the pdfio header to "${prefix}/include", the library to
|
Other configure options can be found using the `--help` option:
|
||||||
"${prefix}/lib", the `pkg-config` file to "${prefix}/lib/pkgconfig", the man
|
|
||||||
page to "${prefix}/share/man/man3", and the documentation to
|
|
||||||
"${prefix}/share/doc/pdfio".
|
|
||||||
|
|
||||||
The makefile supports the following variables that can be specified in the make
|
./configure --help
|
||||||
command or as environment variables:
|
|
||||||
|
|
||||||
- `AR`: the library archiver (default "ar")
|
|
||||||
- `ARFLAGS`: options for the library archiver (default "cr")
|
|
||||||
- `CC`: the C compiler (default "cc")
|
|
||||||
- `CFLAGS`: options for the C compiler (default "")
|
|
||||||
- `CODESIGN_IDENTITY`: the identity to use when code signing the shared library
|
|
||||||
on macOS (default "Developer ID")
|
|
||||||
- `COMMONFLAGS`: options for the C compiler and linker (typically architecture
|
|
||||||
and optimization options, default is "-Os -g")
|
|
||||||
- `CPPFLAGS`: options for the C preprocessor (default "")
|
|
||||||
- `DESTDIR` and `DSTROOT`: specifies a root directory when installing
|
|
||||||
(default is "", specify only one)
|
|
||||||
- `DSOFLAGS`: options for the C compiler when linking the shared library
|
|
||||||
(default "")
|
|
||||||
- `LDFLAGS`: options for the C compiler when linking the test programs
|
|
||||||
(default "")
|
|
||||||
- `LIBS`: library options when linking the test programs (default "-lz")
|
|
||||||
- `RANLIB`: program that generates a table-of-contents in a library
|
|
||||||
(default "ranlib")
|
|
||||||
- `prefix`: specifies the installation directory (default "/usr/local")
|
|
||||||
|
|
||||||
|
|
||||||
Visual Studio Project
|
Visual Studio Project
|
||||||
@ -102,10 +81,6 @@ generates a static library that will be installed under "/usr/local" with:
|
|||||||
|
|
||||||
sudo xcodebuild install
|
sudo xcodebuild install
|
||||||
|
|
||||||
You can reproduce this with the makefile using:
|
|
||||||
|
|
||||||
sudo make macos install
|
|
||||||
|
|
||||||
|
|
||||||
Detecting PDFio
|
Detecting PDFio
|
||||||
---------------
|
---------------
|
||||||
@ -163,15 +138,32 @@ Reading PDF Files
|
|||||||
You open an existing PDF file using the [`pdfioFileOpen`](@@) function:
|
You open an existing PDF file using the [`pdfioFileOpen`](@@) function:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
pdfio_file_t *pdf = pdfioFileOpen("myinputfile.pdf", error_cb, error_data);
|
pdfio_file_t *pdf = pdfioFileOpen("myinputfile.pdf", password_cb, password_data,
|
||||||
|
error_cb, error_data);
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
where the three arguments to the function are the filename ("myinputfile.pdf"),
|
where the five arguments to the function are the filename ("myinputfile.pdf"),
|
||||||
an optional error callback function (`error_cb`), and an optional pointer value
|
an optional password callback function (`password_cb`) and data pointer value
|
||||||
for the error callback function (`error_data`). The error callback is called
|
(`password_data`), and an optional error callback function (`error_cb`) and data
|
||||||
for both errors and warnings and accepts the `pdfio_file_t` pointer, a message
|
pointer value (`error_data`). The password callback is called for encrypted PDF
|
||||||
string, and the callback pointer value, for example:
|
files that are not using the default password, for example:
|
||||||
|
|
||||||
|
```c
|
||||||
|
const char *
|
||||||
|
password_cb(void *data, const char *filename)
|
||||||
|
{
|
||||||
|
(void)data; // This callback doesn't use the data pointer
|
||||||
|
(void)filename; // This callback doesn't use the filename
|
||||||
|
|
||||||
|
// Return a password string for the file...
|
||||||
|
return ("Password42");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The error callback is called for both errors and warnings and accepts the
|
||||||
|
`pdfio_file_t` pointer, a message string, and the callback pointer value, for
|
||||||
|
example:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
bool
|
bool
|
||||||
@ -361,7 +353,7 @@ PDF Content Helper Functions
|
|||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
PDFio includes many helper functions for embedding or writing specific kinds of
|
PDFio includes many helper functions for embedding or writing specific kinds of
|
||||||
content to a PDF file. These functions can be roughly grouped into ???
|
content to a PDF file. These functions can be roughly grouped into five
|
||||||
categories:
|
categories:
|
||||||
|
|
||||||
- [Color Space Functions](@)
|
- [Color Space Functions](@)
|
||||||
@ -455,7 +447,7 @@ pdfio_obj_t *arial = pdfioFileCreateFontObjFromFile(pdf, "NotoSansJP-Regular.otf
|
|||||||
|
|
||||||
will embed the NotoSansJP Regular OpenType font with full support for Unicode.
|
will embed the NotoSansJP Regular OpenType font with full support for Unicode.
|
||||||
|
|
||||||
Note: Not all fonts support Unicode.
|
> Note: Not all fonts support Unicode.
|
||||||
|
|
||||||
|
|
||||||
### Image Object Functions
|
### Image Object Functions
|
||||||
@ -584,8 +576,12 @@ escaping, as needed:
|
|||||||
- [`pdfioContentTextMoveLine`](@@) moves to the next line with an offset in a
|
- [`pdfioContentTextMoveLine`](@@) moves to the next line with an offset in a
|
||||||
text block
|
text block
|
||||||
- [`pdfioContentTextMoveTo`](@@) moves within the current line in a text block
|
- [`pdfioContentTextMoveTo`](@@) moves within the current line in a text block
|
||||||
- [`pdfioContentTextNextLine`](@@) moves to the beginning of the next line in a
|
- [`pdfioContentTextNewLine`](@@) moves to the beginning of the next line in a
|
||||||
text block
|
text block
|
||||||
|
- [`pdfioContentTextNewLineShow`](@@) moves to the beginning of the next line in a
|
||||||
|
text block and shows literal text with optional word and character spacing
|
||||||
|
- [`pdfioContentTextNewLineShowf`](@@) moves to the beginning of the next line in a
|
||||||
|
text block and shows formatted text with optional word and character spacing
|
||||||
- [`pdfioContentTextShow`](@@) draws a literal string in a text block
|
- [`pdfioContentTextShow`](@@) draws a literal string in a text block
|
||||||
- [`pdfioContentTextShowf`](@@) draws a formatted string in a text block
|
- [`pdfioContentTextShowf`](@@) draws a formatted string in a text block
|
||||||
- [`pdfioContentTextShowJustified`](@@) draws an array of literal strings with
|
- [`pdfioContentTextShowJustified`](@@) draws an array of literal strings with
|
||||||
|
53
makesrcdist
53
makesrcdist
@ -2,18 +2,61 @@
|
|||||||
#
|
#
|
||||||
# makesrcdist - make a source distribution of pdfio.
|
# makesrcdist - make a source distribution of pdfio.
|
||||||
#
|
#
|
||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# ./makesrcdist [--snapshot] VERSION
|
||||||
|
#
|
||||||
|
|
||||||
|
# Support "--snapshot" option...
|
||||||
|
if test "$1" == "--snapshot"; then
|
||||||
|
shift
|
||||||
|
snapshot=1
|
||||||
|
else
|
||||||
|
snapshot=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get version...
|
||||||
if test $# != 1; then
|
if test $# != 1; then
|
||||||
echo "Usage: ./makesrcdist version"
|
echo "Usage: ./makesrcdist [--snapshot] VERSION"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
version=$1
|
version=$1
|
||||||
|
|
||||||
echo Creating tag for release...
|
# Check that version number has been updated everywhere...
|
||||||
git tag -m "Tag $version" v$version
|
if test $(grep AC_INIT configure.ac | awk '{print $2}') != "[$version],"; then
|
||||||
git push origin v$version
|
echo "Still need to update AC_INIT version in 'configure.ac'."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $(grep PDFIO_VERSION= configure | awk -F \" '{print $2}') != "$version"; then
|
||||||
|
echo "Still need to run 'autoconf -f'."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $(grep '<version>' pdfio_native.nuspec | sed -E -e '1,$s/^.*<version>([0-9.]+).*$/\1/') != "$version"; then
|
||||||
|
echo "Still need to update version in 'pdfio_native.nuspec'."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $(grep '<version>' pdfio_native.redist.nuspec | sed -E -e '1,$s/^.*<version>([0-9.]+).*$/\1/') != "$version"; then
|
||||||
|
echo "Still need to update version in 'pdfio_native.redist.nuspec'."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $(grep PDFIO_VERSION pdfio.h | awk -F \" '{print $2}') != "$version"; then
|
||||||
|
echo "Still need to update PDFIO_VERSION in 'pdfio.h'."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Tag release...
|
||||||
|
if test $snapshot = 0; then
|
||||||
|
echo Creating tag for release...
|
||||||
|
git tag -m "Tag $version" v$version
|
||||||
|
git push origin v$version
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make source archives...
|
||||||
echo Creating pdfio-$version.tar.gz...
|
echo Creating pdfio-$version.tar.gz...
|
||||||
git archive --format tar --prefix=pdfio-$version/ HEAD | gzip -v9 >pdfio-$version.tar.gz
|
git archive --format tar --prefix=pdfio-$version/ HEAD | gzip -v9 >pdfio-$version.tar.gz
|
||||||
gpg --detach-sign pdfio-$version.tar.gz
|
gpg --detach-sign pdfio-$version.tar.gz
|
||||||
|
@ -10,10 +10,6 @@
|
|||||||
// (<https://github.com/kokke/tiny-AES-c>)
|
// (<https://github.com/kokke/tiny-AES-c>)
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
|
|
||||||
|
|
||||||
@ -21,7 +17,7 @@
|
|||||||
// Local types...
|
// Local types...
|
||||||
//
|
//
|
||||||
|
|
||||||
typedef uint8_t state_t[4][4]; // 4x4 AES state table
|
typedef uint8_t state_t[4][4]; // 4x4 AES state table @private@
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -7,10 +7,6 @@
|
|||||||
// information.
|
// information.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
|
|
||||||
|
|
||||||
@ -331,6 +327,30 @@ pdfioArrayCreate(pdfio_file_t *pdf) // I - PDF file
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfioArrayDecrypt()' - Decrypt values in an array.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` on error
|
||||||
|
_pdfioArrayDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||||
|
pdfio_obj_t *obj, // I - Object
|
||||||
|
pdfio_array_t *a, // I - Array
|
||||||
|
size_t depth) // I - Depth
|
||||||
|
{
|
||||||
|
size_t i; // Looping var
|
||||||
|
_pdfio_value_t *v; // Current value
|
||||||
|
|
||||||
|
|
||||||
|
for (i = a->num_values, v = a->values; i > 0; i --, v ++)
|
||||||
|
{
|
||||||
|
if (!_pdfioValueDecrypt(pdf, obj, v, depth))
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// '_pdfioArrayDebug()' - Print the contents of an array.
|
// '_pdfioArrayDebug()' - Print the contents of an array.
|
||||||
//
|
//
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
//
|
//
|
||||||
// Common support functions for pdfio.
|
// Common support functions for pdfio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2023 by Michael R Sweet.
|
// Copyright © 2021-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.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
|
|
||||||
|
|
||||||
@ -145,7 +141,7 @@ _pdfioFileGets(pdfio_file_t *pdf, // I - PDF file
|
|||||||
*bufend = buffer + bufsize - 1; // Pointer to end of buffer
|
*bufend = buffer + bufsize - 1; // Pointer to end of buffer
|
||||||
|
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioFileGets(pdf=%p, buffer=%p, bufsize=%lu) bufpos=%ld, buffer=%p, bufptr=%p, bufend=%p\n", pdf, buffer, (unsigned long)bufsize, (long)pdf->bufpos, pdf->buffer, pdf->bufptr, pdf->bufend);
|
PDFIO_DEBUG("_pdfioFileGets(pdf=%p, buffer=%p, bufsize=%lu) bufpos=%ld, buffer=%p, bufptr=%p, bufend=%p, offset=%lu\n", pdf, buffer, (unsigned long)bufsize, (long)pdf->bufpos, pdf->buffer, pdf->bufptr, pdf->bufend, (unsigned long)(pdf->bufpos + (pdf->bufptr - pdf->buffer)));
|
||||||
|
|
||||||
while (!eol)
|
while (!eol)
|
||||||
{
|
{
|
||||||
@ -265,7 +261,7 @@ _pdfioFilePrintf(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
// Format the string...
|
// Format the string...
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
_pdfio_vsnprintf(pdf, buffer, sizeof(buffer), format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
// Write it...
|
// Write it...
|
||||||
@ -360,12 +356,12 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
|||||||
off_t offset, // I - Offset
|
off_t offset, // I - Offset
|
||||||
int whence) // I - Offset base
|
int whence) // I - Offset base
|
||||||
{
|
{
|
||||||
PDFIO_DEBUG("_pdfioFileSeek(pdf=%p, offset=%ld, whence=%d)\n", pdf, (long)offset, whence);
|
PDFIO_DEBUG("_pdfioFileSeek(pdf=%p, offset=%ld, whence=%d) pdf->bufpos=%lu\n", pdf, (long)offset, whence, (unsigned long)(pdf ? pdf->bufpos : 0));
|
||||||
|
|
||||||
// Adjust offset for relative seeks...
|
// Adjust offset for relative seeks...
|
||||||
if (whence == SEEK_CUR)
|
if (whence == SEEK_CUR)
|
||||||
{
|
{
|
||||||
offset += pdf->bufpos;
|
offset += pdf->bufpos + (pdf->bufptr - pdf->buffer);
|
||||||
whence = SEEK_SET;
|
whence = SEEK_SET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +404,7 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioFileSeek: Reset bufpos=%ld.\n", (long)pdf->bufpos);
|
PDFIO_DEBUG("_pdfioFileSeek: Reset bufpos=%ld, offset=%lu.\n", (long)pdf->bufpos, (unsigned long)offset);
|
||||||
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p, bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufend);
|
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p, bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufend);
|
||||||
|
|
||||||
pdf->bufpos = offset;
|
pdf->bufpos = offset;
|
||||||
|
124
pdfio-content.c
124
pdfio-content.c
@ -1131,20 +1131,20 @@ pdfioContentTextMeasure(
|
|||||||
if (ch < 128)
|
if (ch < 128)
|
||||||
{
|
{
|
||||||
// ASCII
|
// ASCII
|
||||||
*tempptr++ = ch;
|
*tempptr++ = (char)ch;
|
||||||
}
|
}
|
||||||
else if (ch < 2048)
|
else if (ch < 2048)
|
||||||
{
|
{
|
||||||
// 2-byte UTF-8
|
// 2-byte UTF-8
|
||||||
*tempptr++ = 0xc0 | ((ch >> 6) & 0x1f);
|
*tempptr++ = (char)(0xc0 | ((ch >> 6) & 0x1f));
|
||||||
*tempptr++ = 0x80 | (ch & 0x3f);
|
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 3-byte UTF-8
|
// 3-byte UTF-8
|
||||||
*tempptr++ = 0xe0 | ((ch >> 12) & 0x0f);
|
*tempptr++ = (char)(0xe0 | ((ch >> 12) & 0x0f));
|
||||||
*tempptr++ = 0x80 | ((ch >> 6) & 0x3f);
|
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||||
*tempptr++ = 0x80 | (ch & 0x3f);
|
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1152,7 +1152,7 @@ pdfioContentTextMeasure(
|
|||||||
s = temp;
|
s = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
ttfGetExtents(ttf, size, s, &extents);
|
ttfGetExtents(ttf, (float)size, s, &extents);
|
||||||
|
|
||||||
return (extents.right - extents.left);
|
return (extents.right - extents.left);
|
||||||
}
|
}
|
||||||
@ -1187,7 +1187,21 @@ pdfioContentTextMoveTo(
|
|||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'pdfioContentTextNextLine()' - Move to the next line.
|
// 'pdfioContentTextNewLine()' - Move to the next line.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` on failure
|
||||||
|
pdfioContentTextNewLine(
|
||||||
|
pdfio_stream_t *st) // I - Stream
|
||||||
|
{
|
||||||
|
return (pdfioStreamPuts(st, "T*\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioContentTextNextLine()' - Legacy function name preserved for binary compatibility.
|
||||||
|
//
|
||||||
|
// @private@
|
||||||
//
|
//
|
||||||
|
|
||||||
bool // O - `true` on success, `false` on failure
|
bool // O - `true` on success, `false` on failure
|
||||||
@ -1198,6 +1212,86 @@ pdfioContentTextNextLine(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioContentTextNewLineShow()' - Move to the next line and show text.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
// specifies that the current font maps to full Unicode. The "s" argument
|
||||||
|
// specifies a UTF-8 encoded string.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` on failure
|
||||||
|
pdfioContentTextNewLineShow(
|
||||||
|
pdfio_stream_t *st, // I - Stream
|
||||||
|
double ws, // I - Word spacing or `0.0` for none
|
||||||
|
double cs, // I - Character spacing or `0.0` for none
|
||||||
|
bool unicode, // I - Unicode text?
|
||||||
|
const char *s) // I - String to show
|
||||||
|
{
|
||||||
|
bool newline = false; // New line?
|
||||||
|
char op; // Text operator
|
||||||
|
|
||||||
|
|
||||||
|
// Write word and/or character spacing as needed...
|
||||||
|
if (ws > 0.0 || cs > 0.0)
|
||||||
|
{
|
||||||
|
// Use " operator to show text with word and character spacing...
|
||||||
|
if (!pdfioStreamPrintf(st, "%g %g", ws, cs))
|
||||||
|
return (false);
|
||||||
|
|
||||||
|
op = '\"';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use ' operator to show text with the defaults...
|
||||||
|
op = '\'';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the string...
|
||||||
|
if (!write_string(st, unicode, s, &newline))
|
||||||
|
return (false);
|
||||||
|
|
||||||
|
// Draw it...
|
||||||
|
if (newline)
|
||||||
|
return (pdfioStreamPrintf(st, "%c T*\n", op));
|
||||||
|
else
|
||||||
|
return (pdfioStreamPrintf(st, "%c\n", op));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioContentTextNewLineShowf()' - Show formatted text.
|
||||||
|
//
|
||||||
|
// 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"
|
||||||
|
// argument specifies that the current font maps to full Unicode. The "format"
|
||||||
|
// argument specifies a UTF-8 encoded `printf`-style format string.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` on failure
|
||||||
|
pdfioContentTextNewLineShowf(
|
||||||
|
pdfio_stream_t *st, // I - Stream
|
||||||
|
double ws, // I - Word spacing or `0.0` for none
|
||||||
|
double cs, // I - Character spacing or `0.0` for none
|
||||||
|
bool unicode, // I - Unicode text?
|
||||||
|
const char *format, // I - `printf`-style format string
|
||||||
|
...) // I - Additional arguments as needed
|
||||||
|
{
|
||||||
|
char buffer[8192]; // Text buffer
|
||||||
|
va_list ap; // Argument pointer
|
||||||
|
|
||||||
|
|
||||||
|
// Format the string...
|
||||||
|
va_start(ap, format);
|
||||||
|
vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
// Show it...
|
||||||
|
return (pdfioContentTextNewLineShow(st, ws, cs, unicode, buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'pdfioContentTextShow()' - Show text.
|
// 'pdfioContentTextShow()' - Show text.
|
||||||
//
|
//
|
||||||
@ -1230,9 +1324,9 @@ pdfioContentTextShow(
|
|||||||
//
|
//
|
||||||
// 'pdfioContentTextShowf()' - Show formatted text.
|
// 'pdfioContentTextShowf()' - Show formatted text.
|
||||||
//
|
//
|
||||||
// This function shows some text in a PDF content stream. The "unicode" argument
|
// This function shows some formatted text in a PDF content stream. The
|
||||||
// specifies that the current font maps to full Unicode. The "format" argument
|
// "unicode" argument specifies that the current font maps to full Unicode.
|
||||||
// specifies a UTF-8 encoded `printf`-style format string.
|
// The "format" argument specifies a UTF-8 encoded `printf`-style format string.
|
||||||
//
|
//
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -1548,7 +1642,7 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
*bufptr++ = (unsigned char)(cmap[i] >> 8);
|
*bufptr++ = (unsigned char)(cmap[i] >> 8);
|
||||||
*bufptr++ = (unsigned char)(cmap[i] & 255);
|
*bufptr++ = (unsigned char)(cmap[i] & 255);
|
||||||
|
|
||||||
glyphs[cmap[i]] = i;
|
glyphs[cmap[i]] = (unsigned short)i;
|
||||||
if (cmap[i] < min_glyph)
|
if (cmap[i] < min_glyph)
|
||||||
min_glyph = cmap[i];
|
min_glyph = cmap[i];
|
||||||
if (cmap[i] > max_glyph)
|
if (cmap[i] > max_glyph)
|
||||||
@ -1633,9 +1727,9 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
|
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
for (start = 0, w0 = ttfGetWidth(font, 0), i = 1; i < 65536; start = i, w0 = w1, i ++)
|
for (start = 0, w0 = ttfGetWidth(font, 0), w1 = 0, i = 1; i < 65536; start = i, w0 = w1, i ++)
|
||||||
{
|
{
|
||||||
while (i < 65536 && (w1 = ttfGetWidth(font, i)) == w0)
|
while (i < 65536 && (w1 = ttfGetWidth(font, (int)i)) == w0)
|
||||||
i ++;
|
i ++;
|
||||||
|
|
||||||
if ((i - start) > 1)
|
if ((i - start) > 1)
|
||||||
@ -1656,7 +1750,7 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
pdfioArrayAppendNumber(temp_array, w0);
|
pdfioArrayAppendNumber(temp_array, w0);
|
||||||
for (w0 = w1, i ++; i < 65536; w0 = w1, i ++)
|
for (w0 = w1, i ++; i < 65536; w0 = w1, i ++)
|
||||||
{
|
{
|
||||||
if ((w1 = ttfGetWidth(font, i)) == w0 && i < 65535)
|
if ((w1 = ttfGetWidth(font, (int)i)) == w0 && i < 65535)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
pdfioArrayAppendNumber(temp_array, w0);
|
pdfioArrayAppendNumber(temp_array, w0);
|
||||||
|
@ -118,6 +118,9 @@ extern bool pdfioContentTextEnd(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
|||||||
extern double pdfioContentTextMeasure(pdfio_obj_t *font, const char *s, double size) _PDFIO_PUBLIC;
|
extern double pdfioContentTextMeasure(pdfio_obj_t *font, const char *s, double size) _PDFIO_PUBLIC;
|
||||||
extern bool pdfioContentTextMoveLine(pdfio_stream_t *st, double tx, double ty) _PDFIO_PUBLIC;
|
extern bool pdfioContentTextMoveLine(pdfio_stream_t *st, double tx, double ty) _PDFIO_PUBLIC;
|
||||||
extern bool pdfioContentTextMoveTo(pdfio_stream_t *st, double tx, double ty) _PDFIO_PUBLIC;
|
extern bool pdfioContentTextMoveTo(pdfio_stream_t *st, double tx, double ty) _PDFIO_PUBLIC;
|
||||||
|
extern bool pdfioContentTextNewLine(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||||
|
extern bool pdfioContentTextNewLineShow(pdfio_stream_t *st, double ws, double cs, bool unicode, const char *s) _PDFIO_PUBLIC;
|
||||||
|
extern bool pdfioContentTextNewLineShowf(pdfio_stream_t *st, double ws, double cs, bool unicode, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(5,6);
|
||||||
extern bool pdfioContentTextNextLine(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
extern bool pdfioContentTextNextLine(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||||
extern bool pdfioContentTextShow(pdfio_stream_t *st, bool unicode, const char *s) _PDFIO_PUBLIC;
|
extern bool pdfioContentTextShow(pdfio_stream_t *st, bool unicode, const char *s) _PDFIO_PUBLIC;
|
||||||
extern bool pdfioContentTextShowf(pdfio_stream_t *st, bool unicode, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(3,4);
|
extern bool pdfioContentTextShowf(pdfio_stream_t *st, bool unicode, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(3,4);
|
||||||
|
@ -7,10 +7,6 @@
|
|||||||
// information.
|
// information.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
@ -403,16 +399,23 @@ _pdfioCryptoMakeRandom(uint8_t *buffer, // I - Buffer
|
|||||||
//
|
//
|
||||||
|
|
||||||
_pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
_pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
||||||
_pdfioCryptoMakeReader(
|
_pdfioCryptoMakeReader(
|
||||||
pdfio_file_t *pdf, // I - PDF file
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
pdfio_obj_t *obj, // I - PDF object
|
pdfio_obj_t *obj, // I - PDF object
|
||||||
_pdfio_crypto_ctx_t *ctx, // I - Pointer to crypto context
|
_pdfio_crypto_ctx_t *ctx, // I - Pointer to crypto context
|
||||||
uint8_t *iv, // I - Buffer for initialization vector
|
uint8_t *iv, // I - Buffer for initialization vector
|
||||||
size_t *ivlen) // IO - Size of initialization vector
|
size_t *ivlen) // IO - Size of initialization vector
|
||||||
{
|
{
|
||||||
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);
|
||||||
@ -424,6 +427,59 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
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))
|
||||||
|
{
|
||||||
|
*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 :
|
||||||
@ -432,7 +488,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
|
|
||||||
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, sizeof(pdf->file_key));
|
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);
|
||||||
@ -459,7 +515,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
|
|
||||||
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, sizeof(pdf->file_key));
|
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);
|
||||||
@ -495,7 +551,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
//
|
//
|
||||||
|
|
||||||
_pdfio_crypto_cb_t // O - Encryption callback or `NULL` for none
|
_pdfio_crypto_cb_t // O - Encryption callback or `NULL` for none
|
||||||
_pdfioCryptoMakeWriter(
|
_pdfioCryptoMakeWriter(
|
||||||
pdfio_file_t *pdf, // I - PDF file
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
pdfio_obj_t *obj, // I - PDF object
|
pdfio_obj_t *obj, // I - PDF object
|
||||||
_pdfio_crypto_ctx_t *ctx, // I - Pointer to crypto context
|
_pdfio_crypto_ctx_t *ctx, // I - Pointer to crypto context
|
||||||
@ -600,6 +656,8 @@ _pdfioCryptoUnlock(
|
|||||||
revision = (int)pdfioDictGetNumber(encrypt_dict, "R");
|
revision = (int)pdfioDictGetNumber(encrypt_dict, "R");
|
||||||
length = (int)pdfioDictGetNumber(encrypt_dict, "Length");
|
length = (int)pdfioDictGetNumber(encrypt_dict, "Length");
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfioCryptoUnlock: handler=%p(%s), version=%d, revision=%d, length=%d\n", (void *)handler, handler ? handler : "(null)", version, revision, length);
|
||||||
|
|
||||||
if (!handler || strcmp(handler, "Standard"))
|
if (!handler || strcmp(handler, "Standard"))
|
||||||
{
|
{
|
||||||
_pdfioFileError(pdf, "Unsupported security handler '%s'.", handler ? handler : "(null)");
|
_pdfioFileError(pdf, "Unsupported security handler '%s'.", handler ? handler : "(null)");
|
||||||
@ -648,6 +706,8 @@ _pdfioCryptoUnlock(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioCryptoUnlock: CFM=\"%s\"\n", cfm);
|
||||||
|
|
||||||
if (length < 40 || length > 128)
|
if (length < 40 || length > 128)
|
||||||
length = 128; // Default to 128 bits
|
length = 128; // Default to 128 bits
|
||||||
|
|
||||||
@ -773,17 +833,16 @@ _pdfioCryptoUnlock(
|
|||||||
{
|
{
|
||||||
// Matches!
|
// Matches!
|
||||||
memcpy(pdf->file_key, file_key, sizeof(pdf->file_key));
|
memcpy(pdf->file_key, file_key, sizeof(pdf->file_key));
|
||||||
|
memcpy(pdf->password, pad, sizeof(pdf->password));
|
||||||
|
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Not the owner password, try the user password...
|
||||||
* Not the owner password, try the user password...
|
|
||||||
*/
|
|
||||||
|
|
||||||
make_file_key(pdf->encryption, pdf->permissions, file_id, file_idlen, pad, pdf->owner_key, file_key);
|
make_file_key(pdf->encryption, pdf->permissions, file_id, file_idlen, pad, pdf->owner_key, file_key);
|
||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Fuse=%02X%02X%02X%02X...%02X%02X%02X%02X\n", file_key[0], file_key[1], file_key[2], file_key[3], file_key[12], file_key[13], file_key[14], file_key[15]);
|
PDFIO_DEBUG("_pdfioCryptoUnlock: Fuse=%02X%02X%02X%02X...%02X%02X%02X%02X\n", file_key[0], file_key[1], file_key[2], file_key[3], file_key[12], file_key[13], file_key[14], file_key[15]);
|
||||||
|
|
||||||
make_user_key(file_id, file_idlen, user_key);
|
make_user_key(file_id, file_idlen, own_user_key);
|
||||||
|
|
||||||
memcpy(pdf_user_key, pdf->user_key, sizeof(pdf_user_key));
|
memcpy(pdf_user_key, pdf->user_key, sizeof(pdf_user_key));
|
||||||
decrypt_user_key(pdf->encryption, file_key, pdf_user_key);
|
decrypt_user_key(pdf->encryption, file_key, pdf_user_key);
|
||||||
@ -791,10 +850,12 @@ _pdfioCryptoUnlock(
|
|||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Uuse=%02X%02X%02X%02X...%02X%02X%02X%02X\n", user_key[0], user_key[1], user_key[2], user_key[3], user_key[28], user_key[29], user_key[30], user_key[31]);
|
PDFIO_DEBUG("_pdfioCryptoUnlock: Uuse=%02X%02X%02X%02X...%02X%02X%02X%02X\n", user_key[0], user_key[1], user_key[2], user_key[3], user_key[28], user_key[29], user_key[30], user_key[31]);
|
||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Updf=%02X%02X%02X%02X...%02X%02X%02X%02X\n", pdf_user_key[0], pdf_user_key[1], pdf_user_key[2], pdf_user_key[3], pdf_user_key[28], pdf_user_key[29], pdf_user_key[30], pdf_user_key[31]);
|
PDFIO_DEBUG("_pdfioCryptoUnlock: Updf=%02X%02X%02X%02X...%02X%02X%02X%02X\n", pdf_user_key[0], pdf_user_key[1], pdf_user_key[2], pdf_user_key[3], pdf_user_key[28], pdf_user_key[29], pdf_user_key[30], pdf_user_key[31]);
|
||||||
|
|
||||||
if (!memcmp(pad, pdf_user_key, 32) || !memcmp(user_key, pdf_user_key, 16))
|
if (!memcmp(pad, pdf_user_key, 32) || !memcmp(own_user_key, pdf_user_key, 16))
|
||||||
{
|
{
|
||||||
// Matches!
|
// Matches!
|
||||||
memcpy(pdf->file_key, file_key, sizeof(pdf->file_key));
|
memcpy(pdf->file_key, file_key, sizeof(pdf->file_key));
|
||||||
|
memcpy(pdf->password, pad, sizeof(pdf->password));
|
||||||
|
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
53
pdfio-dict.c
53
pdfio-dict.c
@ -7,10 +7,6 @@
|
|||||||
// information.
|
// information.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
|
|
||||||
|
|
||||||
@ -162,6 +158,30 @@ pdfioDictCreate(pdfio_file_t *pdf) // I - PDF file
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfioDictDecrypt()' - Decrypt the values in a dictionary.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` on error
|
||||||
|
_pdfioDictDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||||
|
pdfio_obj_t *obj, // I - Object
|
||||||
|
pdfio_dict_t *dict, // I - Dictionary
|
||||||
|
size_t depth) // I - Depth
|
||||||
|
{
|
||||||
|
size_t i; // Looping var
|
||||||
|
_pdfio_pair_t *pair; // Current pair
|
||||||
|
|
||||||
|
|
||||||
|
for (i = dict->num_pairs, pair = dict->pairs; i > 0; i --, pair ++)
|
||||||
|
{
|
||||||
|
if (strcmp(pair->key, "ID") && !_pdfioValueDecrypt(pdf, obj, &pair->value, depth + 1))
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// '_pdfioDictDebug()' - Dump a dictionary to stderr.
|
// '_pdfioDictDebug()' - Dump a dictionary to stderr.
|
||||||
//
|
//
|
||||||
@ -406,9 +426,27 @@ pdfioDictGetString(pdfio_dict_t *dict, // I - Dictionary
|
|||||||
|
|
||||||
|
|
||||||
if (value && value->type == PDFIO_VALTYPE_STRING)
|
if (value && value->type == PDFIO_VALTYPE_STRING)
|
||||||
|
{
|
||||||
return (value->value.string);
|
return (value->value.string);
|
||||||
|
}
|
||||||
|
else if (value && value->type == PDFIO_VALTYPE_BINARY && value->value.binary.datalen < 4096)
|
||||||
|
{
|
||||||
|
// Convert binary string to regular string...
|
||||||
|
char temp[4096]; // Temporary string
|
||||||
|
|
||||||
|
memcpy(temp, value->value.binary.data, value->value.binary.datalen);
|
||||||
|
temp[value->value.binary.datalen] = '\0';
|
||||||
|
|
||||||
|
free(value->value.binary.data);
|
||||||
|
value->type = PDFIO_VALTYPE_STRING;
|
||||||
|
value->value.string = pdfioStringCreate(dict->pdf, temp);
|
||||||
|
|
||||||
|
return (value->value.string);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -522,7 +560,7 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
_pdfio_value_t value; // Dictionary value
|
_pdfio_value_t value; // Dictionary value
|
||||||
|
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioDictRead(pdf=%p)\n", pdf);
|
PDFIO_DEBUG("_pdfioDictRead(pdf=%p, obj=%p, tb=%p, depth=%lu)\n", pdf, obj, tb, (unsigned long)depth);
|
||||||
|
|
||||||
// Create a dictionary and start reading...
|
// Create a dictionary and start reading...
|
||||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||||
@ -534,6 +572,7 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
if (!strcmp(key, ">>"))
|
if (!strcmp(key, ">>"))
|
||||||
{
|
{
|
||||||
// End of dictionary...
|
// End of dictionary...
|
||||||
|
PDFIO_DEBUG("_pdfioDictRead: Returning dictionary value...\n");
|
||||||
return (dict);
|
return (dict);
|
||||||
}
|
}
|
||||||
else if (key[0] != '/')
|
else if (key[0] != '/')
|
||||||
@ -552,14 +591,14 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
if (!_pdfioValueRead(pdf, obj, tb, &value, depth))
|
if (!_pdfioValueRead(pdf, obj, tb, &value, depth))
|
||||||
{
|
{
|
||||||
_pdfioFileError(pdf, "Missing value for dictionary key.");
|
_pdfioFileError(pdf, "Missing value for dictionary key '%s'.", key + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_pdfioDictSetValue(dict, pdfioStringCreate(pdf, key + 1), &value))
|
if (!_pdfioDictSetValue(dict, pdfioStringCreate(pdf, key + 1), &value))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// PDFIO_DEBUG("_pdfioDictRead: Set %s.\n", key);
|
PDFIO_DEBUG("_pdfioDictRead: Set %s.\n", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dictionary is invalid - pdfioFileClose will free the memory, return NULL
|
// Dictionary is invalid - pdfioFileClose will free the memory, return NULL
|
||||||
|
855
pdfio-file.c
855
pdfio-file.c
File diff suppressed because it is too large
Load Diff
@ -453,9 +453,7 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[0]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
|
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[1]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
|
||||||
if (tb.bufptr && tb.bufptr < tb.bufend && (tb.bufptr[0] == 0x0d || tb.bufptr[0] == 0x0a))
|
|
||||||
tb.bufptr ++; // Skip trailing CR or LF after token
|
|
||||||
|
|
||||||
_pdfioTokenFlush(&tb);
|
_pdfioTokenFlush(&tb);
|
||||||
|
|
||||||
@ -466,6 +464,18 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
|||||||
PDFIO_DEBUG("_pdfioObjLoad: stream_offset=%lu.\n", (unsigned long)obj->stream_offset);
|
PDFIO_DEBUG("_pdfioObjLoad: stream_offset=%lu.\n", (unsigned long)obj->stream_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decrypt as needed...
|
||||||
|
if (obj->pdf->encryption)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioObjLoad: Decrypting value...\n");
|
||||||
|
|
||||||
|
if (!_pdfioValueDecrypt(obj->pdf, obj, &obj->value, 0))
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioObjLoad: Failed to decrypt.\n");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioObjLoad: ");
|
PDFIO_DEBUG("_pdfioObjLoad: ");
|
||||||
PDFIO_DEBUG_VALUE(&obj->value);
|
PDFIO_DEBUG_VALUE(&obj->value);
|
||||||
PDFIO_DEBUG("\n");
|
PDFIO_DEBUG("\n");
|
||||||
|
@ -7,10 +7,6 @@
|
|||||||
// information.
|
// information.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Private header file for PDFio.
|
// Private header file for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2023 by Michael R Sweet.
|
// Copyright © 2021-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.
|
||||||
@ -20,6 +20,7 @@
|
|||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
# include <inttypes.h>
|
# include <inttypes.h>
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
|
# include <locale.h>
|
||||||
# ifdef _WIN32
|
# ifdef _WIN32
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
# include <direct.h>
|
# include <direct.h>
|
||||||
@ -37,9 +38,11 @@
|
|||||||
# define unlink _unlink
|
# define unlink _unlink
|
||||||
# define vsnprintf _vsnprintf
|
# define vsnprintf _vsnprintf
|
||||||
# define write _write
|
# define write _write
|
||||||
# define F_OK 00 // POSIX parameters/flags
|
# ifndef F_OK
|
||||||
# define W_OK 02
|
# define F_OK 00 // POSIX parameters/flags
|
||||||
# define R_OK 04
|
# define W_OK 02
|
||||||
|
# define R_OK 04
|
||||||
|
# endif // !F_OK
|
||||||
# define O_RDONLY _O_RDONLY // Map standard POSIX open flags
|
# define O_RDONLY _O_RDONLY // Map standard POSIX open flags
|
||||||
# define O_WRONLY _O_WRONLY
|
# define O_WRONLY _O_WRONLY
|
||||||
# define O_CREAT _O_CREAT
|
# define O_CREAT _O_CREAT
|
||||||
@ -224,6 +227,7 @@ typedef struct _pdfio_objmap_s // PDF object map
|
|||||||
struct _pdfio_file_s // PDF file structure
|
struct _pdfio_file_s // PDF file structure
|
||||||
{
|
{
|
||||||
char *filename; // Filename
|
char *filename; // Filename
|
||||||
|
struct lconv *loc; // Locale data
|
||||||
char *version; // Version number
|
char *version; // Version number
|
||||||
pdfio_rect_t media_box, // Default MediaBox value
|
pdfio_rect_t media_box, // Default MediaBox value
|
||||||
crop_box; // Default CropBox value
|
crop_box; // Default CropBox value
|
||||||
@ -237,7 +241,8 @@ struct _pdfio_file_s // PDF file structure
|
|||||||
pdfio_permission_t permissions; // Access permissions (encrypted PDF files)
|
pdfio_permission_t permissions; // Access permissions (encrypted PDF files)
|
||||||
uint8_t file_key[16], // File encryption key
|
uint8_t file_key[16], // File encryption key
|
||||||
owner_key[32], // Owner encryption key
|
owner_key[32], // Owner encryption key
|
||||||
user_key[32]; // User encryption key
|
user_key[32], // User encryption key
|
||||||
|
password[32]; // Padded password
|
||||||
size_t file_keylen, // Length of file encryption key
|
size_t file_keylen, // Length of file encryption key
|
||||||
owner_keylen, // Length of owner encryption key
|
owner_keylen, // Length of owner encryption key
|
||||||
user_keylen; // Length of user encryption key
|
user_keylen; // Length of user encryption key
|
||||||
@ -265,7 +270,8 @@ struct _pdfio_file_s // PDF file structure
|
|||||||
alloc_dicts; // Allocated dictionaries
|
alloc_dicts; // Allocated dictionaries
|
||||||
pdfio_dict_t **dicts; // Dictionaries
|
pdfio_dict_t **dicts; // Dictionaries
|
||||||
size_t num_objs, // Number of objects
|
size_t num_objs, // Number of objects
|
||||||
alloc_objs; // Allocated objects
|
alloc_objs, // Allocated objects
|
||||||
|
last_obj; // Last object added
|
||||||
pdfio_obj_t **objs, // Objects
|
pdfio_obj_t **objs, // Objects
|
||||||
*current_obj; // Current object being written/read
|
*current_obj; // Current object being written/read
|
||||||
size_t num_objmaps, // Number of object maps
|
size_t num_objmaps, // Number of object maps
|
||||||
@ -320,6 +326,10 @@ struct _pdfio_stream_s // Stream
|
|||||||
// Functions...
|
// Functions...
|
||||||
//
|
//
|
||||||
|
|
||||||
|
extern double _pdfio_strtod(pdfio_file_t *pdf, const char *s) _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 void _pdfioArrayDebug(pdfio_array_t *a, FILE *fp) _PDFIO_INTERNAL;
|
extern void _pdfioArrayDebug(pdfio_array_t *a, FILE *fp) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioArrayDelete(pdfio_array_t *a) _PDFIO_INTERNAL;
|
extern void _pdfioArrayDelete(pdfio_array_t *a) _PDFIO_INTERNAL;
|
||||||
extern _pdfio_value_t *_pdfioArrayGetValue(pdfio_array_t *a, size_t n) _PDFIO_INTERNAL;
|
extern _pdfio_value_t *_pdfioArrayGetValue(pdfio_array_t *a, size_t n) _PDFIO_INTERNAL;
|
||||||
@ -344,6 +354,7 @@ extern void _pdfioCryptoSHA256Finish(_pdfio_sha256_t *ctx, uint8_t *Message_Dig
|
|||||||
extern bool _pdfioCryptoUnlock(pdfio_file_t *pdf, pdfio_password_cb_t password_cb, void *password_data) _PDFIO_INTERNAL;
|
extern bool _pdfioCryptoUnlock(pdfio_file_t *pdf, pdfio_password_cb_t password_cb, void *password_data) _PDFIO_INTERNAL;
|
||||||
|
|
||||||
extern void _pdfioDictClear(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
extern void _pdfioDictClear(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
||||||
|
extern bool _pdfioDictDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_dict_t *dict, size_t depth) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioDictDebug(pdfio_dict_t *dict, FILE *fp) _PDFIO_INTERNAL;
|
extern void _pdfioDictDebug(pdfio_dict_t *dict, FILE *fp) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioDictDelete(pdfio_dict_t *dict) _PDFIO_INTERNAL;
|
extern void _pdfioDictDelete(pdfio_dict_t *dict) _PDFIO_INTERNAL;
|
||||||
extern _pdfio_value_t *_pdfioDictGetValue(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
extern _pdfio_value_t *_pdfioDictGetValue(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
||||||
@ -387,6 +398,7 @@ extern void _pdfioTokenPush(_pdfio_token_t *tb, const char *token) _PDFIO_INTER
|
|||||||
extern bool _pdfioTokenRead(_pdfio_token_t *tb, char *buffer, size_t bufsize);
|
extern bool _pdfioTokenRead(_pdfio_token_t *tb, char *buffer, size_t bufsize);
|
||||||
|
|
||||||
extern _pdfio_value_t *_pdfioValueCopy(pdfio_file_t *pdfdst, _pdfio_value_t *vdst, pdfio_file_t *pdfsrc, _pdfio_value_t *vsrc) _PDFIO_INTERNAL;
|
extern _pdfio_value_t *_pdfioValueCopy(pdfio_file_t *pdfdst, _pdfio_value_t *vdst, pdfio_file_t *pdfsrc, _pdfio_value_t *vsrc) _PDFIO_INTERNAL;
|
||||||
|
extern bool _pdfioValueDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioValueDebug(_pdfio_value_t *v, FILE *fp) _PDFIO_INTERNAL;
|
extern void _pdfioValueDebug(_pdfio_value_t *v, FILE *fp) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioValueDelete(_pdfio_value_t *v) _PDFIO_INTERNAL;
|
extern void _pdfioValueDelete(_pdfio_value_t *v) _PDFIO_INTERNAL;
|
||||||
extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
|
extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
//
|
//
|
||||||
// PDF stream functions for PDFio.
|
// PDF stream functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2023 by Michael R Sweet.
|
// Copyright © 2021-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.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
|
|
||||||
|
|
||||||
@ -691,7 +687,7 @@ pdfioStreamPrintf(
|
|||||||
|
|
||||||
// Format the string...
|
// Format the string...
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
_pdfio_vsnprintf(st->pdf, buffer, sizeof(buffer), format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
// Write the string...
|
// Write the string...
|
||||||
@ -1070,7 +1066,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
else if (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out)
|
else if (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out)
|
||||||
@ -1131,7 +1127,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
||||||
@ -1201,7 +1197,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
||||||
|
457
pdfio-string.c
457
pdfio-string.c
@ -1,16 +1,12 @@
|
|||||||
//
|
//
|
||||||
// PDF dictionary functions for PDFio.
|
// PDF string functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021 by Michael R Sweet.
|
// Copyright © 2021-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.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
|
|
||||||
|
|
||||||
@ -18,7 +14,360 @@
|
|||||||
// Local functions...
|
// Local functions...
|
||||||
//
|
//
|
||||||
|
|
||||||
static int compare_strings(char **a, char **b);
|
static size_t find_string(pdfio_file_t *pdf, const char *s, int *rdiff);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfio_strtod()' - Convert a string to a double value.
|
||||||
|
//
|
||||||
|
// This function wraps strtod() to avoid locale issues.
|
||||||
|
//
|
||||||
|
|
||||||
|
double // O - Double value
|
||||||
|
_pdfio_strtod(pdfio_file_t *pdf, // I - PDF file
|
||||||
|
const char *s) // I - String
|
||||||
|
{
|
||||||
|
char temp[64], // Temporary buffer
|
||||||
|
*tempptr; // Pointer into temporary buffer
|
||||||
|
|
||||||
|
|
||||||
|
// See if the locale has a special decimal point string...
|
||||||
|
if (!pdf->loc)
|
||||||
|
return (strtod(s, NULL));
|
||||||
|
|
||||||
|
// Copy leading sign, numbers, period, and then numbers...
|
||||||
|
tempptr = temp;
|
||||||
|
temp[sizeof(temp) - 1] = '\0';
|
||||||
|
|
||||||
|
while (*s && *s != '.')
|
||||||
|
{
|
||||||
|
if (tempptr < (temp + sizeof(temp) - 1))
|
||||||
|
*tempptr++ = *s++;
|
||||||
|
else
|
||||||
|
return (0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*s == '.')
|
||||||
|
{
|
||||||
|
// Convert decimal point to locale equivalent...
|
||||||
|
size_t declen = strlen(pdf->loc->decimal_point);
|
||||||
|
// Length of decimal point
|
||||||
|
s ++;
|
||||||
|
|
||||||
|
if (declen <= (sizeof(temp) - (size_t)(tempptr - temp)))
|
||||||
|
{
|
||||||
|
memcpy(tempptr, pdf->loc->decimal_point, declen);
|
||||||
|
tempptr += declen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy any remaining characters...
|
||||||
|
while (*s)
|
||||||
|
{
|
||||||
|
if (tempptr < (temp + sizeof(temp) - 1))
|
||||||
|
*tempptr++ = *s++;
|
||||||
|
else
|
||||||
|
return (0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nul-terminate the temporary string and convert the string...
|
||||||
|
*tempptr = '\0';
|
||||||
|
|
||||||
|
return (strtod(temp, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfio_vsnprintf()' - Format a string.
|
||||||
|
//
|
||||||
|
// This function emulates vsnprintf() to avoid locale issues.
|
||||||
|
//
|
||||||
|
|
||||||
|
ssize_t // O - Number of bytes
|
||||||
|
_pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||||
|
char *buffer, // I - Output buffer
|
||||||
|
size_t bufsize, // I - Size of output buffer
|
||||||
|
const char *format, // I - printf-style format string
|
||||||
|
va_list ap) // I - Pointer to additional arguments
|
||||||
|
{
|
||||||
|
char *bufptr, // Pointer to position in buffer
|
||||||
|
*bufend, // Pointer to end of buffer
|
||||||
|
size, // Size character (h, l, L)
|
||||||
|
type; // Format type character
|
||||||
|
int width, // Width of field
|
||||||
|
prec; // Number of characters of precision
|
||||||
|
char tformat[100], // Temporary format string for snprintf()
|
||||||
|
*tptr, // Pointer into temporary format
|
||||||
|
temp[1024], // Buffer for formatted numbers
|
||||||
|
*tempptr; // Pointer into buffer
|
||||||
|
char *s; // Pointer to string
|
||||||
|
ssize_t bytes; // Total number of bytes needed
|
||||||
|
const char *dec = pdf->loc ? pdf->loc->decimal_point : ".";
|
||||||
|
// Decimal point string
|
||||||
|
char *decptr; // Pointer to decimal point
|
||||||
|
|
||||||
|
|
||||||
|
// Loop through the format string, formatting as needed...
|
||||||
|
bufptr = buffer;
|
||||||
|
bufend = buffer + bufsize - 1;
|
||||||
|
*bufend = '\0';
|
||||||
|
bytes = 0;
|
||||||
|
|
||||||
|
while (*format)
|
||||||
|
{
|
||||||
|
if (*format == '%')
|
||||||
|
{
|
||||||
|
// Format character...
|
||||||
|
tptr = tformat;
|
||||||
|
*tptr++ = *format++;
|
||||||
|
|
||||||
|
if (*format == '%')
|
||||||
|
{
|
||||||
|
if (bufptr < bufend)
|
||||||
|
*bufptr++ = *format;
|
||||||
|
bytes ++;
|
||||||
|
format ++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (strchr(" -+#\'", *format))
|
||||||
|
{
|
||||||
|
*tptr++ = *format++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*format == '*')
|
||||||
|
{
|
||||||
|
// Get width from argument...
|
||||||
|
format ++;
|
||||||
|
width = va_arg(ap, int);
|
||||||
|
|
||||||
|
snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", width);
|
||||||
|
tptr += strlen(tptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
width = 0;
|
||||||
|
|
||||||
|
while (isdigit(*format & 255))
|
||||||
|
{
|
||||||
|
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||||
|
*tptr++ = *format;
|
||||||
|
|
||||||
|
width = width * 10 + *format++ - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*format == '.')
|
||||||
|
{
|
||||||
|
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||||
|
*tptr++ = *format;
|
||||||
|
|
||||||
|
format ++;
|
||||||
|
|
||||||
|
if (*format == '*')
|
||||||
|
{
|
||||||
|
// Get precision from argument...
|
||||||
|
format ++;
|
||||||
|
prec = va_arg(ap, int);
|
||||||
|
|
||||||
|
snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", prec);
|
||||||
|
tptr += strlen(tptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prec = 0;
|
||||||
|
|
||||||
|
while (isdigit(*format & 255))
|
||||||
|
{
|
||||||
|
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||||
|
*tptr++ = *format;
|
||||||
|
|
||||||
|
prec = prec * 10 + *format++ - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*format == 'l' && format[1] == 'l')
|
||||||
|
{
|
||||||
|
size = 'L';
|
||||||
|
|
||||||
|
if (tptr < (tformat + sizeof(tformat) - 2))
|
||||||
|
{
|
||||||
|
*tptr++ = 'l';
|
||||||
|
*tptr++ = 'l';
|
||||||
|
}
|
||||||
|
|
||||||
|
format += 2;
|
||||||
|
}
|
||||||
|
else if (*format == 'h' || *format == 'l' || *format == 'L')
|
||||||
|
{
|
||||||
|
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||||
|
*tptr++ = *format;
|
||||||
|
|
||||||
|
size = *format++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*format)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||||
|
*tptr++ = *format;
|
||||||
|
|
||||||
|
type = *format++;
|
||||||
|
*tptr = '\0';
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case 'E' : // Floating point formats
|
||||||
|
case 'G' :
|
||||||
|
case 'e' :
|
||||||
|
case 'f' :
|
||||||
|
case 'g' :
|
||||||
|
if ((size_t)(width + 2) > sizeof(temp))
|
||||||
|
break;
|
||||||
|
|
||||||
|
snprintf(temp, sizeof(temp), tformat, va_arg(ap, double));
|
||||||
|
|
||||||
|
if ((decptr = strstr(temp, dec)) != NULL)
|
||||||
|
{
|
||||||
|
// Convert locale decimal point to "."
|
||||||
|
PDFIO_DEBUG("_pdfio_vsnprintf: Before \"%s\"\n", temp);
|
||||||
|
tempptr = decptr + strlen(dec);
|
||||||
|
if (tempptr > (decptr + 1))
|
||||||
|
memmove(decptr + 1, tempptr, strlen(tempptr) + 1);
|
||||||
|
*decptr = '.';
|
||||||
|
|
||||||
|
// Strip trailing 0's...
|
||||||
|
for (tempptr = temp + strlen(temp) - 1; tempptr > temp && *tempptr == '0'; tempptr --)
|
||||||
|
*tempptr = '\0';
|
||||||
|
|
||||||
|
if (*tempptr == '.')
|
||||||
|
*tempptr = '\0'; // Strip trailing decimal point
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfio_vsnprintf: After \"%s\"\n", temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy to the output buffer
|
||||||
|
bytes += (int)strlen(temp);
|
||||||
|
|
||||||
|
if (bufptr < bufend)
|
||||||
|
{
|
||||||
|
strncpy(bufptr, temp, (size_t)(bufend - bufptr - 1));
|
||||||
|
bufptr += strlen(bufptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'B' : // Integer formats
|
||||||
|
case 'X' :
|
||||||
|
case 'b' :
|
||||||
|
case 'd' :
|
||||||
|
case 'i' :
|
||||||
|
case 'o' :
|
||||||
|
case 'u' :
|
||||||
|
case 'x' :
|
||||||
|
if ((size_t)(width + 2) > sizeof(temp))
|
||||||
|
break;
|
||||||
|
|
||||||
|
# ifdef HAVE_LONG_LONG
|
||||||
|
if (size == 'L')
|
||||||
|
snprintf(temp, sizeof(temp), tformat, va_arg(ap, long long));
|
||||||
|
else
|
||||||
|
# endif // HAVE_LONG_LONG
|
||||||
|
if (size == 'l')
|
||||||
|
snprintf(temp, sizeof(temp), tformat, va_arg(ap, long));
|
||||||
|
else
|
||||||
|
snprintf(temp, sizeof(temp), tformat, va_arg(ap, int));
|
||||||
|
|
||||||
|
bytes += (int)strlen(temp);
|
||||||
|
|
||||||
|
if (bufptr < bufend)
|
||||||
|
{
|
||||||
|
strncpy(bufptr, temp, (size_t)(bufend - bufptr - 1));
|
||||||
|
bufptr += strlen(bufptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p' : // Pointer value
|
||||||
|
if ((size_t)(width + 2) > sizeof(temp))
|
||||||
|
break;
|
||||||
|
|
||||||
|
snprintf(temp, sizeof(temp), tformat, va_arg(ap, void *));
|
||||||
|
|
||||||
|
bytes += (int)strlen(temp);
|
||||||
|
|
||||||
|
if (bufptr < bufend)
|
||||||
|
{
|
||||||
|
strncpy(bufptr, temp, (size_t)(bufend - bufptr - 1));
|
||||||
|
bufptr += strlen(bufptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c' : // Character or character array
|
||||||
|
bytes += width;
|
||||||
|
|
||||||
|
if (bufptr < bufend)
|
||||||
|
{
|
||||||
|
if (width <= 1)
|
||||||
|
{
|
||||||
|
*bufptr++ = (char)va_arg(ap, int);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((bufptr + width) > bufend)
|
||||||
|
width = (int)(bufend - bufptr);
|
||||||
|
|
||||||
|
memcpy(bufptr, va_arg(ap, char *), (size_t)width);
|
||||||
|
bufptr += width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's' : // String
|
||||||
|
if ((s = va_arg(ap, char *)) == NULL)
|
||||||
|
s = "(null)";
|
||||||
|
|
||||||
|
bytes += strlen(s);
|
||||||
|
|
||||||
|
if (bufptr < bufend)
|
||||||
|
{
|
||||||
|
strncpy(bufptr, s, (size_t)(bufend - bufptr - 1));
|
||||||
|
bufptr += strlen(bufptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n' : // Output number of chars so far
|
||||||
|
*(va_arg(ap, int *)) = (int)bytes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Literal character...
|
||||||
|
bytes ++;
|
||||||
|
|
||||||
|
if (bufptr < bufend)
|
||||||
|
*bufptr++ = *format++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nul-terminate the string and return the number of characters needed.
|
||||||
|
if (bufptr < bufend)
|
||||||
|
{
|
||||||
|
// Everything fit in the buffer...
|
||||||
|
*bufptr = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfio_vsnprintf: Returning %ld \"%s\"\n", (long)bytes, buffer);
|
||||||
|
|
||||||
|
return (bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -36,8 +385,9 @@ pdfioStringCreate(
|
|||||||
pdfio_file_t *pdf, // I - PDF file
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
const char *s) // I - Nul-terminated string
|
const char *s) // I - Nul-terminated string
|
||||||
{
|
{
|
||||||
char *news; // New string
|
char *news; // New string
|
||||||
char **match; // Matching string
|
size_t idx; // Index into strings
|
||||||
|
int diff; // Different
|
||||||
|
|
||||||
|
|
||||||
PDFIO_DEBUG("pdfioStringCreate(pdf=%p, s=\"%s\")\n", pdf, s);
|
PDFIO_DEBUG("pdfioStringCreate(pdf=%p, s=\"%s\")\n", pdf, s);
|
||||||
@ -47,8 +397,17 @@ pdfioStringCreate(
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
// See if the string has already been added...
|
// See if the string has already been added...
|
||||||
if (pdf->num_strings > 0 && (match = (char **)bsearch(&s, pdf->strings, pdf->num_strings, sizeof(char *), (int (*)(const void *, const void *))compare_strings)) != NULL)
|
if (pdf->num_strings > 0)
|
||||||
return (*match);
|
{
|
||||||
|
idx = find_string(pdf, s, &diff);
|
||||||
|
if (diff == 0)
|
||||||
|
return (pdf->strings[idx]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx = 0;
|
||||||
|
diff = -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Not already added, so add it...
|
// Not already added, so add it...
|
||||||
if ((news = strdup(s)) == NULL)
|
if ((news = strdup(s)) == NULL)
|
||||||
@ -69,11 +428,17 @@ pdfioStringCreate(
|
|||||||
pdf->alloc_strings += 128;
|
pdf->alloc_strings += 128;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Change to insertion sort as needed...
|
// Insert the string...
|
||||||
pdf->strings[pdf->num_strings ++] = news;
|
if (diff > 0)
|
||||||
|
idx ++;
|
||||||
|
|
||||||
if (pdf->num_strings > 1)
|
PDFIO_DEBUG("pdfioStringCreate: Inserting \"%s\" at %u\n", news, (unsigned)idx);
|
||||||
qsort(pdf->strings, pdf->num_strings, sizeof(char *), (int (*)(const void *, const void *))compare_strings);
|
|
||||||
|
if (idx < pdf->num_strings)
|
||||||
|
memmove(pdf->strings + idx + 1, pdf->strings + idx, (pdf->num_strings - idx) * sizeof(char *));
|
||||||
|
|
||||||
|
pdf->strings[idx] = news;
|
||||||
|
pdf->num_strings ++;
|
||||||
|
|
||||||
PDFIO_DEBUG("pdfioStringCreate: %lu strings\n", (unsigned long)pdf->num_strings);
|
PDFIO_DEBUG("pdfioStringCreate: %lu strings\n", (unsigned long)pdf->num_strings);
|
||||||
|
|
||||||
@ -124,17 +489,67 @@ _pdfioStringIsAllocated(
|
|||||||
pdfio_file_t *pdf, // I - PDF file
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
const char *s) // I - String
|
const char *s) // I - String
|
||||||
{
|
{
|
||||||
return (pdf->num_strings > 0 && bsearch(&s, pdf->strings, pdf->num_strings, sizeof(char *), (int (*)(const void *, const void *))compare_strings) != NULL);
|
int diff; // Difference
|
||||||
|
|
||||||
|
|
||||||
|
if (pdf->num_strings == 0)
|
||||||
|
return (false);
|
||||||
|
|
||||||
|
find_string(pdf, s, &diff);
|
||||||
|
|
||||||
|
return (diff == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'compare_strings()' - Compare two strings.
|
// 'find_string()' - Find an element in the array.
|
||||||
//
|
//
|
||||||
|
|
||||||
static int // O - Result of comparison
|
static size_t // O - Index of match
|
||||||
compare_strings(char **a, // I - First string
|
find_string(pdfio_file_t *pdf, // I - PDF file
|
||||||
char **b) // I - Second string
|
const char *s, // I - String to find
|
||||||
|
int *rdiff) // O - Difference of match
|
||||||
{
|
{
|
||||||
return (strcmp(*a, *b));
|
size_t left, // Left side of search
|
||||||
|
right, // Right side of search
|
||||||
|
current; // Current element
|
||||||
|
int diff; // Comparison with current element
|
||||||
|
|
||||||
|
|
||||||
|
// Do a binary search for the string...
|
||||||
|
left = 0;
|
||||||
|
right = pdf->num_strings - 1;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
current = (left + right) / 2;
|
||||||
|
diff = strcmp(s, pdf->strings[current]);
|
||||||
|
|
||||||
|
if (diff == 0)
|
||||||
|
break;
|
||||||
|
else if (diff < 0)
|
||||||
|
right = current;
|
||||||
|
else
|
||||||
|
left = current;
|
||||||
|
}
|
||||||
|
while ((right - left) > 1);
|
||||||
|
|
||||||
|
if (diff != 0)
|
||||||
|
{
|
||||||
|
// Check the last 1 or 2 elements...
|
||||||
|
if ((diff = strcmp(s, pdf->strings[left])) <= 0)
|
||||||
|
{
|
||||||
|
current = left;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
diff = strcmp(s, pdf->strings[right]);
|
||||||
|
current = right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the closest string and the difference...
|
||||||
|
*rdiff = diff;
|
||||||
|
|
||||||
|
return (current);
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,6 @@
|
|||||||
// information.
|
// information.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
|
|
||||||
|
|
||||||
@ -212,9 +208,10 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
*bufend, // End of buffer
|
*bufend, // End of buffer
|
||||||
state = '\0'; // Current state
|
state = '\0'; // Current state
|
||||||
bool saw_nul = false; // Did we see a nul character?
|
bool saw_nul = false; // Did we see a nul character?
|
||||||
|
size_t count = 0; // Number of whitespace/comment bytes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// "state" is:
|
// "state" is:
|
||||||
//
|
//
|
||||||
// - '\0' for idle
|
// - '\0' for idle
|
||||||
@ -233,21 +230,45 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
// Skip leading whitespace...
|
// Skip leading whitespace...
|
||||||
while ((ch = get_char(tb)) != EOF)
|
while ((ch = get_char(tb)) != EOF)
|
||||||
{
|
{
|
||||||
|
count ++;
|
||||||
|
|
||||||
if (ch == '%')
|
if (ch == '%')
|
||||||
{
|
{
|
||||||
// Skip comment
|
// Skip comment
|
||||||
|
PDFIO_DEBUG("_pdfioTokenRead: Skipping comment...\n");
|
||||||
while ((ch = get_char(tb)) != EOF)
|
while ((ch = get_char(tb)) != EOF)
|
||||||
{
|
{
|
||||||
|
count ++;
|
||||||
|
|
||||||
if (ch == '\n' || ch == '\r')
|
if (ch == '\n' || ch == '\r')
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
else if (count > 2048)
|
||||||
|
{
|
||||||
|
_pdfioFileError(tb->pdf, "Comment too long.");
|
||||||
|
*bufptr = '\0';
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!isspace(ch))
|
else if (!isspace(ch))
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
else if (count > 2048)
|
||||||
|
{
|
||||||
|
_pdfioFileError(tb->pdf, "Too much whitespace.");
|
||||||
|
*bufptr = '\0';
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == EOF)
|
if (ch == EOF)
|
||||||
|
{
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
// Check for delimiters...
|
// Check for delimiters...
|
||||||
if (strchr(PDFIO_DELIM_CHARS, ch) != NULL)
|
if (strchr(PDFIO_DELIM_CHARS, ch) != NULL)
|
||||||
@ -267,6 +288,8 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
*bufptr++ = (char)ch;
|
*bufptr++ = (char)ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfioTokenRead: state='%c'\n", state);
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case '(' : // Literal string
|
case '(' : // Literal string
|
||||||
@ -358,6 +381,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
{
|
{
|
||||||
// Out of space
|
// Out of space
|
||||||
_pdfioFileError(tb->pdf, "Token too large.");
|
_pdfioFileError(tb->pdf, "Token too large.");
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -365,6 +389,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
if (ch != ')')
|
if (ch != ')')
|
||||||
{
|
{
|
||||||
_pdfioFileError(tb->pdf, "Unterminated string literal.");
|
_pdfioFileError(tb->pdf, "Unterminated string literal.");
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,6 +409,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
{
|
{
|
||||||
// Out of space...
|
// Out of space...
|
||||||
_pdfioFileError(tb->pdf, "Token too large.");
|
_pdfioFileError(tb->pdf, "Token too large.");
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,9 +443,17 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
{
|
{
|
||||||
// Out of space...
|
// Out of space...
|
||||||
_pdfioFileError(tb->pdf, "Token too large.");
|
_pdfioFileError(tb->pdf, "Token too large.");
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ch == '\r')
|
||||||
|
{
|
||||||
|
// Look for a trailing LF
|
||||||
|
if ((ch = get_char(tb)) != EOF && ch != '\n')
|
||||||
|
tb->bufptr --;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'N' : // number
|
case 'N' : // number
|
||||||
@ -428,6 +462,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
if (!isdigit(ch) && ch != '.')
|
if (!isdigit(ch) && ch != '.')
|
||||||
{
|
{
|
||||||
// End of number...
|
// End of number...
|
||||||
|
PDFIO_DEBUG("_pdfioTokenRead: End of number with ch=0x%02x\n", ch);
|
||||||
tb->bufptr --;
|
tb->bufptr --;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -440,6 +475,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
{
|
{
|
||||||
// Out of space...
|
// Out of space...
|
||||||
_pdfioFileError(tb->pdf, "Token too large.");
|
_pdfioFileError(tb->pdf, "Token too large.");
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -466,12 +502,17 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
if (!isxdigit(tch & 255))
|
if (!isxdigit(tch & 255))
|
||||||
{
|
{
|
||||||
_pdfioFileError(tb->pdf, "Bad # escape in name.");
|
_pdfioFileError(tb->pdf, "Bad # escape in name.");
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
else if (isdigit(tch))
|
else if (isdigit(tch))
|
||||||
|
{
|
||||||
ch = ((ch & 255) << 4) | (tch - '0');
|
ch = ((ch & 255) << 4) | (tch - '0');
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ch = ((ch & 255) << 4) | (tolower(tch) - 'a' + 10);
|
ch = ((ch & 255) << 4) | (tolower(tch) - 'a' + 10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,9 +524,17 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
{
|
{
|
||||||
// Out of space
|
// Out of space
|
||||||
_pdfioFileError(tb->pdf, "Token too large.");
|
_pdfioFileError(tb->pdf, "Token too large.");
|
||||||
|
*bufptr = '\0';
|
||||||
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
|
||||||
@ -505,9 +554,12 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
else if (!isspace(ch & 255) && !isxdigit(ch & 255))
|
else if (!isspace(ch & 255) && !isxdigit(ch & 255))
|
||||||
{
|
{
|
||||||
_pdfioFileError(tb->pdf, "Syntax error: '<%c'", ch);
|
_pdfioFileError(tb->pdf, "Syntax error: '<%c'", ch);
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (isxdigit(ch))
|
if (isxdigit(ch))
|
||||||
@ -516,25 +568,39 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
{
|
{
|
||||||
// Hex digit
|
// Hex digit
|
||||||
*bufptr++ = (char)ch;
|
*bufptr++ = (char)ch;
|
||||||
|
count = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Too large
|
// Too large
|
||||||
_pdfioFileError(tb->pdf, "Token too large.");
|
_pdfioFileError(tb->pdf, "Token too large.");
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!isspace(ch))
|
else if (!isspace(ch))
|
||||||
{
|
{
|
||||||
_pdfioFileError(tb->pdf, "Invalid hex string character '%c'.", ch);
|
_pdfioFileError(tb->pdf, "Invalid hex string character '%c'.", ch);
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count ++;
|
||||||
|
if (count > 2048)
|
||||||
|
{
|
||||||
|
_pdfioFileError(tb->pdf, "Too much whitespace.");
|
||||||
|
*bufptr = '\0';
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while ((ch = get_char(tb)) != EOF && ch != '>');
|
while ((ch = get_char(tb)) != EOF && ch != '>');
|
||||||
|
|
||||||
if (ch == EOF)
|
if (ch == EOF)
|
||||||
{
|
{
|
||||||
_pdfioFileError(tb->pdf, "Unterminated hex string.");
|
_pdfioFileError(tb->pdf, "Unterminated hex string.");
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -547,6 +613,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_pdfioFileError(tb->pdf, "Syntax error: '>%c'.", ch);
|
_pdfioFileError(tb->pdf, "Syntax error: '>%c'.", ch);
|
||||||
|
*bufptr = '\0';
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -554,7 +621,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
|
|
||||||
*bufptr = '\0';
|
*bufptr = '\0';
|
||||||
|
|
||||||
// PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
||||||
|
|
||||||
return (bufptr > buffer);
|
return (bufptr > buffer);
|
||||||
}
|
}
|
||||||
@ -591,7 +658,6 @@ get_char(_pdfio_token_t *tb) // I - Token buffer
|
|||||||
tb->bufptr = tb->buffer;
|
tb->bufptr = tb->buffer;
|
||||||
tb->bufend = tb->buffer + bytes;
|
tb->bufend = tb->buffer + bytes;
|
||||||
|
|
||||||
#if 0
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
unsigned char *ptr; // Pointer into buffer
|
unsigned char *ptr; // Pointer into buffer
|
||||||
|
|
||||||
@ -605,7 +671,6 @@ get_char(_pdfio_token_t *tb) // I - Token buffer
|
|||||||
}
|
}
|
||||||
PDFIO_DEBUG("'\n");
|
PDFIO_DEBUG("'\n");
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
#endif // 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the next character...
|
// Return the next character...
|
||||||
|
279
pdfio-value.c
279
pdfio-value.c
@ -1,17 +1,20 @@
|
|||||||
//
|
//
|
||||||
// PDF value functions for PDFio.
|
// PDF value functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2023 by Michael R Sweet.
|
// Copyright © 2021-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.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "pdfio-private.h"
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Include necessary headers...
|
// Local functions...
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
static time_t get_date_time(const char *s);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -109,6 +112,101 @@ _pdfioValueCopy(pdfio_file_t *pdfdst, // I - Destination PDF file
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfioValueDecrypt()' - Decrypt a value.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` on error
|
||||||
|
_pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||||
|
pdfio_obj_t *obj, // I - Object
|
||||||
|
_pdfio_value_t *v, // I - Value
|
||||||
|
size_t depth)// I - Depth
|
||||||
|
{
|
||||||
|
_pdfio_crypto_ctx_t ctx; // Decryption context
|
||||||
|
_pdfio_crypto_cb_t cb; // Decryption callback
|
||||||
|
size_t ivlen; // Number of initialization vector bytes
|
||||||
|
uint8_t temp[32768]; // Temporary buffer for decryption
|
||||||
|
size_t templen; // Number of actual data bytes
|
||||||
|
time_t timeval; // Date/time value
|
||||||
|
|
||||||
|
|
||||||
|
if (depth > PDFIO_MAX_DEPTH)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Value too deep.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (v->type)
|
||||||
|
{
|
||||||
|
default :
|
||||||
|
// Do nothing
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFIO_VALTYPE_ARRAY :
|
||||||
|
return (_pdfioArrayDecrypt(pdf, obj, v->value.array, depth + 1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFIO_VALTYPE_DICT :
|
||||||
|
return (_pdfioDictDecrypt(pdf, obj, v->value.dict, depth + 1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFIO_VALTYPE_BINARY :
|
||||||
|
// Decrypt the binary string...
|
||||||
|
if (v->value.binary.datalen > (sizeof(temp) - 32))
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to read encrypted binary string - too long.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ivlen = v->value.binary.datalen;
|
||||||
|
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL)
|
||||||
|
return (false);
|
||||||
|
|
||||||
|
templen = (cb)(&ctx, temp, v->value.binary.data + ivlen, v->value.binary.datalen - ivlen);
|
||||||
|
|
||||||
|
// Copy the decrypted string back to the value and adjust the length...
|
||||||
|
memcpy(v->value.binary.data, temp, templen);
|
||||||
|
|
||||||
|
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128)
|
||||||
|
v->value.binary.datalen = templen - temp[templen - 1];
|
||||||
|
else
|
||||||
|
v->value.binary.datalen = templen;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFIO_VALTYPE_STRING :
|
||||||
|
// Decrypt regular string...
|
||||||
|
templen = strlen(v->value.string);
|
||||||
|
if (templen > (sizeof(temp) - 33))
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to read encrypted string - too long.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ivlen = templen;
|
||||||
|
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, (uint8_t *)v->value.string, &ivlen)) == NULL)
|
||||||
|
return (false);
|
||||||
|
|
||||||
|
templen = (cb)(&ctx, temp, (uint8_t *)v->value.string + ivlen, templen - ivlen);
|
||||||
|
temp[templen] = '\0';
|
||||||
|
|
||||||
|
if ((timeval = get_date_time((char *)temp)) != 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, (char *)temp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// '_pdfioValueDebug()' - Print the contents of a value.
|
// '_pdfioValueDebug()' - Print the contents of a value.
|
||||||
//
|
//
|
||||||
@ -200,6 +298,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
size_t depth) // I - Depth of value
|
size_t depth) // I - Depth of value
|
||||||
{
|
{
|
||||||
char token[32768]; // Token buffer
|
char token[32768]; // Token buffer
|
||||||
|
time_t timeval; // Date/time value
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static const char * const valtypes[] =
|
static const char * const valtypes[] =
|
||||||
{
|
{
|
||||||
@ -249,73 +348,10 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL)
|
if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
else if (!strncmp(token, "(D:", 3))
|
else if (!strncmp(token, "(D:", 3) && (timeval = get_date_time(token + 1)) != 0)
|
||||||
{
|
{
|
||||||
// Possible date value of the form:
|
v->type = PDFIO_VALTYPE_DATE;
|
||||||
//
|
v->value.date = timeval;
|
||||||
// (D:YYYYMMDDhhmmssZ)
|
|
||||||
// (D:YYYYMMDDhhmmss+HH'mm)
|
|
||||||
// (D:YYYYMMDDhhmmss-HH'mm)
|
|
||||||
//
|
|
||||||
int i; // Looping var
|
|
||||||
struct tm dateval; // Date value
|
|
||||||
int offset; // Date offset
|
|
||||||
|
|
||||||
for (i = 3; i < 17; i ++)
|
|
||||||
{
|
|
||||||
if (!isdigit(token[i] & 255))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= 17)
|
|
||||||
{
|
|
||||||
if (token[i] == 'Z')
|
|
||||||
{
|
|
||||||
i ++;
|
|
||||||
}
|
|
||||||
else if (token[i] == '-' || token[i] == '+')
|
|
||||||
{
|
|
||||||
if (isdigit(token[i + 1] & 255) && isdigit(token[i + 2] & 255) && token[i + 3] == '\'' && isdigit(token[i + 4] & 255) && isdigit(token[i + 5] & 255))
|
|
||||||
{
|
|
||||||
i += 6;
|
|
||||||
if (token[i] == '\'')
|
|
||||||
i ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token[i])
|
|
||||||
{
|
|
||||||
// Just a string...
|
|
||||||
v->type = PDFIO_VALTYPE_STRING;
|
|
||||||
v->value.string = pdfioStringCreate(pdf, token + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Date value...
|
|
||||||
memset(&dateval, 0, sizeof(dateval));
|
|
||||||
|
|
||||||
dateval.tm_year = (token[3] - '0') * 1000 + (token[4] - '0') * 100 + (token[5] - '0') * 10 + token[6] - '0' - 1900;
|
|
||||||
dateval.tm_mon = (token[7] - '0') * 10 + token[8] - '0' - 1;
|
|
||||||
dateval.tm_mday = (token[9] - '0') * 10 + token[10] - '0';
|
|
||||||
dateval.tm_hour = (token[11] - '0') * 10 + token[12] - '0';
|
|
||||||
dateval.tm_min = (token[13] - '0') * 10 + token[14] - '0';
|
|
||||||
dateval.tm_sec = (token[15] - '0') * 10 + token[16] - '0';
|
|
||||||
|
|
||||||
if (token[17] == 'Z')
|
|
||||||
{
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
offset = (token[18] - '0') * 600 + (token[19] - '0') * 60 + (token[20] - '0') * 10 + token[21] - '0';
|
|
||||||
if (token[17] == '-')
|
|
||||||
offset = -offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
v->type = PDFIO_VALTYPE_DATE;
|
|
||||||
v->value.date = mktime(&dateval) + offset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (token[0] == '(')
|
else if (token[0] == '(')
|
||||||
{
|
{
|
||||||
@ -367,36 +403,6 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
*dataptr++ = (unsigned char)d;
|
*dataptr++ = (unsigned char)d;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj && pdf->encryption)
|
|
||||||
{
|
|
||||||
// Decrypt the string...
|
|
||||||
_pdfio_crypto_ctx_t ctx; // Decryption context
|
|
||||||
_pdfio_crypto_cb_t cb; // Decryption callback
|
|
||||||
size_t ivlen; // Number of initialization vector bytes
|
|
||||||
uint8_t temp[32768]; // Temporary buffer for decryption
|
|
||||||
size_t templen; // Number of actual data bytes
|
|
||||||
|
|
||||||
if (v->value.binary.datalen > (sizeof(temp) - 32))
|
|
||||||
{
|
|
||||||
_pdfioFileError(pdf, "Unable to read encrypted binary string - too long.");
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ivlen = v->value.binary.datalen;
|
|
||||||
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL)
|
|
||||||
return (false);
|
|
||||||
|
|
||||||
templen = (cb)(&ctx, temp, v->value.binary.data + ivlen, v->value.binary.datalen - ivlen);
|
|
||||||
|
|
||||||
// Copy the decrypted string back to the value and adjust the length...
|
|
||||||
memcpy(v->value.binary.data, temp, templen);
|
|
||||||
|
|
||||||
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128)
|
|
||||||
v->value.binary.datalen = templen - temp[templen - 1];
|
|
||||||
else
|
|
||||||
v->value.binary.datalen = templen;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (strchr("0123456789-+.", token[0]) != NULL)
|
else if (strchr("0123456789-+.", token[0]) != NULL)
|
||||||
{
|
{
|
||||||
@ -491,7 +497,7 @@ _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 = (double)strtod(token, NULL);
|
v->value.number = _pdfio_strtod(pdf, token);
|
||||||
}
|
}
|
||||||
else if (!strcmp(token, "true") || !strcmp(token, "false"))
|
else if (!strcmp(token, "true") || !strcmp(token, "false"))
|
||||||
{
|
{
|
||||||
@ -732,3 +738,76 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'get_date_time()' - Convert PDF date/time value to time_t.
|
||||||
|
//
|
||||||
|
|
||||||
|
static time_t // O - Time in seconds
|
||||||
|
get_date_time(const char *s) // I - PDF date/time value
|
||||||
|
{
|
||||||
|
int i; // Looping var
|
||||||
|
struct tm dateval; // Date value
|
||||||
|
int offset; // Date offset
|
||||||
|
|
||||||
|
|
||||||
|
// Possible date value of the form:
|
||||||
|
//
|
||||||
|
// (D:YYYYMMDDhhmmssZ)
|
||||||
|
// (D:YYYYMMDDhhmmss+HH'mm)
|
||||||
|
// (D:YYYYMMDDhhmmss-HH'mm)
|
||||||
|
//
|
||||||
|
|
||||||
|
for (i = 2; i < 16; i ++)
|
||||||
|
{
|
||||||
|
if (!isdigit(s[i] & 255) || !s[i])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= 16)
|
||||||
|
{
|
||||||
|
if (s[i] == 'Z')
|
||||||
|
{
|
||||||
|
i ++;
|
||||||
|
}
|
||||||
|
else if (s[i] == '-' || s[i] == '+')
|
||||||
|
{
|
||||||
|
if (isdigit(s[i + 1] & 255) && isdigit(s[i + 2] & 255) && s[i + 3] == '\'' && isdigit(s[i + 4] & 255) && isdigit(s[i + 5] & 255))
|
||||||
|
{
|
||||||
|
i += 6;
|
||||||
|
if (s[i] == '\'')
|
||||||
|
i ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s[i])
|
||||||
|
{
|
||||||
|
// Just a string...
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Date value...
|
||||||
|
memset(&dateval, 0, sizeof(dateval));
|
||||||
|
|
||||||
|
dateval.tm_year = (s[2] - '0') * 1000 + (s[3] - '0') * 100 + (s[4] - '0') * 10 + s[5] - '0' - 1900;
|
||||||
|
dateval.tm_mon = (s[6] - '0') * 10 + s[7] - '0' - 1;
|
||||||
|
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';
|
||||||
|
|
||||||
|
if (s[16] == 'Z')
|
||||||
|
{
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset = (s[17] - '0') * 600 + (s[18] - '0') * 60 + (s[19] - '0') * 10 + s[20] - '0';
|
||||||
|
if (s[16] == '-')
|
||||||
|
offset = -offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (mktime(&dateval) + offset);
|
||||||
|
}
|
||||||
|
11
pdfio.h
11
pdfio.h
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Public header file for PDFio.
|
// Public header file for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2023 by Michael R Sweet.
|
// Copyright © 2021-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.
|
||||||
@ -23,7 +23,7 @@ extern "C" {
|
|||||||
// Version number...
|
// Version number...
|
||||||
//
|
//
|
||||||
|
|
||||||
# define PDFIO_VERSION "1.2.0"
|
# define PDFIO_VERSION "1.3.0"
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -33,9 +33,11 @@ extern "C" {
|
|||||||
# if defined(__has_extension) || defined(__GNUC__)
|
# if defined(__has_extension) || defined(__GNUC__)
|
||||||
# define _PDFIO_PUBLIC __attribute__ ((visibility("default")))
|
# define _PDFIO_PUBLIC __attribute__ ((visibility("default")))
|
||||||
# define _PDFIO_FORMAT(a,b) __attribute__ ((__format__(__printf__, a,b)))
|
# define _PDFIO_FORMAT(a,b) __attribute__ ((__format__(__printf__, a,b)))
|
||||||
|
# define _PDFIO_DEPRECATED __attribute__ ((deprecated)) _PDFIO_PUBLIC
|
||||||
# else
|
# else
|
||||||
# define _PDFIO_PUBLIC
|
# define _PDFIO_PUBLIC
|
||||||
# define _PDFIO_FORMAT(a,b)
|
# define _PDFIO_FORMAT(a,b)
|
||||||
|
# define _PDFIO_DEPRECATED
|
||||||
# endif // __has_extension || __GNUC__
|
# endif // __has_extension || __GNUC__
|
||||||
|
|
||||||
|
|
||||||
@ -63,7 +65,7 @@ typedef enum pdfio_encryption_e // PDF encryption modes
|
|||||||
PDFIO_ENCRYPTION_RC4_40, // 40-bit RC4 encryption (PDF 1.3)
|
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)
|
PDFIO_ENCRYPTION_AES_256 // 256-bit AES encryption (PDF 2.0) @exclude all@
|
||||||
} pdfio_encryption_t;
|
} pdfio_encryption_t;
|
||||||
typedef enum pdfio_filter_e // Compression/decompression filters for streams
|
typedef enum pdfio_filter_e // Compression/decompression filters for streams
|
||||||
{
|
{
|
||||||
@ -180,13 +182,16 @@ extern bool pdfioDictSetStringf(pdfio_dict_t *dict, const char *key, const char
|
|||||||
extern bool pdfioFileClose(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
extern bool pdfioFileClose(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||||
extern pdfio_file_t *pdfioFileCreate(const char *filename, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
extern pdfio_file_t *pdfioFileCreate(const char *filename, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileCreateArrayObj(pdfio_file_t *pdf, pdfio_array_t *array) _PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileCreateArrayObj(pdfio_file_t *pdf, pdfio_array_t *array) _PDFIO_PUBLIC;
|
||||||
|
extern pdfio_obj_t *pdfioFileCreateNumberObj(pdfio_file_t *pdf, double number) _PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
||||||
extern pdfio_file_t *pdfioFileCreateOutput(pdfio_output_cb_t output_cb, void *output_ctx, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
extern pdfio_file_t *pdfioFileCreateOutput(pdfio_output_cb_t output_cb, void *output_ctx, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||||
// TODO: Add number, array, string, etc. versions of pdfioFileCreateObject?
|
// TODO: Add number, array, string, etc. versions of pdfioFileCreateObject?
|
||||||
extern pdfio_stream_t *pdfioFileCreatePage(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
extern pdfio_stream_t *pdfioFileCreatePage(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
||||||
|
extern pdfio_obj_t *pdfioFileCreateStringObj(pdfio_file_t *pdf, const char *s) _PDFIO_PUBLIC;
|
||||||
extern pdfio_file_t *pdfioFileCreateTemporary(char *buffer, size_t bufsize, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
extern pdfio_file_t *pdfioFileCreateTemporary(char *buffer, size_t bufsize, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileFindObj(pdfio_file_t *pdf, size_t number) _PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileFindObj(pdfio_file_t *pdf, size_t number) _PDFIO_PUBLIC;
|
||||||
extern const char *pdfioFileGetAuthor(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
extern const char *pdfioFileGetAuthor(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||||
|
extern pdfio_dict_t *pdfioFileGetCatalog(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||||
extern time_t pdfioFileGetCreationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
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;
|
||||||
|
@ -9,5 +9,5 @@ Version: @PDFIO_VERSION@
|
|||||||
URL: https://www.msweet.org/pdfio
|
URL: https://www.msweet.org/pdfio
|
||||||
Requires: @PKGCONFIG_REQUIRES@
|
Requires: @PKGCONFIG_REQUIRES@
|
||||||
Libs: @PKGCONFIG_LIBS@
|
Libs: @PKGCONFIG_LIBS@
|
||||||
Libs.private: @PKGCONFIG_LIBS_PRIVATE@ -lm
|
Libs.private: @PKGCONFIG_LIBS_PRIVATE@
|
||||||
Cflags: @PKGCONFIG_CFLAGS@
|
Cflags: @PKGCONFIG_CFLAGS@
|
||||||
|
@ -141,6 +141,9 @@ pdfioContentTextEnd
|
|||||||
pdfioContentTextMeasure
|
pdfioContentTextMeasure
|
||||||
pdfioContentTextMoveLine
|
pdfioContentTextMoveLine
|
||||||
pdfioContentTextMoveTo
|
pdfioContentTextMoveTo
|
||||||
|
pdfioContentTextNewLine
|
||||||
|
pdfioContentTextNewLineShow
|
||||||
|
pdfioContentTextNewLineShowf
|
||||||
pdfioContentTextNextLine
|
pdfioContentTextNextLine
|
||||||
pdfioContentTextShow
|
pdfioContentTextShow
|
||||||
pdfioContentTextShowJustified
|
pdfioContentTextShowJustified
|
||||||
@ -179,9 +182,11 @@ pdfioFileCreateFontObjFromFile
|
|||||||
pdfioFileCreateICCObjFromFile
|
pdfioFileCreateICCObjFromFile
|
||||||
pdfioFileCreateImageObjFromData
|
pdfioFileCreateImageObjFromData
|
||||||
pdfioFileCreateImageObjFromFile
|
pdfioFileCreateImageObjFromFile
|
||||||
|
pdfioFileCreateNumberObj
|
||||||
pdfioFileCreateObj
|
pdfioFileCreateObj
|
||||||
pdfioFileCreateOutput
|
pdfioFileCreateOutput
|
||||||
pdfioFileCreatePage
|
pdfioFileCreatePage
|
||||||
|
pdfioFileCreateStringObj
|
||||||
pdfioFileCreateTemporary
|
pdfioFileCreateTemporary
|
||||||
pdfioFileFindObj
|
pdfioFileFindObj
|
||||||
pdfioFileGetAuthor
|
pdfioFileGetAuthor
|
||||||
|
@ -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.2.0</version>
|
<version>1.3.0</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>
|
||||||
@ -13,10 +13,10 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<description>PDFio Library for VS2019+</description>
|
<description>PDFio Library for VS2019+</description>
|
||||||
<summary>PDFio is a simple C library for reading and writing PDF files. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
<summary>PDFio is a simple C library for reading and writing PDF files. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
||||||
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
<copyright>Copyright © 2019-2024 by Michael R Sweet</copyright>
|
||||||
<tags>pdf file native</tags>
|
<tags>pdf file native</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="pdfio_native.redist" version="1.2.0" />
|
<dependency id="pdfio_native.redist" version="1.3.0" />
|
||||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -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.2.0</version>
|
<version>1.3.0</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>
|
||||||
@ -13,7 +13,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<description>PDFio Library for VS2019+</description>
|
<description>PDFio Library for VS2019+</description>
|
||||||
<summary>PDFio is a simple C library for reading and writing PDF files. This package provides the redistributable content for the PDFio library. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
<summary>PDFio is a simple C library for reading and writing PDF files. This package provides the redistributable content for the PDFio library. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
||||||
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
<copyright>Copyright © 2019-2024 by Michael R Sweet</copyright>
|
||||||
<tags>pdf file native</tags>
|
<tags>pdf file native</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||||
|
16
runtests.bat
Normal file
16
runtests.bat
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
:: Script to run unit test program
|
||||||
|
::
|
||||||
|
:: Usage:
|
||||||
|
::
|
||||||
|
:: .\runtests.bat x64\{Debug|Release}
|
||||||
|
::
|
||||||
|
|
||||||
|
:: Copy dependent DLLs to the named build directory
|
||||||
|
echo Copying DLLs
|
||||||
|
copy packages\zlib_native.redist.1.2.11\build\native\bin\x64\Debug\*.dll %1
|
||||||
|
copy packages\zlib_native.redist.1.2.11\build\native\bin\x64\Release\*.dll %1
|
||||||
|
|
||||||
|
:: Run unit test program
|
||||||
|
echo Running %1\testpdfio.exe
|
||||||
|
cd %1
|
||||||
|
testpdfio.exe
|
126
testpdfio.c
126
testpdfio.c
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Test program for PDFio.
|
// Test program for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021 by Michael R Sweet.
|
// Copyright © 2021-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.
|
||||||
@ -10,16 +10,13 @@
|
|||||||
//
|
//
|
||||||
// ./testpdfio
|
// ./testpdfio
|
||||||
//
|
//
|
||||||
// ./testpdfio FILENAME [OBJECT-NUMBER] [FILENAME [OBJECT-NUMBER]] ...
|
// ./testpdfio [--verbose] FILENAME [OBJECT-NUMBER] [FILENAME [OBJECT-NUMBER]] ...
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
#include "pdfio-content.h"
|
#include "pdfio-content.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <locale.h>
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
# define M_PI 3.14159265358979323846264338327950288
|
# define M_PI 3.14159265358979323846264338327950288
|
||||||
#endif // M_PI
|
#endif // M_PI
|
||||||
@ -51,7 +48,7 @@ static int write_images_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
|||||||
static int write_jpeg_test(pdfio_file_t *pdf, const char *title, int number, pdfio_obj_t *font, pdfio_obj_t *image);
|
static int write_jpeg_test(pdfio_file_t *pdf, const char *title, int number, pdfio_obj_t *font, pdfio_obj_t *image);
|
||||||
static int write_png_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
static int write_png_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
||||||
static int write_text_test(pdfio_file_t *pdf, int first_page, pdfio_obj_t *font, const char *filename);
|
static int write_text_test(pdfio_file_t *pdf, int first_page, pdfio_obj_t *font, const char *filename);
|
||||||
static int write_unit_file(pdfio_file_t *inpdf, pdfio_file_t *outpdf, size_t *num_pages, size_t *first_image);
|
static int write_unit_file(pdfio_file_t *inpdf, const char *outname, pdfio_file_t *outpdf, size_t *num_pages, size_t *first_image);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -65,6 +62,8 @@ main(int argc, // I - Number of command-line arguments
|
|||||||
int ret = 0; // Return value
|
int ret = 0; // Return value
|
||||||
|
|
||||||
|
|
||||||
|
fprintf(stderr, "testpdfio: Test locale is \"%s\".\n", setlocale(LC_ALL, getenv("LANG")));
|
||||||
|
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
{
|
{
|
||||||
int i; // Looping var
|
int i; // Looping var
|
||||||
@ -1045,7 +1044,7 @@ do_unit_tests(void)
|
|||||||
else
|
else
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
if (write_unit_file(inpdf, "testpdfio-out.pdf", outpdf, &num_pages, &first_image))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_unit_file("testpdfio-out.pdf", num_pages, first_image, false))
|
if (read_unit_file("testpdfio-out.pdf", num_pages, first_image, false))
|
||||||
@ -1064,7 +1063,7 @@ do_unit_tests(void)
|
|||||||
else
|
else
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
if (write_unit_file(inpdf, "testpdfio-out2.pdf", outpdf, &num_pages, &first_image))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
close(outfd);
|
close(outfd);
|
||||||
@ -1085,7 +1084,7 @@ do_unit_tests(void)
|
|||||||
else
|
else
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
if (write_unit_file(inpdf, "testpdfio-rc4.pdf", outpdf, &num_pages, &first_image))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (read_unit_file("testpdfio-rc4.pdf", num_pages, first_image, false))
|
if (read_unit_file("testpdfio-rc4.pdf", num_pages, first_image, false))
|
||||||
@ -1104,7 +1103,7 @@ do_unit_tests(void)
|
|||||||
else
|
else
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
if (write_unit_file(inpdf, "testpdfio-rc4p.pdf", outpdf, &num_pages, &first_image))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (read_unit_file("testpdfio-rc4p.pdf", num_pages, first_image, false))
|
if (read_unit_file("testpdfio-rc4p.pdf", num_pages, first_image, false))
|
||||||
@ -1122,7 +1121,7 @@ do_unit_tests(void)
|
|||||||
else
|
else
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
if (write_unit_file(inpdf, "testpdfio-aes.pdf", outpdf, &num_pages, &first_image))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (read_unit_file("testpdfio-aes.pdf", num_pages, first_image, false))
|
if (read_unit_file("testpdfio-aes.pdf", num_pages, first_image, false))
|
||||||
@ -1140,7 +1139,7 @@ do_unit_tests(void)
|
|||||||
else
|
else
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
if (write_unit_file(inpdf, "testpdfio-aesp.pdf", outpdf, &num_pages, &first_image))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (read_unit_file("testpdfio-aesp.pdf", num_pages, first_image, false))
|
if (read_unit_file("testpdfio-aesp.pdf", num_pages, first_image, false))
|
||||||
@ -1152,7 +1151,7 @@ do_unit_tests(void)
|
|||||||
else
|
else
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
if (write_unit_file(inpdf, "<temporary>", outpdf, &num_pages, &first_image))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (read_unit_file(temppdf, num_pages, first_image, false))
|
if (read_unit_file(temppdf, num_pages, first_image, false))
|
||||||
@ -1309,6 +1308,7 @@ read_unit_file(const char *filename, // I - File to read
|
|||||||
bool is_output) // I - File written with output callback?
|
bool is_output) // I - File written with output callback?
|
||||||
{
|
{
|
||||||
pdfio_file_t *pdf; // PDF file
|
pdfio_file_t *pdf; // PDF file
|
||||||
|
pdfio_dict_t *catalog; // Catalog dictionary
|
||||||
size_t i; // Looping var
|
size_t i; // Looping var
|
||||||
const char *s; // String
|
const char *s; // String
|
||||||
bool error = false; // Error callback data
|
bool error = false; // Error callback data
|
||||||
@ -1321,6 +1321,83 @@ read_unit_file(const char *filename, // I - File to read
|
|||||||
else
|
else
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
|
// Get the root object/catalog dictionary
|
||||||
|
fputs("pdfioFileGetCatalog: ", stdout);
|
||||||
|
if ((catalog = pdfioFileGetCatalog(pdf)) != NULL)
|
||||||
|
{
|
||||||
|
puts("PASS");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL (got NULL, expected dictionary)");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify some catalog values...
|
||||||
|
fputs("pdfioDictGetName(PageLayout): ", stdout);
|
||||||
|
if ((s = pdfioDictGetName(catalog, "PageLayout")) != NULL && !strcmp(s, "SinglePage"))
|
||||||
|
{
|
||||||
|
puts("PASS");
|
||||||
|
}
|
||||||
|
else if (s)
|
||||||
|
{
|
||||||
|
printf("FAIL (got '%s', expected 'SinglePage')\n", s);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL (got NULL, expected 'SinglePage')");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("pdfioDictGetName(PageLayout): ", stdout);
|
||||||
|
if ((s = pdfioDictGetName(catalog, "PageLayout")) != NULL && !strcmp(s, "SinglePage"))
|
||||||
|
{
|
||||||
|
puts("PASS");
|
||||||
|
}
|
||||||
|
else if (s)
|
||||||
|
{
|
||||||
|
printf("FAIL (got '%s', expected 'SinglePage')\n", s);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL (got NULL, expected 'SinglePage')");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("pdfioDictGetName(PageMode): ", stdout);
|
||||||
|
if ((s = pdfioDictGetName(catalog, "PageMode")) != NULL && !strcmp(s, "UseThumbs"))
|
||||||
|
{
|
||||||
|
puts("PASS");
|
||||||
|
}
|
||||||
|
else if (s)
|
||||||
|
{
|
||||||
|
printf("FAIL (got '%s', expected 'UseThumbs')\n", s);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL (got NULL, expected 'UseThumbs')");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("pdfioDictGetString(Lang): ", stdout);
|
||||||
|
if ((s = pdfioDictGetString(catalog, "Lang")) != NULL && !strcmp(s, "en"))
|
||||||
|
{
|
||||||
|
puts("PASS");
|
||||||
|
}
|
||||||
|
else if (s)
|
||||||
|
{
|
||||||
|
printf("FAIL (got '%s', expected 'en')\n", s);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL (got NULL, expected 'en')");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
// Verify metadata...
|
// Verify metadata...
|
||||||
fputs("pdfioFileGetAuthor: ", stdout);
|
fputs("pdfioFileGetAuthor: ", stdout);
|
||||||
if ((s = pdfioFileGetAuthor(pdf)) != NULL && !strcmp(s, "Michael R Sweet"))
|
if ((s = pdfioFileGetAuthor(pdf)) != NULL && !strcmp(s, "Michael R Sweet"))
|
||||||
@ -3247,6 +3324,7 @@ write_text_test(pdfio_file_t *pdf, // I - PDF file
|
|||||||
static int // O - Exit status
|
static int // O - Exit status
|
||||||
write_unit_file(
|
write_unit_file(
|
||||||
pdfio_file_t *inpdf, // I - Input PDF file
|
pdfio_file_t *inpdf, // I - Input PDF file
|
||||||
|
const char *outname, // I - Output PDF file name
|
||||||
pdfio_file_t *outpdf, // I - Output PDF file
|
pdfio_file_t *outpdf, // I - Output PDF file
|
||||||
size_t *num_pages, // O - Number of pages
|
size_t *num_pages, // O - Number of pages
|
||||||
size_t *first_image) // O - First image object
|
size_t *first_image) // O - First image object
|
||||||
@ -3256,8 +3334,26 @@ write_unit_file(
|
|||||||
*gray_jpg, // gray.jpg image
|
*gray_jpg, // gray.jpg image
|
||||||
*helvetica, // Helvetica font
|
*helvetica, // Helvetica font
|
||||||
*page; // Page from test PDF file
|
*page; // Page from test PDF file
|
||||||
|
pdfio_dict_t *catalog; // Catalog dictionary
|
||||||
|
|
||||||
|
|
||||||
|
// Get the root object/catalog dictionary
|
||||||
|
fputs("pdfioFileGetCatalog: ", stdout);
|
||||||
|
if ((catalog = pdfioFileGetCatalog(outpdf)) != NULL)
|
||||||
|
{
|
||||||
|
puts("PASS");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL (got NULL, expected dictionary)");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set some catalog values...
|
||||||
|
pdfioDictSetName(catalog, "PageLayout", "SinglePage");
|
||||||
|
pdfioDictSetName(catalog, "PageMode", "UseThumbs");
|
||||||
|
pdfioDictSetString(catalog, "Lang", "en");
|
||||||
|
|
||||||
// Set info values...
|
// Set info values...
|
||||||
fputs("pdfioFileGet/SetAuthor: ", stdout);
|
fputs("pdfioFileGet/SetAuthor: ", stdout);
|
||||||
pdfioFileSetAuthor(outpdf, "Michael R Sweet");
|
pdfioFileSetAuthor(outpdf, "Michael R Sweet");
|
||||||
@ -3441,7 +3537,7 @@ write_unit_file(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close the new PDF file...
|
// Close the new PDF file...
|
||||||
fputs("pdfioFileClose(...): ", stdout);
|
printf("pdfioFileClose(\"%s\"): ", outname);
|
||||||
if (pdfioFileClose(outpdf))
|
if (pdfioFileClose(outpdf))
|
||||||
puts("PASS");
|
puts("PASS");
|
||||||
else
|
else
|
||||||
|
2
ttf.c
2
ttf.c
@ -1307,7 +1307,7 @@ read_cmap(ttf_t *font) // I - Font
|
|||||||
{
|
{
|
||||||
// Use an "obscure indexing trick" (words from the spec, not
|
// Use an "obscure indexing trick" (words from the spec, not
|
||||||
// mine) to look up the glyph index...
|
// mine) to look up the glyph index...
|
||||||
temp = segment->idRangeOffset / 2 - segCount + (ch - segment->startCode) + (segment - segments);
|
temp = (int)(segment->idRangeOffset / 2 - segCount + (ch - segment->startCode) + (segment - segments));
|
||||||
|
|
||||||
TTF_DEBUG("read_cmap: ch=%d, temp=%d\n", ch, temp);
|
TTF_DEBUG("read_cmap: ch=%d, temp=%d\n", ch, temp);
|
||||||
if (temp < 0 || temp >= numGlyphIdArray)
|
if (temp < 0 || temp >= numGlyphIdArray)
|
||||||
|
Reference in New Issue
Block a user