mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2026-01-18 09:40:09 +01:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e9ec397f1 | ||
|
|
3c60d4a886 | ||
|
|
aac04a2a96 | ||
|
|
65098b5509 | ||
|
|
e6e0b84dfc | ||
|
|
3e6c38a436 | ||
|
|
6daf9e5e64 | ||
|
|
1044cc71a4 | ||
|
|
387a30f6c5 | ||
|
|
09520d250f | ||
|
|
bdcd963352 | ||
|
|
4565c52ff1 | ||
|
|
9cb19db1c5 | ||
|
|
5618c432cc | ||
|
|
4143808398 | ||
|
|
c92546ed94 | ||
|
|
07c6005fad | ||
|
|
6fd1b781dc | ||
|
|
6e8bd06937 | ||
|
|
0feace3eb5 | ||
|
|
846b0c9c7f | ||
|
|
fda0963220 | ||
|
|
31fb66917e | ||
|
|
089288946e | ||
|
|
68dda34448 | ||
|
|
ae97788728 | ||
|
|
6e049d4ed1 | ||
|
|
d70a72fdda | ||
|
|
8ba48ba4ae | ||
|
|
031ad03a38 | ||
|
|
9b1047b2e3 | ||
|
|
62dabe3580 | ||
|
|
16e2d6c91a | ||
|
|
d1cbeec9e3 | ||
|
|
29c2d131da | ||
|
|
115119a6f8 | ||
|
|
616f053835 | ||
|
|
d1536eee0c | ||
|
|
06d3e85627 | ||
|
|
850b0fa0a0 | ||
|
|
7ac8669057 | ||
|
|
f6f3191a8d | ||
|
|
c2b25a1fa0 |
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@@ -13,7 +13,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout PDFio sources
|
- name: Checkout PDFio sources
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
- name: Update Build Environment
|
- name: Update Build Environment
|
||||||
run: sudo apt-get update --fix-missing -y
|
run: sudo apt-get update --fix-missing -y
|
||||||
- name: Install Prerequisites
|
- name: Install Prerequisites
|
||||||
@@ -37,7 +39,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout PDFio sources
|
- name: Checkout PDFio sources
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
- name: Configure PDFio
|
- name: Configure PDFio
|
||||||
run: ./configure --enable-debug --enable-sanitizer --enable-maintainer
|
run: ./configure --enable-debug --enable-sanitizer --enable-maintainer
|
||||||
- name: Build PDFio
|
- name: Build PDFio
|
||||||
@@ -53,7 +57,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout PDFio sources
|
- name: Checkout PDFio sources
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
- name: Setup MSBuild
|
- name: Setup MSBuild
|
||||||
uses: microsoft/setup-msbuild@v2
|
uses: microsoft/setup-msbuild@v2
|
||||||
- name: Nuget Restore
|
- name: Nuget Restore
|
||||||
|
|||||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout PDFio sources
|
- name: Checkout PDFio sources
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
|||||||
4
.github/workflows/coverity.yml
vendored
4
.github/workflows/coverity.yml
vendored
@@ -8,7 +8,9 @@ jobs:
|
|||||||
environment: Coverity
|
environment: Coverity
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout PDFio sources
|
- name: Checkout PDFio sources
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
- name: Update Build Environment
|
- name: Update Build Environment
|
||||||
run: sudo apt-get update --fix-missing -y
|
run: sudo apt-get update --fix-missing -y
|
||||||
- name: Install Prerequisites
|
- name: Install Prerequisites
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -25,5 +25,4 @@
|
|||||||
/pdfio-*.zip*
|
/pdfio-*.zip*
|
||||||
/testpdfio
|
/testpdfio
|
||||||
/testpdfio-*.pdf
|
/testpdfio-*.pdf
|
||||||
/testttf
|
|
||||||
/x64
|
/x64
|
||||||
|
|||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "ttf"]
|
||||||
|
path = ttf
|
||||||
|
url = https://github.com/michaelrsweet/ttf.git
|
||||||
30
CHANGES.md
30
CHANGES.md
@@ -2,14 +2,42 @@ Changes in PDFio
|
|||||||
================
|
================
|
||||||
|
|
||||||
|
|
||||||
v1.6.1 - YYYY-MM-DD
|
v1.7.0 - YYYY-MM-DD
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- Now use TTF 1.1 or later for font support.
|
||||||
|
- Added support for basic compound stream filters for ASCII85Decode support
|
||||||
|
(Issue #11)
|
||||||
|
- Added support for LZWDecode filters (Issue #11)
|
||||||
|
- Added `pdfioPageGetXxx` functions to get values from the page dictionaries
|
||||||
|
(Issue #150)
|
||||||
|
- Fixed a buffer overflow in the (still not enabled) AES-256 code.
|
||||||
|
|
||||||
|
|
||||||
|
v1.6.2 - YYYY-MM-DD
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- Increased the maximum length of a single string to 128k (Issue #146)
|
||||||
|
- Added missing range checks to `pdfioArrayCopy` and `pdfioDictCopy`.
|
||||||
|
- Refactored PDF encryption code to fix unlocking with certain files.
|
||||||
|
- Improved xref table loop detection (Issue #148)
|
||||||
|
- Fixed xref reconstruction for objects lacking a `Type` value.
|
||||||
|
- Fixed `pdfioPageOpenStream` for indirect `Contents` arrays.
|
||||||
|
- Fixed an error propagation bug when reading too-long values (Issue #146)
|
||||||
|
- Fixed a Clang warning.
|
||||||
|
|
||||||
|
|
||||||
|
v1.6.1 - 2025-12-26
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
- Added missing input checking to `pdfioFileCreateFontObjFromBase` function.
|
- Added missing input checking to `pdfioFileCreateFontObjFromBase` function.
|
||||||
- Updated support for UTF-16 strings (Issue #141)
|
- Updated support for UTF-16 strings (Issue #141)
|
||||||
- Updated Xcode project to use installed PNG library.
|
- Updated Xcode project to use installed PNG library.
|
||||||
|
- Fixed decryption of PDF files using an Encrypt dictionary instead of an
|
||||||
|
indirect reference (Issue #139)
|
||||||
- Fixed character range checking in a TTF support function.
|
- Fixed character range checking in a TTF support function.
|
||||||
- Fixed some clang warnings.
|
- Fixed some clang warnings.
|
||||||
|
- Fixed the generated pkg-config file.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
43
Makefile.in
43
Makefile.in
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Makefile for PDFio.
|
# Makefile for PDFio.
|
||||||
#
|
#
|
||||||
# Copyright © 2021-2025 by Michael R Sweet.
|
# Copyright © 2021-2026 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.
|
||||||
@@ -69,6 +69,8 @@ top_srcdir = @top_srcdir@
|
|||||||
|
|
||||||
BUILDROOT = $(DSTROOT)$(RPM_BUILD_ROOT)$(DESTDIR)
|
BUILDROOT = $(DSTROOT)$(RPM_BUILD_ROOT)$(DESTDIR)
|
||||||
|
|
||||||
|
TTFDIR = @TTFDIR@
|
||||||
|
|
||||||
|
|
||||||
# Build commands...
|
# Build commands...
|
||||||
.SUFFIXES: .c .h .o
|
.SUFFIXES: .c .h .o
|
||||||
@@ -89,6 +91,7 @@ PUBOBJS = \
|
|||||||
pdfio-crypto.o \
|
pdfio-crypto.o \
|
||||||
pdfio-dict.o \
|
pdfio-dict.o \
|
||||||
pdfio-file.o \
|
pdfio-file.o \
|
||||||
|
pdfio-lzw.o \
|
||||||
pdfio-md5.o \
|
pdfio-md5.o \
|
||||||
pdfio-object.o \
|
pdfio-object.o \
|
||||||
pdfio-page.o \
|
pdfio-page.o \
|
||||||
@@ -99,17 +102,14 @@ PUBOBJS = \
|
|||||||
pdfio-token.o \
|
pdfio-token.o \
|
||||||
pdfio-value.o
|
pdfio-value.o
|
||||||
LIBOBJS = \
|
LIBOBJS = \
|
||||||
$(PUBOBJS) \
|
$(PUBOBJS)
|
||||||
ttf.o
|
|
||||||
OBJS = \
|
OBJS = \
|
||||||
$(LIBOBJS) \
|
$(LIBOBJS) \
|
||||||
testpdfio.o \
|
testpdfio.o
|
||||||
testttf.o
|
|
||||||
TARGETS = \
|
TARGETS = \
|
||||||
$(LIBPDFIO) \
|
$(LIBPDFIO) \
|
||||||
$(LIBPDFIO_STATIC) \
|
$(LIBPDFIO_STATIC) \
|
||||||
testpdfio \
|
testpdfio
|
||||||
testttf
|
|
||||||
DOCFILES = \
|
DOCFILES = \
|
||||||
doc/pdfio.html \
|
doc/pdfio.html \
|
||||||
doc/pdfio-512.png \
|
doc/pdfio-512.png \
|
||||||
@@ -135,16 +135,30 @@ EXAMPLES = \
|
|||||||
|
|
||||||
|
|
||||||
# Make everything
|
# Make everything
|
||||||
all: $(TARGETS)
|
all:
|
||||||
|
if test "x$(TTFDIR)" != x; then \
|
||||||
|
echo Making all in $(TTFDIR)...; \
|
||||||
|
(cd $(TTFDIR); $(MAKE) $(MFLAGS) all) || exit 1; \
|
||||||
|
fi
|
||||||
|
$(MAKE) $(MFLAGS) $(TARGETS)
|
||||||
|
|
||||||
|
|
||||||
# Clean everything
|
# Clean everything
|
||||||
clean:
|
clean:
|
||||||
|
if test "x$(TTFDIR)" != x; then \
|
||||||
|
echo Cleaning in $(TTFDIR)...; \
|
||||||
|
(cd $(TTFDIR); $(MAKE) $(MFLAGS) clean) || exit 1; \
|
||||||
|
fi
|
||||||
|
echo Cleaning build files...
|
||||||
rm -f $(TARGETS) $(OBJS)
|
rm -f $(TARGETS) $(OBJS)
|
||||||
|
|
||||||
|
|
||||||
# Install everything
|
# Install everything
|
||||||
install: $(TARGETS)
|
install: $(TARGETS)
|
||||||
|
if test "x$(TTFDIR)" != x; then \
|
||||||
|
echo Installing in $(TTFDIR)...; \
|
||||||
|
(cd $(TTFDIR); $(MAKE) $(MFLAGS) install) || exit 1; \
|
||||||
|
fi
|
||||||
echo Installing header files to $(BUILDROOT)$(includedir)...
|
echo Installing header files to $(BUILDROOT)$(includedir)...
|
||||||
$(INSTALL) -d -m 755 $(BUILDROOT)$(includedir)
|
$(INSTALL) -d -m 755 $(BUILDROOT)$(includedir)
|
||||||
for file in $(PUBHEADERS); do \
|
for file in $(PUBHEADERS); do \
|
||||||
@@ -186,8 +200,7 @@ install: $(TARGETS)
|
|||||||
|
|
||||||
|
|
||||||
# Test everything
|
# Test everything
|
||||||
test: testpdfio testttf
|
test: testpdfio
|
||||||
./testttf 2>test.log
|
|
||||||
./testpdfio 2>>test.log
|
./testpdfio 2>>test.log
|
||||||
LANG=fr_FR.UTF-8 ./testpdfio 2>>test.log
|
LANG=fr_FR.UTF-8 ./testpdfio 2>>test.log
|
||||||
|
|
||||||
@@ -232,18 +245,10 @@ testpdfio: testpdfio.o libpdfio.a
|
|||||||
$(CC) $(LDFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
|
$(CC) $(LDFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
|
||||||
|
|
||||||
|
|
||||||
# TTF test program
|
|
||||||
testttf: ttf.o testttf.o
|
|
||||||
echo Linking $@...
|
|
||||||
$(CC) $(LDFLAGS) -o testttf ttf.o testttf.o $(LIBS)
|
|
||||||
|
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
$(OBJS): pdfio.h pdfio-private.h Makefile
|
$(OBJS): pdfio.h pdfio-private.h Makefile
|
||||||
pdfio-content.o: pdfio-content.h ttf.h
|
pdfio-content.o: pdfio-content.h
|
||||||
testpdfio.o: test.h
|
testpdfio.o: test.h
|
||||||
testttf.o: ttf.h
|
|
||||||
ttf.o: ttf.h
|
|
||||||
|
|
||||||
|
|
||||||
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
||||||
|
|||||||
2
NOTICE
2
NOTICE
@@ -1,6 +1,6 @@
|
|||||||
PDFio - PDF Read/Write Library
|
PDFio - PDF Read/Write Library
|
||||||
|
|
||||||
Copyright © 2021-2025 by Michael R Sweet.
|
Copyright © 2021-2026 by Michael R Sweet.
|
||||||
|
|
||||||
(Optional) Exceptions to the Apache 2.0 License:
|
(Optional) Exceptions to the Apache 2.0 License:
|
||||||
================================================
|
================================================
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ pdfio - PDF Read/Write Library
|
|||||||
|
|
||||||

|

|
||||||

|

|
||||||
[](https://github.com/michaelrsweet/pdfio/actions/workflows/build.yml)
|
[](https://github.com/michaelrsweet/pdfio/actions/workflows/build.yml)
|
||||||
[](https://scan.coverity.com/projects/michaelrsweet-pdfio)
|
[](https://scan.coverity.com/projects/michaelrsweet-pdfio)
|
||||||
|
|
||||||
PDFio is a simple C library for reading and writing PDF files. The primary
|
PDFio is a simple C library for reading and writing PDF files. The primary
|
||||||
goals of PDFio are:
|
goals of PDFio are:
|
||||||
@@ -28,7 +28,8 @@ 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
|
||||||
- ZLIB (<https://www.zlib.net>) 1.1 or higher
|
- LIBPNG (1.6 or later) for full PNG image support (optional)
|
||||||
|
- ZLIB (1.1 or later)
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
@@ -89,7 +90,7 @@ generates a static library that will be installed under "/usr/local" with:
|
|||||||
Legal Stuff
|
Legal Stuff
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
PDFio is Copyright © 2021-2025 by Michael R Sweet.
|
PDFio is Copyright © 2021-2026 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
|
||||||
|
|||||||
38
SECURITY.md
38
SECURITY.md
@@ -5,12 +5,40 @@ This file describes how security issues are reported and handled, and what the
|
|||||||
expectations are for security issues reported to this project.
|
expectations are for security issues reported to this project.
|
||||||
|
|
||||||
|
|
||||||
|
What is a Security Bug?
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Not every bug is a security bug.
|
||||||
|
|
||||||
|
Certain bugs that might be considered security bugs in a program, such as bugs
|
||||||
|
that lead to a Denial of Service, are *not* considered security bugs simply
|
||||||
|
because this project *does not provide a service*. Some might argue that, "my
|
||||||
|
server uses this library and the bug in this library causes a denial of service
|
||||||
|
for my server", however it is the responsibility of the *server* to protect
|
||||||
|
against DoS attacks, not a subordinate library, because only the server knows
|
||||||
|
what is an appropriate use of memory, CPU, time, and other resources.
|
||||||
|
|
||||||
|
Similarly, bugs caused by incorrect API usage such as passing `NULL` pointers
|
||||||
|
where such pointers are not allowed, passing the wrong kinds of pointers or
|
||||||
|
objects to an API, or using a private API are not security bugs because they
|
||||||
|
are not caused by an attacker but by the developer.
|
||||||
|
|
||||||
|
Finally, bugs that only exist in unreleased (non-production) or inactive code
|
||||||
|
are not security bugs because they do not affect ordinary users. See the
|
||||||
|
[Supported Versions](#supported-versions) section below for more information
|
||||||
|
about what versions of the project are covered by this security policy.
|
||||||
|
|
||||||
|
If the bug you've found falls into one of these three categories, please report
|
||||||
|
the bug as an the ordinary project issue at
|
||||||
|
<https://github.com/michaelrsweet/pdfio/issues>.
|
||||||
|
|
||||||
|
|
||||||
Reporting a Security Bug
|
Reporting a Security Bug
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
For the purposes of this project, a security bug is a software defect that
|
For the purposes of this project, a security bug is a software defect that
|
||||||
allows a *local or remote user* to gain unauthorized access or privileges on the
|
allows a *local or remote user* to gain unauthorized access or privileges on the
|
||||||
host computer or to cause the software to crash. Such defects should be
|
host computer or to causes the software to crash. Such defects should be
|
||||||
reported to the project security advisory page at
|
reported to the project security advisory page at
|
||||||
<https://github.com/michaelrsweet/pdfio/security/advisories>.
|
<https://github.com/michaelrsweet/pdfio/security/advisories>.
|
||||||
|
|
||||||
@@ -18,11 +46,6 @@ Alternately, security bugs can be reported to "security AT msweet.org" using the
|
|||||||
PGP public key below. Expect a response within 5 business days. Any proposed
|
PGP public key below. Expect a response within 5 business days. Any proposed
|
||||||
embargo date should be at least 30 days and no more than 90 days in the future.
|
embargo date should be at least 30 days and no more than 90 days in the future.
|
||||||
|
|
||||||
> *Note:* If you've found a software defect that allows a *program* to gain
|
|
||||||
> unauthorized access or privileges on the host computer or causes the program
|
|
||||||
> to crash, that defect should be reported as an ordinary project issue at
|
|
||||||
> <https://github.com/michaelrsweet/pdfio/issues>.
|
|
||||||
|
|
||||||
|
|
||||||
Responsible Disclosure
|
Responsible Disclosure
|
||||||
----------------------
|
----------------------
|
||||||
@@ -68,6 +91,9 @@ example:
|
|||||||
1.0b2
|
1.0b2
|
||||||
1.0rc1
|
1.0rc1
|
||||||
|
|
||||||
|
Pre-release code in a Git branch ("master", "v1.6.x", etc.) is similarly *not*
|
||||||
|
production release code.
|
||||||
|
|
||||||
|
|
||||||
PGP Public Key
|
PGP Public Key
|
||||||
--------------
|
--------------
|
||||||
|
|||||||
218
configure
vendored
218
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.6.0.
|
# Generated by GNU Autoconf 2.71 for pdfio 1.7.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.6.0'
|
PACKAGE_VERSION='1.7.0'
|
||||||
PACKAGE_STRING='pdfio 1.6.0'
|
PACKAGE_STRING='pdfio 1.7.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'
|
||||||
|
|
||||||
@@ -647,13 +647,16 @@ ac_includes_default="\
|
|||||||
#endif"
|
#endif"
|
||||||
|
|
||||||
ac_header_c_list=
|
ac_header_c_list=
|
||||||
|
enable_option_checking=no
|
||||||
ac_subst_vars='LTLIBOBJS
|
ac_subst_vars='LTLIBOBJS
|
||||||
LIBOBJS
|
LIBOBJS
|
||||||
WARNINGS
|
WARNINGS
|
||||||
CSFLAGS
|
CSFLAGS
|
||||||
LIBPDFIO_STATIC
|
LIBPDFIO_STATIC
|
||||||
LIBPDFIO
|
LIBPDFIO
|
||||||
PKGCONFIG_LIBPNG
|
TTFDIR
|
||||||
|
subdirs
|
||||||
|
PKGCONFIG_REQUIRES_PRIVATE
|
||||||
PKGCONFIG_REQUIRES
|
PKGCONFIG_REQUIRES
|
||||||
PKGCONFIG_LIBS_PRIVATE
|
PKGCONFIG_LIBS_PRIVATE
|
||||||
PKGCONFIG_LIBS
|
PKGCONFIG_LIBS
|
||||||
@@ -747,7 +750,7 @@ CFLAGS
|
|||||||
LDFLAGS
|
LDFLAGS
|
||||||
LIBS
|
LIBS
|
||||||
CPPFLAGS'
|
CPPFLAGS'
|
||||||
|
ac_subdirs_all='ttf'
|
||||||
|
|
||||||
# Initialize some variables set by options.
|
# Initialize some variables set by options.
|
||||||
ac_init_help=
|
ac_init_help=
|
||||||
@@ -1295,7 +1298,7 @@ if test "$ac_init_help" = "long"; then
|
|||||||
# Omit some internal or obsolete options to make the list less imposing.
|
# Omit some internal or obsolete options to make the list less imposing.
|
||||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
cat <<_ACEOF
|
||||||
\`configure' configures pdfio 1.6.0 to adapt to many kinds of systems.
|
\`configure' configures pdfio 1.7.0 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@@ -1361,7 +1364,7 @@ fi
|
|||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of pdfio 1.6.0:";;
|
short | recursive ) echo "Configuration of pdfio 1.7.0:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@@ -1460,7 +1463,7 @@ fi
|
|||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
pdfio configure 1.6.0
|
pdfio configure 1.7.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.
|
||||||
@@ -1678,7 +1681,7 @@ cat >config.log <<_ACEOF
|
|||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
It was created by pdfio $as_me 1.6.0, which was
|
It was created by pdfio $as_me 1.7.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
|
||||||
@@ -2434,9 +2437,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
PDFIO_VERSION="1.6.0"
|
PDFIO_VERSION="1.7.0"
|
||||||
PDFIO_VERSION_MAJOR="`echo 1.6.0 | awk -F. '{print $1}'`"
|
PDFIO_VERSION_MAJOR="`echo 1.7.0 | awk -F. '{print $1}'`"
|
||||||
PDFIO_VERSION_MINOR="`echo 1.6.0 | awk -F. '{printf("%d\n",$2);}'`"
|
PDFIO_VERSION_MINOR="`echo 1.7.0 | awk -F. '{printf("%d\n",$2);}'`"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -4138,13 +4141,44 @@ fi
|
|||||||
PKGCONFIG_CFLAGS="-I\${includedir}"
|
PKGCONFIG_CFLAGS="-I\${includedir}"
|
||||||
PKGCONFIG_LIBS="-L\${libdir} -lpdfio"
|
PKGCONFIG_LIBS="-L\${libdir} -lpdfio"
|
||||||
PKGCONFIG_LIBS_PRIVATE="-lm"
|
PKGCONFIG_LIBS_PRIVATE="-lm"
|
||||||
PKGCONFIG_REQUIRES="zlib"
|
PKGCONFIG_REQUIRES=""
|
||||||
|
PKGCONFIG_REQUIRES_PRIVATE="ttf"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ttf library" >&5
|
||||||
|
printf %s "checking for ttf library... " >&6; }
|
||||||
|
|
||||||
|
|
||||||
|
if $PKGCONFIG --exists ttf
|
||||||
|
then :
|
||||||
|
|
||||||
|
# Use installed TTF library...
|
||||||
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||||
|
printf "%s\n" "yes" >&6; }
|
||||||
|
CPPFLAGS="$CPPFLAGS $($PKGCONFIG --cflags ttf)"
|
||||||
|
TTFDIR=""
|
||||||
|
LIBS="$($PKGCONFIG --libs ttf) $LIBS"
|
||||||
|
|
||||||
|
else $as_nop
|
||||||
|
|
||||||
|
# Use embedded TTF library...
|
||||||
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using embedded version" >&5
|
||||||
|
printf "%s\n" "no, using embedded version" >&6; }
|
||||||
|
CPPFLAGS="$CPPFLAGS -Ittf"
|
||||||
|
TTFDIR="ttf"
|
||||||
|
LIBS="-Lttf \`PKG_CONFIG_PATH=ttf $PKGCONFIG --libs ttf\` $LIBS"
|
||||||
|
subdirs="$subdirs ttf"
|
||||||
|
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib via pkg-config" >&5
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib via pkg-config" >&5
|
||||||
printf %s "checking for zlib via pkg-config... " >&6; }
|
printf %s "checking for zlib via pkg-config... " >&6; }
|
||||||
if $PKGCONFIG --exists zlib
|
if $PKGCONFIG --exists zlib
|
||||||
@@ -4154,6 +4188,7 @@ then :
|
|||||||
printf "%s\n" "yes" >&6; }
|
printf "%s\n" "yes" >&6; }
|
||||||
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
||||||
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
||||||
|
PKGCONFIG_REQUIRES_PRIVATE="$PKGCONFIG_REQUIRES_PRIVATE, zlib"
|
||||||
|
|
||||||
else $as_nop
|
else $as_nop
|
||||||
|
|
||||||
@@ -4216,11 +4251,11 @@ then :
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PKGCONFIG_REQUIRES=""
|
|
||||||
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
|
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Check whether --enable-libpng was given.
|
# Check whether --enable-libpng was given.
|
||||||
if test ${enable_libpng+y}
|
if test ${enable_libpng+y}
|
||||||
then :
|
then :
|
||||||
@@ -4228,9 +4263,6 @@ then :
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
PKGCONFIG_LIBPNG=""
|
|
||||||
|
|
||||||
|
|
||||||
if test "x$PKGCONFIG" != x -a x$enable_libpng != xno
|
if test "x$PKGCONFIG" != x -a x$enable_libpng != xno
|
||||||
then :
|
then :
|
||||||
|
|
||||||
@@ -4246,8 +4278,7 @@ printf "%s\n" "#define HAVE_LIBPNG 1" >>confdefs.h
|
|||||||
|
|
||||||
CPPFLAGS="$($PKGCONFIG --cflags libpng16) -DHAVE_LIBPNG=1 $CPPFLAGS"
|
CPPFLAGS="$($PKGCONFIG --cflags libpng16) -DHAVE_LIBPNG=1 $CPPFLAGS"
|
||||||
LIBS="$($PKGCONFIG --libs libpng16) -lz $LIBS"
|
LIBS="$($PKGCONFIG --libs libpng16) -lz $LIBS"
|
||||||
PKGCONFIG_LIBS_PRIVATE="$($PKGCONFIG --libs libpng16) $PKGCONFIG_LIBS_PRIVATE"
|
PKGCONFIG_REQUIRES_PRIVATE="libpng >= 1.6, $PKGCONFIG_REQUIRES_PRIVATE"
|
||||||
PKGCONFIG_REQUIRES="libpng >= 1.6,$PKGCONFIG_REQUIRES"
|
|
||||||
|
|
||||||
else $as_nop
|
else $as_nop
|
||||||
|
|
||||||
@@ -4314,6 +4345,8 @@ else $as_nop
|
|||||||
LIBPDFIO_STATIC=""
|
LIBPDFIO_STATIC=""
|
||||||
PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE"
|
PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE"
|
||||||
PKGCONFIG_LIBS_PRIVATE=""
|
PKGCONFIG_LIBS_PRIVATE=""
|
||||||
|
PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES_PRIVATE"
|
||||||
|
PKGCONFIG_REQUIRES_PRIVATE=""
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -5106,7 +5139,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
|||||||
# report actual input values of CONFIG_FILES etc. instead of their
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by pdfio $as_me 1.6.0, which was
|
This file was extended by pdfio $as_me 1.7.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
|
||||||
@@ -5162,7 +5195,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
|
|||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config='$ac_cs_config_escaped'
|
ac_cs_config='$ac_cs_config_escaped'
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
pdfio config.status 1.6.0
|
pdfio config.status 1.7.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\\"
|
||||||
|
|
||||||
@@ -5718,6 +5751,149 @@ if test "$no_create" != yes; then
|
|||||||
# would make configure fail if this is the last instruction.
|
# would make configure fail if this is the last instruction.
|
||||||
$ac_cs_success || as_fn_exit 1
|
$ac_cs_success || as_fn_exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# CONFIG_SUBDIRS section.
|
||||||
|
#
|
||||||
|
if test "$no_recursion" != yes; then
|
||||||
|
|
||||||
|
# Remove --cache-file, --srcdir, and --disable-option-checking arguments
|
||||||
|
# so they do not pile up.
|
||||||
|
ac_sub_configure_args=
|
||||||
|
ac_prev=
|
||||||
|
eval "set x $ac_configure_args"
|
||||||
|
shift
|
||||||
|
for ac_arg
|
||||||
|
do
|
||||||
|
if test -n "$ac_prev"; then
|
||||||
|
ac_prev=
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
case $ac_arg in
|
||||||
|
-cache-file | --cache-file | --cache-fil | --cache-fi \
|
||||||
|
| --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
|
||||||
|
ac_prev=cache_file ;;
|
||||||
|
-cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
|
||||||
|
| --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \
|
||||||
|
| --c=*)
|
||||||
|
;;
|
||||||
|
--config-cache | -C)
|
||||||
|
;;
|
||||||
|
-srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
|
||||||
|
ac_prev=srcdir ;;
|
||||||
|
-srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
|
||||||
|
;;
|
||||||
|
-prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
|
||||||
|
ac_prev=prefix ;;
|
||||||
|
-prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
|
||||||
|
;;
|
||||||
|
--disable-option-checking)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
case $ac_arg in
|
||||||
|
*\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
|
||||||
|
esac
|
||||||
|
as_fn_append ac_sub_configure_args " '$ac_arg'" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Always prepend --prefix to ensure using the same prefix
|
||||||
|
# in subdir configurations.
|
||||||
|
ac_arg="--prefix=$prefix"
|
||||||
|
case $ac_arg in
|
||||||
|
*\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
|
||||||
|
esac
|
||||||
|
ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args"
|
||||||
|
|
||||||
|
# Pass --silent
|
||||||
|
if test "$silent" = yes; then
|
||||||
|
ac_sub_configure_args="--silent $ac_sub_configure_args"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Always prepend --disable-option-checking to silence warnings, since
|
||||||
|
# different subdirs can have different --enable and --with options.
|
||||||
|
ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args"
|
||||||
|
|
||||||
|
ac_popdir=`pwd`
|
||||||
|
for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue
|
||||||
|
|
||||||
|
# Do not complain, so a configure script can configure whichever
|
||||||
|
# parts of a large source tree are present.
|
||||||
|
test -d "$srcdir/$ac_dir" || continue
|
||||||
|
|
||||||
|
ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)"
|
||||||
|
printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5
|
||||||
|
printf "%s\n" "$ac_msg" >&6
|
||||||
|
as_dir="$ac_dir"; as_fn_mkdir_p
|
||||||
|
ac_builddir=.
|
||||||
|
|
||||||
|
case "$ac_dir" in
|
||||||
|
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
|
||||||
|
*)
|
||||||
|
ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
|
||||||
|
# A ".." for each directory in $ac_dir_suffix.
|
||||||
|
ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
|
||||||
|
case $ac_top_builddir_sub in
|
||||||
|
"") ac_top_builddir_sub=. ac_top_build_prefix= ;;
|
||||||
|
*) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
|
||||||
|
esac ;;
|
||||||
|
esac
|
||||||
|
ac_abs_top_builddir=$ac_pwd
|
||||||
|
ac_abs_builddir=$ac_pwd$ac_dir_suffix
|
||||||
|
# for backward compatibility:
|
||||||
|
ac_top_builddir=$ac_top_build_prefix
|
||||||
|
|
||||||
|
case $srcdir in
|
||||||
|
.) # We are building in place.
|
||||||
|
ac_srcdir=.
|
||||||
|
ac_top_srcdir=$ac_top_builddir_sub
|
||||||
|
ac_abs_top_srcdir=$ac_pwd ;;
|
||||||
|
[\\/]* | ?:[\\/]* ) # Absolute name.
|
||||||
|
ac_srcdir=$srcdir$ac_dir_suffix;
|
||||||
|
ac_top_srcdir=$srcdir
|
||||||
|
ac_abs_top_srcdir=$srcdir ;;
|
||||||
|
*) # Relative name.
|
||||||
|
ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
|
||||||
|
ac_top_srcdir=$ac_top_build_prefix$srcdir
|
||||||
|
ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
|
||||||
|
esac
|
||||||
|
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
|
||||||
|
|
||||||
|
|
||||||
|
cd "$ac_dir"
|
||||||
|
|
||||||
|
# Check for configure.gnu first; this name is used for a wrapper for
|
||||||
|
# Metaconfig's "Configure" on case-insensitive file systems.
|
||||||
|
if test -f "$ac_srcdir/configure.gnu"; then
|
||||||
|
ac_sub_configure=$ac_srcdir/configure.gnu
|
||||||
|
elif test -f "$ac_srcdir/configure"; then
|
||||||
|
ac_sub_configure=$ac_srcdir/configure
|
||||||
|
else
|
||||||
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5
|
||||||
|
printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2;}
|
||||||
|
ac_sub_configure=
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The recursion is here.
|
||||||
|
if test -n "$ac_sub_configure"; then
|
||||||
|
# Make the cache file name correct relative to the subdirectory.
|
||||||
|
case $cache_file in
|
||||||
|
[\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;;
|
||||||
|
*) # Relative name.
|
||||||
|
ac_sub_cache_file=$ac_top_build_prefix$cache_file ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5
|
||||||
|
printf "%s\n" "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;}
|
||||||
|
# The eval makes quoting arguments work.
|
||||||
|
eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \
|
||||||
|
--cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" ||
|
||||||
|
as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$ac_popdir"
|
||||||
|
done
|
||||||
|
fi
|
||||||
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
|
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
|
||||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
|
||||||
printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
|
printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
|
||||||
|
|||||||
36
configure.ac
36
configure.ac
@@ -21,7 +21,7 @@ AC_PREREQ([2.70])
|
|||||||
|
|
||||||
|
|
||||||
dnl Package name and version...
|
dnl Package name and version...
|
||||||
AC_INIT([pdfio], [1.6.0], [https://github.com/michaelrsweet/pdfio/issues], [pdfio], [https://www.msweet.org/pdfio])
|
AC_INIT([pdfio], [1.7.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}'`"
|
||||||
@@ -119,11 +119,32 @@ AC_PATH_TOOL([PKGCONFIG], [pkg-config])
|
|||||||
PKGCONFIG_CFLAGS="-I\${includedir}"
|
PKGCONFIG_CFLAGS="-I\${includedir}"
|
||||||
PKGCONFIG_LIBS="-L\${libdir} -lpdfio"
|
PKGCONFIG_LIBS="-L\${libdir} -lpdfio"
|
||||||
PKGCONFIG_LIBS_PRIVATE="-lm"
|
PKGCONFIG_LIBS_PRIVATE="-lm"
|
||||||
PKGCONFIG_REQUIRES="zlib"
|
PKGCONFIG_REQUIRES=""
|
||||||
|
PKGCONFIG_REQUIRES_PRIVATE="ttf"
|
||||||
AC_SUBST([PKGCONFIG_CFLAGS])
|
AC_SUBST([PKGCONFIG_CFLAGS])
|
||||||
AC_SUBST([PKGCONFIG_LIBS])
|
AC_SUBST([PKGCONFIG_LIBS])
|
||||||
AC_SUBST([PKGCONFIG_LIBS_PRIVATE])
|
AC_SUBST([PKGCONFIG_LIBS_PRIVATE])
|
||||||
AC_SUBST([PKGCONFIG_REQUIRES])
|
AC_SUBST([PKGCONFIG_REQUIRES])
|
||||||
|
AC_SUBST([PKGCONFIG_REQUIRES_PRIVATE])
|
||||||
|
|
||||||
|
|
||||||
|
dnl TTF library for font support...
|
||||||
|
AC_MSG_CHECKING([for ttf library])
|
||||||
|
AS_IF([$PKGCONFIG --exists ttf], [
|
||||||
|
# Use installed TTF library...
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
CPPFLAGS="$CPPFLAGS $($PKGCONFIG --cflags ttf)"
|
||||||
|
TTFDIR=""
|
||||||
|
LIBS="$($PKGCONFIG --libs ttf) $LIBS"
|
||||||
|
], [
|
||||||
|
# Use embedded TTF library...
|
||||||
|
AC_MSG_RESULT([no, using embedded version])
|
||||||
|
CPPFLAGS="$CPPFLAGS -Ittf"
|
||||||
|
TTFDIR="ttf"
|
||||||
|
LIBS="-Lttf \`PKG_CONFIG_PATH=ttf $PKGCONFIG --libs ttf\` $LIBS"
|
||||||
|
AC_CONFIG_SUBDIRS([ttf])
|
||||||
|
])
|
||||||
|
AC_SUBST([TTFDIR])
|
||||||
|
|
||||||
|
|
||||||
dnl ZLIB
|
dnl ZLIB
|
||||||
@@ -132,6 +153,7 @@ AS_IF([$PKGCONFIG --exists zlib], [
|
|||||||
AC_MSG_RESULT([yes])
|
AC_MSG_RESULT([yes])
|
||||||
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
||||||
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
||||||
|
PKGCONFIG_REQUIRES_PRIVATE="$PKGCONFIG_REQUIRES_PRIVATE, zlib"
|
||||||
],[
|
],[
|
||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
AC_CHECK_HEADER([zlib.h])
|
AC_CHECK_HEADER([zlib.h])
|
||||||
@@ -141,16 +163,13 @@ AS_IF([$PKGCONFIG --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"
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
dnl libpng...
|
dnl libpng...
|
||||||
AC_ARG_ENABLE([libpng], AS_HELP_STRING([--enable-libpng], [use libpng for pdfioFileCreateImageObjFromFile, default=auto]))
|
AC_ARG_ENABLE([libpng], AS_HELP_STRING([--enable-libpng], [use libpng for pdfioFileCreateImageObjFromFile, default=auto]))
|
||||||
|
|
||||||
PKGCONFIG_LIBPNG=""
|
|
||||||
AC_SUBST([PKGCONFIG_LIBPNG])
|
|
||||||
|
|
||||||
AS_IF([test "x$PKGCONFIG" != x -a x$enable_libpng != xno], [
|
AS_IF([test "x$PKGCONFIG" != x -a x$enable_libpng != xno], [
|
||||||
AC_MSG_CHECKING([for libpng-1.6.x])
|
AC_MSG_CHECKING([for libpng-1.6.x])
|
||||||
AS_IF([$PKGCONFIG --exists libpng16], [
|
AS_IF([$PKGCONFIG --exists libpng16], [
|
||||||
@@ -158,8 +177,7 @@ AS_IF([test "x$PKGCONFIG" != x -a x$enable_libpng != xno], [
|
|||||||
AC_DEFINE([HAVE_LIBPNG], 1, [Have PNG library?])
|
AC_DEFINE([HAVE_LIBPNG], 1, [Have PNG library?])
|
||||||
CPPFLAGS="$($PKGCONFIG --cflags libpng16) -DHAVE_LIBPNG=1 $CPPFLAGS"
|
CPPFLAGS="$($PKGCONFIG --cflags libpng16) -DHAVE_LIBPNG=1 $CPPFLAGS"
|
||||||
LIBS="$($PKGCONFIG --libs libpng16) -lz $LIBS"
|
LIBS="$($PKGCONFIG --libs libpng16) -lz $LIBS"
|
||||||
PKGCONFIG_LIBS_PRIVATE="$($PKGCONFIG --libs libpng16) $PKGCONFIG_LIBS_PRIVATE"
|
PKGCONFIG_REQUIRES_PRIVATE="libpng >= 1.6, $PKGCONFIG_REQUIRES_PRIVATE"
|
||||||
PKGCONFIG_REQUIRES="libpng >= 1.6,$PKGCONFIG_REQUIRES"
|
|
||||||
], [
|
], [
|
||||||
AC_MSG_RESULT([no]);
|
AC_MSG_RESULT([no]);
|
||||||
AS_IF([test x$enable_libpng = xyes], [
|
AS_IF([test x$enable_libpng = xyes], [
|
||||||
@@ -192,6 +210,8 @@ AS_IF([test x$enable_shared = xyes], [
|
|||||||
LIBPDFIO_STATIC=""
|
LIBPDFIO_STATIC=""
|
||||||
PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE"
|
PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE"
|
||||||
PKGCONFIG_LIBS_PRIVATE=""
|
PKGCONFIG_LIBS_PRIVATE=""
|
||||||
|
PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES_PRIVATE"
|
||||||
|
PKGCONFIG_REQUIRES_PRIVATE=""
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_SUBST([LIBPDFIO])
|
AC_SUBST([LIBPDFIO])
|
||||||
|
|||||||
148
doc/pdfio.3
148
doc/pdfio.3
@@ -1,4 +1,4 @@
|
|||||||
.TH pdfio 3 "pdf read/write library" "2025-10-05" "pdf read/write library"
|
.TH pdfio 3 "pdf read/write library" "2026-01-16" "pdf read/write library"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
pdfio \- pdf read/write library
|
pdfio \- pdf read/write library
|
||||||
.SH Introduction
|
.SH Introduction
|
||||||
@@ -2555,7 +2555,7 @@ ASCIIHexDecode filter (reading only)
|
|||||||
.TP 5
|
.TP 5
|
||||||
PDFIO_FILTER_CCITTFAX
|
PDFIO_FILTER_CCITTFAX
|
||||||
.br
|
.br
|
||||||
CCITTFaxDecode filter
|
CCITTFaxDecode filter (reading only)
|
||||||
.TP 5
|
.TP 5
|
||||||
PDFIO_FILTER_CRYPT
|
PDFIO_FILTER_CRYPT
|
||||||
.br
|
.br
|
||||||
@@ -2571,7 +2571,7 @@ FlateDecode filter
|
|||||||
.TP 5
|
.TP 5
|
||||||
PDFIO_FILTER_JBIG2
|
PDFIO_FILTER_JBIG2
|
||||||
.br
|
.br
|
||||||
JBIG2Decode filter
|
JBIG2Decode filter (reading only)
|
||||||
.TP 5
|
.TP 5
|
||||||
PDFIO_FILTER_JPX
|
PDFIO_FILTER_JPX
|
||||||
.br
|
.br
|
||||||
@@ -4924,6 +4924,91 @@ bool pdfioPageDictAddImage (
|
|||||||
pdfio_obj_t *obj
|
pdfio_obj_t *obj
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
|
.SS pdfioPageGetArray
|
||||||
|
Get an array value from the page dictionary.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
pdfio_array_t * pdfioPageGetArray (
|
||||||
|
pdfio_obj_t *page,
|
||||||
|
const char *key
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
This function looks up an array value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
|
||||||
|
.SS pdfioPageGetBinary
|
||||||
|
Get a binary value from the page dictionary.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
unsigned char * pdfioPageGetBinary (
|
||||||
|
pdfio_obj_t *page,
|
||||||
|
const char *key,
|
||||||
|
size_t *length
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
This function looks up a binary value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
|
||||||
|
.SS pdfioPageGetBoolean
|
||||||
|
Get a boolean value from the page dictionary.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
bool pdfioPageGetBoolean (
|
||||||
|
pdfio_obj_t *page,
|
||||||
|
const char *key
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
This function looks up a boolean value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
|
||||||
|
.SS pdfioPageGetDate
|
||||||
|
Get a date value from the page dictionary.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
time_t pdfioPageGetDate (
|
||||||
|
pdfio_obj_t *page,
|
||||||
|
const char *key
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
This function looks up a date value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
|
||||||
|
.SS pdfioPageGetDict
|
||||||
|
Get a dictionary value from the page dictionary.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
pdfio_dict_t * pdfioPageGetDict (
|
||||||
|
pdfio_obj_t *page,
|
||||||
|
const char *key
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
This function looks up a dictionary value in the page dictionary, either in
|
||||||
|
the specified object or one of its parents.
|
||||||
|
|
||||||
|
|
||||||
|
.SS pdfioPageGetName
|
||||||
|
Get a name value from the page dictionary.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
const char * pdfioPageGetName (
|
||||||
|
pdfio_obj_t *page,
|
||||||
|
const char *key
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
This function looks up a name value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
|
||||||
.SS pdfioPageGetNumStreams
|
.SS pdfioPageGetNumStreams
|
||||||
Get the number of content streams for a page object.
|
Get the number of content streams for a page object.
|
||||||
.PP
|
.PP
|
||||||
@@ -4932,6 +5017,63 @@ size_t pdfioPageGetNumStreams (
|
|||||||
pdfio_obj_t *page
|
pdfio_obj_t *page
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
|
.SS pdfioPageGetNumber
|
||||||
|
Get a number value from the page dictionary.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
double pdfioPageGetNumber (
|
||||||
|
pdfio_obj_t *page,
|
||||||
|
const char *key
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
This function looks up a number value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
|
||||||
|
.SS pdfioPageGetObj
|
||||||
|
Get an indirect object value from the page dictionary.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
pdfio_obj_t * pdfioPageGetObj (
|
||||||
|
pdfio_obj_t *page,
|
||||||
|
const char *key
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
This function looks up an indirect object value in the page dictionary,
|
||||||
|
either in the specified object or one of its parents.
|
||||||
|
|
||||||
|
|
||||||
|
.SS pdfioPageGetRect
|
||||||
|
Get a rectangle value from the page dictionary.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
pdfio_rect_t * pdfioPageGetRect (
|
||||||
|
pdfio_obj_t *page,
|
||||||
|
const char *key,
|
||||||
|
pdfio_rect_t *rect
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
This function looks up a rectangle value in the page dictionary, either in
|
||||||
|
the specified object or one of its parents.
|
||||||
|
|
||||||
|
|
||||||
|
.SS pdfioPageGetString
|
||||||
|
Get a string value from the page dictionary.
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
const char * pdfioPageGetString (
|
||||||
|
pdfio_obj_t *page,
|
||||||
|
const char *key
|
||||||
|
);
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
This function looks up a string value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
|
||||||
.SS pdfioPageOpenStream
|
.SS pdfioPageOpenStream
|
||||||
Open a content stream for a page.
|
Open a content stream for a page.
|
||||||
.PP
|
.PP
|
||||||
|
|||||||
226
doc/pdfio.html
226
doc/pdfio.html
@@ -1,13 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en-US">
|
<html lang="en-US">
|
||||||
<head>
|
<head>
|
||||||
<title>PDFio Programming Manual v1.6.0</title>
|
<title>PDFio Programming Manual v1.7.0</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
<meta name="generator" content="codedoc v3.8">
|
<meta name="generator" content="codedoc v3.8">
|
||||||
<meta name="author" content="Michael R Sweet">
|
<meta name="author" content="Michael R Sweet">
|
||||||
<meta name="language" content="en-US">
|
<meta name="language" content="en-US">
|
||||||
<meta name="copyright" content="Copyright © 2021-2025 by Michael R Sweet">
|
<meta name="copyright" content="Copyright © 2021-2025 by Michael R Sweet">
|
||||||
<meta name="version" content="1.6.0">
|
<meta name="version" content="1.7.0">
|
||||||
<style type="text/css"><!--
|
<style type="text/css"><!--
|
||||||
body {
|
body {
|
||||||
background: white;
|
background: white;
|
||||||
@@ -92,13 +92,16 @@ blockquote :first-child {
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
p code, li code, p.code, pre, ul.code li {
|
p code, li code, p.code, pre, ul.code li {
|
||||||
|
background: rgba(127,127,127,0.25);
|
||||||
|
border: thin dotted gray;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
hyphens: manual;
|
hyphens: manual;
|
||||||
-webkit-hyphens: manual;
|
-webkit-hyphens: manual;
|
||||||
}
|
}
|
||||||
|
p code, li code {
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
p.code, pre, ul.code li {
|
p.code, pre, ul.code li {
|
||||||
background: rgba(127,127,127,0.25);
|
|
||||||
border: thin dotted gray;
|
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
page-break-inside: avoid;
|
page-break-inside: avoid;
|
||||||
}
|
}
|
||||||
@@ -217,6 +220,21 @@ span.string {
|
|||||||
a:link:hover, a:visited:hover, a:active {
|
a:link:hover, a:visited:hover, a:active {
|
||||||
color: #f06;
|
color: #f06;
|
||||||
}
|
}
|
||||||
|
span.comment {
|
||||||
|
color: #7c7;
|
||||||
|
}
|
||||||
|
span.directive {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
span.number {
|
||||||
|
color: #c64;
|
||||||
|
}
|
||||||
|
span.reserved {
|
||||||
|
color: #77f;
|
||||||
|
}
|
||||||
|
span.string {
|
||||||
|
color: #f7f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Show contents on left side in web browser */
|
/* Show contents on left side in web browser */
|
||||||
@media screen and (min-width: 800px) {
|
@media screen and (min-width: 800px) {
|
||||||
@@ -251,7 +269,7 @@ span.string {
|
|||||||
<body>
|
<body>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<p><img class="title" src="pdfio-512.png"></p>
|
<p><img class="title" src="pdfio-512.png"></p>
|
||||||
<h1 class="title">PDFio Programming Manual v1.6.0</h1>
|
<h1 class="title">PDFio Programming Manual v1.7.0</h1>
|
||||||
<p>Michael R Sweet</p>
|
<p>Michael R Sweet</p>
|
||||||
<p>Copyright © 2021-2025 by Michael R Sweet</p>
|
<p>Copyright © 2021-2025 by Michael R Sweet</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -464,7 +482,17 @@ span.string {
|
|||||||
<li><a href="#pdfioPageDictAddColorSpace">pdfioPageDictAddColorSpace</a></li>
|
<li><a href="#pdfioPageDictAddColorSpace">pdfioPageDictAddColorSpace</a></li>
|
||||||
<li><a href="#pdfioPageDictAddFont">pdfioPageDictAddFont</a></li>
|
<li><a href="#pdfioPageDictAddFont">pdfioPageDictAddFont</a></li>
|
||||||
<li><a href="#pdfioPageDictAddImage">pdfioPageDictAddImage</a></li>
|
<li><a href="#pdfioPageDictAddImage">pdfioPageDictAddImage</a></li>
|
||||||
|
<li><a href="#pdfioPageGetArray">pdfioPageGetArray</a></li>
|
||||||
|
<li><a href="#pdfioPageGetBinary">pdfioPageGetBinary</a></li>
|
||||||
|
<li><a href="#pdfioPageGetBoolean">pdfioPageGetBoolean</a></li>
|
||||||
|
<li><a href="#pdfioPageGetDate">pdfioPageGetDate</a></li>
|
||||||
|
<li><a href="#pdfioPageGetDict">pdfioPageGetDict</a></li>
|
||||||
|
<li><a href="#pdfioPageGetName">pdfioPageGetName</a></li>
|
||||||
<li><a href="#pdfioPageGetNumStreams">pdfioPageGetNumStreams</a></li>
|
<li><a href="#pdfioPageGetNumStreams">pdfioPageGetNumStreams</a></li>
|
||||||
|
<li><a href="#pdfioPageGetNumber">pdfioPageGetNumber</a></li>
|
||||||
|
<li><a href="#pdfioPageGetObj">pdfioPageGetObj</a></li>
|
||||||
|
<li><a href="#pdfioPageGetRect">pdfioPageGetRect</a></li>
|
||||||
|
<li><a href="#pdfioPageGetString">pdfioPageGetString</a></li>
|
||||||
<li><a href="#pdfioPageOpenStream">pdfioPageOpenStream</a></li>
|
<li><a href="#pdfioPageOpenStream">pdfioPageOpenStream</a></li>
|
||||||
<li><a href="#pdfioStreamClose">pdfioStreamClose</a></li>
|
<li><a href="#pdfioStreamClose">pdfioStreamClose</a></li>
|
||||||
<li><a href="#pdfioStreamConsume">pdfioStreamConsume</a></li>
|
<li><a href="#pdfioStreamConsume">pdfioStreamConsume</a></li>
|
||||||
@@ -5409,6 +5437,116 @@ array that was created using the
|
|||||||
</tbody></table>
|
</tbody></table>
|
||||||
<h4 class="returnvalue">Return Value</h4>
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
||||||
|
<h3 class="function"><span class="info"> PDFio 1.7 </span><a id="pdfioPageGetArray">pdfioPageGetArray</a></h3>
|
||||||
|
<p class="description">Get an array value from the page dictionary.</p>
|
||||||
|
<p class="code">
|
||||||
|
<a href="#pdfio_array_t">pdfio_array_t</a> *pdfioPageGetArray(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page, <span class="reserved">const</span> <span class="reserved">char</span> *key);</p>
|
||||||
|
<h4 class="parameters">Parameters</h4>
|
||||||
|
<table class="list"><tbody>
|
||||||
|
<tr><th>page</th>
|
||||||
|
<td class="description">Page object</td></tr>
|
||||||
|
<tr><th>key</th>
|
||||||
|
<td class="description">Dictionary key</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
|
<p class="description">Array or <code>NULL</code> if none</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function looks up an array value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<h3 class="function"><span class="info"> PDFio 1.7 </span><a id="pdfioPageGetBinary">pdfioPageGetBinary</a></h3>
|
||||||
|
<p class="description">Get a binary value from the page dictionary.</p>
|
||||||
|
<p class="code">
|
||||||
|
<span class="reserved">unsigned</span> <span class="reserved">char</span> *pdfioPageGetBinary(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page, <span class="reserved">const</span> <span class="reserved">char</span> *key, size_t *length);</p>
|
||||||
|
<h4 class="parameters">Parameters</h4>
|
||||||
|
<table class="list"><tbody>
|
||||||
|
<tr><th>page</th>
|
||||||
|
<td class="description">Page object</td></tr>
|
||||||
|
<tr><th>key</th>
|
||||||
|
<td class="description">Dictionary key</td></tr>
|
||||||
|
<tr><th>length</th>
|
||||||
|
<td class="description">Length of value</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
|
<p class="description">Pointer to binary data or <code>NULL</code> if none</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function looks up a binary value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<h3 class="function"><span class="info"> PDFio 1.7 </span><a id="pdfioPageGetBoolean">pdfioPageGetBoolean</a></h3>
|
||||||
|
<p class="description">Get a boolean value from the page dictionary.</p>
|
||||||
|
<p class="code">
|
||||||
|
<span class="reserved">bool</span> pdfioPageGetBoolean(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page, <span class="reserved">const</span> <span class="reserved">char</span> *key);</p>
|
||||||
|
<h4 class="parameters">Parameters</h4>
|
||||||
|
<table class="list"><tbody>
|
||||||
|
<tr><th>page</th>
|
||||||
|
<td class="description">Page object</td></tr>
|
||||||
|
<tr><th>key</th>
|
||||||
|
<td class="description">Dictionary key</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
|
<p class="description">Boolean value or <code>false</code> if none</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function looks up a boolean value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<h3 class="function"><span class="info"> PDFio 1.7 </span><a id="pdfioPageGetDate">pdfioPageGetDate</a></h3>
|
||||||
|
<p class="description">Get a date value from the page dictionary.</p>
|
||||||
|
<p class="code">
|
||||||
|
time_t pdfioPageGetDate(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page, <span class="reserved">const</span> <span class="reserved">char</span> *key);</p>
|
||||||
|
<h4 class="parameters">Parameters</h4>
|
||||||
|
<table class="list"><tbody>
|
||||||
|
<tr><th>page</th>
|
||||||
|
<td class="description">Page object</td></tr>
|
||||||
|
<tr><th>key</th>
|
||||||
|
<td class="description">Dictionary key</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
|
<p class="description">Date/time or <code>0</code> if none</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function looks up a date value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<h3 class="function"><span class="info"> PDFio 1.7 </span><a id="pdfioPageGetDict">pdfioPageGetDict</a></h3>
|
||||||
|
<p class="description">Get a dictionary value from the page dictionary.</p>
|
||||||
|
<p class="code">
|
||||||
|
<a href="#pdfio_dict_t">pdfio_dict_t</a> *pdfioPageGetDict(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page, <span class="reserved">const</span> <span class="reserved">char</span> *key);</p>
|
||||||
|
<h4 class="parameters">Parameters</h4>
|
||||||
|
<table class="list"><tbody>
|
||||||
|
<tr><th>page</th>
|
||||||
|
<td class="description">Page object</td></tr>
|
||||||
|
<tr><th>key</th>
|
||||||
|
<td class="description">Dictionary key</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
|
<p class="description">Dictionary or <code>NULL</code> if none</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function looks up a dictionary value in the page dictionary, either in
|
||||||
|
the specified object or one of its parents.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<h3 class="function"><span class="info"> PDFio 1.7 </span><a id="pdfioPageGetName">pdfioPageGetName</a></h3>
|
||||||
|
<p class="description">Get a name value from the page dictionary.</p>
|
||||||
|
<p class="code">
|
||||||
|
<span class="reserved">const</span> <span class="reserved">char</span> *pdfioPageGetName(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page, <span class="reserved">const</span> <span class="reserved">char</span> *key);</p>
|
||||||
|
<h4 class="parameters">Parameters</h4>
|
||||||
|
<table class="list"><tbody>
|
||||||
|
<tr><th>page</th>
|
||||||
|
<td class="description">Page object</td></tr>
|
||||||
|
<tr><th>key</th>
|
||||||
|
<td class="description">Dictionary key</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
|
<p class="description">Name string or <code>NULL</code> if none</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function looks up a name value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
</p>
|
||||||
<h3 class="function"><a id="pdfioPageGetNumStreams">pdfioPageGetNumStreams</a></h3>
|
<h3 class="function"><a id="pdfioPageGetNumStreams">pdfioPageGetNumStreams</a></h3>
|
||||||
<p class="description">Get the number of content streams for a page object.</p>
|
<p class="description">Get the number of content streams for a page object.</p>
|
||||||
<p class="code">
|
<p class="code">
|
||||||
@@ -5420,6 +5558,80 @@ size_t pdfioPageGetNumStreams(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page);</p>
|
|||||||
</tbody></table>
|
</tbody></table>
|
||||||
<h4 class="returnvalue">Return Value</h4>
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
<p class="description">Number of streams</p>
|
<p class="description">Number of streams</p>
|
||||||
|
<h3 class="function"><span class="info"> PDFio 1.7 </span><a id="pdfioPageGetNumber">pdfioPageGetNumber</a></h3>
|
||||||
|
<p class="description">Get a number value from the page dictionary.</p>
|
||||||
|
<p class="code">
|
||||||
|
<span class="reserved">double</span> pdfioPageGetNumber(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page, <span class="reserved">const</span> <span class="reserved">char</span> *key);</p>
|
||||||
|
<h4 class="parameters">Parameters</h4>
|
||||||
|
<table class="list"><tbody>
|
||||||
|
<tr><th>page</th>
|
||||||
|
<td class="description">Page object</td></tr>
|
||||||
|
<tr><th>key</th>
|
||||||
|
<td class="description">Dictionary key</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
|
<p class="description">Number value or <code>0.0</code> if none</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function looks up a number value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<h3 class="function"><span class="info"> PDFio 1.7 </span><a id="pdfioPageGetObj">pdfioPageGetObj</a></h3>
|
||||||
|
<p class="description">Get an indirect object value from the page dictionary.</p>
|
||||||
|
<p class="code">
|
||||||
|
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioPageGetObj(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page, <span class="reserved">const</span> <span class="reserved">char</span> *key);</p>
|
||||||
|
<h4 class="parameters">Parameters</h4>
|
||||||
|
<table class="list"><tbody>
|
||||||
|
<tr><th>page</th>
|
||||||
|
<td class="description">Page object</td></tr>
|
||||||
|
<tr><th>key</th>
|
||||||
|
<td class="description">Dictionary key</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
|
<p class="description">Object or <code>NULL</code> if none</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function looks up an indirect object value in the page dictionary,
|
||||||
|
either in the specified object or one of its parents.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<h3 class="function"><span class="info"> PDFio 1.7 </span><a id="pdfioPageGetRect">pdfioPageGetRect</a></h3>
|
||||||
|
<p class="description">Get a rectangle value from the page dictionary.</p>
|
||||||
|
<p class="code">
|
||||||
|
<a href="#pdfio_rect_t">pdfio_rect_t</a> *pdfioPageGetRect(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page, <span class="reserved">const</span> <span class="reserved">char</span> *key, <a href="#pdfio_rect_t">pdfio_rect_t</a> *rect);</p>
|
||||||
|
<h4 class="parameters">Parameters</h4>
|
||||||
|
<table class="list"><tbody>
|
||||||
|
<tr><th>page</th>
|
||||||
|
<td class="description">Page object</td></tr>
|
||||||
|
<tr><th>key</th>
|
||||||
|
<td class="description">Dictionary key</td></tr>
|
||||||
|
<tr><th>rect</th>
|
||||||
|
<td class="description">Rectangle</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
|
<p class="description">Rectangle or <code>NULL</code> if none</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function looks up a rectangle value in the page dictionary, either in
|
||||||
|
the specified object or one of its parents.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<h3 class="function"><span class="info"> PDFio 1.7 </span><a id="pdfioPageGetString">pdfioPageGetString</a></h3>
|
||||||
|
<p class="description">Get a string value from the page dictionary.</p>
|
||||||
|
<p class="code">
|
||||||
|
<span class="reserved">const</span> <span class="reserved">char</span> *pdfioPageGetString(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page, <span class="reserved">const</span> <span class="reserved">char</span> *key);</p>
|
||||||
|
<h4 class="parameters">Parameters</h4>
|
||||||
|
<table class="list"><tbody>
|
||||||
|
<tr><th>page</th>
|
||||||
|
<td class="description">Page object</td></tr>
|
||||||
|
<tr><th>key</th>
|
||||||
|
<td class="description">Dictionary key</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
|
<p class="description">String value or <code>NULL</code> if none</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function looks up a string value in the page dictionary, either in the
|
||||||
|
specified object or one of its parents.
|
||||||
|
|
||||||
|
</p>
|
||||||
<h3 class="function"><a id="pdfioPageOpenStream">pdfioPageOpenStream</a></h3>
|
<h3 class="function"><a id="pdfioPageOpenStream">pdfioPageOpenStream</a></h3>
|
||||||
<p class="description">Open a content stream for a page.</p>
|
<p class="description">Open a content stream for a page.</p>
|
||||||
<p class="code">
|
<p class="code">
|
||||||
@@ -5759,11 +5971,11 @@ typedef enum <a href="#pdfio_valtype_e">pdfio_valtype_e</a> pdfio_valtype_t;
|
|||||||
<table class="list"><tbody>
|
<table class="list"><tbody>
|
||||||
<tr><th>PDFIO_FILTER_ASCII85 </th><td class="description">ASCII85Decode filter (reading only)</td></tr>
|
<tr><th>PDFIO_FILTER_ASCII85 </th><td class="description">ASCII85Decode filter (reading only)</td></tr>
|
||||||
<tr><th>PDFIO_FILTER_ASCIIHEX </th><td class="description">ASCIIHexDecode filter (reading only)</td></tr>
|
<tr><th>PDFIO_FILTER_ASCIIHEX </th><td class="description">ASCIIHexDecode filter (reading only)</td></tr>
|
||||||
<tr><th>PDFIO_FILTER_CCITTFAX </th><td class="description">CCITTFaxDecode filter</td></tr>
|
<tr><th>PDFIO_FILTER_CCITTFAX </th><td class="description">CCITTFaxDecode filter (reading only)</td></tr>
|
||||||
<tr><th>PDFIO_FILTER_CRYPT </th><td class="description">Encryption filter</td></tr>
|
<tr><th>PDFIO_FILTER_CRYPT </th><td class="description">Encryption filter</td></tr>
|
||||||
<tr><th>PDFIO_FILTER_DCT </th><td class="description">DCTDecode (JPEG) filter</td></tr>
|
<tr><th>PDFIO_FILTER_DCT </th><td class="description">DCTDecode (JPEG) filter</td></tr>
|
||||||
<tr><th>PDFIO_FILTER_FLATE </th><td class="description">FlateDecode filter</td></tr>
|
<tr><th>PDFIO_FILTER_FLATE </th><td class="description">FlateDecode filter</td></tr>
|
||||||
<tr><th>PDFIO_FILTER_JBIG2 </th><td class="description">JBIG2Decode filter</td></tr>
|
<tr><th>PDFIO_FILTER_JBIG2 </th><td class="description">JBIG2Decode filter (reading only)</td></tr>
|
||||||
<tr><th>PDFIO_FILTER_JPX </th><td class="description">JPXDecode filter (reading only)</td></tr>
|
<tr><th>PDFIO_FILTER_JPX </th><td class="description">JPXDecode filter (reading only)</td></tr>
|
||||||
<tr><th>PDFIO_FILTER_LZW </th><td class="description">LZWDecode filter (reading only)</td></tr>
|
<tr><th>PDFIO_FILTER_LZW </th><td class="description">LZWDecode filter (reading only)</td></tr>
|
||||||
<tr><th>PDFIO_FILTER_NONE </th><td class="description">No filter</td></tr>
|
<tr><th>PDFIO_FILTER_NONE </th><td class="description">No filter</td></tr>
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
|
|
||||||
#include <pdfio.h>
|
#include <pdfio.h>
|
||||||
#include <pdfio-content.h>
|
#include <pdfio-content.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
# include <io.h>
|
||||||
|
# include <fcntl.h>
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
|
# include <fcntl.h>
|
||||||
#else
|
#else
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|||||||
41
makesrcdist
41
makesrcdist
@@ -7,6 +7,10 @@
|
|||||||
# ./makesrcdist [--snapshot] VERSION
|
# ./makesrcdist [--snapshot] VERSION
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# Save the current directory...
|
||||||
|
basedir="$(pwd)"
|
||||||
|
|
||||||
|
|
||||||
# Support "--snapshot" option...
|
# Support "--snapshot" option...
|
||||||
if test "$1" == "--snapshot"; then
|
if test "$1" == "--snapshot"; then
|
||||||
shift
|
shift
|
||||||
@@ -15,18 +19,21 @@ else
|
|||||||
snapshot=0
|
snapshot=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get version...
|
|
||||||
|
# Get the release version...
|
||||||
if test $# != 1; then
|
if test $# != 1; then
|
||||||
echo "Usage: ./makesrcdist [--snapshot] VERSION"
|
echo "Usage: ./makesrcdist [--snapshot] VERSION"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
status=0
|
|
||||||
version=$1
|
version=$1
|
||||||
version_major=$(echo $1 | awk -F. '{print $1}')
|
version_major=$(echo $1 | awk -F. '{print $1}')
|
||||||
version_minor=$(echo $1 | awk -F. '{print $2}')
|
version_minor=$(echo $1 | awk -F. '{print $2}')
|
||||||
|
|
||||||
|
|
||||||
# Check that version number has been updated everywhere...
|
# Check that version number has been updated everywhere...
|
||||||
|
status=0
|
||||||
|
|
||||||
if test $(grep AC_INIT configure.ac | awk '{print $2}') != "[$version],"; then
|
if test $(grep AC_INIT configure.ac | awk '{print $2}') != "[$version],"; then
|
||||||
echo "Still need to update AC_INIT version in 'configure.ac'."
|
echo "Still need to update AC_INIT version in 'configure.ac'."
|
||||||
status=1
|
status=1
|
||||||
@@ -78,18 +85,32 @@ if test $status = 1; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Tag release...
|
# Tag release...
|
||||||
if test $snapshot = 0; then
|
if test $snapshot = 0; then
|
||||||
echo Creating tag for release...
|
echo "Creating tag v$version for release..."
|
||||||
git tag -m "Tag $version" v$version
|
git tag -m "Tag $version" v$version
|
||||||
git push origin v$version
|
git push origin v$version
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Make source archives...
|
|
||||||
echo Creating 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
|
|
||||||
|
|
||||||
echo Creating pdfio-$version.zip...
|
# Make and sign source archives...
|
||||||
git archive --format zip --prefix=pdfio-$version/ HEAD >pdfio-$version.zip
|
echo "Exporting $version..."
|
||||||
gpg --detach-sign pdfio-$version.zip
|
rm -rf $TMPDIR/pdfio-$version
|
||||||
|
mkdir $TMPDIR/pdfio-$version
|
||||||
|
git archive --format tar HEAD | (cd $TMPDIR/pdfio-$version; tar xf -)
|
||||||
|
(cd ttf; git archive --prefix=ttf/ HEAD) | (cd $TMPDIR/pdfio-$version; tar xf -)
|
||||||
|
cd $TMPDIR
|
||||||
|
|
||||||
|
echo "Creating pdfio-$version.tar.gz..."
|
||||||
|
tar cf - pdfio-$version | gzip -v9 >"$basedir/pdfio-$version.tar.gz"
|
||||||
|
gpg --detach-sign "$basedir/pdfio-$version.tar.gz"
|
||||||
|
|
||||||
|
echo "Creating pdfio-$version.zip..."
|
||||||
|
zip -r "$basedir/pdfio-$version.zip" pdfio-$version
|
||||||
|
gpg --detach-sign "$basedir/pdfio-$version.zip"
|
||||||
|
|
||||||
|
|
||||||
|
# Clean up...
|
||||||
|
echo "Removing temporary files..."
|
||||||
|
rm -rf pdfio-$version
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// AES functions for PDFio.
|
// AES functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2025 by Michael R Sweet.
|
// Copyright © 2021-2026 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.
|
||||||
@@ -117,7 +117,7 @@ _pdfioCryptoAESInit(
|
|||||||
memcpy(ctx->round_key, key, keylen);
|
memcpy(ctx->round_key, key, keylen);
|
||||||
|
|
||||||
// All other round keys are found from the previous round keys.
|
// All other round keys are found from the previous round keys.
|
||||||
for (rkptr0 = ctx->round_key, rkptr = rkptr0 + keylen, rkend = rkptr + 16 * ctx->round_size, i = nwords; rkptr < rkend; i ++)
|
for (rkptr0 = ctx->round_key, rkptr = rkptr0 + keylen, rkend = rkptr0 + 16 * ctx->round_size + 16, i = nwords; rkptr < rkend; i ++)
|
||||||
{
|
{
|
||||||
if ((i % nwords) == 0)
|
if ((i % nwords) == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// PDF array functions for PDFio.
|
// PDF array functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2024 by Michael R Sweet.
|
// Copyright © 2021-2026 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.
|
||||||
@@ -264,6 +264,10 @@ pdfioArrayCopy(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
PDFIO_DEBUG("pdfioArrayCopy(pdf=%p, a=%p(%p))\n", (void *)pdf, (void *)a, a ? (void *)a->pdf : NULL);
|
PDFIO_DEBUG("pdfioArrayCopy(pdf=%p, a=%p(%p))\n", (void *)pdf, (void *)a, a ? (void *)a->pdf : NULL);
|
||||||
|
|
||||||
|
// Range check input...
|
||||||
|
if (!pdf || !a)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
// Create the new array...
|
// Create the new array...
|
||||||
if ((na = pdfioArrayCreate(pdf)) == NULL)
|
if ((na = pdfioArrayCreate(pdf)) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|||||||
269
pdfio-crypto.c
269
pdfio-crypto.c
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Cryptographic support functions for PDFio.
|
// Cryptographic support functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2025 by Michael R Sweet.
|
// Copyright © 2021-2026 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.
|
||||||
@@ -96,12 +96,14 @@ static uint8_t pdf_passpad[32] = // Padding for passwords
|
|||||||
// Local functions...
|
// Local functions...
|
||||||
//
|
//
|
||||||
|
|
||||||
static void decrypt_user_key(pdfio_encryption_t encryption, const uint8_t *file_key, uint8_t user_key[32]);
|
static void decrypt_ou_key(pdfio_encryption_t encryption, const uint8_t *file_key, size_t file_keylen, uint8_t ou_key[32]);
|
||||||
static void encrypt_user_key(pdfio_encryption_t encryption, const uint8_t *file_key, uint8_t user_key[32]);
|
static void encrypt_ou_key(pdfio_encryption_t encryption, const uint8_t *file_key, size_t file_keylen, uint8_t ou_key[32]);
|
||||||
static void make_file_key(pdfio_encryption_t encryption, pdfio_permission_t permissions, const unsigned char *file_id, size_t file_idlen, const uint8_t *user_pad, const uint8_t *owner_key, bool encrypt_metadata, uint8_t file_key[16]);
|
static void make_file_key(pdfio_encryption_t encryption, size_t file_keylen, pdfio_permission_t permissions, const unsigned char *file_id, size_t file_idlen, const uint8_t *user_pad, const uint8_t *owner_key, bool encrypt_metadata, uint8_t file_key[16]);
|
||||||
static void make_owner_key(pdfio_encryption_t encryption, const uint8_t *owner_pad, const uint8_t *user_pad, uint8_t owner_key[32]);
|
static void make_owner_key(pdfio_encryption_t encryption, size_t file_keylen, const uint8_t *owner_pad, const uint8_t *user_pad, uint8_t owner_key[32]);
|
||||||
|
static void make_password_key(pdfio_encryption_t encryption, size_t file_keylen, const uint8_t *pad, uint8_t *key);
|
||||||
static void make_user_key(const unsigned char *file_id, size_t file_idlen, uint8_t user_key[32]);
|
static void make_user_key(const unsigned char *file_id, size_t file_idlen, uint8_t user_key[32]);
|
||||||
static void pad_password(const char *password, uint8_t pad[32]);
|
static void pad_password(const char *password, uint8_t pad[32]);
|
||||||
|
static bool test_password(pdfio_encryption_t encryption, size_t file_keylen, pdfio_permission_t permisions,const unsigned char *file_id, size_t file_idlen, const uint8_t *user_pad, const uint8_t *user_key, const uint8_t *owner_key, bool encrypt_metadata, uint8_t file_key[16]);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -139,6 +141,7 @@ _pdfioCryptoLock(
|
|||||||
case PDFIO_ENCRYPTION_AES_128 :
|
case PDFIO_ENCRYPTION_AES_128 :
|
||||||
// Create the 128-bit encryption keys...
|
// Create the 128-bit encryption keys...
|
||||||
pad_password(user_password, user_pad);
|
pad_password(user_password, user_pad);
|
||||||
|
pdf->file_keylen = 16;
|
||||||
|
|
||||||
if (!owner_password && user_password && *user_password)
|
if (!owner_password && user_password && *user_password)
|
||||||
{
|
{
|
||||||
@@ -152,18 +155,17 @@ _pdfioCryptoLock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute the owner key...
|
// Compute the owner key...
|
||||||
make_owner_key(encryption, owner_pad, user_pad, pdf->owner_key);
|
make_owner_key(encryption, pdf->file_keylen, owner_pad, user_pad, pdf->owner_key);
|
||||||
pdf->owner_keylen = 32;
|
pdf->owner_keylen = 32;
|
||||||
|
|
||||||
// Generate the encryption key
|
// Generate the encryption key
|
||||||
file_id = pdfioArrayGetBinary(pdf->id_array, 0, &file_idlen);
|
file_id = pdfioArrayGetBinary(pdf->id_array, 0, &file_idlen);
|
||||||
|
|
||||||
make_file_key(encryption, permissions, file_id, file_idlen, user_pad, pdf->owner_key, pdf->encrypt_metadata, pdf->file_key);
|
make_file_key(encryption, pdf->file_keylen, permissions, file_id, file_idlen, user_pad, pdf->owner_key, pdf->encrypt_metadata, pdf->file_key);
|
||||||
pdf->file_keylen = 16;
|
|
||||||
|
|
||||||
// Generate the user key...
|
// Generate the user key...
|
||||||
make_user_key(file_id, file_idlen, pdf->user_key);
|
make_user_key(file_id, file_idlen, pdf->user_key);
|
||||||
encrypt_user_key(encryption, pdf->file_key, pdf->user_key);
|
encrypt_ou_key(encryption, pdf->file_key, pdf->file_keylen, pdf->user_key);
|
||||||
pdf->user_keylen = 32;
|
pdf->user_keylen = 32;
|
||||||
|
|
||||||
// Save everything in the dictionary...
|
// Save everything in the dictionary...
|
||||||
@@ -214,8 +216,9 @@ _pdfioCryptoLock(
|
|||||||
|
|
||||||
pdfioObjClose(pdf->encrypt_obj);
|
pdfioObjClose(pdf->encrypt_obj);
|
||||||
|
|
||||||
pdf->encryption = encryption;
|
pdf->encrypt_dict = dict;
|
||||||
pdf->permissions = permissions;
|
pdf->encryption = encryption;
|
||||||
|
pdf->permissions = permissions;
|
||||||
|
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
@@ -570,7 +573,6 @@ _pdfioCryptoUnlock(
|
|||||||
{
|
{
|
||||||
int tries; // Number of tries
|
int tries; // Number of tries
|
||||||
const char *password = NULL; // Password to try
|
const char *password = NULL; // Password to try
|
||||||
pdfio_dict_t *encrypt_dict; // Encrypt objection dictionary
|
|
||||||
int version, // Version value
|
int version, // Version value
|
||||||
revision, // Revision value
|
revision, // Revision value
|
||||||
length; // Key length value
|
length; // Key length value
|
||||||
@@ -590,20 +592,14 @@ _pdfioCryptoUnlock(
|
|||||||
_pdfio_value_t *value; // Encrypt dictionary value, if any
|
_pdfio_value_t *value; // Encrypt dictionary value, if any
|
||||||
|
|
||||||
|
|
||||||
// See if we support the type of encryption specified by the Encrypt object
|
// See if we support the type of encryption specified by the Encrypt
|
||||||
// dictionary...
|
// dictionary...
|
||||||
if ((encrypt_dict = pdfioObjGetDict(pdf->encrypt_obj)) == NULL)
|
handler = pdfioDictGetName(pdf->encrypt_dict, "Filter");
|
||||||
{
|
version = (int)pdfioDictGetNumber(pdf->encrypt_dict, "V");
|
||||||
_pdfioFileError(pdf, "Unable to get encryption dictionary.");
|
revision = (int)pdfioDictGetNumber(pdf->encrypt_dict, "R");
|
||||||
return (false);
|
length = (int)pdfioDictGetNumber(pdf->encrypt_dict, "Length");
|
||||||
}
|
|
||||||
|
|
||||||
handler = pdfioDictGetName(encrypt_dict, "Filter");
|
if ((value = _pdfioDictGetValue(pdf->encrypt_dict, "EncryptMetadata")) != NULL && value->type == PDFIO_VALTYPE_BOOLEAN)
|
||||||
version = (int)pdfioDictGetNumber(encrypt_dict, "V");
|
|
||||||
revision = (int)pdfioDictGetNumber(encrypt_dict, "R");
|
|
||||||
length = (int)pdfioDictGetNumber(encrypt_dict, "Length");
|
|
||||||
|
|
||||||
if ((value = _pdfioDictGetValue(encrypt_dict, "EncryptMetadata")) != NULL && value->type == PDFIO_VALTYPE_BOOLEAN)
|
|
||||||
pdf->encrypt_metadata = value->value.boolean;
|
pdf->encrypt_metadata = value->value.boolean;
|
||||||
else
|
else
|
||||||
pdf->encrypt_metadata = true;
|
pdf->encrypt_metadata = true;
|
||||||
@@ -622,9 +618,9 @@ _pdfioCryptoUnlock(
|
|||||||
pdfio_dict_t *filter; // Crypt Filter
|
pdfio_dict_t *filter; // Crypt Filter
|
||||||
const char *cfm; // Crypt filter method
|
const char *cfm; // Crypt filter method
|
||||||
|
|
||||||
stream_filter = pdfioDictGetName(encrypt_dict, "StmF");
|
stream_filter = pdfioDictGetName(pdf->encrypt_dict, "StmF");
|
||||||
string_filter = pdfioDictGetName(encrypt_dict, "StrF");
|
string_filter = pdfioDictGetName(pdf->encrypt_dict, "StrF");
|
||||||
cf_dict = pdfioDictGetDict(encrypt_dict, "CF");
|
cf_dict = pdfioDictGetDict(pdf->encrypt_dict, "CF");
|
||||||
|
|
||||||
if (!cf_dict)
|
if (!cf_dict)
|
||||||
{
|
{
|
||||||
@@ -697,11 +693,16 @@ _pdfioCryptoUnlock(
|
|||||||
_pdfioFileError(pdf, "Unsupported encryption V%d R%d.", version, revision);
|
_pdfioFileError(pdf, "Unsupported encryption V%d R%d.", version, revision);
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
else if (length < 40 || length > 128)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unsupported key length %d.", length);
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
// Grab the remaining values we need to unlock the PDF...
|
// Grab the remaining values we need to unlock the PDF...
|
||||||
pdf->file_keylen = (size_t)(length / 8);
|
pdf->file_keylen = (size_t)(length / 8);
|
||||||
|
|
||||||
p = pdfioDictGetNumber(encrypt_dict, "P");
|
p = pdfioDictGetNumber(pdf->encrypt_dict, "P");
|
||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: P=%.0f\n", p);
|
PDFIO_DEBUG("_pdfioCryptoUnlock: P=%.0f\n", p);
|
||||||
if (p < 0x7fffffff) // Handle integers > 2^31-1
|
if (p < 0x7fffffff) // Handle integers > 2^31-1
|
||||||
pdf->permissions = (pdfio_permission_t)p;
|
pdf->permissions = (pdfio_permission_t)p;
|
||||||
@@ -709,8 +710,8 @@ _pdfioCryptoUnlock(
|
|||||||
pdf->permissions = (pdfio_permission_t)(p - 4294967296.0);
|
pdf->permissions = (pdfio_permission_t)(p - 4294967296.0);
|
||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: permissions=%d\n", pdf->permissions);
|
PDFIO_DEBUG("_pdfioCryptoUnlock: permissions=%d\n", pdf->permissions);
|
||||||
|
|
||||||
owner_key = pdfioDictGetBinary(encrypt_dict, "O", &owner_keylen);
|
owner_key = pdfioDictGetBinary(pdf->encrypt_dict, "O", &owner_keylen);
|
||||||
user_key = pdfioDictGetBinary(encrypt_dict, "U", &user_keylen);
|
user_key = pdfioDictGetBinary(pdf->encrypt_dict, "U", &user_keylen);
|
||||||
|
|
||||||
if (!owner_key)
|
if (!owner_key)
|
||||||
{
|
{
|
||||||
@@ -739,7 +740,7 @@ _pdfioCryptoUnlock(
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: user_key[%d]=%02X%02X%02X%02X...%02X%02X%02X%02X\n", (int)user_keylen, 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: user_key[%d]=<%02X%02X%02X%02X...%02X%02X%02X%02X>\n", (int)user_keylen, user_key[0], user_key[1], user_key[2], user_key[3], user_key[28], user_key[29], user_key[30], user_key[31]);
|
||||||
|
|
||||||
memcpy(pdf->user_key, user_key, user_keylen);
|
memcpy(pdf->user_key, user_key, user_keylen);
|
||||||
pdf->user_keylen = user_keylen;
|
pdf->user_keylen = user_keylen;
|
||||||
@@ -750,6 +751,9 @@ _pdfioCryptoUnlock(
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfioCryptoUnlock: P=%d\n", pdf->permissions);
|
||||||
|
PDFIO_DEBUG("_pdfioCryptoUnlock: file_id(%d)=<%02X%02X%02X%02X...%02X%02X%02X%02X>\n", (int)file_idlen, file_id[0], file_id[1], file_id[2], file_id[3], file_id[12], file_id[13], file_id[14], file_id[15]);
|
||||||
|
|
||||||
// Generate a base hash from known values...
|
// Generate a base hash from known values...
|
||||||
_pdfioCryptoMD5Init(&md5);
|
_pdfioCryptoMD5Init(&md5);
|
||||||
_pdfioCryptoMD5Append(&md5, pdf_passpad, 32);
|
_pdfioCryptoMD5Append(&md5, pdf_passpad, 32);
|
||||||
@@ -761,56 +765,34 @@ _pdfioCryptoUnlock(
|
|||||||
{
|
{
|
||||||
if (pdf->encryption <= PDFIO_ENCRYPTION_AES_128)
|
if (pdf->encryption <= PDFIO_ENCRYPTION_AES_128)
|
||||||
{
|
{
|
||||||
|
// RC4 and AES-128 encryption...
|
||||||
uint8_t pad[32], // Padded password
|
uint8_t pad[32], // Padded password
|
||||||
file_key[16], // File key
|
padkey[16], // Password key
|
||||||
user_pad[32], // Padded user password
|
file_key[16]; // File key
|
||||||
own_user_key[32], // Calculated user key
|
|
||||||
pdf_user_key[32]; // Decrypted user key
|
|
||||||
|
|
||||||
// Pad the supplied password, if any...
|
// Pad the supplied password, if any...
|
||||||
pad_password(password, pad);
|
pad_password(password, pad);
|
||||||
|
|
||||||
// Generate keys to see if things match...
|
// Test the user password...
|
||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Trying %02X%02X%02X%02X...%02X%02X%02X%02X\n", pad[0], pad[1], pad[2], pad[3], pad[28], pad[29], pad[30], pad[31]);
|
PDFIO_DEBUG("_pdfioCryptoUnlock: Trying <%02X%02X%02X%02X...%02X%02X%02X%02X>\n", pad[0], pad[1], pad[2], pad[3], pad[28], pad[29], pad[30], pad[31]);
|
||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: P=%d\n", pdf->permissions);
|
|
||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Fid(%d)=%02X%02X%02X%02X...%02X%02X%02X%02X\n", (int)file_idlen, file_id[0], file_id[1], file_id[2], file_id[3], file_id[12], file_id[13], file_id[14], file_id[15]);
|
|
||||||
|
|
||||||
make_owner_key(pdf->encryption, pad, pdf->owner_key, user_pad);
|
if (test_password(pdf->encryption, pdf->file_keylen, pdf->permissions, file_id, file_idlen, pad, pdf->user_key, pdf->owner_key, pdf->encrypt_metadata, file_key))
|
||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Upad=%02X%02X%02X%02X...%02X%02X%02X%02X\n", user_pad[0], user_pad[1], user_pad[2], user_pad[3], user_pad[28], user_pad[29], user_pad[30], user_pad[31]);
|
|
||||||
|
|
||||||
make_file_key(pdf->encryption, pdf->permissions, file_id, file_idlen, user_pad, pdf->owner_key, pdf->encrypt_metadata, file_key);
|
|
||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Fown=%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, own_user_key);
|
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioCryptoUnlock: U=%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: Uown=%02X%02X%02X%02X...%02X%02X%02X%02X\n", own_user_key[0], own_user_key[1], own_user_key[2], own_user_key[3], own_user_key[28], own_user_key[29], own_user_key[30], own_user_key[31]);
|
|
||||||
|
|
||||||
if (!memcmp(own_user_key, pdf->user_key, sizeof(own_user_key)))
|
|
||||||
{
|
{
|
||||||
// Matches!
|
memcpy(pdf->file_key, file_key, pdf->file_keylen);
|
||||||
memcpy(pdf->file_key, file_key, sizeof(pdf->file_key));
|
|
||||||
memcpy(pdf->password, pad, sizeof(pdf->password));
|
memcpy(pdf->password, pad, sizeof(pdf->password));
|
||||||
|
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not the owner password, try the user password...
|
// Test the owner password...
|
||||||
make_file_key(pdf->encryption, pdf->permissions, file_id, file_idlen, pad, pdf->owner_key, pdf->encrypt_metadata, file_key);
|
make_password_key(pdf->encryption, pdf->file_keylen, pad, padkey);
|
||||||
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, own_user_key);
|
memcpy(pad, pdf->owner_key, sizeof(pad));
|
||||||
|
decrypt_ou_key(pdf->encryption, padkey, pdf->file_keylen, pad);
|
||||||
|
|
||||||
memcpy(pdf_user_key, pdf->user_key, sizeof(pdf_user_key));
|
if (test_password(pdf->encryption, pdf->file_keylen, pdf->permissions, file_id, file_idlen, pad, pdf->user_key, pdf->owner_key, pdf->encrypt_metadata, file_key))
|
||||||
decrypt_user_key(pdf->encryption, file_key, pdf_user_key);
|
|
||||||
|
|
||||||
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]);
|
|
||||||
|
|
||||||
if (!memcmp(pad, pdf_user_key, 32) || !memcmp(own_user_key, pdf_user_key, 16))
|
|
||||||
{
|
{
|
||||||
// Matches!
|
memcpy(pdf->file_key, file_key, pdf->file_keylen);
|
||||||
memcpy(pdf->file_key, file_key, sizeof(pdf->file_key));
|
|
||||||
memcpy(pdf->password, pad, sizeof(pdf->password));
|
memcpy(pdf->password, pad, sizeof(pdf->password));
|
||||||
|
|
||||||
return (true);
|
return (true);
|
||||||
@@ -838,14 +820,15 @@ _pdfioCryptoUnlock(
|
|||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'decrypt_user_key()' - Decrypt the user key.
|
// 'decrypt_ou_key()' - Decrypt the user key.
|
||||||
//
|
//
|
||||||
|
|
||||||
static void
|
static void
|
||||||
decrypt_user_key(
|
decrypt_ou_key(
|
||||||
pdfio_encryption_t encryption, // I - Type of encryption
|
pdfio_encryption_t encryption, // I - Type of encryption
|
||||||
const uint8_t *file_key, // I - File encryption key
|
const uint8_t *file_key, // I - File encryption key
|
||||||
uint8_t user_key[32]) // IO - User key
|
size_t file_keylen, // I - Length of file encryption key
|
||||||
|
uint8_t ou_key[32]) // IO - Owner/User key
|
||||||
{
|
{
|
||||||
size_t i, j; // Looping vars
|
size_t i, j; // Looping vars
|
||||||
_pdfio_rc4_t rc4; // RC4 encryption context
|
_pdfio_rc4_t rc4; // RC4 encryption context
|
||||||
@@ -855,38 +838,38 @@ decrypt_user_key(
|
|||||||
{
|
{
|
||||||
// Encrypt the result once...
|
// Encrypt the result once...
|
||||||
_pdfioCryptoRC4Init(&rc4, file_key, 5);
|
_pdfioCryptoRC4Init(&rc4, file_key, 5);
|
||||||
_pdfioCryptoRC4Crypt(&rc4, user_key, user_key, 32);
|
_pdfioCryptoRC4Crypt(&rc4, ou_key, ou_key, 32);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Encrypt the result 20 times...
|
// Encrypt the result 20 times...
|
||||||
uint8_t key[16]; // Current encryption key
|
uint8_t key[16]; // Current encryption key
|
||||||
|
|
||||||
for (i = 19; i > 0; i --)
|
for (i = 20; i > 0;)
|
||||||
{
|
{
|
||||||
// XOR each byte in the key with the loop counter...
|
// XOR each byte in the key with the loop counter...
|
||||||
for (j = 0; j < 16; j ++)
|
i --;
|
||||||
|
|
||||||
|
for (j = 0; j < file_keylen; j ++)
|
||||||
key[j] = (uint8_t)(file_key[j] ^ i);
|
key[j] = (uint8_t)(file_key[j] ^ i);
|
||||||
|
|
||||||
_pdfioCryptoRC4Init(&rc4, key, 16);
|
_pdfioCryptoRC4Init(&rc4, key, file_keylen);
|
||||||
_pdfioCryptoRC4Crypt(&rc4, user_key, user_key, 32);
|
_pdfioCryptoRC4Crypt(&rc4, ou_key, ou_key, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
_pdfioCryptoRC4Init(&rc4, file_key, 16);
|
|
||||||
_pdfioCryptoRC4Crypt(&rc4, user_key, user_key, 32);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'encrypt_user_key()' - Encrypt the user key.
|
// 'encrypt_ou_key()' - Encrypt the owner/user key.
|
||||||
//
|
//
|
||||||
|
|
||||||
static void
|
static void
|
||||||
encrypt_user_key(
|
encrypt_ou_key(
|
||||||
pdfio_encryption_t encryption, // I - Type of encryption
|
pdfio_encryption_t encryption, // I - Type of encryption
|
||||||
const uint8_t *file_key, // I - File encryption key
|
const uint8_t *file_key, // I - File encryption key
|
||||||
uint8_t user_key[32]) // IO - User key
|
size_t file_keylen, // I - Length of file encryption key
|
||||||
|
uint8_t ou_key[32]) // IO - Owner/User key
|
||||||
{
|
{
|
||||||
size_t i, j; // Looping vars
|
size_t i, j; // Looping vars
|
||||||
_pdfio_rc4_t rc4; // RC4 encryption context
|
_pdfio_rc4_t rc4; // RC4 encryption context
|
||||||
@@ -896,7 +879,7 @@ encrypt_user_key(
|
|||||||
{
|
{
|
||||||
// Encrypt the result once...
|
// Encrypt the result once...
|
||||||
_pdfioCryptoRC4Init(&rc4, file_key, 5);
|
_pdfioCryptoRC4Init(&rc4, file_key, 5);
|
||||||
_pdfioCryptoRC4Crypt(&rc4, user_key, user_key, 32);
|
_pdfioCryptoRC4Crypt(&rc4, ou_key, ou_key, 32);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -906,11 +889,11 @@ encrypt_user_key(
|
|||||||
for (i = 0; i < 20; i ++)
|
for (i = 0; i < 20; i ++)
|
||||||
{
|
{
|
||||||
// XOR each byte in the key with the loop counter...
|
// XOR each byte in the key with the loop counter...
|
||||||
for (j = 0; j < 16; j ++)
|
for (j = 0; j < file_keylen; j ++)
|
||||||
key[j] = (uint8_t)(file_key[j] ^ i);
|
key[j] = (uint8_t)(file_key[j] ^ i);
|
||||||
|
|
||||||
_pdfioCryptoRC4Init(&rc4, key, 16);
|
_pdfioCryptoRC4Init(&rc4, key, file_keylen);
|
||||||
_pdfioCryptoRC4Crypt(&rc4, user_key, user_key, 32);
|
_pdfioCryptoRC4Crypt(&rc4, ou_key, ou_key, 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -923,6 +906,7 @@ encrypt_user_key(
|
|||||||
static void
|
static void
|
||||||
make_file_key(
|
make_file_key(
|
||||||
pdfio_encryption_t encryption, // I - Type of encryption
|
pdfio_encryption_t encryption, // I - Type of encryption
|
||||||
|
size_t file_keylen, // I - Encryption key length
|
||||||
pdfio_permission_t permissions, // I - File permissions
|
pdfio_permission_t permissions, // I - File permissions
|
||||||
const unsigned char *file_id, // I - File ID value
|
const unsigned char *file_id, // I - File ID value
|
||||||
size_t file_idlen, // I - Length of file ID
|
size_t file_idlen, // I - Length of file ID
|
||||||
@@ -968,14 +952,14 @@ make_file_key(
|
|||||||
for (i = 0; i < 50; i ++)
|
for (i = 0; i < 50; i ++)
|
||||||
{
|
{
|
||||||
_pdfioCryptoMD5Init(&md5);
|
_pdfioCryptoMD5Init(&md5);
|
||||||
_pdfioCryptoMD5Append(&md5, digest, 16);
|
_pdfioCryptoMD5Append(&md5, digest, file_keylen);
|
||||||
_pdfioCryptoMD5Finish(&md5, digest);
|
_pdfioCryptoMD5Finish(&md5, digest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFIO_DEBUG("make_file_key: file_key[16]=<%02X%02X%02X%02X...%02X%02X%02X%02X>\n", digest[0], digest[1], digest[2], digest[3], digest[12], digest[13], digest[14], digest[15]);
|
PDFIO_DEBUG("make_file_key: file_key[16]=<%02X%02X%02X%02X...%02X%02X%02X%02X>\n", digest[0], digest[1], digest[2], digest[3], digest[12], digest[13], digest[14], digest[15]);
|
||||||
|
|
||||||
memcpy(file_key, digest, 16);
|
memcpy(file_key, digest, file_keylen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -986,57 +970,57 @@ make_file_key(
|
|||||||
static void
|
static void
|
||||||
make_owner_key(
|
make_owner_key(
|
||||||
pdfio_encryption_t encryption, // I - Type of encryption
|
pdfio_encryption_t encryption, // I - Type of encryption
|
||||||
|
size_t file_keylen, // I - Length of encryption key
|
||||||
const uint8_t *owner_pad, // I - Padded owner password
|
const uint8_t *owner_pad, // I - Padded owner password
|
||||||
const uint8_t *user_pad, // I - Padded user password
|
const uint8_t *user_pad, // I - Padded user password
|
||||||
uint8_t owner_key[32]) // O - Owner key value
|
uint8_t owner_key[32]) // O - Owner key value
|
||||||
{
|
{
|
||||||
size_t i, j; // Looping vars
|
uint8_t key[16]; // Base encryption key
|
||||||
_pdfio_md5_t md5; // MD5 context
|
|
||||||
uint8_t digest[16]; // 128-bit MD5 digest
|
|
||||||
_pdfio_rc4_t rc4; // RC4 encryption context
|
|
||||||
|
|
||||||
|
|
||||||
// Hash the owner password...
|
// Hash the owner password...
|
||||||
|
make_password_key(encryption, file_keylen, owner_pad, key);
|
||||||
|
|
||||||
|
// Copy and encrypt the padded user password...
|
||||||
|
memcpy(owner_key, user_pad, 32);
|
||||||
|
decrypt_ou_key(encryption, key, file_keylen, owner_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'make_password_key()' - Make a password key.
|
||||||
|
//
|
||||||
|
|
||||||
|
static void
|
||||||
|
make_password_key(
|
||||||
|
pdfio_encryption_t encryption, // I - Type of encryption
|
||||||
|
size_t file_keylen, // I - Length of encryption key
|
||||||
|
const uint8_t *pad, // I - Padded password
|
||||||
|
uint8_t *key) // O - Key data
|
||||||
|
{
|
||||||
|
size_t i; // Looping var
|
||||||
|
_pdfio_md5_t md5; // MD5 context
|
||||||
|
uint8_t digest[16]; // 128-bit MD5 digest
|
||||||
|
|
||||||
|
|
||||||
|
// Hash the padded password...
|
||||||
_pdfioCryptoMD5Init(&md5);
|
_pdfioCryptoMD5Init(&md5);
|
||||||
_pdfioCryptoMD5Append(&md5, owner_pad, 32);
|
_pdfioCryptoMD5Append(&md5, pad, 32);
|
||||||
_pdfioCryptoMD5Finish(&md5, digest);
|
_pdfioCryptoMD5Finish(&md5, digest);
|
||||||
|
|
||||||
if (encryption != PDFIO_ENCRYPTION_RC4_40)
|
if (encryption != PDFIO_ENCRYPTION_RC4_40)
|
||||||
{
|
{
|
||||||
|
// Hash the hash another 50 times...
|
||||||
for (i = 0; i < 50; i ++)
|
for (i = 0; i < 50; i ++)
|
||||||
{
|
{
|
||||||
_pdfioCryptoMD5Init(&md5);
|
_pdfioCryptoMD5Init(&md5);
|
||||||
_pdfioCryptoMD5Append(&md5, digest, 16);
|
_pdfioCryptoMD5Append(&md5, digest, file_keylen);
|
||||||
_pdfioCryptoMD5Finish(&md5, digest);
|
_pdfioCryptoMD5Finish(&md5, digest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy and encrypt the padded user password...
|
// Copy the key portion of the hashed password to the key...
|
||||||
memcpy(owner_key, user_pad, 32);
|
memcpy(key, digest, file_keylen);
|
||||||
|
|
||||||
if (encryption == PDFIO_ENCRYPTION_RC4_40)
|
|
||||||
{
|
|
||||||
// Encrypt once...
|
|
||||||
_pdfioCryptoRC4Init(&rc4, digest, 5);
|
|
||||||
_pdfioCryptoRC4Crypt(&rc4, owner_key, owner_key, 32);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Encrypt 20 times...
|
|
||||||
uint8_t encrypt_key[16]; // RC4 encryption key
|
|
||||||
|
|
||||||
for (i = 20; i > 0;)
|
|
||||||
{
|
|
||||||
// XOR each byte in the digest with the loop counter to make a key...
|
|
||||||
i --;
|
|
||||||
|
|
||||||
for (j = 0; j < sizeof(encrypt_key); j ++)
|
|
||||||
encrypt_key[j] = (uint8_t)(digest[j] ^ i);
|
|
||||||
|
|
||||||
_pdfioCryptoRC4Init(&rc4, encrypt_key, sizeof(encrypt_key));
|
|
||||||
_pdfioCryptoRC4Crypt(&rc4, owner_key, owner_key, 32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1091,3 +1075,52 @@ pad_password(const char *password, // I - Password string or `NULL`
|
|||||||
if (len < 32)
|
if (len < 32)
|
||||||
memcpy(pad + len, pdf_passpad, 32 - len);
|
memcpy(pad + len, pdf_passpad, 32 - len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'test_password()' - Test a user password...
|
||||||
|
//
|
||||||
|
|
||||||
|
static bool // O - `true` if password is correct, `false` otherwise
|
||||||
|
test_password(
|
||||||
|
pdfio_encryption_t encryption, // I - Type of encryption
|
||||||
|
size_t file_keylen, // I - Length of encryption key
|
||||||
|
pdfio_permission_t permissions, // I - File permissions
|
||||||
|
const unsigned char *file_id, // I - File ID value
|
||||||
|
size_t file_idlen, // I - Length of file ID
|
||||||
|
const uint8_t *user_pad, // I - Padded user password
|
||||||
|
const uint8_t *user_key, // I - User key
|
||||||
|
const uint8_t *owner_key, // I - Owner key
|
||||||
|
bool encrypt_metadata,
|
||||||
|
// I - Encrypt metadata?
|
||||||
|
uint8_t file_key[16]) // O - Encryption key
|
||||||
|
{
|
||||||
|
uint8_t pdf_user_key[32]; // Decrypted user key
|
||||||
|
|
||||||
|
|
||||||
|
// Make the file key...
|
||||||
|
make_file_key(encryption, file_keylen, permissions, file_id, file_idlen, user_pad, owner_key, encrypt_metadata, file_key);
|
||||||
|
|
||||||
|
// Decrypt the user key using the file key...
|
||||||
|
memcpy(pdf_user_key, user_key, sizeof(pdf_user_key));
|
||||||
|
decrypt_ou_key(encryption, file_key, file_keylen, pdf_user_key);
|
||||||
|
PDFIO_DEBUG("test_password: pdf_user_key[32]=<%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 (encryption == PDFIO_ENCRYPTION_RC4_40 && !memcmp(pdf_user_key, pdf_passpad, 32))
|
||||||
|
{
|
||||||
|
// 40-bit encryption just compares the eecrypted user key matches...
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 128-bit encryption needs to match the calculated user key...
|
||||||
|
uint8_t own_user_key[32]; // Calculated user key
|
||||||
|
|
||||||
|
// Calculate what the user key should be...
|
||||||
|
make_user_key(file_id, file_idlen, own_user_key);
|
||||||
|
PDFIO_DEBUG("test_password: own_user_key[32]=<%02X%02X%02X%02X...%02X%02X%02X%02X>\n", own_user_key[0], own_user_key[1], own_user_key[2], own_user_key[3], own_user_key[28], own_user_key[29], own_user_key[30], own_user_key[31]);
|
||||||
|
|
||||||
|
// Return whether they match...
|
||||||
|
return (!memcmp(pdf_user_key, own_user_key, 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
26
pdfio-dict.c
26
pdfio-dict.c
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// PDF dictionary functions for PDFio.
|
// PDF dictionary functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2025 by Michael R Sweet.
|
// Copyright © 2021-2026 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.
|
||||||
@@ -79,6 +79,10 @@ pdfioDictCopy(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
PDFIO_DEBUG("pdfioDictCopy(pdf=%p, dict=%p(%p))\n", (void *)pdf, (void *)dict, dict ? (void *)dict->pdf : NULL);
|
PDFIO_DEBUG("pdfioDictCopy(pdf=%p, dict=%p(%p))\n", (void *)pdf, (void *)dict, dict ? (void *)dict->pdf : NULL);
|
||||||
|
|
||||||
|
// Range check input...
|
||||||
|
if (!pdf || !dict)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
// Create the new dictionary...
|
// Create the new dictionary...
|
||||||
if ((ndict = pdfioDictCreate(pdf)) == NULL)
|
if ((ndict = pdfioDictCreate(pdf)) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@@ -92,6 +96,8 @@ pdfioDictCopy(pdfio_file_t *pdf, // I - PDF file
|
|||||||
// Copy and add each of the source dictionary's key/value pairs...
|
// Copy and add each of the source dictionary's key/value pairs...
|
||||||
for (i = dict->num_pairs, p = dict->pairs; i > 0; i --, p ++)
|
for (i = dict->num_pairs, p = dict->pairs; i > 0; i --, p ++)
|
||||||
{
|
{
|
||||||
|
PDFIO_DEBUG("pdfioDictCopy: key=\"%s\", value.type=%d\n", p->key, p->value.type);
|
||||||
|
|
||||||
if (!strcmp(p->key, "Length") && p->value.type == PDFIO_VALTYPE_INDIRECT && dict->pdf != pdf)
|
if (!strcmp(p->key, "Length") && p->value.type == PDFIO_VALTYPE_INDIRECT && dict->pdf != pdf)
|
||||||
{
|
{
|
||||||
// Don't use indirect stream lengths for copied objects...
|
// Don't use indirect stream lengths for copied objects...
|
||||||
@@ -102,15 +108,28 @@ pdfioDictCopy(pdfio_file_t *pdf, // I - PDF file
|
|||||||
if (lenobj)
|
if (lenobj)
|
||||||
{
|
{
|
||||||
if (lenobj->value.type == PDFIO_VALTYPE_NONE)
|
if (lenobj->value.type == PDFIO_VALTYPE_NONE)
|
||||||
_pdfioObjLoad(lenobj);
|
{
|
||||||
|
if (!_pdfioObjLoad(lenobj))
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("pdfioDictCopy: Unable to copy value of \"%s\", returning NULL.\n", p->key);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
v.value.number = lenobj->value.value.number;
|
v.value.number = lenobj->value.value.number;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
v.value.number = 0.0;
|
v.value.number = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("pdfioDictCopy: Length is %.0f.\n", v.value.number);
|
||||||
}
|
}
|
||||||
else if (!_pdfioValueCopy(pdf, &v, dict->pdf, &p->value))
|
else if (!_pdfioValueCopy(pdf, &v, dict->pdf, &p->value))
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("pdfioDictCopy: Unable to copy value of \"%s\", returning NULL.\n", p->key);
|
||||||
return (NULL); // Let pdfioFileClose do the cleanup...
|
return (NULL); // Let pdfioFileClose do the cleanup...
|
||||||
|
}
|
||||||
|
|
||||||
if (_pdfioStringIsAllocated(dict->pdf, p->key))
|
if (_pdfioStringIsAllocated(dict->pdf, p->key))
|
||||||
key = pdfioStringCreate(pdf, p->key);
|
key = pdfioStringCreate(pdf, p->key);
|
||||||
@@ -650,8 +669,7 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
}
|
}
|
||||||
else if (_pdfioDictGetValue(dict, key + 1))
|
else if (_pdfioDictGetValue(dict, key + 1))
|
||||||
{
|
{
|
||||||
// Issue 118: Discard duplicate key/value pairs, in the future this will
|
// Issue 118: Discard duplicate key/value pairs...
|
||||||
// be a warning message...
|
|
||||||
_pdfioValueDelete(&value);
|
_pdfioValueDelete(&value);
|
||||||
if (_pdfioFileError(pdf, "WARNING: Discarding value for duplicate dictionary key '%s'.", key + 1))
|
if (_pdfioFileError(pdf, "WARNING: Discarding value for duplicate dictionary key '%s'.", key + 1))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
80
pdfio-file.c
80
pdfio-file.c
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// PDF file functions for PDFio.
|
// PDF file functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2025 by Michael R Sweet.
|
// Copyright © 2021-2026 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.
|
||||||
@@ -2006,6 +2006,9 @@ load_xref(
|
|||||||
_pdfio_token_t tb; // Token buffer/stack
|
_pdfio_token_t tb; // Token buffer/stack
|
||||||
off_t line_offset; // Offset to start of line
|
off_t line_offset; // Offset to start of line
|
||||||
pdfio_obj_t *pages_obj; // Pages object
|
pdfio_obj_t *pages_obj; // Pages object
|
||||||
|
size_t num_xrefs = 1; // Number of xref offsets
|
||||||
|
off_t xrefs[100] = { xref_offset };
|
||||||
|
// xref offsets
|
||||||
|
|
||||||
|
|
||||||
while (!done)
|
while (!done)
|
||||||
@@ -2283,12 +2286,18 @@ load_xref(
|
|||||||
{
|
{
|
||||||
// Save the trailer dictionary and grab the root (catalog) and info
|
// Save the trailer dictionary and grab the root (catalog) and info
|
||||||
// objects...
|
// objects...
|
||||||
|
pdfio_obj_t *encrypt_obj; // Encryption object
|
||||||
|
|
||||||
pdf->trailer_dict = trailer.value.dict;
|
pdf->trailer_dict = trailer.value.dict;
|
||||||
pdf->encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt");
|
|
||||||
pdf->id_array = pdfioDictGetArray(pdf->trailer_dict, "ID");
|
pdf->id_array = pdfioDictGetArray(pdf->trailer_dict, "ID");
|
||||||
|
|
||||||
|
if ((encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt")) != NULL)
|
||||||
|
pdf->encrypt_dict = pdfioObjGetDict(encrypt_obj);
|
||||||
|
else
|
||||||
|
pdf->encrypt_dict = pdfioDictGetDict(pdf->trailer_dict, "Encrypt");
|
||||||
|
|
||||||
// If the trailer contains an Encrypt key, try unlocking the file...
|
// If the trailer contains an Encrypt key, try unlocking the file...
|
||||||
if (pdf->encrypt_obj && !_pdfioCryptoUnlock(pdf, password_cb, password_data))
|
if (pdf->encrypt_dict && !_pdfioCryptoUnlock(pdf, password_cb, password_data))
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2434,12 +2443,18 @@ load_xref(
|
|||||||
{
|
{
|
||||||
// Save the trailer dictionary and grab the root (catalog) and info
|
// Save the trailer dictionary and grab the root (catalog) and info
|
||||||
// objects...
|
// objects...
|
||||||
|
pdfio_obj_t *encrypt_obj; // Encryption object
|
||||||
|
|
||||||
pdf->trailer_dict = trailer.value.dict;
|
pdf->trailer_dict = trailer.value.dict;
|
||||||
pdf->encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt");
|
|
||||||
pdf->id_array = pdfioDictGetArray(pdf->trailer_dict, "ID");
|
pdf->id_array = pdfioDictGetArray(pdf->trailer_dict, "ID");
|
||||||
|
|
||||||
|
if ((encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt")) != NULL)
|
||||||
|
pdf->encrypt_dict = pdfioObjGetDict(encrypt_obj);
|
||||||
|
else
|
||||||
|
pdf->encrypt_dict = pdfioDictGetDict(pdf->trailer_dict, "Encrypt");
|
||||||
|
|
||||||
// If the trailer contains an Encrypt key, try unlocking the file...
|
// If the trailer contains an Encrypt key, try unlocking the file...
|
||||||
if (pdf->encrypt_obj && !_pdfioCryptoUnlock(pdf, password_cb, password_data))
|
if (pdf->encrypt_dict && !_pdfioCryptoUnlock(pdf, password_cb, password_data))
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2459,13 +2474,31 @@ load_xref(
|
|||||||
{
|
{
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
else if (new_offset == xref_offset)
|
else
|
||||||
{
|
{
|
||||||
_pdfioFileError(pdf, "Recursive xref table.");
|
// See if we've seen this xref table before...
|
||||||
return (false);
|
size_t i; // Looping var
|
||||||
}
|
|
||||||
|
|
||||||
xref_offset = new_offset;
|
for (i = 0; i < num_xrefs; i ++)
|
||||||
|
{
|
||||||
|
if (new_offset == xrefs[i])
|
||||||
|
{
|
||||||
|
// Yes, error out...
|
||||||
|
_pdfioFileError(pdf, "Recursive xref table.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No, save it...
|
||||||
|
if (i >= (sizeof(xrefs) / sizeof(xrefs[0])))
|
||||||
|
{
|
||||||
|
// Too many xref tables...
|
||||||
|
_pdfioFileError(pdf, "Too many xref tables.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
xrefs[num_xrefs ++] = xref_offset = new_offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once we have all of the xref tables loaded, get the important objects and
|
// Once we have all of the xref tables loaded, get the important objects and
|
||||||
@@ -2529,7 +2562,7 @@ repair_xref(
|
|||||||
pdf->root_obj = NULL;
|
pdf->root_obj = NULL;
|
||||||
pdf->info_obj = NULL;
|
pdf->info_obj = NULL;
|
||||||
pdf->pages_obj = NULL;
|
pdf->pages_obj = NULL;
|
||||||
pdf->encrypt_obj = NULL;
|
pdf->encrypt_dict = NULL;
|
||||||
|
|
||||||
// Read from the beginning of the file, looking for objects...
|
// Read from the beginning of the file, looking for objects...
|
||||||
if ((line_offset = _pdfioFileSeek(pdf, 0, SEEK_SET)) < 0)
|
if ((line_offset = _pdfioFileSeek(pdf, 0, SEEK_SET)) < 0)
|
||||||
@@ -2588,25 +2621,32 @@ repair_xref(
|
|||||||
|
|
||||||
_pdfioTokenFlush(&tb);
|
_pdfioTokenFlush(&tb);
|
||||||
|
|
||||||
if (type && !strcmp(line, "stream"))
|
if (!strcmp(line, "stream"))
|
||||||
{
|
{
|
||||||
// Possible object or XRef stream...
|
// Possible object or XRef stream...
|
||||||
obj->stream_offset = _pdfioFileTell(pdf);
|
obj->stream_offset = _pdfioFileTell(pdf);
|
||||||
|
|
||||||
if (!strcmp(type, "ObjStm") && num_sobjs < (sizeof(sobjs) / sizeof(sobjs[0])))
|
if (type && !strcmp(type, "ObjStm") && num_sobjs < (sizeof(sobjs) / sizeof(sobjs[0])))
|
||||||
{
|
{
|
||||||
PDFIO_DEBUG("repair_xref: Object stream...\n");
|
PDFIO_DEBUG("repair_xref: Object stream...\n");
|
||||||
sobjs[num_sobjs] = obj;
|
sobjs[num_sobjs] = obj;
|
||||||
num_sobjs ++;
|
num_sobjs ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(type, "XRef") && !pdf->trailer_dict)
|
if (type && !strcmp(type, "XRef") && !pdf->trailer_dict)
|
||||||
{
|
{
|
||||||
// Save the trailer dictionary...
|
// Save the trailer dictionary...
|
||||||
|
pdfio_obj_t *encrypt_obj;
|
||||||
|
// Encryption object
|
||||||
|
|
||||||
PDFIO_DEBUG("repair_xref: XRef stream...\n");
|
PDFIO_DEBUG("repair_xref: XRef stream...\n");
|
||||||
pdf->trailer_dict = pdfioObjGetDict(obj);
|
pdf->trailer_dict = pdfioObjGetDict(obj);
|
||||||
pdf->encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt");
|
|
||||||
pdf->id_array = pdfioDictGetArray(pdf->trailer_dict, "ID");
|
pdf->id_array = pdfioDictGetArray(pdf->trailer_dict, "ID");
|
||||||
|
|
||||||
|
if ((encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt")) != NULL)
|
||||||
|
pdf->encrypt_dict = pdfioObjGetDict(encrypt_obj);
|
||||||
|
else
|
||||||
|
pdf->encrypt_dict = pdfioDictGetDict(pdf->trailer_dict, "Encrypt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (type && !strcmp(line, "endobj"))
|
else if (type && !strcmp(line, "endobj"))
|
||||||
@@ -2660,11 +2700,17 @@ repair_xref(
|
|||||||
{
|
{
|
||||||
// Save the trailer dictionary and grab the root (catalog) and info
|
// Save the trailer dictionary and grab the root (catalog) and info
|
||||||
// objects...
|
// objects...
|
||||||
|
pdfio_obj_t *encrypt_obj; // Encryption object
|
||||||
|
|
||||||
PDFIO_DEBUG("repair_xref: Using this trailer dictionary.\n");
|
PDFIO_DEBUG("repair_xref: Using this trailer dictionary.\n");
|
||||||
|
|
||||||
pdf->trailer_dict = trailer.value.dict;
|
pdf->trailer_dict = trailer.value.dict;
|
||||||
pdf->encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt");
|
|
||||||
pdf->id_array = pdfioDictGetArray(pdf->trailer_dict, "ID");
|
pdf->id_array = pdfioDictGetArray(pdf->trailer_dict, "ID");
|
||||||
|
|
||||||
|
if ((encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt")) != NULL)
|
||||||
|
pdf->encrypt_dict = pdfioObjGetDict(encrypt_obj);
|
||||||
|
else
|
||||||
|
pdf->encrypt_dict = pdfioDictGetDict(pdf->trailer_dict, "Encrypt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2678,7 +2724,7 @@ repair_xref(
|
|||||||
pdf->trailer_dict = backup_trailer;
|
pdf->trailer_dict = backup_trailer;
|
||||||
|
|
||||||
// If the trailer contains an Encrypt key, try unlocking the file...
|
// If the trailer contains an Encrypt key, try unlocking the file...
|
||||||
if (pdf->encrypt_obj && !_pdfioCryptoUnlock(pdf, password_cb, password_data))
|
if (pdf->encrypt_dict && !_pdfioCryptoUnlock(pdf, password_cb, password_data))
|
||||||
return (false);
|
return (false);
|
||||||
|
|
||||||
// Load any stream objects...
|
// Load any stream objects...
|
||||||
|
|||||||
320
pdfio-lzw.c
Normal file
320
pdfio-lzw.c
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
//
|
||||||
|
// LZW decoding functions for PDFio.
|
||||||
|
//
|
||||||
|
// This code is used to support (legacy) PDF object streams using the LZWDecode
|
||||||
|
// filter as well as when embedding (legacy) GIF images. None of this is public
|
||||||
|
// API and we only support reading (decoding) since FlateDecode is superior in
|
||||||
|
// every way.
|
||||||
|
//
|
||||||
|
// Copyright © 2026 by Michael R Sweet.
|
||||||
|
//
|
||||||
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
|
// information.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "pdfio-private.h"
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Local functions...
|
||||||
|
//
|
||||||
|
|
||||||
|
static void lzw_clear(_pdfio_lzw_t *lzw);
|
||||||
|
static int lzw_get_code(_pdfio_lzw_t *lzw);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfioLZWCreate()' - Create a LZW decompressor.
|
||||||
|
//
|
||||||
|
|
||||||
|
_pdfio_lzw_t * // O - LZW state
|
||||||
|
_pdfioLZWCreate(int code_size, // I - Data code size in bits (typically 8 for PDF, 2-8 for GIF)
|
||||||
|
int early) // I - Number of early codes
|
||||||
|
{
|
||||||
|
_pdfio_lzw_t *lzw; // LZW state
|
||||||
|
|
||||||
|
|
||||||
|
if ((lzw = (_pdfio_lzw_t *)calloc(1, sizeof(_pdfio_lzw_t))) != NULL)
|
||||||
|
{
|
||||||
|
lzw->def_code_size = code_size + 1;
|
||||||
|
lzw->clear_code = (short)(1 << code_size);
|
||||||
|
lzw->eod_code = lzw->clear_code + 1;
|
||||||
|
lzw->early = early;
|
||||||
|
|
||||||
|
lzw_clear(lzw);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (lzw);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfioLZWDelete()' - Delete a LZW decompressor.
|
||||||
|
//
|
||||||
|
|
||||||
|
void
|
||||||
|
_pdfioLZWDelete(_pdfio_lzw_t *lzw) // I - LZW state
|
||||||
|
{
|
||||||
|
free(lzw);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfioLZWInflate()' - Decompress pending input data.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` on error
|
||||||
|
_pdfioLZWInflate(_pdfio_lzw_t *lzw) // I - LZW state
|
||||||
|
{
|
||||||
|
int cur_code, // Current code
|
||||||
|
in_code; // Input code
|
||||||
|
|
||||||
|
|
||||||
|
// Stop if we already saw the "end of data" code...
|
||||||
|
if (lzw->saw_eod)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: EOD, returning false.\n");
|
||||||
|
lzw->error = "End of data.";
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy pending compressed data to the output buffer...
|
||||||
|
while (lzw->stptr > lzw->stack && lzw->avail_out > 0)
|
||||||
|
{
|
||||||
|
*(lzw->next_out++) = *(--lzw->stptr);
|
||||||
|
lzw->avail_out --;
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: Unrolled value %d, stptr=%p(%ld), avail_out=%u\n", *(lzw->stptr), (void *)lzw->stptr, lzw->stptr - lzw->stack, (unsigned)lzw->avail_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop as long as we have room in the output buffer and data in the input
|
||||||
|
// buffer...
|
||||||
|
while (lzw->avail_out > 0)
|
||||||
|
{
|
||||||
|
if ((in_code = lzw_get_code(lzw)) < 0)
|
||||||
|
{
|
||||||
|
// Out of data, stop now...
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: Out of data.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (in_code == lzw->clear_code)
|
||||||
|
{
|
||||||
|
// Clear the compression tables and reset...
|
||||||
|
lzw_clear(lzw);
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: Clear.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (in_code == lzw->eod_code)
|
||||||
|
{
|
||||||
|
// End of data...
|
||||||
|
lzw->saw_eod = true;
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: EOD.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get this far we have something to write to the output buffer and/or
|
||||||
|
// stack...
|
||||||
|
if (lzw->first_code == 0xffff)
|
||||||
|
{
|
||||||
|
// First code...
|
||||||
|
lzw->first_code = lzw->old_code = in_code;
|
||||||
|
*(lzw->next_out++) = in_code;
|
||||||
|
lzw->avail_out --;
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: first_code=%d.\n", in_code);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: in_code=%d, old_code=%d.\n", in_code, lzw->old_code);
|
||||||
|
|
||||||
|
cur_code = in_code;
|
||||||
|
|
||||||
|
if (cur_code >= lzw->next_code)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: New cur_code=%d, next_code=%d\n", cur_code, lzw->next_code);
|
||||||
|
*(lzw->stptr++) = lzw->first_code;
|
||||||
|
cur_code = lzw->old_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cur_code >= lzw->clear_code)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: cur_code=%d (%d,%d)\n", cur_code, lzw->table[cur_code].prefix_code, lzw->table[cur_code].suffix);
|
||||||
|
|
||||||
|
// Protect against overflow/loops...
|
||||||
|
if (lzw->stptr >= (lzw->stack + sizeof(lzw->stack) / sizeof(lzw->stack[0])))
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: Stack overflow, returning false.\n");
|
||||||
|
lzw->error = "Output overflow.";
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add this character to the output stack and move to the next character
|
||||||
|
// in the sequence...
|
||||||
|
*(lzw->stptr++) = lzw->table[cur_code].suffix;
|
||||||
|
|
||||||
|
if (cur_code == lzw->table[cur_code].prefix_code)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: Table loop on code %d, returning false.\n", cur_code);
|
||||||
|
lzw->error = "Table loop detected.";
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_code = lzw->table[cur_code].prefix_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lzw->stptr >= (lzw->stack + sizeof(lzw->stack) / sizeof(lzw->stack[0])))
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: Stack overflow, returning false.\n");
|
||||||
|
lzw->error = "Output overflow.";
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
*(lzw->stptr++) = lzw->first_code = lzw->table[cur_code].suffix;
|
||||||
|
|
||||||
|
if ((cur_code = lzw->next_code) < 4096)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: Adding code %d (%d,%d), next_size_code=%d\n", cur_code, lzw->old_code, lzw->first_code, lzw->next_size_code);
|
||||||
|
|
||||||
|
lzw->table[cur_code].prefix_code = lzw->old_code;
|
||||||
|
lzw->table[cur_code].suffix = lzw->first_code;
|
||||||
|
lzw->next_code ++;
|
||||||
|
|
||||||
|
if (lzw->next_code >= lzw->next_size_code && lzw->cur_code_size < 12)
|
||||||
|
{
|
||||||
|
lzw->cur_code_size ++;
|
||||||
|
lzw->next_size_code = (1 << lzw->cur_code_size) - lzw->early;
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: Increased code size to %u, next_size_code=%u\n", lzw->cur_code_size, lzw->next_size_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lzw->old_code = (uint16_t)in_code;
|
||||||
|
|
||||||
|
while (lzw->stptr > lzw->stack && lzw->avail_out > 0)
|
||||||
|
{
|
||||||
|
*(lzw->next_out++) = *(--lzw->stptr);
|
||||||
|
lzw->avail_out --;
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: Unrolled value %d, stptr=%p(%ld), avail_out=%u\n", *(lzw->stptr), (void *)lzw->stptr, lzw->stptr - lzw->stack, (unsigned)lzw->avail_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfioLZWInflate: Returning true, avail_in=%u, avail_out=%u.\n", (unsigned)lzw->avail_in, (unsigned)lzw->avail_out);
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'lzw_clear()' - Clear the compression table.
|
||||||
|
//
|
||||||
|
|
||||||
|
static void
|
||||||
|
lzw_clear(_pdfio_lzw_t *lzw) // I - LZW state
|
||||||
|
{
|
||||||
|
uint16_t i; // Looping var
|
||||||
|
|
||||||
|
|
||||||
|
lzw->cur_code_size = lzw->def_code_size;
|
||||||
|
lzw->next_code = lzw->clear_code + 2;
|
||||||
|
lzw->next_size_code = (1 << lzw->cur_code_size) - lzw->early;
|
||||||
|
lzw->first_code = 0xffff;
|
||||||
|
lzw->old_code = 0xffff;
|
||||||
|
|
||||||
|
memset(lzw->table, 0, sizeof(lzw->table));
|
||||||
|
|
||||||
|
for (i = 0; i < lzw->clear_code; i ++)
|
||||||
|
lzw->table[i].suffix = i;
|
||||||
|
|
||||||
|
lzw->stptr = lzw->stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'lzw_get_code()' - Get a code from the input buffer.
|
||||||
|
//
|
||||||
|
|
||||||
|
static int // O - Code or -1 if there is not enough data available
|
||||||
|
lzw_get_code(_pdfio_lzw_t *lzw) // I - LZW state
|
||||||
|
{
|
||||||
|
uint16_t code, // Code
|
||||||
|
in_bit; // Bit offset in buffer
|
||||||
|
uint8_t bits, // Bits in current byte
|
||||||
|
boff, // Bit offset in current byte
|
||||||
|
byte, // Current byte
|
||||||
|
remaining; // Remaining bits for code
|
||||||
|
static uint8_t mask[8] = // Value mask
|
||||||
|
{
|
||||||
|
0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Fill input bytes as needed...
|
||||||
|
if ((lzw->in_bit + lzw->cur_code_size) > lzw->in_bits)
|
||||||
|
{
|
||||||
|
uint16_t in_used = lzw->in_bits / 8,
|
||||||
|
// Number of input bytes
|
||||||
|
in_offset = lzw->in_bit / 8,
|
||||||
|
// Offset to current input
|
||||||
|
in_add; // Number of bytes to "read"
|
||||||
|
|
||||||
|
|
||||||
|
if (lzw->avail_in == 0)
|
||||||
|
{
|
||||||
|
// No more data
|
||||||
|
PDFIO_DEBUG("lzw_get_code: No data, returning -1.\n");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_offset > 0)
|
||||||
|
{
|
||||||
|
// Make room in the input buffer
|
||||||
|
memmove(lzw->in_bytes, lzw->in_bytes + in_offset, in_used - in_offset);
|
||||||
|
in_used -= in_offset;
|
||||||
|
lzw->in_bit &= 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((in_add = sizeof(lzw->in_bytes) - in_used) > lzw->avail_in)
|
||||||
|
in_add = lzw->avail_in;
|
||||||
|
|
||||||
|
memcpy(lzw->in_bytes + in_used, lzw->next_in, in_add);
|
||||||
|
lzw->next_in += in_add;
|
||||||
|
lzw->avail_in -= in_add;
|
||||||
|
lzw->in_bits = 8 * (in_used + in_add);
|
||||||
|
|
||||||
|
if ((lzw->in_bit + lzw->cur_code_size) > lzw->in_bits)
|
||||||
|
{
|
||||||
|
// Not enough data
|
||||||
|
PDFIO_DEBUG("lzw_get_code: Not enough data, returning -1.\n");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("lzw_get_code: in_bit=%u, in_bits=%u, in_bytes=<...%02X%02X%02X...>, cur_code_size=%u\n", lzw->in_bit, lzw->in_bits, lzw->in_bytes[lzw->in_bit / 8], lzw->in_bytes[lzw->in_bit / 8 + 1], lzw->in_bytes[lzw->in_bit / 8 + 2], lzw->cur_code_size);
|
||||||
|
|
||||||
|
// Now extract the code from the buffer...
|
||||||
|
for (code = 0, in_bit = lzw->in_bit, remaining = lzw->cur_code_size; remaining > 0; in_bit += bits, remaining -= bits)
|
||||||
|
{
|
||||||
|
// See how many bits we can extract from the current byte...
|
||||||
|
boff = (in_bit & 7);
|
||||||
|
byte = lzw->in_bytes[in_bit / 8];
|
||||||
|
bits = 8 - boff;
|
||||||
|
if (bits > remaining)
|
||||||
|
bits = remaining;
|
||||||
|
|
||||||
|
// Get those bits
|
||||||
|
if (bits == 8) // Full byte from buffer
|
||||||
|
code = (code << 8) | byte;
|
||||||
|
else // Partial byte from buffer
|
||||||
|
code = (code << bits) | ((byte >> (8 - bits - boff)) & mask[bits]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the updated position in the input buffer and return the code...
|
||||||
|
lzw->in_bit = in_bit;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (code >= 0x20 && code < 0x7f)
|
||||||
|
PDFIO_DEBUG("lzw_get_code: Returning %u('%c').\n", code, code);
|
||||||
|
else
|
||||||
|
PDFIO_DEBUG("lzw_get_code: Returning %u.\n", code);
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
|
return ((int)code);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// PDF object functions for PDFio.
|
// PDF object functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2025 by Michael R Sweet.
|
// Copyright © 2021-2026 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.
|
||||||
@@ -69,7 +69,7 @@ pdfioObjCopy(pdfio_file_t *pdf, // I - PDF file
|
|||||||
ssize_t bytes; // Bytes read
|
ssize_t bytes; // Bytes read
|
||||||
|
|
||||||
|
|
||||||
PDFIO_DEBUG("pdfioObjCopy(pdf=%p, srcobj=%p(%p))\n", (void *)pdf, (void *)srcobj, srcobj ? (void *)srcobj->pdf : NULL);
|
PDFIO_DEBUG("pdfioObjCopy(pdf=%p, srcobj=%p(%u,%p))\n", (void *)pdf, (void *)srcobj, srcobj ? (unsigned)srcobj->number : 0, srcobj ? (void *)srcobj->pdf : NULL);
|
||||||
|
|
||||||
// Range check input
|
// Range check input
|
||||||
if (!pdf || !srcobj)
|
if (!pdf || !srcobj)
|
||||||
@@ -77,7 +77,10 @@ pdfioObjCopy(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
// Load the object value if needed...
|
// Load the object value if needed...
|
||||||
if (srcobj->value.type == PDFIO_VALTYPE_NONE)
|
if (srcobj->value.type == PDFIO_VALTYPE_NONE)
|
||||||
_pdfioObjLoad(srcobj);
|
{
|
||||||
|
if (!_pdfioObjLoad(srcobj))
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// See if we have already mapped this object...
|
// See if we have already mapped this object...
|
||||||
if ((dstobj = _pdfioFileFindMappedObj(pdf, srcobj->pdf, srcobj->number)) != NULL)
|
if ((dstobj = _pdfioFileFindMappedObj(pdf, srcobj->pdf, srcobj->number)) != NULL)
|
||||||
@@ -544,6 +547,8 @@ pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object
|
|||||||
pdfio_stream_t *st; // Stream
|
pdfio_stream_t *st; // Stream
|
||||||
|
|
||||||
|
|
||||||
|
PDFIO_DEBUG("pdfioObjOpenStream(obj=%p(%lu), decode=%s)\n", (void *)obj, obj ? (unsigned long)obj->number : 0, decode ? "true" : "false");
|
||||||
|
|
||||||
// Range check input...
|
// Range check input...
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@@ -563,7 +568,10 @@ pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object
|
|||||||
|
|
||||||
// No stream if there is no dict or offset to a stream...
|
// No stream if there is no dict or offset to a stream...
|
||||||
if (obj->value.type != PDFIO_VALTYPE_DICT || !obj->stream_offset)
|
if (obj->value.type != PDFIO_VALTYPE_DICT || !obj->stream_offset)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("pdfioObjOpenStream: value.type=%d, stream_offset=%ld\n", obj->value.type, (long)obj->stream_offset);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// Open the stream...
|
// Open the stream...
|
||||||
if ((st = _pdfioStreamOpen(obj, decode)) != NULL)
|
if ((st = _pdfioStreamOpen(obj, decode)) != NULL)
|
||||||
|
|||||||
332
pdfio-page.c
332
pdfio-page.c
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// PDF page functions for PDFio.
|
// PDF page functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2022 by Michael R Sweet.
|
// Copyright © 2021-2026 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.
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
static _pdfio_value_t *get_contents(pdfio_obj_t *page);
|
static _pdfio_value_t *get_contents(pdfio_obj_t *page);
|
||||||
|
static _pdfio_value_t *get_page_value(pdfio_obj_t *page, const char *key);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -52,6 +53,158 @@ pdfioPageCopy(pdfio_file_t *pdf, // I - PDF file
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioPageGetArray()' - Get an array value from the page dictionary.
|
||||||
|
//
|
||||||
|
// This function looks up an array value in the page dictionary, either in the
|
||||||
|
// specified object or one of its parents.
|
||||||
|
//
|
||||||
|
// @since PDFio 1.7@
|
||||||
|
//
|
||||||
|
|
||||||
|
pdfio_array_t * // O - Array or `NULL` if none
|
||||||
|
pdfioPageGetArray(pdfio_obj_t *page, // I - Page object
|
||||||
|
const char *key) // I - Dictionary key
|
||||||
|
{
|
||||||
|
_pdfio_value_t *v = get_page_value(page, key);
|
||||||
|
// Dictionary value
|
||||||
|
|
||||||
|
|
||||||
|
if (v && v->type == PDFIO_VALTYPE_ARRAY)
|
||||||
|
return (v->value.array);
|
||||||
|
else
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioPageGetBinary()' - Get a binary value from the page dictionary.
|
||||||
|
//
|
||||||
|
// This function looks up a binary value in the page dictionary, either in the
|
||||||
|
// specified object or one of its parents.
|
||||||
|
//
|
||||||
|
// @since PDFio 1.7@
|
||||||
|
//
|
||||||
|
|
||||||
|
unsigned char * // O - Pointer to binary data or `NULL` if none
|
||||||
|
pdfioPageGetBinary(pdfio_obj_t *page, // I - Page object
|
||||||
|
const char *key, // I - Dictionary key
|
||||||
|
size_t *length) // O - Length of value
|
||||||
|
{
|
||||||
|
_pdfio_value_t *v = get_page_value(page, key);
|
||||||
|
// Dictionary value
|
||||||
|
|
||||||
|
|
||||||
|
if (v && v->type == PDFIO_VALTYPE_BINARY)
|
||||||
|
{
|
||||||
|
if (length)
|
||||||
|
*length = v->value.binary.datalen;
|
||||||
|
|
||||||
|
return (v->value.binary.data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioPageGetBoolean()' - Get a boolean value from the page dictionary.
|
||||||
|
//
|
||||||
|
// This function looks up a boolean value in the page dictionary, either in the
|
||||||
|
// specified object or one of its parents.
|
||||||
|
//
|
||||||
|
// @since PDFio 1.7@
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - Boolean value or `false` if none
|
||||||
|
pdfioPageGetBoolean(pdfio_obj_t *page, // I - Page object
|
||||||
|
const char *key) // I - Dictionary key
|
||||||
|
{
|
||||||
|
_pdfio_value_t *v = get_page_value(page, key);
|
||||||
|
// Dictionary value
|
||||||
|
|
||||||
|
|
||||||
|
if (v && v->type == PDFIO_VALTYPE_ARRAY)
|
||||||
|
return (v->value.boolean);
|
||||||
|
else
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioPageGetDate()' - Get a date value from the page dictionary.
|
||||||
|
//
|
||||||
|
// This function looks up a date value in the page dictionary, either in the
|
||||||
|
// specified object or one of its parents.
|
||||||
|
//
|
||||||
|
// @since PDFio 1.7@
|
||||||
|
//
|
||||||
|
|
||||||
|
time_t // O - Date/time or `0` if none
|
||||||
|
pdfioPageGetDate(pdfio_obj_t *page, // I - Page object
|
||||||
|
const char *key) // I - Dictionary key
|
||||||
|
{
|
||||||
|
_pdfio_value_t *v = get_page_value(page, key);
|
||||||
|
// Dictionary value
|
||||||
|
|
||||||
|
|
||||||
|
if (v && v->type == PDFIO_VALTYPE_DATE)
|
||||||
|
return (v->value.date);
|
||||||
|
else
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioPageGetDict()' - Get a dictionary value from the page dictionary.
|
||||||
|
//
|
||||||
|
// This function looks up a dictionary value in the page dictionary, either in
|
||||||
|
// the specified object or one of its parents.
|
||||||
|
//
|
||||||
|
// @since PDFio 1.7@
|
||||||
|
//
|
||||||
|
|
||||||
|
pdfio_dict_t * // O - Dictionary or `NULL` if none
|
||||||
|
pdfioPageGetDict(pdfio_obj_t *page, // I - Page object
|
||||||
|
const char *key) // I - Dictionary key
|
||||||
|
{
|
||||||
|
_pdfio_value_t *v = get_page_value(page, key);
|
||||||
|
// Dictionary value
|
||||||
|
|
||||||
|
|
||||||
|
if (v && v->type == PDFIO_VALTYPE_DICT)
|
||||||
|
return (v->value.dict);
|
||||||
|
else
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioPageGetName()' - Get a name value from the page dictionary.
|
||||||
|
//
|
||||||
|
// This function looks up a name value in the page dictionary, either in the
|
||||||
|
// specified object or one of its parents.
|
||||||
|
//
|
||||||
|
// @since PDFio 1.7@
|
||||||
|
//
|
||||||
|
|
||||||
|
const char * // O - Name string or `NULL` if none
|
||||||
|
pdfioPageGetName(pdfio_obj_t *page, // I - Page object
|
||||||
|
const char *key) // I - Dictionary key
|
||||||
|
{
|
||||||
|
_pdfio_value_t *v = get_page_value(page, key);
|
||||||
|
// Dictionary value
|
||||||
|
|
||||||
|
|
||||||
|
if (v && v->type == PDFIO_VALTYPE_NAME)
|
||||||
|
return (v->value.name);
|
||||||
|
else
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'pdfioPageGetNumStreams()' - Get the number of content streams for a page object.
|
// 'pdfioPageGetNumStreams()' - Get the number of content streams for a page object.
|
||||||
//
|
//
|
||||||
@@ -73,6 +226,112 @@ pdfioPageGetNumStreams(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioPageGetNumber()' - Get a number value from the page dictionary.
|
||||||
|
//
|
||||||
|
// This function looks up a number value in the page dictionary, either in the
|
||||||
|
// specified object or one of its parents.
|
||||||
|
//
|
||||||
|
// @since PDFio 1.7@
|
||||||
|
//
|
||||||
|
|
||||||
|
double // O - Number value or `0.0` if none
|
||||||
|
pdfioPageGetNumber(pdfio_obj_t *page, // I - Page object
|
||||||
|
const char *key) // I - Dictionary key
|
||||||
|
{
|
||||||
|
_pdfio_value_t *v = get_page_value(page, key);
|
||||||
|
// Dictionary value
|
||||||
|
|
||||||
|
|
||||||
|
if (v && v->type == PDFIO_VALTYPE_NUMBER)
|
||||||
|
return (v->value.number);
|
||||||
|
else
|
||||||
|
return (0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioPageGetObj()' - Get an indirect object value from the page dictionary.
|
||||||
|
//
|
||||||
|
// This function looks up an indirect object value in the page dictionary,
|
||||||
|
// either in the specified object or one of its parents.
|
||||||
|
//
|
||||||
|
// @since PDFio 1.7@
|
||||||
|
//
|
||||||
|
|
||||||
|
pdfio_obj_t * // O - Object or `NULL` if none
|
||||||
|
pdfioPageGetObj(pdfio_obj_t *page, // I - Page object
|
||||||
|
const char *key) // I - Dictionary key
|
||||||
|
{
|
||||||
|
_pdfio_value_t *v = get_page_value(page, key);
|
||||||
|
// Dictionary value
|
||||||
|
|
||||||
|
|
||||||
|
if (v && v->type == PDFIO_VALTYPE_INDIRECT)
|
||||||
|
return (pdfioFileFindObj(page->pdf, v->value.indirect.number));
|
||||||
|
else
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioPageGetRect()' - Get a rectangle value from the page dictionary.
|
||||||
|
//
|
||||||
|
// This function looks up a rectangle value in the page dictionary, either in
|
||||||
|
// the specified object or one of its parents.
|
||||||
|
//
|
||||||
|
// @since PDFio 1.7@
|
||||||
|
//
|
||||||
|
|
||||||
|
pdfio_rect_t * // O - Rectangle or `NULL` if none
|
||||||
|
pdfioPageGetRect(pdfio_obj_t *page, // I - Page object
|
||||||
|
const char *key, // I - Dictionary key
|
||||||
|
pdfio_rect_t *rect) // O - Rectangle
|
||||||
|
{
|
||||||
|
_pdfio_value_t *v = get_page_value(page, key);
|
||||||
|
// Dictionary value
|
||||||
|
|
||||||
|
|
||||||
|
if (v && v->type == PDFIO_VALTYPE_ARRAY && pdfioArrayGetSize(v->value.array) == 4)
|
||||||
|
{
|
||||||
|
rect->x1 = pdfioArrayGetNumber(v->value.array, 0);
|
||||||
|
rect->y1 = pdfioArrayGetNumber(v->value.array, 1);
|
||||||
|
rect->x2 = pdfioArrayGetNumber(v->value.array, 2);
|
||||||
|
rect->y2 = pdfioArrayGetNumber(v->value.array, 3);
|
||||||
|
|
||||||
|
return (rect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioPageGetString()' - Get a string value from the page dictionary.
|
||||||
|
//
|
||||||
|
// This function looks up a string value in the page dictionary, either in the
|
||||||
|
// specified object or one of its parents.
|
||||||
|
//
|
||||||
|
// @since PDFio 1.7@
|
||||||
|
//
|
||||||
|
|
||||||
|
const char * // O - String value or `NULL` if none
|
||||||
|
pdfioPageGetString(pdfio_obj_t *page, // I - Page object
|
||||||
|
const char *key) // I - Dictionary key
|
||||||
|
{
|
||||||
|
_pdfio_value_t *v = get_page_value(page, key);
|
||||||
|
// Dictionary value
|
||||||
|
|
||||||
|
|
||||||
|
if (v && v->type == PDFIO_VALTYPE_STRING)
|
||||||
|
return (v->value.string);
|
||||||
|
else
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'pdfioPageOpenStream()' - Open a content stream for a page.
|
// 'pdfioPageOpenStream()' - Open a content stream for a page.
|
||||||
//
|
//
|
||||||
@@ -87,14 +346,28 @@ pdfioPageOpenStream(
|
|||||||
// Contents value
|
// Contents value
|
||||||
|
|
||||||
|
|
||||||
|
PDFIO_DEBUG("pdfioPageOpenStream(page=%p(%lu), n=%lu, decode=%s)\n", (void *)page, page ? (unsigned long)page->number : 0, (unsigned long)n, decode ? "true" : "false");
|
||||||
|
|
||||||
if (!contents)
|
if (!contents)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("pdfioPageOpenStream: No contents.\n");
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
else if (contents->type == PDFIO_VALTYPE_ARRAY && n < pdfioArrayGetSize(contents->value.array))
|
else if (contents->type == PDFIO_VALTYPE_ARRAY && n < pdfioArrayGetSize(contents->value.array))
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("pdfioPageOpenStream: Contents is array, opening numbered content stream.\n");
|
||||||
return (pdfioObjOpenStream(pdfioArrayGetObj(contents->value.array, n), decode));
|
return (pdfioObjOpenStream(pdfioArrayGetObj(contents->value.array, n), decode));
|
||||||
|
}
|
||||||
else if (n)
|
else if (n)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("pdfioPageOpenStream: Numbered stream does not exist.\n");
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("pdfioPageOpenStream: Opening single content stream %d.\n", (int)contents->value.indirect.number);
|
||||||
return (pdfioObjOpenStream(pdfioFileFindObj(page->pdf, contents->value.indirect.number), decode));
|
return (pdfioObjOpenStream(pdfioFileFindObj(page->pdf, contents->value.indirect.number), decode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -105,6 +378,10 @@ pdfioPageOpenStream(
|
|||||||
static _pdfio_value_t * // O - Value or NULL on error
|
static _pdfio_value_t * // O - Value or NULL on error
|
||||||
get_contents(pdfio_obj_t *page) // I - Page object
|
get_contents(pdfio_obj_t *page) // I - Page object
|
||||||
{
|
{
|
||||||
|
_pdfio_value_t *contents; // Contents value
|
||||||
|
pdfio_obj_t *obj; // Contents object
|
||||||
|
|
||||||
|
|
||||||
// Range check input...
|
// Range check input...
|
||||||
if (!page)
|
if (!page)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@@ -119,5 +396,56 @@ get_contents(pdfio_obj_t *page) // I - Page object
|
|||||||
if (page->value.type != PDFIO_VALTYPE_DICT)
|
if (page->value.type != PDFIO_VALTYPE_DICT)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
return (_pdfioDictGetValue(page->value.value.dict, "Contents"));
|
contents = _pdfioDictGetValue(page->value.value.dict, "Contents");
|
||||||
|
|
||||||
|
if (contents->type == PDFIO_VALTYPE_INDIRECT)
|
||||||
|
{
|
||||||
|
// See if the indirect object is a stream or an array of indirect object
|
||||||
|
// references...
|
||||||
|
if ((obj = pdfioFileFindObj(page->pdf, contents->value.indirect.number)) != NULL)
|
||||||
|
{
|
||||||
|
if (obj->value.type == PDFIO_VALTYPE_NONE)
|
||||||
|
{
|
||||||
|
if (!_pdfioObjLoad(obj))
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->value.type == PDFIO_VALTYPE_ARRAY)
|
||||||
|
contents = &(obj->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'get_page_value()' - Get a page dictionary value, including parents.
|
||||||
|
//
|
||||||
|
|
||||||
|
static _pdfio_value_t * // O - Dictionary value or `NULL` if none
|
||||||
|
get_page_value(pdfio_obj_t *page, // I - Page object
|
||||||
|
const char *key) // I - Dictionary key
|
||||||
|
{
|
||||||
|
_pdfio_value_t *v = NULL; // Dictionary value
|
||||||
|
|
||||||
|
|
||||||
|
while (page != NULL)
|
||||||
|
{
|
||||||
|
// Load the page object as needed...
|
||||||
|
if (page->value.type == PDFIO_VALTYPE_NONE && !_pdfioObjLoad(page))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// If there isn't a dictionary for the object, stop...
|
||||||
|
if (page->value.type != PDFIO_VALTYPE_DICT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Lookup the key...
|
||||||
|
if ((v = _pdfioDictGetValue(page->value.value.dict, key)) != NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
page = pdfioDictGetObj(page->value.value.dict, "Parent");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (v);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Private header file for PDFio.
|
// Private header file for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2025 by Michael R Sweet.
|
// Copyright © 2021-2026 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.
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
# define PDFIO_MAX_DEPTH 32 // Maximum nesting depth for values
|
# define PDFIO_MAX_DEPTH 32 // Maximum nesting depth for values
|
||||||
# define PDFIO_MAX_STRING 65536 // Maximum length of string
|
# define PDFIO_MAX_STRING 131072 // Maximum length of string
|
||||||
|
|
||||||
typedef void (*_pdfio_extfree_t)(void *);
|
typedef void (*_pdfio_extfree_t)(void *);
|
||||||
// Extension data free function
|
// Extension data free function
|
||||||
@@ -176,7 +176,7 @@ typedef struct _pdfio_value_s // Value structure
|
|||||||
typedef struct _pdfio_aes_s // AES encryption state
|
typedef struct _pdfio_aes_s // AES encryption state
|
||||||
{
|
{
|
||||||
size_t round_size; // Size of round key
|
size_t round_size; // Size of round key
|
||||||
uint8_t round_key[240], // Round key
|
uint8_t round_key[256], // Round key
|
||||||
iv[16]; // Initialization vector
|
iv[16]; // Initialization vector
|
||||||
} _pdfio_aes_t;
|
} _pdfio_aes_t;
|
||||||
|
|
||||||
@@ -211,6 +211,37 @@ typedef union _pdfio_crypto_ctx_u // Cryptographic contexts
|
|||||||
} _pdfio_crypto_ctx_t;
|
} _pdfio_crypto_ctx_t;
|
||||||
typedef size_t (*_pdfio_crypto_cb_t)(_pdfio_crypto_ctx_t *ctx, uint8_t *outbuffer, const uint8_t *inbuffer, size_t len);
|
typedef size_t (*_pdfio_crypto_cb_t)(_pdfio_crypto_ctx_t *ctx, uint8_t *outbuffer, const uint8_t *inbuffer, size_t len);
|
||||||
|
|
||||||
|
typedef struct _pdfio_lzws_s // LZW string table
|
||||||
|
{
|
||||||
|
uint16_t prefix_code, // Prefix code
|
||||||
|
suffix; // Suffix (character)
|
||||||
|
} _pdfio_lzws_t;
|
||||||
|
|
||||||
|
typedef struct _pdfio_lzw_s // LZW state
|
||||||
|
{
|
||||||
|
uint8_t *next_in; // Next input byte
|
||||||
|
size_t avail_in; // Available input bytes
|
||||||
|
uint8_t in_bytes[256]; // Current input bytes
|
||||||
|
uint16_t in_bit, // Current input bit
|
||||||
|
in_bits; // Total input bits
|
||||||
|
uint8_t *next_out; // Next output byte
|
||||||
|
size_t avail_out; // Available output bytes
|
||||||
|
uint8_t cur_code_size, // Current code size
|
||||||
|
def_code_size, // Initial/default code size
|
||||||
|
early; // Early code change offset
|
||||||
|
uint16_t clear_code, // Clear code
|
||||||
|
eod_code, // End code
|
||||||
|
next_code, // Next code to be used
|
||||||
|
next_size_code, // Code where we need to increase the code size
|
||||||
|
first_code, // First code in sequence
|
||||||
|
old_code, // Previous code in sequence
|
||||||
|
stack[8192], // Output stack
|
||||||
|
*stptr; // Current stack pointer
|
||||||
|
_pdfio_lzws_t table[4096]; // String table
|
||||||
|
bool saw_eod; // Saw end-of-data code?
|
||||||
|
const char *error; // Error, if any
|
||||||
|
} _pdfio_lzw_t;
|
||||||
|
|
||||||
struct _pdfio_array_s
|
struct _pdfio_array_s
|
||||||
{
|
{
|
||||||
pdfio_file_t *pdf; // PDF file
|
pdfio_file_t *pdf; // PDF file
|
||||||
@@ -283,7 +314,8 @@ struct _pdfio_file_s // PDF file structure
|
|||||||
pdfio_obj_t *root_obj; // Root object/dictionary
|
pdfio_obj_t *root_obj; // Root object/dictionary
|
||||||
pdfio_obj_t *info_obj; // Information object
|
pdfio_obj_t *info_obj; // Information object
|
||||||
pdfio_obj_t *pages_obj; // Root pages object
|
pdfio_obj_t *pages_obj; // Root pages object
|
||||||
pdfio_obj_t *encrypt_obj; // De/Encryption object/dictionary
|
pdfio_obj_t *encrypt_obj; // Encryption object (not used for reading)
|
||||||
|
pdfio_dict_t *encrypt_dict; // De/Encryption dictionary
|
||||||
pdfio_obj_t *cgats001_obj, // CGATS001 ICC profile object
|
pdfio_obj_t *cgats001_obj, // CGATS001 ICC profile object
|
||||||
*cp1252_obj, // CP1252 font encoding object
|
*cp1252_obj, // CP1252 font encoding object
|
||||||
*unicode_obj; // Unicode font encoding object
|
*unicode_obj; // Unicode font encoding object
|
||||||
@@ -340,12 +372,20 @@ struct _pdfio_stream_s // Stream
|
|||||||
char buffer[8192], // Read/write buffer
|
char buffer[8192], // Read/write buffer
|
||||||
*bufptr, // Current position in buffer
|
*bufptr, // Current position in buffer
|
||||||
*bufend; // End of buffer
|
*bufend; // End of buffer
|
||||||
|
size_t a85size; // Size of ASCII85Decode buffer
|
||||||
|
char *a85buffer, // ASCII85Decode buffer, if any
|
||||||
|
*a85bufptr, // Pointer into ASCII85Decode buffer
|
||||||
|
*a85bufend, // End of data in ASCII85Decode buffer
|
||||||
|
a85decode[4], // Current block of decoded characters
|
||||||
|
*a85decptr, // Pointer into decoded characters
|
||||||
|
*a85decend; // Last decoded character
|
||||||
z_stream flate; // Flate filter state
|
z_stream flate; // Flate filter state
|
||||||
|
_pdfio_lzw_t *lzw; // LZW filter state
|
||||||
_pdfio_predictor_t predictor; // Predictor function, if any
|
_pdfio_predictor_t predictor; // Predictor function, if any
|
||||||
size_t pbpixel, // Size of a pixel in bytes
|
size_t pbpixel, // Size of a pixel in bytes
|
||||||
pbsize, // Predictor buffer size, if any
|
pbsize, // Predictor buffer size, if any
|
||||||
cbsize; // Compressed data buffer size
|
cbsize; // Compressed data buffer size
|
||||||
unsigned char *cbuffer, // Compressed data buffer
|
uint8_t *cbuffer, // Compressed data buffer
|
||||||
*prbuffer, // Raw buffer (previous line), as needed
|
*prbuffer, // Raw buffer (previous line), as needed
|
||||||
*psbuffer; // PNG filter buffer, as needed
|
*psbuffer; // PNG filter buffer, as needed
|
||||||
_pdfio_crypto_cb_t crypto_cb; // Encryption/descryption callback, if any
|
_pdfio_crypto_cb_t crypto_cb; // Encryption/descryption callback, if any
|
||||||
@@ -412,6 +452,10 @@ extern off_t _pdfioFileSeek(pdfio_file_t *pdf, off_t offset, int whence) _PDFIO
|
|||||||
extern off_t _pdfioFileTell(pdfio_file_t *pdf) _PDFIO_INTERNAL;
|
extern off_t _pdfioFileTell(pdfio_file_t *pdf) _PDFIO_INTERNAL;
|
||||||
extern bool _pdfioFileWrite(pdfio_file_t *pdf, const void *buffer, size_t bytes) _PDFIO_INTERNAL;
|
extern bool _pdfioFileWrite(pdfio_file_t *pdf, const void *buffer, size_t bytes) _PDFIO_INTERNAL;
|
||||||
|
|
||||||
|
extern _pdfio_lzw_t *_pdfioLZWCreate(int def_code_size, int early) _PDFIO_INTERNAL;
|
||||||
|
extern void _pdfioLZWDelete(_pdfio_lzw_t *lzw) _PDFIO_INTERNAL;
|
||||||
|
extern bool _pdfioLZWInflate(_pdfio_lzw_t *lzw) _PDFIO_INTERNAL;
|
||||||
|
|
||||||
extern void _pdfioObjDelete(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
extern void _pdfioObjDelete(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||||
extern void *_pdfioObjGetExtension(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
extern void *_pdfioObjGetExtension(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||||
extern bool _pdfioObjLoad(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
extern bool _pdfioObjLoad(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||||
|
|||||||
525
pdfio-stream.c
525
pdfio-stream.c
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// PDF stream functions for PDFio.
|
// PDF stream functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2025 by Michael R Sweet.
|
// Copyright © 2021-2026 by Michael R Sweet.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
// Local functions...
|
// Local functions...
|
||||||
//
|
//
|
||||||
|
|
||||||
|
static ssize_t stream_get_bytes(pdfio_stream_t *st, void *buffer, size_t bytes);
|
||||||
|
static ssize_t stream_inflate(pdfio_stream_t *st, uint8_t *buffer, size_t bytes, bool exactly);
|
||||||
static unsigned char stream_paeth(unsigned char a, unsigned char b, unsigned char c);
|
static unsigned char stream_paeth(unsigned char a, unsigned char b, unsigned char c);
|
||||||
static ssize_t stream_read(pdfio_stream_t *st, char *buffer, size_t bytes);
|
static ssize_t stream_read(pdfio_stream_t *st, char *buffer, size_t bytes);
|
||||||
static bool stream_write(pdfio_stream_t *st, const void *buffer, size_t bytes);
|
static bool stream_write(pdfio_stream_t *st, const void *buffer, size_t bytes);
|
||||||
@@ -39,6 +41,8 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
|||||||
{
|
{
|
||||||
if (st->filter == PDFIO_FILTER_FLATE)
|
if (st->filter == PDFIO_FILTER_FLATE)
|
||||||
inflateEnd(&(st->flate));
|
inflateEnd(&(st->flate));
|
||||||
|
else if (st->filter == PDFIO_FILTER_LZW)
|
||||||
|
_pdfioLZWDelete(st->lzw);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -172,6 +176,7 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
|||||||
|
|
||||||
st->pdf->current_obj = NULL;
|
st->pdf->current_obj = NULL;
|
||||||
|
|
||||||
|
free(st->a85buffer);
|
||||||
free(st->cbuffer);
|
free(st->cbuffer);
|
||||||
free(st->prbuffer);
|
free(st->prbuffer);
|
||||||
free(st->psbuffer);
|
free(st->psbuffer);
|
||||||
@@ -479,10 +484,34 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
pdfio_array_t *fa = pdfioDictGetArray(dict, "Filter");
|
pdfio_array_t *fa = pdfioDictGetArray(dict, "Filter");
|
||||||
// Filter array
|
// Filter array
|
||||||
|
|
||||||
if (!filter && fa && pdfioArrayGetSize(fa) == 1)
|
if (!filter && fa)
|
||||||
{
|
{
|
||||||
// Support single-valued arrays...
|
const char *filter0 = pdfioArrayGetName(fa, 0);
|
||||||
filter = pdfioArrayGetName(fa, 0);
|
// First filter
|
||||||
|
|
||||||
|
if (pdfioArrayGetSize(fa) == 1)
|
||||||
|
{
|
||||||
|
// Support single-valued arrays...
|
||||||
|
filter = filter0;
|
||||||
|
}
|
||||||
|
else if (pdfioArrayGetSize(fa) == 2 && filter0 && !strcmp(filter0, "ASCII85Decode"))
|
||||||
|
{
|
||||||
|
// Support ASCII85Decode + something else
|
||||||
|
st->a85size = 5200; // Enough for 4k of decoded data
|
||||||
|
|
||||||
|
// Allocate the ASCII85Decode buffer...
|
||||||
|
if ((st->a85buffer = malloc(st->a85size)) == NULL)
|
||||||
|
{
|
||||||
|
_pdfioFileError(st->pdf, "Unable to allocate ASCII85Decode buffer.");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->a85bufptr = st->a85buffer;
|
||||||
|
st->a85bufend = st->a85buffer;
|
||||||
|
|
||||||
|
// Get the second filter...
|
||||||
|
filter = pdfioArrayGetName(fa, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filter)
|
if (!filter)
|
||||||
@@ -490,7 +519,6 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
// No single filter name, do we have a compound filter?
|
// No single filter name, do we have a compound filter?
|
||||||
if (fa)
|
if (fa)
|
||||||
{
|
{
|
||||||
// TODO: Implement compound filters...
|
|
||||||
_pdfioFileError(st->pdf, "Unsupported compound stream filter.");
|
_pdfioFileError(st->pdf, "Unsupported compound stream filter.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -498,9 +526,9 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
// No filter, read as-is...
|
// No filter, read as-is...
|
||||||
st->filter = PDFIO_FILTER_NONE;
|
st->filter = PDFIO_FILTER_NONE;
|
||||||
}
|
}
|
||||||
else if (!strcmp(filter, "FlateDecode"))
|
else if (!strcmp(filter, "FlateDecode") || !strcmp(filter, "LZWDecode"))
|
||||||
{
|
{
|
||||||
// Flate compression
|
// Flate or LZW compression
|
||||||
pdfio_dict_t *params = pdfioDictGetDict(dict, "DecodeParms");
|
pdfio_dict_t *params = pdfioDictGetDict(dict, "DecodeParms");
|
||||||
// Decoding parameters
|
// Decoding parameters
|
||||||
int bpc = (int)pdfioDictGetNumber(params, "BitsPerComponent");
|
int bpc = (int)pdfioDictGetNumber(params, "BitsPerComponent");
|
||||||
@@ -511,12 +539,11 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
// Number of columns
|
// Number of columns
|
||||||
int predictor = (int)pdfioDictGetNumber(params, "Predictor");
|
int predictor = (int)pdfioDictGetNumber(params, "Predictor");
|
||||||
// Predictory value, if any
|
// Predictory value, if any
|
||||||
int status; // ZLIB status
|
|
||||||
ssize_t rbytes; // Bytes read
|
ssize_t rbytes; // Bytes read
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioStreamOpen: FlateDecode - BitsPerComponent=%d, Colors=%d, Columns=%d, Predictor=%d\n", bpc, colors, columns, predictor);
|
PDFIO_DEBUG("_pdfioStreamOpen: %s - BitsPerComponent=%d, Colors=%d, Columns=%d, Predictor=%d\n", filter, bpc, colors, columns, predictor);
|
||||||
|
|
||||||
st->filter = PDFIO_FILTER_FLATE;
|
st->filter = !strcmp(filter, "FlateDecode") ? PDFIO_FILTER_FLATE : PDFIO_FILTER_LZW;
|
||||||
|
|
||||||
if (bpc == 0)
|
if (bpc == 0)
|
||||||
{
|
{
|
||||||
@@ -583,42 +610,57 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
st->cbsize = 4096;
|
st->cbsize = 4096;
|
||||||
if ((st->cbuffer = malloc(st->cbsize)) == NULL)
|
if ((st->cbuffer = malloc(st->cbsize)) == NULL)
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Flate compression buffer.", (unsigned long)st->cbsize);
|
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for FlateDecode decompression buffer.", (unsigned long)st->cbsize);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioStreamOpen: pos=%ld\n", (long)_pdfioFileTell(st->pdf));
|
PDFIO_DEBUG("_pdfioStreamOpen: pos=%ld\n", (long)_pdfioFileTell(st->pdf));
|
||||||
if (st->cbsize > st->remaining)
|
if ((rbytes = stream_get_bytes(st, st->cbuffer, st->cbsize)) <= 0)
|
||||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
|
||||||
else
|
|
||||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
|
||||||
|
|
||||||
if (rbytes <= 0)
|
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to read bytes for stream.");
|
_pdfioFileError(st->pdf, "Unable to read bytes for stream.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->crypto_cb)
|
if (st->filter == PDFIO_FILTER_FLATE)
|
||||||
rbytes = (ssize_t)(st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, (size_t)rbytes);
|
|
||||||
|
|
||||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
|
||||||
st->flate.avail_in = (uInt)rbytes;
|
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioStreamOpen: avail_in=%u, cbuffer=<%02X%02X%02X%02X%02X%02X%02X%02X...>\n", st->flate.avail_in, st->cbuffer[0], st->cbuffer[1], st->cbuffer[2], st->cbuffer[3], st->cbuffer[4], st->cbuffer[5], st->cbuffer[6], st->cbuffer[7]);
|
|
||||||
|
|
||||||
if ((status = inflateInit(&(st->flate))) != Z_OK)
|
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to start Flate filter: %s", zstrerror(status));
|
// Flate decompression...
|
||||||
goto error;
|
int status; // ZLIB status
|
||||||
}
|
|
||||||
|
|
||||||
st->remaining -= st->flate.avail_in;
|
st->flate.next_in = (Bytef *)st->cbuffer;
|
||||||
}
|
st->flate.avail_in = (uInt)rbytes;
|
||||||
else if (!strcmp(filter, "LZWDecode"))
|
|
||||||
{
|
PDFIO_DEBUG("_pdfioStreamOpen: avail_in=%u, cbuffer=<%02X%02X%02X%02X%02X%02X%02X%02X...>\n", st->flate.avail_in, st->cbuffer[0], st->cbuffer[1], st->cbuffer[2], st->cbuffer[3], st->cbuffer[4], st->cbuffer[5], st->cbuffer[6], st->cbuffer[7]);
|
||||||
// LZW compression
|
|
||||||
st->filter = PDFIO_FILTER_LZW;
|
if ((status = inflateInit(&(st->flate))) != Z_OK)
|
||||||
|
{
|
||||||
|
_pdfioFileError(st->pdf, "Unable to start FlateDecode filter: %s", zstrerror(status));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// LZW decompression...
|
||||||
|
int early = 1;
|
||||||
|
|
||||||
|
if (pdfioDictGetType(params, "EarlyChange") == PDFIO_VALTYPE_NUMBER)
|
||||||
|
{
|
||||||
|
early = (int)pdfioDictGetNumber(params, "EarlyChange");
|
||||||
|
if (early < 0 || early > 100)
|
||||||
|
{
|
||||||
|
_pdfioFileError(st->pdf, "Bad EarlyChange value %d for LZWDecode filter.", early);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((st->lzw = _pdfioLZWCreate(/*code_size*/8, early)) == NULL)
|
||||||
|
{
|
||||||
|
_pdfioFileError(st->pdf, "Unable to initialize LZWDecode filter: %s", strerror(errno));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->lzw->next_in = st->cbuffer;
|
||||||
|
st->lzw->avail_in = (size_t)rbytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -638,12 +680,13 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
// If we get here something went wrong...
|
// If we get here something went wrong...
|
||||||
error:
|
error:
|
||||||
|
|
||||||
|
free(st->a85buffer);
|
||||||
free(st->cbuffer);
|
free(st->cbuffer);
|
||||||
free(st->prbuffer);
|
free(st->prbuffer);
|
||||||
free(st->psbuffer);
|
free(st->psbuffer);
|
||||||
free(st);
|
free(st);
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1011,6 +1054,271 @@ pdfioStreamWrite(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'stream_get_bytes()' - Read and decrypt raw or ASCII85Decode-encoded data.
|
||||||
|
//
|
||||||
|
|
||||||
|
static ssize_t // O - Bytes read or `-1` on error
|
||||||
|
stream_get_bytes(
|
||||||
|
pdfio_stream_t *st, // I - Stream
|
||||||
|
void *buffer, // I - Buffer
|
||||||
|
size_t bytes) // I - Maximum number of bytes to read
|
||||||
|
{
|
||||||
|
ssize_t rbytes; // Bytes read
|
||||||
|
|
||||||
|
|
||||||
|
if (st->a85buffer)
|
||||||
|
{
|
||||||
|
// Decode through the ASCII85Decode buffer...
|
||||||
|
char *bufptr = (char *)buffer; // Pointer into read buffer
|
||||||
|
|
||||||
|
rbytes = 0;
|
||||||
|
|
||||||
|
// Read as much as we can...
|
||||||
|
while (bytes > 0 && (st->a85bufptr < st->a85bufend || st->remaining > 0))
|
||||||
|
{
|
||||||
|
unsigned count, // Number of ASCII85 chars
|
||||||
|
a85val; // ASCII85 "chunk" value
|
||||||
|
char *a85bufptr; // Local copy of buffer pointer
|
||||||
|
size_t declen; // Decoded length
|
||||||
|
|
||||||
|
|
||||||
|
// First use up any remaining decoded chars...
|
||||||
|
if (st->a85decptr)
|
||||||
|
{
|
||||||
|
declen = (size_t)(st->a85decend - st->a85decptr);
|
||||||
|
|
||||||
|
if (bytes >= declen)
|
||||||
|
{
|
||||||
|
memcpy(bufptr, st->a85decptr, declen);
|
||||||
|
bufptr += declen;
|
||||||
|
rbytes += (ssize_t)declen;
|
||||||
|
st->a85decptr = NULL;
|
||||||
|
bytes -= declen;
|
||||||
|
|
||||||
|
if (bytes == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(bufptr, st->a85decptr, bytes);
|
||||||
|
rbytes += (ssize_t)bytes;
|
||||||
|
st->a85decptr += bytes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((st->a85bufend - st->a85bufptr) < 5 && st->remaining > 0)
|
||||||
|
{
|
||||||
|
// Fill the ASCII85Decode buffer...
|
||||||
|
ssize_t a85bytes = st->a85bufend - st->a85bufptr;
|
||||||
|
// Bytes in the ASCII85Decode buffer
|
||||||
|
size_t a85remaining = st->a85size - (size_t)a85bytes;
|
||||||
|
// Remaining capacity in the buffer
|
||||||
|
|
||||||
|
// First move any remaining bytes to the front of the buffer...
|
||||||
|
if (a85bytes > 0)
|
||||||
|
memmove(st->a85buffer, st->a85bufptr, (size_t)a85bytes);
|
||||||
|
|
||||||
|
st->a85bufptr = st->a85buffer;
|
||||||
|
st->a85bufend = st->a85buffer + a85bytes;
|
||||||
|
|
||||||
|
// Then read more data from the file...
|
||||||
|
if (a85remaining > st->remaining)
|
||||||
|
a85bytes = _pdfioFileRead(st->pdf, st->a85bufend, st->remaining);
|
||||||
|
else
|
||||||
|
a85bytes = _pdfioFileRead(st->pdf, st->a85bufend, a85remaining);
|
||||||
|
|
||||||
|
if (a85bytes > 0)
|
||||||
|
{
|
||||||
|
st->remaining -= (size_t)a85bytes;
|
||||||
|
|
||||||
|
if (st->crypto_cb)
|
||||||
|
(st->crypto_cb)(&st->crypto_ctx, (uint8_t *)st->a85bufend, (uint8_t *)st->a85bufend, (size_t)a85bytes);
|
||||||
|
|
||||||
|
st->a85bufend += a85bytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pdfioFileError(st->pdf, "Read error in stream.");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the next chunk...
|
||||||
|
for (a85bufptr = st->a85bufptr, a85val = 0, count = 0; a85bufptr < st->a85bufend && count < 5; a85bufptr ++)
|
||||||
|
{
|
||||||
|
char a85ch = *a85bufptr; // Current character
|
||||||
|
|
||||||
|
if (a85ch >= '!' && a85ch <= 'u')
|
||||||
|
{
|
||||||
|
// Valid ASCII85Decode character...
|
||||||
|
a85val = a85val * 85 + a85ch - '!';
|
||||||
|
count ++;
|
||||||
|
}
|
||||||
|
else if (a85ch == 'z' && count == 0)
|
||||||
|
{
|
||||||
|
// 'z' == 0's
|
||||||
|
a85val = 0;
|
||||||
|
count = 5;
|
||||||
|
|
||||||
|
a85bufptr++;
|
||||||
|
}
|
||||||
|
else if (a85ch == '~')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (!isspace(a85ch & 255))
|
||||||
|
{
|
||||||
|
// Invalid ASCII85Decode character...
|
||||||
|
_pdfioFileError(st->pdf, "Invalid ASCII85Decode character '%c' in stream.", a85ch);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
st->a85bufptr = a85bufptr;
|
||||||
|
|
||||||
|
if (*a85bufptr == '~')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (count < 2)
|
||||||
|
{
|
||||||
|
// Need at least 2 characters to decode a single byte...
|
||||||
|
_pdfioFileError(st->pdf, "Invalid ASCII85Decode sequence in stream.");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
declen = count - 1;
|
||||||
|
|
||||||
|
// Add rounds to properly align the decoded value...
|
||||||
|
while (count < 5)
|
||||||
|
{
|
||||||
|
a85val = a85val * 85 + 84;
|
||||||
|
count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the bytes to the decode buffer...
|
||||||
|
st->a85decode[0] = (char)(a85val >> 24);
|
||||||
|
st->a85decode[1] = (char)((a85val >> 16) & 255);
|
||||||
|
st->a85decode[2] = (char)((a85val >> 8) & 255);
|
||||||
|
st->a85decode[3] = (char)(a85val & 255);
|
||||||
|
|
||||||
|
st->a85decptr = st->a85decode;
|
||||||
|
st->a85decend = st->a85decode + declen;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("stream_get_bytes: Returning %ld ASCII85 bytes for stream.\n", (long)rbytes);
|
||||||
|
|
||||||
|
return (rbytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Limit reads to the length of the stream...
|
||||||
|
if (bytes > st->remaining)
|
||||||
|
rbytes = _pdfioFileRead(st->pdf, buffer, st->remaining);
|
||||||
|
else
|
||||||
|
rbytes = _pdfioFileRead(st->pdf, buffer, bytes);
|
||||||
|
|
||||||
|
if (rbytes > 0)
|
||||||
|
{
|
||||||
|
st->remaining -= (size_t)rbytes;
|
||||||
|
|
||||||
|
if (st->crypto_cb)
|
||||||
|
(st->crypto_cb)(&st->crypto_ctx, (uint8_t *)buffer, (uint8_t *)buffer, (size_t)rbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("stream_get_bytes: Returning %ld raw bytes for stream.\n", (long)rbytes);
|
||||||
|
|
||||||
|
return (rbytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'stream_inflate()' - Decompress bytes from a stream (Flate or LZW) into the specified buffer.
|
||||||
|
//
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
stream_inflate(pdfio_stream_t *st, // I - Stream
|
||||||
|
uint8_t *buffer, // I - Output buffer
|
||||||
|
size_t bytes, // I - Number of bytes
|
||||||
|
bool exactly) // I - Require exactly the number of bytes
|
||||||
|
{
|
||||||
|
ssize_t rbytes; // Bytes read
|
||||||
|
|
||||||
|
|
||||||
|
// Setup decompression to the output buffer...
|
||||||
|
if (st->filter == PDFIO_FILTER_FLATE)
|
||||||
|
{
|
||||||
|
st->flate.next_out = (Bytef *)buffer;
|
||||||
|
st->flate.avail_out = (uInt)bytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
st->lzw->next_out = buffer;
|
||||||
|
st->lzw->avail_out = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop to get the bytes...
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (st->filter == PDFIO_FILTER_FLATE)
|
||||||
|
{
|
||||||
|
// Flate decompress
|
||||||
|
int status; // Status of decompression
|
||||||
|
|
||||||
|
PDFIO_DEBUG("stream_inflate: avail_in=%u, avail_out=%u\n", st->flate.avail_in, st->flate.avail_out);
|
||||||
|
|
||||||
|
if (st->flate.avail_in == 0)
|
||||||
|
{
|
||||||
|
// Read more from the file...
|
||||||
|
if ((rbytes = stream_get_bytes(st, st->cbuffer, st->cbsize)) <= 0)
|
||||||
|
return (-1); // End of file...
|
||||||
|
|
||||||
|
st->flate.next_in = (Bytef *)st->cbuffer;
|
||||||
|
st->flate.avail_in = (uInt)rbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("stream_inflate: inflate() returned %d\n", status);
|
||||||
|
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = (size_t)st->flate.avail_out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// LZW decompress
|
||||||
|
if (st->lzw->avail_in == 0)
|
||||||
|
{
|
||||||
|
// Read more from the file...
|
||||||
|
if ((rbytes = stream_get_bytes(st, st->cbuffer, st->cbsize)) <= 0)
|
||||||
|
return (-1); // End of file...
|
||||||
|
|
||||||
|
st->lzw->next_in = st->cbuffer;
|
||||||
|
st->lzw->avail_in = (size_t)rbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_pdfioLZWInflate(st->lzw) && !st->lzw->saw_eod)
|
||||||
|
{
|
||||||
|
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, st->lzw->error);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = st->lzw->avail_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (bytes > 0 && exactly);
|
||||||
|
|
||||||
|
if (st->filter == PDFIO_FILTER_FLATE)
|
||||||
|
return (st->flate.next_out - (Bytef *)buffer);
|
||||||
|
else
|
||||||
|
return (st->lzw->next_out - (uint8_t *)buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'stream_paeth()' - PaethPredictor function for PNG decompression filter.
|
// 'stream_paeth()' - PaethPredictor function for PNG decompression filter.
|
||||||
//
|
//
|
||||||
@@ -1038,67 +1346,20 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
char *buffer, // I - Buffer
|
char *buffer, // I - Buffer
|
||||||
size_t bytes) // I - Number of bytes to read
|
size_t bytes) // I - Number of bytes to read
|
||||||
{
|
{
|
||||||
ssize_t rbytes; // Bytes read
|
|
||||||
uInt avail_in, avail_out; // Previous flate values
|
|
||||||
|
|
||||||
|
|
||||||
if (st->filter == PDFIO_FILTER_NONE)
|
if (st->filter == PDFIO_FILTER_NONE)
|
||||||
{
|
{
|
||||||
// No filtering, but limit reads to the length of the stream...
|
// No filtering...
|
||||||
if (bytes > st->remaining)
|
return (stream_get_bytes(st, buffer, bytes));
|
||||||
rbytes = _pdfioFileRead(st->pdf, buffer, st->remaining);
|
|
||||||
else
|
|
||||||
rbytes = _pdfioFileRead(st->pdf, buffer, bytes);
|
|
||||||
|
|
||||||
if (rbytes > 0)
|
|
||||||
{
|
|
||||||
st->remaining -= (size_t)rbytes;
|
|
||||||
|
|
||||||
if (st->crypto_cb)
|
|
||||||
(st->crypto_cb)(&st->crypto_ctx, (uint8_t *)buffer, (uint8_t *)buffer, (size_t)rbytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (rbytes);
|
|
||||||
}
|
}
|
||||||
else if (st->filter == PDFIO_FILTER_FLATE)
|
else if (st->filter == PDFIO_FILTER_FLATE || st->filter == PDFIO_FILTER_LZW)
|
||||||
{
|
{
|
||||||
// Deflate compression...
|
// Flate or LZW compression...
|
||||||
int status; // Status of decompression
|
|
||||||
|
|
||||||
if (st->predictor == _PDFIO_PREDICTOR_NONE)
|
if (st->predictor == _PDFIO_PREDICTOR_NONE)
|
||||||
{
|
{
|
||||||
// Decompress into the buffer...
|
// Decompress into the buffer...
|
||||||
PDFIO_DEBUG("stream_read: No predictor.\n");
|
PDFIO_DEBUG("stream_read: No predictor.\n");
|
||||||
|
|
||||||
if (st->flate.avail_in == 0)
|
return (stream_inflate(st, (uint8_t *)buffer, bytes, /*exactly*/false));
|
||||||
{
|
|
||||||
// Read more from the file...
|
|
||||||
if (st->cbsize > st->remaining)
|
|
||||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
|
||||||
else
|
|
||||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
|
||||||
|
|
||||||
if (rbytes <= 0)
|
|
||||||
return (-1); // End of file...
|
|
||||||
|
|
||||||
if (st->crypto_cb)
|
|
||||||
rbytes = (ssize_t)(st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, (size_t)rbytes);
|
|
||||||
|
|
||||||
st->remaining -= (size_t)rbytes;
|
|
||||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
|
||||||
st->flate.avail_in = (uInt)rbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
st->flate.next_out = (Bytef *)buffer;
|
|
||||||
st->flate.avail_out = (uInt)bytes;
|
|
||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
|
||||||
{
|
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (st->flate.next_out - (Bytef *)buffer);
|
|
||||||
}
|
}
|
||||||
else if (st->predictor == _PDFIO_PREDICTOR_TIFF2)
|
else if (st->predictor == _PDFIO_PREDICTOR_TIFF2)
|
||||||
{
|
{
|
||||||
@@ -1106,9 +1367,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
// Size of pixel in bytes
|
// Size of pixel in bytes
|
||||||
remaining = st->pbsize;
|
remaining = st->pbsize;
|
||||||
// Remaining bytes
|
// Remaining bytes
|
||||||
unsigned char *bufptr = (unsigned char *)buffer,
|
uint8_t *bufptr = (uint8_t *)buffer,
|
||||||
// Pointer into buffer
|
// Pointer into buffer
|
||||||
*bufsecond = (unsigned char *)buffer + pbpixel,
|
*bufsecond = (uint8_t *)buffer + pbpixel,
|
||||||
// Pointer to second pixel in buffer
|
// Pointer to second pixel in buffer
|
||||||
*sptr = st->psbuffer;
|
*sptr = st->psbuffer;
|
||||||
// Current (raw) line
|
// Current (raw) line
|
||||||
@@ -1121,43 +1382,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
st->flate.next_out = (Bytef *)sptr;
|
if (stream_inflate(st, sptr, st->pbsize, /*exactly*/true) < 0)
|
||||||
st->flate.avail_out = (uInt)st->pbsize;
|
|
||||||
|
|
||||||
while (st->flate.avail_out > 0)
|
|
||||||
{
|
|
||||||
if (st->flate.avail_in == 0)
|
|
||||||
{
|
|
||||||
// Read more from the file...
|
|
||||||
if (st->cbsize > st->remaining)
|
|
||||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
|
||||||
else
|
|
||||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
|
||||||
|
|
||||||
if (rbytes <= 0)
|
|
||||||
return (-1); // End of file...
|
|
||||||
|
|
||||||
if (st->crypto_cb)
|
|
||||||
rbytes = (ssize_t)(st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, (size_t)rbytes);
|
|
||||||
|
|
||||||
st->remaining -= (size_t)rbytes;
|
|
||||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
|
||||||
st->flate.avail_in = (uInt)rbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
avail_in = st->flate.avail_in;
|
|
||||||
avail_out = st->flate.avail_out;
|
|
||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
|
||||||
{
|
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (st->flate.avail_out > 0)
|
|
||||||
return (-1); // Early end of stream
|
return (-1); // Early end of stream
|
||||||
|
|
||||||
for (; bufptr < bufsecond; remaining --, sptr ++)
|
for (; bufptr < bufsecond; remaining --, sptr ++)
|
||||||
@@ -1174,9 +1399,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
// Size of pixel in bytes
|
// Size of pixel in bytes
|
||||||
remaining = st->pbsize - 1;
|
remaining = st->pbsize - 1;
|
||||||
// Remaining bytes
|
// Remaining bytes
|
||||||
unsigned char *bufptr = (unsigned char *)buffer,
|
uint8_t *bufptr = (uint8_t *)buffer,
|
||||||
// Pointer into buffer
|
// Pointer into buffer
|
||||||
*bufsecond = (unsigned char *)buffer + pbpixel,
|
*bufsecond = (uint8_t *)buffer + pbpixel,
|
||||||
// Pointer to second pixel in buffer
|
// Pointer to second pixel in buffer
|
||||||
*sptr = st->psbuffer + 1,
|
*sptr = st->psbuffer + 1,
|
||||||
// Current (raw) line
|
// Current (raw) line
|
||||||
@@ -1191,46 +1416,10 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
st->flate.next_out = (Bytef *)sptr - 1;
|
if (stream_inflate(st, sptr - 1, st->pbsize, /*exactly*/true) < 0)
|
||||||
st->flate.avail_out = (uInt)st->pbsize;
|
|
||||||
|
|
||||||
while (st->flate.avail_out > 0)
|
|
||||||
{
|
|
||||||
if (st->flate.avail_in == 0)
|
|
||||||
{
|
|
||||||
// Read more from the file...
|
|
||||||
if (st->cbsize > st->remaining)
|
|
||||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
|
||||||
else
|
|
||||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
|
||||||
|
|
||||||
if (rbytes <= 0)
|
|
||||||
return (-1); // End of file...
|
|
||||||
|
|
||||||
if (st->crypto_cb)
|
|
||||||
rbytes = (ssize_t)(st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, (size_t)rbytes);
|
|
||||||
|
|
||||||
st->remaining -= (size_t)rbytes;
|
|
||||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
|
||||||
st->flate.avail_in = (uInt)rbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
avail_in = st->flate.avail_in;
|
|
||||||
avail_out = st->flate.avail_out;
|
|
||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
|
||||||
{
|
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (st->flate.avail_out > 0)
|
|
||||||
{
|
{
|
||||||
// Early end of stream
|
// Early end of stream
|
||||||
PDFIO_DEBUG("stream_read: Early EOF (remaining=%u, avail_in=%d, avail_out=%d, data_type=%d, next_in=<%02X%02X%02X%02X...>).\n", (unsigned)st->remaining, st->flate.avail_in, st->flate.avail_out, st->flate.data_type, st->flate.next_in[0], st->flate.next_in[1], st->flate.next_in[2], st->flate.next_in[3]);
|
PDFIO_DEBUG("stream_read: Early EOF (remaining=%u).\n", (unsigned)st->remaining);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1333,8 +1522,6 @@ stream_write(pdfio_stream_t *st, // I - Stream
|
|||||||
outbytes = cbytes;
|
outbytes = cbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fprintf(stderr, "stream_write: bytes=%u, outbytes=%u\n", (unsigned)bytes, (unsigned)outbytes);
|
|
||||||
|
|
||||||
if (!_pdfioFileWrite(st->pdf, st->cbuffer, outbytes))
|
if (!_pdfioFileWrite(st->pdf, st->cbuffer, outbytes))
|
||||||
return (false);
|
return (false);
|
||||||
|
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
{
|
{
|
||||||
// UTF-16 string, convert to UTF-8...
|
// UTF-16 string, convert to UTF-8...
|
||||||
PDFIO_DEBUG("_pdfioTokenRead: Converting string to UTF-8.\n", stderr);
|
PDFIO_DEBUG("_pdfioTokenRead: Converting string to UTF-8.\n", stderr);
|
||||||
_pdfio_utf16cpy(buffer + 1, (unsigned char *)buffer + 1, bufptr - buffer - 1, bufsize - 1);
|
_pdfio_utf16cpy(buffer + 1, (unsigned char *)buffer + 1, (size_t)(bufptr - buffer - 1), bufsize - 1);
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
||||||
return (true);
|
return (true);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// PDF value functions for PDFio.
|
// PDF value functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2025 by Michael R Sweet.
|
// Copyright © 2021-2026 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.
|
||||||
@@ -76,7 +76,8 @@ _pdfioValueCopy(pdfio_file_t *pdfdst, // I - Destination PDF file
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
case PDFIO_VALTYPE_ARRAY :
|
case PDFIO_VALTYPE_ARRAY :
|
||||||
vdst->value.array = pdfioArrayCopy(pdfdst, vsrc->value.array);
|
if ((vdst->value.array = pdfioArrayCopy(pdfdst, vsrc->value.array)) == NULL)
|
||||||
|
return (NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PDFIO_VALTYPE_BINARY :
|
case PDFIO_VALTYPE_BINARY :
|
||||||
@@ -97,12 +98,14 @@ _pdfioValueCopy(pdfio_file_t *pdfdst, // I - Destination PDF file
|
|||||||
return (vdst);
|
return (vdst);
|
||||||
|
|
||||||
case PDFIO_VALTYPE_DICT :
|
case PDFIO_VALTYPE_DICT :
|
||||||
vdst->value.dict = pdfioDictCopy(pdfdst, vsrc->value.dict);
|
if ((vdst->value.dict = pdfioDictCopy(pdfdst, vsrc->value.dict)) == NULL)
|
||||||
|
return (NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PDFIO_VALTYPE_NAME :
|
case PDFIO_VALTYPE_NAME :
|
||||||
case PDFIO_VALTYPE_STRING :
|
case PDFIO_VALTYPE_STRING :
|
||||||
vdst->value.name = pdfioStringCreate(pdfdst, vsrc->value.name);
|
if ((vdst->value.name = pdfioStringCreate(pdfdst, vsrc->value.name)) == NULL)
|
||||||
|
return (NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
pdfio.h
20
pdfio.h
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Public header file for PDFio.
|
// Public header file for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2025 by Michael R Sweet.
|
// Copyright © 2021-2026 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,9 +23,9 @@ extern "C" {
|
|||||||
// Version numbers...
|
// Version numbers...
|
||||||
//
|
//
|
||||||
|
|
||||||
# define PDFIO_VERSION "1.6.0"
|
# define PDFIO_VERSION "1.7.0"
|
||||||
# define PDFIO_VERSION_MAJOR 1
|
# define PDFIO_VERSION_MAJOR 1
|
||||||
# define PDFIO_VERSION_MINOR 6
|
# define PDFIO_VERSION_MINOR 7
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -72,11 +72,11 @@ typedef enum pdfio_filter_e // Compression/decompression filters for streams
|
|||||||
PDFIO_FILTER_NONE, // No filter
|
PDFIO_FILTER_NONE, // No filter
|
||||||
PDFIO_FILTER_ASCIIHEX, // ASCIIHexDecode filter (reading only)
|
PDFIO_FILTER_ASCIIHEX, // ASCIIHexDecode filter (reading only)
|
||||||
PDFIO_FILTER_ASCII85, // ASCII85Decode filter (reading only)
|
PDFIO_FILTER_ASCII85, // ASCII85Decode filter (reading only)
|
||||||
PDFIO_FILTER_CCITTFAX, // CCITTFaxDecode filter
|
PDFIO_FILTER_CCITTFAX, // CCITTFaxDecode filter (reading only)
|
||||||
PDFIO_FILTER_CRYPT, // Encryption filter
|
PDFIO_FILTER_CRYPT, // Encryption filter
|
||||||
PDFIO_FILTER_DCT, // DCTDecode (JPEG) filter
|
PDFIO_FILTER_DCT, // DCTDecode (JPEG) filter
|
||||||
PDFIO_FILTER_FLATE, // FlateDecode filter
|
PDFIO_FILTER_FLATE, // FlateDecode filter
|
||||||
PDFIO_FILTER_JBIG2, // JBIG2Decode filter
|
PDFIO_FILTER_JBIG2, // JBIG2Decode filter (reading only)
|
||||||
PDFIO_FILTER_JPX, // JPXDecode filter (reading only)
|
PDFIO_FILTER_JPX, // JPXDecode filter (reading only)
|
||||||
PDFIO_FILTER_LZW, // LZWDecode filter (reading only)
|
PDFIO_FILTER_LZW, // LZWDecode filter (reading only)
|
||||||
PDFIO_FILTER_RUNLENGTH, // RunLengthDecode filter (reading only)
|
PDFIO_FILTER_RUNLENGTH, // RunLengthDecode filter (reading only)
|
||||||
@@ -238,7 +238,17 @@ extern const char *pdfioObjGetType(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
|||||||
extern pdfio_stream_t *pdfioObjOpenStream(pdfio_obj_t *obj, bool decode) _PDFIO_PUBLIC;
|
extern pdfio_stream_t *pdfioObjOpenStream(pdfio_obj_t *obj, bool decode) _PDFIO_PUBLIC;
|
||||||
|
|
||||||
extern bool pdfioPageCopy(pdfio_file_t *pdf, pdfio_obj_t *srcpage) _PDFIO_PUBLIC;
|
extern bool pdfioPageCopy(pdfio_file_t *pdf, pdfio_obj_t *srcpage) _PDFIO_PUBLIC;
|
||||||
|
extern pdfio_array_t *pdfioPageGetArray(pdfio_obj_t *page, const char *key) _PDFIO_PUBLIC;
|
||||||
|
extern unsigned char *pdfioPageGetBinary(pdfio_obj_t *page, const char *key, size_t *length) _PDFIO_PUBLIC;
|
||||||
|
extern bool pdfioPageGetBoolean(pdfio_obj_t *page, const char *key) _PDFIO_PUBLIC;
|
||||||
|
extern time_t pdfioDictPageDate(pdfio_obj_t *page, const char *key) _PDFIO_PUBLIC;
|
||||||
|
extern pdfio_dict_t *pdfioPageGetDict(pdfio_obj_t *page, const char *key) _PDFIO_PUBLIC;
|
||||||
|
extern const char *pdfioPageGetName(pdfio_obj_t *page, const char *key) _PDFIO_PUBLIC;
|
||||||
extern size_t pdfioPageGetNumStreams(pdfio_obj_t *page) _PDFIO_PUBLIC;
|
extern size_t pdfioPageGetNumStreams(pdfio_obj_t *page) _PDFIO_PUBLIC;
|
||||||
|
extern double pdfioPageGetNumber(pdfio_obj_t *page, const char *key) _PDFIO_PUBLIC;
|
||||||
|
extern pdfio_obj_t *pdfioPageGetObj(pdfio_obj_t *page, const char *key) _PDFIO_PUBLIC;
|
||||||
|
extern pdfio_rect_t *pdfioPageGetRect(pdfio_obj_t *page, const char *key, pdfio_rect_t *rect) _PDFIO_PUBLIC;
|
||||||
|
extern const char *pdfioPageGetString(pdfio_obj_t *page, const char *key) _PDFIO_PUBLIC;
|
||||||
extern pdfio_stream_t *pdfioPageOpenStream(pdfio_obj_t *page, size_t n, bool decode) _PDFIO_PUBLIC;
|
extern pdfio_stream_t *pdfioPageOpenStream(pdfio_obj_t *page, size_t n, bool decode) _PDFIO_PUBLIC;
|
||||||
|
|
||||||
extern bool pdfioStreamClose(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
extern bool pdfioStreamClose(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ Cflags: @PKGCONFIG_CFLAGS@
|
|||||||
Libs: @PKGCONFIG_LIBS@
|
Libs: @PKGCONFIG_LIBS@
|
||||||
Libs.private: @PKGCONFIG_LIBS_PRIVATE@
|
Libs.private: @PKGCONFIG_LIBS_PRIVATE@
|
||||||
Requires: @PKGCONFIG_REQUIRES@
|
Requires: @PKGCONFIG_REQUIRES@
|
||||||
|
Requires.private: @PKGCONFIG_REQUIRES_PRIVATE@
|
||||||
|
|||||||
@@ -87,6 +87,7 @@
|
|||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<AdditionalIncludeDirectories>ttf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -101,6 +102,7 @@
|
|||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<AdditionalIncludeDirectories>ttf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -115,6 +117,7 @@
|
|||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<AdditionalIncludeDirectories>ttf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>HAVE_LIBPNG;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>HAVE_LIBPNG;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -130,6 +133,7 @@
|
|||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<AdditionalIncludeDirectories>ttf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>HAVE_LIBPNG;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>HAVE_LIBPNG;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -145,7 +149,8 @@
|
|||||||
<ClInclude Include="pdfio-content.h" />
|
<ClInclude Include="pdfio-content.h" />
|
||||||
<ClInclude Include="pdfio-private.h" />
|
<ClInclude Include="pdfio-private.h" />
|
||||||
<ClInclude Include="pdfio.h" />
|
<ClInclude Include="pdfio.h" />
|
||||||
<ClInclude Include="ttf.h" />
|
<ClInclude Include="ttf\ttf.h" />
|
||||||
|
<ClInclude Include="ttf\ttf-private.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="pdfio-aes.c" />
|
<ClCompile Include="pdfio-aes.c" />
|
||||||
@@ -155,6 +160,7 @@
|
|||||||
<ClCompile Include="pdfio-crypto.c" />
|
<ClCompile Include="pdfio-crypto.c" />
|
||||||
<ClCompile Include="pdfio-dict.c" />
|
<ClCompile Include="pdfio-dict.c" />
|
||||||
<ClCompile Include="pdfio-file.c" />
|
<ClCompile Include="pdfio-file.c" />
|
||||||
|
<ClCompile Include="pdfio-lzw.c" />
|
||||||
<ClCompile Include="pdfio-md5.c" />
|
<ClCompile Include="pdfio-md5.c" />
|
||||||
<ClCompile Include="pdfio-object.c" />
|
<ClCompile Include="pdfio-object.c" />
|
||||||
<ClCompile Include="pdfio-page.c" />
|
<ClCompile Include="pdfio-page.c" />
|
||||||
@@ -164,7 +170,8 @@
|
|||||||
<ClCompile Include="pdfio-string.c" />
|
<ClCompile Include="pdfio-string.c" />
|
||||||
<ClCompile Include="pdfio-token.c" />
|
<ClCompile Include="pdfio-token.c" />
|
||||||
<ClCompile Include="pdfio-value.c" />
|
<ClCompile Include="pdfio-value.c" />
|
||||||
<ClCompile Include="ttf.c" />
|
<ClCompile Include="ttf\ttf-cache.c" />
|
||||||
|
<ClCompile Include="ttf\ttf-file.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
|
|||||||
@@ -22,8 +22,10 @@
|
|||||||
273440CD263D727800FBFD63 /* pdfio-page.c in Sources */ = {isa = PBXBuildFile; fileRef = 273440C2263D727800FBFD63 /* pdfio-page.c */; };
|
273440CD263D727800FBFD63 /* pdfio-page.c in Sources */ = {isa = PBXBuildFile; fileRef = 273440C2263D727800FBFD63 /* pdfio-page.c */; };
|
||||||
273440D8263D72E100FBFD63 /* testpdfio.c in Sources */ = {isa = PBXBuildFile; fileRef = 273440D7263D72E100FBFD63 /* testpdfio.c */; };
|
273440D8263D72E100FBFD63 /* testpdfio.c in Sources */ = {isa = PBXBuildFile; fileRef = 273440D7263D72E100FBFD63 /* testpdfio.c */; };
|
||||||
273440E4263DD7EA00FBFD63 /* pdfio-token.c in Sources */ = {isa = PBXBuildFile; fileRef = 273440E3263DD7EA00FBFD63 /* pdfio-token.c */; };
|
273440E4263DD7EA00FBFD63 /* pdfio-token.c in Sources */ = {isa = PBXBuildFile; fileRef = 273440E3263DD7EA00FBFD63 /* pdfio-token.c */; };
|
||||||
279E1035267D043B00D3A349 /* ttf.h in Headers */ = {isa = PBXBuildFile; fileRef = 279E1033267D043B00D3A349 /* ttf.h */; };
|
2741C9A22F05872C002D93F2 /* ttf-cache.c in Sources */ = {isa = PBXBuildFile; fileRef = 2741C99F2F05872C002D93F2 /* ttf-cache.c */; };
|
||||||
279E1036267D043B00D3A349 /* ttf.c in Sources */ = {isa = PBXBuildFile; fileRef = 279E1034267D043B00D3A349 /* ttf.c */; };
|
2741C9A32F05872C002D93F2 /* ttf-file.c in Sources */ = {isa = PBXBuildFile; fileRef = 2741C9A02F05872C002D93F2 /* ttf-file.c */; };
|
||||||
|
2741C9A42F05872C002D93F2 /* ttf-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2741C9A12F05872C002D93F2 /* ttf-private.h */; };
|
||||||
|
2741C9A52F05872C002D93F2 /* ttf.h in Headers */ = {isa = PBXBuildFile; fileRef = 2741C99E2F05872C002D93F2 /* ttf.h */; };
|
||||||
279E103B267D04E600D3A349 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 279E103A267D04E600D3A349 /* libz.tbd */; };
|
279E103B267D04E600D3A349 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 279E103A267D04E600D3A349 /* libz.tbd */; };
|
||||||
27CF90442711DFFE00E50FE4 /* pdfio-aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 27CF90432711DFFE00E50FE4 /* pdfio-aes.c */; };
|
27CF90442711DFFE00E50FE4 /* pdfio-aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 27CF90432711DFFE00E50FE4 /* pdfio-aes.c */; };
|
||||||
27ECBD8926419DAB0025312A /* libpdfio.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 273440B0263D6FE200FBFD63 /* libpdfio.a */; };
|
27ECBD8926419DAB0025312A /* libpdfio.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 273440B0263D6FE200FBFD63 /* libpdfio.a */; };
|
||||||
@@ -82,8 +84,10 @@
|
|||||||
273440E1263D73A300FBFD63 /* pdfio.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = pdfio.html; path = doc/pdfio.html; sourceTree = "<group>"; };
|
273440E1263D73A300FBFD63 /* pdfio.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = pdfio.html; path = doc/pdfio.html; sourceTree = "<group>"; };
|
||||||
273440E2263D73A300FBFD63 /* pdfio.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = pdfio.3; path = doc/pdfio.3; sourceTree = "<group>"; };
|
273440E2263D73A300FBFD63 /* pdfio.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = pdfio.3; path = doc/pdfio.3; sourceTree = "<group>"; };
|
||||||
273440E3263DD7EA00FBFD63 /* pdfio-token.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-token.c"; sourceTree = "<group>"; };
|
273440E3263DD7EA00FBFD63 /* pdfio-token.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-token.c"; sourceTree = "<group>"; };
|
||||||
279E1033267D043B00D3A349 /* ttf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ttf.h; sourceTree = "<group>"; };
|
2741C99E2F05872C002D93F2 /* ttf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ttf.h; path = ttf/ttf.h; sourceTree = "<group>"; };
|
||||||
279E1034267D043B00D3A349 /* ttf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ttf.c; sourceTree = "<group>"; };
|
2741C99F2F05872C002D93F2 /* ttf-cache.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "ttf-cache.c"; path = "ttf/ttf-cache.c"; sourceTree = "<group>"; };
|
||||||
|
2741C9A02F05872C002D93F2 /* ttf-file.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "ttf-file.c"; path = "ttf/ttf-file.c"; sourceTree = "<group>"; };
|
||||||
|
2741C9A12F05872C002D93F2 /* ttf-private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "ttf-private.h"; path = "ttf/ttf-private.h"; sourceTree = "<group>"; };
|
||||||
279E103A267D04E600D3A349 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
279E103A267D04E600D3A349 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||||
27CF90432711DFFE00E50FE4 /* pdfio-aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-aes.c"; sourceTree = "<group>"; };
|
27CF90432711DFFE00E50FE4 /* pdfio-aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-aes.c"; sourceTree = "<group>"; };
|
||||||
27F2F05D2710BE92008ECD36 /* pdfio-md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-md5.c"; sourceTree = "<group>"; };
|
27F2F05D2710BE92008ECD36 /* pdfio-md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-md5.c"; sourceTree = "<group>"; };
|
||||||
@@ -179,8 +183,10 @@
|
|||||||
273440B9263D727800FBFD63 /* pdfio-string.c */,
|
273440B9263D727800FBFD63 /* pdfio-string.c */,
|
||||||
273440E3263DD7EA00FBFD63 /* pdfio-token.c */,
|
273440E3263DD7EA00FBFD63 /* pdfio-token.c */,
|
||||||
273440C0263D727800FBFD63 /* pdfio-value.c */,
|
273440C0263D727800FBFD63 /* pdfio-value.c */,
|
||||||
279E1034267D043B00D3A349 /* ttf.c */,
|
2741C99E2F05872C002D93F2 /* ttf.h */,
|
||||||
279E1033267D043B00D3A349 /* ttf.h */,
|
2741C99F2F05872C002D93F2 /* ttf-cache.c */,
|
||||||
|
2741C9A02F05872C002D93F2 /* ttf-file.c */,
|
||||||
|
2741C9A12F05872C002D93F2 /* ttf-private.h */,
|
||||||
);
|
);
|
||||||
name = Library;
|
name = Library;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -209,10 +215,11 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
27FCBDE42D19F9B300485EEE /* pdfio-base-font-widths.h in Headers */,
|
27FCBDE42D19F9B300485EEE /* pdfio-base-font-widths.h in Headers */,
|
||||||
|
2741C9A42F05872C002D93F2 /* ttf-private.h in Headers */,
|
||||||
|
2741C9A52F05872C002D93F2 /* ttf.h in Headers */,
|
||||||
273440CC263D727800FBFD63 /* pdfio.h in Headers */,
|
273440CC263D727800FBFD63 /* pdfio.h in Headers */,
|
||||||
271EA706265B2B1000ACDD39 /* pdfio-content.h in Headers */,
|
271EA706265B2B1000ACDD39 /* pdfio-content.h in Headers */,
|
||||||
273440C3263D727800FBFD63 /* pdfio-private.h in Headers */,
|
273440C3263D727800FBFD63 /* pdfio-private.h in Headers */,
|
||||||
279E1035267D043B00D3A349 /* ttf.h in Headers */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -295,7 +302,6 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
279E1036267D043B00D3A349 /* ttf.c in Sources */,
|
|
||||||
273440C9263D727800FBFD63 /* pdfio-dict.c in Sources */,
|
273440C9263D727800FBFD63 /* pdfio-dict.c in Sources */,
|
||||||
273440C8263D727800FBFD63 /* pdfio-file.c in Sources */,
|
273440C8263D727800FBFD63 /* pdfio-file.c in Sources */,
|
||||||
273440CB263D727800FBFD63 /* pdfio-value.c in Sources */,
|
273440CB263D727800FBFD63 /* pdfio-value.c in Sources */,
|
||||||
@@ -303,6 +309,8 @@
|
|||||||
273440CD263D727800FBFD63 /* pdfio-page.c in Sources */,
|
273440CD263D727800FBFD63 /* pdfio-page.c in Sources */,
|
||||||
27F2F0622710BE92008ECD36 /* pdfio-crypto.c in Sources */,
|
27F2F0622710BE92008ECD36 /* pdfio-crypto.c in Sources */,
|
||||||
27F2F0642711243D008ECD36 /* pdfio-sha256.c in Sources */,
|
27F2F0642711243D008ECD36 /* pdfio-sha256.c in Sources */,
|
||||||
|
2741C9A22F05872C002D93F2 /* ttf-cache.c in Sources */,
|
||||||
|
2741C9A32F05872C002D93F2 /* ttf-file.c in Sources */,
|
||||||
273440C5263D727800FBFD63 /* pdfio-array.c in Sources */,
|
273440C5263D727800FBFD63 /* pdfio-array.c in Sources */,
|
||||||
273440E4263DD7EA00FBFD63 /* pdfio-token.c in Sources */,
|
273440E4263DD7EA00FBFD63 /* pdfio-token.c in Sources */,
|
||||||
273440C7263D727800FBFD63 /* pdfio-object.c in Sources */,
|
273440C7263D727800FBFD63 /* pdfio-object.c in Sources */,
|
||||||
@@ -360,7 +368,7 @@
|
|||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
CLANG_WARN_IMPLICIT_FALLTHROUGH = YES;
|
CLANG_WARN_IMPLICIT_FALLTHROUGH = NO;
|
||||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
@@ -398,7 +406,7 @@
|
|||||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
|
||||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
@@ -460,7 +468,7 @@
|
|||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
CLANG_WARN_IMPLICIT_FALLTHROUGH = YES;
|
CLANG_WARN_IMPLICIT_FALLTHROUGH = NO;
|
||||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
@@ -497,7 +505,7 @@
|
|||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
|
||||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
|||||||
15
pdfio1.def
15
pdfio1.def
@@ -1,5 +1,5 @@
|
|||||||
LIBRARY pdfio1
|
LIBRARY pdfio1
|
||||||
VERSION 1.6
|
VERSION 1.7
|
||||||
EXPORTS
|
EXPORTS
|
||||||
_pdfio_strlcpy
|
_pdfio_strlcpy
|
||||||
_pdfio_strtod
|
_pdfio_strtod
|
||||||
@@ -51,6 +51,9 @@ _pdfioFileRead
|
|||||||
_pdfioFileSeek
|
_pdfioFileSeek
|
||||||
_pdfioFileTell
|
_pdfioFileTell
|
||||||
_pdfioFileWrite
|
_pdfioFileWrite
|
||||||
|
_pdfioLZWCreate
|
||||||
|
_pdfioLZWDelete
|
||||||
|
_pdfioLZWInflate
|
||||||
_pdfioObjDelete
|
_pdfioObjDelete
|
||||||
_pdfioObjGetExtension
|
_pdfioObjGetExtension
|
||||||
_pdfioObjLoad
|
_pdfioObjLoad
|
||||||
@@ -255,7 +258,17 @@ pdfioPageCopy
|
|||||||
pdfioPageDictAddColorSpace
|
pdfioPageDictAddColorSpace
|
||||||
pdfioPageDictAddFont
|
pdfioPageDictAddFont
|
||||||
pdfioPageDictAddImage
|
pdfioPageDictAddImage
|
||||||
|
pdfioPageGetArray
|
||||||
|
pdfioPageGetBinary
|
||||||
|
pdfioPageGetBoolean
|
||||||
|
pdfioPageGetDate
|
||||||
|
pdfioPageGetDict
|
||||||
|
pdfioPageGetName
|
||||||
|
pdfioPageGetNumber
|
||||||
pdfioPageGetNumStreams
|
pdfioPageGetNumStreams
|
||||||
|
pdfioPageGetObj
|
||||||
|
pdfioPageGetRect
|
||||||
|
pdfioPageGetString
|
||||||
pdfioPageOpenStream
|
pdfioPageOpenStream
|
||||||
pdfioStreamClose
|
pdfioStreamClose
|
||||||
pdfioStreamConsume
|
pdfioStreamConsume
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<metadata>
|
<metadata>
|
||||||
<id>pdfio_native</id>
|
<id>pdfio_native</id>
|
||||||
<title>PDFio Library for VS2019+</title>
|
<title>PDFio Library for VS2019+</title>
|
||||||
<version>1.6.0</version>
|
<version>1.7.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>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<copyright>Copyright © 2019-2025 by Michael R Sweet</copyright>
|
<copyright>Copyright © 2019-2025 by Michael R Sweet</copyright>
|
||||||
<tags>pdf file native</tags>
|
<tags>pdf file native</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="pdfio_native.redist" version="1.6.0" />
|
<dependency id="pdfio_native.redist" version="1.7.0" />
|
||||||
<dependency id="libpng_native.redist" version="1.6.30" />
|
<dependency id="libpng_native.redist" version="1.6.30" />
|
||||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<metadata>
|
<metadata>
|
||||||
<id>pdfio_native.redist</id>
|
<id>pdfio_native.redist</id>
|
||||||
<title>PDFio Library for VS2019+</title>
|
<title>PDFio Library for VS2019+</title>
|
||||||
<version>1.6.0</version>
|
<version>1.7.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>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#
|
#
|
||||||
# Script to test PDFio against a directory of PDF files.
|
# Script to test PDFio against a directory of PDF files.
|
||||||
#
|
#
|
||||||
# Copyright © 2025 by Michael R Sweet.
|
# Copyright © 2025-2026 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.
|
||||||
@@ -17,14 +17,28 @@ if test $# = 0; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
|
||||||
|
ac_n=-n
|
||||||
|
ac_c=
|
||||||
|
else
|
||||||
|
ac_n=
|
||||||
|
ac_c='\c'
|
||||||
|
fi
|
||||||
|
|
||||||
for file in $(find "$@" -name \*.pdf -print); do
|
for file in $(find "$@" -name \*.pdf -print); do
|
||||||
# Run testpdfio to test loading the file...
|
# Run testpdfio to test loading the file...
|
||||||
./testpdfio $file >$file.log 2>&1
|
echo $ac_n "\r$file: $ac_c"
|
||||||
|
|
||||||
|
./testpdfio --verbose $file >/dev/null 2>$file.log
|
||||||
|
|
||||||
if test $? = 0; then
|
if test $? = 0; then
|
||||||
# Passed
|
# Passed
|
||||||
|
echo PASS
|
||||||
rm -f $file.log
|
rm -f $file.log
|
||||||
else
|
else
|
||||||
# Failed, preserve log and write filename to stdout...
|
# Failed, preserve log and write to stdout...
|
||||||
echo $file
|
echo FAIL
|
||||||
|
cat $file.log
|
||||||
|
echo ""
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
10
test.h
10
test.h
@@ -96,6 +96,16 @@ static int test_progress; // Current progress
|
|||||||
static char test_title[1024] = ""; // Current test title
|
static char test_title[1024] = ""; // Current test title
|
||||||
|
|
||||||
|
|
||||||
|
// Add printf syntax checking on supported compilers...
|
||||||
|
#if defined(__has_extension) || defined(__GNUC__)
|
||||||
|
# define TEST_FORMAT(a,b) __attribute__ ((__format__(__printf__,a,b)))
|
||||||
|
static inline void testBegin(const char *title, ...) TEST_FORMAT(1,2);
|
||||||
|
static inline void testEndMessage(bool pass, const char *message, ...) TEST_FORMAT(2,3);
|
||||||
|
static inline void testError(const char *error, ...) TEST_FORMAT(1,2);
|
||||||
|
static inline void testMessage(const char *error, ...) TEST_FORMAT(1,2);
|
||||||
|
#endif // __has_extension || __GNUC__
|
||||||
|
|
||||||
|
|
||||||
// Start a test
|
// Start a test
|
||||||
static inline void
|
static inline void
|
||||||
testBegin(const char *title, ...) // I - printf-style title string
|
testBegin(const char *title, ...) // I - printf-style title string
|
||||||
|
|||||||
283
testpdfio.c
283
testpdfio.c
@@ -1,16 +1,21 @@
|
|||||||
//
|
//
|
||||||
// Test program for PDFio.
|
// Test program for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2025 by Michael R Sweet.
|
// Copyright © 2021-2026 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.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// ./testpdfio
|
// ./testpdfio OPTIONS [FILENAME {OBJECT-NUMBER,OUT-FILENAME}] ...
|
||||||
//
|
//
|
||||||
// ./testpdfio [--verbose] FILENAME [OBJECT-NUMBER] [FILENAME [OBJECT-NUMBER]] ...
|
// Options:
|
||||||
|
//
|
||||||
|
// --decode Decode object stream
|
||||||
|
// --help Show help
|
||||||
|
// --password PASSWORD Set access password
|
||||||
|
// --verbose Be verbose
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
@@ -28,8 +33,9 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
static int do_crypto_tests(void);
|
static int do_crypto_tests(void);
|
||||||
|
static int do_lzw_tests(void);
|
||||||
static int do_pdfa_tests(void);
|
static int do_pdfa_tests(void);
|
||||||
static int do_test_file(const char *filename, int objnum, const char *password, bool verbose);
|
static int do_test_file(const char *filename, const char *outfile, int objnum, const char *password, bool decode, bool verbose);
|
||||||
static int do_unit_tests(void);
|
static int do_unit_tests(void);
|
||||||
static int draw_image(pdfio_stream_t *st, const char *name, double x, double y, double w, double h, const char *label);
|
static int draw_image(pdfio_stream_t *st, const char *name, double x, double y, double w, double h, const char *label);
|
||||||
static bool error_cb(pdfio_file_t *pdf, const char *message, bool *error);
|
static bool error_cb(pdfio_file_t *pdf, const char *message, bool *error);
|
||||||
@@ -70,11 +76,16 @@ main(int argc, // I - Number of command-line arguments
|
|||||||
{
|
{
|
||||||
int i; // Looping var
|
int i; // Looping var
|
||||||
const char *password = NULL; // Password
|
const char *password = NULL; // Password
|
||||||
bool verbose = false; // Be verbose?
|
bool decode = false, // Decode object stream?
|
||||||
|
verbose = false; // Be verbose?
|
||||||
|
|
||||||
for (i = 1; i < argc; i ++)
|
for (i = 1; i < argc; i ++)
|
||||||
{
|
{
|
||||||
if (!strcmp(argv[i], "--help"))
|
if (!strcmp(argv[i], "--decode"))
|
||||||
|
{
|
||||||
|
decode = true;
|
||||||
|
}
|
||||||
|
else if (!strcmp(argv[i], "--help"))
|
||||||
{
|
{
|
||||||
return (usage(stdout));
|
return (usage(stdout));
|
||||||
}
|
}
|
||||||
@@ -103,14 +114,18 @@ main(int argc, // I - Number of command-line arguments
|
|||||||
else if ((i + 1) < argc && isdigit(argv[i + 1][0] & 255))
|
else if ((i + 1) < argc && isdigit(argv[i + 1][0] & 255))
|
||||||
{
|
{
|
||||||
// filename.pdf object-number
|
// filename.pdf object-number
|
||||||
if (do_test_file(argv[i], atoi(argv[i + 1]), password, verbose))
|
if (do_test_file(argv[i], /*outfile*/NULL, atoi(argv[i + 1]), password, decode, verbose))
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
||||||
i ++;
|
i ++;
|
||||||
}
|
}
|
||||||
else if (do_test_file(argv[i], 0, password, verbose))
|
else
|
||||||
{
|
{
|
||||||
ret = 1;
|
if (do_test_file(argv[i], argv[i + 1], /*objnum*/0, password, decode, verbose))
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
|
if (argv[i + 1])
|
||||||
|
i ++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,6 +145,7 @@ main(int argc, // I - Number of command-line arguments
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'do_crypto_tests()' - Test the various cryptographic functions in PDFio.
|
// 'do_crypto_tests()' - Test the various cryptographic functions in PDFio.
|
||||||
//
|
//
|
||||||
@@ -373,6 +389,102 @@ do_crypto_tests(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'do_lzw_tests()' - Test the various LZW functions in PDFio.
|
||||||
|
//
|
||||||
|
|
||||||
|
static int // O - Exit status
|
||||||
|
do_lzw_tests(void)
|
||||||
|
{
|
||||||
|
int status = 0; // Exit status
|
||||||
|
_pdfio_lzw_t *lzw; // LZW state
|
||||||
|
uint8_t buffer[8192]; // Output buffer
|
||||||
|
size_t bytes; // Output bytes
|
||||||
|
static uint8_t iso32000_in[] = // ISO-32000-2 test case input
|
||||||
|
{
|
||||||
|
0x80, 0x0B, 0x60, 0x50, 0x22, 0x0C, 0x0C, 0x85, 0x01
|
||||||
|
};
|
||||||
|
static uint8_t iso32000_out[] = // ISO-32000-2 test case output
|
||||||
|
{
|
||||||
|
45, 45, 45, 45, 45, 65, 45, 45, 45, 66
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
testBegin("_pdfioLZWCreate(8)");
|
||||||
|
testEnd((lzw = _pdfioLZWCreate(/*code_size*/8, /*early*/1)) != NULL);
|
||||||
|
if (!lzw)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
testBegin("_pdfioLZWInflate(ISO 32000-2 test case)");
|
||||||
|
|
||||||
|
lzw->avail_in = sizeof(iso32000_in);
|
||||||
|
lzw->next_in = iso32000_in;
|
||||||
|
|
||||||
|
lzw->avail_out = sizeof(buffer);
|
||||||
|
lzw->next_out = buffer;
|
||||||
|
|
||||||
|
if (!_pdfioLZWInflate(lzw))
|
||||||
|
{
|
||||||
|
testEndMessage(false, "returned false");
|
||||||
|
status = 1;
|
||||||
|
}
|
||||||
|
else if ((bytes = sizeof(buffer) - lzw->avail_out) != sizeof(iso32000_out))
|
||||||
|
{
|
||||||
|
testEndMessage(false, "got %u bytes, expected %u bytes", (unsigned)bytes, (unsigned)sizeof(iso32000_out));
|
||||||
|
status = 1;
|
||||||
|
}
|
||||||
|
else if (memcmp(buffer, iso32000_out, bytes))
|
||||||
|
{
|
||||||
|
size_t i; // Looping var
|
||||||
|
|
||||||
|
testEndMessage(false, "got incorrect output");
|
||||||
|
|
||||||
|
testMessage(" EXPECTED %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", iso32000_out[0], iso32000_out[1], iso32000_out[2], iso32000_out[3], iso32000_out[4], iso32000_out[5], iso32000_out[6], iso32000_out[7], iso32000_out[8], iso32000_out[9]);
|
||||||
|
|
||||||
|
for (i = 0; i < bytes; i += 8)
|
||||||
|
{
|
||||||
|
switch (bytes - i)
|
||||||
|
{
|
||||||
|
case 1 :
|
||||||
|
testMessage(" %s %02X", i == 0 ? "GOT" : " ", buffer[i + 0]);
|
||||||
|
break;
|
||||||
|
case 2 :
|
||||||
|
testMessage(" %s %02X %02X", i == 0 ? "GOT" : " ", buffer[i + 0], buffer[i + 1]);
|
||||||
|
break;
|
||||||
|
case 3 :
|
||||||
|
testMessage(" %s %02X %02X %02X", i == 0 ? "GOT" : " ", buffer[i + 0], buffer[i + 1], buffer[i + 2]);
|
||||||
|
break;
|
||||||
|
case 4 :
|
||||||
|
testMessage(" %s %02X %02X %02X %02X", i == 0 ? "GOT" : " ", buffer[i + 0], buffer[i + 1], buffer[i + 2], buffer[i + 3]);
|
||||||
|
break;
|
||||||
|
case 5 :
|
||||||
|
testMessage(" %s %02X %02X %02X %02X %02X", i == 0 ? "GOT" : " ", buffer[i + 0], buffer[i + 1], buffer[i + 2], buffer[i + 3], buffer[i + 4]);
|
||||||
|
break;
|
||||||
|
case 6 :
|
||||||
|
testMessage(" %s %02X %02X %02X %02X %02X %02X", i == 0 ? "GOT" : " ", buffer[i + 0], buffer[i + 1], buffer[i + 2], buffer[i + 3], buffer[i + 4], buffer[i + 5]);
|
||||||
|
break;
|
||||||
|
case 7 :
|
||||||
|
testMessage(" %s %02X %02X %02X %02X %02X %02X %02X", i == 0 ? "GOT" : " ", buffer[i + 0], buffer[i + 1], buffer[i + 2], buffer[i + 3], buffer[i + 4], buffer[i + 5], buffer[i + 6]);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
testMessage(" %s %02X %02X %02X %02X %02X %02X %02X %02X", i == 0 ? "GOT" : " ", buffer[i + 0], buffer[i + 1], buffer[i + 2], buffer[i + 3], buffer[i + 4], buffer[i + 5], buffer[i + 6], buffer[i + 7]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
testEnd(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_pdfioLZWDelete(lzw);
|
||||||
|
|
||||||
|
return (status);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'do_pdfa_tests()' - Run PDF/A generation and compliance tests.
|
// 'do_pdfa_tests()' - Run PDF/A generation and compliance tests.
|
||||||
//
|
//
|
||||||
@@ -429,12 +541,16 @@ do_pdfa_tests(void)
|
|||||||
|
|
||||||
static int // O - Exit status
|
static int // O - Exit status
|
||||||
do_test_file(const char *filename, // I - PDF filename
|
do_test_file(const char *filename, // I - PDF filename
|
||||||
|
const char *outfile, // I - Output filename, if any
|
||||||
int objnum, // I - Object number to dump, if any
|
int objnum, // I - Object number to dump, if any
|
||||||
const char *password, // I - Password for file
|
const char *password, // I - Password for file
|
||||||
|
bool decode, // I - Decode object?
|
||||||
bool verbose) // I - Be verbose?
|
bool verbose) // I - Be verbose?
|
||||||
{
|
{
|
||||||
|
int status = 0; // Exit status
|
||||||
bool error = false; // Have we shown an error yet?
|
bool error = false; // Have we shown an error yet?
|
||||||
pdfio_file_t *pdf; // PDF file
|
pdfio_file_t *pdf, // PDF file
|
||||||
|
*outpdf; // Output PDF file, if any
|
||||||
size_t n, // Object/page index
|
size_t n, // Object/page index
|
||||||
num_objs, // Number of objects
|
num_objs, // Number of objects
|
||||||
num_pages; // Number of pages
|
num_pages; // Number of pages
|
||||||
@@ -444,7 +560,12 @@ do_test_file(const char *filename, // I - PDF filename
|
|||||||
|
|
||||||
// Try opening the file...
|
// Try opening the file...
|
||||||
if (!objnum)
|
if (!objnum)
|
||||||
testBegin("%s", filename);
|
{
|
||||||
|
if (outfile)
|
||||||
|
testBegin("%s -> %s", filename, outfile);
|
||||||
|
else
|
||||||
|
testBegin("pdfioFileOpen(%s)", filename);
|
||||||
|
}
|
||||||
|
|
||||||
if ((pdf = pdfioFileOpen(filename, password_cb, (void *)password, (pdfio_error_cb_t)error_cb, &error)) != NULL)
|
if ((pdf = pdfioFileOpen(filename, password_cb, (void *)password, (pdfio_error_cb_t)error_cb, &error)) != NULL)
|
||||||
{
|
{
|
||||||
@@ -458,6 +579,7 @@ do_test_file(const char *filename, // I - PDF filename
|
|||||||
if ((obj = pdfioFileFindObj(pdf, (size_t)objnum)) == NULL)
|
if ((obj = pdfioFileFindObj(pdf, (size_t)objnum)) == NULL)
|
||||||
{
|
{
|
||||||
puts("Not found.");
|
puts("Not found.");
|
||||||
|
pdfioFileClose(pdf);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,15 +587,17 @@ do_test_file(const char *filename, // I - PDF filename
|
|||||||
{
|
{
|
||||||
_pdfioValueDebug(&obj->value, stdout);
|
_pdfioValueDebug(&obj->value, stdout);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
|
pdfioFileClose(pdf);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter = pdfioDictGetName(dict, "Filter");
|
filter = pdfioDictGetName(dict, "Filter");
|
||||||
|
|
||||||
if ((st = pdfioObjOpenStream(obj, filter && !strcmp(filter, "FlateDecode"))) == NULL)
|
if ((st = pdfioObjOpenStream(obj, decode || (filter && !strcmp(filter, "FlateDecode")))) == NULL)
|
||||||
{
|
{
|
||||||
_pdfioValueDebug(&obj->value, stdout);
|
_pdfioValueDebug(&obj->value, stdout);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
|
pdfioFileClose(pdf);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,63 +605,106 @@ do_test_file(const char *filename, // I - PDF filename
|
|||||||
fwrite(buffer, 1, (size_t)bytes, stdout);
|
fwrite(buffer, 1, (size_t)bytes, stdout);
|
||||||
|
|
||||||
pdfioStreamClose(st);
|
pdfioStreamClose(st);
|
||||||
|
pdfioFileClose(pdf);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
testEnd(true);
|
if (outfile)
|
||||||
|
|
||||||
// Show basic stats...
|
|
||||||
num_objs = pdfioFileGetNumObjs(pdf);
|
|
||||||
num_pages = pdfioFileGetNumPages(pdf);
|
|
||||||
|
|
||||||
printf(" PDF %s, %d pages, %d objects.\n", pdfioFileGetVersion(pdf), (int)num_pages, (int)num_objs);
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
{
|
{
|
||||||
// Show a summary of each page...
|
if (!access(outfile, 0))
|
||||||
for (n = 0; n < num_pages; n ++)
|
{
|
||||||
{
|
testEndMessage(false, "output file already exists");
|
||||||
if ((obj = pdfioFileGetPage(pdf, n)) == NULL)
|
pdfioFileClose(pdf);
|
||||||
{
|
return (1);
|
||||||
printf("%s: Unable to get page #%d.\n", filename, (int)n + 1);
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pdfio_rect_t media_box; // MediaBox value
|
|
||||||
|
|
||||||
memset(&media_box, 0, sizeof(media_box));
|
// Copy pages to the output file...
|
||||||
dict = pdfioObjGetDict(obj);
|
if ((outpdf = pdfioFileCreate(outfile, pdfioFileGetVersion(pdf), /*media_box*/NULL, /*crop_box*/NULL, (pdfio_error_cb_t)error_cb, &error)) != NULL)
|
||||||
|
{
|
||||||
if (!pdfioDictGetRect(dict, "MediaBox", &media_box))
|
for (n = 0, num_pages = pdfioFileGetNumPages(pdf); n < num_pages; n ++)
|
||||||
|
{
|
||||||
|
if (!pdfioPageCopy(outpdf, pdfioFileGetPage(pdf, n)))
|
||||||
{
|
{
|
||||||
if ((obj = pdfioDictGetObj(dict, "Parent")) != NULL)
|
status = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioFileClose(outpdf);
|
||||||
|
testEnd(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show basic stats...
|
||||||
|
num_objs = pdfioFileGetNumObjs(pdf);
|
||||||
|
num_pages = pdfioFileGetNumPages(pdf);
|
||||||
|
|
||||||
|
testEndMessage(true, "PDF %s, %d pages, %d objects", pdfioFileGetVersion(pdf), (int)num_pages, (int)num_objs);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
// Show a summary of each page...
|
||||||
|
for (n = 0; n < num_pages; n ++)
|
||||||
|
{
|
||||||
|
testBegin("pdfioFileGetPage(%u)", (unsigned)n);
|
||||||
|
|
||||||
|
if ((obj = pdfioFileGetPage(pdf, n)) != NULL)
|
||||||
|
{
|
||||||
|
pdfio_rect_t media_box;
|
||||||
|
// MediaBox value
|
||||||
|
pdfio_stream_t *st; // Page content stream
|
||||||
|
|
||||||
|
memset(&media_box, 0, sizeof(media_box));
|
||||||
|
pdfioPageGetRect(obj, "MediaBox", &media_box);
|
||||||
|
|
||||||
|
if ((st = pdfioPageOpenStream(obj, /*number*/0, /*decode*/true)) != NULL)
|
||||||
{
|
{
|
||||||
dict = pdfioObjGetDict(obj);
|
char buffer[8192]; // Content buffer
|
||||||
pdfioDictGetRect(dict, "MediaBox", &media_box);
|
ssize_t bytes; // Number of bytes read
|
||||||
|
size_t length = 0; // Content length
|
||||||
|
|
||||||
|
while ((bytes = pdfioStreamRead(st, buffer, sizeof(buffer))) > 0)
|
||||||
|
length += (size_t)bytes;
|
||||||
|
|
||||||
|
pdfioStreamClose(st);
|
||||||
|
|
||||||
|
testEndMessage(true, "page #%d/obj %d is %gx%g, content is %lu bytes", (int)n + 1, (int)pdfioObjGetNumber(obj), media_box.x2, media_box.y2, (unsigned long)length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
testEndMessage(false, "page #%d/obj %d is %gx%g, unable to open content stream", (int)n + 1, (int)pdfioObjGetNumber(obj), media_box.x2, media_box.y2);
|
||||||
|
status = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
printf(" Page #%d (obj %d) is %gx%g.\n", (int)n + 1, (int)pdfioObjGetNumber(obj), media_box.x2, media_box.y2);
|
{
|
||||||
|
testEnd(false);
|
||||||
|
status = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Show the associated value with each object...
|
// Show the associated value with each object...
|
||||||
for (n = 0; n < num_objs; n ++)
|
for (n = 0; n < num_objs; n ++)
|
||||||
{
|
|
||||||
if ((obj = pdfioFileGetObj(pdf, n)) == NULL)
|
|
||||||
{
|
{
|
||||||
printf(" Unable to get object #%d.\n", (int)n);
|
testBegin("pdfioFileGetObj(%u)", (unsigned)n);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dict = pdfioObjGetDict(obj);
|
|
||||||
|
|
||||||
printf(" %u %u obj dict=%p(%lu pairs)\n", (unsigned)pdfioObjGetNumber(obj), (unsigned)pdfioObjGetGeneration(obj), (void *)dict, dict ? (unsigned long)dict->num_pairs : 0UL);
|
if ((obj = pdfioFileGetObj(pdf, n)) != NULL)
|
||||||
fputs(" ", stdout);
|
{
|
||||||
_pdfioValueDebug(&obj->value, stdout);
|
dict = pdfioObjGetDict(obj);
|
||||||
putchar('\n');
|
|
||||||
|
testEndMessage(true, "%u %u obj dict=%p/%lu pairs", (unsigned)pdfioObjGetNumber(obj), (unsigned)pdfioObjGetGeneration(obj), (void *)dict, dict ? (unsigned long)dict->num_pairs : 0UL);
|
||||||
|
fputs(" ", stderr);
|
||||||
|
_pdfioValueDebug(&obj->value, stderr);
|
||||||
|
fputs("\n", stderr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
testEnd(false);
|
||||||
|
status = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -545,7 +712,7 @@ do_test_file(const char *filename, // I - PDF filename
|
|||||||
|
|
||||||
// Close the file and return success...
|
// Close the file and return success...
|
||||||
pdfioFileClose(pdf);
|
pdfioFileClose(pdf);
|
||||||
return (0);
|
return (status);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1108,6 +1275,10 @@ do_unit_tests(void)
|
|||||||
if (do_crypto_tests())
|
if (do_crypto_tests())
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
|
// Do LZW tests...
|
||||||
|
if (do_lzw_tests())
|
||||||
|
return (1);
|
||||||
|
|
||||||
// Create a new PDF file...
|
// Create a new PDF file...
|
||||||
testBegin("pdfioFileCreate(\"testpdfio-out.pdf\", ...)");
|
testBegin("pdfioFileCreate(\"testpdfio-out.pdf\", ...)");
|
||||||
if ((outpdf = pdfioFileCreate("testpdfio-out.pdf", /*version*/"1.7", /*media_box*/NULL, /*crop_box*/NULL, (pdfio_error_cb_t)error_cb, &error)) != NULL)
|
if ((outpdf = pdfioFileCreate("testpdfio-out.pdf", /*version*/"1.7", /*media_box*/NULL, /*crop_box*/NULL, (pdfio_error_cb_t)error_cb, &error)) != NULL)
|
||||||
@@ -1739,7 +1910,7 @@ token_peek_cb(const char **s, // IO - Test string
|
|||||||
static int // O - Exit status
|
static int // O - Exit status
|
||||||
usage(FILE *fp) // I - Output file
|
usage(FILE *fp) // I - Output file
|
||||||
{
|
{
|
||||||
fputs("Usage: ./testpdfio [OPTIONS] [FILENAME [OBJNUM]] ...\n", fp);
|
fputs("Usage: ./testpdfio [OPTIONS] [FILENAME {OBJECT-NUM,OUT-FILENAME}] ...\n", fp);
|
||||||
fputs("Options:\n", fp);
|
fputs("Options:\n", fp);
|
||||||
fputs(" --help Show program help.\n", fp);
|
fputs(" --help Show program help.\n", fp);
|
||||||
fputs(" --password PASSWORD Set PDF password.\n", fp);
|
fputs(" --password PASSWORD Set PDF password.\n", fp);
|
||||||
|
|||||||
396
testttf.c
396
testttf.c
@@ -1,396 +0,0 @@
|
|||||||
//
|
|
||||||
// Unit test program for TTF library
|
|
||||||
//
|
|
||||||
// https://github.com/michaelrsweet/ttf
|
|
||||||
//
|
|
||||||
// Copyright © 2018-2025 by Michael R Sweet.
|
|
||||||
//
|
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
|
||||||
// information.
|
|
||||||
//
|
|
||||||
// Usage:
|
|
||||||
//
|
|
||||||
// ./testttf [FILENAME]
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include "ttf.h"
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Local functions...
|
|
||||||
//
|
|
||||||
|
|
||||||
static void error_cb(void *data, const char *message);
|
|
||||||
static int test_font(const char *filename);
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// 'main()' - Main entry for unit tests.
|
|
||||||
//
|
|
||||||
|
|
||||||
int // O - Exit status
|
|
||||||
main(int argc, // I - Number of command-line arguments
|
|
||||||
char *argv[]) // I - Command-line arguments
|
|
||||||
{
|
|
||||||
int i; // Looping var
|
|
||||||
int errors = 0; // Number of errors
|
|
||||||
|
|
||||||
|
|
||||||
if (argc > 1)
|
|
||||||
{
|
|
||||||
for (i = 1; i < argc; i ++)
|
|
||||||
errors += test_font(argv[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Test with the bundled TrueType files...
|
|
||||||
errors += test_font("testfiles/OpenSans-Bold.ttf");
|
|
||||||
errors += test_font("testfiles/OpenSans-Regular.ttf");
|
|
||||||
errors += test_font("testfiles/NotoSansJP-Regular.otf");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!errors)
|
|
||||||
puts("\nALL TESTS PASSED");
|
|
||||||
else
|
|
||||||
printf("\n%d TEST(S) FAILED\n", errors);
|
|
||||||
|
|
||||||
return (errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// 'error_cb()' - Error callback.
|
|
||||||
//
|
|
||||||
|
|
||||||
static void
|
|
||||||
error_cb(void *data, // I - User data (not used)
|
|
||||||
const char *message) // I - Message string
|
|
||||||
{
|
|
||||||
fprintf(stderr, "FAIL (%s)\n", message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// 'test_font()' - Test a font file.
|
|
||||||
//
|
|
||||||
|
|
||||||
static int // O - Number of errors
|
|
||||||
test_font(const char *filename) // I - Font filename
|
|
||||||
{
|
|
||||||
int i, // Looping var
|
|
||||||
errors = 0; // Number of errors
|
|
||||||
ttf_t *font; // Font
|
|
||||||
struct stat fileinfo; // Font file information
|
|
||||||
FILE *fp = NULL; // File pointer
|
|
||||||
void *data = NULL; // Memory buffer for font file
|
|
||||||
const char *value; // Font (string) value
|
|
||||||
int intvalue; // Font (integer) value
|
|
||||||
float realvalue; // Font (real) value
|
|
||||||
char psname[1024]; // Postscript font name
|
|
||||||
ttf_rect_t bounds; // Bounds
|
|
||||||
ttf_rect_t extents; // Extents
|
|
||||||
size_t num_fonts; // Number of fonts
|
|
||||||
ttf_style_t style; // Font style
|
|
||||||
ttf_weight_t weight; // Font weight
|
|
||||||
static const char * const stretches[] =
|
|
||||||
{ // Font stretch strings
|
|
||||||
"TTF_STRETCH_NORMAL", // normal
|
|
||||||
"TTF_STRETCH_ULTRA_CONDENSED", // ultra-condensed
|
|
||||||
"TTF_STRETCH_EXTRA_CONDENSED", // extra-condensed
|
|
||||||
"TTF_STRETCH_CONDENSED", // condensed
|
|
||||||
"TTF_STRETCH_SEMI_CONDENSED", // semi-condensed
|
|
||||||
"TTF_STRETCH_SEMI_EXPANDED", // semi-expanded
|
|
||||||
"TTF_STRETCH_EXPANDED", // expanded
|
|
||||||
"TTF_STRETCH_EXTRA_EXPANDED", // extra-expanded
|
|
||||||
"TTF_STRETCH_ULTRA_EXPANDED" // ultra-expanded
|
|
||||||
};
|
|
||||||
static const char * const strings[] = // Test strings
|
|
||||||
{
|
|
||||||
"Hello, World!", // English
|
|
||||||
"مرحبا بالعالم!", // Arabic
|
|
||||||
"Bonjour le monde!", // French
|
|
||||||
"Γειά σου Κόσμε!", // Greek
|
|
||||||
"שלום עולם!", // Hebrew
|
|
||||||
"Привет мир!", // Russian
|
|
||||||
"こんにちは世界!" // Japanese
|
|
||||||
};
|
|
||||||
static const char * const styles[] = // Font style names
|
|
||||||
{
|
|
||||||
"TTF_STYLE_NORMAL",
|
|
||||||
"TTF_STYLE_ITALIC",
|
|
||||||
"TTF_STYLE_OBLIQUE"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
printf("ttfCreate(\"%s\"): ", filename);
|
|
||||||
fflush(stdout);
|
|
||||||
if ((font = ttfCreate(filename, 0, error_cb, NULL)) != NULL)
|
|
||||||
puts("PASS");
|
|
||||||
else
|
|
||||||
errors ++;
|
|
||||||
|
|
||||||
fputs("ttfGetAscent: ", stdout);
|
|
||||||
if ((intvalue = ttfGetAscent(font)) > 0)
|
|
||||||
{
|
|
||||||
printf("PASS (%d)\n", intvalue);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("FAIL (%d)\n", intvalue);
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetBounds: ", stdout);
|
|
||||||
if (ttfGetBounds(font, &bounds))
|
|
||||||
{
|
|
||||||
printf("PASS (%g %g %g %g)\n", bounds.left, bounds.bottom, bounds.right, bounds.top);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("FAIL");
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetCapHeight: ", stdout);
|
|
||||||
if ((intvalue = ttfGetCapHeight(font)) > 0)
|
|
||||||
{
|
|
||||||
printf("PASS (%d)\n", intvalue);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("FAIL (%d)\n", intvalue);
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetCopyright: ", stdout);
|
|
||||||
if ((value = ttfGetCopyright(font)) != NULL)
|
|
||||||
{
|
|
||||||
printf("PASS (%s)\n", value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("WARNING (no copyright found)");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < (int)(sizeof(strings) / sizeof(strings[0])); i ++)
|
|
||||||
{
|
|
||||||
printf("ttfGetExtents(\"%s\"): ", strings[i]);
|
|
||||||
if (ttfGetExtents(font, 12.0f, strings[i], &extents))
|
|
||||||
{
|
|
||||||
printf("PASS (%.1f %.1f %.1f %.1f)\n", extents.left, extents.bottom, extents.right, extents.top);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("FAIL");
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetFamily: ", stdout);
|
|
||||||
if ((value = ttfGetFamily(font)) != NULL)
|
|
||||||
{
|
|
||||||
printf("PASS (%s)\n", value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("FAIL");
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetItalicAngle: ", stdout);
|
|
||||||
if ((realvalue = ttfGetItalicAngle(font)) >= -180.0 && realvalue <= 180.0)
|
|
||||||
{
|
|
||||||
printf("PASS (%g)\n", realvalue);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("FAIL (%g)\n", realvalue);
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetNumFonts: ", stdout);
|
|
||||||
if ((num_fonts = ttfGetNumFonts(font)) > 0)
|
|
||||||
{
|
|
||||||
printf("PASS (%u)\n", (unsigned)num_fonts);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("FAIL");
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetPostScriptName: ", stdout);
|
|
||||||
if ((value = ttfGetPostScriptName(font)) != NULL)
|
|
||||||
{
|
|
||||||
printf("PASS (%s)\n", value);
|
|
||||||
|
|
||||||
strncpy(psname, value, sizeof(psname) - 1);
|
|
||||||
psname[sizeof(psname) - 1] = '\0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("FAIL");
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetStretch: ", stdout);
|
|
||||||
if ((intvalue = (int)ttfGetStretch(font)) >= TTF_STRETCH_NORMAL && intvalue <= TTF_STRETCH_ULTRA_EXPANDED)
|
|
||||||
{
|
|
||||||
printf("PASS (%s)\n", stretches[intvalue]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("FAIL (%d)\n", intvalue);
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetStyle: ", stdout);
|
|
||||||
if ((style = ttfGetStyle(font)) >= TTF_STYLE_NORMAL && style <= TTF_STYLE_ITALIC)
|
|
||||||
{
|
|
||||||
printf("PASS (%s)\n", styles[style]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("FAIL");
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetVersion: ", stdout);
|
|
||||||
if ((value = ttfGetVersion(font)) != NULL)
|
|
||||||
{
|
|
||||||
printf("PASS (%s)\n", value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("FAIL");
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetWeight: ", stdout);
|
|
||||||
if ((weight = ttfGetWeight(font)) >= 0)
|
|
||||||
{
|
|
||||||
printf("PASS (%u)\n", (unsigned)weight);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("FAIL");
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetWidth(' '): ", stdout);
|
|
||||||
if ((intvalue = ttfGetWidth(font, ' ')) > 0)
|
|
||||||
{
|
|
||||||
printf("PASS (%d)\n", intvalue);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("FAIL (%d)\n", intvalue);
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfGetXHeight: ", stdout);
|
|
||||||
if ((intvalue = ttfGetXHeight(font)) > 0)
|
|
||||||
{
|
|
||||||
printf("PASS (%d)\n", intvalue);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("FAIL (%d)\n", intvalue);
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("ttfIsFixedPitch: ", stdout);
|
|
||||||
if (ttfIsFixedPitch(font))
|
|
||||||
puts("PASS (true)");
|
|
||||||
else
|
|
||||||
puts("PASS (false)");
|
|
||||||
|
|
||||||
ttfDelete(font);
|
|
||||||
font = NULL;
|
|
||||||
|
|
||||||
// Now copy the font to memory and open it that way...
|
|
||||||
printf("fopen(\"%s\", \"rb\"): ", filename);
|
|
||||||
if ((fp = fopen(filename, "rb")) == NULL)
|
|
||||||
{
|
|
||||||
printf("FAIL (%s)\n", strerror(errno));
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("PASS (%d)\n", fileno(fp));
|
|
||||||
printf("fstat(%d): ", fileno(fp));
|
|
||||||
if (fstat(fileno(fp), &fileinfo))
|
|
||||||
{
|
|
||||||
printf("FAIL (%s)\n", strerror(errno));
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("PASS (%lu bytes)\n", (unsigned long)fileinfo.st_size);
|
|
||||||
|
|
||||||
fputs("malloc(): ", stdout);
|
|
||||||
if ((data = malloc((size_t)fileinfo.st_size)) == NULL)
|
|
||||||
{
|
|
||||||
printf("FAIL (%s)\n", strerror(errno));
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("PASS");
|
|
||||||
fputs("fread(): ", stdout);
|
|
||||||
if (fread(data, (size_t)fileinfo.st_size, 1, fp) != 1)
|
|
||||||
{
|
|
||||||
printf("FAIL (%s)\n", strerror(errno));
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("PASS");
|
|
||||||
fputs("ttfCreateData(): ", stdout);
|
|
||||||
if ((font = ttfCreateData(data, (size_t)fileinfo.st_size, /*idx*/0, error_cb, /*err_data*/NULL)) == NULL)
|
|
||||||
{
|
|
||||||
puts("FAIL");
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("PASS");
|
|
||||||
|
|
||||||
fputs("ttfGetPostScriptName: ", stdout);
|
|
||||||
if ((value = ttfGetPostScriptName(font)) != NULL)
|
|
||||||
{
|
|
||||||
if (!strcmp(value, psname))
|
|
||||||
{
|
|
||||||
printf("PASS (%s)\n", value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("FAIL (got \"%s\", expected \"%s\")\n", value, psname);
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts("FAIL");
|
|
||||||
errors ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp)
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
free(data);
|
|
||||||
|
|
||||||
ttfDelete(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (errors);
|
|
||||||
}
|
|
||||||
1
ttf
Submodule
1
ttf
Submodule
Submodule ttf added at f2e6f45ab3
111
ttf.h
111
ttf.h
@@ -1,111 +0,0 @@
|
|||||||
//
|
|
||||||
// Header file for TTF library
|
|
||||||
//
|
|
||||||
// https://github.com/michaelrsweet/ttf
|
|
||||||
//
|
|
||||||
// Copyright © 2018-2025 by Michael R Sweet.
|
|
||||||
//
|
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
|
||||||
// information.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef TTF_H
|
|
||||||
# define TTF_H
|
|
||||||
# include <stddef.h>
|
|
||||||
# include <stdbool.h>
|
|
||||||
# include <sys/types.h>
|
|
||||||
# ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
# endif // __cplusplus
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Types...
|
|
||||||
//
|
|
||||||
|
|
||||||
typedef struct _ttf_s ttf_t; // Font object
|
|
||||||
|
|
||||||
typedef void (*ttf_err_cb_t)(void *data, const char *message);
|
|
||||||
// Font error callback
|
|
||||||
|
|
||||||
typedef enum ttf_stretch_e // Font stretch
|
|
||||||
{
|
|
||||||
TTF_STRETCH_NORMAL, // normal
|
|
||||||
TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed
|
|
||||||
TTF_STRETCH_EXTRA_CONDENSED, // extra-condensed
|
|
||||||
TTF_STRETCH_CONDENSED, // condensed
|
|
||||||
TTF_STRETCH_SEMI_CONDENSED, // semi-condensed
|
|
||||||
TTF_STRETCH_SEMI_EXPANDED, // semi-expanded
|
|
||||||
TTF_STRETCH_EXPANDED, // expanded
|
|
||||||
TTF_STRETCH_EXTRA_EXPANDED, // extra-expanded
|
|
||||||
TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded
|
|
||||||
} ttf_stretch_t;
|
|
||||||
|
|
||||||
typedef enum ttf_style_e // Font style
|
|
||||||
{
|
|
||||||
TTF_STYLE_NORMAL, // Normal font
|
|
||||||
TTF_STYLE_ITALIC, // Italic font
|
|
||||||
TTF_STYLE_OBLIQUE // Oblique (angled) font
|
|
||||||
} ttf_style_t;
|
|
||||||
|
|
||||||
typedef enum ttf_variant_e // Font variant
|
|
||||||
{
|
|
||||||
TTF_VARIANT_NORMAL, // Normal font
|
|
||||||
TTF_VARIANT_SMALL_CAPS // Font whose lowercase letters are small capitals
|
|
||||||
} ttf_variant_t;
|
|
||||||
|
|
||||||
typedef enum ttf_weight_e // Font weight
|
|
||||||
{
|
|
||||||
TTF_WEIGHT_100 = 100, // Weight 100 (Thin)
|
|
||||||
TTF_WEIGHT_200 = 200, // Weight 200 (Extra/Ultra-Light)
|
|
||||||
TTF_WEIGHT_300 = 300, // Weight 300 (Light)
|
|
||||||
TTF_WEIGHT_400 = 400, // Weight 400 (Normal/Regular)
|
|
||||||
TTF_WEIGHT_500 = 500, // Weight 500 (Medium)
|
|
||||||
TTF_WEIGHT_600 = 600, // Weight 600 (Semi/Demi-Bold)
|
|
||||||
TTF_WEIGHT_700 = 700, // Weight 700 (Bold)
|
|
||||||
TTF_WEIGHT_800 = 800, // Weight 800 (Extra/Ultra-Bold)
|
|
||||||
TTF_WEIGHT_900 = 900 // Weight 900 (Black/Heavy)
|
|
||||||
} ttf_weight_t;
|
|
||||||
|
|
||||||
typedef struct ttf_rect_s // Bounding rectangle
|
|
||||||
{
|
|
||||||
float left; // Left offset
|
|
||||||
float top; // Top offset
|
|
||||||
float right; // Right offset
|
|
||||||
float bottom; // Bottom offset
|
|
||||||
} ttf_rect_t;
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Functions...
|
|
||||||
//
|
|
||||||
|
|
||||||
extern ttf_t *ttfCreate(const char *filename, size_t idx, ttf_err_cb_t err_cb, void *err_data);
|
|
||||||
extern ttf_t *ttfCreateData(const void *data, size_t data_size, size_t idx, ttf_err_cb_t err_cb, void *err_data);
|
|
||||||
extern void ttfDelete(ttf_t *font);
|
|
||||||
extern int ttfGetAscent(ttf_t *font);
|
|
||||||
extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds);
|
|
||||||
extern const int *ttfGetCMap(ttf_t *font, size_t *num_cmap);
|
|
||||||
extern int ttfGetCapHeight(ttf_t *font);
|
|
||||||
extern const char *ttfGetCopyright(ttf_t *font);
|
|
||||||
extern int ttfGetDescent(ttf_t *font);
|
|
||||||
extern ttf_rect_t *ttfGetExtents(ttf_t *font, float size, const char *s, ttf_rect_t *extents);
|
|
||||||
extern const char *ttfGetFamily(ttf_t *font);
|
|
||||||
extern float ttfGetItalicAngle(ttf_t *font);
|
|
||||||
extern int ttfGetMaxChar(ttf_t *font);
|
|
||||||
extern int ttfGetMinChar(ttf_t *font);
|
|
||||||
extern size_t ttfGetNumFonts(ttf_t *font);
|
|
||||||
extern const char *ttfGetPostScriptName(ttf_t *font);
|
|
||||||
extern ttf_stretch_t ttfGetStretch(ttf_t *font);
|
|
||||||
extern ttf_style_t ttfGetStyle(ttf_t *font);
|
|
||||||
extern const char *ttfGetVersion(ttf_t *font);
|
|
||||||
extern int ttfGetWidth(ttf_t *font, int ch);
|
|
||||||
extern ttf_weight_t ttfGetWeight(ttf_t *font);
|
|
||||||
extern int ttfGetXHeight(ttf_t *font);
|
|
||||||
extern bool ttfIsFixedPitch(ttf_t *font);
|
|
||||||
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
|
||||||
}
|
|
||||||
# endif // __cplusplus
|
|
||||||
#endif // !TTF_H
|
|
||||||
Reference in New Issue
Block a user