Compare commits
178 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3b2f7e21d9 | ||
|
7e01069c5a | ||
|
88839ccb56 | ||
|
ebd5aab39b | ||
|
71d33c03ff | ||
|
cfe91b4ea2 | ||
|
458f366d78 | ||
|
4165cd23ba | ||
|
7e56d26ff8 | ||
|
712b213ec6 | ||
|
b7b6655db0 | ||
|
e9debcd169 | ||
|
2f925ccd3c | ||
|
89c2a75376 | ||
|
1237599dea | ||
|
6e2e4bbcc6 | ||
|
d535067c91 | ||
|
e996898b57 | ||
|
aa6a20c042 | ||
|
f09105dd3f | ||
|
5be5552b2b | ||
|
492a4f51b2 | ||
|
44827bac1a | ||
|
3fad0d6f15 | ||
|
aeee24b856 | ||
|
8d72f22efe | ||
|
77117ac789 | ||
|
fceb5a807d | ||
|
4f123c2a01 | ||
|
c4c8fa6036 | ||
|
9a5c5ec65d | ||
|
3f4308b68d | ||
|
9e930a7c5d | ||
|
afa010cea2 | ||
|
c26b200a83 | ||
|
eff02198ab | ||
|
5f98c7838c | ||
|
4f880bc0c1 | ||
|
d032483ed4 | ||
|
b2fc82f3a8 | ||
|
b81d01f319 | ||
|
1b35321615 | ||
|
990342f2a5 | ||
|
7f5fc456bc | ||
|
7c527cc908 | ||
|
41d17fc4e3 | ||
|
4e89137689 | ||
|
e686669b9d | ||
|
1e5cc6ffd5 | ||
|
4f1b373232 | ||
|
6f4bfe107f | ||
|
5b5de3aff6 | ||
|
48fe8d1bc9 | ||
|
a4026bfe00 | ||
|
1e945cb750 | ||
|
4cb4ceaadd | ||
|
cca7383c73 | ||
|
6c68b9fa5a | ||
|
dd7ed67ec1 | ||
|
9e2f3aba10 | ||
|
fca4dbd395 | ||
|
41ac7a0b4b | ||
|
5fc571b711 | ||
|
acf27d29c6 | ||
|
8b2b013b36 | ||
|
026f653e07 | ||
|
3bc041e6d3 | ||
|
fbd61d1fe9 | ||
|
ee2794199c | ||
|
31c3400f23 | ||
|
6d65a609e5 | ||
|
e96f9bfa6b | ||
|
10c15fc281 | ||
|
fd8427d68a | ||
|
ed1421287f | ||
|
aa91b141a8 | ||
|
5dc68f3285 | ||
|
52b508bdd2 | ||
|
41ebe39f3b | ||
|
62df5f5c78 | ||
|
a1237db52c | ||
|
a24fdee335 | ||
|
e4081f2ba3 | ||
|
5bc7ebee2c | ||
|
b872df5a1e | ||
|
53967552df | ||
|
f8639fbd64 | ||
|
9020e92928 | ||
|
48e6597337 | ||
|
d4e3bbcf16 | ||
|
2c8a996875 | ||
|
3d6d9e3e3e | ||
|
62fdf48ff9 | ||
|
294f5e07c5 | ||
|
4baafde74b | ||
|
2d175fdf70 | ||
|
56a0f290aa | ||
|
2e5319a623 | ||
|
d3d6683041 | ||
|
0d08dd5f1b | ||
|
00c9905317 | ||
|
b8b9d7ef8a | ||
|
63cdb13b1b | ||
|
72e55b5bd1 | ||
|
dc65eb8d2f | ||
|
a39b01ec9c | ||
|
4b29c9a1c2 | ||
|
5a4afad566 | ||
|
7a45adb7f5 | ||
|
45ac66874c | ||
|
eb9dad9b51 | ||
|
2ecb9cfb2d | ||
|
91a467e55c | ||
|
d705d7eb5d | ||
|
55745bcea8 | ||
|
2ea99597cc | ||
|
a3a3512ed8 | ||
|
afac83530f | ||
|
21ac2b52d1 | ||
|
21b8e3b06f | ||
|
91392a931f | ||
|
1d8bcf4d73 | ||
|
1e55779906 | ||
|
0e45e49ea4 | ||
|
0ab291a78b | ||
|
cac6d4891c | ||
|
4f29ad89da | ||
|
9c04d1dc20 | ||
|
335472023e | ||
|
25834e07ef | ||
|
2d2a7126d2 | ||
|
df1064ff39 | ||
|
853fa4fe8f | ||
|
2cadfd8a1e | ||
|
f5d40a305e | ||
|
eb5be57b4a | ||
|
3de47ea63d | ||
|
8f2c47cb07 | ||
|
74dfefdcc1 | ||
|
ee31096019 | ||
|
121b933307 | ||
|
f4409146e3 | ||
|
4312933409 | ||
|
a19949834b | ||
|
04c4f44324 | ||
|
206f75403a | ||
|
7d22477917 | ||
|
7c3651671b | ||
|
6cb661f0f4 | ||
|
7e01451b18 | ||
|
138f3955d1 | ||
|
82844ad2ce | ||
|
d7cce4dfbc | ||
|
1cec42f399 | ||
|
f3f70e7877 | ||
|
90923c3818 | ||
|
986cc512cd | ||
|
c35ddbec00 | ||
|
e4e1c39578 | ||
|
1d4f77cab1 | ||
|
b035130cde | ||
|
d6d5813b04 | ||
|
6492f210cf | ||
|
207062a996 | ||
|
7d37abb0df | ||
|
0c1122b689 | ||
|
d4f8dd46b5 | ||
|
986c5f0438 | ||
|
a81907bdb9 | ||
|
63a7a2cdbd | ||
|
f040cc41c2 | ||
|
23883268e3 | ||
|
a1e14503fd | ||
|
0766869ad1 | ||
|
6c1db141a1 | ||
|
b117959725 | ||
|
e882622233 | ||
|
c13b5a5e90 |
4
.github/workflows/build.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
- name: Update Build Environment
|
||||
run: sudo apt-get update --fix-missing -y
|
||||
- name: Install Prerequisites
|
||||
run: sudo apt-get install -y cppcheck zlib1g-dev
|
||||
run: sudo apt-get install -y cppcheck zlib1g-dev libpng-dev
|
||||
- name: Configure PDFio
|
||||
run: ./configure --enable-debug --enable-sanitizer --enable-maintainer
|
||||
- name: Build PDFio
|
||||
@ -60,3 +60,5 @@ jobs:
|
||||
run: nuget restore pdfio.sln
|
||||
- name: Build PDFio
|
||||
run: msbuild pdfio.sln
|
||||
- name: Test PDFio
|
||||
run: .\runtests.bat x64\Debug
|
||||
|
2
.github/workflows/codeql.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
||||
run: sudo apt-get update --fix-missing -y
|
||||
|
||||
- name: Install Prerequisites
|
||||
run: sudo apt-get install -y zlib1g-dev
|
||||
run: sudo apt-get install -y zlib1g-dev libpng-dev
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
|
2
.github/workflows/coverity.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
- name: Update Build Environment
|
||||
run: sudo apt-get update --fix-missing -y
|
||||
- name: Install Prerequisites
|
||||
run: sudo apt-get install -y zlib1g-dev
|
||||
run: sudo apt-get install -y zlib1g-dev libpng-dev
|
||||
- name: Download Coverity Build Tool
|
||||
run: |
|
||||
wget -q https://scan.coverity.com/download/linux64 --post-data token="$TOKEN&project=$GITHUB_REPOSITORY" -O cov-analysis-linux64.tar.gz
|
||||
|
9
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
*.1.dylib
|
||||
*.a
|
||||
*.dSYM
|
||||
*.log
|
||||
*.o
|
||||
*.so.1
|
||||
@ -8,14 +9,20 @@
|
||||
/autom4te.cache
|
||||
/config.log
|
||||
/config.status
|
||||
/configure~
|
||||
/doc/pdfio.epub
|
||||
/examples/code128
|
||||
/examples/image2pdf
|
||||
/examples/md2pdf
|
||||
/examples/pdf2text
|
||||
/examples/pdfioinfo
|
||||
/examples/pdfiomerge
|
||||
/Makefile
|
||||
/packages
|
||||
/pdfio.pc
|
||||
/pdfio.xcodeproj/xcshareddata
|
||||
/pdfio-*.tar.gz*
|
||||
/pdfio-*.zip*
|
||||
/pdfiototext
|
||||
/testpdfio
|
||||
/testpdfio-*.pdf
|
||||
/testttf
|
||||
|
127
CHANGES.md
@ -1,9 +1,92 @@
|
||||
Changes in PDFio
|
||||
================
|
||||
|
||||
v1.5.1 - 2025-03-28
|
||||
-------------------
|
||||
|
||||
v1.2.0 (January 24, 2024)
|
||||
-------------------------
|
||||
- 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
|
||||
-------------------
|
||||
|
||||
- Added support for embedded color profiles in JPEG images (Issue #7)
|
||||
- Added `pdfioFileCreateICCObjFromData` API.
|
||||
- Added support for writing cross-reference streams for PDF 1.5 and newer files
|
||||
(Issue #10)
|
||||
- Added `pdfioFileGetModDate()` API (Issue #88)
|
||||
- Added support for using libpng to embed PNG images in PDF output (Issue #90)
|
||||
- Added support for writing the PCLm subset of PDF (Issue #99)
|
||||
- Now support opening damaged PDF files (Issue #45)
|
||||
- Updated documentation (Issue #95)
|
||||
- Updated the pdf2txt example to support font encodings.
|
||||
- Fixed potential heap/integer overflow issues in the TrueType cmap code.
|
||||
- Fixed an output issue for extremely small `double` values with the
|
||||
`pdfioContent` APIs.
|
||||
- Fixed a missing Widths array issue for embedded TrueType fonts.
|
||||
- Fixed some Unicode font embedding issues.
|
||||
|
||||
|
||||
v1.4.1 - 2025-01-24
|
||||
-------------------
|
||||
|
||||
- Added license files for the example fonts now bundled with PDFio (Issue #91)
|
||||
- Fixed the link libraries for the example source code (Issue #86)
|
||||
- Fixed handling of the Info object (Issue #87)
|
||||
- Fixed opening of PDF files less than 1024 bytes in length (Issue #87)
|
||||
- Fixed potential `NULL` dereference when reading (Issue #89)
|
||||
- Fixed reading of compressed object streams (Issue #92)
|
||||
- Fixed reading of UTF-16 string values (Issue #92)
|
||||
|
||||
|
||||
v1.4.0 - 2024-12-26
|
||||
-------------------
|
||||
|
||||
- Added new `pdfioDictGetKey` and `pdfioDictGetNumPairs` APIs (Issue #63)
|
||||
- Added new `pdfioArrayRemove` and `pdfioDictClear` APIs (Issue #74)
|
||||
- Added new `pdfioFileCreateNameObj` and `pdfioObjGetName` APIs for creating and
|
||||
getting name object values (Issue #76)
|
||||
- Updated documentation (Issue #78)
|
||||
- Updated `pdfioContentTextMeasure` to support measuring PDF base fonts created
|
||||
with `pdfioFileCreateFontObjFromBase` (Issue #84)
|
||||
- Fixed reading of PDF files whose trailer is missing a newline (Issue #80)
|
||||
- Fixed builds with some versions of VC++ (Issue #81)
|
||||
- Fixed validation of date/time values (Issue #83)
|
||||
|
||||
|
||||
v1.3.2 - 2024-08-15
|
||||
-------------------
|
||||
|
||||
- Added some more sanity checks to the TrueType font reader.
|
||||
- Updated documentation (Issue #77)
|
||||
- Fixed an issue when opening certain encrypted PDF files (Issue #62)
|
||||
|
||||
|
||||
v1.3.1 - 2024-08-05
|
||||
-------------------
|
||||
|
||||
- CVE 2024-42358: Updated TrueType font reader to avoid large memory
|
||||
allocations.
|
||||
- Fixed some documentation errors and added examples (Issue #68, Issue #69)
|
||||
|
||||
|
||||
v1.3.0 - 2024-06-28
|
||||
-------------------
|
||||
|
||||
- Added `pdfioFileGetCatalog` API for accessing the root/catalog object of a
|
||||
PDF file (Issue #67)
|
||||
- Updated number support to avoid locale issues (Issue #61)
|
||||
- Updated the PDFio private header to allow compilation with MingW; note that
|
||||
MingW is NOT a supported toolchain for PDFio (Issue #66)
|
||||
- Optimized string pool code.
|
||||
|
||||
|
||||
v1.2.0 - 2024-01-24
|
||||
-------------------
|
||||
|
||||
- Now use autoconf to configure the PDFio sources (Issue #54)
|
||||
- Added `pdfioFileCreateNumberObj` and `pdfioFileCreateStringObj` functions
|
||||
@ -26,8 +109,8 @@ v1.2.0 (January 24, 2024)
|
||||
65536 in the xref table (Issue #59)
|
||||
|
||||
|
||||
v1.1.4 (December 3, 2023)
|
||||
-------------------------
|
||||
v1.1.4 - 2023-12-03
|
||||
-------------------
|
||||
|
||||
- Fixed detection of encrypted strings that are too short (Issue #52)
|
||||
- Fixed a TrueType CMAP decoding bug.
|
||||
@ -35,15 +118,15 @@ v1.1.4 (December 3, 2023)
|
||||
- Added a ToUnicode map for Unicode text to support text copying.
|
||||
|
||||
|
||||
v1.1.3 (November 15, 2023)
|
||||
--------------------------
|
||||
v1.1.3 - 2023-11-15
|
||||
-------------------
|
||||
|
||||
- Fixed Unicode font support (Issue #16)
|
||||
- Fixed missing initializer for 40-bit RC4 encryption (Issue #51)
|
||||
|
||||
|
||||
v1.1.2 (October 10, 2023)
|
||||
-------------------------
|
||||
v1.1.2 - 2023-10-10
|
||||
-------------------
|
||||
|
||||
- Updated `pdfioContentSetDashPattern` to support setting a solid (0 length)
|
||||
dash pattern (Issue #41)
|
||||
@ -58,15 +141,15 @@ v1.1.2 (October 10, 2023)
|
||||
(Issue #48)
|
||||
|
||||
|
||||
v1.1.1 (March 20, 2023)
|
||||
-----------------------
|
||||
v1.1.1 - 2023-03-20
|
||||
-------------------
|
||||
|
||||
- CVE-2023-28428: Fixed a potential denial-of-service with corrupt PDF files.
|
||||
- Fixed a few build issues.
|
||||
|
||||
|
||||
v1.1.0 (February 6, 2023)
|
||||
-------------------------
|
||||
v1.1.0 - 2023-02-06
|
||||
-------------------
|
||||
|
||||
- CVE-2023-24808: Fixed a potential denial-of-service with corrupt PDF files.
|
||||
- Added `pdfioFileCreateTemporary` function (Issue #29)
|
||||
@ -80,28 +163,28 @@ v1.1.0 (February 6, 2023)
|
||||
- Fixed `pdfioContentMatrixRotate` function.
|
||||
|
||||
|
||||
v1.0.1 (March 2, 2022)
|
||||
----------------------
|
||||
v1.0.1 - 2022-03-02
|
||||
-------------------
|
||||
|
||||
- Added missing `pdfioPageGetNumStreams` and `pdfioPageOpenStream` functions.
|
||||
- Added demo pdfiototext utility.
|
||||
- Fixed bug in `pdfioStreamGetToken`.
|
||||
|
||||
|
||||
v1.0.0 (December 14, 2021)
|
||||
--------------------------
|
||||
v1.0.0 - 2021-12-14
|
||||
-------------------
|
||||
|
||||
- First stable release.
|
||||
|
||||
|
||||
v1.0rc1 (November 30, 2021)
|
||||
---------------------------
|
||||
v1.0rc1 - 2021-11-30
|
||||
--------------------
|
||||
|
||||
- Fixed a few stack/buffer overflow bugs discovered via fuzzing.
|
||||
|
||||
|
||||
v1.0b2 (November 7, 2021)
|
||||
-------------------------
|
||||
v1.0b2 - 2021-11-07
|
||||
-------------------
|
||||
|
||||
- Added `pdfioFileCreateOutput` API to support streaming output of PDF
|
||||
(Issue #21)
|
||||
@ -112,7 +195,7 @@ v1.0b2 (November 7, 2021)
|
||||
- Fixed some issues identified by a Coverity scan.
|
||||
|
||||
|
||||
v1.0b1 (August 30, 2021)
|
||||
------------------------
|
||||
v1.0b1 - 2021-08-30
|
||||
-------------------
|
||||
|
||||
- Initial release
|
||||
|
18
EXAMPLES.md
Normal file
@ -0,0 +1,18 @@
|
||||
PDFio Examples
|
||||
==============
|
||||
|
||||
The "examples" subdirectory contains example code showing how to do different
|
||||
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.
|
51
Makefile.in
@ -1,7 +1,7 @@
|
||||
#
|
||||
# Makefile 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.
|
||||
@ -15,7 +15,7 @@
|
||||
.SILENT:
|
||||
|
||||
|
||||
# Version number...
|
||||
# Version numbers...
|
||||
PDFIO_VERSION = @PDFIO_VERSION@
|
||||
PDFIO_VERSION_MAJOR = @PDFIO_VERSION_MAJOR@
|
||||
PDFIO_VERSION_MINOR = @PDFIO_VERSION_MINOR@
|
||||
@ -103,15 +103,35 @@ LIBOBJS = \
|
||||
ttf.o
|
||||
OBJS = \
|
||||
$(LIBOBJS) \
|
||||
pdfiototext.o \
|
||||
testpdfio.o \
|
||||
testttf.o
|
||||
TARGETS = \
|
||||
$(LIBPDFIO) \
|
||||
$(LIBPDFIO_STATIC) \
|
||||
pdfiototext \
|
||||
testpdfio \
|
||||
testttf
|
||||
DOCFILES = \
|
||||
doc/pdfio.html \
|
||||
doc/pdfio-512.png \
|
||||
LICENSE \
|
||||
NOTICE
|
||||
EXAMPLES = \
|
||||
examples/Makefile \
|
||||
examples/Roboto-LICENSE.txt \
|
||||
examples/Roboto-Bold.ttf \
|
||||
examples/Roboto-Italic.ttf \
|
||||
examples/Roboto-Regular.ttf \
|
||||
examples/RobotoMono-Regular.ttf \
|
||||
examples/code128.c \
|
||||
examples/code128.ttf \
|
||||
examples/code128-LICENSE.txt \
|
||||
examples/image2pdf.c \
|
||||
examples/md2pdf.c \
|
||||
examples/md2pdf.md \
|
||||
examples/mmd.c \
|
||||
examples/mmd.h \
|
||||
examples/pdf2text.c \
|
||||
examples/pdfioinfo.c
|
||||
|
||||
|
||||
# Make everything
|
||||
@ -152,8 +172,13 @@ install: $(TARGETS)
|
||||
$(INSTALL) -c -m 644 pdfio.pc $(BUILDROOT)$(libdir)/pkgconfig
|
||||
echo Installing documentation to $(BUILDROOT)$(datadir)/doc/pdfio...
|
||||
$(INSTALL) -d -m 755 $(BUILDROOT)$(datadir)/doc/pdfio
|
||||
for file in doc/pdfio.html doc/pdfio-512.png LICENSE NOTICE; do \
|
||||
$(INSTALL) -c -m 644 $$file $(BUILDROOT)$(datadir)/doc/pdfio; \
|
||||
for file in $(DOCFILES); do \
|
||||
$(INSTALL) -c -m 644 $$file $(BUILDROOT)$(datadir)/doc/pdfio; \
|
||||
done
|
||||
echo Installing examples to $(BUILDROOT)$(datadir)/doc/pdfio/examples...
|
||||
$(INSTALL) -d -m 755 $(BUILDROOT)$(datadir)/doc/pdfio/examples
|
||||
for file in $(EXAMPLES); do \
|
||||
$(INSTALL) -c -m 644 $$file $(BUILDROOT)$(datadir)/doc/pdfio/examples; \
|
||||
done
|
||||
echo Installing man page to $(BUILDROOT)$(mandir)/man3...
|
||||
$(INSTALL) -d -m 755 $(BUILDROOT)$(mandir)/man3
|
||||
@ -163,7 +188,9 @@ install: $(TARGETS)
|
||||
# Test everything
|
||||
test: testpdfio testttf
|
||||
./testttf 2>test.log
|
||||
./testpdfio 2>test.log
|
||||
./testpdfio 2>>test.log
|
||||
LANG=fr_FR.UTF-8 ./testpdfio 2>>test.log
|
||||
|
||||
|
||||
valgrind: testpdfio
|
||||
valgrind --leak-check=full ./testpdfio
|
||||
@ -199,12 +226,6 @@ pdfio1.def: $(LIBOBJS) Makefile
|
||||
grep -v '^_ttf' | sed -e '1,$$s/^_//' | sort >>$@
|
||||
|
||||
|
||||
# pdfio text extraction (demo, doesn't handle a lot of things yet)
|
||||
pdfiototext: pdfiototext.o libpdfio.a
|
||||
echo Linking $@...
|
||||
$(CC) $(LDFLAGS) -o $@ pdfiototext.o libpdfio.a $(LIBS)
|
||||
|
||||
|
||||
# pdfio test program
|
||||
testpdfio: testpdfio.o libpdfio.a
|
||||
echo Linking $@...
|
||||
@ -227,7 +248,7 @@ ttf.o: ttf.h
|
||||
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
||||
DOCFLAGS = \
|
||||
--author "Michael R Sweet" \
|
||||
--copyright "Copyright (c) 2021-2024 by Michael R Sweet" \
|
||||
--copyright "Copyright (c) 2021-2025 by Michael R Sweet" \
|
||||
--docversion $(PDFIO_VERSION)
|
||||
|
||||
.PHONY: doc
|
||||
@ -256,5 +277,5 @@ clang:
|
||||
|
||||
# Analyze code using Cppcheck <http://cppcheck.sourceforge.net>
|
||||
cppcheck:
|
||||
cppcheck $(CPPFLAGS) --template=gcc --addon=cert.py --suppressions-list=.cppcheck $(OBJS:.o=.c) 2>cppcheck.log
|
||||
cppcheck $(CPPFLAGS) --template=gcc --suppressions-list=.cppcheck $(OBJS:.o=.c) 2>cppcheck.log
|
||||
test -s cppcheck.log && (echo "$(GHA_ERROR)Cppcheck detected issues."; echo ""; cat cppcheck.log; exit 1) || exit 0
|
||||
|
2
NOTICE
@ -1,6 +1,6 @@
|
||||
PDFio - PDF Read/Write Library
|
||||
|
||||
Copyright © 2021-2024 by Michael R Sweet.
|
||||
Copyright © 2021-2025 by Michael R Sweet.
|
||||
|
||||
(Optional) Exceptions to the Apache 2.0 License:
|
||||
================================================
|
||||
|
@ -89,7 +89,7 @@ generates a static library that will be installed under "/usr/local" with:
|
||||
Legal Stuff
|
||||
-----------
|
||||
|
||||
PDFio is Copyright © 2021-2024 by Michael R Sweet.
|
||||
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
|
||||
|
80
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.2.0.
|
||||
# Generated by GNU Autoconf 2.71 for pdfio 1.5.1.
|
||||
#
|
||||
# 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.2.0'
|
||||
PACKAGE_STRING='pdfio 1.2.0'
|
||||
PACKAGE_VERSION='1.5.1'
|
||||
PACKAGE_STRING='pdfio 1.5.1'
|
||||
PACKAGE_BUGREPORT='https://github.com/michaelrsweet/pdfio/issues'
|
||||
PACKAGE_URL='https://www.msweet.org/pdfio'
|
||||
|
||||
@ -653,6 +653,7 @@ WARNINGS
|
||||
CSFLAGS
|
||||
LIBPDFIO_STATIC
|
||||
LIBPDFIO
|
||||
PKGCONFIG_LIBPNG
|
||||
PKGCONFIG_REQUIRES
|
||||
PKGCONFIG_LIBS_PRIVATE
|
||||
PKGCONFIG_LIBS
|
||||
@ -729,6 +730,7 @@ SHELL'
|
||||
ac_subst_files=''
|
||||
ac_user_opts='
|
||||
enable_option_checking
|
||||
enable_libpng
|
||||
enable_static
|
||||
enable_shared
|
||||
enable_debug
|
||||
@ -1293,7 +1295,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.2.0 to adapt to many kinds of systems.
|
||||
\`configure' configures pdfio 1.5.1 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@ -1359,7 +1361,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of pdfio 1.2.0:";;
|
||||
short | recursive ) echo "Configuration of pdfio 1.5.1:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@ -1367,6 +1369,8 @@ 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,
|
||||
default=auto
|
||||
--disable-static do not install static library
|
||||
--enable-shared install shared library
|
||||
--enable-debug turn on debugging, default=no
|
||||
@ -1456,7 +1460,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
pdfio configure 1.2.0
|
||||
pdfio configure 1.5.1
|
||||
generated by GNU Autoconf 2.71
|
||||
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
@ -1612,7 +1616,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.2.0, which was
|
||||
It was created by pdfio $as_me 1.5.1, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
$ $0$ac_configure_args_raw
|
||||
@ -2368,9 +2372,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
|
||||
PDFIO_VERSION="1.2.0"
|
||||
PDFIO_VERSION_MAJOR="`echo 1.2.0 | awk -F. '{print $1}'`"
|
||||
PDFIO_VERSION_MINOR="`echo 1.2.0 | awk -F. '{printf("%d\n",$2);}'`"
|
||||
PDFIO_VERSION="1.5.1"
|
||||
PDFIO_VERSION_MAJOR="`echo 1.5.1 | awk -F. '{print $1}'`"
|
||||
PDFIO_VERSION_MINOR="`echo 1.5.1 | awk -F. '{printf("%d\n",$2);}'`"
|
||||
|
||||
|
||||
|
||||
@ -4029,8 +4033,8 @@ then :
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; }
|
||||
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
||||
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
||||
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
||||
|
||||
else $as_nop
|
||||
|
||||
@ -4093,11 +4097,61 @@ then :
|
||||
|
||||
fi
|
||||
|
||||
PKGCONFIG_REQUIRES=""
|
||||
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-libpng was given.
|
||||
if test ${enable_libpng+y}
|
||||
then :
|
||||
enableval=$enable_libpng;
|
||||
fi
|
||||
|
||||
|
||||
PKGCONFIG_LIBPNG=""
|
||||
|
||||
|
||||
if test "x$PKGCONFIG" != x -a x$enable_libpng != xno
|
||||
then :
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libpng-1.6.x" >&5
|
||||
printf %s "checking for libpng-1.6.x... " >&6; }
|
||||
if $PKGCONFIG --exists libpng16
|
||||
then :
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; };
|
||||
|
||||
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"
|
||||
|
||||
else $as_nop
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; };
|
||||
if test x$enable_libpng = xyes
|
||||
then :
|
||||
|
||||
as_fn_error $? "libpng-dev 1.6 or later required for --enable-libpng." "$LINENO" 5
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
elif test x$enable_libpng = xyes
|
||||
then :
|
||||
|
||||
as_fn_error $? "libpng-dev 1.6 or later required for --enable-libpng." "$LINENO" 5
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-static was given.
|
||||
if test ${enable_static+y}
|
||||
then :
|
||||
@ -4934,7 +4988,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.2.0, which was
|
||||
This file was extended by pdfio $as_me 1.5.1, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@ -4990,7 +5044,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.2.0
|
||||
pdfio config.status 1.5.1
|
||||
configured by $0, generated by GNU Autoconf 2.71,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
30
configure.ac
@ -1,7 +1,7 @@
|
||||
dnl
|
||||
dnl Configuration script for PDFio
|
||||
dnl
|
||||
dnl Copyright © 2023-2024 by Michael R Sweet
|
||||
dnl Copyright © 2023-2025 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.2.0], [https://github.com/michaelrsweet/pdfio/issues], [pdfio], [https://www.msweet.org/pdfio])
|
||||
AC_INIT([pdfio], [1.5.1], [https://github.com/michaelrsweet/pdfio/issues], [pdfio], [https://www.msweet.org/pdfio])
|
||||
|
||||
PDFIO_VERSION="AC_PACKAGE_VERSION"
|
||||
PDFIO_VERSION_MAJOR="`echo AC_PACKAGE_VERSION | awk -F. '{print $1}'`"
|
||||
@ -121,6 +121,32 @@ AS_IF([$PKGCONFIG --exists zlib], [
|
||||
])
|
||||
|
||||
|
||||
dnl libpng...
|
||||
AC_ARG_ENABLE([libpng], AS_HELP_STRING([--enable-libpng], [use libpng for pdfioFileCreateImageObjFromFile, default=auto]))
|
||||
|
||||
PKGCONFIG_LIBPNG=""
|
||||
AC_SUBST([PKGCONFIG_LIBPNG])
|
||||
|
||||
AS_IF([test "x$PKGCONFIG" != x -a x$enable_libpng != xno], [
|
||||
AC_MSG_CHECKING([for libpng-1.6.x])
|
||||
AS_IF([$PKGCONFIG --exists libpng16], [
|
||||
AC_MSG_RESULT([yes]);
|
||||
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"
|
||||
], [
|
||||
AC_MSG_RESULT([no]);
|
||||
AS_IF([test x$enable_libpng = xyes], [
|
||||
AC_MSG_ERROR([libpng-dev 1.6 or later required for --enable-libpng.])
|
||||
])
|
||||
])
|
||||
], [test x$enable_libpng = xyes], [
|
||||
AC_MSG_ERROR([libpng-dev 1.6 or later required for --enable-libpng.])
|
||||
])
|
||||
|
||||
|
||||
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]))
|
||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
1804
doc/pdfio.3
1959
doc/pdfio.html
1773
doc/pdfio.md
71
examples/Makefile
Normal file
@ -0,0 +1,71 @@
|
||||
#
|
||||
# Makefile for PDFio examples.
|
||||
#
|
||||
# Copyright © 2024-2025 by Michael R Sweet.
|
||||
#
|
||||
# Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
# information.
|
||||
#
|
||||
|
||||
# POSIX makefile
|
||||
.POSIX:
|
||||
|
||||
|
||||
# Common options
|
||||
CFLAGS = -g $(CPPFLAGS)
|
||||
#CFLAGS = -g -fsanitize=address $(CPPFLAGS)
|
||||
CPPFLAGS = -I.. $(shell PKG_CONFIG_PATH="..:$(PKG_CONFIG_PATH)" pkg-config pdfio --cflags)
|
||||
LIBS = -L.. $(shell PKG_CONFIG_PATH="..:$(PKG_CONFIG_PATH)" pkg-config pdfio --libs)
|
||||
|
||||
|
||||
# Targets
|
||||
TARGETS = \
|
||||
code128 \
|
||||
image2pdf \
|
||||
md2pdf \
|
||||
pdf2text \
|
||||
pdfioinfo \
|
||||
pdfiomerge
|
||||
|
||||
|
||||
# Make everything
|
||||
all: $(TARGETS)
|
||||
|
||||
|
||||
# Clean everything
|
||||
clean:
|
||||
rm -f $(TARGETS)
|
||||
|
||||
|
||||
# code128
|
||||
code128: code128.c
|
||||
$(CC) $(CFLAGS) -o $@ code128.c $(LIBS)
|
||||
|
||||
|
||||
# image2pdf
|
||||
image2pdf: image2pdf.c
|
||||
$(CC) $(CFLAGS) -o $@ image2pdf.c $(LIBS)
|
||||
|
||||
|
||||
# md2pdf
|
||||
md2pdf: md2pdf.c mmd.c mmd.h
|
||||
$(CC) $(CFLAGS) -o $@ md2pdf.c mmd.c $(LIBS)
|
||||
|
||||
|
||||
# pdfio text extraction (demo, doesn't handle a lot of things yet)
|
||||
pdf2text: pdf2text.c
|
||||
$(CC) $(CFLAGS) -o $@ pdf2text.c $(LIBS)
|
||||
|
||||
|
||||
# pdfioinfo
|
||||
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
|
BIN
examples/Roboto-Bold.ttf
Normal file
BIN
examples/Roboto-Italic.ttf
Normal file
93
examples/Roboto-LICENSE.txt
Normal file
@ -0,0 +1,93 @@
|
||||
Copyright 2011 The Roboto Project Authors (https://github.com/googlefonts/roboto-classic)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
examples/Roboto-Regular.ttf
Normal file
BIN
examples/RobotoMono-Regular.ttf
Normal file
343
examples/code128-LICENSE.txt
Normal file
@ -0,0 +1,343 @@
|
||||
Copyright 2003 Grandzebu, All Rights Reserved
|
||||
|
||||
http://grandzebu.net/informatique/codbar-en/code128.htm
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
208
examples/code128.c
Normal file
@ -0,0 +1,208 @@
|
||||
//
|
||||
// Code 128 barcode example for PDFio.
|
||||
//
|
||||
// Copyright © 2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./code128 "BARCODE" ["TEXT"] >FILENAME.pdf
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <pdfio-content.h>
|
||||
|
||||
|
||||
//
|
||||
// 'make_code128()' - Make a Code 128 barcode string.
|
||||
//
|
||||
// This function produces a Code B (printable ASCII) representation of the
|
||||
// source string and doesn't try to optimize using Code C. Non-printable and
|
||||
// extended characters are ignored in the source string.
|
||||
//
|
||||
|
||||
static char * // O - Output string
|
||||
make_code128(char *dst, // I - Destination buffer
|
||||
const char *src, // I - Source string
|
||||
size_t dstsize) // I - Size of destination buffer
|
||||
{
|
||||
char *dstptr, // Pointer into destination buffer
|
||||
*dstend; // End of destination buffer
|
||||
int sum; // Weighted sum
|
||||
static const char *code128_chars = // Code 128 characters
|
||||
" !\"#$%&'()*+,-./0123456789:;<=>?"
|
||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
|
||||
"`abcdefghijklmnopqrstuvwxyz{|}~\303"
|
||||
"\304\305\306\307\310\311\312";
|
||||
static const char code128_fnc_3 = '\304';
|
||||
// FNC 3
|
||||
static const char code128_fnc_2 = '\305';
|
||||
// FNC 2
|
||||
static const char code128_shift_b = '\306';
|
||||
// Shift B (for lowercase)
|
||||
static const char code128_code_c = '\307';
|
||||
// Code C
|
||||
static const char code128_code_b = '\310';
|
||||
// Code B
|
||||
static const char code128_fnc_4 = '\311';
|
||||
// FNC 4
|
||||
static const char code128_fnc_1 = '\312';
|
||||
// FNC 1
|
||||
static const char code128_start_code_a = '\313';
|
||||
// Start code A
|
||||
static const char code128_start_code_b = '\314';
|
||||
// Start code B
|
||||
static const char code128_start_code_c = '\315';
|
||||
// Start code C
|
||||
static const char code128_stop = '\316';
|
||||
// Stop pattern
|
||||
|
||||
|
||||
// Start a Code B barcode...
|
||||
dstptr = dst;
|
||||
dstend = dst + dstsize - 3;
|
||||
|
||||
*dstptr++ = code128_start_code_b;
|
||||
sum = code128_start_code_b - 100;
|
||||
|
||||
while (*src && dstptr < dstend)
|
||||
{
|
||||
if (*src >= ' ' && *src < 0x7f)
|
||||
{
|
||||
sum += (dstptr - dst) * (*src - ' ');
|
||||
*dstptr++ = *src;
|
||||
}
|
||||
|
||||
src ++;
|
||||
}
|
||||
|
||||
// Add the weighted sum modulo 103
|
||||
*dstptr++ = code128_chars[sum % 103];
|
||||
|
||||
// Add the stop pattern and return...
|
||||
*dstptr++ = code128_stop;
|
||||
*dstptr = '\0';
|
||||
|
||||
return (dst);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '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));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Produce a single-page barcode file.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // I - Command-line arguments
|
||||
{
|
||||
const char *barcode, // Barcode to show
|
||||
*text; // Text to display under barcode
|
||||
pdfio_file_t *pdf; // Output PDF file
|
||||
pdfio_obj_t *barcode_font; // Barcode font object
|
||||
pdfio_obj_t *text_font = NULL; // Text font object
|
||||
pdfio_dict_t *page_dict; // Page dictionary
|
||||
pdfio_rect_t media_box; // Media/CropBox for page
|
||||
pdfio_stream_t *page_st; // Page stream
|
||||
char barcode_temp[256]; // Barcode buffer
|
||||
double barcode_height = 36.0, // Height of barcode
|
||||
barcode_width, // Width of barcode
|
||||
text_height = 0.0, // Height of text
|
||||
text_width = 0.0; // Width of text
|
||||
|
||||
|
||||
// Get the barcode and optional text from the command-line...
|
||||
if (argc < 2 || argc > 3)
|
||||
{
|
||||
fputs("Usage: code128 \"BARCODE\" [\"TEXT\"] >FILENAME.pdf\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
barcode = argv[1];
|
||||
text = argv[2];
|
||||
|
||||
// Output a PDF file to the standard output...
|
||||
#ifdef _WIN32
|
||||
setmode(1, O_BINARY); // Force binary output on Windows
|
||||
#endif // _WIN32
|
||||
|
||||
if ((pdf = pdfioFileCreateOutput(output_cb, /*output_cbdata*/NULL, /*version*/NULL, /*media_box*/NULL, /*crop_box*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
return (1);
|
||||
|
||||
// Load fonts...
|
||||
barcode_font = pdfioFileCreateFontObjFromFile(pdf, "code128.ttf", /*unicode*/false);
|
||||
if (text)
|
||||
text_font = pdfioFileCreateFontObjFromBase(pdf, "Helvetica");
|
||||
|
||||
// Generate Code128 characters for the desired barcode...
|
||||
if (!(barcode[0] & 0x80))
|
||||
barcode = make_code128(barcode_temp, barcode, sizeof(barcode_temp));
|
||||
|
||||
// Compute sizes of the text...
|
||||
barcode_width = pdfioContentTextMeasure(barcode_font, barcode, barcode_height);
|
||||
if (text && text_font)
|
||||
{
|
||||
text_height = 9.0;
|
||||
text_width = pdfioContentTextMeasure(text_font, text, text_height);
|
||||
}
|
||||
|
||||
// Compute the size of the PDF page...
|
||||
media_box.x1 = 0.0;
|
||||
media_box.y1 = 0.0;
|
||||
media_box.x2 = (barcode_width > text_width ? barcode_width : text_width) + 18.0;
|
||||
media_box.y2 = barcode_height + text_height + 18.0;
|
||||
|
||||
// Start a page for the barcode...
|
||||
page_dict = pdfioDictCreate(pdf);
|
||||
|
||||
pdfioDictSetRect(page_dict, "MediaBox", &media_box);
|
||||
pdfioDictSetRect(page_dict, "CropBox", &media_box);
|
||||
|
||||
pdfioPageDictAddFont(page_dict, "B128", barcode_font);
|
||||
if (text_font)
|
||||
pdfioPageDictAddFont(page_dict, "TEXT", text_font);
|
||||
|
||||
page_st = pdfioFileCreatePage(pdf, page_dict);
|
||||
|
||||
// Draw the page...
|
||||
pdfioContentSetFillColorGray(page_st, 0.0);
|
||||
|
||||
pdfioContentSetTextFont(page_st, "B128", barcode_height);
|
||||
pdfioContentTextBegin(page_st);
|
||||
pdfioContentTextMoveTo(page_st, 0.5 * (media_box.x2 - barcode_width), 9.0 + text_height);
|
||||
pdfioContentTextShow(page_st, /*unicode*/false, barcode);
|
||||
pdfioContentTextEnd(page_st);
|
||||
|
||||
if (text && text_font)
|
||||
{
|
||||
pdfioContentSetTextFont(page_st, "TEXT", text_height);
|
||||
pdfioContentTextBegin(page_st);
|
||||
pdfioContentTextMoveTo(page_st, 0.5 * (media_box.x2 - text_width), 9.0);
|
||||
pdfioContentTextShow(page_st, /*unicode*/false, text);
|
||||
pdfioContentTextEnd(page_st);
|
||||
}
|
||||
|
||||
pdfioStreamClose(page_st);
|
||||
|
||||
// Close and return...
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
BIN
examples/code128.ttf
Normal file
148
examples/image2pdf.c
Normal file
@ -0,0 +1,148 @@
|
||||
//
|
||||
// Image example for PDFio.
|
||||
//
|
||||
// Copyright © 2023-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./image2pdf FILENAME.{jpg,png} FILENAME.pdf ["TEXT"]
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <pdfio-content.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//
|
||||
// 'create_pdf_image_file()' - Create a PDF file of an image with optional caption.
|
||||
//
|
||||
|
||||
bool // O - True on success, false on failure
|
||||
create_pdf_image_file(
|
||||
const char *imagename, // I - Image filename
|
||||
const char *pdfname, // I - PDF filename
|
||||
const char *caption) // I - Caption filename
|
||||
{
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
pdfio_obj_t *font; // Caption font
|
||||
pdfio_obj_t *image; // Image
|
||||
pdfio_dict_t *dict; // Page dictionary
|
||||
pdfio_stream_t *page; // Page stream
|
||||
double width, height; // Width and height of image
|
||||
double swidth, sheight; // Scaled width and height on page
|
||||
double tx, ty; // Position on page
|
||||
|
||||
|
||||
// Default the caption...
|
||||
if (!caption)
|
||||
{
|
||||
if ((caption = strrchr(imagename, '/')) != NULL)
|
||||
caption ++;
|
||||
else
|
||||
caption = imagename;
|
||||
}
|
||||
|
||||
// Create the PDF file...
|
||||
pdf = pdfioFileCreate(pdfname, /*version*/NULL, /*media_box*/NULL,
|
||||
/*crop_box*/NULL, /*error_cb*/NULL,
|
||||
/*error_cbdata*/NULL);
|
||||
if (!pdf)
|
||||
return (false);
|
||||
|
||||
// Create a Courier base font for the caption
|
||||
font = pdfioFileCreateFontObjFromBase(pdf, "Courier");
|
||||
|
||||
if (!font)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Create an image object from the JPEG/PNG image file...
|
||||
image = pdfioFileCreateImageObjFromFile(pdf, imagename, true);
|
||||
|
||||
if (!image)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Create a page dictionary with the font and image...
|
||||
dict = pdfioDictCreate(pdf);
|
||||
pdfioPageDictAddFont(dict, "F1", font);
|
||||
pdfioPageDictAddImage(dict, "IM1", image);
|
||||
|
||||
// Create the page and its content stream...
|
||||
page = pdfioFileCreatePage(pdf, dict);
|
||||
|
||||
// Position and scale the image on the page...
|
||||
width = pdfioImageGetWidth(image);
|
||||
height = pdfioImageGetHeight(image);
|
||||
|
||||
// Default media_box is "universal" 595.28x792 points (8.27x11in or
|
||||
// 210x279mm). Use margins of 36 points (0.5in or 12.7mm) with another
|
||||
// 36 points for the caption underneath...
|
||||
swidth = 595.28 - 72.0;
|
||||
sheight = swidth * height / width;
|
||||
if (sheight > (792.0 - 36.0 - 72.0))
|
||||
{
|
||||
sheight = 792.0 - 36.0 - 72.0;
|
||||
swidth = sheight * width / height;
|
||||
}
|
||||
|
||||
tx = 0.5 * (595.28 - swidth);
|
||||
ty = 0.5 * (792 - 36 - sheight);
|
||||
|
||||
pdfioContentDrawImage(page, "IM1", tx, ty + 36.0, swidth, sheight);
|
||||
|
||||
// Draw the caption in black...
|
||||
pdfioContentSetFillColorDeviceGray(page, 0.0);
|
||||
|
||||
// Compute the starting point for the text - Courier is monospaced
|
||||
// with a nominal width of 0.6 times the text height...
|
||||
tx = 0.5 * (595.28 - 18.0 * 0.6 * strlen(caption));
|
||||
|
||||
// Position and draw the caption underneath...
|
||||
pdfioContentTextBegin(page);
|
||||
pdfioContentSetTextFont(page, "F1", 18.0);
|
||||
pdfioContentTextMoveTo(page, tx, ty);
|
||||
pdfioContentTextShow(page, /*unicode*/false, caption);
|
||||
pdfioContentTextEnd(page);
|
||||
|
||||
// Close the page stream and the PDF file...
|
||||
pdfioStreamClose(page);
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Produce a single-page file from an image.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // I - Command-line arguments
|
||||
{
|
||||
const char *imagefile, // Image filename
|
||||
*pdffile, // PDF filename
|
||||
*caption; // Caption text
|
||||
|
||||
|
||||
// Get the image file, PDF file, and optional caption text from the command-line...
|
||||
if (argc < 3 || argc > 4)
|
||||
{
|
||||
fputs("Usage: image2pdf FILENAME.{jpg,png} FILENAME.pdf [\"TEXT\"]\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
imagefile = argv[1];
|
||||
pdffile = argv[2];
|
||||
caption = argv[3];
|
||||
|
||||
return (create_pdf_image_file(imagefile, pdffile, caption) ? 0 : 1);
|
||||
}
|
1865
examples/md2pdf.c
Normal file
84
examples/md2pdf.md
Normal file
@ -0,0 +1,84 @@
|
||||
---
|
||||
title: Markdown to PDF Converter Test File
|
||||
...
|
||||
|
||||
|
||||
Markdown to PDF Converter Test File
|
||||
===================================
|
||||
|
||||
The `md2pdf` program is organized into three source files: `md2pdf.c` which
|
||||
contains the code to format the markdown content and `mmd.h` and `mmd.c` (from
|
||||
the [Miniature Markdown Library][MMD] project) which load the markdown content.
|
||||
|
||||
[MMD]: https://www.msweet.org/mmd/
|
||||
|
||||
This is a test file for `md2pdf`. Here is a bullet list:
|
||||
|
||||
- Embed base and TrueType fonts,
|
||||
- Format text with embedded JPEG and PNG images and check boxes, with support
|
||||
for wrapping, alignment in table cells, leader text (as used for lists), and
|
||||
variable line height,
|
||||
- Add headers and footers, and
|
||||
- Add hyperlinks and document platform.
|
||||
|
||||
And here is an ordered list:
|
||||
|
||||
1. Embed base and TrueType fonts,
|
||||
2. Format text with embedded JPEG and PNG images and check boxes, with support
|
||||
for wrapping, alignment in table cells, leader text (as used for lists), and
|
||||
variable line height,
|
||||
3. Add headers and footers, and
|
||||
4. Add hyperlinks and document platform.
|
||||
|
||||
|
||||
Code Blocks
|
||||
-----------
|
||||
|
||||
```
|
||||
0 1 2 3 4 5 6 7 8
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
```
|
||||
|
||||
|
||||
Images
|
||||
------
|
||||
|
||||
PDFio book cover image:
|
||||
|
||||

|
||||
|
||||
|
||||
Tables
|
||||
------
|
||||
|
||||
Table with leading/trailing pipes:
|
||||
|
||||
| Heading 1 | Heading 2 | Heading 3 |
|
||||
| --------- | --------- | --------- |
|
||||
| Cell 1,1 | Cell 1,2 | Cell 1,3 |
|
||||
| Cell 2,1 | Cell 2,2 | Cell 2,3 |
|
||||
| Cell 3,1 | Cell 3,2 | Cell 3,3 |
|
||||
|
||||
Table without leading/trailing pipes:
|
||||
|
||||
Heading 1 | Heading 2 | Heading 3
|
||||
--------- | --------- | ---------
|
||||
Cell 1,1 | Cell 1,2 | Cell 1,3
|
||||
Cell 2,1 | Cell 2,2 | Cell 2,3
|
||||
Cell 3,1 | Cell 3,2 | Cell 3,3
|
||||
|
||||
Table with alignment:
|
||||
|
||||
Left Alignment | Center Alignment | Right Alignment
|
||||
:-------- | :-------: | --------:
|
||||
Cell 1,1 | Cell 1,2 | 1
|
||||
Cell 2,1 | Cell 2,2 | 12
|
||||
Cell 3,1 | Cell 3,2 | 123
|
||||
|
||||
Table in block quote:
|
||||
|
||||
> Heading 1 | Heading 2 | Heading 3
|
||||
> --------- | --------- | ---------
|
||||
> Cell 1,1 | Cell 1,2 | Cell 1,3
|
||||
> Cell 2,1 | Cell 2,2 | Cell 2,3
|
||||
> Cell 3,1 | Cell 3,2 | Cell 3,3
|
2381
examples/mmd.c
Normal file
112
examples/mmd.h
Normal file
@ -0,0 +1,112 @@
|
||||
//
|
||||
// Header file for miniature markdown library.
|
||||
//
|
||||
// https://www.msweet.org/mmd
|
||||
//
|
||||
// Copyright © 2017-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
#ifndef MMD_H
|
||||
# define MMD_H
|
||||
# include <stdio.h>
|
||||
# include <stdbool.h>
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif // __cplusplus
|
||||
|
||||
|
||||
//
|
||||
// Constants...
|
||||
//
|
||||
|
||||
enum mmd_option_e
|
||||
{
|
||||
MMD_OPTION_NONE = 0x00, // No markdown extensions
|
||||
MMD_OPTION_METADATA = 0x01, // Jekyll metadata extension
|
||||
MMD_OPTION_TABLES = 0x02, // Github table extension
|
||||
MMD_OPTION_TASKS = 0x04, // Github task item extension (check boxes)
|
||||
MMD_OPTION_ALL = 0x07 // All supported markdown extensions
|
||||
};
|
||||
typedef unsigned mmd_option_t;
|
||||
|
||||
typedef enum mmd_type_e
|
||||
{
|
||||
MMD_TYPE_NONE = -1,
|
||||
MMD_TYPE_DOCUMENT, // The document root
|
||||
MMD_TYPE_METADATA, // Document metadata
|
||||
MMD_TYPE_BLOCK_QUOTE, // <blockquote>
|
||||
MMD_TYPE_ORDERED_LIST, // <ol>
|
||||
MMD_TYPE_UNORDERED_LIST, // <ul>
|
||||
MMD_TYPE_LIST_ITEM, // <li>
|
||||
MMD_TYPE_TABLE, // <table>
|
||||
MMD_TYPE_TABLE_HEADER, // <thead>
|
||||
MMD_TYPE_TABLE_BODY, // <tbody>
|
||||
MMD_TYPE_TABLE_ROW, // <tr>
|
||||
MMD_TYPE_HEADING_1 = 10, // <h1>
|
||||
MMD_TYPE_HEADING_2, // <h2>
|
||||
MMD_TYPE_HEADING_3, // <h3>
|
||||
MMD_TYPE_HEADING_4, // <h4>
|
||||
MMD_TYPE_HEADING_5, // <h5>
|
||||
MMD_TYPE_HEADING_6, // <h6>
|
||||
MMD_TYPE_PARAGRAPH, // <p>
|
||||
MMD_TYPE_CODE_BLOCK, // <pre><code>
|
||||
MMD_TYPE_THEMATIC_BREAK, // <hr />
|
||||
MMD_TYPE_TABLE_HEADER_CELL, // <th>
|
||||
MMD_TYPE_TABLE_BODY_CELL_LEFT, // <td align="left">
|
||||
MMD_TYPE_TABLE_BODY_CELL_CENTER, // <td align="center">
|
||||
MMD_TYPE_TABLE_BODY_CELL_RIGHT, // <td align="right">
|
||||
MMD_TYPE_NORMAL_TEXT = 100, // Normal text
|
||||
MMD_TYPE_EMPHASIZED_TEXT, // <em>text</em>
|
||||
MMD_TYPE_STRONG_TEXT, // <strong>text</strong>
|
||||
MMD_TYPE_STRUCK_TEXT, // <del>text</del>
|
||||
MMD_TYPE_LINKED_TEXT, // <a href="link">text</a>
|
||||
MMD_TYPE_CODE_TEXT, // <code>text</code>
|
||||
MMD_TYPE_IMAGE, // <img src="link" />
|
||||
MMD_TYPE_HARD_BREAK, // <br />
|
||||
MMD_TYPE_SOFT_BREAK, // <wbr />
|
||||
MMD_TYPE_METADATA_TEXT, // name: value
|
||||
MMD_TYPE_CHECKBOX // [ ] or [x]
|
||||
} mmd_type_t;
|
||||
|
||||
|
||||
//
|
||||
// Types...
|
||||
//
|
||||
|
||||
typedef struct _mmd_s mmd_t; // Markdown node
|
||||
typedef size_t (*mmd_iocb_t)(void *cbdata, char *buffer, size_t bytes);
|
||||
// mmdLoadIO callback function
|
||||
|
||||
//
|
||||
// Functions...
|
||||
//
|
||||
|
||||
extern char *mmdCopyAllText(mmd_t *node);
|
||||
extern void mmdFree(mmd_t *node);
|
||||
extern const char *mmdGetExtra(mmd_t *node);
|
||||
extern mmd_t *mmdGetFirstChild(mmd_t *node);
|
||||
extern mmd_t *mmdGetLastChild(mmd_t *node);
|
||||
extern const char *mmdGetMetadata(mmd_t *doc, const char *keyword);
|
||||
extern mmd_t *mmdGetNextSibling(mmd_t *node);
|
||||
extern mmd_option_t mmdGetOptions(void);
|
||||
extern mmd_t *mmdGetParent(mmd_t *node);
|
||||
extern mmd_t *mmdGetPrevSibling(mmd_t *node);
|
||||
extern const char *mmdGetText(mmd_t *node);
|
||||
extern mmd_type_t mmdGetType(mmd_t *node);
|
||||
extern const char *mmdGetURL(mmd_t *node);
|
||||
extern bool mmdGetWhitespace(mmd_t *node);
|
||||
extern bool mmdIsBlock(mmd_t *node);
|
||||
extern mmd_t *mmdLoad(mmd_t *root, const char *filename);
|
||||
extern mmd_t *mmdLoadFile(mmd_t *root, FILE *fp);
|
||||
extern mmd_t *mmdLoadIO(mmd_t *root, mmd_iocb_t cb, void *cbdata);
|
||||
extern mmd_t *mmdLoadString(mmd_t *root, const char *s);
|
||||
extern void mmdSetOptions(mmd_option_t options);
|
||||
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif // __cplusplus
|
||||
#endif // !MMD_H
|
1420
examples/pdf2text.c
Normal file
162
examples/pdfioinfo.c
Normal file
@ -0,0 +1,162 @@
|
||||
//
|
||||
// PDF metadata example for PDFio.
|
||||
//
|
||||
// Copyright © 2023-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./pdfioinfo FILENAME.pdf
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Open a PDF file and show its metadata.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // Command-line arguments
|
||||
{
|
||||
const char *filename; // PDF filename
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
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...
|
||||
if (argc != 2)
|
||||
{
|
||||
fputs("Usage: ./pdfioinfo FILENAME.pdf\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
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);
|
||||
if (pdf == NULL)
|
||||
return (1);
|
||||
|
||||
// Get the title, author, etc...
|
||||
catalog = pdfioFileGetCatalog(pdf);
|
||||
author = pdfioFileGetAuthor(pdf);
|
||||
creator = pdfioFileGetCreator(pdf);
|
||||
has_acroform = pdfioDictGetObj(catalog, "AcroForm") != NULL ? true : false;
|
||||
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)
|
||||
{
|
||||
creation_tm = localtime(&creation_date);
|
||||
strftime(creation_text, sizeof(creation_text), "%c", creation_tm);
|
||||
}
|
||||
else
|
||||
{
|
||||
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(" 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...
|
||||
for (page = pdfioFileGetPage(pdf, cur);
|
||||
page != NULL;
|
||||
page = pdfioDictGetObj(page_dict, "Parent"))
|
||||
{
|
||||
cur_box.x1 = cur_box.x2 = cur_box.y1 = cur_box.y2 = 0.0;
|
||||
page_dict = pdfioObjGetDict(page);
|
||||
|
||||
if (pdfioDictGetRect(page_dict, "MediaBox", &cur_box))
|
||||
break;
|
||||
}
|
||||
|
||||
// If this MediaBox is different from the previous one, show the range of
|
||||
// pages that have that size...
|
||||
if (cur == 0 ||
|
||||
fabs(cur_box.x1 - prev_box.x1) > 0.01 ||
|
||||
fabs(cur_box.y1 - prev_box.y1) > 0.01 ||
|
||||
fabs(cur_box.x2 - prev_box.x2) > 0.01 ||
|
||||
fabs(cur_box.y2 - prev_box.y2) > 0.01)
|
||||
{
|
||||
if (cur > prev)
|
||||
{
|
||||
snprintf(range_text, sizeof(range_text), "Pages %u-%u",
|
||||
(unsigned)(prev + 1), (unsigned)cur);
|
||||
printf("%16s: [%g %g %g %g]\n", range_text,
|
||||
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
|
||||
}
|
||||
|
||||
// Start a new series of pages with the new size...
|
||||
prev = cur;
|
||||
prev_box = cur_box;
|
||||
}
|
||||
}
|
||||
|
||||
// Show the last range as needed...
|
||||
if (cur > prev)
|
||||
{
|
||||
snprintf(range_text, sizeof(range_text), "Pages %u-%u",
|
||||
(unsigned)(prev + 1), (unsigned)cur);
|
||||
printf("%16s: [%g %g %g %g]\n", range_text,
|
||||
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
|
||||
}
|
||||
|
||||
// Close the PDF file...
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
return (0);
|
||||
}
|
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:
|
||||
//
|
||||
// ./pdfmerge [-o OUTPUT.pdf] INPUT.pdf [... INPUT.pdf]
|
||||
// ./pdfmerge 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, "pdfmerge: 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("pdfmerge: Only one output file can be specified.\n", stderr);
|
||||
return (usage(stderr));
|
||||
}
|
||||
|
||||
i ++;
|
||||
if (i >= argc)
|
||||
{
|
||||
fputs("pdfmerge: 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, "pdfmerge: 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);
|
||||
}
|
84
makesrcdist
@ -2,18 +2,90 @@
|
||||
#
|
||||
# makesrcdist - make a source distribution of pdfio.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ./makesrcdist [--snapshot] VERSION
|
||||
#
|
||||
|
||||
if test $# != 1; then
|
||||
echo "Usage: ./makesrcdist version"
|
||||
exit 1
|
||||
# Support "--snapshot" option...
|
||||
if test "$1" == "--snapshot"; then
|
||||
shift
|
||||
snapshot=1
|
||||
else
|
||||
snapshot=0
|
||||
fi
|
||||
|
||||
# Get 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}')
|
||||
|
||||
echo Creating tag for release...
|
||||
git tag -m "Tag $version" v$version
|
||||
git push origin v$version
|
||||
# Check that version number has been updated everywhere...
|
||||
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
|
||||
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
|
||||
echo "Still need to update CHANGES.md release date."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(grep PDFIO_VERSION= configure | awk -F \" '{print $2}') != "$version"; then
|
||||
echo "Still need to run 'autoconf -f'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(grep '<version>' pdfio_native.nuspec | sed -E -e '1,$s/^.*<version>([0-9.]+).*$/\1/') != "$version"; then
|
||||
echo "Still need to update version in 'pdfio_native.nuspec'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(grep '<version>' pdfio_native.redist.nuspec | sed -E -e '1,$s/^.*<version>([0-9.]+).*$/\1/') != "$version"; then
|
||||
echo "Still need to update version in 'pdfio_native.redist.nuspec'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(grep PDFIO_VERSION pdfio.h | awk -F \" '{print $2}') != "$version"; then
|
||||
echo "Still need to update PDFIO_VERSION in 'pdfio.h'."
|
||||
status=1
|
||||
fi
|
||||
if test $(grep PDFIO_VERSION_MAJOR pdfio.h | awk '{print $4}') != "$version_major"; then
|
||||
echo "Still need to update PDFIO_VERSION_MAJOR in 'pdfio.h'."
|
||||
status=1
|
||||
fi
|
||||
if test $(grep PDFIO_VERSION_MINOR pdfio.h | awk '{print $4}') != "$version_minor"; then
|
||||
echo "Still need to update PDFIO_VERSION_MINOR in 'pdfio.h'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(grep VERSION pdfio1.def | awk '{print $2}') != "$version_major.$version_minor"; then
|
||||
echo "Still need to update VERSION in 'pdfio1.def'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $status = 1; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Tag release...
|
||||
if test $snapshot = 0; then
|
||||
echo Creating tag for release...
|
||||
git tag -m "Tag $version" v$version
|
||||
git push origin v$version
|
||||
fi
|
||||
|
||||
# Make source archives...
|
||||
echo Creating pdfio-$version.tar.gz...
|
||||
git archive --format tar --prefix=pdfio-$version/ HEAD | gzip -v9 >pdfio-$version.tar.gz
|
||||
gpg --detach-sign pdfio-$version.tar.gz
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="libpng_native" version="1.6.30" targetFramework="native" />
|
||||
<package id="libpng_native.redist" version="1.6.30" targetFramework="native" />
|
||||
<package id="zlib_native" version="1.2.11" targetFramework="native" />
|
||||
<package id="zlib_native.redist" version="1.2.11" targetFramework="native" />
|
||||
</packages>
|
181
pdfio-aes.c
@ -1,7 +1,7 @@
|
||||
//
|
||||
// AES functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -76,18 +76,18 @@ static const uint8_t Rcon[11] = // Round constants
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
static void AddRoundKey(size_t round, state_t *state, const uint8_t *RoundKey);
|
||||
static void SubBytes(state_t *state);
|
||||
static void ShiftRows(state_t *state);
|
||||
static void add_round_key(size_t round, state_t *state, const uint8_t *round_key);
|
||||
static void sub_bytes(state_t *state);
|
||||
static void shift_rows(state_t *state);
|
||||
static uint8_t xtime(uint8_t x);
|
||||
static void MixColumns(state_t *state);
|
||||
static uint8_t Multiply(uint8_t x, uint8_t y);
|
||||
static void InvMixColumns(state_t *state);
|
||||
static void InvSubBytes(state_t *state);
|
||||
static void InvShiftRows(state_t *state);
|
||||
static void Cipher(state_t *state, const _pdfio_aes_t *ctx);
|
||||
static void InvCipher(state_t *state, const _pdfio_aes_t *ctx);
|
||||
static void XorWithIv(uint8_t *buf, const uint8_t *Iv);
|
||||
static void mix_columns(state_t *state);
|
||||
static uint8_t multiply(uint8_t x, uint8_t y);
|
||||
static void inv_mix_columns(state_t *state);
|
||||
static void inv_sub_bytes(state_t *state);
|
||||
static void inv_shift_rows(state_t *state);
|
||||
static void cipher(state_t *state, const _pdfio_aes_t *ctx);
|
||||
static void inv_cipher(state_t *state, const _pdfio_aes_t *ctx);
|
||||
static void xor_with_iv(uint8_t *buf, const uint8_t *Iv);
|
||||
|
||||
|
||||
//
|
||||
@ -106,7 +106,6 @@ _pdfioCryptoAESInit(
|
||||
*rkptr, // Current round_key values
|
||||
*rkend, // End of round_key values
|
||||
tempa[4]; // Used for the column/row operations
|
||||
// size_t roundlen = keylen + 24; // Length of round_key
|
||||
size_t nwords = keylen / 4; // Number of 32-bit words in key
|
||||
|
||||
|
||||
@ -188,8 +187,8 @@ _pdfioCryptoAESDecrypt(
|
||||
while (len > 15)
|
||||
{
|
||||
memcpy(next_iv, outbuffer, 16);
|
||||
InvCipher((state_t *)outbuffer, ctx);
|
||||
XorWithIv(outbuffer, ctx->iv);
|
||||
inv_cipher((state_t *)outbuffer, ctx);
|
||||
xor_with_iv(outbuffer, ctx->iv);
|
||||
memcpy(ctx->iv, next_iv, 16);
|
||||
outbuffer += 16;
|
||||
len -= 16;
|
||||
@ -231,8 +230,8 @@ _pdfioCryptoAESEncrypt(
|
||||
|
||||
while (len > 15)
|
||||
{
|
||||
XorWithIv(outbuffer, iv);
|
||||
Cipher((state_t*)outbuffer, ctx);
|
||||
xor_with_iv(outbuffer, iv);
|
||||
cipher((state_t*)outbuffer, ctx);
|
||||
iv = outbuffer;
|
||||
outbuffer += 16;
|
||||
len -= 16;
|
||||
@ -242,10 +241,10 @@ _pdfioCryptoAESEncrypt(
|
||||
if (len > 0)
|
||||
{
|
||||
// Pad the final buffer with (16 - len)...
|
||||
memset(outbuffer + len, 16 - len, 16 - len);
|
||||
memset(outbuffer + len, (int)(16 - len), 16 - len);
|
||||
|
||||
XorWithIv(outbuffer, iv);
|
||||
Cipher((state_t*)outbuffer, ctx);
|
||||
xor_with_iv(outbuffer, iv);
|
||||
cipher((state_t*)outbuffer, ctx);
|
||||
iv = outbuffer;
|
||||
outbytes += 16;
|
||||
}
|
||||
@ -257,24 +256,32 @@ _pdfioCryptoAESEncrypt(
|
||||
}
|
||||
|
||||
|
||||
// This function adds the round key to state.
|
||||
//
|
||||
// 'add_round_key()' - Add the round key to state.
|
||||
//
|
||||
// The round key is added to the state by an XOR function.
|
||||
//
|
||||
|
||||
static void
|
||||
AddRoundKey(size_t round, state_t *state, const uint8_t *RoundKey)
|
||||
add_round_key(size_t round, // I - Which round
|
||||
state_t *state, // I - Current state
|
||||
const uint8_t *round_key) // I - Key
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
|
||||
|
||||
for (RoundKey += round * 16, i = 16; i > 0; i --, sptr ++, RoundKey ++)
|
||||
*sptr ^= *RoundKey;
|
||||
for (round_key += round * 16, i = 16; i > 0; i --, sptr ++, round_key ++)
|
||||
*sptr ^= *round_key;
|
||||
}
|
||||
|
||||
|
||||
// The SubBytes Function Substitutes the values in the
|
||||
// state matrix with values in an S-box.
|
||||
//
|
||||
// 'sub_bytes()' - Substitute the values in the state matrix with values in an S-box.
|
||||
//
|
||||
|
||||
static void
|
||||
SubBytes(state_t *state)
|
||||
sub_bytes(state_t *state) // I - Current state
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
@ -284,11 +291,16 @@ SubBytes(state_t *state)
|
||||
*sptr = sbox[*sptr];
|
||||
}
|
||||
|
||||
// The ShiftRows() function shifts the rows in the state to the left.
|
||||
|
||||
//
|
||||
// 'shift_rows()' - Shift the rows in the state to the left.
|
||||
//
|
||||
// Each row is shifted with different offset.
|
||||
// Offset = Row number. So the first row is not shifted.
|
||||
//
|
||||
|
||||
static void
|
||||
ShiftRows(state_t *state)
|
||||
shift_rows(state_t *state) // I - Current state
|
||||
{
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
uint8_t temp; // Temporary value
|
||||
@ -319,21 +331,29 @@ ShiftRows(state_t *state)
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
xtime(uint8_t x)
|
||||
//
|
||||
// 'xtime()' - Compute the AES xtime function.
|
||||
//
|
||||
|
||||
static uint8_t // O - xtime(x)
|
||||
xtime(uint8_t x) // I - Column value
|
||||
{
|
||||
return ((uint8_t)((x << 1) ^ ((x >> 7) * 0x1b)));
|
||||
}
|
||||
|
||||
|
||||
// MixColumns function mixes the columns of the state matrix
|
||||
//
|
||||
// 'mix_columns()' - Mix the columns of the state matrix.
|
||||
//
|
||||
|
||||
static void
|
||||
MixColumns(state_t *state)
|
||||
mix_columns(state_t *state) // I - Current state
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
uint8_t Tmp, Tm, t; // Temporary values
|
||||
|
||||
|
||||
for (i = 4; i > 0; i --, sptr += 4)
|
||||
{
|
||||
t = sptr[0];
|
||||
@ -357,11 +377,15 @@ MixColumns(state_t *state)
|
||||
}
|
||||
|
||||
|
||||
// Multiply is used to multiply numbers in the field GF(2^8)
|
||||
//
|
||||
// 'multiply()' - Multiply numbers in the field GF(2^8)
|
||||
//
|
||||
// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary
|
||||
// The compiler seems to be able to vectorize the operation better this way.
|
||||
// See https://github.com/kokke/tiny-AES-c/pull/34
|
||||
static uint8_t Multiply(uint8_t x, uint8_t y)
|
||||
//
|
||||
|
||||
static uint8_t multiply(uint8_t x, uint8_t y)
|
||||
{
|
||||
return (((y & 1) * x) ^
|
||||
((y>>1 & 1) * xtime(x)) ^
|
||||
@ -371,11 +395,15 @@ static uint8_t Multiply(uint8_t x, uint8_t y)
|
||||
}
|
||||
|
||||
|
||||
// MixColumns function mixes the columns of the state matrix.
|
||||
//
|
||||
// 'mix_columns()' - Mix the columns of the state matrix.
|
||||
//
|
||||
// The method used to multiply may be difficult to understand for the inexperienced.
|
||||
// Please use the references to gain more information.
|
||||
//
|
||||
|
||||
static void
|
||||
InvMixColumns(state_t *state)
|
||||
inv_mix_columns(state_t *state) // I - Current state
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
@ -389,18 +417,20 @@ InvMixColumns(state_t *state)
|
||||
c = sptr[2];
|
||||
d = sptr[3];
|
||||
|
||||
*sptr++ = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
|
||||
*sptr++ = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
|
||||
*sptr++ = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
|
||||
*sptr++ = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
|
||||
*sptr++ = multiply(a, 0x0e) ^ multiply(b, 0x0b) ^ multiply(c, 0x0d) ^ multiply(d, 0x09);
|
||||
*sptr++ = multiply(a, 0x09) ^ multiply(b, 0x0e) ^ multiply(c, 0x0b) ^ multiply(d, 0x0d);
|
||||
*sptr++ = multiply(a, 0x0d) ^ multiply(b, 0x09) ^ multiply(c, 0x0e) ^ multiply(d, 0x0b);
|
||||
*sptr++ = multiply(a, 0x0b) ^ multiply(b, 0x0d) ^ multiply(c, 0x09) ^ multiply(d, 0x0e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The SubBytes Function Substitutes the values in the
|
||||
// state matrix with values in an S-box.
|
||||
//
|
||||
// 'sub_bytes()' - Substitute the values in the state matrix with values in an S-box.
|
||||
//
|
||||
|
||||
static void
|
||||
InvSubBytes(state_t *state)
|
||||
inv_sub_bytes(state_t *state) // I - Current state
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
@ -411,8 +441,12 @@ InvSubBytes(state_t *state)
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'inv_shift_rows()' - Shift the rows in the state to the right.
|
||||
//
|
||||
|
||||
static void
|
||||
InvShiftRows(state_t *state)
|
||||
inv_shift_rows(state_t *state) // I - Current state
|
||||
{
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
uint8_t temp; // Temporary value
|
||||
@ -443,40 +477,52 @@ InvShiftRows(state_t *state)
|
||||
}
|
||||
|
||||
|
||||
// Cipher is the main function that encrypts the PlainText.
|
||||
//
|
||||
// 'cipher()' - Encrypt the PlainText.
|
||||
//
|
||||
|
||||
static void
|
||||
Cipher(state_t *state, const _pdfio_aes_t *ctx)
|
||||
cipher(state_t *state, // I - Current state
|
||||
const _pdfio_aes_t *ctx) // I - AES context
|
||||
{
|
||||
size_t round = 0;
|
||||
size_t round = 0; // Current round
|
||||
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
AddRoundKey(0, state, ctx->round_key);
|
||||
add_round_key(0, state, ctx->round_key);
|
||||
|
||||
// There will be Nr rounds.
|
||||
// The first Nr-1 rounds are identical.
|
||||
// These Nr rounds are executed in the loop below.
|
||||
// Last one without MixColumns()
|
||||
// Last one without mix_columns()
|
||||
for (round = 1; round < ctx->round_size; round ++)
|
||||
{
|
||||
SubBytes(state);
|
||||
ShiftRows(state);
|
||||
MixColumns(state);
|
||||
AddRoundKey(round, state, ctx->round_key);
|
||||
sub_bytes(state);
|
||||
shift_rows(state);
|
||||
mix_columns(state);
|
||||
add_round_key(round, state, ctx->round_key);
|
||||
}
|
||||
|
||||
// Add round key to last round
|
||||
SubBytes(state);
|
||||
ShiftRows(state);
|
||||
AddRoundKey(ctx->round_size, state, ctx->round_key);
|
||||
sub_bytes(state);
|
||||
shift_rows(state);
|
||||
add_round_key(ctx->round_size, state, ctx->round_key);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'inv_cipher()' - Decrypt the CipherText.
|
||||
//
|
||||
|
||||
static void
|
||||
InvCipher(state_t *state, const _pdfio_aes_t *ctx)
|
||||
inv_cipher(state_t *state, // I - Current state
|
||||
const _pdfio_aes_t *ctx) // I - AES context
|
||||
{
|
||||
size_t round;
|
||||
size_t round; // Current round
|
||||
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
AddRoundKey(ctx->round_size, state, ctx->round_key);
|
||||
add_round_key(ctx->round_size, state, ctx->round_key);
|
||||
|
||||
// There will be Nr rounds.
|
||||
// The first Nr-1 rounds are identical.
|
||||
@ -484,20 +530,25 @@ InvCipher(state_t *state, const _pdfio_aes_t *ctx)
|
||||
// Last one without InvMixColumn()
|
||||
for (round = ctx->round_size - 1; ; round --)
|
||||
{
|
||||
InvShiftRows(state);
|
||||
InvSubBytes(state);
|
||||
AddRoundKey(round, state, ctx->round_key);
|
||||
inv_shift_rows(state);
|
||||
inv_sub_bytes(state);
|
||||
add_round_key(round, state, ctx->round_key);
|
||||
|
||||
if (round == 0)
|
||||
break;
|
||||
|
||||
InvMixColumns(state);
|
||||
inv_mix_columns(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'xor_with_iv()' - XOR a block with the initialization vector.
|
||||
//
|
||||
|
||||
static void
|
||||
XorWithIv(uint8_t *buf, const uint8_t *Iv)
|
||||
xor_with_iv(uint8_t *buf, // I - Block
|
||||
const uint8_t *Iv) // I - Initialization vector
|
||||
{
|
||||
// 16-byte block...
|
||||
*buf++ ^= *Iv++;
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF array functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -363,6 +363,9 @@ _pdfioArrayDebug(pdfio_array_t *a, // I - Array
|
||||
_pdfio_value_t *v; // Current value
|
||||
|
||||
|
||||
if (!a)
|
||||
return;
|
||||
|
||||
putc('[', fp);
|
||||
for (i = a->num_values, v = a->values; i > 0; i --, v ++)
|
||||
_pdfioValueDebug(v, fp);
|
||||
@ -634,6 +637,28 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioArrayRemove()' - Remove an array entry.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` otherwise
|
||||
pdfioArrayRemove(pdfio_array_t *a, // I - Array
|
||||
size_t n) // I - Index
|
||||
{
|
||||
if (!a || n >= a->num_values)
|
||||
return (false);
|
||||
|
||||
if (a->values[n].type == PDFIO_VALTYPE_BINARY)
|
||||
free(a->values[n].value.binary.data);
|
||||
|
||||
a->num_values --;
|
||||
if (n < a->num_values)
|
||||
memmove(a->values + n, a->values + n + 1, (a->num_values - n) * sizeof(_pdfio_value_t));
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioArrayWrite()' - Write an array to a PDF file.
|
||||
//
|
||||
|
308
pdfio-base-font-widths.h
Normal file
@ -0,0 +1,308 @@
|
||||
//
|
||||
// PDF base font widths for PDFio.
|
||||
//
|
||||
// Copyright © 2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
#ifndef PDFIO_BASE_FONT_WIDTHS_H
|
||||
# define PDFIO_BASE_FONT_WIDTHS_H 1
|
||||
|
||||
|
||||
static short courier_bold_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short courier_boldoblique_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short courier_oblique_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short courier_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_bold_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611,
|
||||
975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556,
|
||||
333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611,
|
||||
611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0,
|
||||
556, 0, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 351, 351, 333, 611, 556, 278, 333, 351, 365, 556, 869, 869, 869, 611,
|
||||
722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_boldoblique_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611,
|
||||
975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556,
|
||||
333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611,
|
||||
611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0,
|
||||
556, 0, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 444, 444, 333, 611, 556, 278, 333, 444, 365, 556, 1055, 1055, 1055, 611,
|
||||
722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_oblique_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556,
|
||||
1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556,
|
||||
333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556,
|
||||
556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0,
|
||||
556, 0, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 390, 390, 333, 556, 537, 278, 333, 390, 365, 556, 947, 947, 947, 611,
|
||||
667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556,
|
||||
1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556,
|
||||
333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556,
|
||||
556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0,
|
||||
556, 0, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 222, 221, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 351, 351, 333, 556, 537, 278, 333, 351, 365, 556, 869, 869, 869, 611,
|
||||
667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 666, 666, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 555, 500
|
||||
};
|
||||
|
||||
|
||||
static short symbol_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
250, 333, 713, 500, 549, 833, 778, 439, 333, 333, 500, 549, 250, 549, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444,
|
||||
549, 722, 667, 722, 612, 611, 763, 603, 722, 333, 631, 722, 686, 889, 722, 722,
|
||||
768, 741, 556, 592, 611, 690, 439, 768, 645, 795, 611, 333, 863, 333, 658, 500,
|
||||
500, 631, 549, 549, 494, 439, 521, 411, 603, 329, 603, 549, 549, 576, 521, 549,
|
||||
549, 521, 549, 603, 439, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549, 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, 0, 0,
|
||||
762, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603,
|
||||
400, 549, 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658,
|
||||
823, 686, 795, 987, 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713,
|
||||
768, 713, 790, 790, 890, 823, 549, 250, 713, 603, 603, 1042, 987, 603, 987, 603,
|
||||
494, 329, 790, 790, 786, 713, 384, 384, 384, 384, 384, 384, 494, 494, 494, 494,
|
||||
0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494, 494, 494, 0
|
||||
};
|
||||
|
||||
|
||||
static short times_bold_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
250, 333, 555, 500, 500, 1000, 833, 278, 333, 333, 500, 570, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500,
|
||||
930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778,
|
||||
611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500,
|
||||
333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500,
|
||||
556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 0,
|
||||
500, 0, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 1000, 0, 667, 0,
|
||||
0, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 0, 444, 722,
|
||||
0, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 570, 747, 333,
|
||||
400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500,
|
||||
722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389,
|
||||
722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556,
|
||||
500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500
|
||||
};
|
||||
|
||||
|
||||
static short times_bolditalic_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
250, 389, 555, 500, 500, 833, 778, 278, 333, 333, 500, 570, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500,
|
||||
832, 667, 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611, 889, 722, 722,
|
||||
611, 722, 667, 556, 611, 722, 667, 889, 667, 611, 611, 333, 278, 333, 570, 500,
|
||||
333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778, 556, 500,
|
||||
500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570, 0,
|
||||
500, 0, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 944, 0, 611, 0,
|
||||
0, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 0, 389, 611,
|
||||
0, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 606, 606, 747, 333,
|
||||
400, 570, 300, 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500,
|
||||
667, 667, 667, 667, 667, 667, 944, 667, 667, 667, 667, 667, 389, 389, 389, 389,
|
||||
722, 722, 722, 722, 722, 722, 722, 570, 722, 722, 722, 722, 722, 611, 611, 500,
|
||||
500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500, 444
|
||||
};
|
||||
|
||||
|
||||
static short times_italic_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
250, 333, 420, 500, 500, 833, 778, 214, 333, 333, 500, 675, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500,
|
||||
920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722,
|
||||
611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500,
|
||||
333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500,
|
||||
500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 0,
|
||||
500, 0, 333, 500, 556, 889, 500, 500, 333, 1000, 500, 333, 944, 0, 556, 0,
|
||||
0, 333, 333, 556, 556, 350, 500, 889, 333, 980, 389, 333, 667, 0, 389, 556,
|
||||
0, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 675, 760, 333,
|
||||
400, 675, 300, 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500,
|
||||
611, 611, 611, 611, 611, 611, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333,
|
||||
722, 667, 722, 722, 722, 722, 722, 675, 722, 722, 722, 722, 722, 556, 611, 500,
|
||||
500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500, 444
|
||||
};
|
||||
|
||||
|
||||
static short times_roman_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
250, 333, 408, 500, 500, 833, 778, 180, 333, 333, 500, 564, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444,
|
||||
921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722,
|
||||
556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500,
|
||||
333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500,
|
||||
500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 0,
|
||||
500, 0, 333, 500, 444, 1000, 500, 500, 333, 1000, 556, 333, 889, 0, 611, 0,
|
||||
0, 333, 333, 444, 444, 350, 500, 1000, 333, 980, 389, 333, 722, 0, 444, 722,
|
||||
0, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 564, 760, 333,
|
||||
400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444,
|
||||
722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333,
|
||||
722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500,
|
||||
444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500
|
||||
};
|
||||
|
||||
|
||||
static short zapfdingbats_widths[256] =
|
||||
{
|
||||
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, 0,
|
||||
278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933,
|
||||
911, 945, 974, 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537,
|
||||
577, 692, 786, 788, 788, 790, 793, 794, 816, 823, 789, 841, 823, 833, 816, 831,
|
||||
923, 744, 723, 749, 790, 792, 695, 776, 768, 792, 759, 707, 708, 682, 701, 826,
|
||||
815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785, 791, 873, 761, 762,
|
||||
762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668, 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, 0, 0,
|
||||
0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788, 788, 788, 788,
|
||||
788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788,
|
||||
788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788,
|
||||
788, 788, 788, 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834,
|
||||
873, 828, 924, 924, 917, 930, 931, 463, 883, 836, 836, 867, 867, 696, 696, 874,
|
||||
0, 874, 760, 946, 771, 865, 771, 888, 967, 888, 831, 873, 927, 970, 918, 0
|
||||
};
|
||||
|
||||
|
||||
#endif // !PDFIO_BASE_FONT_WIDTHS_H
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Common support 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.
|
||||
@ -98,7 +98,7 @@ _pdfioFileFlush(pdfio_file_t *pdf) // I - PDF file
|
||||
if (!write_buffer(pdf, pdf->buffer, (size_t)(pdf->bufptr - pdf->buffer)))
|
||||
return (false);
|
||||
|
||||
pdf->bufpos += pdf->bufptr - pdf->buffer;
|
||||
pdf->bufpos += (off_t)(pdf->bufptr - pdf->buffer);
|
||||
}
|
||||
|
||||
pdf->bufptr = pdf->buffer;
|
||||
@ -216,7 +216,7 @@ _pdfioFilePeek(pdfio_file_t *pdf, // I - PDF file
|
||||
PDFIO_DEBUG("_pdfioFilePeek: Sliding buffer, total=%ld\n", (long)total);
|
||||
|
||||
memmove(pdf->buffer, pdf->bufptr, total);
|
||||
pdf->bufpos += pdf->bufptr - pdf->buffer;
|
||||
pdf->bufpos += (off_t)(pdf->bufptr - pdf->buffer);
|
||||
pdf->bufptr = pdf->buffer;
|
||||
pdf->bufend = pdf->buffer + total;
|
||||
|
||||
@ -261,7 +261,7 @@ _pdfioFilePrintf(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
// Format the string...
|
||||
va_start(ap, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||
_pdfio_vsnprintf(pdf, buffer, sizeof(buffer), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Write it...
|
||||
@ -317,14 +317,14 @@ _pdfioFileRead(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);
|
||||
pdf->bufptr = pdf->bufend = NULL;
|
||||
}
|
||||
|
||||
// Read directly from the file...
|
||||
if ((rbytes = read_buffer(pdf, bufptr, bytes)) > 0)
|
||||
{
|
||||
pdf->bufpos += rbytes;
|
||||
pdf->bufpos += (off_t)rbytes;
|
||||
continue;
|
||||
}
|
||||
else if (rbytes < 0 && (errno == EINTR || errno == EAGAIN))
|
||||
@ -361,14 +361,14 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
||||
// Adjust offset for relative seeks...
|
||||
if (whence == SEEK_CUR)
|
||||
{
|
||||
offset += pdf->bufpos + (pdf->bufptr - pdf->buffer);
|
||||
offset += pdf->bufpos + (off_t)(pdf->bufptr - pdf->buffer);
|
||||
whence = SEEK_SET;
|
||||
}
|
||||
|
||||
if (pdf->mode == _PDFIO_MODE_READ)
|
||||
{
|
||||
// Reading, see if we already have the data we need...
|
||||
if (whence != SEEK_END && offset >= pdf->bufpos && offset < (pdf->bufpos + pdf->bufend - pdf->buffer))
|
||||
if (whence != SEEK_END && offset >= pdf->bufpos && pdf->bufend && offset < (off_t)(pdf->bufpos + pdf->bufend - pdf->buffer))
|
||||
{
|
||||
// Yes, seek within existing buffer...
|
||||
pdf->bufptr = pdf->buffer + (offset - pdf->bufpos);
|
||||
@ -398,7 +398,10 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
// Seek within the file...
|
||||
if ((offset = lseek(pdf->fd, offset, whence)) < 0)
|
||||
if ((offset = lseek(pdf->fd, offset, whence)) < 0 && whence == SEEK_END && errno == EINVAL)
|
||||
offset = lseek(pdf->fd, 0, SEEK_SET);
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to seek within file - %s", strerror(errno));
|
||||
return (-1);
|
||||
|
1602
pdfio-content.c
@ -120,15 +120,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 pdfio_obj_t *pdfioFileCreateFontObjFromBase(pdfio_file_t *pdf, const char *name) _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;
|
||||
extern pdfio_obj_t *pdfioFileCreateImageObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t width, size_t height, size_t num_colors, pdfio_array_t *color_data, bool alpha, bool interpolate) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateImageObjFromFile(pdfio_file_t *pdf, const char *filename, bool interpolate) _PDFIO_PUBLIC;
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Cryptographic support 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.
|
||||
@ -466,6 +466,7 @@ _pdfioCryptoMakeReader(
|
||||
|
||||
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);
|
||||
}
|
||||
@ -483,6 +484,7 @@ _pdfioCryptoMakeReader(
|
||||
switch (pdf->encryption)
|
||||
{
|
||||
default :
|
||||
_pdfioFileError(pdf, "Unsupported encryption algorithm.");
|
||||
*ivlen = 0;
|
||||
return (NULL);
|
||||
|
||||
|
189
pdfio-dict.c
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF dictionary 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.
|
||||
@ -18,19 +18,22 @@ static int compare_pairs(_pdfio_pair_t *a, _pdfio_pair_t *b);
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioDictClear()' - Remove a key/value pair from a dictionary.
|
||||
// 'pdfioDictClear()' - Remove a key/value pair from a dictionary.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioDictClear(pdfio_dict_t *dict, // I - Dictionary
|
||||
const char *key) // I - Key
|
||||
bool // O - `true` if cleared, `false` otherwise
|
||||
pdfioDictClear(pdfio_dict_t *dict, // I - Dictionary
|
||||
const char *key) // I - Key
|
||||
{
|
||||
size_t idx; // Index into pairs
|
||||
_pdfio_pair_t *pair, // Current pair
|
||||
pkey; // Search key
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioDictClear(dict=%p, key=\"%s\")\n", dict, key);
|
||||
PDFIO_DEBUG("pdfioDictClear(dict=%p, key=\"%s\")\n", dict, key);
|
||||
|
||||
if (!dict || !key)
|
||||
return (false);
|
||||
|
||||
// See if the key is already set...
|
||||
if (dict->num_pairs > 0)
|
||||
@ -48,8 +51,12 @@ _pdfioDictClear(pdfio_dict_t *dict, // I - Dictionary
|
||||
|
||||
if (idx < dict->num_pairs)
|
||||
memmove(pair, pair + 1, (dict->num_pairs - idx) * sizeof(_pdfio_pair_t));
|
||||
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
@ -194,6 +201,9 @@ _pdfioDictDebug(pdfio_dict_t *dict, // I - Dictionary
|
||||
_pdfio_pair_t *pair; // Current pair
|
||||
|
||||
|
||||
if (!dict)
|
||||
return;
|
||||
|
||||
for (i = dict->num_pairs, pair = dict->pairs; i > 0; i --, pair ++)
|
||||
{
|
||||
fprintf(fp, "/%s", pair->key);
|
||||
@ -332,6 +342,18 @@ pdfioDictGetDict(pdfio_dict_t *dict, // I - Dictionary
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictGetKey()' - Get the key for the specified pair.
|
||||
//
|
||||
|
||||
const char * // O - Key for specified pair
|
||||
pdfioDictGetKey(pdfio_dict_t *dict, // I - Dictionary
|
||||
size_t n) // I - Pair index (`0`-based)
|
||||
{
|
||||
return ((dict && n < dict->num_pairs) ? dict->pairs[n].key : NULL);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictGetName()' - Get a key name value from a dictionary.
|
||||
//
|
||||
@ -350,6 +372,17 @@ pdfioDictGetName(pdfio_dict_t *dict, // I - Dictionary
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictGetNumPairs()' - Get the number of key/value pairs in a dictionary.
|
||||
//
|
||||
|
||||
size_t // O - Number of pairs
|
||||
pdfioDictGetNumPairs(pdfio_dict_t *dict)// I - Dictionary
|
||||
{
|
||||
return (dict ? dict->num_pairs : 0);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictGetNumber()' - Get a key number value from a dictionary.
|
||||
//
|
||||
@ -426,9 +459,151 @@ pdfioDictGetString(pdfio_dict_t *dict, // I - Dictionary
|
||||
|
||||
|
||||
if (value && value->type == PDFIO_VALTYPE_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
|
||||
|
||||
if (!(value->value.binary.datalen & 1) && !memcmp(value->value.binary.data, "\376\377", 2))
|
||||
{
|
||||
// Copy UTF-16 BE
|
||||
int ch; // Unicode character
|
||||
size_t remaining; // Remaining bytes
|
||||
|
||||
for (dataptr = value->value.binary.data + 2, remaining = value->value.binary.datalen - 2, tempptr = temp; remaining > 1 && tempptr < (temp + sizeof(temp) - 5); dataptr += 2, remaining -= 2)
|
||||
{
|
||||
ch = (dataptr[0] << 8) | dataptr[1];
|
||||
|
||||
if (ch >= 0xd800 && ch <= 0xdbff && remaining > 3)
|
||||
{
|
||||
// Multi-word UTF-16 char...
|
||||
int lch; // Lower bits
|
||||
|
||||
lch = (dataptr[2] << 8) | dataptr[3];
|
||||
|
||||
if (lch < 0xdc00 || lch >= 0xdfff)
|
||||
break;
|
||||
|
||||
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
|
||||
dataptr += 2;
|
||||
remaining -= 2;
|
||||
}
|
||||
else if (ch >= 0xfffe)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*tempptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 4096)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*tempptr++ = (char)(0xc0 | (ch >> 6));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else if (ch < 65536)
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 12));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 18));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
*tempptr = '\0';
|
||||
}
|
||||
else if (!(value->value.binary.datalen & 1) && !memcmp(value->value.binary.data, "\377\376", 2))
|
||||
{
|
||||
// Copy UTF-16 LE
|
||||
int ch; // Unicode character
|
||||
size_t remaining; // Remaining bytes
|
||||
|
||||
for (dataptr = value->value.binary.data + 2, remaining = value->value.binary.datalen - 2, tempptr = temp; remaining > 1 && tempptr < (temp + sizeof(temp) - 5); dataptr += 2, remaining -= 2)
|
||||
{
|
||||
ch = (dataptr[1] << 8) | dataptr[0];
|
||||
|
||||
if (ch >= 0xd800 && ch <= 0xdbff && remaining > 3)
|
||||
{
|
||||
// Multi-word UTF-16 char...
|
||||
int lch; // Lower bits
|
||||
|
||||
lch = (dataptr[3] << 8) | dataptr[2];
|
||||
|
||||
if (lch < 0xdc00 || lch >= 0xdfff)
|
||||
break;
|
||||
|
||||
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
|
||||
dataptr += 2;
|
||||
remaining -= 2;
|
||||
}
|
||||
else if (ch >= 0xfffe)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*tempptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 4096)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*tempptr++ = (char)(0xc0 | (ch >> 6));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else if (ch < 65536)
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 12));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 18));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
*tempptr = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy as-is...
|
||||
memcpy(temp, value->value.binary.data, value->value.binary.datalen);
|
||||
temp[value->value.binary.datalen] = '\0';
|
||||
}
|
||||
|
||||
free(value->value.binary.data);
|
||||
value->type = PDFIO_VALTYPE_STRING;
|
||||
value->value.string = pdfioStringCreate(dict->pdf, temp);
|
||||
|
||||
return (value->value.string);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -993,7 +1168,7 @@ _pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary
|
||||
// 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 (!_pdfioFilePrintf(pdf, "%N", pair->key))
|
||||
return (false);
|
||||
|
||||
if (length && !strcmp(pair->key, "Length") && pair->value.type == PDFIO_VALTYPE_NUMBER && pair->value.value.number <= 0.0)
|
||||
|
1117
pdfio-file.c
432
pdfio-md5.c
@ -1,7 +1,7 @@
|
||||
//
|
||||
// MD5 functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
// Copyright © 1999 Aladdin Enterprises. All rights reserved.
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
@ -108,231 +108,285 @@
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T64 0xeb86d391
|
||||
|
||||
|
||||
//
|
||||
// Use the unoptimized (big-endian) implementation if we don't know the
|
||||
// endian-ness of the platform.
|
||||
//
|
||||
|
||||
#ifdef __BYTE_ORDER__
|
||||
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define ARCH_IS_BIG_ENDIAN 0 // Use little endian optimized version
|
||||
# else
|
||||
# define ARCH_IS_BIG_ENDIAN 1 // Use generic version
|
||||
# endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#elif !defined(ARCH_IS_BIG_ENDIAN)
|
||||
# define ARCH_IS_BIG_ENDIAN 1 // Use generic version
|
||||
#endif // !ARCH_IS_BIG_ENDIAN
|
||||
|
||||
|
||||
//
|
||||
// 'md5_process()' - Hash a block of data.
|
||||
//
|
||||
|
||||
static void
|
||||
md5_process(_pdfio_md5_t *pms, const uint8_t *data /*[64]*/)
|
||||
md5_process(_pdfio_md5_t *pms, // I - MD5 state
|
||||
const uint8_t *data/*[64]*/)// I - Data
|
||||
{
|
||||
uint32_t
|
||||
a = pms->abcd[0], b = pms->abcd[1],
|
||||
c = pms->abcd[2], d = pms->abcd[3];
|
||||
uint32_t t;
|
||||
uint32_t a = pms->abcd[0], // First word of state
|
||||
b = pms->abcd[1], // Second word of state
|
||||
c = pms->abcd[2], // Third word of state
|
||||
d = pms->abcd[3]; // Fourth word of state
|
||||
uint32_t t; // Temporary state
|
||||
|
||||
|
||||
#ifndef ARCH_IS_BIG_ENDIAN
|
||||
# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */
|
||||
#endif
|
||||
#if ARCH_IS_BIG_ENDIAN
|
||||
// On big-endian machines, we must arrange the bytes in the right
|
||||
// order. (This also works on machines of unknown byte order.)
|
||||
uint32_t X[16]; // Little-endian representation
|
||||
const uint8_t *xp; // Pointer into data
|
||||
int i; // Looping var
|
||||
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the right
|
||||
* order. (This also works on machines of unknown byte order.)
|
||||
*/
|
||||
uint32_t X[16];
|
||||
const uint8_t *xp = data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
X[i] = xp[0] + (unsigned)(xp[1] << 8) + (unsigned)(xp[2] << 16) + (unsigned)(xp[3] << 24);
|
||||
for (i = 0, xp = data; i < 16; i ++, xp += 4)
|
||||
X[i] = xp[0] + (unsigned)(xp[1] << 8) + (unsigned)(xp[2] << 16) + (unsigned)(xp[3] << 24);
|
||||
|
||||
#else /* !ARCH_IS_BIG_ENDIAN */
|
||||
// On little-endian machines, we can process properly aligned data without copying it.
|
||||
uint32_t xbuf[16]; // Aligned buffer
|
||||
const uint32_t *X; // Pointer to little-endian representation
|
||||
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned data
|
||||
* without copying it.
|
||||
*/
|
||||
uint32_t xbuf[16];
|
||||
const uint32_t *X;
|
||||
|
||||
if (!((data - (const uint8_t *)0) & 3)) {
|
||||
/* data are properly aligned */
|
||||
X = (const uint32_t *)data;
|
||||
} else {
|
||||
/* not aligned */
|
||||
memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
#endif
|
||||
if (!((data - (const uint8_t *)0) & 3))
|
||||
{
|
||||
// data is properly aligned, use it directly...
|
||||
X = (const uint32_t *)data;
|
||||
}
|
||||
else
|
||||
{
|
||||
// data is not aligned, copy to the aligned buffer...
|
||||
memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
#endif // ARCH_IS_BIG_ENDIAN
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* Round 1. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + F(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
// Round 1.
|
||||
// Let [abcd k s i] denote the operation
|
||||
// a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s).
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) t = a + F(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
// Do the following 16 operations.
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
|
||||
#undef SET
|
||||
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + G(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
// Round 2.
|
||||
// Let [abcd k s i] denote the operation
|
||||
// a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s).
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) t = a + G(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
// Do the following 16 operations.
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
|
||||
#undef SET
|
||||
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + H(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
// Round 3.
|
||||
// Let [abcd k s t] denote the operation
|
||||
// a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s).
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti) t = a + H(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
// Do the following 16 operations.
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
|
||||
#undef SET
|
||||
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + I(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
// Round 4.
|
||||
// Let [abcd k s t] denote the operation
|
||||
// a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s).
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) t = a + I(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
// Do the following 16 operations.
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
|
||||
#undef SET
|
||||
|
||||
/* Then perform the following additions. (That is increment each
|
||||
of the four registers by the value it had before this block
|
||||
was started.) */
|
||||
pms->abcd[0] += a;
|
||||
pms->abcd[1] += b;
|
||||
pms->abcd[2] += c;
|
||||
pms->abcd[3] += d;
|
||||
// Then perform the following additions. (That is increment each of the four
|
||||
// registers by the value it had before this block was started.)
|
||||
pms->abcd[0] += a;
|
||||
pms->abcd[1] += b;
|
||||
pms->abcd[2] += c;
|
||||
pms->abcd[3] += d;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioCryptoMD5Init()' - Initialize an MD5 hash.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioCryptoMD5Init(_pdfio_md5_t *pms)
|
||||
_pdfioCryptoMD5Init(_pdfio_md5_t *pms) // I - MD5 state
|
||||
{
|
||||
pms->count[0] = pms->count[1] = 0;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = 0xefcdab89;
|
||||
pms->abcd[2] = 0x98badcfe;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = 0xefcdab89;
|
||||
pms->abcd[2] = 0x98badcfe;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioCryptoMD5Append()' - Append bytes to the MD5 hash.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioCryptoMD5Append(_pdfio_md5_t *pms, const uint8_t *data, size_t nbytes)
|
||||
_pdfioCryptoMD5Append(
|
||||
_pdfio_md5_t *pms, // I - MD5 state
|
||||
const uint8_t *data, // I - Data to add
|
||||
size_t nbytes) // I - Number of bytes
|
||||
{
|
||||
const uint8_t *p = data;
|
||||
size_t left = nbytes;
|
||||
size_t offset = (pms->count[0] >> 3) & 63;
|
||||
uint32_t nbits = (uint32_t)(nbytes << 3);
|
||||
const uint8_t *p = data; // Pointer into data
|
||||
size_t left = nbytes; // Remaining bytes
|
||||
size_t offset = (pms->count[0] >> 3) & 63;
|
||||
// Offset into state
|
||||
uint32_t nbits = (uint32_t)(nbytes << 3);
|
||||
// Number of bits to add
|
||||
|
||||
if (nbytes == 0)
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
pms->count[1] += (unsigned)(nbytes >> 29);
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1]++;
|
||||
if (nbytes == 0)
|
||||
return;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
if (offset) {
|
||||
size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||
// Update the message length.
|
||||
pms->count[1] += (unsigned)(nbytes >> 29);
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1] ++;
|
||||
|
||||
memcpy(pms->buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(pms, pms->buf);
|
||||
}
|
||||
// Process an initial partial block.
|
||||
if (offset)
|
||||
{
|
||||
size_t copy = ((offset + nbytes) > 64 ? 64 - offset : nbytes);
|
||||
// Number of bytes to copy
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(pms, p);
|
||||
memcpy(pms->buf + offset, p, copy);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
if ((offset + copy) < 64)
|
||||
return;
|
||||
|
||||
p += copy;
|
||||
left -= copy;
|
||||
|
||||
md5_process(pms, pms->buf);
|
||||
}
|
||||
|
||||
// Process full blocks.
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(pms, p);
|
||||
|
||||
// Copy a final partial block.
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioCryptoMD5Finish()' - Finalize the MD5 hash.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioCryptoMD5Finish(_pdfio_md5_t *pms, uint8_t digest[16])
|
||||
_pdfioCryptoMD5Finish(
|
||||
_pdfio_md5_t *pms, // I - MD5 state
|
||||
uint8_t digest[16]) // O - Digest value
|
||||
{
|
||||
static const uint8_t pad[64] = {
|
||||
0x80, 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,
|
||||
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, 0
|
||||
};
|
||||
uint8_t data[8];
|
||||
int i;
|
||||
int i; // Looping var
|
||||
uint8_t data[8]; // Digest length data
|
||||
static const uint8_t pad[64] = // Padding bytes
|
||||
{
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
_pdfioCryptoMD5Append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
_pdfioCryptoMD5Append(pms, data, 8);
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
|
||||
// Save the length before padding.
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
|
||||
// Pad to 56 bytes mod 64.
|
||||
_pdfioCryptoMD5Append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
|
||||
// Append the length.
|
||||
_pdfioCryptoMD5Append(pms, data, 8);
|
||||
|
||||
// Copy the digest from the state...
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF object 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.
|
||||
@ -10,13 +10,6 @@
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
//
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
static bool write_obj_header(pdfio_obj_t *obj);
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioObjClose()' - Close an object, writing any data as needed to the PDF
|
||||
// file.
|
||||
@ -42,7 +35,7 @@ pdfioObjClose(pdfio_obj_t *obj) // I - Object
|
||||
if (!obj->offset)
|
||||
{
|
||||
// Write the object value
|
||||
if (!write_obj_header(obj))
|
||||
if (!_pdfioObjWriteHeader(obj))
|
||||
return (false);
|
||||
|
||||
// Write the "endobj" line...
|
||||
@ -99,7 +92,7 @@ pdfioObjCopy(pdfio_file_t *pdf, // I - PDF file
|
||||
return (NULL);
|
||||
|
||||
if (dstobj->value.type == PDFIO_VALTYPE_DICT)
|
||||
_pdfioDictClear(dstobj->value.value.dict, "Length");
|
||||
pdfioDictClear(dstobj->value.value.dict, "Length");
|
||||
|
||||
if (srcobj->stream_offset)
|
||||
{
|
||||
@ -195,7 +188,7 @@ pdfioObjCreateStream(
|
||||
}
|
||||
}
|
||||
|
||||
if (!write_obj_header(obj))
|
||||
if (!_pdfioObjWriteHeader(obj))
|
||||
return (NULL);
|
||||
|
||||
if (!_pdfioFilePuts(obj->pdf, "stream\n"))
|
||||
@ -205,7 +198,7 @@ pdfioObjCreateStream(
|
||||
obj->pdf->current_obj = obj;
|
||||
|
||||
// Return the new stream...
|
||||
return (_pdfioStreamCreate(obj, length_obj, filter));
|
||||
return (_pdfioStreamCreate(obj, length_obj, 0, filter));
|
||||
}
|
||||
|
||||
|
||||
@ -314,7 +307,8 @@ pdfioObjGetLength(pdfio_obj_t *obj) // I - Object
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -333,6 +327,26 @@ pdfioObjGetLength(pdfio_obj_t *obj) // I - Object
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioObjGetName()' - Get the name value associated with an object.
|
||||
//
|
||||
|
||||
const char * // O - Dictionary or `NULL` on error
|
||||
pdfioObjGetName(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
if (!obj)
|
||||
return (NULL);
|
||||
|
||||
if (obj->value.type == PDFIO_VALTYPE_NONE)
|
||||
_pdfioObjLoad(obj);
|
||||
|
||||
if (obj->value.type == PDFIO_VALTYPE_NAME)
|
||||
return (obj->value.value.name);
|
||||
else
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioObjGetNumber()' - Get the object's number.
|
||||
//
|
||||
@ -347,8 +361,21 @@ pdfioObjGetNumber(pdfio_obj_t *obj) // I - Object
|
||||
//
|
||||
// 'pdfioObjGetSubtype()' - Get an object's subtype.
|
||||
//
|
||||
// This function returns an object's PDF subtype name, if any. Common subtype
|
||||
// names include:
|
||||
//
|
||||
// - "CIDFontType0": A CID Type0 font
|
||||
// - "CIDFontType2": A CID TrueType font
|
||||
// - "Image": An image or image mask
|
||||
// - "Form": A fillable form
|
||||
// - "OpenType": An OpenType font
|
||||
// - "Type0": A composite font
|
||||
// - "Type1": A PostScript Type1 font
|
||||
// - "Type3": A PDF Type3 font
|
||||
// - "TrueType": A TrueType font
|
||||
//
|
||||
|
||||
const char * // O - Object subtype
|
||||
const char * // O - Object subtype name or `NULL` for none
|
||||
pdfioObjGetSubtype(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
pdfio_dict_t *dict; // Object dictionary
|
||||
@ -364,8 +391,21 @@ pdfioObjGetSubtype(pdfio_obj_t *obj) // I - Object
|
||||
//
|
||||
// 'pdfioObjGetType()' - Get an object's type.
|
||||
//
|
||||
// This function returns an object's PDF type name, if any. Common type names
|
||||
// include:
|
||||
//
|
||||
// - "CMap": A character map for composite fonts
|
||||
// - "Font": An embedded font (@link pdfioObjGetSubtype@ will tell you the
|
||||
// font format)
|
||||
// - "FontDescriptor": A font descriptor
|
||||
// - "Page": A (visible) page
|
||||
// - "Pages": A page tree node
|
||||
// - "Template": An invisible template page
|
||||
// - "XObject": An image, image mask, or form (@link pdfioObjGetSubtype@ will
|
||||
// tell you which)
|
||||
//
|
||||
|
||||
const char * // O - Object type
|
||||
const char * // O - Object type name or `NULL` for none
|
||||
pdfioObjGetType(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
pdfio_dict_t *dict; // Object dictionary
|
||||
@ -536,11 +576,11 @@ _pdfioObjSetExtension(
|
||||
|
||||
|
||||
//
|
||||
// 'write_obj_header()' - Write the object header...
|
||||
// '_pdfioObjWriteHeader()' - Write the object header...
|
||||
//
|
||||
|
||||
static bool // O - `true` on success, `false` on failure
|
||||
write_obj_header(pdfio_obj_t *obj) // I - Object
|
||||
bool // O - `true` on success, `false` on failure
|
||||
_pdfioObjWriteHeader(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
obj->offset = _pdfioFileTell(obj->pdf);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Private 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.
|
||||
@ -20,6 +20,7 @@
|
||||
# include <errno.h>
|
||||
# include <inttypes.h>
|
||||
# include <fcntl.h>
|
||||
# include <locale.h>
|
||||
# ifdef _WIN32
|
||||
# include <io.h>
|
||||
# include <direct.h>
|
||||
@ -37,9 +38,11 @@
|
||||
# define unlink _unlink
|
||||
# define vsnprintf _vsnprintf
|
||||
# define write _write
|
||||
# define F_OK 00 // POSIX parameters/flags
|
||||
# define W_OK 02
|
||||
# define R_OK 04
|
||||
# ifndef F_OK
|
||||
# define F_OK 00 // POSIX parameters/flags
|
||||
# define W_OK 02
|
||||
# define R_OK 04
|
||||
# endif // !F_OK
|
||||
# define O_RDONLY _O_RDONLY // Map standard POSIX open flags
|
||||
# define O_WRONLY _O_WRONLY
|
||||
# define O_CREAT _O_CREAT
|
||||
@ -104,7 +107,7 @@ typedef enum _pdfio_mode_e // Read/write mode
|
||||
typedef enum _pdfio_predictor_e // PNG predictor constants
|
||||
{
|
||||
_PDFIO_PREDICTOR_NONE = 1, // No predictor (default)
|
||||
_PDFIO_PREDICTOR_TIFF2 = 2, // TIFF2 predictor (???)
|
||||
_PDFIO_PREDICTOR_TIFF2 = 2, // TIFF predictor 2 (difference from left neighbor)
|
||||
_PDFIO_PREDICTOR_PNG_NONE = 10, // PNG None predictor (same as `_PDFIO_PREDICTOR_NONE`)
|
||||
_PDFIO_PREDICTOR_PNG_SUB = 11, // PNG Sub predictor
|
||||
_PDFIO_PREDICTOR_PNG_UP = 12, // PNG Up predictor
|
||||
@ -224,6 +227,7 @@ typedef struct _pdfio_objmap_s // PDF object map
|
||||
struct _pdfio_file_s // PDF file structure
|
||||
{
|
||||
char *filename; // Filename
|
||||
struct lconv *loc; // Locale data
|
||||
char *version; // Version number
|
||||
pdfio_rect_t media_box, // Default MediaBox value
|
||||
crop_box; // Default CropBox value
|
||||
@ -309,8 +313,9 @@ struct _pdfio_stream_s // Stream
|
||||
z_stream flate; // Flate 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
|
||||
unsigned char cbuffer[4096], // Compressed data buffer
|
||||
pbsize, // Predictor buffer size, if any
|
||||
cbsize; // Compressed data buffer size
|
||||
unsigned char *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
|
||||
@ -322,6 +327,10 @@ 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 ssize_t _pdfio_vsnprintf(pdfio_file_t *pdf, char *buffer, size_t bufsize, const char *format, va_list ap) _PDFIO_INTERNAL;
|
||||
|
||||
extern bool _pdfioArrayDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_array_t *a, size_t depth) _PDFIO_INTERNAL;
|
||||
extern void _pdfioArrayDebug(pdfio_array_t *a, FILE *fp) _PDFIO_INTERNAL;
|
||||
extern void _pdfioArrayDelete(pdfio_array_t *a) _PDFIO_INTERNAL;
|
||||
@ -346,7 +355,6 @@ extern void _pdfioCryptoSHA256Init(_pdfio_sha256_t *ctx) _PDFIO_INTERNAL;
|
||||
extern void _pdfioCryptoSHA256Finish(_pdfio_sha256_t *ctx, uint8_t *Message_Digest) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioCryptoUnlock(pdfio_file_t *pdf, pdfio_password_cb_t password_cb, void *password_data) _PDFIO_INTERNAL;
|
||||
|
||||
extern void _pdfioDictClear(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioDictDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_dict_t *dict, size_t depth) _PDFIO_INTERNAL;
|
||||
extern void _pdfioDictDebug(pdfio_dict_t *dict, FILE *fp) _PDFIO_INTERNAL;
|
||||
extern void _pdfioDictDelete(pdfio_dict_t *dict) _PDFIO_INTERNAL;
|
||||
@ -360,13 +368,13 @@ extern bool _pdfioFileAddPage(pdfio_file_t *pdf, pdfio_obj_t *obj) _PDFIO_INTER
|
||||
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 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;
|
||||
@ -377,8 +385,9 @@ 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;
|
||||
extern void _pdfioObjSetExtension(pdfio_obj_t *obj, void *data, _pdfio_extfree_t datafree) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioObjWriteHeader(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
|
||||
extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, pdfio_filter_t compression) _PDFIO_INTERNAL;
|
||||
extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, size_t cbsize, pdfio_filter_t compression) _PDFIO_INTERNAL;
|
||||
extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL;
|
||||
|
||||
extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
|
||||
|
155
pdfio-stream.c
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF stream 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.
|
||||
@ -50,7 +50,7 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
|
||||
while ((status = deflate(&st->flate, Z_FINISH)) != Z_STREAM_END)
|
||||
{
|
||||
size_t bytes = sizeof(st->cbuffer) - st->flate.avail_out,
|
||||
size_t bytes = st->cbsize - st->flate.avail_out,
|
||||
// Bytes to write
|
||||
outbytes; // Actual bytes written
|
||||
|
||||
@ -89,13 +89,13 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
}
|
||||
|
||||
st->flate.next_out = (Bytef *)st->cbuffer + bytes;
|
||||
st->flate.avail_out = (uInt)(sizeof(st->cbuffer) - bytes);
|
||||
st->flate.avail_out = (uInt)(st->cbsize - bytes);
|
||||
}
|
||||
|
||||
if (st->flate.avail_out < (uInt)sizeof(st->cbuffer))
|
||||
if (st->flate.avail_out < (uInt)st->cbsize)
|
||||
{
|
||||
// Write any residuals...
|
||||
size_t bytes = sizeof(st->cbuffer) - st->flate.avail_out;
|
||||
size_t bytes = st->cbsize - st->flate.avail_out;
|
||||
// Bytes to write
|
||||
|
||||
if (st->crypto_cb)
|
||||
@ -140,7 +140,7 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
// Update the length as needed...
|
||||
if (st->length_obj)
|
||||
{
|
||||
st->length_obj->value.value.number = st->obj->stream_length;
|
||||
st->length_obj->value.value.number = (double)st->obj->stream_length;
|
||||
pdfioObjClose(st->length_obj);
|
||||
}
|
||||
else if (st->obj->length_offset)
|
||||
@ -172,6 +172,7 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
|
||||
st->pdf->current_obj = NULL;
|
||||
|
||||
free(st->cbuffer);
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
@ -190,6 +191,7 @@ pdfio_stream_t * // O - Stream or `NULL` on error
|
||||
_pdfioStreamCreate(
|
||||
pdfio_obj_t *obj, // I - Object
|
||||
pdfio_obj_t *length_obj, // I - Length object, if any
|
||||
size_t cbsize, // I - Size of compression buffer
|
||||
pdfio_filter_t compression) // I - Compression to apply
|
||||
{
|
||||
pdfio_stream_t *st; // Stream
|
||||
@ -302,8 +304,21 @@ _pdfioStreamCreate(
|
||||
else
|
||||
st->predictor = _PDFIO_PREDICTOR_NONE;
|
||||
|
||||
if (cbsize == 0)
|
||||
cbsize = 4096;
|
||||
|
||||
st->cbsize = cbsize;
|
||||
if ((st->cbuffer = malloc(cbsize)) == NULL)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Flate output buffer: %s", (unsigned long)cbsize, strerror(errno));
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
st->flate.next_out = (Bytef *)st->cbuffer;
|
||||
st->flate.avail_out = (uInt)sizeof(st->cbuffer);
|
||||
st->flate.avail_out = (uInt)cbsize;
|
||||
|
||||
if ((status = deflateInit(&(st->flate), 9)) != Z_OK)
|
||||
{
|
||||
@ -362,15 +377,16 @@ pdfioStreamConsume(pdfio_stream_t *st, // I - Stream
|
||||
//
|
||||
// 'pdfioStreamGetToken()' - Read a single PDF token from a stream.
|
||||
//
|
||||
// This function reads a single PDF token from a stream. Operator tokens,
|
||||
// boolean values, and numbers are returned as-is in the provided string buffer.
|
||||
// String values start with the opening parenthesis ('(') but have all escaping
|
||||
// resolved and the terminating parenthesis removed. Hexadecimal string values
|
||||
// start with the opening angle bracket ('<') and have all whitespace and the
|
||||
// terminating angle bracket removed.
|
||||
// This function reads a single PDF token from a stream, skipping all whitespace
|
||||
// and comments. Operator tokens, boolean values, and numbers are returned
|
||||
// as-is in the provided string buffer. String values start with the opening
|
||||
// parenthesis ('(') but have all escaping resolved and the terminating
|
||||
// parenthesis removed. Hexadecimal string values start with the opening angle
|
||||
// bracket ('<') and have all whitespace and the terminating angle bracket
|
||||
// removed.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on EOF
|
||||
bool // O - `true` on success, `false` on end-of-stream or error
|
||||
pdfioStreamGetToken(
|
||||
pdfio_stream_t *st, // I - Stream
|
||||
char *buffer, // I - String buffer
|
||||
@ -408,6 +424,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
pdfio_stream_t *st; // Stream
|
||||
pdfio_dict_t *dict = pdfioObjGetDict(obj);
|
||||
// Object dictionary
|
||||
const char *type; // Object type
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen(obj=%p(%u), decode=%s)\n", obj, (unsigned)obj->number, decode ? "true" : "false");
|
||||
@ -422,19 +439,21 @@ _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"))
|
||||
{
|
||||
free(st);
|
||||
return (NULL);
|
||||
_pdfioFileError(obj->pdf, "No stream data.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (_pdfioFileSeek(st->pdf, obj->stream_offset, SEEK_SET) != obj->stream_offset)
|
||||
{
|
||||
free(st);
|
||||
return (NULL);
|
||||
_pdfioFileError(obj->pdf, "Unable to seek to stream data.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (obj->pdf->encryption)
|
||||
type = pdfioObjGetType(obj);
|
||||
|
||||
if (obj->pdf->encryption && (!type || strcmp(type, "XRef")))
|
||||
{
|
||||
uint8_t iv[64]; // Initialization vector
|
||||
size_t ivlen; // Length of initialization vector, if any
|
||||
@ -442,11 +461,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
ivlen = (size_t)_pdfioFilePeek(st->pdf, iv, sizeof(iv));
|
||||
|
||||
if ((st->crypto_cb = _pdfioCryptoMakeReader(st->pdf, obj, &st->crypto_ctx, iv, &ivlen)) == NULL)
|
||||
{
|
||||
// TODO: Add error message?
|
||||
free(st);
|
||||
return (NULL);
|
||||
}
|
||||
goto error;
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen: ivlen=%d\n", (int)ivlen);
|
||||
if (ivlen > 0)
|
||||
@ -477,8 +492,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
{
|
||||
// TODO: Implement compound filters...
|
||||
_pdfioFileError(st->pdf, "Unsupported compound stream filter.");
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// No filter, read as-is...
|
||||
@ -511,8 +525,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
else if (bpc < 1 || bpc == 3 || (bpc > 4 && bpc < 8) || (bpc > 8 && bpc < 16) || bpc > 16)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported BitsPerColor value %d.", bpc);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (colors == 0)
|
||||
@ -522,8 +535,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
else if (colors < 0 || colors > 4)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Colors value %d.", colors);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (columns == 0)
|
||||
@ -533,15 +545,13 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
else if (columns < 0)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Columns value %d.", columns);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((predictor > 2 && predictor < 10) || predictor > 15)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Predictor function %d.", predictor);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
else if (predictor > 1)
|
||||
{
|
||||
@ -555,28 +565,31 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
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);
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
st->predictor = _PDFIO_PREDICTOR_NONE;
|
||||
}
|
||||
|
||||
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);
|
||||
goto error;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen: pos=%ld\n", (long)_pdfioFileTell(st->pdf));
|
||||
if (sizeof(st->cbuffer) > st->remaining)
|
||||
if (st->cbsize > st->remaining)
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
||||
else
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer));
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
||||
|
||||
if (rbytes <= 0)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to read bytes for stream.");
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (st->crypto_cb)
|
||||
@ -590,10 +603,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
if ((status = inflateInit(&(st->flate))) != Z_OK)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to start Flate filter: %s", zstrerror(status));
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
st->remaining -= st->flate.avail_in;
|
||||
@ -606,9 +616,8 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
else
|
||||
{
|
||||
// Something else we don't support
|
||||
_pdfioFileError(st->pdf, "Unsupported stream filter '/%s'.", filter);
|
||||
free(st);
|
||||
return (NULL);
|
||||
_pdfioFileError(st->pdf, "Unsupported stream filter '%N'.", filter);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -618,6 +627,16 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
}
|
||||
|
||||
return (st);
|
||||
|
||||
// If we get here something went wrong...
|
||||
error:
|
||||
|
||||
free(st->cbuffer);
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
return (NULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -670,6 +689,10 @@ 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 "%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(
|
||||
@ -687,7 +710,7 @@ pdfioStreamPrintf(
|
||||
|
||||
// Format the string...
|
||||
va_start(ap, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||
_pdfio_vsnprintf(st->pdf, buffer, sizeof(buffer), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Write the string...
|
||||
@ -1042,10 +1065,10 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
if (st->flate.avail_in == 0)
|
||||
{
|
||||
// Read more from the file...
|
||||
if (sizeof(st->cbuffer) > st->remaining)
|
||||
if (st->cbsize > st->remaining)
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
||||
else
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer));
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
||||
|
||||
if (rbytes <= 0)
|
||||
return (-1); // End of file...
|
||||
@ -1061,19 +1084,11 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
st->flate.next_out = (Bytef *)buffer;
|
||||
st->flate.avail_out = (uInt)bytes;
|
||||
|
||||
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 (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Corrupt stream data.");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (st->flate.next_out - (Bytef *)buffer);
|
||||
}
|
||||
@ -1106,10 +1121,10 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
if (st->flate.avail_in == 0)
|
||||
{
|
||||
// Read more from the file...
|
||||
if (sizeof(st->cbuffer) > st->remaining)
|
||||
if (st->cbsize > st->remaining)
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
||||
else
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer));
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
||||
|
||||
if (rbytes <= 0)
|
||||
return (-1); // End of file...
|
||||
@ -1176,10 +1191,10 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
if (st->flate.avail_in == 0)
|
||||
{
|
||||
// Read more from the file...
|
||||
if (sizeof(st->cbuffer) > st->remaining)
|
||||
if (st->cbsize > st->remaining)
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
||||
else
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer));
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
||||
|
||||
if (rbytes <= 0)
|
||||
return (-1); // End of file...
|
||||
@ -1283,10 +1298,10 @@ stream_write(pdfio_stream_t *st, // I - Stream
|
||||
|
||||
while (st->flate.avail_in > 0)
|
||||
{
|
||||
if (st->flate.avail_out < (sizeof(st->cbuffer) / 8))
|
||||
if (st->flate.avail_out < (st->cbsize / 8))
|
||||
{
|
||||
// Flush the compression buffer...
|
||||
size_t cbytes = sizeof(st->cbuffer) - st->flate.avail_out,
|
||||
size_t cbytes = st->cbsize - st->flate.avail_out,
|
||||
outbytes;
|
||||
|
||||
if (st->crypto_cb)
|
||||
@ -1315,7 +1330,7 @@ stream_write(pdfio_stream_t *st, // I - Stream
|
||||
}
|
||||
|
||||
st->flate.next_out = (Bytef *)st->cbuffer + cbytes;
|
||||
st->flate.avail_out = (uInt)(sizeof(st->cbuffer) - cbytes);
|
||||
st->flate.avail_out = (uInt)(st->cbsize - cbytes);
|
||||
}
|
||||
|
||||
// Deflate what we can this time...
|
||||
|
615
pdfio-string.c
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF dictionary functions for PDFio.
|
||||
// PDF string functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -14,7 +14,522 @@
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
static int compare_strings(char **a, char **b);
|
||||
static size_t find_string(pdfio_file_t *pdf, const char *s, int *rdiff);
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_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.
|
||||
//
|
||||
// This function wraps strtod() to avoid locale issues.
|
||||
//
|
||||
|
||||
double // O - Double value
|
||||
_pdfio_strtod(pdfio_file_t *pdf, // I - PDF file
|
||||
const char *s) // I - String
|
||||
{
|
||||
char temp[64], // Temporary buffer
|
||||
*tempptr; // Pointer into temporary buffer
|
||||
|
||||
|
||||
// See if the locale has a special decimal point string...
|
||||
if (!pdf->loc)
|
||||
return (strtod(s, NULL));
|
||||
|
||||
// Copy leading sign, numbers, period, and then numbers...
|
||||
tempptr = temp;
|
||||
temp[sizeof(temp) - 1] = '\0';
|
||||
|
||||
while (*s && *s != '.')
|
||||
{
|
||||
if (tempptr < (temp + sizeof(temp) - 1))
|
||||
*tempptr++ = *s++;
|
||||
else
|
||||
return (0.0);
|
||||
}
|
||||
|
||||
if (*s == '.')
|
||||
{
|
||||
// Convert decimal point to locale equivalent...
|
||||
size_t declen = strlen(pdf->loc->decimal_point);
|
||||
// Length of decimal point
|
||||
s ++;
|
||||
|
||||
if (declen <= (sizeof(temp) - (size_t)(tempptr - temp)))
|
||||
{
|
||||
memcpy(tempptr, pdf->loc->decimal_point, declen);
|
||||
tempptr += declen;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy any remaining characters...
|
||||
while (*s)
|
||||
{
|
||||
if (tempptr < (temp + sizeof(temp) - 1))
|
||||
*tempptr++ = *s++;
|
||||
else
|
||||
return (0.0);
|
||||
}
|
||||
|
||||
// Nul-terminate the temporary string and convert the string...
|
||||
*tempptr = '\0';
|
||||
|
||||
return (strtod(temp, NULL));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_vsnprintf()' - Format a string.
|
||||
//
|
||||
// This function emulates vsnprintf() to avoid locale issues.
|
||||
//
|
||||
|
||||
ssize_t // O - Number of bytes
|
||||
_pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
char *buffer, // I - Output buffer
|
||||
size_t bufsize, // I - Size of output buffer
|
||||
const char *format, // I - printf-style format string
|
||||
va_list ap) // I - Pointer to additional arguments
|
||||
{
|
||||
char *bufptr, // Pointer to position in buffer
|
||||
*bufend, // Pointer to end of buffer
|
||||
size, // Size character (h, l, L)
|
||||
type; // Format type character
|
||||
int width, // Width of field
|
||||
prec; // Number of characters of precision
|
||||
char tformat[100], // Temporary format string for snprintf()
|
||||
*tptr, // Pointer into temporary format
|
||||
temp[1024], // Buffer for formatted numbers
|
||||
*tempptr; // Pointer into buffer
|
||||
char *s; // Pointer to string
|
||||
ssize_t bytes; // Total number of bytes needed
|
||||
const char *dec = pdf->loc ? pdf->loc->decimal_point : ".";
|
||||
// Decimal point string
|
||||
char *decptr; // Pointer to decimal point
|
||||
|
||||
|
||||
// Loop through the format string, formatting as needed...
|
||||
bufptr = buffer;
|
||||
bufend = buffer + bufsize - 1;
|
||||
bytes = 0;
|
||||
|
||||
while (*format)
|
||||
{
|
||||
if (*format == '%')
|
||||
{
|
||||
// Format character...
|
||||
tptr = tformat;
|
||||
*tptr++ = *format++;
|
||||
|
||||
if (*format == '%')
|
||||
{
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *format;
|
||||
bytes ++;
|
||||
format ++;
|
||||
continue;
|
||||
}
|
||||
else if (strchr(" -+#\'", *format))
|
||||
{
|
||||
*tptr++ = *format++;
|
||||
}
|
||||
|
||||
if (*format == '*')
|
||||
{
|
||||
// Get width from argument...
|
||||
format ++;
|
||||
width = va_arg(ap, int);
|
||||
|
||||
snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", width);
|
||||
tptr += strlen(tptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
width = 0;
|
||||
|
||||
while (isdigit(*format & 255))
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
width = width * 10 + *format++ - '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (*format == '.')
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
format ++;
|
||||
|
||||
if (*format == '*')
|
||||
{
|
||||
// Get precision from argument...
|
||||
format ++;
|
||||
prec = va_arg(ap, int);
|
||||
|
||||
snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", prec);
|
||||
tptr += strlen(tptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (isdigit(*format & 255))
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
format ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*format == 'l' && format[1] == 'l')
|
||||
{
|
||||
size = 'L';
|
||||
|
||||
if (tptr < (tformat + sizeof(tformat) - 2))
|
||||
{
|
||||
*tptr++ = 'l';
|
||||
*tptr++ = 'l';
|
||||
}
|
||||
|
||||
format += 2;
|
||||
}
|
||||
else if (*format == 'h' || *format == 'l' || *format == 'L')
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
size = *format++;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = 0;
|
||||
}
|
||||
|
||||
if (!*format)
|
||||
break;
|
||||
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
type = *format++;
|
||||
*tptr = '\0';
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 'E' : // Floating point formats
|
||||
case 'G' :
|
||||
case 'e' :
|
||||
case 'f' :
|
||||
case 'g' :
|
||||
if ((size_t)(width + 2) > sizeof(temp))
|
||||
break;
|
||||
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, double));
|
||||
|
||||
if ((decptr = strstr(temp, dec)) != NULL)
|
||||
{
|
||||
// Convert locale decimal point to "."
|
||||
PDFIO_DEBUG("_pdfio_vsnprintf: Before \"%s\"\n", temp);
|
||||
tempptr = decptr + strlen(dec);
|
||||
if (tempptr > (decptr + 1))
|
||||
memmove(decptr + 1, tempptr, strlen(tempptr) + 1);
|
||||
*decptr = '.';
|
||||
|
||||
// Strip trailing 0's...
|
||||
for (tempptr = temp + strlen(temp) - 1; tempptr > temp && *tempptr == '0'; tempptr --)
|
||||
*tempptr = '\0';
|
||||
|
||||
if (*tempptr == '.')
|
||||
*tempptr = '\0'; // Strip trailing decimal point
|
||||
|
||||
PDFIO_DEBUG("_pdfio_vsnprintf: After \"%s\"\n", temp);
|
||||
}
|
||||
|
||||
// Copy to the output buffer
|
||||
bytes += (int)strlen(temp);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'B' : // Integer formats
|
||||
case 'X' :
|
||||
case 'b' :
|
||||
case 'd' :
|
||||
case 'i' :
|
||||
case 'o' :
|
||||
case 'u' :
|
||||
case 'x' :
|
||||
if ((size_t)(width + 2) > sizeof(temp))
|
||||
break;
|
||||
|
||||
# ifdef HAVE_LONG_LONG
|
||||
if (size == 'L')
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, long long));
|
||||
else
|
||||
# endif // HAVE_LONG_LONG
|
||||
if (size == 'l')
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, long));
|
||||
else
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, int));
|
||||
|
||||
bytes += (int)strlen(temp);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p' : // Pointer value
|
||||
if ((size_t)(width + 2) > sizeof(temp))
|
||||
break;
|
||||
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, void *));
|
||||
|
||||
bytes += (int)strlen(temp);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c' : // Character or character array
|
||||
bytes += width;
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
if (width <= 1)
|
||||
{
|
||||
*bufptr++ = (char)va_arg(ap, int);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((bufptr + width) > bufend)
|
||||
width = (int)(bufend - bufptr);
|
||||
|
||||
memcpy(bufptr, va_arg(ap, char *), (size_t)width);
|
||||
bufptr += width;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S' : // 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)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal character...
|
||||
bytes ++;
|
||||
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *format++;
|
||||
}
|
||||
}
|
||||
|
||||
// Nul-terminate the string and return the number of characters needed.
|
||||
*bufptr = '\0';
|
||||
|
||||
PDFIO_DEBUG("_pdfio_vsnprintf: Returning %ld \"%s\"\n", (long)bytes, buffer);
|
||||
|
||||
return (bytes);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
@ -32,8 +547,9 @@ pdfioStringCreate(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
const char *s) // I - Nul-terminated string
|
||||
{
|
||||
char *news; // New string
|
||||
char **match; // Matching string
|
||||
char *news; // New string
|
||||
size_t idx; // Index into strings
|
||||
int diff; // Different
|
||||
|
||||
|
||||
PDFIO_DEBUG("pdfioStringCreate(pdf=%p, s=\"%s\")\n", pdf, s);
|
||||
@ -43,8 +559,17 @@ pdfioStringCreate(
|
||||
return (NULL);
|
||||
|
||||
// See if the string has already been added...
|
||||
if (pdf->num_strings > 0 && (match = (char **)bsearch(&s, pdf->strings, pdf->num_strings, sizeof(char *), (int (*)(const void *, const void *))compare_strings)) != NULL)
|
||||
return (*match);
|
||||
if (pdf->num_strings > 0)
|
||||
{
|
||||
idx = find_string(pdf, s, &diff);
|
||||
if (diff == 0)
|
||||
return (pdf->strings[idx]);
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = 0;
|
||||
diff = -1;
|
||||
}
|
||||
|
||||
// Not already added, so add it...
|
||||
if ((news = strdup(s)) == NULL)
|
||||
@ -65,11 +590,17 @@ pdfioStringCreate(
|
||||
pdf->alloc_strings += 128;
|
||||
}
|
||||
|
||||
// TODO: Change to insertion sort as needed...
|
||||
pdf->strings[pdf->num_strings ++] = news;
|
||||
// Insert the string...
|
||||
if (diff > 0)
|
||||
idx ++;
|
||||
|
||||
if (pdf->num_strings > 1)
|
||||
qsort(pdf->strings, pdf->num_strings, sizeof(char *), (int (*)(const void *, const void *))compare_strings);
|
||||
PDFIO_DEBUG("pdfioStringCreate: Inserting \"%s\" at %u\n", news, (unsigned)idx);
|
||||
|
||||
if (idx < pdf->num_strings)
|
||||
memmove(pdf->strings + idx + 1, pdf->strings + idx, (pdf->num_strings - idx) * sizeof(char *));
|
||||
|
||||
pdf->strings[idx] = news;
|
||||
pdf->num_strings ++;
|
||||
|
||||
PDFIO_DEBUG("pdfioStringCreate: %lu strings\n", (unsigned long)pdf->num_strings);
|
||||
|
||||
@ -120,17 +651,67 @@ _pdfioStringIsAllocated(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
const char *s) // I - String
|
||||
{
|
||||
return (pdf->num_strings > 0 && bsearch(&s, pdf->strings, pdf->num_strings, sizeof(char *), (int (*)(const void *, const void *))compare_strings) != NULL);
|
||||
int diff; // Difference
|
||||
|
||||
|
||||
if (pdf->num_strings == 0)
|
||||
return (false);
|
||||
|
||||
find_string(pdf, s, &diff);
|
||||
|
||||
return (diff == 0);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'compare_strings()' - Compare two strings.
|
||||
// 'find_string()' - Find an element in the array.
|
||||
//
|
||||
|
||||
static int // O - Result of comparison
|
||||
compare_strings(char **a, // I - First string
|
||||
char **b) // I - Second string
|
||||
static size_t // O - Index of match
|
||||
find_string(pdfio_file_t *pdf, // I - PDF file
|
||||
const char *s, // I - String to find
|
||||
int *rdiff) // O - Difference of match
|
||||
{
|
||||
return (strcmp(*a, *b));
|
||||
size_t left, // Left side of search
|
||||
right, // Right side of search
|
||||
current; // Current element
|
||||
int diff; // Comparison with current element
|
||||
|
||||
|
||||
// Do a binary search for the string...
|
||||
left = 0;
|
||||
right = pdf->num_strings - 1;
|
||||
|
||||
do
|
||||
{
|
||||
current = (left + right) / 2;
|
||||
diff = strcmp(s, pdf->strings[current]);
|
||||
|
||||
if (diff == 0)
|
||||
break;
|
||||
else if (diff < 0)
|
||||
right = current;
|
||||
else
|
||||
left = current;
|
||||
}
|
||||
while ((right - left) > 1);
|
||||
|
||||
if (diff != 0)
|
||||
{
|
||||
// Check the last 1 or 2 elements...
|
||||
if ((diff = strcmp(s, pdf->strings[left])) <= 0)
|
||||
{
|
||||
current = left;
|
||||
}
|
||||
else
|
||||
{
|
||||
diff = strcmp(s, pdf->strings[right]);
|
||||
current = right;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the closest string and the difference...
|
||||
*rdiff = diff;
|
||||
|
||||
return (current);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF value 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.
|
||||
@ -215,6 +215,9 @@ void
|
||||
_pdfioValueDebug(_pdfio_value_t *v, // I - Value
|
||||
FILE *fp) // I - Output file
|
||||
{
|
||||
if (!v)
|
||||
return;
|
||||
|
||||
switch (v->type)
|
||||
{
|
||||
case PDFIO_VALTYPE_ARRAY :
|
||||
@ -497,7 +500,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
// If we get here, we have a number...
|
||||
v->type = PDFIO_VALTYPE_NUMBER;
|
||||
v->value.number = (double)strtod(token, NULL);
|
||||
v->value.number = _pdfio_strtod(pdf, token);
|
||||
}
|
||||
else if (!strcmp(token, "true") || !strcmp(token, "false"))
|
||||
{
|
||||
@ -634,7 +637,7 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
else
|
||||
{
|
||||
return (_pdfioFilePrintf(pdf, "(%s)", datestr));
|
||||
return (_pdfioFilePrintf(pdf, "%S", datestr));
|
||||
}
|
||||
}
|
||||
|
||||
@ -645,13 +648,13 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
return (_pdfioFilePrintf(pdf, " %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 (_pdfioFilePrintf(pdf, "%N", v->value.name));
|
||||
|
||||
case PDFIO_VALTYPE_NULL :
|
||||
return (_pdfioFilePuts(pdf, " null"));
|
||||
|
||||
case PDFIO_VALTYPE_NUMBER :
|
||||
return (_pdfioFilePrintf(pdf, " %g", v->value.number));
|
||||
return (_pdfioFilePrintf(pdf, " %.6f", v->value.number));
|
||||
|
||||
case PDFIO_VALTYPE_STRING :
|
||||
if (obj && pdf->encryption)
|
||||
@ -692,47 +695,7 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
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 (_pdfioFilePrintf(pdf, "%S", v->value.string));
|
||||
}
|
||||
}
|
||||
|
||||
@ -752,6 +715,8 @@ get_date_time(const char *s) // I - PDF date/time value
|
||||
int offset; // Date offset
|
||||
|
||||
|
||||
PDFIO_DEBUG("get_date_time(s=\"%s\")\n", s);
|
||||
|
||||
// Possible date value of the form:
|
||||
//
|
||||
// (D:YYYYMMDDhhmmssZ)
|
||||
@ -769,10 +734,12 @@ get_date_time(const char *s) // I - PDF date/time value
|
||||
{
|
||||
if (s[i] == 'Z')
|
||||
{
|
||||
// UTC...
|
||||
i ++;
|
||||
}
|
||||
else if (s[i] == '-' || s[i] == '+')
|
||||
{
|
||||
// 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))
|
||||
{
|
||||
i += 6;
|
||||
@ -780,6 +747,11 @@ get_date_time(const char *s) // I - PDF date/time value
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
else if (!s[i])
|
||||
{
|
||||
// Missing zone info, invalid date string...
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (s[i])
|
||||
|
25
pdfio.h
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Public 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.
|
||||
@ -20,10 +20,12 @@ extern "C" {
|
||||
|
||||
|
||||
//
|
||||
// Version number...
|
||||
// Version numbers...
|
||||
//
|
||||
|
||||
# define PDFIO_VERSION "1.2.0"
|
||||
# define PDFIO_VERSION "1.5.1"
|
||||
# define PDFIO_VERSION_MAJOR 1
|
||||
# define PDFIO_VERSION_MINOR 5
|
||||
|
||||
|
||||
//
|
||||
@ -32,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__
|
||||
|
||||
@ -151,7 +151,9 @@ extern pdfio_obj_t *pdfioArrayGetObj(pdfio_array_t *a, size_t n) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioArrayGetSize(pdfio_array_t *a) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioArrayGetString(pdfio_array_t *a, size_t n) _PDFIO_PUBLIC;
|
||||
extern pdfio_valtype_t pdfioArrayGetType(pdfio_array_t *a, size_t n) _PDFIO_PUBLIC;
|
||||
extern bool pdfioArrayRemove(pdfio_array_t *a, size_t n) _PDFIO_PUBLIC;
|
||||
|
||||
extern bool pdfioDictClear(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern pdfio_dict_t *pdfioDictCopy(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
||||
extern pdfio_dict_t *pdfioDictCreate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_array_t *pdfioDictGetArray(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
@ -159,7 +161,9 @@ extern unsigned char *pdfioDictGetBinary(pdfio_dict_t *dict, const char *key, si
|
||||
extern bool pdfioDictGetBoolean(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern time_t pdfioDictGetDate(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern pdfio_dict_t *pdfioDictGetDict(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioDictGetKey(pdfio_dict_t *dict, size_t n) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioDictGetName(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioDictGetNumPairs(pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
||||
extern double pdfioDictGetNumber(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioDictGetObj(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern pdfio_rect_t *pdfioDictGetRect(pdfio_dict_t *dict, const char *key, pdfio_rect_t *rect) _PDFIO_PUBLIC;
|
||||
@ -177,11 +181,12 @@ 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;
|
||||
extern pdfio_obj_t *pdfioFileCreateArrayObj(pdfio_file_t *pdf, pdfio_array_t *array) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateNameObj(pdfio_file_t *pdf, const char *name) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateNumberObj(pdfio_file_t *pdf, double number) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
||||
extern pdfio_file_t *pdfioFileCreateOutput(pdfio_output_cb_t output_cb, void *output_ctx, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||
@ -191,10 +196,12 @@ extern pdfio_obj_t *pdfioFileCreateStringObj(pdfio_file_t *pdf, const char *s) _
|
||||
extern pdfio_file_t *pdfioFileCreateTemporary(char *buffer, size_t bufsize, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileFindObj(pdfio_file_t *pdf, size_t number) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetAuthor(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_dict_t *pdfioFileGetCatalog(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern time_t pdfioFileGetCreationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern 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 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;
|
||||
extern size_t pdfioFileGetNumPages(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
@ -210,6 +217,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 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;
|
||||
extern void pdfioFileSetTitle(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
@ -221,6 +229,7 @@ extern pdfio_array_t *pdfioObjGetArray(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern pdfio_dict_t *pdfioObjGetDict(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern unsigned short pdfioObjGetGeneration(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioObjGetLength(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioObjGetName(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioObjGetNumber(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioObjGetSubtype(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioObjGetType(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
@ -234,14 +243,14 @@ 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
|
||||
|
@ -7,7 +7,7 @@ Name: pdfio
|
||||
Description: PDF read/write library
|
||||
Version: @PDFIO_VERSION@
|
||||
URL: https://www.msweet.org/pdfio
|
||||
Requires: @PKGCONFIG_REQUIRES@
|
||||
Cflags: @PKGCONFIG_CFLAGS@
|
||||
Libs: @PKGCONFIG_LIBS@
|
||||
Libs.private: @PKGCONFIG_LIBS_PRIVATE@
|
||||
Cflags: @PKGCONFIG_CFLAGS@
|
||||
Requires: @PKGCONFIG_REQUIRES@
|
||||
|
@ -115,7 +115,7 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HAVE_LIBPNG;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -130,7 +130,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HAVE_LIBPNG;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -172,6 +172,8 @@
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="packages\libpng_native.redist.1.6.30\build\native\libpng_native.redist.targets" Condition="Exists('packages\libpng_native.redist.1.6.30\build\native\libpng_native.redist.targets')" />
|
||||
<Import Project="packages\libpng_native.1.6.30\build\native\libpng_native.targets" Condition="Exists('packages\libpng_native.1.6.30\build\native\libpng_native.targets')" />
|
||||
<Import Project="packages\zlib_native.redist.1.2.11\build\native\zlib_native.redist.targets" Condition="Exists('packages\zlib_native.redist.1.2.11\build\native\zlib_native.redist.targets')" />
|
||||
<Import Project="packages\zlib_native.1.2.11\build\native\zlib_native.targets" Condition="Exists('packages\zlib_native.1.2.11\build\native\zlib_native.targets')" />
|
||||
</ImportGroup>
|
||||
|
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@ -31,6 +31,7 @@
|
||||
27F2F0612710BE92008ECD36 /* pdfio-rc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 27F2F05E2710BE92008ECD36 /* pdfio-rc4.c */; };
|
||||
27F2F0622710BE92008ECD36 /* pdfio-crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 27F2F05F2710BE92008ECD36 /* pdfio-crypto.c */; };
|
||||
27F2F0642711243D008ECD36 /* pdfio-sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = 27F2F0632711243D008ECD36 /* pdfio-sha256.c */; };
|
||||
27FCBDE42D19F9B300485EEE /* pdfio-base-font-widths.h in Headers */ = {isa = PBXBuildFile; fileRef = 27FCBDE32D19F9B300485EEE /* pdfio-base-font-widths.h */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -89,6 +90,7 @@
|
||||
27F2F05E2710BE92008ECD36 /* pdfio-rc4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-rc4.c"; sourceTree = "<group>"; };
|
||||
27F2F05F2710BE92008ECD36 /* pdfio-crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-crypto.c"; sourceTree = "<group>"; };
|
||||
27F2F0632711243D008ECD36 /* pdfio-sha256.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-sha256.c"; sourceTree = "<group>"; };
|
||||
27FCBDE32D19F9B300485EEE /* pdfio-base-font-widths.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "pdfio-base-font-widths.h"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -162,6 +164,7 @@
|
||||
children = (
|
||||
27CF90432711DFFE00E50FE4 /* pdfio-aes.c */,
|
||||
273440BA263D727800FBFD63 /* pdfio-array.c */,
|
||||
27FCBDE32D19F9B300485EEE /* pdfio-base-font-widths.h */,
|
||||
273440BB263D727800FBFD63 /* pdfio-common.c */,
|
||||
271EA703265B2B1000ACDD39 /* pdfio-content.c */,
|
||||
27F2F05F2710BE92008ECD36 /* pdfio-crypto.c */,
|
||||
@ -205,6 +208,7 @@
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
27FCBDE42D19F9B300485EEE /* pdfio-base-font-widths.h in Headers */,
|
||||
273440CC263D727800FBFD63 /* pdfio.h in Headers */,
|
||||
271EA706265B2B1000ACDD39 /* pdfio-content.h in Headers */,
|
||||
273440C3263D727800FBFD63 /* pdfio-private.h in Headers */,
|
||||
@ -256,7 +260,8 @@
|
||||
273440A8263D6FE200FBFD63 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1300;
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1600;
|
||||
TargetAttributes = {
|
||||
273440AF263D6FE200FBFD63 = {
|
||||
CreatedOnToolsVersion = 12.5;
|
||||
@ -373,9 +378,11 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.1.2;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@ -450,15 +457,15 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.1.2;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
@ -486,6 +493,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RU58A2256H;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -497,6 +505,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RU58A2256H;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -509,6 +518,7 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
@ -525,6 +535,7 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
|
61
pdfio1.def
@ -1,69 +1,20 @@
|
||||
LIBRARY pdfio1
|
||||
VERSION 1.2
|
||||
VERSION 1.5
|
||||
EXPORTS
|
||||
_pdfioArrayDebug
|
||||
_pdfioArrayDelete
|
||||
_pdfioArrayGetValue
|
||||
_pdfioArrayRead
|
||||
_pdfioArrayWrite
|
||||
_pdfioCryptoAESDecrypt
|
||||
_pdfioCryptoAESEncrypt
|
||||
_pdfioCryptoAESInit
|
||||
_pdfioCryptoLock
|
||||
_pdfioCryptoMD5Append
|
||||
_pdfioCryptoMD5Finish
|
||||
_pdfioCryptoMD5Init
|
||||
_pdfioCryptoMakeRandom
|
||||
_pdfioCryptoMakeReader
|
||||
_pdfioCryptoMakeWriter
|
||||
_pdfioCryptoRC4Crypt
|
||||
_pdfioCryptoRC4Init
|
||||
_pdfioCryptoSHA256Append
|
||||
_pdfioCryptoSHA256Finish
|
||||
_pdfioCryptoSHA256Init
|
||||
_pdfioCryptoUnlock
|
||||
_pdfioDictClear
|
||||
_pdfioDictDebug
|
||||
_pdfioDictDelete
|
||||
_pdfioDictGetValue
|
||||
_pdfioDictRead
|
||||
_pdfioDictSetValue
|
||||
_pdfioDictWrite
|
||||
_pdfioFileAddMappedObj
|
||||
_pdfioFileAddPage
|
||||
_pdfioFileConsume
|
||||
_pdfioFileCreateObj
|
||||
_pdfioFileDefaultError
|
||||
_pdfioFileError
|
||||
_pdfioFileFindMappedObj
|
||||
_pdfioFileFlush
|
||||
_pdfioFileGetChar
|
||||
_pdfioFileGets
|
||||
_pdfioFilePeek
|
||||
_pdfioFilePrintf
|
||||
_pdfioFilePuts
|
||||
_pdfioFileRead
|
||||
_pdfioFileSeek
|
||||
_pdfioFileTell
|
||||
_pdfioFileWrite
|
||||
_pdfioObjDelete
|
||||
_pdfioObjGetExtension
|
||||
_pdfioObjLoad
|
||||
_pdfioObjSetExtension
|
||||
_pdfioStreamCreate
|
||||
_pdfioStreamOpen
|
||||
_pdfioStringIsAllocated
|
||||
_pdfioTokenClear
|
||||
_pdfioTokenFlush
|
||||
_pdfioTokenGet
|
||||
_pdfioTokenInit
|
||||
_pdfioTokenPush
|
||||
_pdfioTokenRead
|
||||
_pdfioValueCopy
|
||||
_pdfioValueDebug
|
||||
_pdfioValueDelete
|
||||
_pdfioValueRead
|
||||
_pdfioValueWrite
|
||||
pdfioArrayAppendArray
|
||||
pdfioArrayAppendBinary
|
||||
pdfioArrayAppendBoolean
|
||||
@ -91,6 +42,7 @@ pdfioArrayGetObj
|
||||
pdfioArrayGetSize
|
||||
pdfioArrayGetString
|
||||
pdfioArrayGetType
|
||||
pdfioArrayRemove
|
||||
pdfioContentClip
|
||||
pdfioContentDrawImage
|
||||
pdfioContentFill
|
||||
@ -148,6 +100,7 @@ pdfioContentTextNextLine
|
||||
pdfioContentTextShow
|
||||
pdfioContentTextShowJustified
|
||||
pdfioContentTextShowf
|
||||
pdfioDictClear
|
||||
pdfioDictCopy
|
||||
pdfioDictCreate
|
||||
pdfioDictGetArray
|
||||
@ -155,7 +108,9 @@ pdfioDictGetBinary
|
||||
pdfioDictGetBoolean
|
||||
pdfioDictGetDate
|
||||
pdfioDictGetDict
|
||||
pdfioDictGetKey
|
||||
pdfioDictGetName
|
||||
pdfioDictGetNumPairs
|
||||
pdfioDictGetNumber
|
||||
pdfioDictGetObj
|
||||
pdfioDictGetRect
|
||||
@ -179,9 +134,11 @@ pdfioFileCreate
|
||||
pdfioFileCreateArrayObj
|
||||
pdfioFileCreateFontObjFromBase
|
||||
pdfioFileCreateFontObjFromFile
|
||||
pdfioFileCreateICCObjFromData
|
||||
pdfioFileCreateICCObjFromFile
|
||||
pdfioFileCreateImageObjFromData
|
||||
pdfioFileCreateImageObjFromFile
|
||||
pdfioFileCreateNameObj
|
||||
pdfioFileCreateNumberObj
|
||||
pdfioFileCreateObj
|
||||
pdfioFileCreateOutput
|
||||
@ -190,10 +147,12 @@ pdfioFileCreateStringObj
|
||||
pdfioFileCreateTemporary
|
||||
pdfioFileFindObj
|
||||
pdfioFileGetAuthor
|
||||
pdfioFileGetCatalog
|
||||
pdfioFileGetCreationDate
|
||||
pdfioFileGetCreator
|
||||
pdfioFileGetID
|
||||
pdfioFileGetKeywords
|
||||
pdfioFileGetModificationDate
|
||||
pdfioFileGetName
|
||||
pdfioFileGetNumObjs
|
||||
pdfioFileGetNumPages
|
||||
@ -209,6 +168,7 @@ pdfioFileSetAuthor
|
||||
pdfioFileSetCreationDate
|
||||
pdfioFileSetCreator
|
||||
pdfioFileSetKeywords
|
||||
pdfioFileSetModificationDate
|
||||
pdfioFileSetPermissions
|
||||
pdfioFileSetSubject
|
||||
pdfioFileSetTitle
|
||||
@ -222,6 +182,7 @@ pdfioObjGetArray
|
||||
pdfioObjGetDict
|
||||
pdfioObjGetGeneration
|
||||
pdfioObjGetLength
|
||||
pdfioObjGetName
|
||||
pdfioObjGetNumber
|
||||
pdfioObjGetSubtype
|
||||
pdfioObjGetType
|
||||
|
@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.2.0</version>
|
||||
<version>1.5.1</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
@ -13,10 +13,11 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>PDFio Library for VS2019+</description>
|
||||
<summary>PDFio is a simple C library for reading and writing PDF files. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
||||
<copyright>Copyright © 2019-2024 by Michael R Sweet</copyright>
|
||||
<copyright>Copyright © 2019-2025 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
<dependencies>
|
||||
<dependency id="pdfio_native.redist" version="1.2.0" />
|
||||
<dependency id="pdfio_native.redist" version="1.5.1" />
|
||||
<dependency id="libpng_native.redist" version="1.6.30" />
|
||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native.redist</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.2.0</version>
|
||||
<version>1.5.1</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
@ -13,9 +13,10 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>PDFio Library for VS2019+</description>
|
||||
<summary>PDFio is a simple C library for reading and writing PDF files. This package provides the redistributable content for the PDFio library. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
||||
<copyright>Copyright © 2019-2024 by Michael R Sweet</copyright>
|
||||
<copyright>Copyright © 2019-2025 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
<dependencies>
|
||||
<dependency id="libpng_native.redist" version="1.6.30" />
|
||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
@ -1,95 +0,0 @@
|
||||
//
|
||||
// PDF to text program for PDFio.
|
||||
//
|
||||
// Copyright © 2022 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./pdfiototext FILENAME.pdf > FILENAME.txt
|
||||
//
|
||||
|
||||
#include "pdfio.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Main entry.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // I - Command-line arguments
|
||||
{
|
||||
pdfio_file_t *file; // PDF file
|
||||
size_t i, j, // Looping vars
|
||||
num_pages, // Number of pages
|
||||
num_streams; // Number of streams for page
|
||||
pdfio_obj_t *obj; // Current page object
|
||||
pdfio_stream_t *st; // Current page content stream
|
||||
char buffer[1024]; // String buffer
|
||||
bool first; // First string token?
|
||||
|
||||
|
||||
// Verify command-line arguments...
|
||||
if (argc != 2)
|
||||
{
|
||||
puts("Usage: pdfiototext FILENAME.pdf > FILENAME.txt");
|
||||
return (1);
|
||||
}
|
||||
|
||||
// Open the PDF file...
|
||||
if ((file = pdfioFileOpen(argv[1], NULL, NULL, NULL, NULL)) == NULL)
|
||||
return (1);
|
||||
|
||||
// printf("%s: %u pages\n", argv[1], (unsigned)pdfioFileGetNumPages(file));
|
||||
|
||||
// Try grabbing content from all of the pages...
|
||||
for (i = 0, num_pages = pdfioFileGetNumPages(file); i < num_pages; i ++)
|
||||
{
|
||||
if ((obj = pdfioFileGetPage(file, i)) == NULL)
|
||||
continue;
|
||||
|
||||
num_streams = pdfioPageGetNumStreams(obj);
|
||||
|
||||
// printf("%s: page%u=%p, num_streams=%u\n", argv[1], (unsigned)i, obj, (unsigned)num_streams);
|
||||
|
||||
for (j = 0; j < num_streams; j ++)
|
||||
{
|
||||
if ((st = pdfioPageOpenStream(obj, j, true)) == NULL)
|
||||
continue;
|
||||
|
||||
// printf("%s: page%u st%u=%p\n", argv[1], (unsigned)i, (unsigned)j, st);
|
||||
|
||||
first = true;
|
||||
while (pdfioStreamGetToken(st, buffer, sizeof(buffer)))
|
||||
{
|
||||
if (buffer[0] == '(')
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
putchar(' ');
|
||||
|
||||
fputs(buffer + 1, stdout);
|
||||
}
|
||||
else if (!strcmp(buffer, "Td") || !strcmp(buffer, "TD") || !strcmp(buffer, "T*") || !strcmp(buffer, "\'") || !strcmp(buffer, "\""))
|
||||
{
|
||||
putchar('\n');
|
||||
first = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!first)
|
||||
putchar('\n');
|
||||
|
||||
pdfioStreamClose(st);
|
||||
}
|
||||
}
|
||||
|
||||
pdfioFileClose(file);
|
||||
|
||||
return (0);
|
||||
}
|
18
runtests.bat
Normal file
@ -0,0 +1,18 @@
|
||||
:: Script to run unit test program
|
||||
::
|
||||
:: Usage:
|
||||
::
|
||||
:: .\runtests.bat x64\{Debug|Release}
|
||||
::
|
||||
|
||||
:: Copy dependent DLLs to the named build directory
|
||||
echo Copying DLLs
|
||||
copy packages\libpng_native.redist.1.6.30\build\native\bin\x64\Debug\*.dll %1
|
||||
copy packages\libpng_native.redist.1.6.30\build\native\bin\x64\Release\*.dll %1
|
||||
copy packages\zlib_native.redist.1.2.11\build\native\bin\x64\Debug\*.dll %1
|
||||
copy packages\zlib_native.redist.1.2.11\build\native\bin\x64\Release\*.dll %1
|
||||
|
||||
:: Run unit test program
|
||||
echo Running %1\testpdfio.exe
|
||||
cd %1
|
||||
testpdfio.exe
|
@ -1,3 +1,7 @@
|
||||
https://www.color.org/chardata/rgb/rommrgb.xalter
|
||||
|
||||
Copyright © 2006 Hewlett-Packard
|
||||
|
||||
Terms of use
|
||||
|
||||
This profile is made available by ICC, and may be copied, distributed, embedded, made, used, and sold without restriction. Altered versions of this profile shall have the original identification and copyright information removed and shall not be misrepresented as the original profile.
|
||||
|
9
testfiles/pngsuite-LICENSE.txt
Normal file
@ -0,0 +1,9 @@
|
||||
PngSuite
|
||||
--------
|
||||
|
||||
Permission to use, copy, modify and distribute these images for any
|
||||
purpose and without fee is hereby granted.
|
||||
|
||||
|
||||
(c) Willem van Schaik, 1996, 2011
|
||||
|
BIN
testfiles/pngsuite/basi0g01.png
Normal file
After Width: | Height: | Size: 217 B |
BIN
testfiles/pngsuite/basi0g02.png
Normal file
After Width: | Height: | Size: 154 B |
BIN
testfiles/pngsuite/basi0g04.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
testfiles/pngsuite/basi0g08.png
Normal file
After Width: | Height: | Size: 254 B |
BIN
testfiles/pngsuite/basi2c08.png
Normal file
After Width: | Height: | Size: 315 B |
BIN
testfiles/pngsuite/basi3p01.png
Normal file
After Width: | Height: | Size: 132 B |
BIN
testfiles/pngsuite/basi3p02.png
Normal file
After Width: | Height: | Size: 193 B |
BIN
testfiles/pngsuite/basi3p04.png
Normal file
After Width: | Height: | Size: 327 B |
BIN
testfiles/pngsuite/basi3p08.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
testfiles/pngsuite/basi4a08.png
Normal file
After Width: | Height: | Size: 214 B |
BIN
testfiles/pngsuite/basi6a08.png
Normal file
After Width: | Height: | Size: 361 B |
BIN
testfiles/pngsuite/basn0g01.png
Normal file
After Width: | Height: | Size: 164 B |
BIN
testfiles/pngsuite/basn0g02.png
Normal file
After Width: | Height: | Size: 104 B |
BIN
testfiles/pngsuite/basn0g04.png
Normal file
After Width: | Height: | Size: 145 B |
BIN
testfiles/pngsuite/basn0g08.png
Normal file
After Width: | Height: | Size: 138 B |
BIN
testfiles/pngsuite/basn2c08.png
Normal file
After Width: | Height: | Size: 145 B |
BIN
testfiles/pngsuite/basn3p01.png
Normal file
After Width: | Height: | Size: 112 B |
BIN
testfiles/pngsuite/basn3p02.png
Normal file
After Width: | Height: | Size: 146 B |
BIN
testfiles/pngsuite/basn3p04.png
Normal file
After Width: | Height: | Size: 216 B |
BIN
testfiles/pngsuite/basn3p08.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
testfiles/pngsuite/basn4a08.png
Normal file
After Width: | Height: | Size: 126 B |
BIN
testfiles/pngsuite/basn6a08.png
Normal file
After Width: | Height: | Size: 184 B |
BIN
testfiles/pngsuite/exif2c08.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
testfiles/pngsuite/g03n2c08.png
Normal file
After Width: | Height: | Size: 370 B |
BIN
testfiles/pngsuite/g03n3p04.png
Normal file
After Width: | Height: | Size: 214 B |
BIN
testfiles/pngsuite/g04n2c08.png
Normal file
After Width: | Height: | Size: 377 B |
BIN
testfiles/pngsuite/g04n3p04.png
Normal file
After Width: | Height: | Size: 219 B |
BIN
testfiles/pngsuite/g05n2c08.png
Normal file
After Width: | Height: | Size: 350 B |
BIN
testfiles/pngsuite/g05n3p04.png
Normal file
After Width: | Height: | Size: 206 B |
BIN
testfiles/pngsuite/g07n2c08.png
Normal file
After Width: | Height: | Size: 340 B |
BIN
testfiles/pngsuite/g07n3p04.png
Normal file
After Width: | Height: | Size: 207 B |
BIN
testfiles/pngsuite/g10n2c08.png
Normal file
After Width: | Height: | Size: 285 B |
BIN
testfiles/pngsuite/g10n3p04.png
Normal file
After Width: | Height: | Size: 214 B |
BIN
testfiles/pngsuite/g25n2c08.png
Normal file
After Width: | Height: | Size: 405 B |
BIN
testfiles/pngsuite/g25n3p04.png
Normal file
After Width: | Height: | Size: 215 B |
BIN
testfiles/pngsuite/s02i3p01.png
Normal file
After Width: | Height: | Size: 114 B |
BIN
testfiles/pngsuite/s02n3p01.png
Normal file
After Width: | Height: | Size: 115 B |
BIN
testfiles/pngsuite/s03i3p01.png
Normal file
After Width: | Height: | Size: 118 B |
BIN
testfiles/pngsuite/s03n3p01.png
Normal file
After Width: | Height: | Size: 120 B |
BIN
testfiles/pngsuite/s04i3p01.png
Normal file
After Width: | Height: | Size: 126 B |