Compare commits
189 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a81732f3b | ||
|
|
96840e97c5 | ||
|
|
d6e4570c2e | ||
|
|
73e3805aea | ||
|
|
d4c3e5ac13 | ||
|
|
7d43cabbe0 | ||
|
|
baa9fca941 | ||
|
|
d9444880c5 | ||
|
|
15f197d030 | ||
|
|
d03e5ee5d9 | ||
|
|
2837cafd41 | ||
|
|
c7bf1695fd | ||
|
|
14d844e436 | ||
|
|
ee42352228 | ||
|
|
700f7a011b | ||
|
|
3eb9c4a13f | ||
|
|
c7103e9558 | ||
|
|
e9ba25c0da | ||
|
|
a6160e7f6f | ||
|
|
390e8cef8f | ||
|
|
78c6852413 | ||
|
|
f4055f0d7a | ||
|
|
a37455c009 | ||
|
|
e61e08b5d2 | ||
|
|
a818dee123 | ||
|
|
ddb57bb754 | ||
|
|
61d7e0c68d | ||
|
|
c2f2cd6c37 | ||
|
|
b3aaf2e70f | ||
|
|
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 | ||
|
|
d5d089c560 | ||
|
|
23eb44e80b | ||
|
|
7d412cf855 | ||
|
|
597c9f8cda | ||
|
|
789b74af39 | ||
|
|
5032ce926e | ||
|
|
2977b82f35 | ||
|
|
b6008bae76 | ||
|
|
8459d97ff3 | ||
|
|
ed8be1f378 | ||
|
|
5edb5ad006 | ||
|
|
1b82f141e7 | ||
|
|
5699a52127 | ||
|
|
3c9a52a824 | ||
|
|
c272ddde3b | ||
|
|
26a92febc6 | ||
|
|
d82da750d9 | ||
|
|
e6fea00d74 | ||
|
|
815a45aec1 | ||
|
|
fe3ab5d67f | ||
|
|
abf2d6e7d8 | ||
|
|
2b68a0e0db | ||
|
|
c319f5a047 | ||
|
|
6e98635d91 | ||
|
|
04c52a74f6 | ||
|
|
c603a4e2b0 | ||
|
|
66f0c84621 | ||
|
|
98f6b90b53 | ||
|
|
c1ecf3a1ed | ||
|
|
f417a25121 | ||
|
|
1325c9cd61 | ||
|
|
71790bb6c4 | ||
|
|
a08614911a | ||
|
|
7bc3e84aed | ||
|
|
0194feca6f | ||
|
|
219a288488 | ||
|
|
2b4b20efe4 | ||
|
|
4032eef826 | ||
|
|
da58eec96d | ||
|
|
203a974682 | ||
|
|
7c69f13ba9 | ||
|
|
6dcb2cdced | ||
|
|
b1550fdc10 | ||
|
|
ef3a6cb1c0 | ||
|
|
0d1d5413ee | ||
|
|
f7db310942 | ||
|
|
99d03ddf9c | ||
|
|
fe122d557b | ||
|
|
2582052377 | ||
|
|
af5c412c96 | ||
|
|
e13526226a | ||
|
|
868794ab24 | ||
|
|
604396c0e7 | ||
|
|
156a184a45 | ||
|
|
eb0c785d6d | ||
|
|
359b65298e | ||
|
|
ccf3a90c97 | ||
|
|
c8017f50f6 | ||
|
|
4a1c53e31b | ||
|
|
5e8c3eb0b2 | ||
|
|
07ea310cd1 | ||
|
|
7ce8ec07ab | ||
|
|
f9ff913bb9 | ||
|
|
0c41a14919 | ||
|
|
57a01a7317 | ||
|
|
5b08046ece | ||
|
|
d1bf9a92dc | ||
|
|
749c0f845d | ||
|
|
cad8f450ab | ||
|
|
278ddb7fa7 | ||
|
|
1e6bb710e3 | ||
|
|
4ca93bd34f | ||
|
|
404ca72882 | ||
|
|
67704ce493 | ||
|
|
e983ba98d8 | ||
|
|
c23c6dec9a | ||
|
|
5e9617a742 | ||
|
|
09ee7d16c1 | ||
|
|
078985fc20 | ||
|
|
13fedfc424 | ||
|
|
c07927dc2d | ||
|
|
1393cd6c04 | ||
|
|
b278e33aac | ||
|
|
1116e929f7 | ||
|
|
c75611e274 | ||
|
|
c507cabbda | ||
|
|
81aeef46d2 | ||
|
|
ba7371b2e1 | ||
|
|
ec64af8b20 | ||
|
|
acd68df592 | ||
|
|
3d9c22aa49 | ||
|
|
3ae95f1545 | ||
|
|
cfdd6f55d9 | ||
|
|
06f38edcc7 | ||
|
|
76c1cc694f | ||
|
|
4219b8fd77 | ||
|
|
064e7fa473 | ||
|
|
ea9b7843fc | ||
|
|
755efe08da | ||
|
|
0391df5bbd | ||
|
|
49efd97cab | ||
|
|
d7eb1fc540 | ||
|
|
7afefda326 | ||
|
|
cbea3ecc2a | ||
|
|
130cef8702 | ||
|
|
0bd9edc845 | ||
|
|
fe755eac3d | ||
|
|
8cca645835 | ||
|
|
b8ea9ea064 | ||
|
|
2874022aa4 | ||
|
|
3befcf2fd5 | ||
|
|
3b2f7e21d9 | ||
|
|
7e01069c5a | ||
|
|
88839ccb56 | ||
|
|
ebd5aab39b | ||
|
|
71d33c03ff | ||
|
|
cfe91b4ea2 |
16
.github/workflows/build.yml
vendored
@@ -13,7 +13,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Update Build Environment
|
||||
run: sudo apt-get update --fix-missing -y
|
||||
- name: Install Prerequisites
|
||||
@@ -21,7 +23,7 @@ jobs:
|
||||
- name: Configure PDFio
|
||||
run: ./configure --enable-debug --enable-sanitizer --enable-maintainer
|
||||
- name: Build PDFio
|
||||
run: make "COMMONFLAGS=-g -fsanitize=address"
|
||||
run: make
|
||||
- name: Test PDFio
|
||||
env:
|
||||
ASAN_OPTIONS: leak_check_at_exit=false
|
||||
@@ -37,7 +39,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Configure PDFio
|
||||
run: ./configure --enable-debug --enable-sanitizer --enable-maintainer
|
||||
- name: Build PDFio
|
||||
@@ -53,9 +57,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Setup MSBuild
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
- name: Nuget Restore
|
||||
run: nuget restore pdfio.sln
|
||||
- name: Build PDFio
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
4
.github/workflows/coverity.yml
vendored
@@ -8,7 +8,9 @@ jobs:
|
||||
environment: Coverity
|
||||
steps:
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Update Build Environment
|
||||
run: sudo apt-get update --fix-missing -y
|
||||
- name: Install Prerequisites
|
||||
|
||||
3
.gitignore
vendored
@@ -16,6 +16,7 @@
|
||||
/examples/md2pdf
|
||||
/examples/pdf2text
|
||||
/examples/pdfioinfo
|
||||
/examples/pdfiomerge
|
||||
/Makefile
|
||||
/packages
|
||||
/pdfio.pc
|
||||
@@ -24,5 +25,5 @@
|
||||
/pdfio-*.zip*
|
||||
/testpdfio
|
||||
/testpdfio-*.pdf
|
||||
/testttf
|
||||
/testfiles/testpdfio-*.pdf
|
||||
/x64
|
||||
|
||||
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "ttf"]
|
||||
path = ttf
|
||||
url = https://github.com/michaelrsweet/ttf.git
|
||||
114
CHANGES.md
@@ -1,6 +1,120 @@
|
||||
Changes in PDFio
|
||||
================
|
||||
|
||||
|
||||
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 support for Unicode filenames on Windows (Issue #18)
|
||||
- Added support for writing object streams (Issue #101)
|
||||
- Added support for GIF files (Issue #145)
|
||||
- Added support for WebP files (Issue #144)
|
||||
- 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 - 2026-02-15
|
||||
-------------------
|
||||
|
||||
- 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)
|
||||
- Changed how duplicate objects are handled in PDF files (Issue #155)
|
||||
- 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 bug when converting Unicode characters above plane 0 (issue #159)
|
||||
- Fixed a Clang warning.
|
||||
|
||||
|
||||
v1.6.1 - 2025-12-26
|
||||
-------------------
|
||||
|
||||
- Added missing input checking to `pdfioFileCreateFontObjFromBase` function.
|
||||
- Updated support for UTF-16 strings (Issue #141)
|
||||
- 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 some clang warnings.
|
||||
- Fixed the generated pkg-config file.
|
||||
|
||||
|
||||
|
||||
v1.6.0 - 2025-10-06
|
||||
-------------------
|
||||
|
||||
- Added generation of XMP metadata when writing PDFs (Issue #103)
|
||||
- Added "standard" `PDFIO_CS_CGATS001` color space for non-device CMYK
|
||||
(Issue #104)
|
||||
- Added CMYK JPEG support with embedded ICC profiles or using the CGATS001
|
||||
profile (Issue #104)
|
||||
- Added `pdfioFileAddOutputIntent` function to adding output intent information
|
||||
to a PDF file (Issue #104)
|
||||
- Added explicit support for warning messages (Issue #118)
|
||||
- Added `pdfioFileCreateFontObjFromData` function for embedding fonts in
|
||||
memory (Issue #120)
|
||||
- Added support for specifying PDF/A versions for created PDF files (Issue #122)
|
||||
- Added `pdfioContentBeginMarked` and `pdfioContentEndMarked` functions for
|
||||
creating tagged PDF content (Issue #123)
|
||||
- Added `pdfioFileGetLanguage` and `pdfioFileSetLanguage` functions for getting
|
||||
and setting the default/primary language of a PDF file (Issue #124)
|
||||
- Now add default grayscale, RGB, and CMYK profile resources to pages as needed
|
||||
(Issue #104)
|
||||
- Fixed unsupported filter error (Issue #130)
|
||||
- Fixed EOF comment written to the PDF (Issue #136)
|
||||
- Fixed TTF cmap underflow error.
|
||||
- Fixed some Clang warnings.
|
||||
|
||||
|
||||
v1.5.4 - 2025-08-26
|
||||
-------------------
|
||||
|
||||
- Updated indirect reference reading code to limit the range of generation
|
||||
numbers.
|
||||
- Updated error messages for too large tokens (Issue #131)
|
||||
- Fixed a JPEG copy bug (Issue #132)
|
||||
|
||||
|
||||
v1.5.3 - 2025-05-03
|
||||
-------------------
|
||||
|
||||
- Fixed decryption of PDF files "protected" by 40-bit RC4 (Issue #42)
|
||||
- Fixed decryption of UTF-16 strings (Issue #42)
|
||||
- Fixed decryption of PDF files with large permission values.
|
||||
- Fixed support for EncryptMetadata key in the encryption dictionary.
|
||||
- Fixed `pdfioObjCopy` and `pdfioPageCopy` to properly identify the source PDF
|
||||
file being used (Issue #125)
|
||||
|
||||
|
||||
v1.5.2 - 2025-04-12
|
||||
-------------------
|
||||
|
||||
- Updated maximum allowed PDF string size to 64k (Issue #117)
|
||||
- Updated dictionary reading code to discard duplicate key/value pairs with a
|
||||
warning message (Issue #118)
|
||||
- Fixed form detection in `pdfioinfo` example code (Issue #114)
|
||||
- Fixed parsing of certain date/time values (Issue #115)
|
||||
- Fixed support for empty name values (Issue #116)
|
||||
- Fixed range checking in `pdfioImageGetBytesPerLine` (Issue #121)
|
||||
|
||||
|
||||
v1.5.1 - 2025-03-28
|
||||
-------------------
|
||||
|
||||
- Fixed output of special characters in name values (Issue #106)
|
||||
- Fixed output of special characters in string values (Issue #107)
|
||||
- Fixed output of large integers in dictionaries (Issue #108)
|
||||
- Fixed handling of 0-length streams (Issue #111)
|
||||
- Fixed detection of UTF-16 Big-Endian strings (Issue #112)
|
||||
|
||||
|
||||
v1.5.0 - 2025-03-06
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -110,10 +110,11 @@ same guidelines as allowed by the language.
|
||||
|
||||
### Source Files
|
||||
|
||||
All source files names must be 16 characters or less in length to ensure
|
||||
compatibility with older UNIX filesystems. Source files containing functions
|
||||
have an extension of ".c" for C source files. All "include" files have an
|
||||
extension of ".h". Tabs are set to 8 characters or columns.
|
||||
All source files names must be lowercase and should be 16 characters or less in
|
||||
length to ensure compatibility with older UNIX filesystems. Source files
|
||||
containing functions have an extension of ".c" for C source files. All
|
||||
"include" files have an extension of ".h". Tabs are set every 8 characters,
|
||||
columns, or spaces, with an indentation of 2 spaces in code.
|
||||
|
||||
The top of each source file contains a header giving the purpose or nature of
|
||||
the source file and the copyright and licensing notice:
|
||||
@@ -141,8 +142,8 @@ private API header file will include the corresponding public API header file.
|
||||
All source code utilizes block comments within functions to describe the
|
||||
operations being performed by a group of statements; avoid putting a comment
|
||||
per line unless absolutely necessary, and then consider refactoring the code
|
||||
so that it is not necessary. C source files use the C99 comment format
|
||||
("// comment"):
|
||||
so that it is not necessary. C source files typically use the C99 comment
|
||||
format ("// comment"):
|
||||
|
||||
// Clear the state array before we begin...
|
||||
for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
|
||||
@@ -159,6 +160,17 @@ so that it is not necessary. C source files use the C99 comment format
|
||||
sleep(1);
|
||||
} while (i == (sizeof(array) / sizeof(array[0])));
|
||||
|
||||
When passing literal argument values to functions, the argument name should be
|
||||
supplied as an inline comment:
|
||||
|
||||
// This function call lacks any inline comments so it is hard to
|
||||
// know what the numbers mean!
|
||||
do_something(filename, 1, 42);
|
||||
|
||||
// This uses inline comments to specify what the numbers mean and
|
||||
// makes the code easier to read and maintain:
|
||||
do_something(filename, /*initial_value*/1, /*count*/42);
|
||||
|
||||
|
||||
### Indentation
|
||||
|
||||
@@ -256,16 +268,16 @@ Return/output values are indicated using an "O" prefix, input values are
|
||||
indicated using the "I" prefix, and values that are both input and output use
|
||||
the "IO" prefix for the corresponding in-line comment.
|
||||
|
||||
The [`codedoc` documentation generator][1] also understands the following
|
||||
The [`codedoc` documentation generator][CODEDOC] also understands the following
|
||||
special text in the function description comment:
|
||||
|
||||
@deprecated@ - Marks the function as deprecated (not recommended
|
||||
for new development and scheduled for removal)
|
||||
@since version@ - Marks the function as new in the specified version.
|
||||
@since VERSION@ - Marks the function as new in the specified version.
|
||||
@private@ - Marks the function as private (same as starting the
|
||||
function name with an underscore)
|
||||
|
||||
[1]: https://www.msweet.org/codedoc
|
||||
[CODEDOC]: https://www.msweet.org/codedoc
|
||||
|
||||
|
||||
### Variables
|
||||
@@ -373,11 +385,13 @@ The following variables are defined in the makefile:
|
||||
|
||||
- `AR`; the static library archiver command,
|
||||
- `ARFLAGS`; options for the static library archiver,
|
||||
- `BUILDROOT`: the destination root directory when installing - also picks up
|
||||
the value of the `DESTDIR`, `DSTROOT`, and/or `RPM_BUILD_ROOT` environment
|
||||
variables,
|
||||
- `CC`; the C compiler command,
|
||||
- `CFLAGS`; options for the C compiler,
|
||||
- `CODESIGN_IDENTITY`: the code signing identity,
|
||||
- `CPPFLAGS`; options for the C preprocessor,
|
||||
- `DESTDIR`/`DSTROOT`: the destination root directory when installing.
|
||||
- `DSO`; the shared library building command,
|
||||
- `DSOFLAGS`; options for the shared library building command,
|
||||
- `LDFLAGS`; options for the linker,
|
||||
@@ -395,5 +409,6 @@ The following standard targets are defined in the makefile:
|
||||
- `all`; creates the static library and unit test program.
|
||||
- `clean`; removes all target programs libraries, documentation files, and
|
||||
object files,
|
||||
- `doc`; creates the library documentation files using [`codedoc`][CODEDOC],
|
||||
- `install`; installs all distribution files in their corresponding locations.
|
||||
- `test`; runs the unit test program, building it as needed.
|
||||
|
||||
21
EXAMPLES.md
@@ -2,17 +2,12 @@ PDFio Examples
|
||||
==============
|
||||
|
||||
The "examples" subdirectory contains example code showing how to do different
|
||||
things with PDFio.
|
||||
things with PDFio:
|
||||
|
||||
|
||||
code128.c
|
||||
---------
|
||||
|
||||
This example shows how to embed and use a barcode font.
|
||||
|
||||
|
||||
md2pdf.c
|
||||
--------
|
||||
|
||||
This example shows how to generate pages with multiple fonts, embedded images,
|
||||
and headers and footers.
|
||||
- `code128.c`: Shows how to embed and use a barcode font.
|
||||
- `image2pdf.c`: Shows how to embed and use an image file.
|
||||
- `md2pdf.c`: Shows how to generate pages with multiple fonts, embedded images,
|
||||
and headers and footers.
|
||||
- `pdf2text.c`: Shows how to extract plain text from a PDF.
|
||||
- `pdfioinfo.c`: Shows how to extract metadata from a PDF.
|
||||
- `pdfiomerge.c`: Shows how to merge two or more PDFs.
|
||||
|
||||
135
INSTALL.md
Normal file
@@ -0,0 +1,135 @@
|
||||
Building, Testing, and Installing PDFio
|
||||
=======================================
|
||||
|
||||
This file describes how to compile, test, and install the PDFio library from
|
||||
source code. For more information on PDFio see the file called `README.md`.
|
||||
|
||||
|
||||
Getting the Code
|
||||
----------------
|
||||
|
||||
> Note: Do not use the ZIP file available via the Github "Code" button on the
|
||||
> main project page, as that archive is missing the TTF submodule and will not
|
||||
> compile.
|
||||
|
||||
The source code is available in release tarballs or via the Github repository.
|
||||
For a release tarball, run the following commands:
|
||||
|
||||
tar xvzf pdfio-VERSION.tar.gz
|
||||
cd pdfio-VERSION
|
||||
|
||||
Similarly, the release ZIP file can be extracted with the following commands:
|
||||
|
||||
unzip pdfio-VERSION.zip
|
||||
cd pdfio-VERSION
|
||||
|
||||
From the Github sources, clone the repository with the `--recurse-submodules`
|
||||
option *or* use the `git submodule` command:
|
||||
|
||||
git clone --recurse-submodules git@github.com:michaelrsweet/pdfio.git
|
||||
cd pdfio
|
||||
|
||||
git clone git@github.com:michaelrsweet/pdfio.git
|
||||
cd pdfio
|
||||
git submodule update --init --recursive
|
||||
|
||||
To update an already-cloned repository:
|
||||
|
||||
git pull
|
||||
git submodule update --init --recursive
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
PDFio requires the following to build the software:
|
||||
|
||||
- A C99 compiler such as Clang, GCC, or MS Visual C
|
||||
- A POSIX-compliant `make` program
|
||||
- A POSIX-compliant `sh` program
|
||||
- libpng (<https://www.libpng.org/>) 1.6 or later for full PNG image support
|
||||
(optional)
|
||||
- libwebp (<https://developers.google.com/speed/webp>) 1.0 or later for WebP
|
||||
image support (optional)
|
||||
- ZLIB (<https://www.zlib.net/>) 1.1 or later for compression support
|
||||
|
||||
IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.
|
||||
|
||||
On a stock Ubuntu install, the following command will install the various
|
||||
prerequisites:
|
||||
|
||||
sudo apt-get install build-essential libpng-dev libwebp-dev zlib1g-dev
|
||||
|
||||
|
||||
Building and Installing on Linux/Unix
|
||||
-------------------------------------
|
||||
|
||||
PDFio uses a configure script on Unix systems to generate a makefile:
|
||||
|
||||
./configure
|
||||
|
||||
If you want a shared library, run:
|
||||
|
||||
./configure --enable-shared
|
||||
|
||||
The default installation location is "/usr/local". Pass the `--prefix` option
|
||||
to make to install it to another location:
|
||||
|
||||
./configure --prefix=/some/other/directory
|
||||
|
||||
Other configure options can be discovered by using the `--help` option:
|
||||
|
||||
./configure --help
|
||||
|
||||
Once configured, run the following command to build the library:
|
||||
|
||||
make all
|
||||
|
||||
Finally, run the following command to install the library, documentation, and
|
||||
examples on the local system:
|
||||
|
||||
sudo make install
|
||||
|
||||
Use the `BUILDROOT` variable to install to an alternate root directory:
|
||||
|
||||
sudo make BUILDROOT=/some/other/root/directory install
|
||||
|
||||
> Note: PDFio also supports the GNU `DSTROOT`, Apple/Darwin `DESTDIR`, and
|
||||
> Red Hat `RPM_BUILD_ROOT` variables to specify an alternate root directory.
|
||||
|
||||
|
||||
### Running the Unit Tests
|
||||
|
||||
PDFio includes a unit test program that thoroughly tests the library. Type the
|
||||
following to run the unit tests:
|
||||
|
||||
make test
|
||||
|
||||
Detailed test results are saved to the "test.log" file.
|
||||
|
||||
|
||||
Building on Windows with Visual Studio
|
||||
--------------------------------------
|
||||
|
||||
The Visual Studio solution (`pdfio.sln`) is provided for Windows developers and
|
||||
generates the PDFIO1 DLL. You can also use NuGet to install the `pdfio_native`
|
||||
package.
|
||||
|
||||
You can build and run the `testpdfio` unit tests target from within Visual
|
||||
Studio to verify the functioning of the library.
|
||||
|
||||
|
||||
Building on macOS with Xcode
|
||||
----------------------------
|
||||
|
||||
The Xcode project (`pdfio.xcodeproj`) is provided for macOS developer which
|
||||
generates a static library that will be installed under "/usr/local". Run the
|
||||
following command to build and install PDFio on macOS:
|
||||
|
||||
sudo xcodebuild install
|
||||
|
||||
Alternately you can add the Xcode project to a workspace and reference the PDFio
|
||||
library target as a dependency in your own project.
|
||||
|
||||
You can build and run the `testpdfio` unit tests target from within Xcode to
|
||||
verify the functioning of the library.
|
||||
49
Makefile.in
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# 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
|
||||
# information.
|
||||
@@ -69,6 +69,8 @@ top_srcdir = @top_srcdir@
|
||||
|
||||
BUILDROOT = $(DSTROOT)$(RPM_BUILD_ROOT)$(DESTDIR)
|
||||
|
||||
TTFDIR = @TTFDIR@
|
||||
|
||||
|
||||
# Build commands...
|
||||
.SUFFIXES: .c .h .o
|
||||
@@ -89,6 +91,7 @@ PUBOBJS = \
|
||||
pdfio-crypto.o \
|
||||
pdfio-dict.o \
|
||||
pdfio-file.o \
|
||||
pdfio-lzw.o \
|
||||
pdfio-md5.o \
|
||||
pdfio-object.o \
|
||||
pdfio-page.o \
|
||||
@@ -99,17 +102,14 @@ PUBOBJS = \
|
||||
pdfio-token.o \
|
||||
pdfio-value.o
|
||||
LIBOBJS = \
|
||||
$(PUBOBJS) \
|
||||
ttf.o
|
||||
$(PUBOBJS)
|
||||
OBJS = \
|
||||
$(LIBOBJS) \
|
||||
testpdfio.o \
|
||||
testttf.o
|
||||
testpdfio.o
|
||||
TARGETS = \
|
||||
$(LIBPDFIO) \
|
||||
$(LIBPDFIO_STATIC) \
|
||||
testpdfio \
|
||||
testttf
|
||||
testpdfio
|
||||
DOCFILES = \
|
||||
doc/pdfio.html \
|
||||
doc/pdfio-512.png \
|
||||
@@ -135,16 +135,30 @@ EXAMPLES = \
|
||||
|
||||
|
||||
# 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:
|
||||
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)
|
||||
|
||||
|
||||
# Install everything
|
||||
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)...
|
||||
$(INSTALL) -d -m 755 $(BUILDROOT)$(includedir)
|
||||
for file in $(PUBHEADERS); do \
|
||||
@@ -186,9 +200,8 @@ install: $(TARGETS)
|
||||
|
||||
|
||||
# Test everything
|
||||
test: testpdfio testttf
|
||||
./testttf 2>test.log
|
||||
./testpdfio 2>>test.log
|
||||
test: testpdfio
|
||||
./testpdfio 2>test.log
|
||||
LANG=fr_FR.UTF-8 ./testpdfio 2>>test.log
|
||||
|
||||
|
||||
@@ -222,6 +235,7 @@ pdfio1.def: $(LIBOBJS) Makefile
|
||||
echo "LIBRARY pdfio1" >$@
|
||||
echo "VERSION $(PDFIO_VERSION_MAJOR).$(PDFIO_VERSION_MINOR)" >>$@
|
||||
echo "EXPORTS" >>$@
|
||||
echo "_pdfio_win32_open" >>$@
|
||||
nm $(LIBOBJS) 2>/dev/null | grep "T _" | awk '{print $$3}' | \
|
||||
grep -v '^_ttf' | sed -e '1,$$s/^_//' | sort >>$@
|
||||
|
||||
@@ -232,23 +246,16 @@ testpdfio: testpdfio.o libpdfio.a
|
||||
$(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
|
||||
$(OBJS): pdfio.h pdfio-private.h Makefile
|
||||
pdfio-content.o: pdfio-content.h ttf.h
|
||||
testttf.o: ttf.h
|
||||
ttf.o: ttf.h
|
||||
pdfio-content.o: pdfio-content.h
|
||||
testpdfio.o: test-internal.h
|
||||
|
||||
|
||||
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
||||
DOCFLAGS = \
|
||||
--author "Michael R Sweet" \
|
||||
--copyright "Copyright (c) 2021-2025 by Michael R Sweet" \
|
||||
--copyright "Copyright (c) 2021-2026 by Michael R Sweet" \
|
||||
--docversion $(PDFIO_VERSION)
|
||||
|
||||
.PHONY: doc
|
||||
|
||||
2
NOTICE
@@ -1,6 +1,6 @@
|
||||
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:
|
||||
================================================
|
||||
|
||||
92
README.md
@@ -1,10 +1,10 @@
|
||||
pdfio - PDF Read/Write Library
|
||||
PDFio - PDF Read/Write Library
|
||||
==============================
|
||||
|
||||

|
||||

|
||||
[](https://github.com/michaelrsweet/pdfio/actions/workflows/build.yml)
|
||||
[](https://scan.coverity.com/projects/michaelrsweet-pdfio)
|
||||
[](https://github.com/michaelrsweet/pdfio/actions/workflows/build.yml)
|
||||
[](https://scan.coverity.com/projects/michaelrsweet-pdfio)
|
||||
|
||||
PDFio is a simple C library for reading and writing PDF files. The primary
|
||||
goals of PDFio are:
|
||||
@@ -20,77 +20,29 @@ goals of PDFio are:
|
||||
PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF
|
||||
RIP or viewer could be written using it.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
PDFio requires the following to build the software:
|
||||
|
||||
- A C99 compiler such as Clang, GCC, or MS Visual C
|
||||
- A POSIX-compliant `make` program
|
||||
- ZLIB (<https://www.zlib.net>) 1.1 or higher
|
||||
|
||||
IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.
|
||||
Copyright © 2021-2026 by Michael R Sweet. PDFio is licensed under the Apache
|
||||
License Version 2.0 with an (optional) exception to allow linking against GNU
|
||||
GPL2-only software. See the files `LICENSE` and `NOTICE` for more information.
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
Reading the Documentation
|
||||
-------------------------
|
||||
|
||||
See the man page (`pdfio.3`) and full HTML documentation (`pdfio.html`) for
|
||||
information on using PDFio.
|
||||
Initial documentation to get you started is provided in the root directory of
|
||||
the PDFio sources:
|
||||
|
||||
- `CHANGES.md`: A list of changes for each release of PDFio.
|
||||
- `CODE_OF_CONDUCT.md`: Code of conduct for the project.
|
||||
- `CONTRIBUTING.md`: Guidelines for contributing to the project.
|
||||
- `INSTALL.md`: Instructions for building, testing, and installing PDFio.
|
||||
- `LICENSE`: The PDFio license agreement (Apache 2.0).
|
||||
- `NOTICE`: Copyright notices and exceptions to the PDFio license agreement.
|
||||
- `README.md`: This file.
|
||||
- `SECURITY.md`: How (and when) to report security issues.
|
||||
|
||||
Installing PDFio
|
||||
----------------
|
||||
You will find the PDFio documentation in HTML, EPUB, and man formats in the
|
||||
`doc` directory.
|
||||
|
||||
PDFio uses a configure script on Unix systems to generate a makefile:
|
||||
Examples can be found in the `examples` directory.
|
||||
|
||||
./configure
|
||||
|
||||
If you want a shared library, run:
|
||||
|
||||
./configure --enable-shared
|
||||
|
||||
The default installation location is "/usr/local". Pass the `--prefix` option
|
||||
to make to install it to another location:
|
||||
|
||||
./configure --prefix=/some/other/directory
|
||||
|
||||
Once configured, run the following to make the library:
|
||||
|
||||
make all
|
||||
|
||||
To test it, run:
|
||||
|
||||
make test
|
||||
|
||||
To install it, run:
|
||||
|
||||
sudo make install
|
||||
|
||||
|
||||
Visual Studio Project
|
||||
---------------------
|
||||
|
||||
The Visual Studio solution ("pdfio.sln") is provided for Windows developers and
|
||||
generates the PDFIO1 DLL. You can also use NuGet to install the `pdfio_native`
|
||||
package.
|
||||
|
||||
|
||||
Xcode Project
|
||||
-------------
|
||||
|
||||
There is also an Xcode project ("pdfio.xcodeproj") you can use on macOS which
|
||||
generates a static library that will be installed under "/usr/local" with:
|
||||
|
||||
sudo xcodebuild install
|
||||
|
||||
|
||||
Legal Stuff
|
||||
-----------
|
||||
|
||||
PDFio is Copyright © 2021-2025 by Michael R Sweet.
|
||||
|
||||
This software is licensed under the Apache License Version 2.0 with an
|
||||
(optional) exception to allow linking against GPL2/LGPL2 software. See the
|
||||
files "LICENSE" and "NOTICE" for more information.
|
||||
*Please read the documentation before asking questions.*
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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
|
||||
------------------------
|
||||
|
||||
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
|
||||
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
|
||||
<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
|
||||
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
|
||||
----------------------
|
||||
@@ -68,6 +91,9 @@ example:
|
||||
1.0b2
|
||||
1.0rc1
|
||||
|
||||
Pre-release code in a Git branch ("master", "v1.6.x", etc.) is similarly *not*
|
||||
production release code.
|
||||
|
||||
|
||||
PGP Public Key
|
||||
--------------
|
||||
|
||||
78
config.guess
vendored
@@ -1,10 +1,10 @@
|
||||
#! /bin/sh
|
||||
# Attempt to guess a canonical system name.
|
||||
# Copyright 1992-2022 Free Software Foundation, Inc.
|
||||
# Copyright 1992-2025 Free Software Foundation, Inc.
|
||||
|
||||
# shellcheck disable=SC2006,SC2268 # see below for rationale
|
||||
|
||||
timestamp='2022-09-17'
|
||||
timestamp='2025-07-10'
|
||||
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
@@ -47,7 +47,7 @@ me=`echo "$0" | sed -e 's,.*/,,'`
|
||||
usage="\
|
||||
Usage: $0 [OPTION]
|
||||
|
||||
Output the configuration name of the system \`$me' is run on.
|
||||
Output the configuration name of the system '$me' is run on.
|
||||
|
||||
Options:
|
||||
-h, --help print this help, then exit
|
||||
@@ -60,13 +60,13 @@ version="\
|
||||
GNU config.guess ($timestamp)
|
||||
|
||||
Originally written by Per Bothner.
|
||||
Copyright 1992-2022 Free Software Foundation, Inc.
|
||||
Copyright 1992-2025 Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
|
||||
help="
|
||||
Try \`$me --help' for more information."
|
||||
Try '$me --help' for more information."
|
||||
|
||||
# Parse command line
|
||||
while test $# -gt 0 ; do
|
||||
@@ -102,8 +102,8 @@ GUESS=
|
||||
# temporary files to be created and, as you can see below, it is a
|
||||
# headache to deal with in a portable fashion.
|
||||
|
||||
# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
|
||||
# use `HOST_CC' if defined, but it is deprecated.
|
||||
# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
|
||||
# use 'HOST_CC' if defined, but it is deprecated.
|
||||
|
||||
# Portable tmp directory creation inspired by the Autoconf team.
|
||||
|
||||
@@ -123,7 +123,7 @@ set_cc_for_build() {
|
||||
dummy=$tmp/dummy
|
||||
case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
|
||||
,,) echo "int x;" > "$dummy.c"
|
||||
for driver in cc gcc c89 c99 ; do
|
||||
for driver in cc gcc c17 c99 c89 ; do
|
||||
if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
|
||||
CC_FOR_BUILD=$driver
|
||||
break
|
||||
@@ -155,6 +155,9 @@ Linux|GNU|GNU/*)
|
||||
|
||||
set_cc_for_build
|
||||
cat <<-EOF > "$dummy.c"
|
||||
#if defined(__ANDROID__)
|
||||
LIBC=android
|
||||
#else
|
||||
#include <features.h>
|
||||
#if defined(__UCLIBC__)
|
||||
LIBC=uclibc
|
||||
@@ -162,6 +165,8 @@ Linux|GNU|GNU/*)
|
||||
LIBC=dietlibc
|
||||
#elif defined(__GLIBC__)
|
||||
LIBC=gnu
|
||||
#elif defined(__LLVM_LIBC__)
|
||||
LIBC=llvm
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
/* First heuristic to detect musl libc. */
|
||||
@@ -169,6 +174,7 @@ Linux|GNU|GNU/*)
|
||||
LIBC=musl
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
EOF
|
||||
cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
|
||||
eval "$cc_set_libc"
|
||||
@@ -459,7 +465,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
|
||||
UNAME_RELEASE=`uname -v`
|
||||
;;
|
||||
esac
|
||||
# Japanese Language versions have a version number like `4.1.3-JL'.
|
||||
# Japanese Language versions have a version number like '4.1.3-JL'.
|
||||
SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
|
||||
GUESS=sparc-sun-sunos$SUN_REL
|
||||
;;
|
||||
@@ -628,7 +634,8 @@ EOF
|
||||
sed 's/^ //' << EOF > "$dummy.c"
|
||||
#include <sys/systemcfg.h>
|
||||
|
||||
main()
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (!__power_pc())
|
||||
exit(1);
|
||||
@@ -712,7 +719,8 @@ EOF
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main ()
|
||||
int
|
||||
main ()
|
||||
{
|
||||
#if defined(_SC_KERNEL_BITS)
|
||||
long bits = sysconf(_SC_KERNEL_BITS);
|
||||
@@ -904,7 +912,7 @@ EOF
|
||||
fi
|
||||
;;
|
||||
*:FreeBSD:*:*)
|
||||
UNAME_PROCESSOR=`/usr/bin/uname -p`
|
||||
UNAME_PROCESSOR=`uname -p`
|
||||
case $UNAME_PROCESSOR in
|
||||
amd64)
|
||||
UNAME_PROCESSOR=x86_64 ;;
|
||||
@@ -976,7 +984,27 @@ EOF
|
||||
GUESS=$UNAME_MACHINE-unknown-minix
|
||||
;;
|
||||
aarch64:Linux:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
|
||||
set_cc_for_build
|
||||
CPU=$UNAME_MACHINE
|
||||
LIBCABI=$LIBC
|
||||
if test "$CC_FOR_BUILD" != no_compiler_found; then
|
||||
ABI=64
|
||||
sed 's/^ //' << EOF > "$dummy.c"
|
||||
#ifdef __ARM_EABI__
|
||||
#ifdef __ARM_PCS_VFP
|
||||
ABI=eabihf
|
||||
#else
|
||||
ABI=eabi
|
||||
#endif
|
||||
#endif
|
||||
EOF
|
||||
cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
|
||||
eval "$cc_set_abi"
|
||||
case $ABI in
|
||||
eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
|
||||
esac
|
||||
fi
|
||||
GUESS=$CPU-unknown-linux-$LIBCABI
|
||||
;;
|
||||
aarch64_be:Linux:*:*)
|
||||
UNAME_MACHINE=aarch64_be
|
||||
@@ -1042,6 +1070,15 @@ EOF
|
||||
k1om:Linux:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
|
||||
;;
|
||||
kvx:Linux:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
|
||||
;;
|
||||
kvx:cos:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-cos
|
||||
;;
|
||||
kvx:mbr:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-mbr
|
||||
;;
|
||||
loongarch32:Linux:*:* | loongarch64:Linux:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
|
||||
;;
|
||||
@@ -1197,7 +1234,7 @@ EOF
|
||||
GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
|
||||
;;
|
||||
i*86:OS/2:*:*)
|
||||
# If we were able to find `uname', then EMX Unix compatibility
|
||||
# If we were able to find 'uname', then EMX Unix compatibility
|
||||
# is probably installed.
|
||||
GUESS=$UNAME_MACHINE-pc-os2-emx
|
||||
;;
|
||||
@@ -1338,7 +1375,7 @@ EOF
|
||||
GUESS=ns32k-sni-sysv
|
||||
fi
|
||||
;;
|
||||
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
|
||||
PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
|
||||
# says <Richard.M.Bartel@ccMail.Census.GOV>
|
||||
GUESS=i586-unisys-sysv4
|
||||
;;
|
||||
@@ -1560,6 +1597,12 @@ EOF
|
||||
*:Unleashed:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
|
||||
;;
|
||||
x86_64:[Ii]ronclad:*:*|i?86:[Ii]ronclad:*:*)
|
||||
GUESS=$UNAME_MACHINE-pc-ironclad-mlibc
|
||||
;;
|
||||
*:[Ii]ronclad:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-ironclad-mlibc
|
||||
;;
|
||||
esac
|
||||
|
||||
# Do we have a guess based on uname results?
|
||||
@@ -1583,6 +1626,7 @@ cat > "$dummy.c" <<EOF
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
int
|
||||
main ()
|
||||
{
|
||||
#if defined (sony)
|
||||
@@ -1767,8 +1811,8 @@ fi
|
||||
exit 1
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp nil t)
|
||||
# time-stamp-start: "timestamp='"
|
||||
# time-stamp-format: "%:y-%02m-%02d"
|
||||
# time-stamp-format: "%Y-%02m-%02d"
|
||||
# time-stamp-end: "'"
|
||||
# End:
|
||||
|
||||
953
config.sub
vendored
446
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.71 for pdfio 1.5.0.
|
||||
# Generated by GNU Autoconf 2.71 for pdfio 1.7.0.
|
||||
#
|
||||
# Report bugs to <https://github.com/michaelrsweet/pdfio/issues>.
|
||||
#
|
||||
@@ -610,8 +610,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='pdfio'
|
||||
PACKAGE_TARNAME='pdfio'
|
||||
PACKAGE_VERSION='1.5.0'
|
||||
PACKAGE_STRING='pdfio 1.5.0'
|
||||
PACKAGE_VERSION='1.7.0'
|
||||
PACKAGE_STRING='pdfio 1.7.0'
|
||||
PACKAGE_BUGREPORT='https://github.com/michaelrsweet/pdfio/issues'
|
||||
PACKAGE_URL='https://www.msweet.org/pdfio'
|
||||
|
||||
@@ -647,13 +647,16 @@ ac_includes_default="\
|
||||
#endif"
|
||||
|
||||
ac_header_c_list=
|
||||
enable_option_checking=no
|
||||
ac_subst_vars='LTLIBOBJS
|
||||
LIBOBJS
|
||||
WARNINGS
|
||||
CSFLAGS
|
||||
LIBPDFIO_STATIC
|
||||
LIBPDFIO
|
||||
PKGCONFIG_LIBPNG
|
||||
TTFDIR
|
||||
subdirs
|
||||
PKGCONFIG_REQUIRES_PRIVATE
|
||||
PKGCONFIG_REQUIRES
|
||||
PKGCONFIG_LIBS_PRIVATE
|
||||
PKGCONFIG_LIBS
|
||||
@@ -731,6 +734,7 @@ ac_subst_files=''
|
||||
ac_user_opts='
|
||||
enable_option_checking
|
||||
enable_libpng
|
||||
enable_libwebp
|
||||
enable_static
|
||||
enable_shared
|
||||
enable_debug
|
||||
@@ -747,7 +751,7 @@ CFLAGS
|
||||
LDFLAGS
|
||||
LIBS
|
||||
CPPFLAGS'
|
||||
|
||||
ac_subdirs_all='ttf'
|
||||
|
||||
# Initialize some variables set by options.
|
||||
ac_init_help=
|
||||
@@ -1295,7 +1299,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# 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.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures pdfio 1.5.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]...
|
||||
|
||||
@@ -1361,7 +1365,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of pdfio 1.5.0:";;
|
||||
short | recursive ) echo "Configuration of pdfio 1.7.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1369,7 +1373,9 @@ Optional Features:
|
||||
--disable-option-checking ignore unrecognized --enable/--with options
|
||||
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
|
||||
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
|
||||
--enable-libpng use libpng for pdfioFileCreateImageObjFromFile,
|
||||
--disable-libpng use libpng for pdfioFileCreateImageObjFromFile,
|
||||
default=auto
|
||||
--disable-libwebp use libwebp for pdfioFileCreateImageObjFromFile,
|
||||
default=auto
|
||||
--disable-static do not install static library
|
||||
--enable-shared install shared library
|
||||
@@ -1460,7 +1466,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
pdfio configure 1.5.0
|
||||
pdfio configure 1.7.0
|
||||
generated by GNU Autoconf 2.71
|
||||
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
@@ -1592,6 +1598,68 @@ fi
|
||||
as_fn_set_status $ac_retval
|
||||
|
||||
} # ac_fn_c_try_link
|
||||
|
||||
# ac_fn_c_check_func LINENO FUNC VAR
|
||||
# ----------------------------------
|
||||
# Tests whether FUNC exists, setting the cache variable VAR accordingly
|
||||
ac_fn_c_check_func ()
|
||||
{
|
||||
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
|
||||
printf %s "checking for $2... " >&6; }
|
||||
if eval test \${$3+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else $as_nop
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
|
||||
For example, HP-UX 11i <limits.h> declares gettimeofday. */
|
||||
#define $2 innocuous_$2
|
||||
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char $2 (); below. */
|
||||
|
||||
#include <limits.h>
|
||||
#undef $2
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char $2 ();
|
||||
/* The GNU C library defines this for functions which it implements
|
||||
to always fail with ENOSYS. Some functions are actually named
|
||||
something starting with __ and the normal name is an alias. */
|
||||
#if defined __stub_$2 || defined __stub___$2
|
||||
choke me
|
||||
#endif
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return $2 ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"
|
||||
then :
|
||||
eval "$3=yes"
|
||||
else $as_nop
|
||||
eval "$3=no"
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
fi
|
||||
eval ac_res=\$$3
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
printf "%s\n" "$ac_res" >&6; }
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
|
||||
} # ac_fn_c_check_func
|
||||
ac_configure_args_raw=
|
||||
for ac_arg
|
||||
do
|
||||
@@ -1616,7 +1684,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by pdfio $as_me 1.5.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
|
||||
|
||||
$ $0$ac_configure_args_raw
|
||||
@@ -2372,9 +2440,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
|
||||
PDFIO_VERSION="1.5.0"
|
||||
PDFIO_VERSION_MAJOR="`echo 1.5.0 | awk -F. '{print $1}'`"
|
||||
PDFIO_VERSION_MINOR="`echo 1.5.0 | awk -F. '{printf("%d\n",$2);}'`"
|
||||
PDFIO_VERSION="1.7.0"
|
||||
PDFIO_VERSION_MAJOR="`echo 1.7.0 | awk -F. '{print $1}'`"
|
||||
PDFIO_VERSION_MINOR="`echo 1.7.0 | awk -F. '{printf("%d\n",$2);}'`"
|
||||
|
||||
|
||||
|
||||
@@ -3877,6 +3945,93 @@ INSTALL="$(pwd)/install-sh"
|
||||
printf "%s\n" "using $INSTALL" >&6; }
|
||||
|
||||
|
||||
|
||||
ac_header= ac_cache=
|
||||
for ac_item in $ac_header_c_list
|
||||
do
|
||||
if test $ac_cache; then
|
||||
ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
|
||||
if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
|
||||
printf "%s\n" "#define $ac_item 1" >> confdefs.h
|
||||
fi
|
||||
ac_header= ac_cache=
|
||||
elif test $ac_header; then
|
||||
ac_cache=$ac_item
|
||||
else
|
||||
ac_header=$ac_item
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
|
||||
then :
|
||||
|
||||
printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_header_compile "$LINENO" "math.h" "ac_cv_header_math_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_math_h" = xyes
|
||||
then :
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "timegm" "ac_cv_func_timegm"
|
||||
if test "x$ac_cv_func_timegm" = xyes
|
||||
then :
|
||||
|
||||
|
||||
printf "%s\n" "#define HAVE_TIMEGM 1" >>confdefs.h
|
||||
|
||||
CPPFLAGS="-DHAVE_TIMEGM=1 $CPPFLAGS"
|
||||
|
||||
fi
|
||||
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tm_gmtoff member in tm structure" >&5
|
||||
printf %s "checking for tm_gmtoff member in tm structure... " >&6; }
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
#include <time.h>
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
struct tm t;
|
||||
int o = t.tm_gmtoff;
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"
|
||||
then :
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; }
|
||||
|
||||
printf "%s\n" "#define HAVE_TM_GMTOFF 1" >>confdefs.h
|
||||
|
||||
CPPFLAGS="-DHAVE_TM_GMTOFF=1 $CPPFLAGS"
|
||||
|
||||
else $as_nop
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; }
|
||||
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
|
||||
|
||||
if test -n "$ac_tool_prefix"; then
|
||||
# Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
|
||||
set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
|
||||
@@ -3989,45 +4144,46 @@ fi
|
||||
PKGCONFIG_CFLAGS="-I\${includedir}"
|
||||
PKGCONFIG_LIBS="-L\${libdir} -lpdfio"
|
||||
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 "checking for zlib via pkg-config... " >&6; }
|
||||
|
||||
ac_header= ac_cache=
|
||||
for ac_item in $ac_header_c_list
|
||||
do
|
||||
if test $ac_cache; then
|
||||
ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
|
||||
if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
|
||||
printf "%s\n" "#define $ac_item 1" >> confdefs.h
|
||||
fi
|
||||
ac_header= ac_cache=
|
||||
elif test $ac_header; then
|
||||
ac_cache=$ac_item
|
||||
else
|
||||
ac_header=$ac_item
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
|
||||
then :
|
||||
|
||||
printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
if $PKGCONFIG --exists zlib
|
||||
then :
|
||||
|
||||
@@ -4035,6 +4191,7 @@ then :
|
||||
printf "%s\n" "yes" >&6; }
|
||||
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
||||
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
||||
PKGCONFIG_REQUIRES_PRIVATE="$PKGCONFIG_REQUIRES_PRIVATE, zlib"
|
||||
|
||||
else $as_nop
|
||||
|
||||
@@ -4097,7 +4254,6 @@ then :
|
||||
|
||||
fi
|
||||
|
||||
PKGCONFIG_REQUIRES=""
|
||||
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
|
||||
|
||||
fi
|
||||
@@ -4110,9 +4266,6 @@ then :
|
||||
fi
|
||||
|
||||
|
||||
PKGCONFIG_LIBPNG=""
|
||||
|
||||
|
||||
if test "x$PKGCONFIG" != x -a x$enable_libpng != xno
|
||||
then :
|
||||
|
||||
@@ -4128,8 +4281,7 @@ printf "%s\n" "#define HAVE_LIBPNG 1" >>confdefs.h
|
||||
|
||||
CPPFLAGS="$($PKGCONFIG --cflags libpng16) -DHAVE_LIBPNG=1 $CPPFLAGS"
|
||||
LIBS="$($PKGCONFIG --libs libpng16) -lz $LIBS"
|
||||
PKGCONFIG_LIBS_PRIVATE="$($PKGCONFIG --libs libpng16) $PKGCONFIG_LIBS_PRIVATE"
|
||||
PKGCONFIG_REQUIRES="libpng >= 1.6,$PKGCONFIG_REQUIRES"
|
||||
PKGCONFIG_REQUIRES_PRIVATE="libpng >= 1.6, $PKGCONFIG_REQUIRES_PRIVATE"
|
||||
|
||||
else $as_nop
|
||||
|
||||
@@ -4152,6 +4304,51 @@ then :
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-libwebp was given.
|
||||
if test ${enable_libwebp+y}
|
||||
then :
|
||||
enableval=$enable_libwebp;
|
||||
fi
|
||||
|
||||
|
||||
if test "x$PKGCONFIG" != x -a x$enable_libwebp != xno
|
||||
then :
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libwebp" >&5
|
||||
printf %s "checking for libwebp... " >&6; }
|
||||
if $PKGCONFIG --exists libwebp
|
||||
then :
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; };
|
||||
|
||||
printf "%s\n" "#define HAVE_LIBWEBP 1" >>confdefs.h
|
||||
|
||||
CPPFLAGS="$($PKGCONFIG --cflags libwebp) -DHAVE_LIBWEBP=1 $CPPFLAGS"
|
||||
LIBS="$($PKGCONFIG --libs libwebp) -lz $LIBS"
|
||||
PKGCONFIG_REQUIRES_PRIVATE="libwebp, $PKGCONFIG_REQUIRES_PRIVATE"
|
||||
|
||||
else $as_nop
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; };
|
||||
if test x$enable_libwebp = xyes
|
||||
then :
|
||||
|
||||
as_fn_error $? "libwebp-dev required for --enable-libwebp." "$LINENO" 5
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
elif test x$enable_libwebp = xyes
|
||||
then :
|
||||
|
||||
as_fn_error $? "libwebp-dev required for --enable-libwebp." "$LINENO" 5
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-static was given.
|
||||
if test ${enable_static+y}
|
||||
then :
|
||||
@@ -4196,6 +4393,8 @@ else $as_nop
|
||||
LIBPDFIO_STATIC=""
|
||||
PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE"
|
||||
PKGCONFIG_LIBS_PRIVATE=""
|
||||
PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES_PRIVATE"
|
||||
PKGCONFIG_REQUIRES_PRIVATE=""
|
||||
|
||||
fi
|
||||
|
||||
@@ -4988,7 +5187,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by pdfio $as_me 1.5.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
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -5044,7 +5243,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config='$ac_cs_config_escaped'
|
||||
ac_cs_version="\\
|
||||
pdfio config.status 1.5.0
|
||||
pdfio config.status 1.7.0
|
||||
configured by $0, generated by GNU Autoconf 2.71,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
@@ -5600,6 +5799,149 @@ if test "$no_create" != yes; then
|
||||
# would make configure fail if this is the last instruction.
|
||||
$ac_cs_success || as_fn_exit 1
|
||||
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
|
||||
{ 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;}
|
||||
|
||||
86
configure.ac
@@ -1,7 +1,7 @@
|
||||
dnl
|
||||
dnl Configuration script for PDFio
|
||||
dnl
|
||||
dnl Copyright © 2023-2025 by Michael R Sweet
|
||||
dnl Copyright © 2023-2026 by Michael R Sweet
|
||||
dnl
|
||||
dnl Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
dnl information.
|
||||
@@ -21,7 +21,7 @@ AC_PREREQ([2.70])
|
||||
|
||||
|
||||
dnl Package name and version...
|
||||
AC_INIT([pdfio], [1.5.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_MAJOR="`echo AC_PACKAGE_VERSION | awk -F. '{print $1}'`"
|
||||
@@ -88,17 +88,63 @@ AC_SUBST([INSTALL])
|
||||
AC_MSG_RESULT([using $INSTALL])
|
||||
|
||||
|
||||
dnl Standard C stuff...
|
||||
AC_CHECK_HEADER([math.h])
|
||||
|
||||
|
||||
dnl Check for date/time functionality...
|
||||
AC_CHECK_FUNC([timegm], [
|
||||
AC_DEFINE([HAVE_TIMEGM], [1], [Do we have the timegm function?])
|
||||
CPPFLAGS="-DHAVE_TIMEGM=1 $CPPFLAGS"
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING([for tm_gmtoff member in tm structure])
|
||||
AC_COMPILE_IFELSE([
|
||||
AC_LANG_PROGRAM([[#include <time.h>]], [[
|
||||
struct tm t;
|
||||
int o = t.tm_gmtoff;
|
||||
]])
|
||||
], [
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([HAVE_TM_GMTOFF], [1], [Have tm_gmtoff member in struct tm?])
|
||||
CPPFLAGS="-DHAVE_TM_GMTOFF=1 $CPPFLAGS"
|
||||
], [
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
|
||||
|
||||
dnl Check for pkg-config, which is used for some other tests later on...
|
||||
AC_PATH_TOOL([PKGCONFIG], [pkg-config])
|
||||
|
||||
PKGCONFIG_CFLAGS="-I\${includedir}"
|
||||
PKGCONFIG_LIBS="-L\${libdir} -lpdfio"
|
||||
PKGCONFIG_LIBS_PRIVATE="-lm"
|
||||
PKGCONFIG_REQUIRES="zlib"
|
||||
PKGCONFIG_REQUIRES=""
|
||||
PKGCONFIG_REQUIRES_PRIVATE="ttf"
|
||||
AC_SUBST([PKGCONFIG_CFLAGS])
|
||||
AC_SUBST([PKGCONFIG_LIBS])
|
||||
AC_SUBST([PKGCONFIG_LIBS_PRIVATE])
|
||||
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
|
||||
@@ -107,6 +153,7 @@ AS_IF([$PKGCONFIG --exists zlib], [
|
||||
AC_MSG_RESULT([yes])
|
||||
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
||||
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
||||
PKGCONFIG_REQUIRES_PRIVATE="$PKGCONFIG_REQUIRES_PRIVATE, zlib"
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
AC_CHECK_HEADER([zlib.h])
|
||||
@@ -116,16 +163,12 @@ AS_IF([$PKGCONFIG --exists zlib], [
|
||||
AC_MSG_ERROR([Sorry, this software requires zlib 1.1 or higher.])
|
||||
])
|
||||
|
||||
PKGCONFIG_REQUIRES=""
|
||||
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
|
||||
])
|
||||
|
||||
|
||||
dnl libpng...
|
||||
AC_ARG_ENABLE([libpng], AS_HELP_STRING([--enable-libpng], [use libpng for pdfioFileCreateImageObjFromFile, default=auto]))
|
||||
|
||||
PKGCONFIG_LIBPNG=""
|
||||
AC_SUBST([PKGCONFIG_LIBPNG])
|
||||
AC_ARG_ENABLE([libpng], AS_HELP_STRING([--disable-libpng], [use libpng for pdfioFileCreateImageObjFromFile, default=auto]))
|
||||
|
||||
AS_IF([test "x$PKGCONFIG" != x -a x$enable_libpng != xno], [
|
||||
AC_MSG_CHECKING([for libpng-1.6.x])
|
||||
@@ -134,8 +177,7 @@ AS_IF([test "x$PKGCONFIG" != x -a x$enable_libpng != xno], [
|
||||
AC_DEFINE([HAVE_LIBPNG], 1, [Have PNG library?])
|
||||
CPPFLAGS="$($PKGCONFIG --cflags libpng16) -DHAVE_LIBPNG=1 $CPPFLAGS"
|
||||
LIBS="$($PKGCONFIG --libs libpng16) -lz $LIBS"
|
||||
PKGCONFIG_LIBS_PRIVATE="$($PKGCONFIG --libs libpng16) $PKGCONFIG_LIBS_PRIVATE"
|
||||
PKGCONFIG_REQUIRES="libpng >= 1.6,$PKGCONFIG_REQUIRES"
|
||||
PKGCONFIG_REQUIRES_PRIVATE="libpng >= 1.6, $PKGCONFIG_REQUIRES_PRIVATE"
|
||||
], [
|
||||
AC_MSG_RESULT([no]);
|
||||
AS_IF([test x$enable_libpng = xyes], [
|
||||
@@ -147,6 +189,28 @@ AS_IF([test "x$PKGCONFIG" != x -a x$enable_libpng != xno], [
|
||||
])
|
||||
|
||||
|
||||
dnl libwebp...
|
||||
AC_ARG_ENABLE([libwebp], AS_HELP_STRING([--disable-libwebp], [use libwebp for pdfioFileCreateImageObjFromFile, default=auto]))
|
||||
|
||||
AS_IF([test "x$PKGCONFIG" != x -a x$enable_libwebp != xno], [
|
||||
AC_MSG_CHECKING([for libwebp])
|
||||
AS_IF([$PKGCONFIG --exists libwebp], [
|
||||
AC_MSG_RESULT([yes]);
|
||||
AC_DEFINE([HAVE_LIBWEBP], 1, [Have WebP library?])
|
||||
CPPFLAGS="$($PKGCONFIG --cflags libwebp) -DHAVE_LIBWEBP=1 $CPPFLAGS"
|
||||
LIBS="$($PKGCONFIG --libs libwebp) -lz $LIBS"
|
||||
PKGCONFIG_REQUIRES_PRIVATE="libwebp, $PKGCONFIG_REQUIRES_PRIVATE"
|
||||
], [
|
||||
AC_MSG_RESULT([no]);
|
||||
AS_IF([test x$enable_libwebp = xyes], [
|
||||
AC_MSG_ERROR([libwebp-dev required for --enable-libwebp.])
|
||||
])
|
||||
])
|
||||
], [test x$enable_libwebp = xyes], [
|
||||
AC_MSG_ERROR([libwebp-dev required for --enable-libwebp.])
|
||||
])
|
||||
|
||||
|
||||
dnl Library target...
|
||||
AC_ARG_ENABLE([static], AS_HELP_STRING([--disable-static], [do not install static library]))
|
||||
AC_ARG_ENABLE([shared], AS_HELP_STRING([--enable-shared], [install shared library]))
|
||||
@@ -168,6 +232,8 @@ AS_IF([test x$enable_shared = xyes], [
|
||||
LIBPDFIO_STATIC=""
|
||||
PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE"
|
||||
PKGCONFIG_LIBS_PRIVATE=""
|
||||
PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES_PRIVATE"
|
||||
PKGCONFIG_REQUIRES_PRIVATE=""
|
||||
])
|
||||
|
||||
AC_SUBST([LIBPDFIO])
|
||||
|
||||
712
doc/pdfio.3
873
doc/pdfio.html
281
doc/pdfio.md
@@ -15,9 +15,9 @@ goals of PDFio are:
|
||||
PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF
|
||||
RIP or viewer could be written using it.
|
||||
|
||||
PDFio is Copyright © 2021-2025 by Michael R Sweet and is licensed under the
|
||||
Apache License Version 2.0 with an (optional) exception to allow linking against
|
||||
GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
||||
Copyright © 2021-2026 by Michael R Sweet. PDFio is licensed under the Apache
|
||||
License Version 2.0 with an (optional) exception to allow linking against GNU
|
||||
GPL2-only software. See the files `LICENSE` and `NOTICE` for more information.
|
||||
|
||||
|
||||
Requirements
|
||||
@@ -28,16 +28,22 @@ PDFio requires the following to build the software:
|
||||
- A C99 compiler such as Clang, GCC, or MS Visual C
|
||||
- A POSIX-compliant `make` program
|
||||
- A POSIX-compliant `sh` program
|
||||
- ZLIB (<https://www.zlib.net/>) 1.0 or higher
|
||||
|
||||
PDFio will also use libpng 1.6 or higher (<https://www.libpng.org/>) to provide
|
||||
enhanced PNG image support.
|
||||
- libpng (<https://www.libpng.org/>) 1.6 or later for full PNG image support
|
||||
(optional)
|
||||
- libwebp (<https://developers.google.com/speed/webp>) 1.0 or later for WebP
|
||||
image support (optional)
|
||||
- ZLIB (<https://www.zlib.net/>) 1.1 or later for compression support
|
||||
|
||||
IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.
|
||||
|
||||
On a stock Ubuntu install, the following command will install the various
|
||||
prerequisites:
|
||||
|
||||
Installing PDFio
|
||||
----------------
|
||||
sudo apt-get install build-essential libpng-dev libwebp-dev zlib1g-dev
|
||||
|
||||
|
||||
Building and Installing PDFio on Linux/Unix
|
||||
-------------------------------------------
|
||||
|
||||
PDFio comes with a configure script that creates a portable makefile that will
|
||||
work on any POSIX-compliant system with ZLIB installed. To make it, run:
|
||||
@@ -69,21 +75,32 @@ Other configure options can be found using the `--help` option:
|
||||
./configure --help
|
||||
|
||||
|
||||
Visual Studio Project
|
||||
---------------------
|
||||
Building on Windows with Visual Studio
|
||||
--------------------------------------
|
||||
|
||||
The Visual Studio solution ("pdfio.sln") is provided for Windows developers and
|
||||
generates both a static library and DLL.
|
||||
generates the PDFIO1 DLL. You can also use NuGet to install the `pdfio_native`
|
||||
package.
|
||||
|
||||
You can build and run the `testpdfio` unit tests target from within Visual
|
||||
Studio to verify the functioning of the library.
|
||||
|
||||
|
||||
Xcode Project
|
||||
-------------
|
||||
Building on macOS with Xcode
|
||||
----------------------------
|
||||
|
||||
There is also an Xcode project ("pdfio.xcodeproj") you can use on macOS which
|
||||
generates a static library that will be installed under "/usr/local" with:
|
||||
The Xcode project (`pdfio.xcodeproj`) is provided for macOS developer which
|
||||
generates a static library that will be installed under "/usr/local". Run the
|
||||
following command to build and install PDFio on macOS:
|
||||
|
||||
sudo xcodebuild install
|
||||
|
||||
Alternately you can add the Xcode project to a workspace and reference the PDFio
|
||||
library target as a dependency in your own project.
|
||||
|
||||
You can build and run the `testpdfio` unit tests target from within Xcode to
|
||||
verify the functioning of the library.
|
||||
|
||||
|
||||
Detecting PDFio
|
||||
---------------
|
||||
@@ -343,8 +360,8 @@ password_cb(void *data, const char *filename)
|
||||
```
|
||||
|
||||
The error callback is called for both errors and warnings and accepts the
|
||||
`pdfio_file_t` pointer, a message string, and the callback pointer value, for
|
||||
example:
|
||||
`pdfio_file_t` pointer, a message string, and the callback pointer value. It
|
||||
returns `true` to continue processing the file or `false` to stop, for example:
|
||||
|
||||
```c
|
||||
bool
|
||||
@@ -354,13 +371,17 @@ error_cb(pdfio_file_t *pdf, const char *message, void *data)
|
||||
|
||||
fprintf(stderr, "%s: %s\n", pdfioFileGetName(pdf), message);
|
||||
|
||||
// Return false to treat warnings as errors
|
||||
return (false);
|
||||
// Return true for warning messages (continue) and false for errors (stop)
|
||||
return (!strncmp(message, "WARNING:", 8));
|
||||
}
|
||||
```
|
||||
|
||||
The default error callback (`NULL`) does the equivalent of the above.
|
||||
|
||||
> Note: Many errors are unrecoverable, so PDFio ignores the return value from
|
||||
> the error callback and always stops processing the PDF file. Warning messages
|
||||
> start with the prefix "WARNING:" while errors have no prefix.
|
||||
|
||||
Each PDF file contains one or more pages. The [`pdfioFileGetNumPages`](@@)
|
||||
function returns the number of pages in the file while the
|
||||
[`pdfioFileGetPage`](@@) function gets the specified page in the PDF file:
|
||||
@@ -383,43 +404,35 @@ Each page is represented by a "page tree" object (what [`pdfioFileGetPage`](@@)
|
||||
returns) that specifies information about the page and one or more "content"
|
||||
objects that contain the images, fonts, text, and graphics that appear on the
|
||||
page. Use the [`pdfioPageGetNumStreams`](@@) and [`pdfioPageOpenStream`](@@)
|
||||
functions to access the content streams for each page, and
|
||||
[`pdfioObjGetDict`](@@) to get the associated page object dictionary. For
|
||||
example, if you want to display the media and crop boxes for a given page:
|
||||
functions to access the content streams for each page, [`pdfioObjGetDict`](@@)
|
||||
to get the associated page object dictionary, and [`pdfioPageGetArray`](@@),
|
||||
[`pdfioPageGetBinary`](@@), [`pdfioPageGetBoolean`](@@),
|
||||
[`pdfioPageGetDate`](@@), [`pdfioPageGetDict`](@@), [`pdfioPageGetName`](@@),
|
||||
[`pdfioPageGetObj`](@@), [`pdfioPageGetRect`](@@), and
|
||||
[`pdfioPageGetString`](@@) to get a value from the page object dictionary or its
|
||||
parents. For example, if you want to display the media and crop boxes for a
|
||||
given page:
|
||||
|
||||
```c
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
size_t i; // Looping var
|
||||
size_t count; // Number of pages
|
||||
pdfio_obj_t *page; // Current page
|
||||
pdfio_dict_t *dict; // Current page dictionary
|
||||
pdfio_array_t *media_box; // MediaBox array
|
||||
double media_values[4]; // MediaBox values
|
||||
pdfio_array_t *crop_box; // CropBox array
|
||||
double crop_values[4]; // CropBox values
|
||||
pdfio_rect_t media_box; // MediaBox values
|
||||
pdfio_rect_t crop_box; // CropBox values
|
||||
|
||||
// Iterate the pages in the PDF file
|
||||
for (i = 0, count = pdfioFileGetNumPages(pdf); i < count; i ++)
|
||||
{
|
||||
page = pdfioFileGetPage(pdf, i);
|
||||
dict = pdfioObjGetDict(page);
|
||||
|
||||
media_box = pdfioDictGetArray(dict, "MediaBox");
|
||||
media_values[0] = pdfioArrayGetNumber(media_box, 0);
|
||||
media_values[1] = pdfioArrayGetNumber(media_box, 1);
|
||||
media_values[2] = pdfioArrayGetNumber(media_box, 2);
|
||||
media_values[3] = pdfioArrayGetNumber(media_box, 3);
|
||||
|
||||
crop_box = pdfioDictGetArray(dict, "CropBox");
|
||||
crop_values[0] = pdfioArrayGetNumber(crop_box, 0);
|
||||
crop_values[1] = pdfioArrayGetNumber(crop_box, 1);
|
||||
crop_values[2] = pdfioArrayGetNumber(crop_box, 2);
|
||||
crop_values[3] = pdfioArrayGetNumber(crop_box, 3);
|
||||
pdfioPageGetRect(page, "MediaBox", &media_box);
|
||||
pdfioPageGetRect(page, "CropBox", &crop_box);
|
||||
|
||||
printf("Page %u: MediaBox=[%g %g %g %g], CropBox=[%g %g %g %g]\n",
|
||||
(unsigned)(i + 1),
|
||||
media_values[0], media_values[1], media_values[2], media_values[3],
|
||||
crop_values[0], crop_values[1], crop_values[2], crop_values[3]);
|
||||
media_box.x1, media_box.y1, media_box.x2, media_box.y2,
|
||||
crop_box.x1, crop_box.y1, crop_box.x2, crop_box.y2);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -756,8 +769,9 @@ The "interpolate" argument specifies whether the colors in the image should be
|
||||
smoothed/interpolated when scaling. This is most useful for photographs but
|
||||
should be `false` for screenshot and barcode images.
|
||||
|
||||
If you have a JPEG or PNG file, use the [`pdfioFileCreateImageObjFromFile`](@@)
|
||||
function to copy the image into a PDF image object, for example:
|
||||
If you have a GIF, JPEG, PNG, or WebP file, use the
|
||||
[`pdfioFileCreateImageObjFromFile`](@@) function to copy the image into a PDF
|
||||
image object, for example:
|
||||
|
||||
```c
|
||||
pdfio_file_t *pdf = pdfioFileCreate(...);
|
||||
@@ -765,9 +779,6 @@ pdfio_obj_t *img =
|
||||
pdfioFileCreateImageObjFromFile(pdf, "myphoto.jpg", /*interpolate*/true);
|
||||
```
|
||||
|
||||
> Note: Currently `pdfioFileCreateImageObjFromFile` does not support 12 bit JPEG
|
||||
> files or PNG files with an alpha channel.
|
||||
|
||||
|
||||
### Page Dictionary Functions
|
||||
|
||||
@@ -864,6 +875,55 @@ escaping, as needed:
|
||||
offsets between them
|
||||
|
||||
|
||||
Tagged and Marked PDF Content
|
||||
-----------------------------
|
||||
|
||||
Content in a page stream can be tagged to help a PDF reader application know the
|
||||
kind and organization of that content. Content inserted using the PDFio
|
||||
[Page Stream Functions](@) can be tagged by surrounding it with the
|
||||
[`pdfioContentBeginMarked`](@@) and [`pdfioContentEndMarked`](@@) functions.
|
||||
|
||||
The `pdfioContentBeginMarked` function accepts a named tag and optional
|
||||
dictionary of attributes such as the marked content identifier ("MCID"). For
|
||||
example, the following code tags a paragraph of text:
|
||||
|
||||
```c
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
pdfio_stream_t *st; // Page stream
|
||||
|
||||
pdfioContentBeginMarked(st, "P", /*dict*/NULL);
|
||||
|
||||
pdfioContentTextShow(st, /*unicode*/false, "Mary had a little lamb\n");
|
||||
pdfioContentTextShow(st, /*unicode*/false, "whose fleece was white as snow.\n");
|
||||
pdfioContentTextShow(st, /*unicode*/false, "And everywhere that Mary went\n");
|
||||
pdfioContentTextShow(st, /*unicode*/false, "the lamb was sure to go,\n");
|
||||
|
||||
pdfioContentEndMarked(st);
|
||||
```
|
||||
|
||||
To mark the same paragraph with a content identifier you would first create a
|
||||
dictionary containing the "MCID" key/value pair and then mark the paragraph with
|
||||
that dictionary:
|
||||
|
||||
```c
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
pdfio_stream_t *st; // Page stream
|
||||
pdfio_dict_t *dict; // Content dictionary
|
||||
|
||||
dict = pdfioDictCreate(pdf);
|
||||
pdfioDictSetNumber(dict, "MCID", 42);
|
||||
|
||||
pdfioContentBeginMarked(st, "P", dict);
|
||||
|
||||
pdfioContentTextShow(st, /*unicode*/false, "Mary had a little lamb\n");
|
||||
pdfioContentTextShow(st, /*unicode*/false, "whose fleece was white as snow.\n");
|
||||
pdfioContentTextShow(st, /*unicode*/false, "And everywhere that Mary went\n");
|
||||
pdfioContentTextShow(st, /*unicode*/false, "the lamb was sure to go,\n");
|
||||
|
||||
pdfioContentEndMarked(st);
|
||||
```
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
@@ -889,11 +949,26 @@ main(int argc, // I - Number of command-line arguments
|
||||
{
|
||||
const char *filename; // PDF filename
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
const char *author; // Author name
|
||||
time_t creation_date; // Creation date
|
||||
struct tm *creation_tm; // Creation date/time information
|
||||
char creation_text[256]; // Creation date/time as a string
|
||||
const char *title; // Title
|
||||
pdfio_dict_t *catalog; // Catalog dictionary
|
||||
const char *author, // Author name
|
||||
*creator, // Creator name
|
||||
*producer, // Producer name
|
||||
*title; // Title
|
||||
time_t creation_date, // Creation date
|
||||
modification_date; // Modification date
|
||||
struct tm *creation_tm, // Creation date/time information
|
||||
*modification_tm; // Modification date/time information
|
||||
char creation_text[256], // Creation date/time as a string
|
||||
modification_text[256], // Modification date/time human fmt string
|
||||
range_text[255]; // Page range text
|
||||
size_t num_pages; // PDF number of pages
|
||||
bool has_acroform; // Does the file have an AcroForm?
|
||||
pdfio_obj_t *page; // Object
|
||||
pdfio_dict_t *page_dict; // Object dictionary
|
||||
size_t cur, // Current page index
|
||||
prev; // Previous page index
|
||||
pdfio_rect_t cur_box, // Current MediaBox
|
||||
prev_box; // Previous MediaBox
|
||||
|
||||
|
||||
// Get the filename from the command-line...
|
||||
@@ -906,14 +981,20 @@ main(int argc, // I - Number of command-line arguments
|
||||
filename = argv[1];
|
||||
|
||||
// Open the PDF file with the default callbacks...
|
||||
pdf = pdfioFileOpen(filename, /*password_cb*/NULL, /*password_cbdata*/NULL,
|
||||
/*error_cb*/NULL, /*error_cbdata*/NULL);
|
||||
pdf = pdfioFileOpen(filename, /*password_cb*/NULL,
|
||||
/*password_cbdata*/NULL, /*error_cb*/NULL,
|
||||
/*error_cbdata*/NULL);
|
||||
if (pdf == NULL)
|
||||
return (1);
|
||||
|
||||
// Get the title and author...
|
||||
author = pdfioFileGetAuthor(pdf);
|
||||
title = pdfioFileGetTitle(pdf);
|
||||
// Get the title, author, etc...
|
||||
catalog = pdfioFileGetCatalog(pdf);
|
||||
author = pdfioFileGetAuthor(pdf);
|
||||
creator = pdfioFileGetCreator(pdf);
|
||||
has_acroform = pdfioDictGetType(catalog, "AcroForm") != PDFIO_VALTYPE_NONE;
|
||||
num_pages = pdfioFileGetNumPages(pdf);
|
||||
producer = pdfioFileGetProducer(pdf);
|
||||
title = pdfioFileGetTitle(pdf);
|
||||
|
||||
// Get the creation date and convert to a string...
|
||||
if ((creation_date = pdfioFileGetCreationDate(pdf)) > 0)
|
||||
@@ -926,12 +1007,70 @@ main(int argc, // I - Number of command-line arguments
|
||||
snprintf(creation_text, sizeof(creation_text), "-- not set --");
|
||||
}
|
||||
|
||||
// Get the modification date and convert to a string...
|
||||
if ((modification_date = pdfioFileGetModificationDate(pdf)) > 0)
|
||||
{
|
||||
modification_tm = localtime(&modification_date);
|
||||
strftime(modification_text, sizeof(modification_text), "%c", modification_tm);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(modification_text, sizeof(modification_text), "-- not set --");
|
||||
}
|
||||
|
||||
// Print file information to stdout...
|
||||
printf("%s:\n", filename);
|
||||
printf(" Title: %s\n", title ? title : "-- not set --");
|
||||
printf(" Author: %s\n", author ? author : "-- not set --");
|
||||
printf(" Created On: %s\n", creation_text);
|
||||
printf(" Number Pages: %u\n", (unsigned)pdfioFileGetNumPages(pdf));
|
||||
printf(" Title: %s\n", title ? title : "-- not set --");
|
||||
printf(" Author: %s\n", author ? author : "-- not set --");
|
||||
printf(" Creator: %s\n", creator ? creator : "-- not set --");
|
||||
printf(" Producer: %s\n", producer ? producer : "-- not set --");
|
||||
printf(" Created On: %s\n", creation_text);
|
||||
printf(" Modified On: %s\n", modification_text);
|
||||
printf(" Version: %s\n", pdfioFileGetVersion(pdf));
|
||||
printf(" AcroForm: %s\n", has_acroform ? "Yes" : "No");
|
||||
printf(" Number of Pages: %u\n", (unsigned)num_pages);
|
||||
|
||||
// Report the MediaBox for all of the pages
|
||||
prev_box.x1 = prev_box.x2 = prev_box.y1 = prev_box.y2 = 0.0;
|
||||
|
||||
for (cur = 0, prev = 0; cur < num_pages; cur ++)
|
||||
{
|
||||
// Find the MediaBox for this page in the page tree...
|
||||
page = pdfioFileGetPage(pdf, cur);
|
||||
|
||||
cur_box.x1 = cur_box.x2 = cur_box.y1 = cur_box.y2 = 0.0;
|
||||
pdfioPageGetRect(page, "MediaBox", &cur_box);
|
||||
|
||||
// If this MediaBox is different from the previous one, show the range of
|
||||
// pages that have that size...
|
||||
if (cur == 0 ||
|
||||
fabs(cur_box.x1 - prev_box.x1) > 0.01 ||
|
||||
fabs(cur_box.y1 - prev_box.y1) > 0.01 ||
|
||||
fabs(cur_box.x2 - prev_box.x2) > 0.01 ||
|
||||
fabs(cur_box.y2 - prev_box.y2) > 0.01)
|
||||
{
|
||||
if (cur > prev)
|
||||
{
|
||||
snprintf(range_text, sizeof(range_text), "Pages %u-%u",
|
||||
(unsigned)(prev + 1), (unsigned)cur);
|
||||
printf("%16s: [%g %g %g %g]\n", range_text,
|
||||
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
|
||||
}
|
||||
|
||||
// Start a new series of pages with the new size...
|
||||
prev = cur;
|
||||
prev_box = cur_box;
|
||||
}
|
||||
}
|
||||
|
||||
// Show the last range as needed...
|
||||
if (cur > prev)
|
||||
{
|
||||
snprintf(range_text, sizeof(range_text), "Pages %u-%u",
|
||||
(unsigned)(prev + 1), (unsigned)cur);
|
||||
printf("%16s: [%g %g %g %g]\n", range_text,
|
||||
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
|
||||
}
|
||||
|
||||
// Close the PDF file...
|
||||
pdfioFileClose(pdf);
|
||||
@@ -1204,7 +1343,7 @@ Unicode glyph for the current index:
|
||||
Create a PDF File With Text and an Image
|
||||
----------------------------------------
|
||||
|
||||
The `image2pdf.c` example code creates a PDF file containing a JPEG or PNG
|
||||
The `image2pdf.c` example code creates a PDF file containing a GIF, JPEG, or PNG
|
||||
image file and optional caption on a single page. The `create_pdf_image_file`
|
||||
function creates the PDF file, embeds a base font and the named JPEG or PNG
|
||||
image file, and then creates a page with the image centered on the page with any
|
||||
@@ -1508,6 +1647,9 @@ typedef struct docdata_s // Document formatting data
|
||||
// State for the current page
|
||||
pdfio_stream_t *st; // Current page stream
|
||||
double y; // Current position on page
|
||||
const char *tag; // Current block tag
|
||||
bool in_table, // Are we in a table?
|
||||
in_row; // Are we in a table row?
|
||||
docfont_t font; // Current font
|
||||
double fsize; // Current font size
|
||||
doccolor_t color; // Current color
|
||||
@@ -2011,6 +2153,9 @@ pdfioContentPathRect(dd->st, left - CODE_PADDING, dd->y + SIZE_CODEBLOCK,
|
||||
pdfioContentFillAndStroke(dd->st, false);
|
||||
|
||||
// Start a code text block...
|
||||
dd->tag = "P";
|
||||
pdfioContentBeginMarked(dd->st, dd->tag, /*dict*/NULL);
|
||||
|
||||
set_font(dd, DOCFONT_MONOSPACE, SIZE_CODEBLOCK);
|
||||
pdfioContentTextBegin(dd->st);
|
||||
pdfioContentTextMoveTo(dd->st, left, dd->y);
|
||||
@@ -2047,6 +2192,9 @@ for (code = mmdGetFirstChild(block); code; code = mmdGetNextSibling(code))
|
||||
pdfioContentTextEnd(dd->st);
|
||||
dd->y += lineheight;
|
||||
|
||||
pdfioContentEndMarked(dd->st);
|
||||
dd->tag = NULL;
|
||||
|
||||
// Draw the bottom padding...
|
||||
set_color(dd, DOCCOLOR_LTGRAY);
|
||||
pdfioContentPathRect(dd->st, left - CODE_PADDING,
|
||||
@@ -2187,8 +2335,17 @@ Finally, we render each row in the table:
|
||||
|
||||
```c
|
||||
// Render each table row...
|
||||
dd->in_table = true;
|
||||
|
||||
if (dd->st)
|
||||
pdfioContentBeginMarked(dd->st, "Table", /*dict*/NULL);
|
||||
|
||||
for (row = 0, rowptr = rows; row < num_rows; row ++, rowptr ++)
|
||||
render_row(dd, num_cols, cols, rowptr);
|
||||
|
||||
pdfioContentEndMarked(dd->st);
|
||||
|
||||
dd->in_table = false;
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ TARGETS = \
|
||||
image2pdf \
|
||||
md2pdf \
|
||||
pdf2text \
|
||||
pdfioinfo
|
||||
pdfioinfo \
|
||||
pdfiomerge
|
||||
|
||||
|
||||
# Make everything
|
||||
@@ -61,5 +62,10 @@ pdfioinfo: pdfioinfo.c
|
||||
$(CC) $(CFLAGS) -o $@ pdfioinfo.c $(LIBS)
|
||||
|
||||
|
||||
# pdfiomerge
|
||||
pdfiomerge: pdfiomerge.c
|
||||
$(CC) $(CFLAGS) -o $@ pdfiomerge.c $(LIBS)
|
||||
|
||||
|
||||
# Common dependencies...
|
||||
$(TARGETS): Makefile ../pdfio.h ../pdfio-content.h
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <pdfio-content.h>
|
||||
#ifdef _WIN32
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
//
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// Simple markdown to PDF converter example for PDFio.
|
||||
//
|
||||
// Copyright © 2024 by Michael R Sweet.
|
||||
// Copyright © 2024-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <math.h>
|
||||
#ifdef _WIN32
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif // _WIN32
|
||||
@@ -122,6 +123,9 @@ typedef struct docdata_s // Document formatting data
|
||||
// State for the current page
|
||||
pdfio_stream_t *st; // Current page stream
|
||||
double y; // Current position on page
|
||||
const char *tag; // Current block tag
|
||||
bool in_table, // Are we in a table?
|
||||
in_row; // Are we in a table row?
|
||||
docfont_t font; // Current font
|
||||
double fsize; // Current font size
|
||||
doccolor_t color; // Current color
|
||||
@@ -289,8 +293,8 @@ main(int argc, // I - Number of command-line arguments
|
||||
// Get the markdown file from the command-line...
|
||||
if (argc < 2 || argc > 3)
|
||||
{
|
||||
fputs("Usage: md2pdf FILENANE.md [FILENAME.pdf]\n", stderr);
|
||||
fputs(" md2pdf FILENANE.md >FILENAME.pdf\n", stderr);
|
||||
fputs("Usage: md2pdf FILENAME.md [FILENAME.pdf]\n", stderr);
|
||||
fputs(" md2pdf FILENAME.md >FILENAME.pdf\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
@@ -472,6 +476,7 @@ add_links(docdata_t *dd) // I - Document data
|
||||
// Create the annotation object pointing to the action...
|
||||
dict = pdfioDictCreate(dd->pdf);
|
||||
pdfioDictSetName(dict, "Subtype", "Link");
|
||||
pdfioDictSetNumber(dict, "F", 4); // Print flag
|
||||
pdfioDictSetRect(dict, "Rect", &l->box);
|
||||
border = pdfioArrayCreate(dd->pdf);
|
||||
pdfioArrayAppendNumber(border, 0.0);
|
||||
@@ -618,6 +623,50 @@ format_block(docdata_t *dd, // I - Document data
|
||||
|
||||
frag = frags + num_frags;
|
||||
|
||||
switch (mmdGetType(block))
|
||||
{
|
||||
case MMD_TYPE_HEADING_1 :
|
||||
dd->tag = "H1";
|
||||
break;
|
||||
|
||||
case MMD_TYPE_HEADING_2 :
|
||||
dd->tag = "H2";
|
||||
break;
|
||||
|
||||
case MMD_TYPE_HEADING_3 :
|
||||
dd->tag = "H3";
|
||||
break;
|
||||
|
||||
case MMD_TYPE_HEADING_4 :
|
||||
dd->tag = "H4";
|
||||
break;
|
||||
|
||||
case MMD_TYPE_HEADING_5 :
|
||||
dd->tag = "H5";
|
||||
break;
|
||||
|
||||
case MMD_TYPE_HEADING_6 :
|
||||
dd->tag = "H6";
|
||||
break;
|
||||
|
||||
case MMD_TYPE_TABLE_HEADER_CELL :
|
||||
dd->tag = "TH";
|
||||
break;
|
||||
|
||||
case MMD_TYPE_TABLE_BODY_CELL_LEFT :
|
||||
case MMD_TYPE_TABLE_BODY_CELL_CENTER :
|
||||
case MMD_TYPE_TABLE_BODY_CELL_RIGHT :
|
||||
dd->tag = "TD";
|
||||
break;
|
||||
|
||||
default :
|
||||
dd->tag = "P";
|
||||
break;
|
||||
}
|
||||
|
||||
if (dd->st)
|
||||
pdfioContentBeginMarked(dd->st, dd->tag, /*dict*/NULL);
|
||||
|
||||
// Loop through the block and render lines...
|
||||
for (current = mmdGetFirstChild(block), x = left; current; current = next)
|
||||
{
|
||||
@@ -796,6 +845,9 @@ format_block(docdata_t *dd, // I - Document data
|
||||
pdfioContentRestore(dd->st);
|
||||
}
|
||||
}
|
||||
|
||||
pdfioContentEndMarked(dd->st);
|
||||
dd->tag = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -835,6 +887,9 @@ format_code(docdata_t *dd, // I - Document data
|
||||
pdfioContentFillAndStroke(dd->st, false);
|
||||
|
||||
// Start a code text block...
|
||||
dd->tag = "P";
|
||||
pdfioContentBeginMarked(dd->st, dd->tag, /*dict*/NULL);
|
||||
|
||||
set_font(dd, DOCFONT_MONOSPACE, SIZE_CODEBLOCK);
|
||||
pdfioContentTextBegin(dd->st);
|
||||
pdfioContentTextMoveTo(dd->st, left, dd->y);
|
||||
@@ -869,6 +924,9 @@ format_code(docdata_t *dd, // I - Document data
|
||||
pdfioContentTextEnd(dd->st);
|
||||
dd->y += lineheight;
|
||||
|
||||
pdfioContentEndMarked(dd->st);
|
||||
dd->tag = NULL;
|
||||
|
||||
// Draw the bottom padding...
|
||||
set_color(dd, DOCCOLOR_LTGRAY);
|
||||
pdfioContentPathRect(dd->st, left - CODE_PADDING, dd->y - CODE_PADDING - (LINE_HEIGHT - 1.0) * SIZE_CODEBLOCK, right - left + 2.0 * CODE_PADDING, CODE_PADDING);
|
||||
@@ -1144,8 +1202,17 @@ format_table(docdata_t *dd, // I - Document data
|
||||
}
|
||||
|
||||
// Render each table row...
|
||||
dd->in_table = true;
|
||||
|
||||
if (dd->st)
|
||||
pdfioContentBeginMarked(dd->st, "Table", /*dict*/NULL);
|
||||
|
||||
for (row = 0, rowptr = rows; row < num_rows; row ++, rowptr ++)
|
||||
render_row(dd, num_cols, cols, rowptr);
|
||||
|
||||
pdfioContentEndMarked(dd->st);
|
||||
|
||||
dd->in_table = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1359,6 +1426,16 @@ new_page(docdata_t *dd) // I - Document data
|
||||
// Close the current page...
|
||||
if (dd->st)
|
||||
{
|
||||
if (dd->tag)
|
||||
{
|
||||
// Close current tag and any row or table...
|
||||
pdfioContentEndMarked(dd->st);
|
||||
if (dd->in_row)
|
||||
pdfioContentEndMarked(dd->st);
|
||||
if (dd->in_table)
|
||||
pdfioContentEndMarked(dd->st);
|
||||
}
|
||||
|
||||
pdfioStreamClose(dd->st);
|
||||
add_links(dd);
|
||||
}
|
||||
@@ -1387,6 +1464,7 @@ new_page(docdata_t *dd) // I - Document data
|
||||
dd->y = dd->art_box.y2;
|
||||
|
||||
// Add header/footer text
|
||||
pdfioContentBeginMarked(dd->st, "Artifact", /*dict*/NULL);
|
||||
set_color(dd, DOCCOLOR_GRAY);
|
||||
set_font(dd, DOCFONT_REGULAR, SIZE_HEADFOOT);
|
||||
|
||||
@@ -1445,6 +1523,17 @@ new_page(docdata_t *dd) // I - Document data
|
||||
pdfioContentTextShow(dd->st, UNICODE_VALUE, dd->heading);
|
||||
pdfioContentTextEnd(dd->st);
|
||||
}
|
||||
|
||||
pdfioContentEndMarked(dd->st);
|
||||
|
||||
if (dd->in_table)
|
||||
pdfioContentBeginMarked(dd->st, "Table", /*dict*/NULL);
|
||||
|
||||
if (dd->in_row)
|
||||
pdfioContentBeginMarked(dd->st, "TR", /*dict*/NULL);
|
||||
|
||||
if (dd->tag)
|
||||
pdfioContentBeginMarked(dd->st, dd->tag, /*dict*/NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -1617,10 +1706,12 @@ render_row(docdata_t *dd, // I - Document data
|
||||
// Start a new page as needed...
|
||||
if (!dd->st)
|
||||
new_page(dd);
|
||||
|
||||
if ((dd->y - row->height) < dd->art_box.y1)
|
||||
else if ((dd->y - row->height) < dd->art_box.y1)
|
||||
new_page(dd);
|
||||
|
||||
dd->in_row = true;
|
||||
pdfioContentBeginMarked(dd->st, "TR", /*dict*/NULL);
|
||||
|
||||
if (mmdGetType(row->cells[0]) == MMD_TYPE_TABLE_HEADER_CELL)
|
||||
{
|
||||
// Header row, no border...
|
||||
@@ -1651,6 +1742,9 @@ render_row(docdata_t *dd, // I - Document data
|
||||
}
|
||||
|
||||
dd->y = row_y - row->height;
|
||||
|
||||
pdfioContentEndMarked(dd->st);
|
||||
dd->in_row = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// https://www.msweet.org/mmd
|
||||
//
|
||||
// Copyright © 2017-2024 by Michael R Sweet.
|
||||
// Copyright © 2017-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@@ -166,7 +166,7 @@ mmdCopyAllText(mmd_t *node) // I - Parent node
|
||||
char *all = NULL, // String buffer
|
||||
*allptr = NULL, // Pointer into string buffer
|
||||
*temp; // Temporary pointer
|
||||
size_t allsize = 1, // Size of "all" buffer
|
||||
size_t allsize = 0, // Size of "all" buffer
|
||||
textlen; // Length of "text" string
|
||||
mmd_t *current, // Current node
|
||||
*next; // Next node
|
||||
@@ -179,6 +179,8 @@ mmdCopyAllText(mmd_t *node) // I - Parent node
|
||||
if (current->text)
|
||||
{
|
||||
// Append this node's text to the string...
|
||||
long alloff = allptr - all; // Offset within current buffer
|
||||
|
||||
textlen = strlen(current->text);
|
||||
allsize += textlen + (size_t)current->whitespace;
|
||||
temp = realloc(all, allsize);
|
||||
@@ -189,8 +191,8 @@ mmdCopyAllText(mmd_t *node) // I - Parent node
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
allptr = temp + (allptr - all);
|
||||
all = temp;
|
||||
allptr = all + alloff;
|
||||
|
||||
if (current->whitespace)
|
||||
*allptr++ = ' ';
|
||||
@@ -1059,6 +1061,8 @@ mmdLoadIO(mmd_t *root, // I - Root node for document or `NULL` for a new d
|
||||
break;
|
||||
else if (line[0] == '>' && *ptr == '>')
|
||||
memmove(ptr, ptr + 1, strlen(ptr));
|
||||
|
||||
DEBUG2_printf(" line=\"%s\"\n", line);
|
||||
}
|
||||
|
||||
mmd_parse_inline(&doc, block, lineptr);
|
||||
@@ -1493,7 +1497,7 @@ mmd_parse_inline(_mmd_doc_t *doc, // I - Document
|
||||
|
||||
for (text = NULL, type = MMD_TYPE_NORMAL_TEXT; *lineptr; lineptr ++)
|
||||
{
|
||||
DEBUG2_printf("mmd_parse_inline: lineptr=%p(\"%32.32s...\"), type=%d, text=%p, whitespace=%d\n", lineptr, lineptr, type, text, whitespace);
|
||||
DEBUG2_printf("mmd_parse_inline: lineptr=%p(\"%s\"), type=%d, text=%p, whitespace=%d\n", lineptr, lineptr, type, text, whitespace);
|
||||
|
||||
if (isspace(*lineptr & 255) && type != MMD_TYPE_CODE_TEXT)
|
||||
{
|
||||
@@ -2090,6 +2094,8 @@ mmd_read_buffer(_mmd_filebuf_t *file) // I - File buffer
|
||||
if (file->bufptr && file->bufptr > file->buffer)
|
||||
{
|
||||
// Discard previous characters in the buffer.
|
||||
DEBUG2_printf("mmd_read_buffer: before buffer=\"%s\"\n", file->bufptr);
|
||||
|
||||
memmove(file->buffer, file->bufptr, file->bufend - file->bufptr);
|
||||
file->bufend -= (file->bufptr - file->buffer);
|
||||
}
|
||||
@@ -2099,11 +2105,13 @@ mmd_read_buffer(_mmd_filebuf_t *file) // I - File buffer
|
||||
file->bufend = file->buffer;
|
||||
}
|
||||
|
||||
if ((bytes = (file->cb)(file->cbdata, file->bufend, sizeof(file->buffer) - (size_t)(file->bufend - file->buffer - 1))) > 0)
|
||||
if ((bytes = (file->cb)(file->cbdata, file->bufend, sizeof(file->buffer) - (size_t)(file->bufend - file->buffer) - 1)) > 0)
|
||||
file->bufend += bytes;
|
||||
|
||||
*(file->bufend) = '\0';
|
||||
file->bufptr = file->buffer;
|
||||
|
||||
DEBUG2_printf("mmd_read_buffer: after buffer=\"%s\"\n", file->buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -2161,6 +2169,8 @@ mmd_read_line(_mmd_filebuf_t *file, // I - File buffer
|
||||
else if (!strchr(file->bufptr, '\n'))
|
||||
mmd_read_buffer(file);
|
||||
|
||||
DEBUG2_printf("mmd_read_line: Returning \"%s\"\n", line);
|
||||
|
||||
return (line);
|
||||
}
|
||||
|
||||
|
||||
@@ -1417,4 +1417,4 @@ puts_utf16(const char *s) // I - Hex string
|
||||
|
||||
put_utf8(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF metadata example for PDFio.
|
||||
//
|
||||
// Copyright © 2023-2025 by Michael R Sweet.
|
||||
// Copyright © 2023-2026 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@@ -68,7 +68,7 @@ main(int argc, // I - Number of command-line arguments
|
||||
catalog = pdfioFileGetCatalog(pdf);
|
||||
author = pdfioFileGetAuthor(pdf);
|
||||
creator = pdfioFileGetCreator(pdf);
|
||||
has_acroform = pdfioDictGetObj(catalog, "AcroForm") != NULL ? true : false;
|
||||
has_acroform = pdfioDictGetType(catalog, "AcroForm") != PDFIO_VALTYPE_NONE;
|
||||
num_pages = pdfioFileGetNumPages(pdf);
|
||||
producer = pdfioFileGetProducer(pdf);
|
||||
title = pdfioFileGetTitle(pdf);
|
||||
@@ -113,16 +113,10 @@ main(int argc, // I - Number of command-line arguments
|
||||
for (cur = 0, prev = 0; cur < num_pages; cur ++)
|
||||
{
|
||||
// Find the MediaBox for this page in the page tree...
|
||||
for (page = pdfioFileGetPage(pdf, cur);
|
||||
page != NULL;
|
||||
page = pdfioDictGetObj(page_dict, "Parent"))
|
||||
{
|
||||
cur_box.x1 = cur_box.x2 = cur_box.y1 = cur_box.y2 = 0.0;
|
||||
page_dict = pdfioObjGetDict(page);
|
||||
page = pdfioFileGetPage(pdf, cur);
|
||||
|
||||
if (pdfioDictGetRect(page_dict, "MediaBox", &cur_box))
|
||||
break;
|
||||
}
|
||||
cur_box.x1 = cur_box.x2 = cur_box.y1 = cur_box.y2 = 0.0;
|
||||
pdfioPageGetRect(page, "MediaBox", &cur_box);
|
||||
|
||||
// If this MediaBox is different from the previous one, show the range of
|
||||
// pages that have that size...
|
||||
|
||||
146
examples/pdfiomerge.c
Normal file
@@ -0,0 +1,146 @@
|
||||
//
|
||||
// PDF merge program for PDFio.
|
||||
//
|
||||
// Copyright © 2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./pdfiomerge [-o OUTPUT.pdf] INPUT.pdf [... INPUT.pdf]
|
||||
// ./pdfiomerge INPUT.pdf [... INPUT.pdf] >OUTPUT.pdf
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
static ssize_t output_cb(void *output_cbdata, const void *buffer, size_t bytes);
|
||||
static int usage(FILE *out);
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Main entry.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // I - Command-line arguments
|
||||
{
|
||||
int i; // Looping var
|
||||
const char *opt; // Current option
|
||||
pdfio_file_t *inpdf, // Input PDF file
|
||||
*outpdf = NULL; // Output PDF file
|
||||
|
||||
|
||||
// Parse command-line...
|
||||
for (i = 1; i < argc; i ++)
|
||||
{
|
||||
if (!strcmp(argv[i], "--help"))
|
||||
{
|
||||
return (usage(stdout));
|
||||
}
|
||||
else if (!strncmp(argv[i], "--", 2))
|
||||
{
|
||||
fprintf(stderr, "pdfiomerge: Unknown option '%s'.\n", argv[i]);
|
||||
return (usage(stderr));
|
||||
}
|
||||
else if (argv[i][0] == '-')
|
||||
{
|
||||
for (opt = argv[i] + 1; *opt; opt ++)
|
||||
{
|
||||
switch (*opt)
|
||||
{
|
||||
case 'o' : // -o OUTPUT.pdf
|
||||
if (outpdf)
|
||||
{
|
||||
fputs("pdfiomerge: Only one output file can be specified.\n", stderr);
|
||||
return (usage(stderr));
|
||||
}
|
||||
|
||||
i ++;
|
||||
if (i >= argc)
|
||||
{
|
||||
fputs("pdfiomerge: Missing output filename after '-o'.\n", stderr);
|
||||
return (usage(stderr));
|
||||
}
|
||||
|
||||
if ((outpdf = pdfioFileCreate(argv[i], /*version*/NULL, /*media_box*/NULL, /*crop_box*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
return (1);
|
||||
break;
|
||||
|
||||
default :
|
||||
fprintf(stderr, "pdfiomerge: Unknown option '-%c'.\n", *opt);
|
||||
return (usage(stderr));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((inpdf = pdfioFileOpen(argv[i], /*password_cb*/NULL, /*password_data*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy PDF file...
|
||||
size_t p, // Current page
|
||||
nump; // Number of pages
|
||||
|
||||
if (!outpdf)
|
||||
{
|
||||
if ((outpdf = pdfioFileCreateOutput(output_cb, /*output_cbdata*/NULL, /*version*/NULL, /*media_box*/NULL, /*crop_box*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
return (1);
|
||||
}
|
||||
|
||||
for (p = 0, nump = pdfioFileGetNumPages(inpdf); p < nump; p ++)
|
||||
{
|
||||
if (!pdfioPageCopy(outpdf, pdfioFileGetPage(inpdf, p)))
|
||||
return (1);
|
||||
}
|
||||
|
||||
pdfioFileClose(inpdf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!outpdf)
|
||||
return (usage(stderr));
|
||||
|
||||
pdfioFileClose(outpdf);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'output_cb()' - Write PDF data to the standard output...
|
||||
//
|
||||
|
||||
static ssize_t // O - Number of bytes written
|
||||
output_cb(void *output_cbdata, // I - Callback data (not used)
|
||||
const void *buffer, // I - Buffer to write
|
||||
size_t bytes) // I - Number of bytes to write
|
||||
{
|
||||
(void)output_cbdata;
|
||||
|
||||
return ((ssize_t)fwrite(buffer, 1, bytes, stdout));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'usage()' - Show program usage.
|
||||
//
|
||||
|
||||
static int // O - Exit status
|
||||
usage(FILE *out) // I - stdout or stderr
|
||||
{
|
||||
fputs("Usage: pdfmerge [OPTIONS] INPUT.pdf [... INPUT.pdf] >OUTPUT.pdf\n", out);
|
||||
fputs("Options:\n", out);
|
||||
fputs(" --help Show help.\n", out);
|
||||
fputs(" -o OUTPUT.pdf Send output to filename instead of stdout.\n", out);
|
||||
|
||||
return (out == stdout ? 0 : 1);
|
||||
}
|
||||
45
makesrcdist
@@ -7,6 +7,10 @@
|
||||
# ./makesrcdist [--snapshot] VERSION
|
||||
#
|
||||
|
||||
# Save the current directory...
|
||||
basedir="$(pwd)"
|
||||
|
||||
|
||||
# Support "--snapshot" option...
|
||||
if test "$1" == "--snapshot"; then
|
||||
shift
|
||||
@@ -15,28 +19,31 @@ else
|
||||
snapshot=0
|
||||
fi
|
||||
|
||||
# Get version...
|
||||
|
||||
# Get the release version...
|
||||
if test $# != 1; then
|
||||
echo "Usage: ./makesrcdist [--snapshot] VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
status=0
|
||||
version=$1
|
||||
version_major=$(echo $1 | awk -F. '{print $1}')
|
||||
version_minor=$(echo $1 | awk -F. '{print $2}')
|
||||
|
||||
|
||||
# Check that version number has been updated everywhere...
|
||||
status=0
|
||||
|
||||
if test $(grep AC_INIT configure.ac | awk '{print $2}') != "[$version],"; then
|
||||
echo "Still need to update AC_INIT version in 'configure.ac'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(head -4 CHANGES.md | tail -1 | awk '{print $1}') != "v$version"; then
|
||||
if test $(head -5 CHANGES.md | tail -1 | awk '{print $1}') != "v$version"; then
|
||||
echo "Still need to update CHANGES.md version number."
|
||||
status=1
|
||||
fi
|
||||
if test $(head -4 CHANGES.md | tail -1 | awk '{print $3}') = "YYYY-MM-DD"; then
|
||||
if test $(head -5 CHANGES.md | tail -1 | awk '{print $3}') = "YYYY-MM-DD"; then
|
||||
echo "Still need to update CHANGES.md release date."
|
||||
status=1
|
||||
fi
|
||||
@@ -78,18 +85,32 @@ if test $status = 1; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Tag release...
|
||||
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 push origin v$version
|
||||
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...
|
||||
git archive --format zip --prefix=pdfio-$version/ HEAD >pdfio-$version.zip
|
||||
gpg --detach-sign pdfio-$version.zip
|
||||
# Make and sign source archives...
|
||||
echo "Exporting $version..."
|
||||
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.
|
||||
//
|
||||
// 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
|
||||
// information.
|
||||
@@ -117,7 +117,7 @@ _pdfioCryptoAESInit(
|
||||
memcpy(ctx->round_key, key, keylen);
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// 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
|
||||
// information.
|
||||
@@ -262,7 +262,11 @@ pdfioArrayCopy(pdfio_file_t *pdf, // I - PDF file
|
||||
vdst; // Current destination value
|
||||
|
||||
|
||||
PDFIO_DEBUG("pdfioArrayCopy(pdf=%p, a=%p(%p))\n", pdf, a, a ? 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...
|
||||
if ((na = pdfioArrayCreate(pdf)) == NULL)
|
||||
@@ -606,7 +610,7 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfio_value_t value; // Value
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioArrayRead(pdf=%p, tb=%p)\n", pdf, tb);
|
||||
PDFIO_DEBUG("_pdfioArrayRead(pdf=%p, tb=%p)\n", (void *)pdf, (void *)tb);
|
||||
|
||||
// Create an array...
|
||||
if ((array = pdfioArrayCreate(pdf)) == NULL)
|
||||
@@ -640,6 +644,8 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
|
||||
//
|
||||
// 'pdfioArrayRemove()' - Remove an array entry.
|
||||
//
|
||||
// @since PDFio v1.4@
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` otherwise
|
||||
pdfioArrayRemove(pdfio_array_t *a, // I - Array
|
||||
@@ -664,27 +670,29 @@ pdfioArrayRemove(pdfio_array_t *a, // I - Array
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` otherwise
|
||||
_pdfioArrayWrite(pdfio_array_t *a, // I - Array
|
||||
pdfio_obj_t *obj) // I - Object, if any
|
||||
_pdfioArrayWrite(
|
||||
_pdfio_printf_t cb, // I - Printf callback function
|
||||
void *cbdata, // I - Printf callback data
|
||||
pdfio_obj_t *obj, // I - Object, if any
|
||||
pdfio_array_t *a) // I - Array
|
||||
{
|
||||
pdfio_file_t *pdf = a->pdf; // PDF file
|
||||
size_t i; // Looping var
|
||||
_pdfio_value_t *v; // Current value
|
||||
|
||||
|
||||
// Arrays are surrounded by square brackets ([ ... ])
|
||||
if (!_pdfioFilePuts(pdf, "["))
|
||||
if (!(cb)(cbdata, "["))
|
||||
return (false);
|
||||
|
||||
// Write each value...
|
||||
for (i = a->num_values, v = a->values; i > 0; i --, v ++)
|
||||
{
|
||||
if (!_pdfioValueWrite(pdf, obj, v, NULL))
|
||||
if (!_pdfioValueWrite(cb, cbdata, obj, v, NULL))
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Closing bracket...
|
||||
return (_pdfioFilePuts(pdf, "]"));
|
||||
return ((cb)(cbdata, "]"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
532
pdfio-cgats001-compat.h
Normal file
@@ -0,0 +1,532 @@
|
||||
/* CGATS001Compat-v2-micro.icc */
|
||||
static unsigned char CGATS001Compat_v2_micro_icc[] = {
|
||||
0,0,33,16,65,68,66,69,2,16,0,0,115,99,110,114,
|
||||
67,77,89,75,76,97,98,32,7,230,0,12,0,7,0,22,
|
||||
0,16,0,42,97,99,115,112,77,83,70,84,0,0,0,0,
|
||||
115,97,119,115,99,116,114,108,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,246,214,0,1,0,0,0,0,211,45,
|
||||
104,97,110,100,195,103,209,209,26,217,105,182,62,57,156,48,
|
||||
22,179,165,88,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,4,100,101,115,99,0,0,0,180,0,0,0,95,
|
||||
99,112,114,116,0,0,0,208,0,0,0,12,119,116,112,116,
|
||||
0,0,0,220,0,0,0,20,65,50,66,48,0,0,0,240,
|
||||
0,0,32,32,100,101,115,99,0,0,0,0,0,0,0,5,
|
||||
117,67,77,89,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
116,101,120,116,0,0,0,0,67,67,48,0,88,89,90,32,
|
||||
0,0,0,0,0,0,246,214,0,1,0,0,0,0,211,45,
|
||||
109,102,116,50,0,0,0,0,4,3,6,0,0,1,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
|
||||
0,48,0,2,0,0,10,35,16,0,22,155,28,150,35,8,
|
||||
41,37,47,68,53,83,59,90,65,90,71,78,77,74,83,48,
|
||||
89,25,94,245,100,188,106,133,112,43,117,193,123,79,128,187,
|
||||
134,23,139,107,144,166,149,206,154,244,160,21,165,30,170,40,
|
||||
175,51,180,64,185,71,190,81,195,91,200,103,205,100,210,85,
|
||||
215,65,220,33,224,252,229,190,234,87,238,218,243,138,248,23,
|
||||
252,104,255,255,0,0,8,214,13,206,19,98,24,129,30,6,
|
||||
35,77,40,160,46,0,51,86,56,193,62,41,67,165,73,37,
|
||||
78,162,84,51,89,175,95,46,100,173,106,10,111,107,116,191,
|
||||
121,244,127,36,132,82,137,98,142,111,147,127,152,147,157,151,
|
||||
162,172,167,211,173,14,178,88,183,186,189,52,194,199,200,90,
|
||||
205,244,211,154,217,72,223,1,228,146,234,19,239,215,245,132,
|
||||
251,7,255,255,0,0,9,30,14,44,19,200,24,222,30,99,
|
||||
35,150,40,200,45,246,51,35,56,84,61,138,66,209,72,33,
|
||||
77,126,82,234,88,89,93,211,99,74,104,190,110,47,115,148,
|
||||
120,237,126,59,131,126,136,180,141,231,147,29,152,90,157,169,
|
||||
163,18,168,158,174,79,180,41,186,39,192,69,198,114,204,164,
|
||||
210,199,216,201,222,161,228,73,233,160,238,170,243,244,248,186,
|
||||
252,225,255,255,0,0,8,135,13,57,18,115,23,60,28,123,
|
||||
33,106,38,94,43,92,48,99,53,110,58,133,63,163,68,202,
|
||||
73,244,79,35,84,77,89,109,94,139,99,158,104,170,109,176,
|
||||
114,172,119,156,124,135,129,112,134,74,139,35,143,254,148,223,
|
||||
153,201,158,194,163,209,168,251,174,67,179,163,185,36,190,202,
|
||||
196,145,202,125,208,133,214,166,220,240,227,93,234,118,241,193,
|
||||
249,40,255,255,255,0,128,0,128,0,214,110,127,181,126,251,
|
||||
173,86,127,150,126,88,131,53,127,186,126,83,86,78,128,50,
|
||||
126,192,31,100,129,254,128,28,251,120,125,171,146,104,211,247,
|
||||
125,155,142,161,171,46,125,194,139,106,129,32,126,37,136,221,
|
||||
84,57,126,196,134,230,28,170,128,62,134,99,248,103,123,237,
|
||||
165,11,209,76,123,249,158,148,168,209,124,68,152,192,127,22,
|
||||
124,213,147,218,82,110,125,139,143,116,26,73,126,145,140,106,
|
||||
245,211,122,201,183,251,206,211,122,205,174,205,166,160,123,35,
|
||||
166,133,125,42,123,200,159,52,80,217,124,141,151,243,24,82,
|
||||
125,10,144,4,243,199,122,9,203,97,204,207,121,247,191,95,
|
||||
164,205,122,74,180,169,123,179,123,1,171,70,79,144,123,201,
|
||||
163,159,22,200,123,191,143,103,242,42,121,140,223,132,203,50,
|
||||
121,98,208,125,163,73,121,169,195,108,122,115,122,107,184,86,
|
||||
78,150,123,56,174,96,21,158,122,200,142,157,227,233,142,168,
|
||||
125,57,191,208,140,54,124,173,154,204,138,30,124,141,116,50,
|
||||
136,124,124,247,74,84,135,121,125,199,20,34,137,177,127,236,
|
||||
224,239,140,172,141,230,189,193,138,73,138,227,152,241,136,91,
|
||||
136,116,114,87,134,238,134,171,72,129,134,18,133,143,18,45,
|
||||
135,202,133,165,222,108,139,13,159,8,187,88,136,200,153,179,
|
||||
150,192,134,245,148,251,112,129,133,173,145,24,70,249,132,229,
|
||||
142,34,16,97,134,27,137,235,220,58,137,245,176,93,185,57,
|
||||
135,184,168,203,148,204,133,239,161,238,110,212,132,170,155,243,
|
||||
69,169,131,235,151,169,15,9,132,165,138,43,218,113,137,45,
|
||||
194,46,183,137,134,242,184,87,147,63,133,43,175,95,109,144,
|
||||
131,243,167,166,68,161,131,41,161,166,14,7,131,135,137,124,
|
||||
217,12,136,152,212,229,182,53,134,99,200,164,145,250,132,152,
|
||||
189,153,108,133,131,103,180,155,67,209,130,165,170,33,13,68,
|
||||
130,183,136,248,201,213,157,235,123,46,169,121,153,123,122,234,
|
||||
136,53,149,117,123,19,101,12,146,14,123,193,62,13,143,191,
|
||||
124,214,9,84,144,204,127,187,199,84,156,73,138,107,167,205,
|
||||
151,198,136,7,134,185,147,217,134,42,99,150,144,153,132,246,
|
||||
60,167,142,98,132,135,8,113,142,126,132,36,197,113,154,202,
|
||||
153,237,165,235,150,98,149,123,132,247,146,119,145,165,98,4,
|
||||
143,82,142,167,59,93,141,42,140,19,7,182,140,158,133,55,
|
||||
195,166,153,193,169,229,164,50,149,94,163,134,131,66,145,135,
|
||||
157,217,96,149,142,92,153,26,58,81,140,51,150,79,7,25,
|
||||
139,41,132,204,194,42,153,10,186,48,162,214,148,166,177,236,
|
||||
129,253,144,210,170,123,95,138,141,175,164,116,57,139,139,110,
|
||||
159,13,6,174,138,21,132,132,192,255,152,123,203,106,161,198,
|
||||
148,25,193,44,128,245,144,72,184,9,94,179,141,45,177,103,
|
||||
56,235,138,244,165,100,6,89,137,77,132,75,177,37,173,245,
|
||||
122,2,147,243,167,169,121,209,117,242,161,206,122,23,85,235,
|
||||
156,180,122,225,49,88,150,201,124,2,0,239,149,92,127,195,
|
||||
175,57,172,141,135,237,146,202,166,25,133,179,116,224,160,67,
|
||||
132,66,84,210,155,60,131,120,48,93,152,11,131,193,0,226,
|
||||
147,96,128,133,173,202,171,58,150,19,145,79,164,217,146,68,
|
||||
115,118,159,2,143,29,83,154,154,5,140,217,47,124,150,201,
|
||||
140,54,0,206,145,182,128,139,172,145,170,52,164,133,144,19,
|
||||
163,219,159,13,114,58,158,5,154,89,82,143,152,241,150,198,
|
||||
46,202,149,168,148,235,0,217,144,85,128,147,171,106,169,130,
|
||||
179,137,143,32,163,20,172,85,113,80,157,63,162,160,81,202,
|
||||
152,62,161,248,46,73,148,212,155,139,0,219,143,72,128,148,
|
||||
170,119,169,1,195,84,142,87,162,131,186,91,112,151,156,179,
|
||||
178,242,81,58,151,186,174,21,45,236,148,82,159,13,0,222,
|
||||
142,134,128,150,154,49,190,221,121,79,127,198,182,195,121,6,
|
||||
100,136,175,54,121,74,71,42,168,146,122,23,36,45,165,99,
|
||||
123,14,0,0,143,153,128,0,152,249,189,121,134,22,127,13,
|
||||
181,72,132,75,99,211,173,165,130,235,70,115,166,244,130,111,
|
||||
35,202,163,124,130,239,0,0,142,213,128,0,152,46,188,21,
|
||||
146,252,126,42,179,238,143,148,98,240,172,64,140,239,69,182,
|
||||
165,143,139,90,35,118,161,226,138,239,0,0,142,33,128,0,
|
||||
151,95,187,20,156,183,125,105,178,222,152,248,98,53,171,44,
|
||||
148,44,69,34,164,102,145,119,35,60,160,141,143,228,0,0,
|
||||
141,150,128,0,150,186,186,65,173,194,124,235,177,250,167,108,
|
||||
97,205,170,70,162,133,68,210,163,131,159,209,35,33,159,106,
|
||||
150,67,0,0,141,57,128,0,150,10,185,176,188,68,124,138,
|
||||
177,69,180,40,97,126,169,128,174,82,68,159,162,198,170,52,
|
||||
35,38,158,179,151,196,0,0,140,230,128,0,132,180,208,159,
|
||||
120,243,108,190,198,205,120,107,83,203,189,201,120,144,56,144,
|
||||
181,241,121,63,22,242,178,158,122,81,0,0,137,249,128,0,
|
||||
132,84,206,246,132,213,108,102,197,80,130,218,83,105,188,24,
|
||||
129,168,56,75,180,0,129,93,23,73,176,8,130,10,0,0,
|
||||
138,37,128,0,132,67,205,78,144,147,108,56,195,164,141,107,
|
||||
83,48,186,79,139,41,56,52,178,35,138,58,23,180,173,196,
|
||||
137,41,0,0,138,73,128,0,132,35,203,251,156,155,108,55,
|
||||
194,41,152,56,83,60,184,196,149,21,56,85,176,133,148,4,
|
||||
24,42,171,234,144,154,0,0,138,101,128,0,131,240,202,242,
|
||||
168,242,108,66,193,0,163,54,83,110,183,140,159,100,56,150,
|
||||
175,80,157,234,24,158,170,120,144,165,0,0,138,121,128,0,
|
||||
131,190,202,18,181,197,108,88,192,13,174,136,83,181,182,138,
|
||||
170,24,56,250,174,76,165,33,25,38,169,99,145,1,0,0,
|
||||
138,136,128,0,235,21,120,95,117,172,198,143,121,103,118,146,
|
||||
160,155,122,106,119,154,120,244,123,117,120,218,78,61,124,157,
|
||||
122,46,24,103,126,52,123,43,231,220,117,150,135,222,195,241,
|
||||
118,230,133,232,158,88,120,46,132,101,118,244,121,124,131,68,
|
||||
76,100,122,195,129,102,22,11,123,166,130,96,228,245,115,130,
|
||||
154,56,193,46,116,236,149,151,155,232,118,93,145,116,116,232,
|
||||
119,221,141,248,74,174,121,54,138,229,19,252,121,133,135,196,
|
||||
226,139,114,5,172,159,190,208,115,112,165,140,153,177,116,238,
|
||||
158,247,114,251,118,134,153,19,73,38,119,231,148,52,18,94,
|
||||
119,220,139,241,224,194,113,11,191,52,189,12,114,105,181,200,
|
||||
151,244,115,224,172,209,113,127,117,135,164,211,71,234,118,225,
|
||||
158,108,17,36,118,168,139,151,223,129,112,120,210,33,187,195,
|
||||
113,192,198,94,150,146,115,32,187,38,112,68,116,200,177,102,
|
||||
70,235,118,28,168,223,16,59,117,202,138,249,209,115,134,135,
|
||||
115,123,177,87,133,101,116,211,143,52,132,136,118,40,106,212,
|
||||
131,237,119,166,66,203,131,210,121,44,13,68,133,161,122,166,
|
||||
207,74,132,21,132,44,175,136,131,38,130,252,141,102,130,108,
|
||||
130,15,105,23,129,246,129,111,65,44,129,242,129,3,11,242,
|
||||
131,47,128,187,204,230,130,32,148,250,173,11,129,68,145,118,
|
||||
139,42,128,171,142,60,103,60,128,104,139,143,63,171,128,112,
|
||||
137,123,10,160,129,38,133,169,202,204,128,181,165,229,170,253,
|
||||
127,222,160,68,137,59,127,80,154,224,101,154,127,25,150,30,
|
||||
62,106,127,39,146,206,9,181,127,147,134,144,201,66,127,194,
|
||||
183,38,169,111,126,232,175,109,135,176,126,82,167,231,100,77,
|
||||
126,40,161,100,61,104,126,40,156,138,9,4,126,105,134,24,
|
||||
200,52,127,42,201,23,168,66,126,72,191,65,134,106,125,151,
|
||||
181,160,99,54,125,111,173,200,60,152,125,113,164,221,8,120,
|
||||
125,143,133,186,184,173,149,106,113,228,156,34,146,61,115,98,
|
||||
125,114,143,136,116,221,92,54,141,74,118,127,54,161,140,45,
|
||||
120,8,3,238,139,88,123,49,182,255,147,72,129,49,154,137,
|
||||
144,64,128,123,123,227,141,162,127,240,90,199,139,126,127,190,
|
||||
53,89,138,93,127,196,3,128,136,228,128,74,181,64,145,117,
|
||||
144,98,152,169,142,132,141,169,122,46,139,240,139,55,89,77,
|
||||
137,236,137,71,52,47,136,204,136,38,3,22,134,234,130,22,
|
||||
179,141,144,32,160,3,151,4,141,51,155,112,120,129,138,173,
|
||||
151,29,87,228,136,172,147,114,51,37,135,135,145,82,2,193,
|
||||
133,95,129,221,178,73,143,62,175,217,149,185,140,83,169,123,
|
||||
119,61,137,196,163,94,86,209,135,201,158,101,50,96,134,132,
|
||||
153,234,2,137,132,59,129,182,177,102,142,167,192,110,148,187,
|
||||
139,188,184,74,118,48,137,28,176,117,85,236,135,30,170,208,
|
||||
49,180,133,217,160,46,2,88,131,104,129,150,161,39,165,31,
|
||||
112,232,135,104,160,39,114,94,107,178,155,186,115,225,77,78,
|
||||
151,243,117,130,41,135,150,141,118,177,0,66,137,171,126,52,
|
||||
160,0,163,78,126,58,134,90,158,94,125,202,106,159,153,235,
|
||||
126,68,76,76,150,41,126,114,40,187,148,150,126,116,0,60,
|
||||
135,218,127,249,158,179,161,163,140,195,132,230,156,194,138,139,
|
||||
105,69,152,84,136,161,75,40,148,163,135,100,39,242,146,245,
|
||||
134,224,0,50,134,74,128,34,157,132,160,84,154,226,131,173,
|
||||
155,126,151,25,104,13,151,13,147,166,74,49,147,72,145,0,
|
||||
39,88,145,123,143,118,0,46,133,35,128,31,156,138,159,124,
|
||||
169,118,130,195,154,160,164,33,103,23,150,32,159,51,73,88,
|
||||
146,97,155,208,38,210,144,100,150,43,0,40,132,62,128,27,
|
||||
155,211,158,242,184,169,130,0,154,13,177,217,102,77,149,124,
|
||||
171,165,72,175,145,184,167,171,38,95,143,176,153,237,0,36,
|
||||
131,152,128,24,139,20,181,218,112,19,115,151,175,83,113,97,
|
||||
90,95,169,85,114,209,62,89,164,67,116,78,27,220,162,240,
|
||||
117,20,0,0,132,76,128,0,138,120,180,61,125,106,115,25,
|
||||
173,150,124,255,89,217,167,107,124,81,61,228,162,62,124,151,
|
||||
27,203,160,109,125,6,0,0,131,187,128,0,137,192,178,136,
|
||||
137,145,114,53,171,233,135,226,88,255,165,185,134,144,61,56,
|
||||
160,141,133,174,27,150,158,104,133,23,0,0,131,37,128,0,
|
||||
136,247,177,65,150,121,113,106,170,160,145,137,88,50,164,101,
|
||||
144,140,60,162,159,30,142,229,27,110,156,173,140,81,0,0,
|
||||
130,194,128,0,136,101,176,88,163,151,112,222,169,174,159,42,
|
||||
87,167,163,100,155,105,60,52,158,16,153,106,27,92,155,60,
|
||||
144,208,0,0,130,140,128,0,135,225,175,208,177,149,112,130,
|
||||
169,4,171,225,87,60,162,144,167,47,59,221,157,49,163,199,
|
||||
27,68,154,81,146,112,0,0,130,90,128,0,118,47,199,165,
|
||||
111,81,96,137,191,214,112,85,73,93,184,132,113,146,47,37,
|
||||
178,156,114,188,14,114,176,12,115,215,0,0,129,66,128,0,
|
||||
118,37,198,9,123,103,96,145,189,252,122,224,73,95,182,83,
|
||||
122,140,47,79,176,27,122,242,15,16,173,6,123,149,0,0,
|
||||
129,65,128,0,118,26,196,25,134,225,96,81,188,12,133,19,
|
||||
73,32,180,78,131,219,47,67,173,249,131,127,15,152,170,90,
|
||||
131,15,0,0,129,64,128,0,117,232,194,153,146,128,96,44,
|
||||
186,112,143,187,72,249,178,157,141,124,47,72,172,34,141,8,
|
||||
16,17,168,31,136,88,0,0,129,63,128,0,117,180,193,153,
|
||||
158,127,96,36,185,65,154,198,72,250,177,80,152,1,47,90,
|
||||
170,197,151,16,16,120,166,98,139,34,0,0,129,63,128,0,
|
||||
117,138,192,236,171,6,96,44,184,93,166,88,73,12,176,73,
|
||||
163,22,47,127,169,175,158,184,16,201,165,41,139,89,0,0,
|
||||
129,62,128,0,215,58,112,125,107,98,182,48,114,183,110,9,
|
||||
147,81,116,191,112,146,110,79,118,168,115,18,69,242,120,110,
|
||||
117,99,17,41,122,4,118,21,212,37,109,25,125,61,179,174,
|
||||
111,175,125,19,145,41,114,6,125,27,108,110,116,58,125,82,
|
||||
68,67,118,17,125,118,15,115,119,100,124,211,209,76,106,99,
|
||||
143,18,176,232,109,33,140,81,142,189,111,175,137,216,106,111,
|
||||
114,31,135,215,66,173,115,252,133,236,14,12,117,65,131,106,
|
||||
206,240,104,112,160,225,174,148,107,62,155,216,140,130,109,225,
|
||||
150,255,104,143,112,110,146,160,65,64,114,73,142,92,12,238,
|
||||
115,154,136,44,205,74,103,27,178,184,172,233,105,229,171,138,
|
||||
138,211,108,132,164,100,103,24,111,33,157,249,64,30,112,232,
|
||||
153,0,12,32,114,96,136,51,204,67,102,85,196,179,171,201,
|
||||
105,11,187,103,137,134,107,139,178,19,101,232,110,39,169,242,
|
||||
63,37,113,29,163,2,11,134,113,150,135,202,191,51,125,253,
|
||||
105,204,162,88,126,40,108,203,130,244,126,117,111,124,96,224,
|
||||
126,227,114,20,58,181,127,161,116,87,6,250,129,135,117,232,
|
||||
189,59,122,243,122,101,160,121,123,114,122,237,129,38,123,241,
|
||||
123,66,95,70,124,136,123,210,57,87,125,61,124,104,6,56,
|
||||
126,240,124,161,186,231,120,104,138,147,158,7,121,10,136,216,
|
||||
126,247,121,180,135,50,93,119,122,128,133,202,55,236,123,44,
|
||||
132,147,5,122,125,75,129,223,184,229,118,148,155,6,156,7,
|
||||
119,69,151,69,125,15,119,255,147,122,91,227,120,220,144,16,
|
||||
54,189,121,122,141,190,4,240,123,230,131,75,183,122,117,78,
|
||||
171,160,154,140,117,255,165,231,123,150,118,180,160,18,90,158,
|
||||
119,159,154,248,53,206,120,29,151,54,4,139,123,11,131,18,
|
||||
182,151,116,140,188,154,153,124,117,45,180,249,122,105,117,198,
|
||||
173,42,89,148,118,175,166,195,52,247,119,27,159,91,4,58,
|
||||
122,75,130,219,168,10,140,102,104,152,142,157,138,129,107,167,
|
||||
114,84,137,23,110,98,83,5,136,13,112,248,46,178,136,50,
|
||||
114,232,0,0,134,1,119,195,166,152,137,165,119,142,140,252,
|
||||
136,21,120,113,112,187,134,199,121,68,81,165,133,209,122,43,
|
||||
45,147,133,199,122,111,0,0,131,203,125,115,164,228,135,58,
|
||||
134,91,139,30,133,208,133,102,111,24,132,156,132,87,80,93,
|
||||
131,190,131,134,44,163,131,149,130,248,0,0,129,242,128,0,
|
||||
163,51,133,129,149,157,137,135,132,33,146,220,109,118,130,247,
|
||||
143,243,78,252,130,37,141,109,43,168,129,222,139,252,0,0,
|
||||
128,80,128,0,162,3,132,83,164,223,136,69,130,249,160,109,
|
||||
108,52,129,194,155,194,77,229,128,243,151,242,42,242,128,117,
|
||||
148,112,0,0,128,0,128,0,161,66,131,152,180,173,135,81,
|
||||
130,59,174,155,107,41,128,225,168,60,77,1,128,10,163,180,
|
||||
42,74,127,120,154,175,0,0,128,0,128,0,145,188,155,172,
|
||||
103,193,122,194,152,25,106,174,97,34,149,28,109,90,68,88,
|
||||
146,185,111,205,33,58,147,6,113,3,0,0,128,158,125,23,
|
||||
144,178,153,85,117,117,121,161,149,241,118,113,96,7,146,235,
|
||||
119,201,67,104,144,128,120,192,32,163,144,90,120,208,0,0,
|
||||
128,83,127,160,143,100,151,24,131,16,120,32,147,209,130,146,
|
||||
94,175,144,218,130,3,66,85,142,130,129,188,32,1,142,10,
|
||||
128,235,0,0,128,0,128,0,142,45,149,108,144,194,118,226,
|
||||
146,54,142,170,93,120,143,61,140,135,65,117,140,210,138,222,
|
||||
31,136,140,18,137,181,0,0,128,0,128,0,141,62,148,80,
|
||||
158,204,117,254,145,26,155,76,92,129,142,10,151,180,64,146,
|
||||
139,158,149,70,31,15,138,141,145,227,0,0,128,0,128,0,
|
||||
140,159,147,161,173,59,117,64,144,98,168,119,91,182,141,51,
|
||||
163,160,63,227,138,184,160,184,30,155,137,127,148,146,0,0,
|
||||
128,0,128,0,124,171,172,10,102,190,103,126,167,39,105,111,
|
||||
80,11,162,201,107,245,53,57,159,120,110,24,19,165,158,208,
|
||||
111,20,0,0,128,0,128,0,123,249,170,24,116,224,102,230,
|
||||
165,24,117,140,79,132,160,128,117,94,52,226,156,255,118,88,
|
||||
19,187,155,193,119,9,0,0,128,0,128,0,123,42,167,228,
|
||||
127,253,101,234,162,244,127,85,78,167,158,94,127,12,52,67,
|
||||
154,215,126,238,19,159,153,39,127,38,0,0,128,0,128,0,
|
||||
122,87,166,68,140,182,101,22,161,89,139,59,77,209,156,183,
|
||||
137,52,51,180,153,17,136,91,19,135,150,246,134,122,0,0,
|
||||
128,0,128,0,121,194,165,30,152,238,100,130,160,44,150,73,
|
||||
77,54,155,119,147,192,51,58,151,189,146,136,19,131,149,48,
|
||||
139,58,0,0,128,0,128,0,121,80,164,119,166,54,100,51,
|
||||
159,99,162,165,76,201,154,118,159,46,50,220,150,162,156,195,
|
||||
19,98,147,245,141,27,0,0,128,0,128,0,104,127,189,181,
|
||||
101,120,84,142,183,253,103,201,62,206,178,149,106,4,37,57,
|
||||
175,32,107,133,7,201,168,185,110,103,0,0,128,0,128,0,
|
||||
104,19,188,17,113,56,84,117,181,220,113,249,62,221,175,253,
|
||||
114,239,37,150,172,20,115,158,8,71,165,174,118,13,0,0,
|
||||
128,0,128,0,103,206,185,191,124,128,84,14,179,133,124,35,
|
||||
62,146,173,145,124,7,37,152,169,115,124,23,8,149,163,10,
|
||||
125,3,0,0,128,0,128,0,103,132,183,243,135,237,83,215,
|
||||
177,160,134,186,62,83,171,151,133,157,37,151,167,69,133,155,
|
||||
8,210,160,225,134,24,0,0,128,0,128,0,103,71,182,193,
|
||||
147,197,83,203,176,53,145,186,62,65,170,12,143,228,37,150,
|
||||
165,157,143,124,9,4,159,47,134,25,0,0,128,0,128,0,
|
||||
103,34,182,5,159,118,83,218,175,42,156,247,62,66,168,216,
|
||||
154,228,37,162,164,81,151,207,9,28,157,237,134,41,0,0,
|
||||
128,0,128,0,195,134,104,39,97,50,165,143,107,98,101,100,
|
||||
133,177,110,87,105,86,99,107,113,26,109,23,61,117,115,78,
|
||||
112,105,10,197,118,146,113,155,192,120,99,196,114,159,163,37,
|
||||
103,127,116,32,131,159,106,221,117,164,97,161,109,247,119,42,
|
||||
59,237,112,35,120,108,9,208,115,227,120,197,189,150,96,56,
|
||||
131,182,160,101,100,60,130,212,129,66,103,227,130,4,95,178,
|
||||
107,69,129,80,58,117,109,94,128,220,8,252,114,54,127,181,
|
||||
187,44,93,116,149,0,158,28,97,167,145,220,127,29,101,119,
|
||||
142,191,93,247,105,0,139,222,57,48,106,248,136,228,8,98,
|
||||
114,207,133,15,185,130,91,150,166,49,156,129,95,216,160,239,
|
||||
125,137,99,178,155,159,92,152,103,80,150,226,56,49,105,27,
|
||||
147,108,7,231,114,249,133,88,184,132,90,105,183,86,155,115,
|
||||
94,161,175,238,124,98,98,101,168,131,91,140,105,1,162,44,
|
||||
55,84,103,155,156,250,7,143,115,57,133,29,173,93,116,242,
|
||||
96,48,147,55,118,74,100,152,118,92,119,176,104,140,86,142,
|
||||
121,30,108,57,50,50,122,128,111,45,2,87,126,109,114,86,
|
||||
171,85,112,240,112,28,145,91,114,194,114,35,116,164,116,109,
|
||||
115,251,85,28,118,12,117,186,49,17,119,53,119,0,2,43,
|
||||
125,195,121,110,168,240,109,150,128,2,142,230,111,169,127,232,
|
||||
114,129,113,144,127,187,83,92,115,109,127,135,47,194,116,98,
|
||||
127,74,1,226,125,94,127,32,166,228,106,254,143,238,140,233,
|
||||
109,54,141,221,112,164,111,63,139,156,81,229,113,51,137,125,
|
||||
46,184,113,233,136,69,1,188,125,70,129,22,165,119,105,58,
|
||||
159,231,139,118,107,126,155,238,111,59,109,141,151,183,80,175,
|
||||
111,144,148,16,45,231,112,10,145,123,1,153,125,77,129,20,
|
||||
164,153,104,24,176,2,138,114,106,82,170,42,110,35,111,42,
|
||||
164,16,79,186,110,75,159,42,45,29,110,151,153,133,1,123,
|
||||
125,127,129,0,151,185,130,155,95,107,128,155,130,26,99,200,
|
||||
102,131,129,250,103,171,73,25,130,36,107,48,37,224,131,72,
|
||||
109,106,0,0,128,15,119,32,150,37,126,232,109,252,126,233,
|
||||
126,222,112,71,100,238,126,239,114,85,71,211,127,49,116,50,
|
||||
36,254,127,224,117,40,0,0,128,0,125,1,148,89,123,191,
|
||||
124,214,124,252,123,247,125,43,99,88,124,49,125,116,70,157,
|
||||
124,147,125,171,36,61,124,241,125,162,0,0,128,0,128,0,
|
||||
146,160,121,84,139,48,123,96,121,170,138,25,97,182,121,248,
|
||||
136,132,69,80,122,100,134,203,35,88,122,135,134,48,0,0,
|
||||
128,0,128,0,145,107,119,175,153,210,122,36,120,16,150,250,
|
||||
96,132,120,91,147,207,68,71,120,200,145,64,34,188,120,174,
|
||||
142,195,0,0,128,0,128,0,144,162,120,93,168,186,121,57,
|
||||
120,129,164,90,95,144,120,148,159,155,67,117,120,204,156,88,
|
||||
34,21,119,83,148,183,0,0,128,0,128,0,130,198,145,99,
|
||||
94,162,109,209,143,77,98,193,86,12,141,196,102,123,58,184,
|
||||
140,221,105,176,24,115,141,200,107,28,0,0,128,0,124,73,
|
||||
129,132,142,31,107,235,108,146,140,92,110,64,84,240,138,218,
|
||||
113,211,57,230,137,229,115,138,24,36,138,59,114,239,0,0,
|
||||
128,0,127,132,128,22,139,40,121,37,107,6,137,153,122,194,
|
||||
83,165,136,48,123,82,56,243,135,70,123,12,23,189,135,58,
|
||||
123,75,0,0,128,0,128,0,126,190,136,215,135,50,105,197,
|
||||
135,98,134,150,82,127,133,248,133,151,56,76,132,242,133,17,
|
||||
23,130,132,161,132,185,0,0,128,0,128,0,125,190,135,83,
|
||||
147,232,104,226,133,228,145,251,81,131,132,98,143,208,55,90,
|
||||
131,82,142,43,23,27,130,174,140,195,0,0,128,0,128,0,
|
||||
125,14,134,79,161,162,104,29,132,220,158,145,80,187,131,56,
|
||||
154,254,54,173,130,12,153,42,22,191,129,62,143,48,0,0,
|
||||
128,0,128,0,110,138,161,103,93,113,91,64,158,36,97,61,
|
||||
69,98,155,115,100,180,43,134,154,24,103,87,11,238,152,5,
|
||||
105,90,0,0,128,0,127,174,109,133,158,164,105,164,90,112,
|
||||
155,103,107,227,68,195,152,129,109,252,43,62,150,221,111,137,
|
||||
12,25,148,105,113,67,0,0,128,0,128,0,108,132,155,200,
|
||||
117,179,89,77,152,172,118,164,67,211,149,207,119,119,42,162,
|
||||
148,24,120,5,12,19,145,67,121,90,0,0,128,0,128,0,
|
||||
107,134,153,143,129,221,88,92,150,130,129,173,66,235,147,154,
|
||||
129,73,42,24,145,180,129,15,12,0,142,157,128,215,0,0,
|
||||
128,0,128,0,106,209,152,11,143,26,87,176,149,0,141,197,
|
||||
66,62,146,3,140,0,41,140,143,253,139,52,12,1,140,140,
|
||||
133,216,0,0,128,0,128,0,106,74,151,18,154,199,87,83,
|
||||
147,243,152,208,65,214,144,186,150,118,41,61,142,132,149,10,
|
||||
11,233,139,8,136,14,0,0,128,0,128,0,90,217,179,10,
|
||||
91,159,72,146,175,35,94,239,52,17,171,191,97,242,26,122,
|
||||
171,135,99,103,2,147,158,4,105,195,0,0,128,0,128,0,
|
||||
89,242,176,188,102,234,72,22,172,122,104,233,51,223,168,163,
|
||||
106,202,26,208,167,186,107,134,3,13,154,120,113,121,0,0,
|
||||
128,0,128,0,89,104,173,222,113,237,71,119,169,158,114,221,
|
||||
51,113,165,180,115,185,26,205,164,114,115,225,3,91,151,84,
|
||||
119,101,0,0,128,0,128,0,88,225,171,136,125,19,71,16,
|
||||
167,63,125,46,51,16,163,58,125,29,26,204,161,154,125,2,
|
||||
3,150,148,166,126,188,0,0,128,0,128,0,88,127,169,250,
|
||||
136,100,70,230,165,137,135,210,50,233,161,96,135,19,26,190,
|
||||
159,136,135,59,3,199,146,155,130,61,0,0,128,0,128,0,
|
||||
88,66,168,239,147,235,70,221,164,67,146,236,50,224,159,237,
|
||||
145,204,26,206,157,221,143,133,3,222,145,7,130,157,0,0,
|
||||
128,0,128,0,176,156,94,195,87,72,149,115,98,233,92,217,
|
||||
120,99,102,205,98,34,88,182,106,104,103,28,53,1,108,159,
|
||||
107,102,5,152,118,139,109,251,173,120,88,199,104,44,147,0,
|
||||
93,173,107,60,118,78,98,35,110,48,86,244,102,42,113,1,
|
||||
51,155,104,36,115,88,5,62,119,36,117,123,170,129,83,218,
|
||||
120,230,144,69,89,66,121,155,116,3,94,37,122,79,85,27,
|
||||
98,129,123,12,50,72,100,77,123,164,4,235,119,176,124,186,
|
||||
167,244,79,239,137,125,142,8,85,186,136,49,114,1,90,231,
|
||||
134,220,83,144,95,120,133,94,49,50,97,23,132,122,4,171,
|
||||
120,27,130,105,166,29,76,244,153,245,140,119,83,4,150,99,
|
||||
112,161,88,98,146,223,82,98,93,18,143,209,48,103,94,148,
|
||||
141,222,4,128,120,101,131,11,165,1,75,27,170,73,139,111,
|
||||
81,61,164,132,111,168,86,158,159,0,81,141,91,86,154,125,
|
||||
47,181,92,180,151,6,4,90,120,165,130,241,156,106,106,192,
|
||||
86,220,132,107,109,76,92,113,105,223,111,205,97,148,76,63,
|
||||
114,46,102,77,41,113,115,222,105,208,0,133,127,32,112,194,
|
||||
154,6,101,52,102,67,130,120,104,112,105,168,104,51,107,92,
|
||||
108,201,74,235,109,253,111,166,40,136,111,123,113,155,0,121,
|
||||
127,52,119,248,151,123,96,136,117,195,127,250,100,52,119,22,
|
||||
102,27,103,124,120,55,73,62,106,97,121,62,39,94,107,182,
|
||||
121,207,0,101,127,85,125,231,149,85,92,216,133,116,125,254,
|
||||
96,208,133,45,100,78,100,86,131,234,71,229,103,88,131,7,
|
||||
38,123,104,160,130,168,0,90,127,104,128,21,147,206,90,13,
|
||||
148,102,124,145,94,51,145,245,98,253,97,219,143,75,70,199,
|
||||
100,234,141,18,37,213,102,40,139,156,0,82,127,118,128,55,
|
||||
146,221,88,74,163,183,123,146,92,123,159,112,97,255,96,28,
|
||||
154,247,69,241,99,40,151,144,37,38,100,94,147,151,0,74,
|
||||
127,132,128,50,136,83,119,164,86,119,114,249,120,152,91,224,
|
||||
90,200,121,197,96,207,63,24,123,14,101,47,28,228,124,239,
|
||||
103,177,0,0,128,0,118,153,134,86,114,117,100,134,113,39,
|
||||
116,9,104,12,89,55,117,132,107,62,61,232,118,232,110,10,
|
||||
28,63,120,131,111,111,0,0,128,0,124,173,132,83,110,13,
|
||||
114,153,111,34,112,8,116,89,87,166,113,196,117,216,60,195,
|
||||
115,69,119,23,27,177,116,190,119,163,0,0,128,0,128,0,
|
||||
130,119,106,149,129,11,109,119,108,205,130,35,86,4,110,179,
|
||||
128,158,59,134,112,55,128,143,26,244,113,202,129,140,0,0,
|
||||
128,0,128,0,129,36,103,242,142,177,108,51,106,79,140,179,
|
||||
84,214,108,70,139,126,58,135,109,187,138,52,26,128,111,130,
|
||||
137,83,0,0,128,0,128,0,128,71,102,62,157,11,107,73,
|
||||
104,167,154,28,83,238,106,146,150,196,57,196,107,241,148,173,
|
||||
25,237,109,244,142,180,0,0,128,0,128,0,116,102,133,188,
|
||||
85,206,97,9,133,77,90,232,74,225,133,71,95,143,48,197,
|
||||
133,211,99,100,15,223,135,31,101,112,0,0,128,0,123,165,
|
||||
114,183,129,2,98,152,95,147,129,17,102,24,73,174,129,44,
|
||||
105,65,47,247,129,153,107,201,15,177,130,194,109,55,0,0,
|
||||
128,0,127,79,113,14,124,224,111,119,93,220,125,64,113,115,
|
||||
72,73,125,135,115,40,46,243,125,235,116,107,15,86,127,106,
|
||||
117,126,0,0,128,0,128,0,111,138,121,149,124,88,92,114,
|
||||
122,42,124,241,71,9,122,128,125,56,46,66,122,185,125,99,
|
||||
15,42,124,159,125,207,0,0,128,0,128,0,110,95,119,23,
|
||||
138,202,91,117,119,207,138,10,70,19,120,28,137,0,45,94,
|
||||
120,38,135,245,14,222,122,140,135,102,0,0,128,0,128,0,
|
||||
109,149,121,89,150,108,90,170,121,119,148,158,69,84,118,115,
|
||||
146,87,44,190,118,78,145,129,14,137,120,225,137,87,0,0,
|
||||
128,0,128,0,96,221,149,113,84,82,79,24,147,218,89,8,
|
||||
58,133,146,240,93,68,32,234,148,5,96,5,5,223,142,72,
|
||||
100,242,0,0,128,0,127,76,95,109,145,55,96,1,77,234,
|
||||
143,234,99,97,57,154,142,232,102,93,32,131,143,118,104,29,
|
||||
6,7,138,144,108,199,0,0,128,0,128,0,94,36,141,70,
|
||||
107,194,76,143,140,50,109,216,56,136,139,63,111,156,31,218,
|
||||
139,127,112,111,5,254,135,60,116,52,0,0,128,0,128,0,
|
||||
92,237,138,30,122,85,75,113,137,51,120,146,55,133,136,57,
|
||||
121,39,31,91,136,14,123,110,5,246,132,117,123,118,0,0,
|
||||
128,0,128,0,91,246,135,172,131,111,74,141,134,231,131,84,
|
||||
54,186,133,222,130,234,30,202,133,72,130,209,6,11,130,149,
|
||||
129,136,0,0,128,0,128,0,91,71,134,25,143,189,74,30,
|
||||
133,105,142,218,54,108,132,29,141,96,30,192,131,24,140,170,
|
||||
6,8,129,66,132,20,0,0,128,0,128,0,77,84,167,52,
|
||||
81,238,60,225,164,229,86,29,41,102,163,178,89,171,15,187,
|
||||
165,245,91,30,0,0,143,192,102,232,0,0,128,0,128,0,
|
||||
76,0,163,132,92,179,59,195,161,83,95,199,40,139,159,206,
|
||||
98,84,15,179,160,234,99,35,0,0,141,58,110,94,0,0,
|
||||
128,0,128,0,75,38,159,158,103,107,58,198,157,140,105,113,
|
||||
39,202,155,249,107,4,15,139,156,80,107,83,0,0,138,237,
|
||||
113,76,0,0,128,0,128,0,74,77,156,103,114,86,58,10,
|
||||
154,119,115,117,39,52,152,188,116,26,15,133,152,85,116,52,
|
||||
0,33,136,220,120,138,0,0,128,0,128,0,73,149,153,242,
|
||||
125,109,57,132,152,31,125,200,38,211,150,60,125,178,15,95,
|
||||
149,64,125,240,0,63,135,71,127,146,0,0,128,0,128,0,
|
||||
73,42,152,77,136,216,57,58,150,125,136,168,38,173,148,107,
|
||||
136,30,15,114,147,1,134,175,0,80,134,33,128,54,0,0,
|
||||
128,0,128,0,158,251,83,213,77,213,134,82,88,228,84,162,
|
||||
107,209,93,194,91,44,78,135,98,47,97,81,44,208,100,17,
|
||||
102,124,1,123,125,128,107,25,155,163,75,156,94,40,131,186,
|
||||
81,193,98,171,105,163,87,113,102,252,76,186,92,94,107,9,
|
||||
43,127,94,109,110,93,1,148,125,85,114,218,152,136,68,110,
|
||||
110,104,128,251,75,123,112,169,103,104,81,210,114,214,74,252,
|
||||
87,33,116,232,42,89,89,132,118,188,1,168,125,50,122,87,
|
||||
149,187,62,95,127,39,126,199,70,68,127,37,101,151,77,45,
|
||||
126,223,73,179,82,194,126,247,41,128,85,129,127,2,1,184,
|
||||
125,23,128,57,147,155,57,144,141,195,125,55,66,42,139,246,
|
||||
100,109,73,147,138,142,72,188,79,81,137,33,40,239,82,91,
|
||||
136,147,1,196,125,4,129,50,146,51,54,15,157,180,124,41,
|
||||
63,34,153,134,99,178,70,225,149,233,72,51,76,186,147,48,
|
||||
40,130,79,242,145,93,1,205,124,245,129,56,140,172,95,13,
|
||||
78,0,118,82,98,194,84,136,93,217,102,97,90,197,66,68,
|
||||
105,148,96,126,32,220,108,22,100,131,0,0,128,0,112,38,
|
||||
137,166,87,69,92,206,116,43,92,3,97,107,92,39,96,73,
|
||||
101,193,64,246,99,194,105,173,32,26,102,123,108,69,0,0,
|
||||
128,0,119,103,134,217,80,99,107,214,113,151,85,234,110,117,
|
||||
90,18,90,193,112,228,63,85,94,121,115,18,31,23,97,180,
|
||||
116,108,0,0,128,0,125,112,132,131,74,171,122,184,111,150,
|
||||
80,207,123,118,88,87,86,26,124,13,62,35,89,237,124,145,
|
||||
30,107,94,103,125,47,0,0,128,0,127,202,130,209,70,47,
|
||||
137,129,110,40,76,204,136,111,87,33,82,108,135,54,61,36,
|
||||
86,56,134,85,29,248,92,10,133,252,0,0,128,0,128,0,
|
||||
129,180,66,231,151,227,109,43,73,215,149,17,86,72,79,164,
|
||||
146,42,60,121,83,93,144,56,29,122,90,173,141,217,0,0,
|
||||
128,0,128,0,122,59,107,13,78,9,101,239,109,128,84,51,
|
||||
79,94,111,248,90,17,53,66,114,34,95,58,20,89,117,114,
|
||||
98,63,0,0,128,0,118,48,119,113,99,183,91,125,99,224,
|
||||
103,9,96,10,77,191,105,251,100,71,52,13,108,44,103,232,
|
||||
19,212,112,104,105,245,0,0,128,0,124,88,117,9,93,44,
|
||||
105,29,97,175,97,41,107,247,76,39,100,134,110,150,50,241,
|
||||
102,174,112,192,19,113,108,243,114,23,0,0,128,0,128,0,
|
||||
114,243,87,180,118,223,95,234,92,47,120,23,74,129,95,218,
|
||||
121,16,49,195,97,217,121,223,18,225,106,136,122,228,0,0,
|
||||
128,0,128,0,113,120,83,101,132,147,94,155,88,59,132,58,
|
||||
73,87,92,22,131,141,48,207,93,197,131,35,18,148,104,170,
|
||||
130,227,0,0,128,0,128,0,112,124,80,47,145,214,93,175,
|
||||
85,72,144,47,72,123,89,48,142,34,48,28,90,139,141,35,
|
||||
18,32,103,124,136,248,0,0,128,0,128,0,103,70,120,84,
|
||||
77,117,84,232,121,161,83,63,64,11,123,28,88,172,38,210,
|
||||
124,209,92,243,8,233,127,70,96,200,0,0,128,0,123,34,
|
||||
100,213,113,135,89,167,83,25,115,126,94,24,62,167,117,48,
|
||||
98,36,37,231,118,126,101,44,8,193,123,161,104,123,0,0,
|
||||
128,0,127,24,98,194,107,80,102,30,81,34,109,203,105,23,
|
||||
61,29,111,188,107,190,36,205,112,158,109,148,8,119,120,180,
|
||||
112,173,0,0,128,0,128,0,96,242,102,12,114,156,79,130,
|
||||
104,236,116,47,59,191,107,0,117,116,36,18,107,82,118,75,
|
||||
8,91,118,101,120,166,0,0,128,0,128,0,95,146,97,206,
|
||||
130,67,78,97,101,12,129,141,58,188,103,46,129,182,35,42,
|
||||
103,31,127,144,8,40,116,175,127,220,0,0,128,0,128,0,
|
||||
94,161,94,147,139,177,77,129,98,16,138,232,57,241,100,48,
|
||||
137,174,34,137,99,241,137,147,7,229,115,133,132,115,0,0,
|
||||
128,0,128,0,84,37,135,119,75,195,67,155,135,178,81,48,
|
||||
48,13,136,148,86,4,22,132,139,57,88,202,1,153,133,28,
|
||||
97,193,0,0,128,0,126,220,82,13,129,47,86,229,65,224,
|
||||
129,244,91,44,46,166,130,201,94,217,21,210,132,77,96,184,
|
||||
1,163,129,218,105,124,0,0,128,0,128,0,80,85,123,60,
|
||||
98,71,64,40,124,97,101,75,45,71,125,64,103,204,20,248,
|
||||
126,25,104,210,1,154,127,79,110,152,0,0,128,0,128,0,
|
||||
78,197,118,17,114,119,62,180,119,146,116,238,44,4,120,106,
|
||||
118,37,20,83,121,5,113,106,1,147,125,213,117,185,0,0,
|
||||
128,0,128,0,77,131,113,206,121,100,61,140,115,179,122,30,
|
||||
43,13,116,126,122,121,19,183,117,62,122,187,1,164,125,57,
|
||||
126,172,0,0,128,0,128,0,76,158,110,125,133,67,60,216,
|
||||
112,196,133,20,42,153,113,118,132,123,19,130,114,86,132,73,
|
||||
1,142,125,96,129,13,0,0,128,0,128,0,64,153,153,69,
|
||||
72,171,49,169,152,158,77,168,30,160,153,228,81,115,6,90,
|
||||
154,60,83,247,0,0,130,209,102,37,0,0,128,0,128,0,
|
||||
62,163,147,140,82,227,47,151,147,139,86,215,28,182,148,160,
|
||||
89,168,5,183,147,71,91,203,0,0,128,103,109,199,0,0,
|
||||
128,0,128,0,61,68,141,206,93,80,46,3,142,29,96,44,
|
||||
27,97,143,2,98,7,5,78,141,29,99,223,0,0,128,0,
|
||||
117,60,0,0,128,0,128,0,59,244,136,146,104,3,44,191,
|
||||
137,80,105,212,26,96,137,238,106,205,5,45,136,30,108,152,
|
||||
0,0,128,0,123,80,0,0,128,0,128,0,58,216,132,48,
|
||||
114,233,43,191,133,110,115,203,25,174,133,218,116,14,4,250,
|
||||
132,101,118,30,0,0,128,0,127,34,0,0,128,0,128,0,
|
||||
58,13,128,170,126,39,42,253,130,99,126,61,25,57,130,182,
|
||||
126,10,4,241,129,178,126,213,0,0,128,0,128,0,0,0,
|
||||
128,0,128,0,0,0,255,255,0,0,255,255,0,0,255,255
|
||||
};
|
||||
@@ -27,7 +27,7 @@ bool // O - `true` on sucess, `false` on EOF
|
||||
_pdfioFileConsume(pdfio_file_t *pdf, // I - PDF file
|
||||
size_t bytes) // I - Bytes to consume
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioFileConsume(pdf=%p, bytes=%u)\n", pdf, (unsigned)bytes);
|
||||
PDFIO_DEBUG("_pdfioFileConsume(pdf=%p, bytes=%u)\n", (void *)pdf, (unsigned)bytes);
|
||||
|
||||
if ((size_t)(pdf->bufend - pdf->bufptr) > bytes)
|
||||
pdf->bufptr += bytes;
|
||||
@@ -47,7 +47,7 @@ _pdfioFileConsume(pdfio_file_t *pdf, // I - PDF file
|
||||
// `false` to halt.
|
||||
//
|
||||
|
||||
bool // O - `false` to stop
|
||||
bool // O - `false` to stop, `true` to continue
|
||||
_pdfioFileDefaultError(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
const char *message, // I - Error message
|
||||
@@ -57,7 +57,7 @@ _pdfioFileDefaultError(
|
||||
|
||||
fprintf(stderr, "%s: %s\n", pdf->filename, message);
|
||||
|
||||
return (false);
|
||||
return (!strncmp(message, "WARNING:", 8));
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ _pdfioFileError(pdfio_file_t *pdf, // I - PDF file
|
||||
bool // O - `true` on success, `false` on failure
|
||||
_pdfioFileFlush(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioFileFlush(pdf=%p)\n", pdf);
|
||||
PDFIO_DEBUG("_pdfioFileFlush(pdf=%p)\n", (void *)pdf);
|
||||
|
||||
if (pdf->bufptr > pdf->buffer)
|
||||
{
|
||||
@@ -134,19 +134,20 @@ _pdfioFileGetChar(pdfio_file_t *pdf) // I - PDF file
|
||||
bool // O - `true` on success, `false` on error
|
||||
_pdfioFileGets(pdfio_file_t *pdf, // I - PDF file
|
||||
char *buffer, // I - Line buffer
|
||||
size_t bufsize) // I - Size of line buffer
|
||||
size_t bufsize, // I - Size of line buffer
|
||||
bool discard) // I - OK to discard excess line chars?
|
||||
{
|
||||
bool eol = false; // End of line?
|
||||
char *bufptr = buffer, // Pointer into buffer
|
||||
*bufend = buffer + bufsize - 1; // Pointer to end of buffer
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioFileGets(pdf=%p, buffer=%p, bufsize=%lu) bufpos=%ld, buffer=%p, bufptr=%p, bufend=%p, offset=%lu\n", pdf, buffer, (unsigned long)bufsize, (long)pdf->bufpos, pdf->buffer, pdf->bufptr, pdf->bufend, (unsigned long)(pdf->bufpos + (pdf->bufptr - pdf->buffer)));
|
||||
PDFIO_DEBUG("_pdfioFileGets(pdf=%p, buffer=%p, bufsize=%lu, discard=%s) bufpos=%ld, buffer=%p, bufptr=%p, bufend=%p, offset=%lu\n", (void *)pdf, (void *)buffer, (unsigned long)bufsize, discard ? "true" : "false", (long)pdf->bufpos, (void *)pdf->buffer, (void *)pdf->bufptr, (void *)pdf->bufend, (unsigned long)(pdf->bufpos + (pdf->bufptr - pdf->buffer)));
|
||||
|
||||
while (!eol)
|
||||
{
|
||||
// If there are characters ready in the buffer, use them...
|
||||
while (!eol && pdf->bufptr < pdf->bufend && bufptr < bufend)
|
||||
while (!eol && pdf->bufptr < pdf->bufend)
|
||||
{
|
||||
char ch = *(pdf->bufptr++); // Next character in buffer
|
||||
|
||||
@@ -168,8 +169,10 @@ _pdfioFileGets(pdfio_file_t *pdf, // I - PDF file
|
||||
pdf->bufptr ++;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (bufptr < bufend)
|
||||
*bufptr++ = ch;
|
||||
else if (!discard)
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill the read buffer as needed...
|
||||
@@ -356,7 +359,7 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
||||
off_t offset, // I - Offset
|
||||
int whence) // I - Offset base
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioFileSeek(pdf=%p, offset=%ld, whence=%d) pdf->bufpos=%lu\n", pdf, (long)offset, whence, (unsigned long)(pdf ? pdf->bufpos : 0));
|
||||
PDFIO_DEBUG("_pdfioFileSeek(pdf=%p, offset=%ld, whence=%d) pdf->bufpos=%lu\n", (void *)pdf, (long)offset, whence, (unsigned long)(pdf ? pdf->bufpos : 0));
|
||||
|
||||
// Adjust offset for relative seeks...
|
||||
if (whence == SEEK_CUR)
|
||||
@@ -373,7 +376,7 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
||||
// Yes, seek within existing buffer...
|
||||
pdf->bufptr = pdf->buffer + (offset - pdf->bufpos);
|
||||
PDFIO_DEBUG("_pdfioFileSeek: Seek within buffer, bufpos=%ld.\n", (long)pdf->bufpos);
|
||||
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p(<%02X%02X...>), bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufptr[0] & 255, pdf->bufptr[1] & 255, pdf->bufend);
|
||||
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p(<%02X%02X...>), bufend=%p\n", (void *)pdf->buffer, (void *)pdf->bufptr, pdf->bufptr[0] & 255, pdf->bufptr[1] & 255, (void *)pdf->bufend);
|
||||
return (offset);
|
||||
}
|
||||
|
||||
@@ -408,7 +411,7 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioFileSeek: Reset bufpos=%ld, offset=%lu.\n", (long)pdf->bufpos, (unsigned long)offset);
|
||||
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p, bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufend);
|
||||
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p, bufend=%p\n", (void *)pdf->buffer, (void *)pdf->bufptr, (void *)pdf->bufend);
|
||||
|
||||
pdf->bufpos = offset;
|
||||
|
||||
@@ -424,7 +427,7 @@ off_t // O - Offset from beginning of file
|
||||
_pdfioFileTell(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
if (pdf->bufptr)
|
||||
return (pdf->bufpos + (pdf->bufptr - pdf->buffer));
|
||||
return (pdf->bufpos + (off_t)(pdf->bufptr - pdf->buffer));
|
||||
else
|
||||
return (pdf->bufpos);
|
||||
}
|
||||
@@ -452,7 +455,7 @@ _pdfioFileWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
if (!write_buffer(pdf, buffer, bytes))
|
||||
return (false);
|
||||
|
||||
pdf->bufpos += bytes;
|
||||
pdf->bufpos += (off_t)bytes;
|
||||
|
||||
return (true);
|
||||
}
|
||||
@@ -478,7 +481,7 @@ fill_buffer(pdfio_file_t *pdf) // I - PDF file
|
||||
|
||||
// Advance current position in file as needed...
|
||||
if (pdf->bufend)
|
||||
pdf->bufpos += pdf->bufend - pdf->buffer;
|
||||
pdf->bufpos += (off_t)(pdf->bufend - pdf->buffer);
|
||||
|
||||
// Try reading from the file...
|
||||
if ((bytes = read_buffer(pdf, pdf->buffer, sizeof(pdf->buffer))) <= 0)
|
||||
|
||||
2062
pdfio-content.c
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// Public content header file for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@@ -23,7 +23,8 @@ typedef enum pdfio_cs_e // Standard color spaces
|
||||
{
|
||||
PDFIO_CS_ADOBE, // AdobeRGB 1998
|
||||
PDFIO_CS_P3_D65, // Display P3
|
||||
PDFIO_CS_SRGB // sRGB
|
||||
PDFIO_CS_SRGB, // sRGB
|
||||
PDFIO_CS_CGATS001 // CGATS001 (CMYK)
|
||||
} pdfio_cs_t;
|
||||
|
||||
typedef enum pdfio_linecap_e // Line capping modes
|
||||
@@ -68,8 +69,10 @@ extern pdfio_array_t *pdfioArrayCreateColorFromPrimaries(pdfio_file_t *pdf, size
|
||||
extern pdfio_array_t *pdfioArrayCreateColorFromStandard(pdfio_file_t *pdf, size_t num_colors, pdfio_cs_t cs);
|
||||
|
||||
// PDF content drawing functions...
|
||||
extern bool pdfioContentBeginMarked(pdfio_stream_t *st, const char *tag, pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentClip(pdfio_stream_t *st, bool even_odd) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentDrawImage(pdfio_stream_t *st, const char *name, double x, double y, double w, double h) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentEndMarked(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentFill(pdfio_stream_t *st, bool even_odd) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentFillAndStroke(pdfio_stream_t *st, bool even_odd) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentMatrixConcat(pdfio_stream_t *st, pdfio_matrix_t m) _PDFIO_PUBLIC;
|
||||
@@ -120,14 +123,16 @@ extern bool pdfioContentTextMoveLine(pdfio_stream_t *st, double tx, double ty)
|
||||
extern bool pdfioContentTextMoveTo(pdfio_stream_t *st, double tx, double ty) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextNewLine(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextNewLineShow(pdfio_stream_t *st, double ws, double cs, bool unicode, const char *s) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextNewLineShowf(pdfio_stream_t *st, double ws, double cs, bool unicode, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(5,6);
|
||||
extern bool pdfioContentTextNewLineShowf(pdfio_stream_t *st, double ws, double cs, bool unicode, const char *format, ...) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextNextLine(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextShow(pdfio_stream_t *st, bool unicode, const char *s) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextShowf(pdfio_stream_t *st, bool unicode, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(3,4);
|
||||
extern bool pdfioContentTextShowf(pdfio_stream_t *st, bool unicode, const char *format, ...) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextShowJustified(pdfio_stream_t *st, bool unicode, size_t num_fragments, const double *offsets, const char * const *fragments) _PDFIO_PUBLIC;
|
||||
|
||||
// Resource helpers...
|
||||
extern void pdfioFileAddOutputIntent(pdfio_file_t *pdf, const char *subtype, const char *condition, const char *cond_id, const char *reg_name, const char *info, pdfio_obj_t *profile) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromBase(pdfio_file_t *pdf, const char *name) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromData(pdfio_file_t *pdf, const void *data, size_t datasize, bool unicode) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromFile(pdfio_file_t *pdf, const char *filename, bool unicode) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateICCObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t datalen, size_t num_colors) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateICCObjFromFile(pdfio_file_t *pdf, const char *filename, size_t num_colors) _PDFIO_PUBLIC;
|
||||
|
||||
382
pdfio-crypto.c
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// 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
|
||||
// information.
|
||||
@@ -96,12 +96,14 @@ static uint8_t pdf_passpad[32] = // Padding for passwords
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
static void decrypt_user_key(pdfio_encryption_t encryption, const uint8_t *file_key, uint8_t user_key[32]);
|
||||
static void encrypt_user_key(pdfio_encryption_t encryption, const uint8_t *file_key, uint8_t user_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, 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 decrypt_ou_key(pdfio_encryption_t encryption, const uint8_t *file_key, size_t file_keylen, uint8_t ou_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, 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, 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 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 :
|
||||
// Create the 128-bit encryption keys...
|
||||
pad_password(user_password, user_pad);
|
||||
pdf->file_keylen = 16;
|
||||
|
||||
if (!owner_password && user_password && *user_password)
|
||||
{
|
||||
@@ -152,18 +155,17 @@ _pdfioCryptoLock(
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// Generate the encryption key
|
||||
file_id = pdfioArrayGetBinary(pdf->id_array, 0, &file_idlen);
|
||||
|
||||
make_file_key(encryption, permissions, file_id, file_idlen, user_pad, pdf->owner_key, pdf->file_key);
|
||||
pdf->file_keylen = 16;
|
||||
make_file_key(encryption, pdf->file_keylen, permissions, file_id, file_idlen, user_pad, pdf->owner_key, pdf->encrypt_metadata, pdf->file_key);
|
||||
|
||||
// Generate the 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;
|
||||
|
||||
// Save everything in the dictionary...
|
||||
@@ -214,8 +216,9 @@ _pdfioCryptoLock(
|
||||
|
||||
pdfioObjClose(pdf->encrypt_obj);
|
||||
|
||||
pdf->encryption = encryption;
|
||||
pdf->permissions = permissions;
|
||||
pdf->encrypt_dict = dict;
|
||||
pdf->encryption = encryption;
|
||||
pdf->permissions = permissions;
|
||||
|
||||
return (true);
|
||||
}
|
||||
@@ -409,16 +412,9 @@ _pdfioCryptoMakeReader(
|
||||
uint8_t data[21]; // Key data
|
||||
_pdfio_md5_t md5; // MD5 state
|
||||
uint8_t digest[16]; // MD5 digest value
|
||||
#if PDFIO_OBJ_CRYPT
|
||||
pdfio_array_t *id_array; // Object ID array
|
||||
unsigned char *id_value; // Object ID value
|
||||
size_t id_len; // Length of object ID
|
||||
uint8_t temp_key[16]; // File key for object
|
||||
#endif // PDFIO_OBJ_CRYPT
|
||||
uint8_t *file_key; // Computed file key to use
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeReader(pdf=%p, obj=%p(%d), ctx=%p, iv=%p, ivlen=%p(%d))\n", pdf, obj, (int)obj->number, ctx, iv, ivlen, (int)*ivlen);
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeReader(pdf=%p, obj=%p(%d), ctx=%p, iv=%p, ivlen=%p(%d))\n", (void *)pdf, (void *)obj, (int)obj->number, (void *)ctx, (void *)iv, (void *)ivlen, (int)*ivlen);
|
||||
|
||||
// Range check input...
|
||||
if (!pdf)
|
||||
@@ -427,60 +423,6 @@ _pdfioCryptoMakeReader(
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#if PDFIO_OBJ_CRYPT
|
||||
if ((id_array = pdfioDictGetArray(pdfioObjGetDict(obj), "ID")) != NULL)
|
||||
{
|
||||
// Object has its own ID that will get used for encryption...
|
||||
_pdfio_md5_t md5; // MD5 context
|
||||
uint8_t file_digest[16]; // MD5 digest of file ID and pad
|
||||
uint8_t user_pad[32], // Padded user password
|
||||
own_user_key[32], // Calculated user key
|
||||
pdf_user_key[32]; // Decrypted user key
|
||||
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeReader: Per-object file ID.\n");
|
||||
|
||||
if ((id_value = pdfioArrayGetBinary(id_array, 0, &id_len)) == NULL)
|
||||
{
|
||||
*ivlen = 0;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
_pdfioCryptoMD5Init(&md5);
|
||||
_pdfioCryptoMD5Append(&md5, pdf_passpad, 32);
|
||||
_pdfioCryptoMD5Append(&md5, id_value, id_len);
|
||||
_pdfioCryptoMD5Finish(&md5, file_digest);
|
||||
|
||||
make_owner_key(pdf->encryption, pdf->password, pdf->owner_key, user_pad);
|
||||
make_file_key(pdf->encryption, pdf->permissions, id_value, id_len, user_pad, pdf->owner_key, temp_key);
|
||||
make_user_key(id_value, id_len, own_user_key);
|
||||
|
||||
if (memcmp(own_user_key, pdf->user_key, sizeof(own_user_key)))
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeReader: Not user password, trying owner password.\n");
|
||||
|
||||
make_file_key(pdf->encryption, pdf->permissions, id_value, id_len, pdf->password, pdf->owner_key, temp_key);
|
||||
make_user_key(id_value, id_len, own_user_key);
|
||||
|
||||
memcpy(pdf_user_key, pdf->user_key, sizeof(pdf_user_key));
|
||||
decrypt_user_key(pdf->encryption, temp_key, pdf_user_key);
|
||||
|
||||
if (memcmp(pdf->password, pdf_user_key, 32) && memcmp(own_user_key, pdf_user_key, 16))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to unlock file.");
|
||||
*ivlen = 0;
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
file_key = temp_key;
|
||||
}
|
||||
else
|
||||
#endif // PDFIO_OBJ_CRYPT
|
||||
{
|
||||
// Use the default file key...
|
||||
file_key = pdf->file_key;
|
||||
}
|
||||
|
||||
switch (pdf->encryption)
|
||||
{
|
||||
default :
|
||||
@@ -490,20 +432,20 @@ _pdfioCryptoMakeReader(
|
||||
|
||||
case PDFIO_ENCRYPTION_RC4_40 :
|
||||
// Copy the key data for the MD5 hash.
|
||||
memcpy(data, file_key, 16);
|
||||
data[16] = (uint8_t)obj->number;
|
||||
data[17] = (uint8_t)(obj->number >> 8);
|
||||
data[18] = (uint8_t)(obj->number >> 16);
|
||||
data[19] = (uint8_t)obj->generation;
|
||||
data[20] = (uint8_t)(obj->generation >> 8);
|
||||
memcpy(data, pdf->file_key, 5);
|
||||
data[5] = (uint8_t)obj->number;
|
||||
data[6] = (uint8_t)(obj->number >> 8);
|
||||
data[7] = (uint8_t)(obj->number >> 16);
|
||||
data[8] = (uint8_t)obj->generation;
|
||||
data[9] = (uint8_t)(obj->generation >> 8);
|
||||
|
||||
// Hash it...
|
||||
_pdfioCryptoMD5Init(&md5);
|
||||
_pdfioCryptoMD5Append(&md5, data, sizeof(data));
|
||||
_pdfioCryptoMD5Append(&md5, data, 10);
|
||||
_pdfioCryptoMD5Finish(&md5, digest);
|
||||
|
||||
// Initialize the RC4 context using 40 bits of the digest...
|
||||
_pdfioCryptoRC4Init(&ctx->rc4, digest, 5);
|
||||
// Initialize the RC4 context using 80 bits of the digest...
|
||||
_pdfioCryptoRC4Init(&ctx->rc4, digest, 10);
|
||||
*ivlen = 0;
|
||||
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
|
||||
|
||||
@@ -515,9 +457,13 @@ _pdfioCryptoMakeReader(
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
__attribute__((fallthrough));
|
||||
#endif // __APPLE__
|
||||
|
||||
case PDFIO_ENCRYPTION_RC4_128 :
|
||||
// Copy the key data for the MD5 hash.
|
||||
memcpy(data, file_key, 16);
|
||||
memcpy(data, pdf->file_key, 16);
|
||||
data[16] = (uint8_t)obj->number;
|
||||
data[17] = (uint8_t)(obj->number >> 8);
|
||||
data[18] = (uint8_t)(obj->number >> 16);
|
||||
@@ -565,7 +511,7 @@ _pdfioCryptoMakeWriter(
|
||||
uint8_t digest[16]; /* MD5 digest value */
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeWriter(pdf=%p, obj=%p(%d), ctx=%p, iv=%p, ivlen=%p(%d))\n", pdf, obj, (int)obj->number, ctx, iv, ivlen, (int)*ivlen);
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeWriter(pdf=%p, obj=%p(%d), ctx=%p, iv=%p, ivlen=%p(%d))\n", (void *)pdf, (void *)obj, (int)obj->number, (void *)ctx, (void *)iv, (void *)ivlen, (int)*ivlen);
|
||||
|
||||
// Range check input...
|
||||
if (!pdf)
|
||||
@@ -627,7 +573,6 @@ _pdfioCryptoUnlock(
|
||||
{
|
||||
int tries; // Number of tries
|
||||
const char *password = NULL; // Password to try
|
||||
pdfio_dict_t *encrypt_dict; // Encrypt objection dictionary
|
||||
int version, // Version value
|
||||
revision, // Revision value
|
||||
length; // Key length value
|
||||
@@ -643,22 +588,23 @@ _pdfioCryptoUnlock(
|
||||
file_idlen; // Length of file ID
|
||||
_pdfio_md5_t md5; // MD5 context
|
||||
uint8_t file_digest[16]; // MD5 digest of file ID and pad
|
||||
double p; // Permissions value as a double
|
||||
_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...
|
||||
if ((encrypt_dict = pdfioObjGetDict(pdf->encrypt_obj)) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to get encryption dictionary.");
|
||||
return (false);
|
||||
}
|
||||
handler = pdfioDictGetName(pdf->encrypt_dict, "Filter");
|
||||
version = (int)pdfioDictGetNumber(pdf->encrypt_dict, "V");
|
||||
revision = (int)pdfioDictGetNumber(pdf->encrypt_dict, "R");
|
||||
length = (int)pdfioDictGetNumber(pdf->encrypt_dict, "Length");
|
||||
|
||||
handler = pdfioDictGetName(encrypt_dict, "Filter");
|
||||
version = (int)pdfioDictGetNumber(encrypt_dict, "V");
|
||||
revision = (int)pdfioDictGetNumber(encrypt_dict, "R");
|
||||
length = (int)pdfioDictGetNumber(encrypt_dict, "Length");
|
||||
if ((value = _pdfioDictGetValue(pdf->encrypt_dict, "EncryptMetadata")) != NULL && value->type == PDFIO_VALTYPE_BOOLEAN)
|
||||
pdf->encrypt_metadata = value->value.boolean;
|
||||
else
|
||||
pdf->encrypt_metadata = true;
|
||||
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: handler=%p(%s), version=%d, revision=%d, length=%d\n", (void *)handler, handler ? handler : "(null)", version, revision, length);
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: handler=%p(%s), version=%d, revision=%d, length=%d, encrypt_metadata=%s\n", (void *)handler, handler ? handler : "(null)", version, revision, length, pdf->encrypt_metadata ? "true" : "false");
|
||||
|
||||
if (!handler || strcmp(handler, "Standard"))
|
||||
{
|
||||
@@ -672,9 +618,9 @@ _pdfioCryptoUnlock(
|
||||
pdfio_dict_t *filter; // Crypt Filter
|
||||
const char *cfm; // Crypt filter method
|
||||
|
||||
stream_filter = pdfioDictGetName(encrypt_dict, "StmF");
|
||||
string_filter = pdfioDictGetName(encrypt_dict, "StrF");
|
||||
cf_dict = pdfioDictGetDict(encrypt_dict, "CF");
|
||||
stream_filter = pdfioDictGetName(pdf->encrypt_dict, "StmF");
|
||||
string_filter = pdfioDictGetName(pdf->encrypt_dict, "StrF");
|
||||
cf_dict = pdfioDictGetDict(pdf->encrypt_dict, "CF");
|
||||
|
||||
if (!cf_dict)
|
||||
{
|
||||
@@ -747,15 +693,25 @@ _pdfioCryptoUnlock(
|
||||
_pdfioFileError(pdf, "Unsupported encryption V%d R%d.", version, revision);
|
||||
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...
|
||||
pdf->file_keylen = (size_t)(length / 8);
|
||||
pdf->permissions = (pdfio_permission_t)pdfioDictGetNumber(encrypt_dict, "P");
|
||||
|
||||
p = pdfioDictGetNumber(pdf->encrypt_dict, "P");
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: P=%.0f\n", p);
|
||||
if (p < 0x7fffffff) // Handle integers > 2^31-1
|
||||
pdf->permissions = (pdfio_permission_t)p;
|
||||
else
|
||||
pdf->permissions = (pdfio_permission_t)(p - 4294967296.0);
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: permissions=%d\n", pdf->permissions);
|
||||
|
||||
owner_key = pdfioDictGetBinary(encrypt_dict, "O", &owner_keylen);
|
||||
user_key = pdfioDictGetBinary(encrypt_dict, "U", &user_keylen);
|
||||
owner_key = pdfioDictGetBinary(pdf->encrypt_dict, "O", &owner_keylen);
|
||||
user_key = pdfioDictGetBinary(pdf->encrypt_dict, "U", &user_keylen);
|
||||
|
||||
if (!owner_key)
|
||||
{
|
||||
@@ -784,7 +740,7 @@ _pdfioCryptoUnlock(
|
||||
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);
|
||||
pdf->user_keylen = user_keylen;
|
||||
@@ -795,6 +751,9 @@ _pdfioCryptoUnlock(
|
||||
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...
|
||||
_pdfioCryptoMD5Init(&md5);
|
||||
_pdfioCryptoMD5Append(&md5, pdf_passpad, 32);
|
||||
@@ -806,56 +765,34 @@ _pdfioCryptoUnlock(
|
||||
{
|
||||
if (pdf->encryption <= PDFIO_ENCRYPTION_AES_128)
|
||||
{
|
||||
// RC4 and AES-128 encryption...
|
||||
uint8_t pad[32], // Padded password
|
||||
file_key[16], // File key
|
||||
user_pad[32], // Padded user password
|
||||
own_user_key[32], // Calculated user key
|
||||
pdf_user_key[32]; // Decrypted user key
|
||||
padkey[16], // Password key
|
||||
file_key[16]; // File key
|
||||
|
||||
// Pad the supplied password, if any...
|
||||
pad_password(password, pad);
|
||||
|
||||
// Generate keys to see if things match...
|
||||
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]);
|
||||
// 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]);
|
||||
|
||||
make_owner_key(pdf->encryption, pad, pdf->owner_key, user_pad);
|
||||
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, 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)))
|
||||
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))
|
||||
{
|
||||
// Matches!
|
||||
memcpy(pdf->file_key, file_key, sizeof(pdf->file_key));
|
||||
memcpy(pdf->file_key, file_key, pdf->file_keylen);
|
||||
memcpy(pdf->password, pad, sizeof(pdf->password));
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
// Not the owner password, try the user password...
|
||||
make_file_key(pdf->encryption, pdf->permissions, file_id, file_idlen, pad, pdf->owner_key, file_key);
|
||||
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]);
|
||||
// Test the owner password...
|
||||
make_password_key(pdf->encryption, pdf->file_keylen, pad, padkey);
|
||||
|
||||
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));
|
||||
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))
|
||||
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))
|
||||
{
|
||||
// Matches!
|
||||
memcpy(pdf->file_key, file_key, sizeof(pdf->file_key));
|
||||
memcpy(pdf->file_key, file_key, pdf->file_keylen);
|
||||
memcpy(pdf->password, pad, sizeof(pdf->password));
|
||||
|
||||
return (true);
|
||||
@@ -883,14 +820,15 @@ _pdfioCryptoUnlock(
|
||||
|
||||
|
||||
//
|
||||
// 'decrypt_user_key()' - Decrypt the user key.
|
||||
// 'decrypt_ou_key()' - Decrypt the user key.
|
||||
//
|
||||
|
||||
static void
|
||||
decrypt_user_key(
|
||||
decrypt_ou_key(
|
||||
pdfio_encryption_t encryption, // I - Type of encryption
|
||||
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
|
||||
_pdfio_rc4_t rc4; // RC4 encryption context
|
||||
@@ -900,38 +838,38 @@ decrypt_user_key(
|
||||
{
|
||||
// Encrypt the result once...
|
||||
_pdfioCryptoRC4Init(&rc4, file_key, 5);
|
||||
_pdfioCryptoRC4Crypt(&rc4, user_key, user_key, 32);
|
||||
_pdfioCryptoRC4Crypt(&rc4, ou_key, ou_key, 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Encrypt the result 20 times...
|
||||
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...
|
||||
for (j = 0; j < 16; j ++)
|
||||
i --;
|
||||
|
||||
for (j = 0; j < file_keylen; j ++)
|
||||
key[j] = (uint8_t)(file_key[j] ^ i);
|
||||
|
||||
_pdfioCryptoRC4Init(&rc4, key, 16);
|
||||
_pdfioCryptoRC4Crypt(&rc4, user_key, user_key, 32);
|
||||
_pdfioCryptoRC4Init(&rc4, key, file_keylen);
|
||||
_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
|
||||
encrypt_user_key(
|
||||
encrypt_ou_key(
|
||||
pdfio_encryption_t encryption, // I - Type of encryption
|
||||
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
|
||||
_pdfio_rc4_t rc4; // RC4 encryption context
|
||||
@@ -941,7 +879,7 @@ encrypt_user_key(
|
||||
{
|
||||
// Encrypt the result once...
|
||||
_pdfioCryptoRC4Init(&rc4, file_key, 5);
|
||||
_pdfioCryptoRC4Crypt(&rc4, user_key, user_key, 32);
|
||||
_pdfioCryptoRC4Crypt(&rc4, ou_key, ou_key, 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -951,11 +889,11 @@ encrypt_user_key(
|
||||
for (i = 0; i < 20; i ++)
|
||||
{
|
||||
// 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);
|
||||
|
||||
_pdfioCryptoRC4Init(&rc4, key, 16);
|
||||
_pdfioCryptoRC4Crypt(&rc4, user_key, user_key, 32);
|
||||
_pdfioCryptoRC4Init(&rc4, key, file_keylen);
|
||||
_pdfioCryptoRC4Crypt(&rc4, ou_key, ou_key, 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -968,11 +906,14 @@ encrypt_user_key(
|
||||
static void
|
||||
make_file_key(
|
||||
pdfio_encryption_t encryption, // I - Type of encryption
|
||||
size_t file_keylen, // I - Encryption key length
|
||||
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 *owner_key, // I - Owner key
|
||||
bool encrypt_metadata,
|
||||
// I - Encrypt metadata?
|
||||
uint8_t file_key[16]) // O - Encryption key
|
||||
{
|
||||
size_t i; // Looping var
|
||||
@@ -986,25 +927,39 @@ make_file_key(
|
||||
perm_bytes[2] = (uint8_t)(permissions >> 16);
|
||||
perm_bytes[3] = (uint8_t)(permissions >> 24);
|
||||
|
||||
PDFIO_DEBUG("make_file_key: user_pad[32]=<%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]);
|
||||
PDFIO_DEBUG("make_file_key: owner_key[32]=<%02X%02X%02X%02X...%02X%02X%02X%02X>\n", owner_key[0], owner_key[1], owner_key[2], owner_key[3], owner_key[28], owner_key[29], owner_key[30], owner_key[31]);
|
||||
PDFIO_DEBUG("make_file_key: permissions(%d)=<%02X%02X%02X%02X>\n", permissions, perm_bytes[0], perm_bytes[1], perm_bytes[2], perm_bytes[3]);
|
||||
|
||||
_pdfioCryptoMD5Init(&md5);
|
||||
_pdfioCryptoMD5Append(&md5, user_pad, 32);
|
||||
_pdfioCryptoMD5Append(&md5, owner_key, 32);
|
||||
_pdfioCryptoMD5Append(&md5, perm_bytes, 4);
|
||||
_pdfioCryptoMD5Append(&md5, file_id, file_idlen);
|
||||
if (!encrypt_metadata)
|
||||
{
|
||||
uint8_t meta_bytes[4] = { 0xff, 0xff, 0xff, 0xff };
|
||||
// Metadata bytes
|
||||
_pdfioCryptoMD5Append(&md5, meta_bytes, 4);
|
||||
}
|
||||
_pdfioCryptoMD5Finish(&md5, digest);
|
||||
|
||||
PDFIO_DEBUG("make_file_key: first md5=<%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]);
|
||||
|
||||
if (encryption != PDFIO_ENCRYPTION_RC4_40)
|
||||
{
|
||||
// MD5 the result 50 times..
|
||||
for (i = 0; i < 50; i ++)
|
||||
{
|
||||
_pdfioCryptoMD5Init(&md5);
|
||||
_pdfioCryptoMD5Append(&md5, digest, 16);
|
||||
_pdfioCryptoMD5Append(&md5, digest, file_keylen);
|
||||
_pdfioCryptoMD5Finish(&md5, digest);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(file_key, digest, 16);
|
||||
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, file_keylen);
|
||||
}
|
||||
|
||||
|
||||
@@ -1015,55 +970,57 @@ make_file_key(
|
||||
static void
|
||||
make_owner_key(
|
||||
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 *user_pad, // I - Padded user password
|
||||
uint8_t owner_key[32]) // O - Owner key value
|
||||
{
|
||||
size_t i, j; // Looping vars
|
||||
_pdfio_md5_t md5; // MD5 context
|
||||
uint8_t digest[16]; // 128-bit MD5 digest
|
||||
_pdfio_rc4_t rc4; // RC4 encryption context
|
||||
uint8_t key[16]; // Base encryption key
|
||||
|
||||
|
||||
// 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);
|
||||
_pdfioCryptoMD5Append(&md5, owner_pad, 32);
|
||||
_pdfioCryptoMD5Append(&md5, pad, 32);
|
||||
_pdfioCryptoMD5Finish(&md5, digest);
|
||||
|
||||
if (encryption != PDFIO_ENCRYPTION_RC4_40)
|
||||
{
|
||||
// Hash the hash another 50 times...
|
||||
for (i = 0; i < 50; i ++)
|
||||
{
|
||||
_pdfioCryptoMD5Init(&md5);
|
||||
_pdfioCryptoMD5Append(&md5, digest, 16);
|
||||
_pdfioCryptoMD5Append(&md5, digest, file_keylen);
|
||||
_pdfioCryptoMD5Finish(&md5, digest);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy and encrypt the padded user password...
|
||||
memcpy(owner_key, user_pad, 32);
|
||||
|
||||
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 = 0; i < 20; i ++)
|
||||
{
|
||||
// XOR each byte in the digest with the loop counter to make a key...
|
||||
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);
|
||||
}
|
||||
}
|
||||
// Copy the key portion of the hashed password to the key...
|
||||
memcpy(key, digest, file_keylen);
|
||||
}
|
||||
|
||||
|
||||
@@ -1118,3 +1075,52 @@ pad_password(const char *password, // I - Password string or `NULL`
|
||||
if (len < 32)
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
212
pdfio-dict.c
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF dictionary 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
|
||||
// information.
|
||||
@@ -20,6 +20,8 @@ static int compare_pairs(_pdfio_pair_t *a, _pdfio_pair_t *b);
|
||||
//
|
||||
// 'pdfioDictClear()' - Remove a key/value pair from a dictionary.
|
||||
//
|
||||
// @since PDFio v1.4@
|
||||
//
|
||||
|
||||
bool // O - `true` if cleared, `false` otherwise
|
||||
pdfioDictClear(pdfio_dict_t *dict, // I - Dictionary
|
||||
@@ -30,7 +32,7 @@ pdfioDictClear(pdfio_dict_t *dict, // I - Dictionary
|
||||
pkey; // Search key
|
||||
|
||||
|
||||
PDFIO_DEBUG("pdfioDictClear(dict=%p, key=\"%s\")\n", dict, key);
|
||||
PDFIO_DEBUG("pdfioDictClear(dict=%p, key=\"%s\")\n", (void *)dict, key);
|
||||
|
||||
if (!dict || !key)
|
||||
return (false);
|
||||
@@ -75,7 +77,11 @@ pdfioDictCopy(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfio_value_t v; // Current destination value
|
||||
|
||||
|
||||
PDFIO_DEBUG("pdfioDictCopy(pdf=%p, dict=%p(%p))\n", pdf, dict, dict ? 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...
|
||||
if ((ndict = pdfioDictCreate(pdf)) == NULL)
|
||||
@@ -90,6 +96,8 @@ pdfioDictCopy(pdfio_file_t *pdf, // I - PDF file
|
||||
// Copy and add each of the source dictionary's key/value pairs...
|
||||
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)
|
||||
{
|
||||
// Don't use indirect stream lengths for copied objects...
|
||||
@@ -100,15 +108,28 @@ pdfioDictCopy(pdfio_file_t *pdf, // I - PDF file
|
||||
if (lenobj)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
v.value.number = 0.0;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("pdfioDictCopy: Length is %.0f.\n", v.value.number);
|
||||
}
|
||||
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...
|
||||
}
|
||||
|
||||
if (_pdfioStringIsAllocated(dict->pdf, p->key))
|
||||
key = pdfioStringCreate(pdf, p->key);
|
||||
@@ -345,6 +366,8 @@ pdfioDictGetDict(pdfio_dict_t *dict, // I - Dictionary
|
||||
//
|
||||
// 'pdfioDictGetKey()' - Get the key for the specified pair.
|
||||
//
|
||||
// @since PDFio v1.4@
|
||||
//
|
||||
|
||||
const char * // O - Key for specified pair
|
||||
pdfioDictGetKey(pdfio_dict_t *dict, // I - Dictionary
|
||||
@@ -375,6 +398,8 @@ pdfioDictGetName(pdfio_dict_t *dict, // I - Dictionary
|
||||
//
|
||||
// 'pdfioDictGetNumPairs()' - Get the number of key/value pairs in a dictionary.
|
||||
//
|
||||
// @since PDFio v1.4@
|
||||
//
|
||||
|
||||
size_t // O - Number of pairs
|
||||
pdfioDictGetNumPairs(pdfio_dict_t *dict)// I - Dictionary
|
||||
@@ -458,134 +483,25 @@ pdfioDictGetString(pdfio_dict_t *dict, // I - Dictionary
|
||||
_pdfio_value_t *value = _pdfioDictGetValue(dict, key);
|
||||
|
||||
|
||||
PDFIO_DEBUG("pdfioDictGetString(dict=%p, key=\"%s\")\n", (void *)dict, key);
|
||||
PDFIO_DEBUG("pdfioDictGetString: value=%p(type=%d)\n", (void *)value, value ? value->type : 0);
|
||||
|
||||
if (value && value->type == PDFIO_VALTYPE_STRING)
|
||||
{
|
||||
PDFIO_DEBUG("pdfioDictGetString: Returning \"%s\".\n", value->value.string);
|
||||
return (value->value.string);
|
||||
}
|
||||
else if (value && value->type == PDFIO_VALTYPE_BINARY && value->value.binary.datalen < 4096)
|
||||
{
|
||||
// Convert binary string to regular string...
|
||||
char temp[4096], // Temporary string
|
||||
*tempptr; // Pointer into temporary string
|
||||
unsigned char *dataptr; // Pointer into the data string
|
||||
char temp[4096]; // Temporary UTF-8 string
|
||||
|
||||
if (!(value->value.binary.datalen & 1) && !memcmp(value->value.binary.data, "\377\376", 2))
|
||||
if (!(value->value.binary.datalen & 1) && (!memcmp(value->value.binary.data, "\376\377", 2) || !memcmp(value->value.binary.data, "\377\376", 2)))
|
||||
{
|
||||
// Copy UTF-16 BE
|
||||
int ch; // Unicode character
|
||||
size_t remaining; // Remaining bytes
|
||||
// Copy UTF-16...
|
||||
PDFIO_DEBUG("pdfioDictGetString: Converting UTF-16 to UTF-8 string.\n");
|
||||
|
||||
for (dataptr = value->value.binary.data + 2, remaining = value->value.binary.datalen - 2, tempptr = temp; remaining > 1 && tempptr < (temp + sizeof(temp) - 5); dataptr += 2, remaining -= 2)
|
||||
{
|
||||
ch = (dataptr[0] << 8) | dataptr[1];
|
||||
|
||||
if (ch >= 0xd800 && ch <= 0xdbff && remaining > 3)
|
||||
{
|
||||
// Multi-word UTF-16 char...
|
||||
int lch; // Lower bits
|
||||
|
||||
lch = (dataptr[2] << 8) | dataptr[3];
|
||||
|
||||
if (lch < 0xdc00 || lch >= 0xdfff)
|
||||
break;
|
||||
|
||||
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
|
||||
dataptr += 2;
|
||||
remaining -= 2;
|
||||
}
|
||||
else if (ch >= 0xfffe)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*tempptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 4096)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*tempptr++ = (char)(0xc0 | (ch >> 6));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else if (ch < 65536)
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 12));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 18));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
*tempptr = '\0';
|
||||
}
|
||||
else if (!(value->value.binary.datalen & 1) && !memcmp(value->value.binary.data, "\376\377", 2))
|
||||
{
|
||||
// Copy UTF-16 LE
|
||||
int ch; // Unicode character
|
||||
size_t remaining; // Remaining bytes
|
||||
|
||||
for (dataptr = value->value.binary.data + 2, remaining = value->value.binary.datalen - 2, tempptr = temp; remaining > 1 && tempptr < (temp + sizeof(temp) - 5); dataptr += 2, remaining -= 2)
|
||||
{
|
||||
ch = (dataptr[1] << 8) | dataptr[0];
|
||||
|
||||
if (ch >= 0xd800 && ch <= 0xdbff && remaining > 3)
|
||||
{
|
||||
// Multi-word UTF-16 char...
|
||||
int lch; // Lower bits
|
||||
|
||||
lch = (dataptr[3] << 8) | dataptr[2];
|
||||
|
||||
if (lch < 0xdc00 || lch >= 0xdfff)
|
||||
break;
|
||||
|
||||
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
|
||||
dataptr += 2;
|
||||
remaining -= 2;
|
||||
}
|
||||
else if (ch >= 0xfffe)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*tempptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 4096)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*tempptr++ = (char)(0xc0 | (ch >> 6));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else if (ch < 65536)
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 12));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 18));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
*tempptr = '\0';
|
||||
_pdfio_utf16cpy(temp, value->value.binary.data, value->value.binary.datalen, sizeof(temp));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -598,10 +514,13 @@ pdfioDictGetString(pdfio_dict_t *dict, // I - Dictionary
|
||||
value->type = PDFIO_VALTYPE_STRING;
|
||||
value->value.string = pdfioStringCreate(dict->pdf, temp);
|
||||
|
||||
PDFIO_DEBUG("pdfioDictGetString: Returning \"%s\".\n", value->value.string);
|
||||
|
||||
return (value->value.string);
|
||||
}
|
||||
else
|
||||
{
|
||||
PDFIO_DEBUG("pdfioDictGetString: Returning NULL.\n");
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
@@ -634,7 +553,7 @@ _pdfioDictGetValue(pdfio_dict_t *dict, // I - Dictionary
|
||||
*match; // Matching key pair
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioDictGetValue(dict=%p, key=\"%s\")\n", dict, key);
|
||||
PDFIO_DEBUG("_pdfioDictGetValue(dict=%p, key=\"%s\")\n", (void *)dict, key);
|
||||
|
||||
if (!dict || !dict->num_pairs || !key)
|
||||
{
|
||||
@@ -677,6 +596,8 @@ _pdfioDictGetValue(pdfio_dict_t *dict, // I - Dictionary
|
||||
// The iteration continues as long as the callback returns `true` or all keys
|
||||
// have been iterated.
|
||||
//
|
||||
// @since PDFio v1.1@
|
||||
//
|
||||
|
||||
void
|
||||
pdfioDictIterateKeys(
|
||||
@@ -717,7 +638,7 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfio_value_t value; // Dictionary value
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioDictRead(pdf=%p, obj=%p, tb=%p, depth=%lu)\n", pdf, obj, tb, (unsigned long)depth);
|
||||
PDFIO_DEBUG("_pdfioDictRead(pdf=%p, obj=%p, tb=%p, depth=%lu)\n", (void *)pdf, (void *)obj, (void *)tb, (unsigned long)depth);
|
||||
|
||||
// Create a dictionary and start reading...
|
||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||
@@ -737,11 +658,6 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfioFileError(pdf, "Invalid dictionary contents.");
|
||||
break;
|
||||
}
|
||||
else if (_pdfioDictGetValue(dict, key + 1))
|
||||
{
|
||||
_pdfioFileError(pdf, "Duplicate dictionary key '%s'.", key + 1);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
// Then get the next value...
|
||||
PDFIO_DEBUG("_pdfioDictRead: Reading value for '%s'.\n", key + 1);
|
||||
@@ -751,8 +667,16 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfioFileError(pdf, "Missing value for dictionary key '%s'.", key + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_pdfioDictSetValue(dict, pdfioStringCreate(pdf, key + 1), &value))
|
||||
else if (_pdfioDictGetValue(dict, key + 1))
|
||||
{
|
||||
// Issue 118: Discard duplicate key/value pairs...
|
||||
_pdfioValueDelete(&value);
|
||||
if (_pdfioFileError(pdf, "WARNING: Discarding value for duplicate dictionary key '%s'.", key + 1))
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if (!_pdfioDictSetValue(dict, pdfioStringCreate(pdf, key + 1), &value))
|
||||
break;
|
||||
|
||||
PDFIO_DEBUG("_pdfioDictRead: Set %s.\n", key);
|
||||
@@ -1087,7 +1011,7 @@ _pdfioDictSetValue(
|
||||
_pdfio_pair_t *pair; // Current pair
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioDictSetValue(dict=%p, key=\"%s\", value=%p)\n", dict, key, (void *)value);
|
||||
PDFIO_DEBUG("_pdfioDictSetValue(dict=%p, key=\"%s\", value=%p)\n", (void *)dict, key, (void *)value);
|
||||
|
||||
// See if the key is already set...
|
||||
if (dict->num_pairs > 0)
|
||||
@@ -1149,11 +1073,13 @@ _pdfioDictSetValue(
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
_pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary
|
||||
pdfio_obj_t *obj, // I - Object, if any
|
||||
off_t *length) // I - Offset to length value
|
||||
_pdfioDictWrite(
|
||||
_pdfio_printf_t cb, // I - Printf callback function
|
||||
void *cbdata, // I - Printf callback data
|
||||
pdfio_obj_t *obj, // I - Object, if any
|
||||
pdfio_dict_t *dict, // I - Dictionary
|
||||
off_t *length) // I - Offset to length value
|
||||
{
|
||||
pdfio_file_t *pdf = dict->pdf; // PDF file
|
||||
size_t i; // Looping var
|
||||
_pdfio_pair_t *pair; // Current key/value pair
|
||||
|
||||
@@ -1162,28 +1088,30 @@ _pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary
|
||||
*length = 0;
|
||||
|
||||
// Dictionaries are bounded by "<<" and ">>"...
|
||||
if (!_pdfioFilePuts(pdf, "<<"))
|
||||
if (!(cb)(cbdata, "<<"))
|
||||
return (false);
|
||||
|
||||
// Write all of the key/value pairs...
|
||||
for (i = dict->num_pairs, pair = dict->pairs; i > 0; i --, pair ++)
|
||||
{
|
||||
if (!_pdfioFilePrintf(pdf, "/%s", pair->key))
|
||||
if (!(cb)(cbdata, "%N", pair->key))
|
||||
return (false);
|
||||
|
||||
if (length && !strcmp(pair->key, "Length") && pair->value.type == PDFIO_VALTYPE_NUMBER && pair->value.value.number <= 0.0)
|
||||
{
|
||||
// Writing an object dictionary with an undefined length
|
||||
*length = _pdfioFileTell(pdf) + 1;
|
||||
if (!_pdfioFilePuts(pdf, " 9999999999"))
|
||||
*length = _pdfioFileTell(dict->pdf) + 1;
|
||||
if (!(cb)(cbdata, " 9999999999"))
|
||||
return (false);
|
||||
}
|
||||
else if (!_pdfioValueWrite(pdf, obj, &pair->value, NULL))
|
||||
else if (!_pdfioValueWrite(cb, cbdata, obj, &pair->value, NULL))
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
// Close it up...
|
||||
return (_pdfioFilePuts(pdf, ">>"));
|
||||
return ((cb)(cbdata, ">>"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
1270
pdfio-file.c
338
pdfio-lzw.c
Normal file
@@ -0,0 +1,338 @@
|
||||
//
|
||||
// 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
|
||||
bool reversed) // I - Reversed (GIF) LZW bit encoding?
|
||||
{
|
||||
_pdfio_lzw_t *lzw; // LZW state
|
||||
|
||||
|
||||
if ((lzw = (_pdfio_lzw_t *)calloc(1, sizeof(_pdfio_lzw_t))) != NULL)
|
||||
{
|
||||
lzw->def_code_size = (uint8_t)(code_size + 1);
|
||||
lzw->clear_code = (uint16_t)(1 << code_size);
|
||||
lzw->eod_code = lzw->clear_code + 1;
|
||||
lzw->early = (uint8_t)early;
|
||||
lzw->reversed = reversed;
|
||||
|
||||
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++) = (uint8_t)*(--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 = (uint16_t)in_code;
|
||||
*(lzw->next_out++) = (uint8_t)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 = (uint16_t)((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++) = (uint8_t)*(--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 = (uint16_t)((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
|
||||
};
|
||||
static uint8_t rbits[8] = // Right-to-left bit masks
|
||||
{
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
|
||||
};
|
||||
|
||||
|
||||
// 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 = (uint16_t)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...
|
||||
if (lzw->reversed)
|
||||
{
|
||||
// Insane GIF-style right-to-left bit encoding...
|
||||
for (code = 0, in_bit = lzw->in_bit + lzw->cur_code_size - 1, remaining = lzw->cur_code_size; remaining > 0; in_bit --, remaining --)
|
||||
{
|
||||
code = (uint16_t)((code << 1) | ((lzw->in_bytes[in_bit / 8] & rbits[in_bit & 7]) != 0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TIFF/PDF-style left-to-right bit encoding...
|
||||
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 = (uint16_t)((code << 8) | byte);
|
||||
else // Partial byte from buffer
|
||||
code = (uint16_t)((code << bits) | ((byte >> (8 - bits - boff)) & mask[bits]));
|
||||
}
|
||||
}
|
||||
|
||||
// Update the position in the input buffer and return the code...
|
||||
lzw->in_bit += lzw->cur_code_size;
|
||||
|
||||
#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.
|
||||
//
|
||||
// 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
|
||||
// information.
|
||||
@@ -32,8 +32,43 @@ pdfioObjClose(pdfio_obj_t *obj) // I - Object
|
||||
}
|
||||
|
||||
// Write what remains for the object...
|
||||
if (!obj->offset)
|
||||
if (!obj->offset && !obj->objstm_data)
|
||||
{
|
||||
// Are we using object streams and is this object eligible?
|
||||
if (obj->pdf->objstm_dict && !obj->pdf->objstm_obj && obj != obj->pdf->encrypt_obj && obj->pdf->num_objstm < 0x10000 && (obj->value.type == PDFIO_VALTYPE_ARRAY || obj->value.type == PDFIO_VALTYPE_DICT))
|
||||
{
|
||||
// Add this to the object stream...
|
||||
_pdfio_strbuf_t *bptr; // String buffer
|
||||
|
||||
if (!_pdfioStringAllocBuffer(obj->pdf, &bptr))
|
||||
goto regular_obj;
|
||||
|
||||
if (!_pdfioValueWrite((_pdfio_printf_t)_pdfioStringPrintf, bptr, /*obj*/NULL, &(obj->value), /*length*/NULL))
|
||||
{
|
||||
_pdfioStringFreeBuffer(obj->pdf, bptr->buffer);
|
||||
goto regular_obj;
|
||||
}
|
||||
|
||||
_pdfioStringPrintf(bptr, "\n");
|
||||
|
||||
if ((obj->objstm_data = pdfioStringCreate(obj->pdf, bptr->buffer)) == NULL)
|
||||
{
|
||||
_pdfioStringFreeBuffer(obj->pdf, bptr->buffer);
|
||||
goto regular_obj;
|
||||
}
|
||||
|
||||
// If we got this far then we have the value string and can assign an
|
||||
// object number, which is all that is required for now...
|
||||
obj->objstm_datalen = (size_t)(bptr->bufptr - bptr->buffer);
|
||||
obj->objstm_number = obj->pdf->num_objstm;
|
||||
obj->pdf->num_objstm ++;
|
||||
|
||||
_pdfioStringFreeBuffer(obj->pdf, bptr->buffer);
|
||||
return (true);
|
||||
}
|
||||
|
||||
regular_obj:
|
||||
|
||||
// Write the object value
|
||||
if (!_pdfioObjWriteHeader(obj))
|
||||
return (false);
|
||||
@@ -69,7 +104,7 @@ pdfioObjCopy(pdfio_file_t *pdf, // I - PDF file
|
||||
ssize_t bytes; // Bytes read
|
||||
|
||||
|
||||
PDFIO_DEBUG("pdfioObjCopy(pdf=%p, srcobj=%p(%p))\n", pdf, srcobj, srcobj ? 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
|
||||
if (!pdf || !srcobj)
|
||||
@@ -77,7 +112,14 @@ pdfioObjCopy(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
// Load the object value if needed...
|
||||
if (srcobj->value.type == PDFIO_VALTYPE_NONE)
|
||||
_pdfioObjLoad(srcobj);
|
||||
{
|
||||
if (!_pdfioObjLoad(srcobj))
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
// See if we have already mapped this object...
|
||||
if ((dstobj = _pdfioFileFindMappedObj(pdf, srcobj->pdf, srcobj->number)) != NULL)
|
||||
return (dstobj); // Yes, return that one...
|
||||
|
||||
// Create the new object...
|
||||
if ((dstobj = _pdfioFileCreateObj(pdf, srcobj->pdf, NULL)) == NULL)
|
||||
@@ -141,6 +183,7 @@ pdfioObjCreateStream(
|
||||
pdfio_obj_t *obj, // I - Object
|
||||
pdfio_filter_t filter) // I - Type of compression to apply
|
||||
{
|
||||
pdfio_stream_t *st; // Stream
|
||||
pdfio_obj_t *length_obj = NULL; // Length object, if any
|
||||
|
||||
|
||||
@@ -194,11 +237,13 @@ pdfioObjCreateStream(
|
||||
if (!_pdfioFilePuts(obj->pdf, "stream\n"))
|
||||
return (NULL);
|
||||
|
||||
obj->stream_offset = _pdfioFileTell(obj->pdf);
|
||||
obj->pdf->current_obj = obj;
|
||||
obj->stream_offset = _pdfioFileTell(obj->pdf);
|
||||
|
||||
// Return the new stream...
|
||||
return (_pdfioStreamCreate(obj, length_obj, 0, filter));
|
||||
if ((st = _pdfioStreamCreate(obj, length_obj, 0, filter)) != NULL)
|
||||
obj->pdf->current_obj = obj;
|
||||
|
||||
return (st);
|
||||
}
|
||||
|
||||
|
||||
@@ -301,13 +346,14 @@ pdfioObjGetLength(pdfio_obj_t *obj) // I - Object
|
||||
// Try getting the length, directly or indirectly
|
||||
if ((length = (size_t)pdfioDictGetNumber(obj->value.value.dict, "Length")) > 0)
|
||||
{
|
||||
PDFIO_DEBUG("pdfioObjGetLength(obj=%p) returning %lu.\n", obj, (unsigned long)length);
|
||||
PDFIO_DEBUG("pdfioObjGetLength(obj=%p) returning %lu.\n", (void *)obj, (unsigned long)length);
|
||||
return (length);
|
||||
}
|
||||
|
||||
if ((lenobj = pdfioDictGetObj(obj->value.value.dict, "Length")) == NULL)
|
||||
{
|
||||
_pdfioFileError(obj->pdf, "Unable to get length of stream.");
|
||||
if (!_pdfioDictGetValue(obj->value.value.dict, "Length"))
|
||||
_pdfioFileError(obj->pdf, "Unable to get length of stream.");
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -320,7 +366,7 @@ pdfioObjGetLength(pdfio_obj_t *obj) // I - Object
|
||||
return (0);
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("pdfioObjGetLength(obj=%p) returning %lu.\n", obj, (unsigned long)lenobj->value.value.number);
|
||||
PDFIO_DEBUG("pdfioObjGetLength(obj=%p) returning %lu.\n", (void *)obj, (unsigned long)lenobj->value.value.number);
|
||||
|
||||
return ((size_t)lenobj->value.value.number);
|
||||
}
|
||||
@@ -329,6 +375,8 @@ pdfioObjGetLength(pdfio_obj_t *obj) // I - Object
|
||||
//
|
||||
// 'pdfioObjGetName()' - Get the name value associated with an object.
|
||||
//
|
||||
// @since PDFio v1.4@
|
||||
//
|
||||
|
||||
const char * // O - Dictionary or `NULL` on error
|
||||
pdfioObjGetName(pdfio_obj_t *obj) // I - Object
|
||||
@@ -430,7 +478,7 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
||||
_pdfio_token_t tb; // Token buffer/stack
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioObjLoad(obj=%p(%lu)), offset=%lu\n", obj, (unsigned long)obj->number, (unsigned long)obj->offset);
|
||||
PDFIO_DEBUG("_pdfioObjLoad(obj=%p(%lu)), offset=%lu\n", (void *)obj, (unsigned long)obj->number, (unsigned long)obj->offset);
|
||||
|
||||
// Seek to the start of the object and read its header...
|
||||
if (_pdfioFileSeek(obj->pdf, obj->offset, SEEK_SET) != obj->offset)
|
||||
@@ -492,7 +540,7 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
||||
return (false);
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[1]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
|
||||
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[1]=0x%02x\n", (void *)tb.bufptr, (void *)tb.bufend, tb.bufptr[0], tb.bufptr[1]);
|
||||
|
||||
_pdfioTokenFlush(&tb);
|
||||
|
||||
@@ -504,7 +552,7 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
||||
}
|
||||
|
||||
// Decrypt as needed...
|
||||
if (obj->pdf->encryption)
|
||||
if (obj->pdf->encryption && obj->pdf->encrypt_metadata)
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioObjLoad: Decrypting value...\n");
|
||||
|
||||
@@ -531,6 +579,11 @@ pdfio_stream_t * // O - Stream or `NULL` on error
|
||||
pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object
|
||||
bool decode) // I - Decode/decompress data?
|
||||
{
|
||||
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...
|
||||
if (!obj)
|
||||
return (NULL);
|
||||
@@ -550,12 +603,16 @@ pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object
|
||||
|
||||
// No stream if there is no dict or offset to a stream...
|
||||
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);
|
||||
}
|
||||
|
||||
// Open the stream...
|
||||
obj->pdf->current_obj = obj;
|
||||
if ((st = _pdfioStreamOpen(obj, decode)) != NULL)
|
||||
obj->pdf->current_obj = obj;
|
||||
|
||||
return (_pdfioStreamOpen(obj, decode));
|
||||
return (st);
|
||||
}
|
||||
|
||||
|
||||
@@ -586,7 +643,7 @@ _pdfioObjWriteHeader(pdfio_obj_t *obj) // I - Object
|
||||
if (!_pdfioFilePrintf(obj->pdf, "%lu %u obj\n", (unsigned long)obj->number, obj->generation))
|
||||
return (false);
|
||||
|
||||
if (!_pdfioValueWrite(obj->pdf, obj, &obj->value, &obj->length_offset))
|
||||
if (!_pdfioValueWrite((_pdfio_printf_t)_pdfioFilePrintf, obj->pdf, obj, &obj->value, &obj->length_offset))
|
||||
return (false);
|
||||
|
||||
return (_pdfioFilePuts(obj->pdf, "\n"));
|
||||
|
||||
335
pdfio-page.c
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// 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
|
||||
// information.
|
||||
@@ -15,6 +15,7 @@
|
||||
//
|
||||
|
||||
static _pdfio_value_t *get_contents(pdfio_obj_t *page);
|
||||
static _pdfio_value_t *get_page_value(pdfio_obj_t *page, const char *key);
|
||||
|
||||
|
||||
//
|
||||
@@ -28,7 +29,7 @@ pdfioPageCopy(pdfio_file_t *pdf, // I - PDF file
|
||||
pdfio_obj_t *dstpage; // Destination page object
|
||||
|
||||
|
||||
PDFIO_DEBUG("pdfioPageCopy(pdf=%p, srcpage=%p(%p))\n", pdf, srcpage, srcpage ? srcpage->pdf : NULL);
|
||||
PDFIO_DEBUG("pdfioPageCopy(pdf=%p, srcpage=%p(%p))\n", (void *)pdf, (void *)srcpage, srcpage ? (void *)srcpage->pdf : NULL);
|
||||
|
||||
// Range check input
|
||||
if (!pdf || !srcpage || srcpage->value.type != PDFIO_VALTYPE_DICT)
|
||||
@@ -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 v1.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 v1.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 v1.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_BOOLEAN)
|
||||
return (v->value.boolean);
|
||||
else
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '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 v1.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 v1.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 v1.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.
|
||||
//
|
||||
@@ -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 v1.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 v1.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 v1.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 v1.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.
|
||||
//
|
||||
@@ -87,14 +346,28 @@ pdfioPageOpenStream(
|
||||
// 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)
|
||||
{
|
||||
PDFIO_DEBUG("pdfioPageOpenStream: No contents.\n");
|
||||
return (NULL);
|
||||
}
|
||||
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));
|
||||
}
|
||||
else if (n)
|
||||
{
|
||||
PDFIO_DEBUG("pdfioPageOpenStream: Numbered stream does not exist.\n");
|
||||
return (NULL);
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +378,10 @@ pdfioPageOpenStream(
|
||||
static _pdfio_value_t * // O - Value or NULL on error
|
||||
get_contents(pdfio_obj_t *page) // I - Page object
|
||||
{
|
||||
_pdfio_value_t *contents; // Contents value
|
||||
pdfio_obj_t *obj; // Contents object
|
||||
|
||||
|
||||
// Range check input...
|
||||
if (!page)
|
||||
return (NULL);
|
||||
@@ -119,5 +396,57 @@ get_contents(pdfio_obj_t *page) // I - Page object
|
||||
if (page->value.type != PDFIO_VALTYPE_DICT)
|
||||
return (NULL);
|
||||
|
||||
return (_pdfioDictGetValue(page->value.value.dict, "Contents"));
|
||||
if ((contents = _pdfioDictGetValue(page->value.value.dict, "Contents")) == NULL)
|
||||
return (NULL);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
129
pdfio-private.h
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// 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
|
||||
// information.
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef PDFIO_PRIVATE_H
|
||||
# define PDFIO_PRIVATE_H
|
||||
# ifdef _WIN32
|
||||
# define _CRT_SECURE_NO_WARNINGS // Disable bogus VS warnings/errors...
|
||||
# define _CRT_SECURE_NO_WARNINGS 1 // Disable bogus VS warnings/errors...
|
||||
# endif // _WIN32
|
||||
# include "pdfio.h"
|
||||
# include <stdarg.h>
|
||||
@@ -28,16 +28,16 @@
|
||||
# define access _access // Map standard POSIX/C99 names
|
||||
# define close _close
|
||||
# define fileno _fileno
|
||||
# define lseek _lseek
|
||||
# define lseek(f,o,w) (off_t)_lseek((f),(long)(o),(w))
|
||||
# define mkdir(d,p) _mkdir(d)
|
||||
# define open _open
|
||||
# define read _read
|
||||
# define open _pdfio_win32_open
|
||||
# define read(f,b,s) _read((f),(b),(unsigned)(s))
|
||||
# define rmdir _rmdir
|
||||
# define snprintf _snprintf
|
||||
# define strdup _strdup
|
||||
# define unlink _unlink
|
||||
# define vsnprintf _vsnprintf
|
||||
# define write _write
|
||||
# define write(f,b,s) _write((f),(b),(unsigned)(s))
|
||||
# ifndef F_OK
|
||||
# define F_OK 00 // POSIX parameters/flags
|
||||
# define W_OK 02
|
||||
@@ -94,9 +94,12 @@
|
||||
//
|
||||
|
||||
# define PDFIO_MAX_DEPTH 32 // Maximum nesting depth for values
|
||||
# define PDFIO_MAX_STRING 131072 // Maximum length of string
|
||||
|
||||
typedef void (*_pdfio_extfree_t)(void *);
|
||||
typedef void (*_pdfio_extfree_t)(void *p);
|
||||
// Extension data free function
|
||||
typedef bool (*_pdfio_printf_t)(void *data, const char *format, ...);
|
||||
// "printf" function
|
||||
|
||||
typedef enum _pdfio_mode_e // Read/write mode
|
||||
{
|
||||
@@ -116,6 +119,21 @@ typedef enum _pdfio_predictor_e // PNG predictor constants
|
||||
_PDFIO_PREDICTOR_PNG_AUTO = 15 // PNG "auto" predictor (currently mapped to Paeth)
|
||||
} _pdfio_predictor_t;
|
||||
|
||||
typedef enum _pdfio_profile_e // PDF profile constants
|
||||
{
|
||||
_PDFIO_PROFILE_NONE = 0, // Base PDF file
|
||||
_PDFIO_PROFILE_PCLM, // PCLm (PDF raster) file
|
||||
_PDFIO_PROFILE_PDFA_1A, // PDF/A-1a:2005
|
||||
_PDFIO_PROFILE_PDFA_1B, // PDF/A-1b:2005
|
||||
_PDFIO_PROFILE_PDFA_2A, // PDF/A-2a:2011
|
||||
_PDFIO_PROFILE_PDFA_2B, // PDF/A-2b:2011
|
||||
_PDFIO_PROFILE_PDFA_2U, // PDF/A-2u:2011
|
||||
_PDFIO_PROFILE_PDFA_3A, // PDF/A-3a:2012
|
||||
_PDFIO_PROFILE_PDFA_3B, // PDF/A-3b:2012
|
||||
_PDFIO_PROFILE_PDFA_3U, // PDF/A-3u:2012
|
||||
_PDFIO_PROFILE_PDFA_4 // PDF/A-4:2020
|
||||
} _pdfio_profile_t;
|
||||
|
||||
typedef ssize_t (*_pdfio_tconsume_cb_t)(void *data, size_t bytes);
|
||||
typedef ssize_t (*_pdfio_tpeek_cb_t)(void *data, void *buffer, size_t bytes);
|
||||
|
||||
@@ -160,7 +178,7 @@ typedef struct _pdfio_value_s // Value structure
|
||||
typedef struct _pdfio_aes_s // AES encryption state
|
||||
{
|
||||
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
|
||||
} _pdfio_aes_t;
|
||||
|
||||
@@ -195,6 +213,38 @@ typedef union _pdfio_crypto_ctx_u // Cryptographic contexts
|
||||
} _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 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
|
||||
bool reversed; // Reversed bit encoding?
|
||||
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
|
||||
{
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
@@ -220,15 +270,27 @@ struct _pdfio_dict_s // Dictionary
|
||||
typedef struct _pdfio_objmap_s // PDF object map
|
||||
{
|
||||
pdfio_obj_t *obj; // Object for this file
|
||||
pdfio_file_t *src_pdf; // Source PDF file
|
||||
unsigned char src_id[32]; // Source PDF file file identifier
|
||||
size_t src_number; // Source object number
|
||||
} _pdfio_objmap_t;
|
||||
|
||||
typedef struct _pdfio_strbuf_s // PDF string buffer
|
||||
{
|
||||
struct _pdfio_strbuf_s *next; // Next string buffer
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
bool bufused; // Is this string buffer being used?
|
||||
char buffer[PDFIO_MAX_STRING + 32],
|
||||
// String buffer
|
||||
*bufptr; // Pointer into buffer
|
||||
} _pdfio_strbuf_t;
|
||||
|
||||
struct _pdfio_file_s // PDF file structure
|
||||
{
|
||||
char *filename; // Filename
|
||||
unsigned char file_id[32]; // File identifier bytes
|
||||
struct lconv *loc; // Locale data
|
||||
char *version; // Version number
|
||||
_pdfio_profile_t profile; // PDF profile, if any
|
||||
pdfio_rect_t media_box, // Default MediaBox value
|
||||
crop_box; // Default CropBox value
|
||||
_pdfio_mode_t mode; // Read/write mode
|
||||
@@ -257,10 +319,17 @@ struct _pdfio_file_s // PDF file structure
|
||||
pdfio_obj_t *root_obj; // Root object/dictionary
|
||||
pdfio_obj_t *info_obj; // Information object
|
||||
pdfio_obj_t *pages_obj; // Root pages object
|
||||
pdfio_obj_t *encrypt_obj; // De/Encryption object/dictionary
|
||||
pdfio_obj_t *cp1252_obj, // CP1252 font encoding object
|
||||
*unicode_obj; // Unicode font encoding object
|
||||
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
|
||||
*cp1252_obj, // CP1252 font encoding object
|
||||
*unicode_obj, // Unicode font encoding object
|
||||
*objstm_obj; // Object stream object
|
||||
pdfio_dict_t *objstm_dict; // Object stream dictionary
|
||||
size_t num_objstm; // Number of objects in object stream
|
||||
pdfio_array_t *id_array; // ID array
|
||||
bool encrypt_metadata; // Encrypt metadata?
|
||||
pdfio_dict_t *markinfo; // MarkInfo dictionary, if any
|
||||
|
||||
// Allocated data elements
|
||||
size_t num_arrays, // Number of arrays
|
||||
@@ -283,6 +352,7 @@ struct _pdfio_file_s // PDF file structure
|
||||
size_t num_strings, // Number of strings
|
||||
alloc_strings; // Allocated strings
|
||||
char **strings; // Nul-terminated strings
|
||||
_pdfio_strbuf_t *strbuffers; // String buffers
|
||||
};
|
||||
|
||||
struct _pdfio_obj_s // Object
|
||||
@@ -296,6 +366,9 @@ struct _pdfio_obj_s // Object
|
||||
size_t stream_length; // Length of stream, if any
|
||||
_pdfio_value_t value; // Dictionary/number/etc. value
|
||||
pdfio_stream_t *stream; // Open stream, if any
|
||||
size_t objstm_number; // Object stream number
|
||||
char *objstm_data; // Object stream data, if any
|
||||
size_t objstm_datalen; // Object stream data length
|
||||
void *data; // Extension data, if any
|
||||
_pdfio_extfree_t datafree; // Free callback for extension data
|
||||
};
|
||||
@@ -310,12 +383,20 @@ struct _pdfio_stream_s // Stream
|
||||
char buffer[8192], // Read/write buffer
|
||||
*bufptr, // Current position in 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
|
||||
_pdfio_lzw_t *lzw; // LZW filter state
|
||||
_pdfio_predictor_t predictor; // Predictor function, if any
|
||||
size_t pbpixel, // Size of a pixel in bytes
|
||||
pbsize, // Predictor buffer size, if any
|
||||
cbsize; // Compressed data buffer size
|
||||
unsigned char *cbuffer, // Compressed data buffer
|
||||
uint8_t *cbuffer, // Compressed data buffer
|
||||
*prbuffer, // Raw buffer (previous line), as needed
|
||||
*psbuffer; // PNG filter buffer, as needed
|
||||
_pdfio_crypto_cb_t crypto_cb; // Encryption/descryption callback, if any
|
||||
@@ -327,15 +408,18 @@ struct _pdfio_stream_s // Stream
|
||||
// Functions...
|
||||
//
|
||||
|
||||
extern size_t _pdfio_strlcpy(char *dst, const char *src, size_t dstsize) _PDFIO_INTERNAL;
|
||||
extern double _pdfio_strtod(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
|
||||
extern void _pdfio_utf16cpy(char *dst, const unsigned char *src, size_t srclen, size_t dstsize) _PDFIO_INTERNAL;
|
||||
extern ssize_t _pdfio_vsnprintf(pdfio_file_t *pdf, char *buffer, size_t bufsize, const char *format, va_list ap) _PDFIO_INTERNAL;
|
||||
extern int _pdfio_win32_open(const char *filename, int oflag, int mode) _PDFIO_INTERNAL;
|
||||
|
||||
extern bool _pdfioArrayDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_array_t *a, size_t depth) _PDFIO_INTERNAL;
|
||||
extern void _pdfioArrayDebug(pdfio_array_t *a, FILE *fp) _PDFIO_INTERNAL;
|
||||
extern void _pdfioArrayDelete(pdfio_array_t *a) _PDFIO_INTERNAL;
|
||||
extern _pdfio_value_t *_pdfioArrayGetValue(pdfio_array_t *a, size_t n) _PDFIO_INTERNAL;
|
||||
extern pdfio_array_t *_pdfioArrayRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, size_t depth) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioArrayWrite(pdfio_array_t *a, pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioArrayWrite(_pdfio_printf_t cb, void *cbdata, pdfio_obj_t *obj, pdfio_array_t *a) _PDFIO_INTERNAL;
|
||||
|
||||
extern void _pdfioCryptoAESInit(_pdfio_aes_t *ctx, const uint8_t *key, size_t keylen, const uint8_t *iv) _PDFIO_INTERNAL;
|
||||
extern size_t _pdfioCryptoAESDecrypt(_pdfio_aes_t *ctx, uint8_t *outbuffer, const uint8_t *inbuffer, size_t len) _PDFIO_INTERNAL;
|
||||
@@ -360,26 +444,30 @@ extern void _pdfioDictDelete(pdfio_dict_t *dict) _PDFIO_INTERNAL;
|
||||
extern _pdfio_value_t *_pdfioDictGetValue(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
||||
extern pdfio_dict_t *_pdfioDictRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, size_t depth) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioDictSetValue(pdfio_dict_t *dict, const char *key, _pdfio_value_t *value) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioDictWrite(pdfio_dict_t *dict, pdfio_obj_t *obj, off_t *length) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioDictWrite(_pdfio_printf_t cb, void *cbdata, pdfio_obj_t *obj, pdfio_dict_t *dict, off_t *length) _PDFIO_INTERNAL;
|
||||
|
||||
extern bool _pdfioFileAddMappedObj(pdfio_file_t *pdf, pdfio_obj_t *dst_obj, pdfio_obj_t *src_obj) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileAddPage(pdfio_file_t *pdf, pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileConsume(pdfio_file_t *pdf, size_t bytes) _PDFIO_INTERNAL;
|
||||
extern pdfio_obj_t *_pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_file_t *srcpdf, _pdfio_value_t *value) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileDefaultError(pdfio_file_t *pdf, const char *message, void *data) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileError(pdfio_file_t *pdf, const char *format, ...) _PDFIO_FORMAT(2,3) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileError(pdfio_file_t *pdf, const char *format, ...) _PDFIO_INTERNAL;
|
||||
extern pdfio_obj_t *_pdfioFileFindMappedObj(pdfio_file_t *pdf, pdfio_file_t *src_pdf, size_t src_number) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileFlush(pdfio_file_t *pdf) _PDFIO_INTERNAL;
|
||||
extern int _pdfioFileGetChar(pdfio_file_t *pdf) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileGets(pdfio_file_t *pdf, char *buffer, size_t bufsize) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileGets(pdfio_file_t *pdf, char *buffer, size_t bufsize, bool discard) _PDFIO_INTERNAL;
|
||||
extern ssize_t _pdfioFilePeek(pdfio_file_t *pdf, void *buffer, size_t bytes) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFilePrintf(pdfio_file_t *pdf, const char *format, ...) _PDFIO_FORMAT(2,3) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFilePrintf(pdfio_file_t *pdf, const char *format, ...) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFilePuts(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
|
||||
extern ssize_t _pdfioFileRead(pdfio_file_t *pdf, void *buffer, size_t bytes) _PDFIO_INTERNAL;
|
||||
extern off_t _pdfioFileSeek(pdfio_file_t *pdf, off_t offset, int whence) _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 _pdfio_lzw_t *_pdfioLZWCreate(int def_code_size, int early, bool reversed) _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 *_pdfioObjGetExtension(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioObjLoad(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
@@ -389,7 +477,10 @@ extern bool _pdfioObjWriteHeader(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, size_t cbsize, pdfio_filter_t compression) _PDFIO_INTERNAL;
|
||||
extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL;
|
||||
|
||||
extern char *_pdfioStringAllocBuffer(pdfio_file_t *pdf, _pdfio_strbuf_t **bptr);
|
||||
extern void _pdfioStringFreeBuffer(pdfio_file_t *pdf, char *buffer);
|
||||
extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioStringPrintf(_pdfio_strbuf_t *bptr, const char *format, ...) _PDFIO_INTERNAL;
|
||||
|
||||
extern void _pdfioTokenClear(_pdfio_token_t *tb) _PDFIO_INTERNAL;
|
||||
extern void _pdfioTokenFlush(_pdfio_token_t *tb) _PDFIO_INTERNAL;
|
||||
@@ -403,7 +494,7 @@ extern bool _pdfioValueDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_valu
|
||||
extern void _pdfioValueDebug(_pdfio_value_t *v, FILE *fp) _PDFIO_INTERNAL;
|
||||
extern void _pdfioValueDelete(_pdfio_value_t *v) _PDFIO_INTERNAL;
|
||||
extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioValueWrite(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_value_t *v, off_t *length) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioValueWrite(_pdfio_printf_t cb, void *cbdata, pdfio_obj_t *obj, _pdfio_value_t *v, off_t *length) _PDFIO_INTERNAL;
|
||||
|
||||
|
||||
#endif // !PDFIO_PRIVATE_H
|
||||
|
||||
564
pdfio-stream.c
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// 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
|
||||
// information.
|
||||
@@ -14,6 +14,8 @@
|
||||
// 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 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);
|
||||
@@ -39,6 +41,8 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
{
|
||||
if (st->filter == PDFIO_FILTER_FLATE)
|
||||
inflateEnd(&(st->flate));
|
||||
else if (st->filter == PDFIO_FILTER_LZW)
|
||||
_pdfioLZWDelete(st->lzw);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -172,6 +176,7 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
|
||||
st->pdf->current_obj = NULL;
|
||||
|
||||
free(st->a85buffer);
|
||||
free(st->cbuffer);
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
@@ -259,7 +264,7 @@ _pdfioStreamCreate(
|
||||
{
|
||||
colors = 1;
|
||||
}
|
||||
else if (colors < 0 || colors > 4)
|
||||
else if (colors < 0 || colors > 32)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Colors value %d.", colors);
|
||||
free(st);
|
||||
@@ -270,7 +275,7 @@ _pdfioStreamCreate(
|
||||
{
|
||||
columns = 1;
|
||||
}
|
||||
else if (columns < 0)
|
||||
else if (columns < 0 || columns > 65536)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Columns value %d.", columns);
|
||||
free(st);
|
||||
@@ -427,7 +432,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
const char *type; // Object type
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen(obj=%p(%u), decode=%s)\n", obj, (unsigned)obj->number, decode ? "true" : "false");
|
||||
PDFIO_DEBUG("_pdfioStreamOpen(obj=%p(%u), decode=%s)\n", (void *)obj, (unsigned)obj->number, decode ? "true" : "false");
|
||||
|
||||
// Allocate a new stream object...
|
||||
if ((st = (pdfio_stream_t *)calloc(1, sizeof(pdfio_stream_t))) == NULL)
|
||||
@@ -439,7 +444,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
st->pdf = obj->pdf;
|
||||
st->obj = obj;
|
||||
|
||||
if ((st->remaining = pdfioObjGetLength(obj)) == 0)
|
||||
if ((st->remaining = pdfioObjGetLength(obj)) == 0 && !_pdfioDictGetValue(pdfioObjGetDict(obj), "Length"))
|
||||
{
|
||||
_pdfioFileError(obj->pdf, "No stream data.");
|
||||
goto error;
|
||||
@@ -479,10 +484,34 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
pdfio_array_t *fa = pdfioDictGetArray(dict, "Filter");
|
||||
// Filter array
|
||||
|
||||
if (!filter && fa && pdfioArrayGetSize(fa) == 1)
|
||||
if (!filter && fa)
|
||||
{
|
||||
// Support single-valued arrays...
|
||||
filter = pdfioArrayGetName(fa, 0);
|
||||
const char *filter0 = 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)
|
||||
@@ -490,7 +519,6 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
// No single filter name, do we have a compound filter?
|
||||
if (fa)
|
||||
{
|
||||
// TODO: Implement compound filters...
|
||||
_pdfioFileError(st->pdf, "Unsupported compound stream filter.");
|
||||
goto error;
|
||||
}
|
||||
@@ -498,9 +526,9 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
// No filter, read as-is...
|
||||
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");
|
||||
// Decoding parameters
|
||||
int bpc = (int)pdfioDictGetNumber(params, "BitsPerComponent");
|
||||
@@ -511,12 +539,11 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
// Number of columns
|
||||
int predictor = (int)pdfioDictGetNumber(params, "Predictor");
|
||||
// Predictory value, if any
|
||||
int status; // ZLIB status
|
||||
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)
|
||||
{
|
||||
@@ -532,7 +559,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
{
|
||||
colors = 1;
|
||||
}
|
||||
else if (colors < 0 || colors > 4)
|
||||
else if (colors < 0 || colors > 32)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Colors value %d.", colors);
|
||||
goto error;
|
||||
@@ -542,7 +569,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
{
|
||||
columns = 1;
|
||||
}
|
||||
else if (columns < 0)
|
||||
else if (columns < 0 || columns > 65536)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Columns value %d.", columns);
|
||||
goto error;
|
||||
@@ -562,6 +589,13 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
if (predictor >= 10)
|
||||
st->pbsize ++; // Add PNG predictor byte
|
||||
|
||||
if (st->pbsize < 2)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Bad Predictor buffer size %lu.", (unsigned long)st->pbsize);
|
||||
goto error;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen: st->predictor=%d, st->pbpixel=%u, st->pbsize=%lu\n", st->predictor, (unsigned)st->pbpixel, (unsigned long)st->pbsize);
|
||||
if ((st->prbuffer = calloc(1, st->pbsize - 1)) == NULL || (st->psbuffer = calloc(1, st->pbsize)) == NULL)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Predictor buffers.", (unsigned long)st->pbsize);
|
||||
@@ -576,42 +610,57 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
st->cbsize = 4096;
|
||||
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;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen: pos=%ld\n", (long)_pdfioFileTell(st->pdf));
|
||||
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)
|
||||
if ((rbytes = stream_get_bytes(st, st->cbuffer, st->cbsize)) <= 0)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to read bytes for stream.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (st->crypto_cb)
|
||||
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)
|
||||
if (st->filter == PDFIO_FILTER_FLATE)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to start Flate filter: %s", zstrerror(status));
|
||||
goto error;
|
||||
}
|
||||
// Flate decompression...
|
||||
int status; // ZLIB status
|
||||
|
||||
st->remaining -= st->flate.avail_in;
|
||||
}
|
||||
else if (!strcmp(filter, "LZWDecode"))
|
||||
{
|
||||
// LZW compression
|
||||
st->filter = PDFIO_FILTER_LZW;
|
||||
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 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, /*reversed*/false)) == 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
|
||||
{
|
||||
@@ -631,12 +680,13 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
// If we get here something went wrong...
|
||||
error:
|
||||
|
||||
free(st->a85buffer);
|
||||
free(st->cbuffer);
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
return (NULL);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -689,6 +739,11 @@ pdfioStreamPeek(pdfio_stream_t *st, // I - Stream
|
||||
//
|
||||
// 'pdfioStreamPrintf()' - Write a formatted string to a stream.
|
||||
//
|
||||
// This function writes a formatted string to a stream. In addition to the
|
||||
// standard `printf` format characters, you can use "%H" to format a HTML/XML
|
||||
// string value, "%N" to format a PDF name value ("/Name"), and "%S" to format
|
||||
// a PDF string ("(String)") value.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
pdfioStreamPrintf(
|
||||
@@ -836,7 +891,7 @@ pdfioStreamWrite(
|
||||
*pptr; // Previous raw buffer
|
||||
|
||||
|
||||
PDFIO_DEBUG("pdfioStreamWrite(st=%p, buffer=%p, bytes=%lu)\n", st, buffer, (unsigned long)bytes);
|
||||
PDFIO_DEBUG("pdfioStreamWrite(st=%p, buffer=%p, bytes=%lu)\n", (void *)st, buffer, (unsigned long)bytes);
|
||||
|
||||
// Range check input...
|
||||
if (!st || st->pdf->mode != _PDFIO_MODE_WRITE || !buffer || !bytes)
|
||||
@@ -999,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 + (unsigned)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.
|
||||
//
|
||||
@@ -1026,67 +1346,20 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
char *buffer, // I - Buffer
|
||||
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)
|
||||
{
|
||||
// No filtering, but 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);
|
||||
}
|
||||
|
||||
return (rbytes);
|
||||
// No filtering...
|
||||
return (stream_get_bytes(st, buffer, bytes));
|
||||
}
|
||||
else if (st->filter == PDFIO_FILTER_FLATE)
|
||||
else if (st->filter == PDFIO_FILTER_FLATE || st->filter == PDFIO_FILTER_LZW)
|
||||
{
|
||||
// Deflate compression...
|
||||
int status; // Status of decompression
|
||||
|
||||
// Flate or LZW compression...
|
||||
if (st->predictor == _PDFIO_PREDICTOR_NONE)
|
||||
{
|
||||
// Decompress into the buffer...
|
||||
PDFIO_DEBUG("stream_read: No predictor.\n");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return (stream_inflate(st, (uint8_t *)buffer, bytes, /*exactly*/false));
|
||||
}
|
||||
else if (st->predictor == _PDFIO_PREDICTOR_TIFF2)
|
||||
{
|
||||
@@ -1094,9 +1367,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
// Size of pixel in bytes
|
||||
remaining = st->pbsize;
|
||||
// Remaining bytes
|
||||
unsigned char *bufptr = (unsigned char *)buffer,
|
||||
uint8_t *bufptr = (uint8_t *)buffer,
|
||||
// Pointer into buffer
|
||||
*bufsecond = (unsigned char *)buffer + pbpixel,
|
||||
*bufsecond = (uint8_t *)buffer + pbpixel,
|
||||
// Pointer to second pixel in buffer
|
||||
*sptr = st->psbuffer;
|
||||
// Current (raw) line
|
||||
@@ -1109,43 +1382,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
return (-1);
|
||||
}
|
||||
|
||||
st->flate.next_out = (Bytef *)sptr;
|
||||
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)
|
||||
if (stream_inflate(st, sptr, st->pbsize, /*exactly*/true) < 0)
|
||||
return (-1); // Early end of stream
|
||||
|
||||
for (; bufptr < bufsecond; remaining --, sptr ++)
|
||||
@@ -1162,9 +1399,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
// Size of pixel in bytes
|
||||
remaining = st->pbsize - 1;
|
||||
// Remaining bytes
|
||||
unsigned char *bufptr = (unsigned char *)buffer,
|
||||
uint8_t *bufptr = (uint8_t *)buffer,
|
||||
// Pointer into buffer
|
||||
*bufsecond = (unsigned char *)buffer + pbpixel,
|
||||
*bufsecond = (uint8_t *)buffer + pbpixel,
|
||||
// Pointer to second pixel in buffer
|
||||
*sptr = st->psbuffer + 1,
|
||||
// Current (raw) line
|
||||
@@ -1179,51 +1416,26 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
return (-1);
|
||||
}
|
||||
|
||||
st->flate.next_out = (Bytef *)sptr - 1;
|
||||
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)
|
||||
if (stream_inflate(st, sptr - 1, st->pbsize, /*exactly*/true) < 0)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Apply predictor for this line
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X %02X %02X %02X.\n", sptr[-1], sptr[0], sptr[0], sptr[2], sptr[3]);
|
||||
#ifdef DEBUG
|
||||
if (remaining > 4)
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X %02X %02X %02X ...\n", sptr[-1], sptr[0], sptr[1], sptr[2], sptr[3]);
|
||||
else if (remaining > 3)
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X %02X %02X %02X.\n", sptr[-1], sptr[0], sptr[1], sptr[2], sptr[3]);
|
||||
else if (remaining > 2)
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X %02X %02X.\n", sptr[-1], sptr[0], sptr[1], sptr[2]);
|
||||
else if (remaining > 1)
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X %02X.\n", sptr[-1], sptr[0], sptr[1]);
|
||||
else
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X.\n", sptr[-1], sptr[0]);
|
||||
#endif // DEBUG
|
||||
|
||||
switch (sptr[-1])
|
||||
{
|
||||
@@ -1310,8 +1522,6 @@ stream_write(pdfio_stream_t *st, // I - Stream
|
||||
outbytes = cbytes;
|
||||
}
|
||||
|
||||
// fprintf(stderr, "stream_write: bytes=%u, outbytes=%u\n", (unsigned)bytes, (unsigned)outbytes);
|
||||
|
||||
if (!_pdfioFileWrite(st->pdf, st->cbuffer, outbytes))
|
||||
return (false);
|
||||
|
||||
|
||||
438
pdfio-string.c
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF string 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
|
||||
// information.
|
||||
@@ -17,6 +17,83 @@
|
||||
static size_t find_string(pdfio_file_t *pdf, const char *s, int *rdiff);
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_strlcpy()' - Safe string copy.
|
||||
//
|
||||
|
||||
size_t // O - Length of source string
|
||||
_pdfio_strlcpy(char *dst, // I - Destination string buffer
|
||||
const char *src, // I - Source string
|
||||
size_t dstsize) // I - Size of destination
|
||||
{
|
||||
size_t srclen; // Length of source string
|
||||
|
||||
|
||||
// Range check input...
|
||||
if (!dst || !src || dstsize == 0)
|
||||
{
|
||||
if (dst)
|
||||
*dst = '\0';
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Figure out how much room is needed...
|
||||
dstsize --;
|
||||
|
||||
srclen = strlen(src);
|
||||
|
||||
// Copy the appropriate amount...
|
||||
if (srclen <= dstsize)
|
||||
{
|
||||
// Source string will fit...
|
||||
memmove(dst, src, srclen);
|
||||
dst[srclen] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Source string too big, copy what we can and clean up the end...
|
||||
char *ptr = dst + dstsize - 1, // Pointer into string
|
||||
*end = ptr + 1; // Pointer to end of string
|
||||
|
||||
memmove(dst, src, dstsize);
|
||||
dst[dstsize] = '\0';
|
||||
|
||||
// Validate last character in destination buffer...
|
||||
if (ptr > dst && *ptr & 0x80)
|
||||
{
|
||||
while ((*ptr & 0xc0) == 0x80 && ptr > dst)
|
||||
ptr --;
|
||||
|
||||
if ((*ptr & 0xe0) == 0xc0)
|
||||
{
|
||||
// Verify 2-byte UTF-8 sequence...
|
||||
if ((end - ptr) != 2)
|
||||
*ptr = '\0';
|
||||
}
|
||||
else if ((*ptr & 0xf0) == 0xe0)
|
||||
{
|
||||
// Verify 3-byte UTF-8 sequence...
|
||||
if ((end - ptr) != 3)
|
||||
*ptr = '\0';
|
||||
}
|
||||
else if ((*ptr & 0xf8) == 0xf0)
|
||||
{
|
||||
// Verify 4-byte UTF-8 sequence...
|
||||
if ((end - ptr) != 4)
|
||||
*ptr = '\0';
|
||||
}
|
||||
else if (*ptr & 0x80)
|
||||
{
|
||||
// Invalid sequence at end...
|
||||
*ptr = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (srclen);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_strtod()' - Convert a string to a double value.
|
||||
//
|
||||
@@ -81,6 +158,89 @@ _pdfio_strtod(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_utf16cpy()' - Convert UTF-16 to UTF-8.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfio_utf16cpy(
|
||||
char *dst, // I - Destination buffer for UTF-8
|
||||
const unsigned char *src, // I - Source UTF-16
|
||||
size_t srclen, // I - Length of UTF-16
|
||||
size_t dstsize) // I - Destination buffer size
|
||||
{
|
||||
char *dstptr = dst, // Pointer into buffer
|
||||
*dstend = dst + dstsize - 5; // End of buffer
|
||||
int ch; // Unicode character
|
||||
bool is_be = !memcmp(src, "\376\377", 2);
|
||||
// Big-endian strings?
|
||||
|
||||
|
||||
// Loop through the UTF-16 string, converting to Unicode then UTF-8...
|
||||
for (src += 2, srclen -= 2; srclen > 1 && dstptr < dstend; src += 2, srclen -= 2)
|
||||
{
|
||||
// Initial character...
|
||||
if (is_be)
|
||||
ch = (src[0] << 8) | src[1];
|
||||
else
|
||||
ch = (src[1] << 8) | src[0];
|
||||
|
||||
if (ch >= 0xd800 && ch <= 0xdbff && srclen > 3)
|
||||
{
|
||||
// Multi-word UTF-16 char...
|
||||
int lch; // Lower bits
|
||||
|
||||
if (is_be)
|
||||
lch = (src[2] << 8) | src[3];
|
||||
else
|
||||
lch = (src[3] << 8) | src[2];
|
||||
|
||||
if (lch < 0xdc00 || lch >= 0xdfff)
|
||||
break;
|
||||
|
||||
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
|
||||
src += 2;
|
||||
srclen -= 2;
|
||||
}
|
||||
else if (ch >= 0xfffe)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert Unicode to UTF-8...
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*dstptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 4096)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*dstptr++ = (char)(0xc0 | (ch >> 6));
|
||||
*dstptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else if (ch < 65536)
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*dstptr++ = (char)(0xe0 | (ch >> 12));
|
||||
*dstptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*dstptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4-byte UTF-8
|
||||
*dstptr++ = (char)(0xf0 | (ch >> 18));
|
||||
*dstptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
|
||||
*dstptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*dstptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
// Nul-terminate the UTF-8 string...
|
||||
*dstptr = '\0';
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_vsnprintf()' - Format a string.
|
||||
//
|
||||
@@ -112,10 +272,9 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
|
||||
// Loop through the format string, formatting as needed...
|
||||
bufptr = buffer;
|
||||
bufend = buffer + bufsize - 1;
|
||||
*bufend = '\0';
|
||||
bytes = 0;
|
||||
bufptr = buffer;
|
||||
bufend = buffer + bufsize - 1;
|
||||
bytes = 0;
|
||||
|
||||
while (*format)
|
||||
{
|
||||
@@ -178,14 +337,12 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
else
|
||||
{
|
||||
prec = 0;
|
||||
|
||||
while (isdigit(*format & 255))
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
prec = prec * 10 + *format++ - '0';
|
||||
format ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,7 +416,7 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
strncpy(bufptr, temp, (size_t)(bufend - bufptr - 1));
|
||||
_pdfio_strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
@@ -289,7 +446,7 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
strncpy(bufptr, temp, (size_t)(bufend - bufptr - 1));
|
||||
_pdfio_strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
@@ -304,7 +461,7 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
strncpy(bufptr, temp, (size_t)(bufend - bufptr - 1));
|
||||
_pdfio_strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
@@ -329,19 +486,164 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
break;
|
||||
|
||||
case 's' : // String
|
||||
case 'H' : // XML/HTML string
|
||||
if ((s = va_arg(ap, char *)) == NULL)
|
||||
s = "(null)";
|
||||
|
||||
// Loop through the literal string...
|
||||
while (*s)
|
||||
{
|
||||
// Escape special characters
|
||||
if (*s == '&')
|
||||
{
|
||||
// &
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, "&", (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
|
||||
bytes += 5;
|
||||
}
|
||||
else if (*s == '<')
|
||||
{
|
||||
// <
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, "<", (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
|
||||
bytes += 4;
|
||||
}
|
||||
else if (*s == '>')
|
||||
{
|
||||
// >
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, ">", (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
|
||||
bytes += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal character...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *s;
|
||||
bytes ++;
|
||||
}
|
||||
|
||||
s ++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S' : // PDF string
|
||||
if ((s = va_arg(ap, char *)) == NULL)
|
||||
s = "(null)";
|
||||
|
||||
// PDF strings start with "("...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = '(';
|
||||
|
||||
bytes ++;
|
||||
|
||||
// Loop through the literal string...
|
||||
while (*s)
|
||||
{
|
||||
// Escape special characters
|
||||
if (*s == '\\' || *s == '(' || *s == ')')
|
||||
{
|
||||
// Simple escape...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = '\\';
|
||||
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *s;
|
||||
|
||||
bytes += 2;
|
||||
}
|
||||
else if (*s < ' ')
|
||||
{
|
||||
// Octal escape...
|
||||
snprintf(bufptr, (size_t)(bufend - bufptr + 1), "\\%03o", *s & 255);
|
||||
bufptr += strlen(bufptr);
|
||||
bytes += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal character...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *s;
|
||||
bytes ++;
|
||||
}
|
||||
|
||||
s ++;
|
||||
}
|
||||
|
||||
// PDF strings end with ")"...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = ')';
|
||||
|
||||
bytes ++;
|
||||
break;
|
||||
|
||||
case 's' : // Literal string
|
||||
if ((s = va_arg(ap, char *)) == NULL)
|
||||
s = "(null)";
|
||||
|
||||
if (width != 0)
|
||||
{
|
||||
// Format string to fit inside the specified width...
|
||||
if ((size_t)(width + 1) > sizeof(temp))
|
||||
break;
|
||||
|
||||
snprintf(temp, sizeof(temp), tformat, s);
|
||||
s = temp;
|
||||
}
|
||||
|
||||
bytes += strlen(s);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
strncpy(bufptr, s, (size_t)(bufend - bufptr - 1));
|
||||
_pdfio_strlcpy(bufptr, s, (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N' : // Output name string with proper escaping
|
||||
if ((s = va_arg(ap, char *)) == NULL)
|
||||
s = "(null)";
|
||||
|
||||
// PDF names start with "/"...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = '/';
|
||||
|
||||
bytes ++;
|
||||
|
||||
// Loop through the name string...
|
||||
while (*s)
|
||||
{
|
||||
if (*s < 0x21 || *s > 0x7e || *s == '#')
|
||||
{
|
||||
// Output #XX for character...
|
||||
snprintf(bufptr, (size_t)(bufend - bufptr + 1), "#%02X", *s & 255);
|
||||
bufptr += strlen(bufptr);
|
||||
bytes += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Output literal character...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *s;
|
||||
bytes ++;
|
||||
}
|
||||
|
||||
s ++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n' : // Output number of chars so far
|
||||
*(va_arg(ap, int *)) = (int)bytes;
|
||||
break;
|
||||
@@ -358,11 +660,7 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
// Nul-terminate the string and return the number of characters needed.
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
// Everything fit in the buffer...
|
||||
*bufptr = '\0';
|
||||
}
|
||||
*bufptr = '\0';
|
||||
|
||||
PDFIO_DEBUG("_pdfio_vsnprintf: Returning %ld \"%s\"\n", (long)bytes, buffer);
|
||||
|
||||
@@ -370,6 +668,55 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioStringAllocBuffer()' - Allocate a string buffer.
|
||||
//
|
||||
|
||||
char * // O - Buffer or `NULL` on error
|
||||
_pdfioStringAllocBuffer(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfio_strbuf_t **bptr) // O - String buffer pointer
|
||||
{
|
||||
_pdfio_strbuf_t *current; // Current string buffer
|
||||
|
||||
|
||||
// See if we have an available string buffer...
|
||||
for (current = pdf->strbuffers; current; current = current->next)
|
||||
{
|
||||
if (!current->bufused)
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Didn't find one, allocate a new one...
|
||||
if ((current = calloc(1, sizeof(_pdfio_strbuf_t))) == NULL)
|
||||
{
|
||||
if (bptr)
|
||||
*bptr = NULL;
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
// Add to the linked list of string buffers...
|
||||
current->pdf = pdf;
|
||||
current->next = pdf->strbuffers;
|
||||
pdf->strbuffers = current;
|
||||
|
||||
// Claim and return the free string buffer...
|
||||
done:
|
||||
|
||||
current->bufused = true;
|
||||
|
||||
if (bptr)
|
||||
{
|
||||
*bptr = current;
|
||||
current->buffer[0] = '\0';
|
||||
current->bufptr = current->buffer;
|
||||
}
|
||||
|
||||
return (current->buffer);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioStringCreate()' - Create a durable literal string.
|
||||
//
|
||||
@@ -390,7 +737,7 @@ pdfioStringCreate(
|
||||
int diff; // Different
|
||||
|
||||
|
||||
PDFIO_DEBUG("pdfioStringCreate(pdf=%p, s=\"%s\")\n", pdf, s);
|
||||
PDFIO_DEBUG("pdfioStringCreate(pdf=%p, s=\"%s\")\n", (void *)pdf, s);
|
||||
|
||||
// Range check input...
|
||||
if (!pdf || !s)
|
||||
@@ -480,6 +827,29 @@ pdfioStringCreatef(
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioStringFreeBuffer()' - Free a string buffer.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioStringFreeBuffer(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
char *buffer) // I - String buffer
|
||||
{
|
||||
_pdfio_strbuf_t *current; // Current string buffer
|
||||
|
||||
|
||||
for (current = pdf->strbuffers; current; current = current->next)
|
||||
{
|
||||
if (current->buffer == buffer)
|
||||
{
|
||||
current->bufused = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioStringIsAllocated()' - Check whether a string has been allocated.
|
||||
//
|
||||
@@ -501,6 +871,36 @@ _pdfioStringIsAllocated(
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioStringPrintf()' - Append a formatted string to a string buffer.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
_pdfioStringPrintf(
|
||||
_pdfio_strbuf_t *bptr, // I - String buffer
|
||||
const char *format, // I - Format string
|
||||
...) // I - Additional arguments as needed
|
||||
{
|
||||
va_list ap; // Pointer to additional arguments
|
||||
size_t remaining; // Remaining bytes
|
||||
ssize_t bytes; // Formatted bytes
|
||||
|
||||
|
||||
// Format the string in the buffer...
|
||||
va_start(ap, format);
|
||||
|
||||
remaining = sizeof(bptr->buffer) - (size_t)(bptr->bufptr - bptr->buffer);
|
||||
bytes = _pdfio_vsnprintf(bptr->pdf, bptr->bufptr, remaining, format, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
// Advance the current position in the buffer and return.
|
||||
bptr->bufptr += strlen(bptr->bufptr);
|
||||
|
||||
return (bytes < (ssize_t)remaining && bytes >= 0);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'find_string()' - Find an element in the array.
|
||||
//
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF token parsing functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@@ -54,7 +54,7 @@ static int get_char(_pdfio_token_t *tb);
|
||||
void
|
||||
_pdfioTokenClear(_pdfio_token_t *tb) // I - Token buffer/stack
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioTokenClear(tb=%p)\n", tb);
|
||||
PDFIO_DEBUG("_pdfioTokenClear(tb=%p)\n", (void *)tb);
|
||||
|
||||
while (tb->num_tokens > 0)
|
||||
{
|
||||
@@ -132,7 +132,7 @@ _pdfioTokenGet(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
if ((len = strlen(tb->tokens[tb->num_tokens])) > (bufsize - 1))
|
||||
{
|
||||
// Value too large...
|
||||
PDFIO_DEBUG("_pdfioTokenGet(tb=%p, buffer=%p, bufsize=%u): Token '%s' from stack too large.\n", tb, buffer, (unsigned)bufsize, tb->tokens[tb->num_tokens]);
|
||||
PDFIO_DEBUG("_pdfioTokenGet(tb=%p, buffer=%p, bufsize=%u): Token '%s' from stack too large.\n", (void *)tb, (void *)buffer, (unsigned)bufsize, tb->tokens[tb->num_tokens]);
|
||||
*buffer = '\0';
|
||||
return (false);
|
||||
}
|
||||
@@ -140,7 +140,7 @@ _pdfioTokenGet(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
memcpy(buffer, tb->tokens[tb->num_tokens], len);
|
||||
buffer[len] = '\0';
|
||||
|
||||
PDFIO_DEBUG("_pdfioTokenGet(tb=%p, buffer=%p, bufsize=%u): Popping '%s' from stack.\n", tb, buffer, (unsigned)bufsize, buffer);
|
||||
PDFIO_DEBUG("_pdfioTokenGet(tb=%p, buffer=%p, bufsize=%u): Popping '%s' from stack.\n", (void *)tb, (void *)buffer, (unsigned)bufsize, buffer);
|
||||
|
||||
free(tb->tokens[tb->num_tokens]);
|
||||
tb->tokens[tb->num_tokens] = NULL;
|
||||
@@ -380,7 +380,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
else
|
||||
{
|
||||
// Out of space
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
_pdfioFileError(tb->pdf, "String token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
@@ -393,9 +393,18 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (saw_nul)
|
||||
if ((bufptr - buffer) > 3 && ((bufptr - buffer) & 1) != 0 && (!memcmp(buffer, "(\377\376", 3) || !memcmp(buffer, "(\376\377", 3)))
|
||||
{
|
||||
// UTF-16 string, convert to UTF-8...
|
||||
PDFIO_DEBUG("_pdfioTokenRead: Converting string to UTF-8.\n", stderr);
|
||||
_pdfio_utf16cpy(buffer + 1, (unsigned char *)buffer + 1, (size_t)(bufptr - buffer - 1), bufsize - 1);
|
||||
|
||||
PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
||||
return (true);
|
||||
}
|
||||
else if (saw_nul)
|
||||
{
|
||||
// Convert to a hex (binary) string...
|
||||
// Contains nul characters, convert to a hex (binary) string...
|
||||
char *litptr, // Pointer to literal character
|
||||
*hexptr; // Pointer to hex character
|
||||
size_t bytes = (size_t)(bufptr - buffer - 1);
|
||||
@@ -408,7 +417,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
if ((2 * (bytes + 1)) > bufsize)
|
||||
{
|
||||
// Out of space...
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
_pdfioFileError(tb->pdf, "Binary string token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
@@ -442,7 +451,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
else
|
||||
{
|
||||
// Out of space...
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
_pdfioFileError(tb->pdf, "Keyword token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
@@ -474,7 +483,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
else
|
||||
{
|
||||
// Out of space...
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
_pdfioFileError(tb->pdf, "Number token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
@@ -523,18 +532,11 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
else
|
||||
{
|
||||
// Out of space
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
_pdfioFileError(tb->pdf, "Name token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
if (bufptr == (buffer + 1))
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Empty name.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
break;
|
||||
|
||||
case '<' : // Potential hex string
|
||||
@@ -573,7 +575,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
else
|
||||
{
|
||||
// Too large
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
_pdfioFileError(tb->pdf, "Hex string token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
|
||||
404
pdfio-value.c
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF value 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
|
||||
// information.
|
||||
@@ -46,7 +46,7 @@ _pdfioValueCopy(pdfio_file_t *pdfdst, // I - Destination PDF file
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioValueCopy(pdfdst=%p, vdst=%p, pdfsrc=%p, vsrc=%p(%s))\n", pdfdst, vdst, pdfsrc, vsrc, types[vsrc->type]);
|
||||
PDFIO_DEBUG("_pdfioValueCopy(pdfdst=%p, vdst=%p, pdfsrc=%p, vsrc=%p(%s))\n", (void *)pdfdst, (void *)vdst, (void *)pdfsrc, (void *)vsrc, types[vsrc->type]);
|
||||
|
||||
if (pdfdst == pdfsrc && vsrc->type != PDFIO_VALTYPE_BINARY)
|
||||
{
|
||||
@@ -76,7 +76,8 @@ _pdfioValueCopy(pdfio_file_t *pdfdst, // I - Destination PDF file
|
||||
return (NULL);
|
||||
|
||||
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;
|
||||
|
||||
case PDFIO_VALTYPE_BINARY :
|
||||
@@ -97,12 +98,14 @@ _pdfioValueCopy(pdfio_file_t *pdfdst, // I - Destination PDF file
|
||||
return (vdst);
|
||||
|
||||
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;
|
||||
|
||||
case PDFIO_VALTYPE_NAME :
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -125,7 +128,7 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfio_crypto_ctx_t ctx; // Decryption context
|
||||
_pdfio_crypto_cb_t cb; // Decryption callback
|
||||
size_t ivlen; // Number of initialization vector bytes
|
||||
uint8_t temp[32768]; // Temporary buffer for decryption
|
||||
uint8_t *temp = NULL; // Temporary buffer for decryption
|
||||
size_t templen; // Number of actual data bytes
|
||||
time_t timeval; // Date/time value
|
||||
|
||||
@@ -152,11 +155,16 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
case PDFIO_VALTYPE_BINARY :
|
||||
// Decrypt the binary string...
|
||||
if (v->value.binary.datalen > (sizeof(temp) - 32))
|
||||
if (v->value.binary.datalen > PDFIO_MAX_STRING)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted binary string - too long.");
|
||||
return (false);
|
||||
}
|
||||
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf, /*bptr*/NULL)) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted binary string - out of memory.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
ivlen = v->value.binary.datalen;
|
||||
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL)
|
||||
@@ -167,29 +175,59 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||
// Copy the decrypted string back to the value and adjust the length...
|
||||
memcpy(v->value.binary.data, temp, templen);
|
||||
|
||||
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128)
|
||||
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128 && temp[templen - 1] <= templen)
|
||||
v->value.binary.datalen = templen - temp[templen - 1];
|
||||
else
|
||||
v->value.binary.datalen = templen;
|
||||
|
||||
_pdfioStringFreeBuffer(pdf, (char *)temp);
|
||||
break;
|
||||
|
||||
case PDFIO_VALTYPE_STRING :
|
||||
// Decrypt regular string...
|
||||
templen = strlen(v->value.string);
|
||||
if (templen > (sizeof(temp) - 33))
|
||||
if (templen > (PDFIO_MAX_STRING - 1))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted string - too long.");
|
||||
return (false);
|
||||
}
|
||||
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf, /*bptr*/NULL)) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted binary string - out of memory.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
ivlen = templen;
|
||||
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, (uint8_t *)v->value.string, &ivlen)) == NULL)
|
||||
return (false);
|
||||
|
||||
templen = (cb)(&ctx, temp, (uint8_t *)v->value.string + ivlen, templen - ivlen);
|
||||
|
||||
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128 && temp[templen - 1] <= templen)
|
||||
templen -= temp[templen - 1];
|
||||
|
||||
temp[templen] = '\0';
|
||||
|
||||
if ((timeval = get_date_time((char *)temp)) != 0)
|
||||
if ((templen & 1) == 0 && (!memcmp(temp, "\376\377", 2) || !memcmp(temp, "\377\376", 2)))
|
||||
{
|
||||
// Convert UTF-16 to UTF-8...
|
||||
char utf8[4096]; // Temporary string
|
||||
|
||||
_pdfio_utf16cpy(utf8, temp, templen, sizeof(utf8));
|
||||
|
||||
if ((timeval = get_date_time((char *)utf8)) != 0)
|
||||
{
|
||||
// Change the type to date...
|
||||
v->type = PDFIO_VALTYPE_DATE;
|
||||
v->value.date = timeval;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the decrypted string back to the value...
|
||||
v->value.string = pdfioStringCreate(pdf, utf8);
|
||||
}
|
||||
}
|
||||
else if ((timeval = get_date_time((char *)temp)) != 0)
|
||||
{
|
||||
// Change the type to date...
|
||||
v->type = PDFIO_VALTYPE_DATE;
|
||||
@@ -200,6 +238,8 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||
// Copy the decrypted string back to the value...
|
||||
v->value.string = pdfioStringCreate(pdf, (char *)temp);
|
||||
}
|
||||
|
||||
_pdfioStringFreeBuffer(pdf, (char *)temp);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -300,7 +340,9 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfio_value_t *v, // I - Value
|
||||
size_t depth) // I - Depth of value
|
||||
{
|
||||
char token[32768]; // Token buffer
|
||||
_pdfio_value_t *ret = NULL; // Return value
|
||||
char *token = _pdfioStringAllocBuffer(pdf, /*bptr*/NULL);
|
||||
// Token buffer
|
||||
time_t timeval; // Date/time value
|
||||
#ifdef DEBUG
|
||||
static const char * const valtypes[] =
|
||||
@@ -320,10 +362,13 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioValueRead(pdf=%p, obj=%p, v=%p)\n", pdf, obj, v);
|
||||
PDFIO_DEBUG("_pdfioValueRead(pdf=%p, obj=%p, v=%p)\n", (void *)pdf, (void *)obj, (void *)v);
|
||||
|
||||
if (!_pdfioTokenGet(tb, token, sizeof(token)))
|
||||
return (NULL);
|
||||
if (!token)
|
||||
goto done;
|
||||
|
||||
if (!_pdfioTokenGet(tb, token, PDFIO_MAX_STRING))
|
||||
goto done;
|
||||
|
||||
if (!strcmp(token, "["))
|
||||
{
|
||||
@@ -331,12 +376,14 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
if (depth >= PDFIO_MAX_DEPTH)
|
||||
{
|
||||
_pdfioFileError(pdf, "Too many nested arrays.");
|
||||
return (NULL);
|
||||
goto done;
|
||||
}
|
||||
|
||||
v->type = PDFIO_VALTYPE_ARRAY;
|
||||
if ((v->value.array = _pdfioArrayRead(pdf, obj, tb, depth + 1)) == NULL)
|
||||
return (NULL);
|
||||
goto done;
|
||||
|
||||
ret = v;
|
||||
}
|
||||
else if (!strcmp(token, "<<"))
|
||||
{
|
||||
@@ -344,29 +391,38 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
if (depth >= PDFIO_MAX_DEPTH)
|
||||
{
|
||||
_pdfioFileError(pdf, "Too many nested dictionaries.");
|
||||
return (NULL);
|
||||
goto done;
|
||||
}
|
||||
|
||||
v->type = PDFIO_VALTYPE_DICT;
|
||||
if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
else if (!strncmp(token, "(D:", 3) && (timeval = get_date_time(token + 1)) != 0)
|
||||
{
|
||||
v->type = PDFIO_VALTYPE_DATE;
|
||||
v->value.date = timeval;
|
||||
goto done;
|
||||
|
||||
ret = v;
|
||||
}
|
||||
else if (token[0] == '(')
|
||||
{
|
||||
// String
|
||||
v->type = PDFIO_VALTYPE_STRING;
|
||||
v->value.string = pdfioStringCreate(pdf, token + 1);
|
||||
if ((timeval = get_date_time(token + 1)) != 0)
|
||||
{
|
||||
// Date
|
||||
v->type = PDFIO_VALTYPE_DATE;
|
||||
v->value.date = timeval;
|
||||
ret = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
// String
|
||||
v->type = PDFIO_VALTYPE_STRING;
|
||||
v->value.string = pdfioStringCreate(pdf, token + 1);
|
||||
ret = v;
|
||||
}
|
||||
}
|
||||
else if (token[0] == '/')
|
||||
{
|
||||
// Name
|
||||
v->type = PDFIO_VALTYPE_NAME;
|
||||
v->value.name = pdfioStringCreate(pdf, token + 1);
|
||||
ret = v;
|
||||
}
|
||||
else if (token[0] == '<')
|
||||
{
|
||||
@@ -379,7 +435,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
if ((v->value.binary.data = (unsigned char *)malloc(v->value.binary.datalen)) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Out of memory for hex string.");
|
||||
return (NULL);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Convert hex to binary...
|
||||
@@ -406,6 +462,8 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
*dataptr++ = (unsigned char)d;
|
||||
}
|
||||
|
||||
ret = v;
|
||||
}
|
||||
else if (strchr("0123456789-+.", token[0]) != NULL)
|
||||
{
|
||||
@@ -460,7 +518,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
// Integer...
|
||||
long generation = 0; // Generation number
|
||||
|
||||
while (tempptr < tb->bufend && isdigit(*tempptr & 255))
|
||||
while (tempptr < tb->bufend && generation < 65536 && isdigit(*tempptr & 255))
|
||||
{
|
||||
generation = generation * 10 + *tempptr - '0';
|
||||
tempptr ++;
|
||||
@@ -493,7 +551,8 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
PDFIO_DEBUG("_pdfioValueRead: Returning indirect value %lu %u R.\n", (unsigned long)v->value.indirect.number, v->value.indirect.generation);
|
||||
|
||||
return (v);
|
||||
ret = v;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -501,27 +560,41 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
// If we get here, we have a number...
|
||||
v->type = PDFIO_VALTYPE_NUMBER;
|
||||
v->value.number = _pdfio_strtod(pdf, token);
|
||||
ret = v;
|
||||
}
|
||||
else if (!strcmp(token, "true") || !strcmp(token, "false"))
|
||||
{
|
||||
// Boolean value
|
||||
v->type = PDFIO_VALTYPE_BOOLEAN;
|
||||
v->value.boolean = !strcmp(token, "true");
|
||||
ret = v;
|
||||
}
|
||||
else if (!strcmp(token, "null"))
|
||||
{
|
||||
// null value
|
||||
v->type = PDFIO_VALTYPE_NULL;
|
||||
ret = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
_pdfioFileError(pdf, "Unexpected '%s' token seen.", token);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioValueRead: Returning %s value.\n", valtypes[v->type]);
|
||||
done:
|
||||
|
||||
return (v);
|
||||
if (token)
|
||||
_pdfioStringFreeBuffer(pdf, token);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioValueRead: Returning %s value.\n", valtypes[ret->type]);
|
||||
return (ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioValueRead: Returning NULL.\n");
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -530,10 +603,12 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
_pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
pdfio_obj_t *obj, // I - Object, if any
|
||||
_pdfio_value_t *v, // I - Value
|
||||
off_t *length)// O - Offset to /Length value, if any
|
||||
_pdfioValueWrite(
|
||||
_pdfio_printf_t cb, // I - Printf callback function
|
||||
void *cbdata, // I - Printf callback data
|
||||
pdfio_obj_t *obj, // I - Object, if any
|
||||
_pdfio_value_t *v, // I - Value
|
||||
off_t *length) // O - Offset to /Length value, if any
|
||||
{
|
||||
switch (v->type)
|
||||
{
|
||||
@@ -541,29 +616,36 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
return (false);
|
||||
|
||||
case PDFIO_VALTYPE_ARRAY :
|
||||
return (_pdfioArrayWrite(v->value.array, obj));
|
||||
return (_pdfioArrayWrite(cb, cbdata, obj, v->value.array));
|
||||
|
||||
case PDFIO_VALTYPE_BINARY :
|
||||
{
|
||||
size_t databytes; // Bytes to write
|
||||
uint8_t temp[32768], // Temporary buffer for encryption
|
||||
uint8_t *temp = NULL, // Temporary buffer for encryption
|
||||
*dataptr; // Pointer into data
|
||||
bool ret = false; // Return value
|
||||
|
||||
if (obj && pdf->encryption)
|
||||
|
||||
if (obj && obj->pdf->encryption)
|
||||
{
|
||||
// Write encrypted string...
|
||||
_pdfio_crypto_ctx_t ctx; // Encryption context
|
||||
_pdfio_crypto_cb_t cb; // Encryption callback
|
||||
_pdfio_crypto_cb_t ccb; // Encryption callback
|
||||
size_t ivlen; // Number of initialization vector bytes
|
||||
|
||||
if (v->value.binary.datalen > (sizeof(temp) - 32))
|
||||
if (v->value.binary.datalen > PDFIO_MAX_STRING)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to write encrypted binary string - too long.");
|
||||
_pdfioFileError(obj->pdf, "Unable to write encrypted binary string - too long.");
|
||||
return (false);
|
||||
}
|
||||
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(obj->pdf, /*bptr*/NULL)) == NULL)
|
||||
{
|
||||
_pdfioFileError(obj->pdf, "Unable to write encrypted binary string - out of memory.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
|
||||
databytes = (cb)(&ctx, temp + ivlen, v->value.binary.data, v->value.binary.datalen) + ivlen;
|
||||
ccb = _pdfioCryptoMakeWriter(obj->pdf, obj, &ctx, temp, &ivlen);
|
||||
databytes = (ccb)(&ctx, temp + ivlen, v->value.binary.data, v->value.binary.datalen) + ivlen;
|
||||
dataptr = temp;
|
||||
}
|
||||
else
|
||||
@@ -572,26 +654,33 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
databytes = v->value.binary.datalen;
|
||||
}
|
||||
|
||||
if (!_pdfioFilePuts(pdf, "<"))
|
||||
return (false);
|
||||
if (!(cb)(cbdata, "<"))
|
||||
goto bindone;
|
||||
|
||||
for (; databytes > 1; databytes -= 2, dataptr += 2)
|
||||
{
|
||||
if (!_pdfioFilePrintf(pdf, "%02X%02X", dataptr[0], dataptr[1]))
|
||||
return (false);
|
||||
if (!(cb)(cbdata, "%02X%02X", dataptr[0], dataptr[1]))
|
||||
goto bindone;
|
||||
}
|
||||
|
||||
if (databytes > 0)
|
||||
return (_pdfioFilePrintf(pdf, "%02X>", dataptr[0]));
|
||||
else
|
||||
return (_pdfioFilePuts(pdf, ">"));
|
||||
if (databytes > 0 && !(cb)(cbdata, "%02X", dataptr[0]))
|
||||
goto bindone;
|
||||
|
||||
ret = (cb)(cbdata, ">");
|
||||
|
||||
bindone:
|
||||
|
||||
if (temp)
|
||||
_pdfioStringFreeBuffer(obj->pdf, (char *)temp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
case PDFIO_VALTYPE_BOOLEAN :
|
||||
if (v->value.boolean)
|
||||
return (_pdfioFilePuts(pdf, " true"));
|
||||
return ((cb)(cbdata, " true"));
|
||||
else
|
||||
return (_pdfioFilePuts(pdf, " false"));
|
||||
return ((cb)(cbdata, " false"));
|
||||
|
||||
case PDFIO_VALTYPE_DATE :
|
||||
{
|
||||
@@ -606,136 +695,108 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
snprintf(datestr, sizeof(datestr), "D:%04d%02d%02d%02d%02d%02dZ", date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, date.tm_hour, date.tm_min, date.tm_sec);
|
||||
|
||||
if (obj && pdf->encryption)
|
||||
if (obj && obj->pdf->encryption)
|
||||
{
|
||||
// Write encrypted string...
|
||||
uint8_t temp[32768], // Encrypted bytes
|
||||
uint8_t temp[64], // Encrypted bytes
|
||||
*tempptr; // Pointer into encrypted bytes
|
||||
_pdfio_crypto_ctx_t ctx; // Encryption context
|
||||
_pdfio_crypto_cb_t cb; // Encryption callback
|
||||
_pdfio_crypto_cb_t ccb; // Encryption callback
|
||||
size_t len = strlen(datestr),
|
||||
// Length of value
|
||||
ivlen, // Number of initialization vector bytes
|
||||
tempbytes; // Number of output bytes
|
||||
|
||||
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
|
||||
tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)datestr, len) + ivlen;
|
||||
ccb = _pdfioCryptoMakeWriter(obj->pdf, obj, &ctx, temp, &ivlen);
|
||||
tempbytes = (ccb)(&ctx, temp + ivlen, (const uint8_t *)datestr, len) + ivlen;
|
||||
|
||||
if (!_pdfioFilePuts(pdf, "<"))
|
||||
if (!(cb)(cbdata, "<"))
|
||||
return (false);
|
||||
|
||||
for (tempptr = temp; tempbytes > 1; tempbytes -= 2, tempptr += 2)
|
||||
{
|
||||
if (!_pdfioFilePrintf(pdf, "%02X%02X", tempptr[0], tempptr[1]))
|
||||
if (!(cb)(cbdata, "%02X%02X", tempptr[0], tempptr[1]))
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (tempbytes > 0)
|
||||
return (_pdfioFilePrintf(pdf, "%02X>", *tempptr));
|
||||
return ((cb)(cbdata, "%02X>", *tempptr));
|
||||
else
|
||||
return (_pdfioFilePuts(pdf, ">"));
|
||||
return ((cb)(cbdata, ">"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (_pdfioFilePrintf(pdf, "(%s)", datestr));
|
||||
return ((cb)(cbdata, "%S", datestr));
|
||||
}
|
||||
}
|
||||
|
||||
case PDFIO_VALTYPE_DICT :
|
||||
return (_pdfioDictWrite(v->value.dict, obj, length));
|
||||
return (_pdfioDictWrite(cb, cbdata, obj, v->value.dict, length));
|
||||
|
||||
case PDFIO_VALTYPE_INDIRECT :
|
||||
return (_pdfioFilePrintf(pdf, " %lu %u R", (unsigned long)v->value.indirect.number, v->value.indirect.generation));
|
||||
return ((cb)(cbdata, " %lu %u R", (unsigned long)v->value.indirect.number, v->value.indirect.generation));
|
||||
|
||||
case PDFIO_VALTYPE_NAME :
|
||||
return (_pdfioFilePrintf(pdf, "/%s", v->value.name));
|
||||
return ((cb)(cbdata, "%N", v->value.name));
|
||||
|
||||
case PDFIO_VALTYPE_NULL :
|
||||
return (_pdfioFilePuts(pdf, " null"));
|
||||
return ((cb)(cbdata, " null"));
|
||||
|
||||
case PDFIO_VALTYPE_NUMBER :
|
||||
return (_pdfioFilePrintf(pdf, " %g", v->value.number));
|
||||
return ((cb)(cbdata, " %.6f", v->value.number));
|
||||
|
||||
case PDFIO_VALTYPE_STRING :
|
||||
if (obj && pdf->encryption)
|
||||
if (obj && obj->pdf->encryption)
|
||||
{
|
||||
// Write encrypted string...
|
||||
uint8_t temp[32768], // Encrypted bytes
|
||||
uint8_t *temp = NULL, // Encrypted bytes
|
||||
*tempptr; // Pointer into encrypted bytes
|
||||
_pdfio_crypto_ctx_t ctx; // Encryption context
|
||||
_pdfio_crypto_cb_t cb; // Encryption callback
|
||||
_pdfio_crypto_cb_t ccb; // Encryption callback
|
||||
size_t len = strlen(v->value.string),
|
||||
// Length of value
|
||||
ivlen, // Number of initialization vector bytes
|
||||
tempbytes; // Number of output bytes
|
||||
bool ret = false; // Return value
|
||||
|
||||
if (len > (sizeof(temp) - 32))
|
||||
if (len > PDFIO_MAX_STRING)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to write encrypted string - too long.");
|
||||
_pdfioFileError(obj->pdf, "Unable to write encrypted string - too long.");
|
||||
return (false);
|
||||
}
|
||||
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(obj->pdf, /*bptr*/NULL)) == NULL)
|
||||
{
|
||||
_pdfioFileError(obj->pdf, "Unable to write encrypted string - out of memory.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
|
||||
tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)v->value.string, len) + ivlen;
|
||||
ccb = _pdfioCryptoMakeWriter(obj->pdf, obj, &ctx, temp, &ivlen);
|
||||
tempbytes = (ccb)(&ctx, temp + ivlen, (const uint8_t *)v->value.string, len) + ivlen;
|
||||
|
||||
if (!_pdfioFilePuts(pdf, "<"))
|
||||
return (false);
|
||||
if (!(cb)(cbdata, "<"))
|
||||
goto strdone;
|
||||
|
||||
for (tempptr = temp; tempbytes > 1; tempbytes -= 2, tempptr += 2)
|
||||
{
|
||||
if (!_pdfioFilePrintf(pdf, "%02X%02X", tempptr[0], tempptr[1]))
|
||||
return (false);
|
||||
if (!(cb)(cbdata, "%02X%02X", tempptr[0], tempptr[1]))
|
||||
goto strdone;
|
||||
}
|
||||
|
||||
if (tempbytes > 0)
|
||||
return (_pdfioFilePrintf(pdf, "%02X>", *tempptr));
|
||||
else
|
||||
return (_pdfioFilePuts(pdf, ">"));
|
||||
if (tempbytes > 0 && !(cb)(cbdata, "%02X", *tempptr))
|
||||
goto strdone;
|
||||
|
||||
ret = (cb)(cbdata, ">");
|
||||
|
||||
strdone :
|
||||
|
||||
_pdfioStringFreeBuffer(obj->pdf, (char *)temp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write unencrypted string...
|
||||
const char *start, // Start of fragment
|
||||
*end; // End of fragment
|
||||
|
||||
if (!_pdfioFilePuts(pdf, "("))
|
||||
return (false);
|
||||
|
||||
// Write a quoted string value...
|
||||
for (start = v->value.string; *start; start = end)
|
||||
{
|
||||
// Find the next character that needs to be quoted...
|
||||
for (end = start; *end; end ++)
|
||||
{
|
||||
if (*end == '\\' || *end == ')' || (*end & 255) < ' ')
|
||||
break;
|
||||
}
|
||||
|
||||
if (end > start)
|
||||
{
|
||||
// Write unquoted (safe) characters...
|
||||
if (!_pdfioFileWrite(pdf, start, (size_t)(end - start)))
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (*end)
|
||||
{
|
||||
// Quote this character...
|
||||
bool success; // Did the write work?
|
||||
|
||||
if (*end == '\\' || *end == ')')
|
||||
success = _pdfioFilePrintf(pdf, "\\%c", *end);
|
||||
else
|
||||
success = _pdfioFilePrintf(pdf, "\\%03o", *end);
|
||||
|
||||
if (!success)
|
||||
return (false);
|
||||
|
||||
end ++;
|
||||
}
|
||||
}
|
||||
|
||||
return (_pdfioFilePuts(pdf, ")"));
|
||||
return ((cb)(cbdata, "%S", v->value.string));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,31 +808,59 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
// 'get_date_time()' - Convert PDF date/time value to time_t.
|
||||
//
|
||||
|
||||
static time_t // O - Time in seconds
|
||||
static time_t // O - Time in seconds or `0` for none
|
||||
get_date_time(const char *s) // I - PDF date/time value
|
||||
{
|
||||
int i; // Looping var
|
||||
struct tm dateval; // Date value
|
||||
int offset; // Date offset
|
||||
int offset = 0; // Date offset in seconds
|
||||
time_t t; // Time value
|
||||
|
||||
|
||||
PDFIO_DEBUG("get_date_time(s=\"%s\")\n", s);
|
||||
|
||||
// Possible date value of the form:
|
||||
//
|
||||
// (D:YYYYMMDDhhmmssZ)
|
||||
// (D:YYYYMMDDhhmmss+HH'mm)
|
||||
// (D:YYYYMMDDhhmmss-HH'mm)
|
||||
// D:YYYYMMDDhhmmssZ
|
||||
// D:YYYYMMDDhhmmss+HH'mm
|
||||
// D:YYYYMMDDhhmmss-HH'mm
|
||||
//
|
||||
|
||||
if (strncmp(s, "D:", 2))
|
||||
return (0);
|
||||
|
||||
for (i = 2; i < 16; i ++)
|
||||
{
|
||||
// Look for date/time digits...
|
||||
if (!isdigit(s[i] & 255) || !s[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= 16)
|
||||
if (i < 6 || (i & 1))
|
||||
{
|
||||
// Short year or missing digit...
|
||||
return (0);
|
||||
}
|
||||
|
||||
memset(&dateval, 0, sizeof(dateval));
|
||||
|
||||
dateval.tm_year = (s[2] - '0') * 1000 + (s[3] - '0') * 100 + (s[4] - '0') * 10 + s[5] - '0' - 1900;
|
||||
if (i > 6)
|
||||
dateval.tm_mon = (s[6] - '0') * 10 + s[7] - '0' - 1;
|
||||
if (i > 8)
|
||||
dateval.tm_mday = (s[8] - '0') * 10 + s[9] - '0';
|
||||
else
|
||||
dateval.tm_mday = 1;
|
||||
if (i > 10)
|
||||
dateval.tm_hour = (s[10] - '0') * 10 + s[11] - '0';
|
||||
if (i > 12)
|
||||
dateval.tm_min = (s[12] - '0') * 10 + s[13] - '0';
|
||||
if (i > 14)
|
||||
dateval.tm_sec = (s[14] - '0') * 10 + s[15] - '0';
|
||||
|
||||
if (i >= 16 && s[i])
|
||||
{
|
||||
// Get zone info...
|
||||
if (s[i] == 'Z')
|
||||
{
|
||||
// UTC...
|
||||
@@ -782,14 +871,20 @@ get_date_time(const char *s) // I - PDF date/time value
|
||||
// Timezone offset from UTC...
|
||||
if (isdigit(s[i + 1] & 255) && isdigit(s[i + 2] & 255) && s[i + 3] == '\'' && isdigit(s[i + 4] & 255) && isdigit(s[i + 5] & 255))
|
||||
{
|
||||
offset = (s[i + 1] - '0') * 36000 + (s[i + 2] - '0') * 3600 + (s[i + 4] - '0') * 600 + (s[i + 5] - '0') * 60;
|
||||
if (s[i] == '-')
|
||||
offset = -offset;
|
||||
|
||||
i += 6;
|
||||
|
||||
// Accept trailing quote, per PDF spec...
|
||||
if (s[i] == '\'')
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
else if (!s[i])
|
||||
else
|
||||
{
|
||||
// Missing zone info, invalid date string...
|
||||
// Random zone info, invalid date string...
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
@@ -800,26 +895,31 @@ get_date_time(const char *s) // I - PDF date/time value
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Date value...
|
||||
memset(&dateval, 0, sizeof(dateval));
|
||||
// Convert date value to time_t...
|
||||
#if _WIN32
|
||||
if ((t = _mkgmtime(&dateval)) <= 0)
|
||||
return (0);
|
||||
|
||||
dateval.tm_year = (s[2] - '0') * 1000 + (s[3] - '0') * 100 + (s[4] - '0') * 10 + s[5] - '0' - 1900;
|
||||
dateval.tm_mon = (s[6] - '0') * 10 + s[7] - '0' - 1;
|
||||
dateval.tm_mday = (s[8] - '0') * 10 + s[9] - '0';
|
||||
dateval.tm_hour = (s[10] - '0') * 10 + s[11] - '0';
|
||||
dateval.tm_min = (s[12] - '0') * 10 + s[13] - '0';
|
||||
dateval.tm_sec = (s[14] - '0') * 10 + s[15] - '0';
|
||||
#elif defined(HAVE_TIMEGM)
|
||||
if ((t = timegm(&dateval)) <= 0)
|
||||
return (0);
|
||||
|
||||
if (s[16] == 'Z')
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = (s[17] - '0') * 600 + (s[18] - '0') * 60 + (s[19] - '0') * 10 + s[20] - '0';
|
||||
if (s[16] == '-')
|
||||
offset = -offset;
|
||||
}
|
||||
#else
|
||||
if ((t = mktime(&dateval)) <= 0)
|
||||
return (0);
|
||||
|
||||
return (mktime(&dateval) + offset);
|
||||
# if defined(HAVE_TM_GMTOFF)
|
||||
// Adjust the time value using the "tm_gmtoff" and "tm_isdst" members. As
|
||||
// noted by M-HT on Github, this DST hack will fail in timezones where the
|
||||
// DST offset is not one hour, such as Australia/Lord_Howe. Fortunately,
|
||||
// this is unusual and most systems support the "timegm" function...
|
||||
t += dateval.tm_gmtoff - 3600 * dateval.tm_isdst;
|
||||
# else
|
||||
// Adjust the time value using the even more legacy "timezone" variable,
|
||||
// which also reflects any DST offset...
|
||||
t += timezone;
|
||||
# endif // HAVE_TM_GMTOFF
|
||||
#endif // _WIN32
|
||||
|
||||
return (t - offset);
|
||||
}
|
||||
|
||||
34
pdfio.h
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// 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
|
||||
// information.
|
||||
@@ -23,9 +23,9 @@ extern "C" {
|
||||
// Version numbers...
|
||||
//
|
||||
|
||||
# define PDFIO_VERSION "1.5.0"
|
||||
# define PDFIO_VERSION "1.7.0"
|
||||
# define PDFIO_VERSION_MAJOR 1
|
||||
# define PDFIO_VERSION_MINOR 5
|
||||
# define PDFIO_VERSION_MINOR 7
|
||||
|
||||
|
||||
//
|
||||
@@ -34,11 +34,9 @@ extern "C" {
|
||||
|
||||
# if defined(__has_extension) || defined(__GNUC__)
|
||||
# define _PDFIO_PUBLIC __attribute__ ((visibility("default")))
|
||||
# define _PDFIO_FORMAT(a,b) __attribute__ ((__format__(__printf__, a,b)))
|
||||
# define _PDFIO_DEPRECATED __attribute__ ((deprecated)) _PDFIO_PUBLIC
|
||||
# else
|
||||
# define _PDFIO_PUBLIC
|
||||
# define _PDFIO_FORMAT(a,b)
|
||||
# define _PDFIO_DEPRECATED
|
||||
# endif // __has_extension || __GNUC__
|
||||
|
||||
@@ -48,7 +46,7 @@ extern "C" {
|
||||
//
|
||||
|
||||
# if _WIN32
|
||||
typedef __int64 ssize_t; // POSIX type not present on Windows... @private@
|
||||
typedef __int64 ssize_t; // POSIX type not present on Windows @private@
|
||||
# endif // _WIN32
|
||||
|
||||
typedef struct _pdfio_array_s pdfio_array_t;
|
||||
@@ -64,7 +62,7 @@ typedef bool (*pdfio_error_cb_t)(pdfio_file_t *pdf, const char *message, void *d
|
||||
typedef enum pdfio_encryption_e // PDF encryption modes
|
||||
{
|
||||
PDFIO_ENCRYPTION_NONE = 0, // No encryption
|
||||
PDFIO_ENCRYPTION_RC4_40, // 40-bit RC4 encryption (PDF 1.3)
|
||||
PDFIO_ENCRYPTION_RC4_40, // 40-bit RC4 encryption (PDF 1.3, reading only)
|
||||
PDFIO_ENCRYPTION_RC4_128, // 128-bit RC4 encryption (PDF 1.4)
|
||||
PDFIO_ENCRYPTION_AES_128, // 128-bit AES encryption (PDF 1.6)
|
||||
PDFIO_ENCRYPTION_AES_256 // 256-bit AES encryption (PDF 2.0) @exclude all@
|
||||
@@ -74,11 +72,11 @@ typedef enum pdfio_filter_e // Compression/decompression filters for streams
|
||||
PDFIO_FILTER_NONE, // No filter
|
||||
PDFIO_FILTER_ASCIIHEX, // ASCIIHexDecode 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_DCT, // DCTDecode (JPEG) 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_LZW, // LZWDecode filter (reading only)
|
||||
PDFIO_FILTER_RUNLENGTH, // RunLengthDecode filter (reading only)
|
||||
@@ -183,7 +181,7 @@ extern bool pdfioDictSetNumber(pdfio_dict_t *dict, const char *key, double valu
|
||||
extern bool pdfioDictSetObj(pdfio_dict_t *dict, const char *key, pdfio_obj_t *value) _PDFIO_PUBLIC;
|
||||
extern bool pdfioDictSetRect(pdfio_dict_t *dict, const char *key, pdfio_rect_t *value) _PDFIO_PUBLIC;
|
||||
extern bool pdfioDictSetString(pdfio_dict_t *dict, const char *key, const char *value) _PDFIO_PUBLIC;
|
||||
extern bool pdfioDictSetStringf(pdfio_dict_t *dict, const char *key, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(3,4);
|
||||
extern bool pdfioDictSetStringf(pdfio_dict_t *dict, const char *key, const char *format, ...) _PDFIO_PUBLIC;
|
||||
|
||||
extern bool pdfioFileClose(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_file_t *pdfioFileCreate(const char *filename, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||
@@ -203,6 +201,7 @@ extern time_t pdfioFileGetCreationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetCreator(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_array_t *pdfioFileGetID(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetKeywords(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetLanguage(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern time_t pdfioFileGetModificationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetName(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioFileGetNumObjs(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
@@ -219,6 +218,7 @@ extern void pdfioFileSetAuthor(pdfio_file_t *pdf, const char *value) _PDFIO_PUB
|
||||
extern void pdfioFileSetCreationDate(pdfio_file_t *pdf, time_t value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetCreator(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetKeywords(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetLanguage(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetModificationDate(pdfio_file_t *pdf, time_t value) _PDFIO_PUBLIC;
|
||||
extern bool pdfioFileSetPermissions(pdfio_file_t *pdf, pdfio_permission_t permissions, pdfio_encryption_t encryption, const char *owner_password, const char *user_password) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetSubject(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
@@ -238,21 +238,31 @@ extern const char *pdfioObjGetType(pdfio_obj_t *obj) _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 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 pdfioPageGetDate(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 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 bool pdfioStreamClose(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamConsume(pdfio_stream_t *st, size_t bytes) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamGetToken(pdfio_stream_t *st, char *buffer, size_t bufsize) _PDFIO_PUBLIC;
|
||||
extern ssize_t pdfioStreamPeek(pdfio_stream_t *st, void *buffer, size_t bytes) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamPrintf(pdfio_stream_t *st, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(2,3);
|
||||
extern bool pdfioStreamPrintf(pdfio_stream_t *st, const char *format, ...) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamPutChar(pdfio_stream_t *st, int ch) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamPuts(pdfio_stream_t *st, const char *s) _PDFIO_PUBLIC;
|
||||
extern ssize_t pdfioStreamRead(pdfio_stream_t *st, void *buffer, size_t bytes) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamWrite(pdfio_stream_t *st, const void *buffer, size_t bytes) _PDFIO_PUBLIC;
|
||||
|
||||
extern char *pdfioStringCreate(pdfio_file_t *pdf, const char *s) _PDFIO_PUBLIC;
|
||||
extern char *pdfioStringCreatef(pdfio_file_t *pdf, const char *format, ...) _PDFIO_FORMAT(2,3) _PDFIO_PUBLIC;
|
||||
extern char *pdfioStringCreatef(pdfio_file_t *pdf, const char *format, ...) _PDFIO_PUBLIC;
|
||||
|
||||
|
||||
# ifdef __cplusplus
|
||||
|
||||
@@ -11,3 +11,4 @@ Cflags: @PKGCONFIG_CFLAGS@
|
||||
Libs: @PKGCONFIG_LIBS@
|
||||
Libs.private: @PKGCONFIG_LIBS_PRIVATE@
|
||||
Requires: @PKGCONFIG_REQUIRES@
|
||||
Requires.private: @PKGCONFIG_REQUIRES_PRIVATE@
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>ttf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
@@ -101,6 +102,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>ttf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
@@ -115,6 +117,7 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>ttf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>HAVE_LIBPNG;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
@@ -130,6 +133,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>ttf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>HAVE_LIBPNG;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
@@ -145,7 +149,8 @@
|
||||
<ClInclude Include="pdfio-content.h" />
|
||||
<ClInclude Include="pdfio-private.h" />
|
||||
<ClInclude Include="pdfio.h" />
|
||||
<ClInclude Include="ttf.h" />
|
||||
<ClInclude Include="ttf\ttf.h" />
|
||||
<ClInclude Include="ttf\ttf-private.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pdfio-aes.c" />
|
||||
@@ -155,6 +160,7 @@
|
||||
<ClCompile Include="pdfio-crypto.c" />
|
||||
<ClCompile Include="pdfio-dict.c" />
|
||||
<ClCompile Include="pdfio-file.c" />
|
||||
<ClCompile Include="pdfio-lzw.c" />
|
||||
<ClCompile Include="pdfio-md5.c" />
|
||||
<ClCompile Include="pdfio-object.c" />
|
||||
<ClCompile Include="pdfio-page.c" />
|
||||
@@ -164,7 +170,8 @@
|
||||
<ClCompile Include="pdfio-string.c" />
|
||||
<ClCompile Include="pdfio-token.c" />
|
||||
<ClCompile Include="pdfio-value.c" />
|
||||
<ClCompile Include="ttf.c" />
|
||||
<ClCompile Include="ttf\ttf-cache.c" />
|
||||
<ClCompile Include="ttf\ttf-file.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
||||
@@ -22,8 +22,11 @@
|
||||
273440CD263D727800FBFD63 /* pdfio-page.c in Sources */ = {isa = PBXBuildFile; fileRef = 273440C2263D727800FBFD63 /* pdfio-page.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 */; };
|
||||
279E1035267D043B00D3A349 /* ttf.h in Headers */ = {isa = PBXBuildFile; fileRef = 279E1033267D043B00D3A349 /* ttf.h */; };
|
||||
279E1036267D043B00D3A349 /* ttf.c in Sources */ = {isa = PBXBuildFile; fileRef = 279E1034267D043B00D3A349 /* ttf.c */; };
|
||||
273707A52F299C3100953C95 /* pdfio-lzw.c in Sources */ = {isa = PBXBuildFile; fileRef = 273707A42F299C3100953C95 /* pdfio-lzw.c */; };
|
||||
2741C9A22F05872C002D93F2 /* ttf-cache.c in Sources */ = {isa = PBXBuildFile; fileRef = 2741C99F2F05872C002D93F2 /* ttf-cache.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 */; };
|
||||
27CF90442711DFFE00E50FE4 /* pdfio-aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 27CF90432711DFFE00E50FE4 /* pdfio-aes.c */; };
|
||||
27ECBD8926419DAB0025312A /* libpdfio.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 273440B0263D6FE200FBFD63 /* libpdfio.a */; };
|
||||
@@ -82,8 +85,11 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
279E1034267D043B00D3A349 /* ttf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ttf.c; sourceTree = "<group>"; };
|
||||
273707A42F299C3100953C95 /* pdfio-lzw.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "pdfio-lzw.c"; sourceTree = "<group>"; };
|
||||
2741C99E2F05872C002D93F2 /* ttf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ttf.h; path = ttf/ttf.h; 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; };
|
||||
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>"; };
|
||||
@@ -170,6 +176,7 @@
|
||||
27F2F05F2710BE92008ECD36 /* pdfio-crypto.c */,
|
||||
273440BE263D727800FBFD63 /* pdfio-dict.c */,
|
||||
273440BD263D727800FBFD63 /* pdfio-file.c */,
|
||||
273707A42F299C3100953C95 /* pdfio-lzw.c */,
|
||||
27F2F05D2710BE92008ECD36 /* pdfio-md5.c */,
|
||||
273440BC263D727800FBFD63 /* pdfio-object.c */,
|
||||
273440C2263D727800FBFD63 /* pdfio-page.c */,
|
||||
@@ -179,8 +186,10 @@
|
||||
273440B9263D727800FBFD63 /* pdfio-string.c */,
|
||||
273440E3263DD7EA00FBFD63 /* pdfio-token.c */,
|
||||
273440C0263D727800FBFD63 /* pdfio-value.c */,
|
||||
279E1034267D043B00D3A349 /* ttf.c */,
|
||||
279E1033267D043B00D3A349 /* ttf.h */,
|
||||
2741C99E2F05872C002D93F2 /* ttf.h */,
|
||||
2741C99F2F05872C002D93F2 /* ttf-cache.c */,
|
||||
2741C9A02F05872C002D93F2 /* ttf-file.c */,
|
||||
2741C9A12F05872C002D93F2 /* ttf-private.h */,
|
||||
);
|
||||
name = Library;
|
||||
sourceTree = "<group>";
|
||||
@@ -209,10 +218,11 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
27FCBDE42D19F9B300485EEE /* pdfio-base-font-widths.h in Headers */,
|
||||
2741C9A42F05872C002D93F2 /* ttf-private.h in Headers */,
|
||||
2741C9A52F05872C002D93F2 /* ttf.h in Headers */,
|
||||
273440CC263D727800FBFD63 /* pdfio.h in Headers */,
|
||||
271EA706265B2B1000ACDD39 /* pdfio-content.h in Headers */,
|
||||
273440C3263D727800FBFD63 /* pdfio-private.h in Headers */,
|
||||
279E1035267D043B00D3A349 /* ttf.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -261,7 +271,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1600;
|
||||
LastUpgradeCheck = 2600;
|
||||
TargetAttributes = {
|
||||
273440AF263D6FE200FBFD63 = {
|
||||
CreatedOnToolsVersion = 12.5;
|
||||
@@ -295,14 +305,16 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
279E1036267D043B00D3A349 /* ttf.c in Sources */,
|
||||
273440C9263D727800FBFD63 /* pdfio-dict.c in Sources */,
|
||||
273440C8263D727800FBFD63 /* pdfio-file.c in Sources */,
|
||||
273440CB263D727800FBFD63 /* pdfio-value.c in Sources */,
|
||||
273707A52F299C3100953C95 /* pdfio-lzw.c in Sources */,
|
||||
273440CA263D727800FBFD63 /* pdfio-stream.c in Sources */,
|
||||
273440CD263D727800FBFD63 /* pdfio-page.c in Sources */,
|
||||
27F2F0622710BE92008ECD36 /* pdfio-crypto.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 */,
|
||||
273440E4263DD7EA00FBFD63 /* pdfio-token.c in Sources */,
|
||||
273440C7263D727800FBFD63 /* pdfio-object.c in Sources */,
|
||||
@@ -353,12 +365,14 @@
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_COMPLETION_HANDLER_MISUSE = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_IMPLICIT_FALLTHROUGH = NO;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
@@ -377,7 +391,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.1.2;
|
||||
CURRENT_PROJECT_VERSION = 1.6.1;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -388,10 +402,16 @@
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"DEBUG=1",
|
||||
"HAVE_LIBPNG=1",
|
||||
"HAVE_TM_GMTOFF=1",
|
||||
"HAVE_TIMEGM=1",
|
||||
);
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = 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_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
@@ -399,16 +419,29 @@
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
/usr/local/include,
|
||||
/opt/local/include,
|
||||
/opt/homebrew/include,
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = (
|
||||
"-L/usr/local/lib",
|
||||
"-L/opt/local/lib",
|
||||
"-L/opt/homebrew/lib",
|
||||
"-lpng16",
|
||||
);
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
SDKROOT = macosx;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -432,12 +465,14 @@
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_COMPLETION_HANDLER_MISUSE = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_IMPLICIT_FALLTHROUGH = NO;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
@@ -456,7 +491,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.1.2;
|
||||
CURRENT_PROJECT_VERSION = 1.6.1;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -465,10 +500,17 @@
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"HAVE_LIBPNG=1",
|
||||
"HAVE_TM_GMTOFF=1",
|
||||
"HAVE_TIMEGM=1",
|
||||
);
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = 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_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
@@ -476,15 +518,28 @@
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
/usr/local/include,
|
||||
/opt/local/include,
|
||||
/opt/homebrew/include,
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_LDFLAGS = (
|
||||
"-L/usr/local/lib",
|
||||
"-L/opt/local/lib",
|
||||
"-L/opt/homebrew/lib",
|
||||
"-lpng16",
|
||||
);
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
SDKROOT = macosx;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
85
pdfio1.def
@@ -1,9 +1,24 @@
|
||||
LIBRARY pdfio1
|
||||
VERSION 1.5
|
||||
VERSION 1.7
|
||||
EXPORTS
|
||||
_pdfio_win32_open
|
||||
_pdfio_strlcpy
|
||||
_pdfio_strtod
|
||||
_pdfio_utf16cpy
|
||||
_pdfio_vsnprintf
|
||||
_pdfioArrayDebug
|
||||
_pdfioArrayDecrypt
|
||||
_pdfioArrayDelete
|
||||
_pdfioArrayGetValue
|
||||
_pdfioArrayRead
|
||||
_pdfioArrayWrite
|
||||
_pdfioCryptoAESDecrypt
|
||||
_pdfioCryptoAESEncrypt
|
||||
_pdfioCryptoAESInit
|
||||
_pdfioCryptoLock
|
||||
_pdfioCryptoMakeRandom
|
||||
_pdfioCryptoMakeReader
|
||||
_pdfioCryptoMakeWriter
|
||||
_pdfioCryptoMD5Append
|
||||
_pdfioCryptoMD5Finish
|
||||
_pdfioCryptoMD5Init
|
||||
@@ -12,9 +27,57 @@ _pdfioCryptoRC4Init
|
||||
_pdfioCryptoSHA256Append
|
||||
_pdfioCryptoSHA256Finish
|
||||
_pdfioCryptoSHA256Init
|
||||
_pdfioCryptoUnlock
|
||||
_pdfioDictDebug
|
||||
_pdfioDictDecrypt
|
||||
_pdfioDictDelete
|
||||
_pdfioDictGetValue
|
||||
_pdfioDictRead
|
||||
_pdfioDictSetValue
|
||||
_pdfioDictWrite
|
||||
_pdfioFileAddMappedObj
|
||||
_pdfioFileAddPage
|
||||
_pdfioFileConsume
|
||||
_pdfioFileCreateObj
|
||||
_pdfioFileDefaultError
|
||||
_pdfioFileError
|
||||
_pdfioFileFindMappedObj
|
||||
_pdfioFileFlush
|
||||
_pdfioFileGetChar
|
||||
_pdfioFileGets
|
||||
_pdfioFilePeek
|
||||
_pdfioFilePrintf
|
||||
_pdfioFilePuts
|
||||
_pdfioFileRead
|
||||
_pdfioFileSeek
|
||||
_pdfioFileTell
|
||||
_pdfioFileWrite
|
||||
_pdfioLZWCreate
|
||||
_pdfioLZWDelete
|
||||
_pdfioLZWInflate
|
||||
_pdfioObjDelete
|
||||
_pdfioObjGetExtension
|
||||
_pdfioObjLoad
|
||||
_pdfioObjSetExtension
|
||||
_pdfioObjWriteHeader
|
||||
_pdfioStreamCreate
|
||||
_pdfioStreamOpen
|
||||
_pdfioStringAllocBuffer
|
||||
_pdfioStringFreeBuffer
|
||||
_pdfioStringIsAllocated
|
||||
_pdfioStringPrintf
|
||||
_pdfioTokenClear
|
||||
_pdfioTokenFlush
|
||||
_pdfioTokenGet
|
||||
_pdfioTokenInit
|
||||
_pdfioTokenPush
|
||||
_pdfioTokenRead
|
||||
_pdfioValueCopy
|
||||
_pdfioValueDebug
|
||||
_pdfioValueDecrypt
|
||||
_pdfioValueDelete
|
||||
_pdfioValueRead
|
||||
_pdfioValueWrite
|
||||
pdfioArrayAppendArray
|
||||
pdfioArrayAppendBinary
|
||||
pdfioArrayAppendBoolean
|
||||
@@ -43,8 +106,10 @@ pdfioArrayGetSize
|
||||
pdfioArrayGetString
|
||||
pdfioArrayGetType
|
||||
pdfioArrayRemove
|
||||
pdfioContentBeginMarked
|
||||
pdfioContentClip
|
||||
pdfioContentDrawImage
|
||||
pdfioContentEndMarked
|
||||
pdfioContentFill
|
||||
pdfioContentFillAndStroke
|
||||
pdfioContentMatrixConcat
|
||||
@@ -98,8 +163,8 @@ pdfioContentTextNewLineShow
|
||||
pdfioContentTextNewLineShowf
|
||||
pdfioContentTextNextLine
|
||||
pdfioContentTextShow
|
||||
pdfioContentTextShowJustified
|
||||
pdfioContentTextShowf
|
||||
pdfioContentTextShowJustified
|
||||
pdfioDictClear
|
||||
pdfioDictCopy
|
||||
pdfioDictCreate
|
||||
@@ -110,8 +175,8 @@ pdfioDictGetDate
|
||||
pdfioDictGetDict
|
||||
pdfioDictGetKey
|
||||
pdfioDictGetName
|
||||
pdfioDictGetNumPairs
|
||||
pdfioDictGetNumber
|
||||
pdfioDictGetNumPairs
|
||||
pdfioDictGetObj
|
||||
pdfioDictGetRect
|
||||
pdfioDictGetString
|
||||
@@ -129,10 +194,12 @@ pdfioDictSetObj
|
||||
pdfioDictSetRect
|
||||
pdfioDictSetString
|
||||
pdfioDictSetStringf
|
||||
pdfioFileAddOutputIntent
|
||||
pdfioFileClose
|
||||
pdfioFileCreate
|
||||
pdfioFileCreateArrayObj
|
||||
pdfioFileCreateFontObjFromBase
|
||||
pdfioFileCreateFontObjFromData
|
||||
pdfioFileCreateFontObjFromFile
|
||||
pdfioFileCreateICCObjFromData
|
||||
pdfioFileCreateICCObjFromFile
|
||||
@@ -152,6 +219,7 @@ pdfioFileGetCreationDate
|
||||
pdfioFileGetCreator
|
||||
pdfioFileGetID
|
||||
pdfioFileGetKeywords
|
||||
pdfioFileGetLanguage
|
||||
pdfioFileGetModificationDate
|
||||
pdfioFileGetName
|
||||
pdfioFileGetNumObjs
|
||||
@@ -168,6 +236,7 @@ pdfioFileSetAuthor
|
||||
pdfioFileSetCreationDate
|
||||
pdfioFileSetCreator
|
||||
pdfioFileSetKeywords
|
||||
pdfioFileSetLanguage
|
||||
pdfioFileSetModificationDate
|
||||
pdfioFileSetPermissions
|
||||
pdfioFileSetSubject
|
||||
@@ -191,7 +260,17 @@ pdfioPageCopy
|
||||
pdfioPageDictAddColorSpace
|
||||
pdfioPageDictAddFont
|
||||
pdfioPageDictAddImage
|
||||
pdfioPageGetArray
|
||||
pdfioPageGetBinary
|
||||
pdfioPageGetBoolean
|
||||
pdfioPageGetDate
|
||||
pdfioPageGetDict
|
||||
pdfioPageGetName
|
||||
pdfioPageGetNumber
|
||||
pdfioPageGetNumStreams
|
||||
pdfioPageGetObj
|
||||
pdfioPageGetRect
|
||||
pdfioPageGetString
|
||||
pdfioPageOpenStream
|
||||
pdfioStreamClose
|
||||
pdfioStreamConsume
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.5.0</version>
|
||||
<version>1.7.0</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
@@ -16,7 +16,7 @@
|
||||
<copyright>Copyright © 2019-2025 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
<dependencies>
|
||||
<dependency id="pdfio_native.redist" version="1.5.0" />
|
||||
<dependency id="pdfio_native.redist" version="1.7.0" />
|
||||
<dependency id="libpng_native.redist" version="1.6.30" />
|
||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||
</dependencies>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native.redist</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.5.0</version>
|
||||
<version>1.7.0</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
|
||||
44
test-corpus.sh
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Script to test PDFio against a directory of PDF files.
|
||||
#
|
||||
# Copyright © 2025-2026 by Michael R Sweet.
|
||||
#
|
||||
# Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
# information.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ./test-corpus.sh DIRECTORY
|
||||
#
|
||||
|
||||
if test $# = 0; then
|
||||
echo "Usage: ./test-corpus.sh DIRECTORY"
|
||||
exit 1
|
||||
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
|
||||
# Run testpdfio to test loading the file...
|
||||
echo $ac_n "\r$file: $ac_c"
|
||||
|
||||
./testpdfio --verbose $file >/dev/null 2>$file.log
|
||||
|
||||
if test $? = 0; then
|
||||
# Passed
|
||||
echo PASS
|
||||
rm -f $file.log
|
||||
else
|
||||
# Failed, preserve log and write to stdout...
|
||||
echo FAIL
|
||||
cat $file.log
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
292
test-internal.h
Normal file
@@ -0,0 +1,292 @@
|
||||
//
|
||||
// Unit test header for C/C++ programs.
|
||||
//
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef TEST_H
|
||||
# define TEST_H
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdarg.h>
|
||||
# include <stdbool.h>
|
||||
# include <string.h>
|
||||
# if _WIN32
|
||||
# include <io.h>
|
||||
# define isatty(f) _isatty(f)
|
||||
# else
|
||||
# include <unistd.h>
|
||||
# endif // !_WIN32
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif // __cplusplus
|
||||
|
||||
|
||||
//
|
||||
// This header implements a simple unit test framework for C/C++ programs.
|
||||
// Inline functions are provided to write a test summary to stdout and the
|
||||
// details to stderr. This allows unit test programs to output a summary to
|
||||
// stdout with details sent to stderr, e.g.:
|
||||
//
|
||||
// mytestprogram 2>test.log
|
||||
//
|
||||
// Documentation:
|
||||
//
|
||||
// void testBegin(const char *title, ...)
|
||||
//
|
||||
// Start a test with a printf-style title message. "Title:" (the formatted
|
||||
// title followed by a colon) is output.
|
||||
//
|
||||
// void testEnd(bool pass)
|
||||
//
|
||||
// End a test without an additional message. "pass" should be `true` if the
|
||||
// test passed and `false` otherwise. "PASS" or "FAIL" is output.
|
||||
//
|
||||
// void testEndMessage(bool pass, const char *message, ...)
|
||||
//
|
||||
// End a test with an additional printf-style message. "pass" should be
|
||||
// `true` if the test passed and `false` otherwise. "PASS (message)" or
|
||||
// "FAIL (message)" is output.
|
||||
//
|
||||
// testError(const char *error, ...)
|
||||
//
|
||||
// Sends a formatted error string to stderr.
|
||||
//
|
||||
// testHexDump(const unsigned char *buffer, size_t bytes)
|
||||
//
|
||||
// Sends a hex dump of the specified buffer to stderr.
|
||||
//
|
||||
// testMessage(const char *error, ...)
|
||||
//
|
||||
// Outputs a formatted message string.
|
||||
//
|
||||
// testProgress(void)
|
||||
//
|
||||
// Shows a progress spinner for long-running tests.
|
||||
//
|
||||
// bool testsPassed
|
||||
//
|
||||
// This global variable specifies whether all tests have passed (`true`)
|
||||
// or one or more have failed (`false`).
|
||||
//
|
||||
|
||||
static bool testsPassed = true; // All tests passed?
|
||||
static int test_progress; // Current progress
|
||||
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
|
||||
static inline void
|
||||
testBegin(const char *title, ...) // I - printf-style title string
|
||||
{
|
||||
va_list ap; // Pointer to additional arguments
|
||||
|
||||
|
||||
// Format the title string
|
||||
va_start(ap, title);
|
||||
vsnprintf(test_title, sizeof(test_title), title, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Send the title to stdout and stderr...
|
||||
test_progress = 0;
|
||||
|
||||
printf("%s: ", test_title);
|
||||
fflush(stdout);
|
||||
|
||||
if (!isatty(2))
|
||||
fprintf(stderr, "%s: ", test_title);
|
||||
}
|
||||
|
||||
|
||||
// End a test with no additional information
|
||||
static inline void
|
||||
testEnd(bool pass) // I - `true` if the test passed, `false` otherwise
|
||||
{
|
||||
// Send the test result to stdout and stderr
|
||||
if (test_progress)
|
||||
putchar('\b');
|
||||
|
||||
if (!pass)
|
||||
testsPassed = false;
|
||||
|
||||
puts(pass ? "PASS" : "FAIL");
|
||||
if (!isatty(2))
|
||||
fputs(pass ? "PASS\n" : "FAIL\n", stderr);
|
||||
|
||||
test_title[0] = '\0';
|
||||
}
|
||||
|
||||
|
||||
// End a test with no additional information
|
||||
static inline void
|
||||
testEndMessage(bool pass, // I - `true` if the test passed, `false` otherwise
|
||||
const char *message, ...)// I - printf-style message
|
||||
{
|
||||
char buffer[1024]; // Formatted title string
|
||||
va_list ap; // Pointer to additional arguments
|
||||
|
||||
|
||||
// Format the title string
|
||||
va_start(ap, message);
|
||||
vsnprintf(buffer, sizeof(buffer), message, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Send the test result to stdout and stderr
|
||||
if (test_progress)
|
||||
putchar('\b');
|
||||
|
||||
printf(pass ? "PASS (%s)\n" : "FAIL (%s)\n", buffer);
|
||||
if (!isatty(2))
|
||||
fprintf(stderr, pass ? "PASS (%s)\n" : "FAIL (%s)\n", buffer);
|
||||
|
||||
test_title[0] = '\0';
|
||||
}
|
||||
|
||||
|
||||
// Show/update a progress spinner
|
||||
static inline void
|
||||
testProgress(void)
|
||||
{
|
||||
if (test_progress)
|
||||
putchar('\b');
|
||||
putchar("-\\|/"[test_progress & 3]);
|
||||
fflush(stdout);
|
||||
|
||||
test_progress ++;
|
||||
}
|
||||
|
||||
|
||||
// Show an error to stderr...
|
||||
static inline void
|
||||
testError(const char *error, ...) // I - printf-style error string
|
||||
{
|
||||
char buffer[1024]; // Formatted title string
|
||||
va_list ap; // Pointer to additional arguments
|
||||
|
||||
|
||||
// Format the error string
|
||||
va_start(ap, error);
|
||||
vsnprintf(buffer, sizeof(buffer), error, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Send the error to stderr...
|
||||
fprintf(stderr, "%s\n", buffer);
|
||||
|
||||
if (test_title[0])
|
||||
fprintf(stderr, "%s: ", test_title);
|
||||
}
|
||||
|
||||
|
||||
// Show a message to stdout and stderr...
|
||||
static inline void
|
||||
testMessage(const char *error, ...) // I - printf-style error string
|
||||
{
|
||||
char buffer[1024]; // Formatted title string
|
||||
va_list ap; // Pointer to additional arguments
|
||||
|
||||
|
||||
// Format the error string
|
||||
va_start(ap, error);
|
||||
vsnprintf(buffer, sizeof(buffer), error, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Send the message to stdout and stderr too if needed...
|
||||
printf("%s\n", buffer);
|
||||
if (test_title[0])
|
||||
{
|
||||
printf("%s: ", test_title);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if (!isatty(2))
|
||||
{
|
||||
fprintf(stderr, "%s\n", buffer);
|
||||
|
||||
if (test_title[0])
|
||||
fprintf(stderr, "%s: ", test_title);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Show a hex dump of a buffer to stderr...
|
||||
static inline void
|
||||
testHexDump(const unsigned char *buffer,// I - Buffer
|
||||
size_t bytes) // I - Number of bytes
|
||||
{
|
||||
size_t i, j; // Looping vars
|
||||
int ch; // Current ASCII char
|
||||
|
||||
|
||||
if (test_title[0])
|
||||
fputs("\n", stderr);
|
||||
|
||||
// Show lines of 16 bytes at a time...
|
||||
for (i = 0; i < bytes; i += 16)
|
||||
{
|
||||
// Show the offset...
|
||||
fprintf(stderr, "%04x ", (unsigned)i);
|
||||
|
||||
// Then up to 16 bytes in hex...
|
||||
for (j = 0; j < 16; j ++)
|
||||
{
|
||||
if ((i + j) < bytes)
|
||||
fprintf(stderr, " %02x", buffer[i + j]);
|
||||
else
|
||||
fputs(" ", stderr);
|
||||
}
|
||||
|
||||
// Then the ASCII representation of the bytes...
|
||||
fputs(" ", stderr);
|
||||
|
||||
for (j = 0; j < 16 && (i + j) < bytes; j ++)
|
||||
{
|
||||
ch = buffer[i + j] & 127;
|
||||
|
||||
if (ch < ' ' || ch == 127)
|
||||
fputc('.', stderr);
|
||||
else
|
||||
fputc(ch, stderr);
|
||||
}
|
||||
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
if (test_title[0])
|
||||
fprintf(stderr, "%s: ", test_title);
|
||||
}
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif // __cplusplus
|
||||
#endif // !TEST_H
|
||||
BIN
testfiles/CGATS001Compat-v2-micro.icc
Normal file
5
testfiles/CGATS001Compat-v2-micro.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
https://github.com/saucecontrol/Compact-ICC-Profiles
|
||||
|
||||
All profiles in this collection are released to the public domain under the
|
||||
Creative Commons CC0 license. They are free from restrictions on distribution
|
||||
and use to the extent allowed by law.
|
||||
BIN
testfiles/color-8bit-i.gif
Normal file
|
After Width: | Height: | Size: 245 KiB |
BIN
testfiles/color.webp
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
testfiles/gray-4bit.gif
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
testfiles/gray.webp
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
testfiles/pdfio-1bit.gif
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
testfiles/pdfio-2bit.gif
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
testfiles/pdfio-4bit-it.gif
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
testfiles/pdfio-4bit.gif
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
testfiles/pdfio-8bit-a.gif
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
testfiles/pdfio-8bit-aipt.gif
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
testfiles/pdfio-8bit-i.gif
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
testfiles/pdfio-8bit-it.gif
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
testfiles/pdfio-color.webp
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
testfiles/pdfio-gray.webp
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
testfiles/pdfio-rgba.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
testfiles/pdfio-rgba.webp
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
2823
testpdfio.c
305
testttf.c
@@ -1,305 +0,0 @@
|
||||
//
|
||||
// Unit test program for TTF library
|
||||
//
|
||||
// https://github.com/michaelrsweet/ttf
|
||||
//
|
||||
// Copyright © 2018-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./testttf [FILENAME]
|
||||
//
|
||||
|
||||
#include <stdio.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
|
||||
const char *value; // Font (string) value
|
||||
int intvalue; // Font (integer) value
|
||||
float realvalue; // Font (real) value
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
return (errors);
|
||||
}
|
||||
1
ttf
Submodule
110
ttf.h
@@ -1,110 +0,0 @@
|
||||
//
|
||||
// Header file for TTF library
|
||||
//
|
||||
// https://github.com/michaelrsweet/ttf
|
||||
//
|
||||
// Copyright © 2018-2024 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 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
|
||||