52 Commits

Author SHA1 Message Date
16c8b830b8 Add pdfioFileCreateNumber/StringObj functions (Issue #14) 2023-12-05 08:16:41 -05:00
7ff051fc8b Add pdfioContentTextNewLineShow/f functions (Issue #24) 2023-12-05 07:49:49 -05:00
927452d1eb Changelog and exports updates. 2023-12-04 21:22:13 -05:00
f1ad982fd1 Update docos. 2023-12-04 21:21:18 -05:00
c188cb8dad Finish implementation of pdfioContentTextMeasure (Issue #17) 2023-12-04 21:20:51 -05:00
4919783da5 Save work on string measure support (Issue #17) 2023-12-04 18:54:33 -05:00
86281750e5 Fix man page installation to use mandir (Issue #55) 2023-12-04 08:50:28 -05:00
d92b72ed02 Add math library. 2023-12-03 20:26:27 -05:00
a195c023af Fix CI scripts. 2023-12-03 20:20:23 -05:00
43000ff01f Fix up targets. 2023-12-03 19:56:25 -05:00
c6f17cc20f Fix some warnings. 2023-12-03 19:23:36 -05:00
41146adbdf Adopt autoconf (Issue #54) 2023-12-03 19:16:34 -05:00
cd80c3037d Prep for 1.1.4 release. 2023-12-03 16:55:57 -05:00
97934ab995 Add ToUnicode map. 2023-11-19 20:49:30 -05:00
088646e1cf Drop the FEFF prefix on Unicode strings. 2023-11-19 07:30:17 -05:00
3f0aad7564 Fix another bug in the CMAPv4 code, and a bug in the unit test program. 2023-11-19 07:06:35 -05:00
d36df63b57 Fix a TrueType CMAP decoding bug and add a NotoSans-Regular test page. 2023-11-18 22:15:52 -05:00
a5dfac7495 Bump version. 2023-11-18 18:23:22 -05:00
0258384d53 Range check encrypted string length (Issue #52) 2023-11-18 18:22:11 -05:00
9fec2195d0 Update changelog. 2023-11-15 10:14:02 -05:00
8ccbdaed94 Update documentation. 2023-11-15 09:28:57 -05:00
4804db38a5 Fix missing ivlen initializer for 40-bit RC4 (Issue #51) 2023-11-15 08:43:07 -05:00
ddd984215a Save work (debug printfs, etc.) 2023-11-15 08:38:47 -05:00
efe7c01015 Fix typo and 'make debug'. 2023-11-14 18:38:26 -05:00
600fa4ce59 Fix Unicode font handling (Issue #16) 2023-11-14 18:19:34 -05:00
688810f143 Save work. 2023-11-13 16:18:02 -05:00
858cc101b6 Save work. 2023-11-13 13:39:06 -05:00
43114f43bf Bump version. 2023-10-10 10:22:27 -04:00
c4abceef79 Make Visual Studio compiler happy. 2023-10-10 07:24:27 -04:00
2e91e05d7b Allow "compound" filters that consist of a single named filter (Issue #47) 2023-10-10 07:14:12 -04:00
7e3db6b639 Merge pull request #48 from crystalidea/master
added windows.h header for GetTempPathA
2023-10-10 07:07:46 -04:00
acb6b66bdb added windows.h header for GetTempPathA 2023-10-10 09:12:03 +02:00
b0a66eef78 Fix reading of PDF files from Crystal Reports (Issue #45) 2023-10-09 10:04:20 -04:00
ed88322496 Debug logging, work in progress for Unicode text support. 2023-10-07 12:05:18 -04:00
59959bf0e5 Merge TTF changes to fix off-by-one error. 2023-10-06 16:44:20 -04:00
19c45871fa Update pdfioContentSetDashPattern to support setting solid line styles (Issue #41) 2023-10-06 15:47:27 -04:00
b0e4646f9d Rework CR/LF skip code to be more consistent. 2023-10-06 14:41:55 -04:00
12ef2fe2c3 Remove LGTM badges. 2023-10-06 14:40:40 -04:00
4630060ee7 Update security reporting and contribution text. 2023-10-06 14:40:28 -04:00
74a6fb1860 Get rid of superfluous comments. 2023-10-06 14:40:08 -04:00
a3ea0a99ff Cleanup spacing and comments. 2023-10-06 14:39:42 -04:00
fdfa700442 Update ignored files. 2023-10-06 14:39:10 -04:00
d759baf11e Bump version and put PDFIO_VERSION definition in the pdfio.h header. 2023-10-06 14:38:38 -04:00
7f6ffcda22 Fix a couple issues with parsing PDF files produced by Microsoft Reporting
Services (Issue #46)

- Odd cross-reference stream containing 3-byte generation number field for this
  16-bit value
- Odd empty hex strings
2023-10-06 10:46:30 -04:00
87ca4db73f Clean up private header. 2023-10-02 05:27:40 -04:00
a83f7f50ff Allow extra whitespace/newlines after stream tokens (Issue #40) 2023-10-02 05:06:33 -04:00
6a4ce57d09 Bump versions for Mac/Windows project files. 2023-03-20 10:40:25 -04:00
d4c594cec4 Bump copyright in readme. 2023-03-20 10:22:19 -04:00
35c674b633 Fix another build issue. 2023-03-20 10:11:05 -04:00
97d4955666 Fix potential denial-of-service in flate stream code. 2023-03-20 09:27:19 -04:00
e138232a93 Fix build error due to mismatched function declarations. 2023-03-20 08:19:31 -04:00
8d8225f4a1 Fix release date. 2023-02-07 17:10:48 -05:00
40 changed files with 11358 additions and 630 deletions

View File

@ -9,23 +9,26 @@ on:
jobs: jobs:
build-linux: build-linux:
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - name: Checkout PDFio sources
- name: update build environment uses: actions/checkout@v4
- name: Update Build Environment
run: sudo apt-get update --fix-missing -y run: sudo apt-get update --fix-missing -y
- name: install prerequisites - name: Install Prerequisites
run: sudo apt-get install -y cppcheck zlib1g-dev run: sudo apt-get install -y cppcheck zlib1g-dev
- name: make - name: Configure PDFio
run: ./configure --enable-debug --enable-sanitizer --enable-maintainer
- name: Build PDFio
run: make "COMMONFLAGS=-g -fsanitize=address" run: make "COMMONFLAGS=-g -fsanitize=address"
- name: test - name: Test PDFio
env: env:
ASAN_OPTIONS: leak_check_at_exit=false ASAN_OPTIONS: leak_check_at_exit=false
run: make test run: make test
- name: clang static analyzer - name: Run Clang Static Analyzer
run: make CC=clang "GHA_ERROR=::error::" clang run: make CC=clang "GHA_ERROR=::error::" clang
- name: cppcheck - name: Run cppcheck
run: make "GHA_ERROR=::error::" cppcheck run: make "GHA_ERROR=::error::" cppcheck
build-macos: build-macos:
@ -33,12 +36,15 @@ jobs:
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v2 - name: Checkout PDFio sources
- name: make uses: actions/checkout@v4
- name: Configure PDFio
run: ./configure --enable-debug --enable-sanitizer --enable-maintainer
- name: Build PDFio
run: make "COMMONFLAGS=-g -fsanitize=address" run: make "COMMONFLAGS=-g -fsanitize=address"
- name: test - name: Test PDFio
run: make test run: make test
- name: clang static analyzer - name: Run Clang Static Analyzer
run: make CC=clang "GHA_ERROR=::error::" clang run: make CC=clang "GHA_ERROR=::error::" clang
build-windows: build-windows:
@ -46,10 +52,11 @@ jobs:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v2 - name: Checkout PDFio sources
- name: setup-msbuild uses: actions/checkout@v4
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v1.0.2 uses: microsoft/setup-msbuild@v1.0.2
- name: nuget restore - name: Nuget Restore
run: nuget restore pdfio.sln run: nuget restore pdfio.sln
- name: msbuild - name: Build PDFio
run: msbuild pdfio.sln run: msbuild pdfio.sln

View File

@ -23,15 +23,15 @@ jobs:
language: [ cpp ] language: [ cpp ]
steps: steps:
- name: Checkout - name: Checkout PDFio sources
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
- name: Update build environment - name: Update Build Environment
run: sudo apt-get update --fix-missing -y run: sudo apt-get update --fix-missing -y
- name: Install prerequisites - name: Install Prerequisites
run: sudo apt-get install -y zlib1g-dev run: sudo apt-get install -y zlib1g-dev
- name: Initialize CodeQL - name: Initialize CodeQL

View File

@ -7,10 +7,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: Coverity environment: Coverity
steps: steps:
- uses: actions/checkout@v2 - name: Checkout PDFio sources
- name: update build environment uses: actions/checkout@v4
- name: Update Build Environment
run: sudo apt-get update --fix-missing -y run: sudo apt-get update --fix-missing -y
- name: install prerequisites - name: Install Prerequisites
run: sudo apt-get install -y zlib1g-dev run: sudo apt-get install -y zlib1g-dev
- name: Download Coverity Build Tool - name: Download Coverity Build Tool
run: | run: |
@ -20,11 +21,15 @@ jobs:
env: env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
- name: Build with cov-build - name: Configure PDFio
run: ./configure --enable-debug --enable-maintainer
- name: Build PDFio with cov-build
run: | run: |
export PATH=`pwd`/cov-analysis-linux64/bin:$PATH export PATH=`pwd`/cov-analysis-linux64/bin:$PATH
cov-build --dir cov-int make cov-build --dir cov-int make
- name: Submit the result to Coverity Scan
- name: Submit the Result to Coverity Scan
run: | run: |
tar czvf cov.tgz cov-int tar czvf cov.tgz cov-int
curl \ curl \

8
.gitignore vendored
View File

@ -5,10 +5,18 @@
*.so.1 *.so.1
/.vs /.vs
/afl-output /afl-output
/autom4te.cache
/config.log
/config.status
/doc/pdfio.epub /doc/pdfio.epub
/Makefile
/packages /packages
/pdfio.pc
/pdfio.xcodeproj/xcshareddata /pdfio.xcodeproj/xcshareddata
/pdfio-*.tar.gz*
/pdfio-*.zip*
/pdfiototext /pdfiototext
/testpdfio /testpdfio
/testpdfio-*.pdf /testpdfio-*.pdf
/testttf
/x64 /x64

View File

@ -2,7 +2,58 @@ Changes in PDFio
================ ================
v1.1.0 (February 3, 2023) v1.2.0 (Month DD, YYYY)
-----------------------
- Added `pdfioFileCreateNumberObj` and `pdfioFileCreateStringObj` functions
(Issue #14)
- Added `pdfioContentTextMeasure` function (Issue #17)
- Added `pdfioContentTextNewLineShow` and `pdfioContentTextNewLineShowf`
functions (Issue #24)
- Renamed `pdfioContentTextNextLine` to `pdfioContentTextNewLine`.
- Now use autoconf to configure the PDFio sources (Issue #54)
v1.1.4 (December 3, 2023)
-------------------------
- Fixed detection of encrypted strings that are too short (Issue #52)
- Fixed a TrueType CMAP decoding bug.
- Fixed a text rendering issue for Asian text.
- Added a ToUnicode map for Unicode text to support text copying.
v1.1.3 (November 15, 2023)
--------------------------
- Fixed Unicode font support (Issue #16)
- Fixed missing initializer for 40-bit RC4 encryption (Issue #51)
v1.1.2 (October 10, 2023)
-------------------------
- Updated `pdfioContentSetDashPattern` to support setting a solid (0 length)
dash pattern (Issue #41)
- Fixed an issue with broken PDF files containing extra CR and/or LF separators
after the object stream token (Issue #40)
- Fixed an issue with PDF files produced by Crystal Reports (Issue #45)
- Fixed an issue with PDF files produced by Microsoft Reporting Services
(Issue #46)
- Fixed support for compound filters where the filter array consists of a
single named filter (Issue #47)
- Fixed builds on Windows - needed windows.h header for temporary files
(Issue #48)
v1.1.1 (March 20, 2023)
-----------------------
- CVE-2023-28428: Fixed a potential denial-of-service with corrupt PDF files.
- Fixed a few build issues.
v1.1.0 (February 6, 2023)
------------------------- -------------------------
- CVE-2023-24808: Fixed a potential denial-of-service with corrupt PDF files. - CVE-2023-24808: Fixed a potential denial-of-service with corrupt PDF files.

View File

@ -118,7 +118,7 @@ the source file and the copyright and licensing notice:
// //
// Description of file contents. // Description of file contents.
// //
// Copyright YYYY by AUTHOR. // Copyright © YYYY by AUTHOR.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -330,7 +330,7 @@ typedef, for example:
All constant names are uppercase with underscores between words, e.g., All constant names are uppercase with underscores between words, e.g.,
`PDFIO_THIS_CONSTANT`, `PDFIO_THAT_CONSTANT`, etc. Constants begin with the `PDFIO_THIS_CONSTANT`, `PDFIO_THAT_CONSTANT`, etc. Constants begin with the
"PDFio\_" prefix to avoid conflicts with system constants. Private constants "PDFIO\_" prefix to avoid conflicts with system constants. Private constants
start with an underscore, e.g., `_PDFIO_THIS_CONSTANT`, start with an underscore, e.g., `_PDFIO_THIS_CONSTANT`,
`_PDFIO_THAT_CONSTANT`, etc. `_PDFIO_THAT_CONSTANT`, etc.
@ -369,11 +369,12 @@ extensions MUST NOT be used.
The following variables are defined in the makefile: The following variables are defined in the makefile:
- `AR`; the static library archiver command, - `AR`; the static library archiver command,
- `ARFLAGS`; options for the static library archiver command, - `ARFLAGS`; options for the static library archiver,
- `CC`; the C compiler command, - `CC`; the C compiler command,
- `CFLAGS`; options for the C compiler command, - `CFLAGS`; options for the C compiler,
- `CODESIGN_IDENTITY`: the code signing identity, - `CODESIGN_IDENTITY`: the code signing identity,
- `COMMONFLAGS`; common compiler optimization options, - `COMMONFLAGS`; common compiler optimization options,
- `CPPFLAGS`; options for the C preprocessor,
- `DESTDIR`/`DSTROOT`: the destination root directory when installing. - `DESTDIR`/`DSTROOT`: the destination root directory when installing.
- `DSO`; the shared library building command, - `DSO`; the shared library building command,
- `DSOFLAGS`; options for the shared library building command, - `DSOFLAGS`; options for the shared library building command,
@ -395,4 +396,5 @@ The following standard targets are defined in the makefile:
with debug printfs and the clang address sanitizer enabled. with debug printfs and the clang address sanitizer enabled.
- `install`; installs all distribution files in their corresponding locations. - `install`; installs all distribution files in their corresponding locations.
- `install-shared`; same as `install` but also installs the shared library. - `install-shared`; same as `install` but also installs the shared library.
- `macos`; same as `all` but creates a Universal Binary (X64 + ARM64).
- `test`; runs the unit test program, building it as needed. - `test`; runs the unit test program, building it as needed.

224
Makefile
View File

@ -1,224 +0,0 @@
#
# Makefile for PDFio.
#
# Copyright © 2021-2023 by Michael R Sweet.
#
# Licensed under Apache License v2.0. See the file "LICENSE" for more
# information.
#
# POSIX makefile
.POSIX:
# Build silently
.SILENT:
# Variables
AR = ar
ARFLAGS = cr
CC = cc
CFLAGS =
CODESIGN_IDENTITY = Developer ID
COMMONFLAGS = -Os -g
#COMMONFLAGS = -O0 -g -fsanitize=address
CPPFLAGS = '-DPDFIO_VERSION="$(VERSION)"'
DESTDIR = $(DSTROOT)
DSO = cc
DSOFLAGS =
DSONAME =
LDFLAGS =
LIBS = -lm -lz
RANLIB = ranlib
VERSION = 1.1.0
prefix = /usr/local
# Base rules
.SUFFIXES: .c .h .o
.c.o:
echo Compiling $<...
$(CC) $(CFLAGS) $(CPPFLAGS) $(COMMONFLAGS) -c $<
# Files
PUBHEADERS = \
pdfio.h \
pdfio-content.h
PUBOBJS = \
pdfio-aes.o \
pdfio-array.o \
pdfio-common.o \
pdfio-content.o \
pdfio-crypto.o \
pdfio-dict.o \
pdfio-file.o \
pdfio-md5.o \
pdfio-object.o \
pdfio-page.o \
pdfio-rc4.o \
pdfio-sha256.o \
pdfio-stream.o \
pdfio-string.o \
pdfio-token.o \
pdfio-value.o
LIBOBJS = \
$(PUBOBJS) \
ttf.o
OBJS = \
$(LIBOBJS) \
pdfiototext.o \
testpdfio.o
TARGETS = \
$(DSONAME) \
libpdfio.a \
pdfiototext \
testpdfio
# Make everything
all: $(TARGETS)
all-shared:
if test `uname` = Darwin; then \
$(MAKE) DSONAME="libpdfio.1.dylib" -$(MAKEFLAGS) all; \
else \
$(MAKE) COMMONFLAGS="-g -Os -fPIC" DSONAME="libpdfio.so.1" -$(MAKEFLAGS) all; \
fi
debug:
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-g -fsanitize=address -DDEBUG=1" clean all
macos:
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-Os -mmacosx-version-min=10.14 -arch x86_64 -arch arm64" clean all
# Clean everything
clean:
rm -f $(TARGETS) $(OBJS)
# Install everything
install: $(TARGETS)
echo Installing header files to $(DESTDIR)$(prefix)/include...
-mkdir -p $(DESTDIR)$(prefix)/include
cp $(PUBHEADERS) $(DESTDIR)$(prefix)/include
echo Installing library files to $(DESTDIR)$(prefix)/lib...
-mkdir -p $(DESTDIR)$(prefix)/lib
cp libpdfio.a $(DESTDIR)$(prefix)/lib
$(RANLIB) $(DESTDIR)$(prefix)/lib/libpdfio.a
if test "x$(DSONAME)" = xlibpdfio.so.1; then \
cp $(DSONAME) $(DESTDIR)$(prefix)/lib; \
ln -sf libpdfio.so.1 $(DESTDIR)$(prefix)/lib/libpdfio.so; \
elif test "x$(DSONAME)" = xlibpdfio.1.dylib; then \
cp $(DSONAME) $(DESTDIR)$(prefix)/lib; \
codesign -s "$(CODESIGN_IDENTITY)" -o runtime --timestamp $(DESTDIR)$(prefix)/lib/libpdfio.1.dylib; \
ln -sf libpdfio.1.dylib $(DESTDIR)$(prefix)/lib/libpdfio.dylib; \
fi
echo Installing pkg-config files to $(DESTDIR)$(prefix)/lib/pkgconfig...
-mkdir -p $(DESTDIR)$(prefix)/lib/pkgconfig
echo 'prefix="$(prefix)"' >$(DESTDIR)$(prefix)/lib/pkgconfig/pdfio.pc
echo 'Version: $(VERSION)' >>$(DESTDIR)$(prefix)/lib/pkgconfig/pdfio.pc
cat pdfio.pc.in >>$(DESTDIR)$(prefix)/lib/pkgconfig/pdfio.pc
echo Installing documentation to $(DESTDIR)$(prefix)/share/doc/pdfio...
-mkdir -p $(DESTDIR)$(prefix)/share/doc/pdfio
cp doc/pdfio.html doc/pdfio-512.png LICENSE NOTICE $(DESTDIR)$(prefix)/share/doc/pdfio
echo Installing man page to $(DESTDIR)$(prefix)/share/man/man3...
-mkdir -p $(DESTDIR)$(prefix)/share/man/man3
cp doc/pdfio.3 $(DESTDIR)$(prefix)/share/man/man3
install-shared:
if test `uname` = Darwin; then \
$(MAKE) DSONAME="libpdfio.1.dylib" -$(MAKEFLAGS) install; \
else \
$(MAKE) DSONAME="libpdfio.so.1" -$(MAKEFLAGS) install; \
fi
# Test everything
test: testpdfio
./testpdfio
valgrind: testpdfio
valgrind --leak-check=full ./testpdfio
# pdfio library
libpdfio.a: $(LIBOBJS)
echo Archiving $@...
$(AR) $(ARFLAGS) $@ $(LIBOBJS)
$(RANLIB) $@
libpdfio.so.1: $(LIBOBJS)
echo Linking $@...
$(CC) $(DSOFLAGS) $(COMMONFLAGS) -shared -o $@ -Wl,-soname,$@ $(LIBOBJS) $(LIBS)
libpdfio.1.dylib: $(LIBOBJS)
echo Linking $@...
$(CC) $(DSOFLAGS) $(COMMONFLAGS) -dynamiclib -o $@ -install_name $(prefix)/lib/$@ -current_version $(VERSION) -compatibility_version 1.0 $(LIBOBJS) $(LIBS)
# pdfio1.def (Windows DLL exports file...)
#
# I'd love to use __declspec(dllexport) but MS puts it before the function
# declaration instead of after like everyone else, and it breaks Codedoc and
# other tools I rely on...
pdfio1.def: $(LIBOBJS) Makefile
echo Generating $@...
echo "LIBRARY pdfio1" >$@
echo "VERSION 1.0" >>$@
echo "EXPORTS" >>$@
nm $(LIBOBJS) 2>/dev/null | grep "T _" | awk '{print $$3}' | \
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) $(COMMONFLAGS) -o $@ pdfiototext.o libpdfio.a $(LIBS)
# pdfio test program
testpdfio: testpdfio.o libpdfio.a
echo Linking $@...
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
# Dependencies
$(OBJS): pdfio.h pdfio-private.h Makefile
pdfio-content.o: pdfio-content.h ttf.h
ttf.o: ttf.h
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
DOCFLAGS = \
--author "Michael R Sweet" \
--copyright "Copyright (c) 2021-2022 by Michael R Sweet" \
--docversion $(VERSION)
.PHONY: doc
doc:
echo Generating documentation...
codedoc $(DOCFLAGS) --title "PDFio Programming Manual v$(VERSION)" $(PUBHEADERS) $(PUBOBJS:.o=.c) --body doc/pdfio.md --coverimage doc/pdfio-512.png pdfio.xml >doc/pdfio.html
codedoc $(DOCFLAGS) --title "PDFio Programming Manual v$(VERSION)" --body doc/pdfio.md --coverimage doc/pdfio-epub.png pdfio.xml --epub doc/pdfio.epub
codedoc $(DOCFLAGS) --title "pdf read/write library" --man pdfio --section 3 --body doc/pdfio.md pdfio.xml >doc/pdfio.3
rm -f pdfio.xml
# Fuzz-test the library <>
.PHONY: afl
afl:
$(MAKE) -$(MAKEFLAGS) CC="afl-clang-fast" COMMONFLAGS="-g" clean all
test afl-output || rm -rf afl-output
afl-fuzz -x afl-pdf.dict -i afl-input -o afl-output -V 600 -e pdf -t 5000 ./testpdfio @@
# Analyze code with the Clang static analyzer <https://clang-analyzer.llvm.org>
clang:
clang $(CPPFLAGS) --analyze $(OBJS:.o=.c) 2>clang.log
rm -rf $(OBJS:.o=.plist)
test -s clang.log && (echo "$(GHA_ERROR)Clang detected issues."; echo ""; cat clang.log; exit 1) || exit 0
# 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
test -s cppcheck.log && (echo "$(GHA_ERROR)Cppcheck detected issues."; echo ""; cat cppcheck.log; exit 1) || exit 0

259
Makefile.in Normal file
View File

@ -0,0 +1,259 @@
#
# Makefile for PDFio.
#
# Copyright © 2021-2023 by Michael R Sweet.
#
# Licensed under Apache License v2.0. See the file "LICENSE" for more
# information.
#
# POSIX makefile
.POSIX:
# Build silently
.SILENT:
# Version number...
PDFIO_VERSION = @PDFIO_VERSION@
PDFIO_VERSION_MAJOR = @PDFIO_VERSION_MAJOR@
PDFIO_VERSION_MINOR = @PDFIO_VERSION_MINOR@
# Programs and options...
AR = @AR@
ARFLAGS = @ARFLAGS@
CC = @CC@
CFLAGS = @CFLAGS@ $(CPPFLAGS) $(OPTIM) $(WARNINGS)
CODE_SIGN = @CODE_SIGN@
CODESIGN_IDENTITY = -
CPPFLAGS = @CPPFLAGS@
CSFLAGS = -s "$(CODESIGN_IDENTITY)" @CSFLAGS@ --timestamp
DSOFLAGS = @DSOFLAGS@ $(CFLAGS)
INSTALL = @INSTALL@
LDFLAGS = @LDFLAGS@ $(OPTIM)
LIBS = @LIBS@ -lm
LN = @LN@
OPTIM = @OPTIM@
RANLIB = @RANLIB@
RM = @RM@ -f
RMDIR = @RMDIR@
SHELL = /bin/sh
WARNINGS = @WARNINGS@
# Targets
LIBPDFIO = @LIBPDFIO@
LIBPDFIO_STATIC = @LIBPDFIO_STATIC@
# Directories...
bindir = @bindir@
datadir = @datadir@
datarootdir = @datarootdir@
exec_prefix = @exec_prefix@
includedir = @includedir@
infodir = @infodir@
libdir = @libdir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
mandir = @mandir@
oldincludedir = @oldincludedir@
prefix = @prefix@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
top_srcdir = @top_srcdir@
BUILDROOT = $(DSTROOT)$(RPM_BUILD_ROOT)$(DESTDIR)
# Build commands...
.SUFFIXES: .c .h .o
.c.o:
echo Compiling $<...
$(CC) $(CFLAGS) -c -o $@ $<
# Files
PUBHEADERS = \
pdfio.h \
pdfio-content.h
PUBOBJS = \
pdfio-aes.o \
pdfio-array.o \
pdfio-common.o \
pdfio-content.o \
pdfio-crypto.o \
pdfio-dict.o \
pdfio-file.o \
pdfio-md5.o \
pdfio-object.o \
pdfio-page.o \
pdfio-rc4.o \
pdfio-sha256.o \
pdfio-stream.o \
pdfio-string.o \
pdfio-token.o \
pdfio-value.o
LIBOBJS = \
$(PUBOBJS) \
ttf.o
OBJS = \
$(LIBOBJS) \
pdfiototext.o \
testpdfio.o \
testttf.o
TARGETS = \
$(LIBPDFIO) \
$(LIBPDFIO_STATIC) \
pdfiototext \
testpdfio \
testttf
# Make everything
all: $(TARGETS)
# Clean everything
clean:
rm -f $(TARGETS) $(OBJS)
# Install everything
install: $(TARGETS)
echo Installing header files to $(BUILDROOT)$(includedir)...
$(INSTALL) -d -m 755 $(BUILDROOT)$(includedir)
for file in $(PUBHEADERS); do \
$(INSTALL) -c -m 644 $$file $(BUILDROOT)$(includedir); \
done
echo Installing library files to $(BUILDROOT)$(libdir)...
$(INSTALL) -d -m 755 $(BUILDROOT)$(libdir)
if test "x$(LIBPDFIO_STATIC)" != x; then \
$(INSTALL) -c -m 644 $(LIBPDFIO_STATIC) $(BUILDROOT)$(libdir); \
$(RANLIB) $(BUILDROOT)$(libdir)/$(LIBPDFIO_STATIC); \
fi
if test "x$(LIBPDFIO)" = xlibpdfio.so.1; then \
$(INSTALL) -c -m 755 libpdfio.so.1 $(BUILDROOT)$(libdir); \
ln -sf libpdfio.so.1 $(BUILDROOT)$(libdir)/libpdfio.so; \
elif test "x$(LIBPDFIO)" = xlibpdfio.1.dylib; then \
$(INSTALL) -c -m 755 libpdfio.1.dylib $(BUILDROOT)$(libdir); \
codesign -s "$(CODESIGN_IDENTITY)" -o runtime --timestamp $(BUILDROOT)$(libdir)/libpdfio.1.dylib; \
ln -sf libpdfio.1.dylib $(BUILDROOT)$(libdir)/libpdfio.dylib; \
else \
$(INSTALL) -c -m 644 $(LIBPDFIO) $(BUILDROOT)$(libdir); \
$(RANLIB) $(BUILDROOT)$(libdir)/$(LIBPDFIO); \
fi
echo Installing pkg-config files to $(BUILDROOT)$(libdir)/pkgconfig...
$(INSTALL) -d -m 755 $(BUILDROOT)$(libdir)/pkgconfig
$(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; \
done
echo Installing man page to $(BUILDROOT)$(mandir)/man3...
$(INSTALL) -d -m 755 $(BUILDROOT)$(mandir)/man3
$(INSTALL) -c -m 644 doc/pdfio.3 $(BUILDROOT)$(mandir)/man3
# Test everything
test: testpdfio testttf
./testttf 2>test.log
./testpdfio 2>test.log
valgrind: testpdfio
valgrind --leak-check=full ./testpdfio
# pdfio library
libpdfio.a: $(LIBOBJS)
echo Archiving $@...
$(AR) $(ARFLAGS) $@ $(LIBOBJS)
$(RANLIB) $@
libpdfio.so.1: $(LIBOBJS)
echo Linking $@...
$(CC) $(DSOFLAGS) -shared -o $@ -Wl,-soname,$@ $(LIBOBJS) $(LIBS)
libpdfio.1.dylib: $(LIBOBJS)
echo Linking $@...
$(CC) $(DSOFLAGS) -dynamiclib -o $@ -install_name $(libdir)/$@ -current_version $(PDFIO_VERSION_MAJOR).$(PDFIO_VERSION_MINOR) -compatibility_version 1.0 $(LIBOBJS) $(LIBS)
# pdfio1.def (Windows DLL exports file...)
#
# I'd love to use __declspec(dllexport) but MS puts it before the function
# declaration instead of after like everyone else, and it breaks Codedoc and
# other tools I rely on...
pdfio1.def: $(LIBOBJS) Makefile
echo Generating $@...
echo "LIBRARY pdfio1" >$@
echo "VERSION $(PDFIO_VERSION_MAJOR).$(PDFIO_VERSION_MINOR)" >>$@
echo "EXPORTS" >>$@
nm $(LIBOBJS) 2>/dev/null | grep "T _" | awk '{print $$3}' | \
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 $@...
$(CC) $(LDFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
# TTF test program
testttf: ttf.o testttf.o
echo Linking $@...
$(CC) $(LDFLAGS) -o testttf ttf.o testttf.o $(LIBS)
# Dependencies
$(OBJS): pdfio.h pdfio-private.h Makefile
pdfio-content.o: pdfio-content.h ttf.h
testttf.o: ttf.h
ttf.o: ttf.h
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
DOCFLAGS = \
--author "Michael R Sweet" \
--copyright "Copyright (c) 2021-2023 by Michael R Sweet" \
--docversion $(PDFIO_VERSION)
.PHONY: doc
doc:
echo Generating documentation...
codedoc $(DOCFLAGS) --title "PDFio Programming Manual v$(PDFIO_VERSION)" $(PUBHEADERS) $(PUBOBJS:.o=.c) --body doc/pdfio.md --coverimage doc/pdfio-512.png pdfio.xml >doc/pdfio.html
codedoc $(DOCFLAGS) --title "PDFio Programming Manual v$(PDFIO_VERSION)" --body doc/pdfio.md --coverimage doc/pdfio-epub.png pdfio.xml --epub doc/pdfio.epub
codedoc $(DOCFLAGS) --title "pdf read/write library" --man pdfio --section 3 --body doc/pdfio.md pdfio.xml >doc/pdfio.3
rm -f pdfio.xml
# Fuzz-test the library <https://lcamtuf.coredump.cx/afl/>
.PHONY: afl
afl:
$(MAKE) -$(MAKEFLAGS) CC="afl-clang-fast" COMMONFLAGS="-g" clean all
test afl-output || rm -rf afl-output
afl-fuzz -x afl-pdf.dict -i afl-input -o afl-output -V 600 -e pdf -t 5000 ./testpdfio @@
# Analyze code with the Clang static analyzer <https://clang-analyzer.llvm.org>
clang:
clang $(CPPFLAGS) --analyze $(OBJS:.o=.c) 2>clang.log
rm -rf $(OBJS:.o=.plist)
test -s clang.log && (echo "$(GHA_ERROR)Clang detected issues."; echo ""; cat clang.log; exit 1) || exit 0
# 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
test -s cppcheck.log && (echo "$(GHA_ERROR)Cppcheck detected issues."; echo ""; cat cppcheck.log; exit 1) || exit 0

View File

@ -5,8 +5,6 @@ pdfio - PDF Read/Write Library
![Apache 2.0](https://img.shields.io/github/license/michaelrsweet/pdfio) ![Apache 2.0](https://img.shields.io/github/license/michaelrsweet/pdfio)
[![Build Status](https://img.shields.io/github/workflow/status/michaelrsweet/pdfio/Build)](https://github.com/michaelrsweet/pdfio/actions/workflows/build.yml) [![Build Status](https://img.shields.io/github/workflow/status/michaelrsweet/pdfio/Build)](https://github.com/michaelrsweet/pdfio/actions/workflows/build.yml)
[![Coverity Scan Status](https://img.shields.io/coverity/scan/22385.svg)](https://scan.coverity.com/projects/michaelrsweet-pdfio) [![Coverity Scan Status](https://img.shields.io/coverity/scan/22385.svg)](https://scan.coverity.com/projects/michaelrsweet-pdfio)
[![LGTM Grade](https://img.shields.io/lgtm/grade/cpp/github/michaelrsweet/pdfio)](https://lgtm.com/projects/g/michaelrsweet/pdfio/context:cpp)
[![LGTM Alerts](https://img.shields.io/lgtm/alerts/github/michaelrsweet/pdfio)](https://lgtm.com/projects/g/michaelrsweet/pdfio/)
PDFio is a simple C library for reading and writing PDF files. The primary PDFio is a simple C library for reading and writing PDF files. The primary
goals of PDFio are: goals of PDFio are:
@ -30,7 +28,7 @@ PDFio requires the following to build the software:
- A C99 compiler such as Clang, GCC, or MS Visual C - A C99 compiler such as Clang, GCC, or MS Visual C
- A POSIX-compliant `make` program - A POSIX-compliant `make` program
- ZLIB (<https://www.zlib.net>) 1.0 or higher - ZLIB (<https://www.zlib.net>) 1.1 or higher
IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided. IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.
@ -38,15 +36,27 @@ IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.
Documentation Documentation
------------- -------------
See the man page (`pdfio.3`), frequently ask questions (`FAQ.md`), and full HTML See the man page (`pdfio.3`) and full HTML documentation (`pdfio.html`) for
documentation (`pdfio.html`) for information on using PDFio. information on using PDFio.
Installing pdfio Installing PDFio
---------------- ----------------
PDFio comes with a portable makefile that will work on any POSIX-compliant PDFio uses a configure script on Unix systems to generate a makefile:
system with ZLIB installed. To make it, run:
./configure
If you want a shared library, run:
./configure --enable-shared
The default installation location is "/usr/local". Pass the `--prefix` option
to make to install it to another location:
./configure --prefix=/some/other/directory
Once configured, run the following to make the library:
make all make all
@ -56,45 +66,7 @@ To test it, run:
To install it, run: To install it, run:
make install sudo make install
If you want a shared library, run:
make all-shared
make install-shared
The default installation location is "/usr/local". Pass the `prefix` variable
to make to install it to another location:
make install prefix=/some/other/directory
The makefile installs the pdfio header to "${prefix}/include", the library to
"${prefix}/lib", the `pkg-config` file to "${prefix}/lib/pkgconfig", the man
page to "${prefix}/share/man/man3", and the documentation to
"${prefix}/share/doc/pdfio".
The makefile supports the following variables that can be specified in the make
command or as environment variables:
- `AR`: the library archiver (default "ar")
- `ARFLAGS`: options for the library archiver (default "cr")
- `CC`: the C compiler (default "cc")
- `CFLAGS`: options for the C compiler (default "")
- `CODESIGN_IDENTITY`: the identity to use when code signing the shared library
on macOS (default "Developer ID")
- `COMMONFLAGS`: options for the C compiler and linker (typically architecture
and optimization options, default is "-Os -g")
- `CPPFLAGS`: options for the C preprocessor (default "")
- `DESTDIR` and `DSTROOT`: specifies a root directory when installing
(default is "", specify only one)
- `DSOFLAGS`: options for the C compiler when linking the shared library
(default "")
- `LDFLAGS`: options for the C compiler when linking the test programs
(default "")
- `LIBS`: library options when linking the test programs (default "-lz")
- `RANLIB`: program that generates a table-of-contents in a library
(default "ranlib")
- `prefix`: specifies the installation directory (default "/usr/local")
Visual Studio Project Visual Studio Project
@ -113,15 +85,11 @@ generates a static library that will be installed under "/usr/local" with:
sudo xcodebuild install sudo xcodebuild install
You can reproduce this with the makefile using:
sudo make macos install
Legal Stuff Legal Stuff
----------- -----------
PDFio is Copyright © 2021-2022 by Michael R Sweet. PDFio is Copyright © 2021-2023 by Michael R Sweet.
This software is licensed under the Apache License Version 2.0 with an This software is licensed under the Apache License Version 2.0 with an
(optional) exception to allow linking against GPL2/LGPL2 software. See the (optional) exception to allow linking against GPL2/LGPL2 software. See the

View File

@ -5,6 +5,25 @@ This file describes how security issues are reported and handled, and what the
expectations are for security issues reported to this project. expectations are for security issues reported to this project.
Reporting a Security Bug
------------------------
For the purposes of this project, a security bug is a software defect that
allows a *local or remote user* to gain unauthorized access or privileges on the
host computer or to cause the software to crash. Such defects should be
reported to the project security advisory page at
<https://github.com/michaelrsweet/pdfio/security/advisories>.
Alternately, security bugs can be reported to "security AT msweet.org" using the
PGP public key below. Expect a response within 5 business days. Any proposed
embargo date should be at least 30 days and no more than 90 days in the future.
> *Note:* If you've found a software defect that allows a *program* to gain
> unauthorized access or privileges on the host computer or causes the program
> to crash, that defect should be reported as an ordinary project issue at
> <https://github.com/michaelrsweet/pdfio/issues>.
Responsible Disclosure Responsible Disclosure
---------------------- ----------------------
@ -50,14 +69,6 @@ example:
1.0rc1 1.0rc1
Reporting a Vulnerability
-------------------------
Report all security issues to "security AT msweet.org". Expect a response
within 5 business days. Any proposed embargo date should be at least 30 days
and no more than 90 days in the future.
PGP Public Key PGP Public Key
-------------- --------------

1774
config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

1907
config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

5554
configure vendored Executable file

File diff suppressed because it is too large Load Diff

272
configure.ac Normal file
View File

@ -0,0 +1,272 @@
dnl
dnl Configuration script for PDFio
dnl
dnl Copyright © 2023 by Michael R Sweet
dnl
dnl Licensed under Apache License v2.0. See the file "LICENSE" for more
dnl information.
dnl
dnl ***********************************************************************
dnl
dnl Note: Using autoheader or automake on this project will break the PDFio
dnl build system. Use "autoconf -f" to regenerate the configure script if
dnl you make changes to this file.
dnl
dnl ***********************************************************************
dnl We need at least autoconf 2.70 for --runstatedir...
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])
PDFIO_VERSION="AC_PACKAGE_VERSION"
PDFIO_VERSION_MAJOR="`echo AC_PACKAGE_VERSION | awk -F. '{print $1}'`"
PDFIO_VERSION_MINOR="`echo AC_PACKAGE_VERSION | awk -F. '{printf("%d\n",$2);}'`"
AC_SUBST([PDFIO_VERSION])
AC_SUBST([PDFIO_VERSION_MAJOR])
AC_SUBST([PDFIO_VERSION_MINOR])
dnl This line is provided to ensure that you don't run the autoheader program
dnl against this project. Doing so is completely unsupported and WILL cause
dnl problems!
AH_TOP([#error "Somebody ran autoheader on this project which is unsupported and WILL cause problems."])
dnl Get the build and host platforms and split the host_os value
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
[host_os_name="$(echo $host_os | sed -e '1,$s/[0-9.]*$//g')"]
[host_os_version="$(echo $host_os | sed -e '1,$s/^[^0-9.]*//g' | awk -F. '{print $1 $2}')"]
# Linux often does not yield an OS version we can use...
AS_IF([test "x$host_os_version" = x], [
host_os_version="0"
])
dnl Compiler options...
CFLAGS="${CFLAGS:=}"
CPPFLAGS="${CPPFLAGS:=}"
DSOFLAGS="${DSOFLAGS:=}"
LDFLAGS="${LDFLAGS:=}"
LIBS="${LIBS:=}"
OPTIM="${OPTIM:=}"
AC_SUBST([DSOFLAGS])
AC_SUBST([OPTIM])
dnl Standard programs...
AC_PROG_CC
AC_PROG_RANLIB
AC_PATH_PROG([AR], [ar])
AC_PATH_PROGS([CODE_SIGN], [codesign true])
AC_PATH_PROG([MKDIR], [mkdir])
AC_PATH_PROG([RM], [rm])
AC_PATH_PROG([RMDIR], [rmdir])
AC_PATH_PROG([LN], [ln])
dnl Figure out the correct "ar" command flags...
AS_IF([test "$ac_cv_prog_ranlib" = ":"], [
ARFLAGS="crs"
], [
ARFLAGS="cr"
])
AC_SUBST([ARFLAGS])
dnl install-sh
AC_MSG_CHECKING([for install-sh script])
INSTALL="$(pwd)/install-sh"
AC_SUBST([INSTALL])
AC_MSG_RESULT([using $INSTALL])
dnl Check for pkg-config, which is used for some other tests later on...
AC_PATH_TOOL([PKGCONFIG], [pkg-config])
PKGCONFIG_CFLAGS="-I\${includedir}"
PKGCONFIG_LIBS="-L\${libdir} -lpdfio"
PKGCONFIG_LIBS_PRIVATE="-lm"
PKGCONFIG_REQUIRES="zlib"
AC_SUBST([PKGCONFIG_CFLAGS])
AC_SUBST([PKGCONFIG_LIBS])
AC_SUBST([PKGCONFIG_LIBS_PRIVATE])
AC_SUBST([PKGCONFIG_REQUIRES])
dnl ZLIB
AC_MSG_CHECKING([for zlib via pkg-config])
AS_IF([$PKCONFIG --exists zlib], [
AC_MSG_RESULT([yes])
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
],[
AC_MSG_RESULT([no])
AC_CHECK_HEADER([zlib.h])
AC_CHECK_LIB([z], [inflateCopy])
AS_IF([test x$ac_cv_header_zlib_h != xyes -o x$ac_cv_lib_z_inflateCopy != xyes], [
AC_MSG_ERROR([Sorry, this software requires zlib 1.1 or higher.])
])
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
])
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]))
AS_IF([test x$enable_shared = xyes], [
AS_IF([test "$host_os_name" = darwin], [
LIBPDFIO="libpdfio.1.dylib"
], [
LIBPDFIO="libpdfio.so.1"
])
AS_IF([test x$enable_static != xno], [
LIBPDFIO_STATIC="libpdfio.a"
], [
LIBPDFIO_STATIC=""
])
], [
LIBPDFIO="libpdfio.a"
LIBPDFIO_STATIC=""
PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE"
PKGCONFIG_LIBS_PRIVATE=""
])
AC_SUBST([LIBPDFIO])
AC_SUBST([LIBPDFIO_STATIC])
dnl Extra compiler options...
AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [turn on debugging, default=no]))
AC_ARG_ENABLE([maintainer], AS_HELP_STRING([--enable-maintainer], [turn on maintainer mode, default=no]))
AC_ARG_ENABLE([sanitizer], AS_HELP_STRING([--enable-sanitizer], [build with AddressSanitizer, default=no]))
AS_IF([test x$enable_debug = xyes], [
OPTIM="$OPTIM -g"
CSFLAGS=""
], [
OPTIM="$OPTIM -g -Os"
CSFLAGS="-o runtime"
])
AC_SUBST([CSFLAGS])
WARNINGS=""
AC_SUBST([WARNINGS])
AS_IF([test -n "$GCC"], [
AS_IF([test x$enable_sanitizer = xyes], [
# Use -fsanitize=address with debugging...
OPTIM="$OPTIM -fsanitize=address"
], [
# Otherwise use the Fortify enhancements to catch any unbounded
# string operations...
CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2"
])
dnl Show all standard warnings + unused variables when compiling...
WARNINGS="-Wall -Wunused"
dnl Drop some not-useful/unreliable warnings...
for warning in char-subscripts format-truncation format-y2k switch unused-result; do
AC_MSG_CHECKING([whether compiler supports -Wno-$warning])
OLDCFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wno-$warning -Werror"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [
AC_MSG_RESULT(yes)
WARNINGS="$WARNINGS -Wno-$warning"
], [
AC_MSG_RESULT(no)
])
CFLAGS="$OLDCFLAGS"
done
dnl Maintainer mode enables -Werror...
AS_IF([test x$enable_maintainer = xyes], [
WARNINGS="$WARNINGS -Werror -Wno-error=deprecated"
])
dnl See if PIE options are supported...
AC_MSG_CHECKING(whether compiler supports -fPIE)
OLDCFLAGS="$CFLAGS"
AS_CASE(["$host_os_name"],
[darwin*], [
CFLAGS="$CFLAGS -fPIC -fPIE -Wl,-pie"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[
OLDCFLAGS="-fPIC $OLDCFLAGS"
LDFLAGS="-fPIE -Wl,-pie $LDFLAGS"
AC_MSG_RESULT(yes)
],[
AC_MSG_RESULT(no)
])
], [*], [
CFLAGS="$CFLAGS -fPIC -fPIE -pie"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[
OLDCFLAGS="-fPIC $OLDCFLAGS"
LDFLAGS="-fPIE -pie $LDFLAGS"
AC_MSG_RESULT(yes)
],[
AC_MSG_RESULT(no)
])
])
CFLAGS="$OLDCFLAGS"
dnl OS-specific compiler options...
AC_MSG_CHECKING([for OS-specific compiler options])
AS_CASE(["$host_os_name"], [linux*], [
# Make sure we get the full set of 64-bit Linux APIs from the headers...
CPPFLAGS="$CPPFLAGS -D__USE_MISC -D_GNU_SOURCE -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64"
# Mark read-only sections as relocatable to random addresses...
LDFLAGS="$LDFLAGS -Wl,-z,relro,-z,now"
AC_MSG_RESULT([-D__USE_MISC -D_GNU_SOURCE -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 -Wl,-z,relro,-z,now])
], [darwin*], [
# When not building for debug, target macOS 11 or later, "universal"
# binaries when possible...
AS_IF([echo "$CPPFLAGS $CFLAGS $LDFLAGS $OPTIM" | grep -q "\\-arch "], [
# Don't add architecture/min-version flags if they are already present
AC_MSG_RESULT([none])
], [echo "$CPPFLAGS $CFLAGS $LDFLAGS $OPTIM" | grep -q "\\-mmacosx-version-"], [
# Don't add architecture/min-version flags if they are already present
AC_MSG_RESULT([none])
], [test "$host_os_version" -ge 200 -a x$enable_debug != xyes], [
# macOS 11.0 and higher support the Apple Silicon (arm64) CPUs
OPTIM="$OPTIM -mmacosx-version-min=11.0 -arch x86_64 -arch arm64"
AC_MSG_RESULT([-mmacosx-version-min=11.0 -arch x86_64 -arch arm64])
], [
# Don't add architecture/min-version flags if debug enabled
AC_MSG_RESULT([none])
])
], [*], [
AC_MSG_RESULT([none])
])
])
dnl Extra linker options...
AC_ARG_WITH([dsoflags], AS_HELP_STRING([--with-dsoflags=...], [Specify additional DSOFLAGS]), [
DSOFLAGS="$withval $DSOFLAGS"
])
AC_ARG_WITH([ldflags], AS_HELP_STRING([--with-ldflags=...], [Specify additional LDFLAGS]), [
LDFLAGS="$withval $LDFLAGS"
])
dnl Generate the Makefile and pkg-config file...
AC_CONFIG_FILES([Makefile pdfio.pc])
AC_OUTPUT

View File

@ -1,4 +1,4 @@
.TH pdfio 3 "pdf read/write library" "2022-07-03" "pdf read/write library" .TH pdfio 3 "pdf read/write library" "2023-12-05" "pdf read/write library"
.SH NAME .SH NAME
pdfio \- pdf read/write library pdfio \- pdf read/write library
.SH Introduction .SH Introduction
@ -34,7 +34,7 @@ PDFio is
.I not .I not
concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it. concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.
.PP .PP
PDFio is Copyright \[co] 2021\-2022 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information. PDFio is Copyright \[co] 2021\-2023 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
.SS Requirements .SS Requirements
.PP .PP
PDFio requires the following to build the software: PDFio requires the following to build the software:
@ -1507,6 +1507,9 @@ bool pdfioContentSetDashPattern (
double off double off
); );
.fi .fi
.PP
This function sets the stroke pattern when drawing lines. If "on" and "off"
are 0, a solid line is drawn.
.SS pdfioContentSetFillColorDeviceCMYK .SS pdfioContentSetFillColorDeviceCMYK
Set device CMYK fill color. Set device CMYK fill color.
.PP .PP
@ -1771,6 +1774,20 @@ bool pdfioContentTextEnd (
pdfio_stream_t *st pdfio_stream_t *st
); );
.fi .fi
.SS pdfioContentTextMeasure
Measure a text string and return its width.
.PP
.nf
double pdfioContentTextMeasure (
pdfio_obj_t *font,
const char *s,
double size
);
.fi
.PP
This function measures the given text string "s" and returns its width based
on "size". The text string must always use the UTF-8 (Unicode) encoding but
any control characters (such as newlines) are ignored.
.SS pdfioContentTextMoveLine .SS pdfioContentTextMoveLine
Move to the next line and offset. Move to the next line and offset.
.PP .PP
@ -1791,14 +1808,49 @@ bool pdfioContentTextMoveTo (
double ty double ty
); );
.fi .fi
.SS pdfioContentTextNextLine .SS pdfioContentTextNewLine
Move to the next line. Move to the next line.
.PP .PP
.nf .nf
bool pdfioContentTextNextLine ( bool pdfioContentTextNewLine (
pdfio_stream_t *st pdfio_stream_t *st
); );
.fi .fi
.SS pdfioContentTextNewLineShow
Move to the next line and show text.
.PP
.nf
bool pdfioContentTextNewLineShow (
pdfio_stream_t *st,
double ws,
double cs,
bool unicode,
const char *s
);
.fi
.PP
This function moves to the next line and then shows some text with optional
word and character spacing in a PDF content stream. The "unicode" argument
specifies that the current font maps to full Unicode. The "s" argument
specifies a UTF-8 encoded string.
.SS pdfioContentTextNewLineShowf
Show formatted text.
.PP
.nf
bool pdfioContentTextNewLineShowf (
pdfio_stream_t *st,
double ws,
double cs,
bool unicode,
const char *format,
...
);
.fi
.PP
This function moves to the next line and shows some formatted text with
optional word and character spacing in a PDF content stream. The "unicode"
argument specifies that the current font maps to full Unicode. The "format"
argument specifies a UTF-8 encoded \fBprintf\fR-style format string.
.SS pdfioContentTextShow .SS pdfioContentTextShow
Show text. Show text.
.PP .PP
@ -1981,6 +2033,7 @@ function "cb":
} }
.fi .fi
The iteration continues as long as the callback returns \fBtrue\fR or all keys The iteration continues as long as the callback returns \fBtrue\fR or all keys
have been iterated. have been iterated.
.SS pdfioDictSetArray .SS pdfioDictSetArray
@ -2272,6 +2325,18 @@ Note: Currently PNG support is limited to grayscale, RGB, or indexed files
without interlacing or alpha. Transparency (masking) based on color/index without interlacing or alpha. Transparency (masking) based on color/index
.IP 5 .IP 5
is supported. is supported.
.SS pdfioFileCreateNumberObj
Create a new object in a PDF file containing a number.
.PP
.nf
pdfio_obj_t * pdfioFileCreateNumberObj (
pdfio_file_t *pdf,
double number
);
.fi
.PP
This function creates a new object with a number value in a PDF file.
You must call \fIpdfioObjClose\fR to write the object to the file.
.SS pdfioFileCreateObj .SS pdfioFileCreateObj
Create a new object in a PDF file. Create a new object in a PDF file.
.PP .PP
@ -2309,6 +2374,7 @@ written:
} }
.fi .fi
The "version" argument specifies the PDF version number for the file or The "version" argument specifies the PDF version number for the file or
\fBNULL\fR for the default ("2.0"). \fBNULL\fR for the default ("2.0").
.PP .PP
@ -2335,6 +2401,18 @@ pdfio_stream_t * pdfioFileCreatePage (
pdfio_dict_t *dict pdfio_dict_t *dict
); );
.fi .fi
.SS pdfioFileCreateStringObj
Create a new object in a PDF file containing a string.
.PP
.nf
pdfio_obj_t * pdfioFileCreateStringObj (
pdfio_file_t *pdf,
const char *string
);
.fi
.PP
This function creates a new object with a string value in a PDF file.
You must call \fIpdfioObjClose\fR to write the object to the file.
.SS pdfioFileCreateTemporary .SS pdfioFileCreateTemporary
.PP .PP
@ -2802,6 +2880,13 @@ bool pdfioStreamGetToken (
size_t bufsize size_t bufsize
); );
.fi .fi
.PP
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.
.SS pdfioStreamPeek .SS pdfioStreamPeek
Peek at data in a stream. Peek at data in a stream.
.PP .PP
@ -3035,4 +3120,4 @@ typedef uint8_t state_t[4][4];
Michael R Sweet Michael R Sweet
.SH COPYRIGHT .SH COPYRIGHT
.PP .PP
Copyright (c) 2021-2022 by Michael R Sweet Copyright (c) 2021-2023 by Michael R Sweet

View File

@ -1,13 +1,13 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-US"> <html lang="en-US">
<head> <head>
<title>PDFio Programming Manual v1.1</title> <title>PDFio Programming Manual v1.2.0</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta name="generator" content="codedoc v3.7"> <meta name="generator" content="codedoc v3.7">
<meta name="author" content="Michael R Sweet"> <meta name="author" content="Michael R Sweet">
<meta name="language" content="en-US"> <meta name="language" content="en-US">
<meta name="copyright" content="Copyright © 2021-2022 by Michael R Sweet"> <meta name="copyright" content="Copyright © 2021-2023 by Michael R Sweet">
<meta name="version" content="1.1"> <meta name="version" content="1.2.0">
<style type="text/css"><!-- <style type="text/css"><!--
body { body {
background: white; background: white;
@ -245,9 +245,9 @@ span.string {
<body> <body>
<div class="header"> <div class="header">
<p><img class="title" src="pdfio-512.png"></p> <p><img class="title" src="pdfio-512.png"></p>
<h1 class="title">PDFio Programming Manual v1.1</h1> <h1 class="title">PDFio Programming Manual v1.2.0</h1>
<p>Michael R Sweet</p> <p>Michael R Sweet</p>
<p>Copyright © 2021-2022 by Michael R Sweet</p> <p>Copyright © 2021-2023 by Michael R Sweet</p>
</div> </div>
<div class="contents"> <div class="contents">
<h2 class="title">Contents</h2> <h2 class="title">Contents</h2>
@ -342,9 +342,12 @@ span.string {
<li><a href="#pdfioContentStroke">pdfioContentStroke</a></li> <li><a href="#pdfioContentStroke">pdfioContentStroke</a></li>
<li><a href="#pdfioContentTextBegin">pdfioContentTextBegin</a></li> <li><a href="#pdfioContentTextBegin">pdfioContentTextBegin</a></li>
<li><a href="#pdfioContentTextEnd">pdfioContentTextEnd</a></li> <li><a href="#pdfioContentTextEnd">pdfioContentTextEnd</a></li>
<li><a href="#pdfioContentTextMeasure">pdfioContentTextMeasure</a></li>
<li><a href="#pdfioContentTextMoveLine">pdfioContentTextMoveLine</a></li> <li><a href="#pdfioContentTextMoveLine">pdfioContentTextMoveLine</a></li>
<li><a href="#pdfioContentTextMoveTo">pdfioContentTextMoveTo</a></li> <li><a href="#pdfioContentTextMoveTo">pdfioContentTextMoveTo</a></li>
<li><a href="#pdfioContentTextNextLine">pdfioContentTextNextLine</a></li> <li><a href="#pdfioContentTextNewLine">pdfioContentTextNewLine</a></li>
<li><a href="#pdfioContentTextNewLineShow">pdfioContentTextNewLineShow</a></li>
<li><a href="#pdfioContentTextNewLineShowf">pdfioContentTextNewLineShowf</a></li>
<li><a href="#pdfioContentTextShow">pdfioContentTextShow</a></li> <li><a href="#pdfioContentTextShow">pdfioContentTextShow</a></li>
<li><a href="#pdfioContentTextShowJustified">pdfioContentTextShowJustified</a></li> <li><a href="#pdfioContentTextShowJustified">pdfioContentTextShowJustified</a></li>
<li><a href="#pdfioContentTextShowf">pdfioContentTextShowf</a></li> <li><a href="#pdfioContentTextShowf">pdfioContentTextShowf</a></li>
@ -382,9 +385,11 @@ span.string {
<li><a href="#pdfioFileCreateICCObjFromFile">pdfioFileCreateICCObjFromFile</a></li> <li><a href="#pdfioFileCreateICCObjFromFile">pdfioFileCreateICCObjFromFile</a></li>
<li><a href="#pdfioFileCreateImageObjFromData">pdfioFileCreateImageObjFromData</a></li> <li><a href="#pdfioFileCreateImageObjFromData">pdfioFileCreateImageObjFromData</a></li>
<li><a href="#pdfioFileCreateImageObjFromFile">pdfioFileCreateImageObjFromFile</a></li> <li><a href="#pdfioFileCreateImageObjFromFile">pdfioFileCreateImageObjFromFile</a></li>
<li><a href="#pdfioFileCreateNumberObj">pdfioFileCreateNumberObj</a></li>
<li><a href="#pdfioFileCreateObj">pdfioFileCreateObj</a></li> <li><a href="#pdfioFileCreateObj">pdfioFileCreateObj</a></li>
<li><a href="#pdfioFileCreateOutput">pdfioFileCreateOutput</a></li> <li><a href="#pdfioFileCreateOutput">pdfioFileCreateOutput</a></li>
<li><a href="#pdfioFileCreatePage">pdfioFileCreatePage</a></li> <li><a href="#pdfioFileCreatePage">pdfioFileCreatePage</a></li>
<li><a href="#pdfioFileCreateStringObj">pdfioFileCreateStringObj</a></li>
<li><a href="#pdfioFileCreateTemporary">pdfioFileCreateTemporary</a></li> <li><a href="#pdfioFileCreateTemporary">pdfioFileCreateTemporary</a></li>
<li><a href="#pdfioFileFindObj">pdfioFileFindObj</a></li> <li><a href="#pdfioFileFindObj">pdfioFileFindObj</a></li>
<li><a href="#pdfioFileGetAuthor">pdfioFileGetAuthor</a></li> <li><a href="#pdfioFileGetAuthor">pdfioFileGetAuthor</a></li>
@ -497,7 +502,7 @@ span.string {
</li> </li>
</ul> </ul>
<p>PDFio is <em>not</em> concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.</p> <p>PDFio is <em>not</em> concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.</p>
<p>PDFio is Copyright © 2021-2022 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files &quot;LICENSE&quot; and &quot;NOTICE&quot; for more information.</p> <p>PDFio is Copyright © 2021-2023 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files &quot;LICENSE&quot; and &quot;NOTICE&quot; for more information.</p>
<h3 class="title" id="requirements">Requirements</h3> <h3 class="title" id="requirements">Requirements</h3>
<p>PDFio requires the following to build the software:</p> <p>PDFio requires the following to build the software:</p>
<ul> <ul>
@ -1614,6 +1619,9 @@ bool pdfioContentSetDashPattern(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p> <p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function sets the stroke pattern when drawing lines. If &quot;on&quot; and &quot;off&quot;
are 0, a solid line is drawn.</p>
<h3 class="function"><a id="pdfioContentSetFillColorDeviceCMYK">pdfioContentSetFillColorDeviceCMYK</a></h3> <h3 class="function"><a id="pdfioContentSetFillColorDeviceCMYK">pdfioContentSetFillColorDeviceCMYK</a></h3>
<p class="description">Set device CMYK fill color.</p> <p class="description">Set device CMYK fill color.</p>
<p class="code"> <p class="code">
@ -2002,6 +2010,25 @@ bool pdfioContentTextEnd(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);</p>
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p> <p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h3 class="function"><a id="pdfioContentTextMeasure">pdfioContentTextMeasure</a></h3>
<p class="description">Measure a text string and return its width.</p>
<p class="code">
double pdfioContentTextMeasure(<a href="#pdfio_obj_t">pdfio_obj_t</a> *font, const char *s, double size);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>font</th>
<td class="description">Font object created by <a href="#pdfioFileCreateFontObjFromFile"><code>pdfioFileCreateFontObjFromFile</code></a></td></tr>
<tr><th>s</th>
<td class="description">UTF-8 string</td></tr>
<tr><th>size</th>
<td class="description">Font size/height</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">Width</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function measures the given text string &quot;s&quot; and returns its width based
on &quot;size&quot;. The text string must always use the UTF-8 (Unicode) encoding but
any control characters (such as newlines) are ignored.</p>
<h3 class="function"><a id="pdfioContentTextMoveLine">pdfioContentTextMoveLine</a></h3> <h3 class="function"><a id="pdfioContentTextMoveLine">pdfioContentTextMoveLine</a></h3>
<p class="description">Move to the next line and offset.</p> <p class="description">Move to the next line and offset.</p>
<p class="code"> <p class="code">
@ -2032,10 +2059,10 @@ bool pdfioContentTextMoveTo(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, do
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p> <p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h3 class="function"><a id="pdfioContentTextNextLine">pdfioContentTextNextLine</a></h3> <h3 class="function"><a id="pdfioContentTextNewLine">pdfioContentTextNewLine</a></h3>
<p class="description">Move to the next line.</p> <p class="description">Move to the next line.</p>
<p class="code"> <p class="code">
bool pdfioContentTextNextLine(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);</p> bool pdfioContentTextNewLine(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);</p>
<h4 class="parameters">Parameters</h4> <h4 class="parameters">Parameters</h4>
<table class="list"><tbody> <table class="list"><tbody>
<tr><th>st</th> <tr><th>st</th>
@ -2043,6 +2070,56 @@ bool pdfioContentTextNextLine(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p> <p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h3 class="function"><a id="pdfioContentTextNewLineShow">pdfioContentTextNewLineShow</a></h3>
<p class="description">Move to the next line and show text.</p>
<p class="code">
bool pdfioContentTextNewLineShow(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, double ws, double cs, bool unicode, const char *s);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>st</th>
<td class="description">Stream</td></tr>
<tr><th>ws</th>
<td class="description">Word spacing or <code>0.0</code> for none</td></tr>
<tr><th>cs</th>
<td class="description">Character spacing or <code>0.0</code> for none</td></tr>
<tr><th>unicode</th>
<td class="description">Unicode text?</td></tr>
<tr><th>s</th>
<td class="description">String to show</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function moves to the next line and then shows some text with optional
word and character spacing in a PDF content stream. The &quot;unicode&quot; argument
specifies that the current font maps to full Unicode. The &quot;s&quot; argument
specifies a UTF-8 encoded string.</p>
<h3 class="function"><a id="pdfioContentTextNewLineShowf">pdfioContentTextNewLineShowf</a></h3>
<p class="description">Show formatted text.</p>
<p class="code">
bool pdfioContentTextNewLineShowf(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, double ws, double cs, bool unicode, const char *format, ...);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>st</th>
<td class="description">Stream</td></tr>
<tr><th>ws</th>
<td class="description">Word spacing or <code>0.0</code> for none</td></tr>
<tr><th>cs</th>
<td class="description">Character spacing or <code>0.0</code> for none</td></tr>
<tr><th>unicode</th>
<td class="description">Unicode text?</td></tr>
<tr><th>format</th>
<td class="description"><code>printf</code>-style format string</td></tr>
<tr><th>...</th>
<td class="description">Additional arguments as needed</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function moves to the next line and shows some formatted text with
optional word and character spacing in a PDF content stream. The &quot;unicode&quot;
argument specifies that the current font maps to full Unicode. The &quot;format&quot;
argument specifies a UTF-8 encoded <code>printf</code>-style format string.</p>
<h3 class="function"><a id="pdfioContentTextShow">pdfioContentTextShow</a></h3> <h3 class="function"><a id="pdfioContentTextShow">pdfioContentTextShow</a></h3>
<p class="description">Show text.</p> <p class="description">Show text.</p>
<p class="code"> <p class="code">
@ -2102,9 +2179,9 @@ bool pdfioContentTextShowf(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, boo
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description">Show formatted text.</p> <p class="description">Show formatted text.</p>
<p class="discussion">This function shows some text in a PDF content stream. The &quot;unicode&quot; argument <p class="discussion">This function shows some formatted text in a PDF content stream. The
specifies that the current font maps to full Unicode. The &quot;format&quot; argument &quot;unicode&quot; argument specifies that the current font maps to full Unicode.
specifies a UTF-8 encoded <code>printf</code>-style format string.</p> The &quot;format&quot; argument specifies a UTF-8 encoded <code>printf</code>-style format string.</p>
<h3 class="function"><a id="pdfioDictCopy">pdfioDictCopy</a></h3> <h3 class="function"><a id="pdfioDictCopy">pdfioDictCopy</a></h3>
<p class="description">Copy a dictionary to a PDF file.</p> <p class="description">Copy a dictionary to a PDF file.</p>
<p class="code"> <p class="code">
@ -2301,6 +2378,7 @@ my_dict_cb(pdfio_dict_t *dict, const char *key, void *cb_data)
... return true to continue or false to stop ... ... return true to continue or false to stop ...
} }
</pre> </pre>
The iteration continues as long as the callback returns <code>true</code> or all keys The iteration continues as long as the callback returns <code>true</code> or all keys
have been iterated.</p> have been iterated.</p>
<h3 class="function"><a id="pdfioDictSetArray">pdfioDictSetArray</a></h3> <h3 class="function"><a id="pdfioDictSetArray">pdfioDictSetArray</a></h3>
@ -2695,6 +2773,22 @@ image on the page.<br>
Note: Currently PNG support is limited to grayscale, RGB, or indexed files Note: Currently PNG support is limited to grayscale, RGB, or indexed files
without interlacing or alpha. Transparency (masking) based on color/index without interlacing or alpha. Transparency (masking) based on color/index
is supported.</blockquote> is supported.</blockquote>
<h3 class="function"><a id="pdfioFileCreateNumberObj">pdfioFileCreateNumberObj</a></h3>
<p class="description">Create a new object in a PDF file containing a number.</p>
<p class="code">
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateNumberObj(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, double number);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>pdf</th>
<td class="description">PDF file</td></tr>
<tr><th>number</th>
<td class="description">Number value</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">New object</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function creates a new object with a number value in a PDF file.
You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file.</p>
<h3 class="function"><a id="pdfioFileCreateObj">pdfioFileCreateObj</a></h3> <h3 class="function"><a id="pdfioFileCreateObj">pdfioFileCreateObj</a></h3>
<p class="description">Create a new object in a PDF file.</p> <p class="description">Create a new object in a PDF file.</p>
<p class="code"> <p class="code">
@ -2744,6 +2838,7 @@ output_cb(void *output_ctx, const void *buffer, size_t bytes)
// Write buffer to output and return the number of bytes written // Write buffer to output and return the number of bytes written
} }
</pre> </pre>
The &quot;version&quot; argument specifies the PDF version number for the file or The &quot;version&quot; argument specifies the PDF version number for the file or
<code>NULL</code> for the default (&quot;2.0&quot;).<br> <code>NULL</code> for the default (&quot;2.0&quot;).<br>
<br> <br>
@ -2772,6 +2867,22 @@ stored as indirect object references.</blockquote>
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description">Contents stream</p> <p class="description">Contents stream</p>
<h3 class="function"><a id="pdfioFileCreateStringObj">pdfioFileCreateStringObj</a></h3>
<p class="description">Create a new object in a PDF file containing a string.</p>
<p class="code">
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateStringObj(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, const char *string);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>pdf</th>
<td class="description">PDF file</td></tr>
<tr><th>string</th>
<td class="description">String</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">New object</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function creates a new object with a string value in a PDF file.
You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file.</p>
<h3 class="function"><a id="pdfioFileCreateTemporary">pdfioFileCreateTemporary</a></h3> <h3 class="function"><a id="pdfioFileCreateTemporary">pdfioFileCreateTemporary</a></h3>
<p class="description"></p> <p class="description"></p>
<p class="code"> <p class="code">
@ -3413,6 +3524,13 @@ bool pdfioStreamGetToken(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, char
</tbody></table> </tbody></table>
<h4 class="returnvalue">Return Value</h4> <h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on EOF</p> <p class="description"><code>true</code> on success, <code>false</code> on EOF</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">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 ('&lt;') and have all whitespace and the
terminating angle bracket removed.</p>
<h3 class="function"><a id="pdfioStreamPeek">pdfioStreamPeek</a></h3> <h3 class="function"><a id="pdfioStreamPeek">pdfioStreamPeek</a></h3>
<p class="description">Peek at data in a stream.</p> <p class="description">Peek at data in a stream.</p>
<p class="code"> <p class="code">

View File

@ -15,7 +15,7 @@ goals of pdfio are:
PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF
RIP or viewer could be written using it. RIP or viewer could be written using it.
PDFio is Copyright © 2021-2022 by Michael R Sweet and is licensed under the PDFio is Copyright © 2021-2023 by Michael R Sweet and is licensed under the
Apache License Version 2.0 with an (optional) exception to allow linking against Apache License Version 2.0 with an (optional) exception to allow linking against
GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information. GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.

232
install-sh Executable file
View File

@ -0,0 +1,232 @@
#!/bin/sh
#
# Install a program, script, or datafile.
#
# Copyright 2008-2012 by Apple Inc.
#
# This script is not compatible with BSD (or any other) install program, as it
# allows owner and group changes to fail with a warning and makes sure that the
# destination directory permissions are as specified - BSD install and the
# original X11 install script did not change permissions of existing
# directories. It also does not support the transform options since CUPS does
# not use them...
#
# Original script from X11R5 (mit/util/scripts/install.sh)
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# Force umask to 022...
umask 022
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
gzipprog="${GZIPPROG-gzip}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
gzipcp() {
# gzipcp from to
$gzipprog -9 <"$1" >"$2"
}
while [ x"$1" != x ]; do
case $1 in
-c)
instcmd="$cpprog"
shift
continue
;;
-d)
dir_arg=true
shift
continue
;;
-m)
chmodcmd="$chmodprog $2"
shift
shift
continue
;;
-o)
chowncmd="$chownprog $2"
shift
shift
continue
;;
-g)
chgrpcmd="$chgrpprog $2"
shift
shift
continue
;;
-s)
stripcmd="$stripprog"
shift
continue
;;
-z)
instcmd="gzipcp"
shift
continue
;;
*)
if [ x"$src" = x ]; then
src="$1"
else
dst="$1"
fi
shift
continue
;;
esac
done
if [ x"$src" = x ]; then
echo "install-sh: No input file specified"
exit 1
fi
if [ x"$dir_arg" != x ]; then
dst="$src"
src=""
if [ -d "$dst" ]; then
instcmd=:
else
instcmd=$mkdirprog
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ ! -f "$src" -a ! -d "$src" ]; then
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]; then
echo "install: No destination specified"
exit 1
fi
# If destination is a directory, append the input filename.
if [ -d "$dst" ]; then
dst="$dst/`basename $src`"
fi
fi
## this sed command emulates the dirname command
dstdir="`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`"
# Make sure that the destination directory exists.
# This part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ]; then $doit $mkdirprog "${pathcomp}"; fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]; then
# Make a directory...
$doit $instcmd $dst || exit 1
# Allow chown/chgrp to fail, but log a warning
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst || echo "warning: Unable to change owner of $dst!"; fi
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst || echo "warning: Unable to change group of $dst!"; fi
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst || exit 1; fi
else
# Install a file...
dstfile="`basename $dst`"
# Check the destination file - for libraries just use the "-x" option
# to strip...
case "$dstfile" in
*.a | *.dylib | *.sl | *.sl.* | *.so | *.so.*)
stripopt="-x"
;;
*)
stripopt=""
;;
esac
# Make a temp file name in the proper directory.
dsttmp="$dstdir/#inst.$$#"
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp || exit 1
# Update permissions and strip as needed, then move to the final name.
# If the chmod, strip, rm, or mv commands fail, remove the installed
# file...
if [ x"$stripcmd" != x ]; then $doit $stripcmd $stripopt "$dsttmp" || echo "warning: Unable to strip $dst!"; fi
if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp" || echo "warning: Unable to change owner of $dst!"; fi
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp" || echo "warning: Unable to change group of $dst!"; fi
trap "rm -f ${dsttmp}" 0 &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; fi &&
$doit $rmcmd -f "$dstdir/$dstfile" &&
$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
fi
exit 0

View File

@ -375,9 +375,9 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
if (whence != SEEK_END && offset >= pdf->bufpos && offset < (pdf->bufpos + pdf->bufend - pdf->buffer)) if (whence != SEEK_END && offset >= pdf->bufpos && offset < (pdf->bufpos + pdf->bufend - pdf->buffer))
{ {
// Yes, seek within existing buffer... // Yes, seek within existing buffer...
pdf->bufptr = pdf->buffer + offset - pdf->bufpos; pdf->bufptr = pdf->buffer + (offset - pdf->bufpos);
PDFIO_DEBUG("_pdfioFileSeek: Seek within buffer, bufpos=%ld.\n", (long)pdf->bufpos); PDFIO_DEBUG("_pdfioFileSeek: Seek within buffer, bufpos=%ld.\n", (long)pdf->bufpos);
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p, bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufend); PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p(<%02X%02X...>), bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufptr[0] & 255, pdf->bufptr[1] & 255, pdf->bufend);
return (offset); return (offset);
} }

View File

@ -1,16 +1,12 @@
// //
// Content helper functions for PDFio. // Content helper functions for PDFio.
// //
// Copyright © 2021 by Michael R Sweet. // Copyright © 2021-2023 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
// //
//
// Include necessary headers...
//
#include "pdfio-private.h" #include "pdfio-private.h"
#include "pdfio-content.h" #include "pdfio-content.h"
#include "ttf.h" #include "ttf.h"
@ -670,6 +666,9 @@ pdfioContentSave(pdfio_stream_t *st) // I - Stream
// //
// 'pdfioContentSetDashPattern()' - Set the stroke pattern. // 'pdfioContentSetDashPattern()' - Set the stroke pattern.
// //
// This function sets the stroke pattern when drawing lines. If "on" and "off"
// are 0, a solid line is drawn.
//
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetDashPattern( pdfioContentSetDashPattern(
@ -678,6 +677,11 @@ pdfioContentSetDashPattern(
double on, // I - On length double on, // I - On length
double off) // I - Off length double off) // I - Off length
{ {
if (on <= 0.0 && off <= 0.0)
return (pdfioStreamPrintf(st, "[] %g d\n", phase));
else if (fabs(on - off) < 0.001)
return (pdfioStreamPrintf(st, "[%g] %g d\n", on, phase));
else
return (pdfioStreamPrintf(st, "[%g %g] %g d\n", on, off, phase)); return (pdfioStreamPrintf(st, "[%g %g] %g d\n", on, off, phase));
} }
@ -1056,6 +1060,104 @@ pdfioContentTextEnd(pdfio_stream_t *st) // I - Stream
} }
//
// 'pdfioContentTextMeasure()' - Measure a text string and return its width.
//
// This function measures the given text string "s" and returns its width based
// on "size". The text string must always use the UTF-8 (Unicode) encoding but
// any control characters (such as newlines) are ignored.
//
double // O - Width
pdfioContentTextMeasure(
pdfio_obj_t *font, // I - Font object created by @link pdfioFileCreateFontObjFromFile@
const char *s, // I - UTF-8 string
double size) // I - Font size/height
{
const char *subtype; // Font sub-type
ttf_t *ttf = (ttf_t *)_pdfioObjGetExtension(font);
// TrueType font data
ttf_rect_t extents; // Text extents
int ch; // Unicode character
char temp[1024], // Temporary string
*tempptr; // Pointer into temporary string
if ((subtype = pdfioObjGetSubtype(font)) == NULL || strcmp(subtype, "Type0"))
{
// Map non-CP1282 characters to '?', everything else as-is...
tempptr = temp;
while (*s && tempptr < (temp + sizeof(temp) - 3))
{
if ((*s & 0xe0) == 0xc0)
{
// Two-byte UTF-8
ch = ((s[0] & 0x1f) << 6) | (s[1] & 0x3f);
s += 2;
}
else if ((*s & 0xf0) == 0xe0)
{
// Three-byte UTF-8
ch = ((s[0] & 0x0f) << 12) | ((s[1] & 0x3f) << 6) | (s[2] & 0x3f);
s += 3;
}
else if ((*s & 0xf8) == 0xf0)
{
// Four-byte UTF-8
ch = ((s[0] & 0x07) << 18) | ((s[1] & 0x3f) << 12) | ((s[2] & 0x3f) << 6) | (s[3] & 0x3f);
s += 4;
}
else
{
ch = *s++;
}
if (ch > 255)
{
// Try mapping from Unicode to CP1252...
size_t i; // Looping var
for (i = 0; i < (sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0])); i ++)
{
if (ch == _pdfio_cp1252[i])
break;
}
if (i >= (sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0])))
ch = '?'; // Unsupported chars map to ?
}
if (ch < 128)
{
// ASCII
*tempptr++ = ch;
}
else if (ch < 2048)
{
// 2-byte UTF-8
*tempptr++ = 0xc0 | ((ch >> 6) & 0x1f);
*tempptr++ = 0x80 | (ch & 0x3f);
}
else
{
// 3-byte UTF-8
*tempptr++ = 0xe0 | ((ch >> 12) & 0x0f);
*tempptr++ = 0x80 | ((ch >> 6) & 0x3f);
*tempptr++ = 0x80 | (ch & 0x3f);
}
}
*tempptr = '\0';
s = temp;
}
ttfGetExtents(ttf, size, s, &extents);
return (extents.right - extents.left);
}
// //
// 'pdfioContentTextMoveLine()' - Move to the next line and offset. // 'pdfioContentTextMoveLine()' - Move to the next line and offset.
// //
@ -1085,17 +1187,97 @@ pdfioContentTextMoveTo(
// //
// 'pdfioContentTextNextLine()' - Move to the next line. // 'pdfioContentTextNewLine()' - Move to the next line.
// //
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentTextNextLine( pdfioContentTextNewLine(
pdfio_stream_t *st) // I - Stream pdfio_stream_t *st) // I - Stream
{ {
return (pdfioStreamPuts(st, "T*\n")); return (pdfioStreamPuts(st, "T*\n"));
} }
//
// 'pdfioContentTextNewLineShow()' - Move to the next line and show text.
//
// This function moves to the next line and then shows some text with optional
// word and character spacing in a PDF content stream. The "unicode" argument
// specifies that the current font maps to full Unicode. The "s" argument
// specifies a UTF-8 encoded string.
//
bool // O - `true` on success, `false` on failure
pdfioContentTextNewLineShow(
pdfio_stream_t *st, // I - Stream
double ws, // I - Word spacing or `0.0` for none
double cs, // I - Character spacing or `0.0` for none
bool unicode, // I - Unicode text?
const char *s) // I - String to show
{
bool newline = false; // New line?
char op; // Text operator
// Write word and/or character spacing as needed...
if (ws > 0.0 || cs > 0.0)
{
// Use " operator to show text with word and character spacing...
if (!pdfioStreamPrintf(st, "%g %g", ws, cs))
return (false);
op = '\"';
}
else
{
// Use ' operator to show text with the defaults...
op = '\'';
}
// Write the string...
if (!write_string(st, unicode, s, &newline))
return (false);
// Draw it...
if (newline)
return (pdfioStreamPrintf(st, "%c T*\n", op));
else
return (pdfioStreamPrintf(st, "%c\n", op));
}
//
// 'pdfioContentTextNewLineShowf()' - Show formatted text.
//
// This function moves to the next line and shows some formatted text with
// optional word and character spacing in a PDF content stream. The "unicode"
// argument specifies that the current font maps to full Unicode. The "format"
// argument specifies a UTF-8 encoded `printf`-style format string.
//
bool // O - `true` on success, `false` on failure
pdfioContentTextNewLineShowf(
pdfio_stream_t *st, // I - Stream
double ws, // I - Word spacing or `0.0` for none
double cs, // I - Character spacing or `0.0` for none
bool unicode, // I - Unicode text?
const char *format, // I - `printf`-style format string
...) // I - Additional arguments as needed
{
char buffer[8192]; // Text buffer
va_list ap; // Argument pointer
// Format the string...
va_start(ap, format);
vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
// Show it...
return (pdfioContentTextNewLineShow(st, ws, cs, unicode, buffer));
}
// //
// 'pdfioContentTextShow()' - Show text. // 'pdfioContentTextShow()' - Show text.
// //
@ -1128,9 +1310,9 @@ pdfioContentTextShow(
// //
// 'pdfioContentTextShowf()' - Show formatted text. // 'pdfioContentTextShowf()' - Show formatted text.
// //
// This function shows some text in a PDF content stream. The "unicode" argument // This function shows some formatted text in a PDF content stream. The
// specifies that the current font maps to full Unicode. The "format" argument // "unicode" argument specifies that the current font maps to full Unicode.
// specifies a UTF-8 encoded `printf`-style format string. // The "format" argument specifies a UTF-8 encoded `printf`-style format string.
// //
bool bool
@ -1281,13 +1463,13 @@ pdfioFileCreateFontObjFromFile(
pdfio_dict_t *dict, // Font dictionary pdfio_dict_t *dict, // Font dictionary
*desc, // Font descriptor *desc, // Font descriptor
*file; // Font file dictionary *file; // Font file dictionary
pdfio_obj_t *obj, // Font object pdfio_obj_t *obj = NULL, // Font object
*desc_obj, // Font descriptor object *desc_obj, // Font descriptor object
*file_obj; // Font file object *file_obj; // Font file object
const char *basefont; // Base font name const char *basefont; // Base font name
pdfio_array_t *bbox; // Font bounding box array pdfio_array_t *bbox; // Font bounding box array
pdfio_stream_t *st; // Font stream pdfio_stream_t *st; // Font stream
int fd; // File int fd = -1; // File
unsigned char buffer[16384]; // Read buffer unsigned char buffer[16384]; // Read buffer
ssize_t bytes; // Bytes read ssize_t bytes; // Bytes read
@ -1316,48 +1498,32 @@ pdfioFileCreateFontObjFromFile(
// Create the font file dictionary and object... // Create the font file dictionary and object...
if ((file = pdfioDictCreate(pdf)) == NULL) if ((file = pdfioDictCreate(pdf)) == NULL)
{ goto done;
ttfDelete(font);
close(fd);
return (NULL);
}
pdfioDictSetName(file, "Filter", "FlateDecode"); pdfioDictSetName(file, "Filter", "FlateDecode");
if ((file_obj = pdfioFileCreateObj(pdf, file)) == NULL) if ((file_obj = pdfioFileCreateObj(pdf, file)) == NULL)
{ goto done;
ttfDelete(font);
close(fd);
return (NULL);
}
if ((st = pdfioObjCreateStream(file_obj, PDFIO_FILTER_FLATE)) == NULL) if ((st = pdfioObjCreateStream(file_obj, PDFIO_FILTER_FLATE)) == NULL)
{ goto done;
ttfDelete(font);
close(fd);
return (NULL);
}
while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
{ {
if (!pdfioStreamWrite(st, buffer, (size_t)bytes)) if (!pdfioStreamWrite(st, buffer, (size_t)bytes))
{ {
ttfDelete(font);
close(fd);
pdfioStreamClose(st); pdfioStreamClose(st);
return (NULL); goto done;
} }
} }
close(fd); close(fd);
fd = -1;
pdfioStreamClose(st); pdfioStreamClose(st);
// Create the font descriptor dictionary and object... // Create the font descriptor dictionary and object...
if ((bbox = pdfioArrayCreate(pdf)) == NULL) if ((bbox = pdfioArrayCreate(pdf)) == NULL)
{ goto done;
ttfDelete(font);
return (NULL);
}
ttfGetBounds(font, &bounds); ttfGetBounds(font, &bounds);
@ -1367,10 +1533,7 @@ pdfioFileCreateFontObjFromFile(
pdfioArrayAppendNumber(bbox, bounds.top); pdfioArrayAppendNumber(bbox, bounds.top);
if ((desc = pdfioDictCreate(pdf)) == NULL) if ((desc = pdfioDictCreate(pdf)) == NULL)
{ goto done;
ttfDelete(font);
return (NULL);
}
basefont = pdfioStringCreate(pdf, ttfGetPostScriptName(font)); basefont = pdfioStringCreate(pdf, ttfGetPostScriptName(font));
@ -1389,59 +1552,70 @@ pdfioFileCreateFontObjFromFile(
pdfioDictSetNumber(desc, "StemV", ttfGetWeight(font) / 4 + 25); pdfioDictSetNumber(desc, "StemV", ttfGetWeight(font) / 4 + 25);
if ((desc_obj = pdfioFileCreateObj(pdf, desc)) == NULL) if ((desc_obj = pdfioFileCreateObj(pdf, desc)) == NULL)
{ goto done;
ttfDelete(font);
return (NULL);
}
pdfioObjClose(desc_obj); pdfioObjClose(desc_obj);
if (unicode) if (unicode)
{ {
// Unicode (CID) font... // Unicode (CID) font...
pdfio_dict_t *cid2gid; // CIDToGIDMap dictionary pdfio_dict_t *cid2gid, // CIDToGIDMap dictionary
pdfio_obj_t *cid2gid_obj; // CIDToGIDMap object *to_unicode; // ToUnicode dictionary
pdfio_obj_t *cid2gid_obj, // CIDToGIDMap object
*to_unicode_obj;// ToUnicode object
size_t i, // Looping var size_t i, // Looping var
start, // Start character
num_cmap; // Number of CMap entries num_cmap; // Number of CMap entries
const int *cmap; // CMap entries const int *cmap; // CMap entries
int min_glyph, // First glyph
max_glyph; // Last glyph
unsigned short glyphs[65536]; // Glyph to Unicode mapping
unsigned char *bufptr, // Pointer into buffer unsigned char *bufptr, // Pointer into buffer
*bufend; // End of buffer *bufend; // End of buffer
pdfio_dict_t *type2; // CIDFontType2 font dictionary pdfio_dict_t *type2; // CIDFontType2 font dictionary
pdfio_obj_t *type2_obj; // CIDFontType2 font object pdfio_obj_t *type2_obj; // CIDFontType2 font object
pdfio_array_t *descendants; // Decendant font list pdfio_array_t *descendants; // Decendant font list
pdfio_dict_t *sidict; // CIDSystemInfo dictionary pdfio_dict_t *sidict; // CIDSystemInfo dictionary
pdfio_array_t *w_array, // Width array
*temp_array; // Temporary width sub-array
int w0, w1; // Widths
// Create a CIDSystemInfo mapping to Adobe UCS2 v0 (Unicode)
if ((sidict = pdfioDictCreate(pdf)) == NULL)
goto done;
pdfioDictSetString(sidict, "Registry", "Adobe");
pdfioDictSetString(sidict, "Ordering", "Identity");
pdfioDictSetNumber(sidict, "Supplement", 0);
// Create a CIDToGIDMap object for the Unicode font... // Create a CIDToGIDMap object for the Unicode font...
if ((cid2gid = pdfioDictCreate(pdf)) == NULL) if ((cid2gid = pdfioDictCreate(pdf)) == NULL)
{ goto done;
ttfDelete(font);
return (NULL);
}
#ifndef DEBUG #ifndef DEBUG
pdfioDictSetName(cid2gid, "Filter", "FlateDecode"); pdfioDictSetName(cid2gid, "Filter", "FlateDecode");
#endif // !DEBUG #endif // !DEBUG
if ((cid2gid_obj = pdfioFileCreateObj(pdf, cid2gid)) == NULL) if ((cid2gid_obj = pdfioFileCreateObj(pdf, cid2gid)) == NULL)
{ goto done;
ttfDelete(font);
return (NULL);
}
#ifdef DEBUG #ifdef DEBUG
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_NONE)) == NULL) if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_NONE)) == NULL)
#else #else
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_FLATE)) == NULL) if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_FLATE)) == NULL)
#endif // DEBUG #endif // DEBUG
{ goto done;
ttfDelete(font);
return (NULL);
}
cmap = ttfGetCMap(font, &num_cmap); cmap = ttfGetCMap(font, &num_cmap);
min_glyph = 65536;
max_glyph = 0;
memset(glyphs, 0, sizeof(glyphs));
PDFIO_DEBUG("pdfioFileCreateFontObjFromFile: num_cmap=%u\n", (unsigned)num_cmap);
for (i = 0, bufptr = buffer, bufend = buffer + sizeof(buffer); i < num_cmap; i ++) for (i = 0, bufptr = buffer, bufend = buffer + sizeof(buffer); i < num_cmap; i ++)
{ {
PDFIO_DEBUG("pdfioFileCreateFontObjFromFile: cmap[%u]=%d\n", (unsigned)i, cmap[i]);
if (cmap[i] < 0) if (cmap[i] < 0)
{ {
// Map undefined glyph to .notdef... // Map undefined glyph to .notdef...
@ -1453,6 +1627,12 @@ pdfioFileCreateFontObjFromFile(
// Map to specified glyph... // Map to specified glyph...
*bufptr++ = (unsigned char)(cmap[i] >> 8); *bufptr++ = (unsigned char)(cmap[i] >> 8);
*bufptr++ = (unsigned char)(cmap[i] & 255); *bufptr++ = (unsigned char)(cmap[i] & 255);
glyphs[cmap[i]] = i;
if (cmap[i] < min_glyph)
min_glyph = cmap[i];
if (cmap[i] > max_glyph)
max_glyph = cmap[i];
} }
if (bufptr >= bufend) if (bufptr >= bufend)
@ -1461,8 +1641,7 @@ pdfioFileCreateFontObjFromFile(
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer))) if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
{ {
pdfioStreamClose(st); pdfioStreamClose(st);
ttfDelete(font); goto done;
return (NULL);
} }
bufptr = buffer; bufptr = buffer;
@ -1475,30 +1654,102 @@ pdfioFileCreateFontObjFromFile(
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer))) if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
{ {
pdfioStreamClose(st); pdfioStreamClose(st);
ttfDelete(font); goto done;
return (NULL);
} }
} }
pdfioStreamClose(st); pdfioStreamClose(st);
// ToUnicode mapping object
to_unicode = pdfioDictCreate(pdf);
pdfioDictSetName(to_unicode, "Type", "CMap");
pdfioDictSetName(to_unicode, "CMapName", "Adobe-Identity-UCS2");
pdfioDictSetDict(to_unicode, "CIDSystemInfo", sidict);
#ifndef DEBUG
pdfioDictSetName(to_unicode, "Filter", "FlateDecode");
#endif // !DEBUG
if ((to_unicode_obj = pdfioFileCreateObj(pdf, to_unicode)) == NULL)
goto done;
#ifdef DEBUG
if ((st = pdfioObjCreateStream(to_unicode_obj, PDFIO_FILTER_NONE)) == NULL)
#else
if ((st = pdfioObjCreateStream(to_unicode_obj, PDFIO_FILTER_FLATE)) == NULL)
#endif // DEBUG
goto done;
pdfioStreamPuts(st,
"stream\n"
"/CIDInit /ProcSet findresource begin\n"
"12 dict begin\n"
"begincmap\n"
"/CIDSystemInfo<<\n"
"/Registry (Adobe)\n"
"/Ordering (UCS2)\n"
"/Supplement 0\n"
">> def\n"
"/CMapName /Adobe-Identity-UCS2 def\n"
"/CMapType 2 def\n"
"1 begincodespacerange\n"
"<0000> <FFFF>\n"
"endcodespacerange\n"
"1 beginbfrange\n"
"<0000> <FFFF> <0000>\n"
"endbfrange\n"
"endcmap\n"
"CMapName currentdict /CMap defineresource pop\n"
"end\n"
"end\n");
pdfioStreamClose(st);
// Create a CIDFontType2 dictionary for the Unicode font... // Create a CIDFontType2 dictionary for the Unicode font...
if ((type2 = pdfioDictCreate(pdf)) == NULL) if ((type2 = pdfioDictCreate(pdf)) == NULL)
goto done;
// Width array
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
goto done;
for (start = 0, w0 = ttfGetWidth(font, 0), i = 1; i < 65536; start = i, w0 = w1, i ++)
{ {
ttfDelete(font); while (i < 65536 && (w1 = ttfGetWidth(font, i)) == w0)
return (NULL); i ++;
if ((i - start) > 1)
{
// Encode a repeating sequence...
pdfioArrayAppendNumber(w_array, start);
pdfioArrayAppendNumber(w_array, i - 1);
pdfioArrayAppendNumber(w_array, w0);
}
else
{
// Encode a non-repeating sequence...
pdfioArrayAppendNumber(w_array, start);
if ((temp_array = pdfioArrayCreate(pdf)) == NULL)
goto done;
pdfioArrayAppendNumber(temp_array, w0);
for (w0 = w1, i ++; i < 65536; w0 = w1, i ++)
{
if ((w1 = ttfGetWidth(font, i)) == w0 && i < 65535)
break;
pdfioArrayAppendNumber(temp_array, w0);
} }
if ((sidict = pdfioDictCreate(pdf)) == NULL) if (i == 65536)
{ pdfioArrayAppendNumber(temp_array, w0);
ttfDelete(font); else
return (NULL); i --;
}
// CIDSystemInfo mapping to Adobe UCS2 v0 (Unicode) pdfioArrayAppendArray(w_array, temp_array);
pdfioDictSetString(sidict, "Registry", "Adobe"); }
pdfioDictSetString(sidict, "Ordering", "Identity"); }
pdfioDictSetNumber(sidict, "Supplement", 0);
// Then the dictionary for the CID base font... // Then the dictionary for the CID base font...
pdfioDictSetName(type2, "Type", "Font"); pdfioDictSetName(type2, "Type", "Font");
@ -1507,56 +1758,41 @@ pdfioFileCreateFontObjFromFile(
pdfioDictSetDict(type2, "CIDSystemInfo", sidict); pdfioDictSetDict(type2, "CIDSystemInfo", sidict);
pdfioDictSetObj(type2, "CIDToGIDMap", cid2gid_obj); pdfioDictSetObj(type2, "CIDToGIDMap", cid2gid_obj);
pdfioDictSetObj(type2, "FontDescriptor", desc_obj); pdfioDictSetObj(type2, "FontDescriptor", desc_obj);
pdfioDictSetArray(type2, "W", w_array);
if ((type2_obj = pdfioFileCreateObj(pdf, type2)) == NULL) if ((type2_obj = pdfioFileCreateObj(pdf, type2)) == NULL)
{ goto done;
ttfDelete(font);
return (NULL);
}
pdfioObjClose(type2_obj); pdfioObjClose(type2_obj);
// Create a Type 0 font object... // Create a Type 0 font object...
if ((descendants = pdfioArrayCreate(pdf)) == NULL) if ((descendants = pdfioArrayCreate(pdf)) == NULL)
{ goto done;
ttfDelete(font);
return (NULL);
}
pdfioArrayAppendObj(descendants, type2_obj); pdfioArrayAppendObj(descendants, type2_obj);
if ((dict = pdfioDictCreate(pdf)) == NULL) if ((dict = pdfioDictCreate(pdf)) == NULL)
{ goto done;
ttfDelete(font);
return (NULL);
}
pdfioDictSetName(dict, "Type", "Font"); pdfioDictSetName(dict, "Type", "Font");
pdfioDictSetName(dict, "Subtype", "Type0"); pdfioDictSetName(dict, "Subtype", "Type0");
pdfioDictSetName(dict, "BaseFont", basefont); pdfioDictSetName(dict, "BaseFont", basefont);
pdfioDictSetArray(dict, "DescendantFonts", descendants); pdfioDictSetArray(dict, "DescendantFonts", descendants);
pdfioDictSetName(dict, "Encoding", "Identity-H"); pdfioDictSetName(dict, "Encoding", "Identity-H");
pdfioDictSetObj(dict, "ToUnicode", to_unicode_obj);
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL) if ((obj = pdfioFileCreateObj(pdf, dict)) != NULL)
return (NULL);
pdfioObjClose(obj); pdfioObjClose(obj);
} }
else else
{ {
// Simple (CP1282 or custom encoding) 8-bit font... // Simple (CP1282 or custom encoding) 8-bit font...
if (ttfGetMaxChar(font) >= 255 && !pdf->cp1252_obj && !create_cp1252(pdf)) if (ttfGetMaxChar(font) >= 255 && !pdf->cp1252_obj && !create_cp1252(pdf))
{ goto done;
ttfDelete(font);
return (NULL);
}
// Create a TrueType font object... // Create a TrueType font object...
if ((dict = pdfioDictCreate(pdf)) == NULL) if ((dict = pdfioDictCreate(pdf)) == NULL)
{ goto done;
ttfDelete(font);
return (NULL);
}
pdfioDictSetName(dict, "Type", "Font"); pdfioDictSetName(dict, "Type", "Font");
pdfioDictSetName(dict, "Subtype", "TrueType"); pdfioDictSetName(dict, "Subtype", "TrueType");
@ -1566,16 +1802,16 @@ pdfioFileCreateFontObjFromFile(
pdfioDictSetObj(dict, "FontDescriptor", desc_obj); pdfioDictSetObj(dict, "FontDescriptor", desc_obj);
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL) if ((obj = pdfioFileCreateObj(pdf, dict)) != NULL)
{
ttfDelete(font);
return (NULL);
}
pdfioObjClose(obj); pdfioObjClose(obj);
} }
ttfDelete(font); done:
if (fd >= 0)
close(fd);
_pdfioObjSetExtension(obj, font, (_pdfio_extfree_t)ttfDelete);
return (obj); return (obj);
} }

View File

@ -1,7 +1,7 @@
// //
// Public content header file for PDFio. // Public content header file for PDFio.
// //
// Copyright © 2021 by Michael R Sweet. // Copyright © 2021-2023 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -9,18 +9,7 @@
#ifndef PDFIO_CONTENT_H #ifndef PDFIO_CONTENT_H
# define PDFIO_CONTENT_H # define PDFIO_CONTENT_H
//
// Include necessary headers...
//
# include "pdfio.h" # include "pdfio.h"
//
// C++ magic...
//
# ifdef __cplusplus # ifdef __cplusplus
extern "C" { extern "C" {
# endif // __cplusplus # endif // __cplusplus
@ -126,9 +115,12 @@ extern bool pdfioContentSetTextXScaling(pdfio_stream_t *st, double percent) _PD
extern bool pdfioContentStroke(pdfio_stream_t *st) _PDFIO_PUBLIC; extern bool pdfioContentStroke(pdfio_stream_t *st) _PDFIO_PUBLIC;
extern bool pdfioContentTextBegin(pdfio_stream_t *st) _PDFIO_PUBLIC; extern bool pdfioContentTextBegin(pdfio_stream_t *st) _PDFIO_PUBLIC;
extern bool pdfioContentTextEnd(pdfio_stream_t *st) _PDFIO_PUBLIC; extern bool pdfioContentTextEnd(pdfio_stream_t *st) _PDFIO_PUBLIC;
extern double pdfioContentTextMeasure(pdfio_obj_t *font, const char *s, double size) _PDFIO_PUBLIC;
extern bool pdfioContentTextMoveLine(pdfio_stream_t *st, double tx, double ty) _PDFIO_PUBLIC; extern bool pdfioContentTextMoveLine(pdfio_stream_t *st, double tx, double ty) _PDFIO_PUBLIC;
extern bool pdfioContentTextMoveTo(pdfio_stream_t *st, double tx, double ty) _PDFIO_PUBLIC; extern bool pdfioContentTextMoveTo(pdfio_stream_t *st, double tx, double ty) _PDFIO_PUBLIC;
extern bool pdfioContentTextNextLine(pdfio_stream_t *st) _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 pdfioContentTextShow(pdfio_stream_t *st, bool unicode, const char *s) _PDFIO_PUBLIC; extern bool pdfioContentTextShow(pdfio_stream_t *st, bool unicode, const char *s) _PDFIO_PUBLIC;
extern bool pdfioContentTextShowf(pdfio_stream_t *st, bool unicode, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(3,4); extern bool pdfioContentTextShowf(pdfio_stream_t *st, bool unicode, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(3,4);
extern bool pdfioContentTextShowJustified(pdfio_stream_t *st, bool unicode, size_t num_fragments, const double *offsets, const char * const *fragments) _PDFIO_PUBLIC; extern bool pdfioContentTextShowJustified(pdfio_stream_t *st, bool unicode, size_t num_fragments, const double *offsets, const char * const *fragments) _PDFIO_PUBLIC;
@ -151,10 +143,6 @@ extern bool pdfioPageDictAddFont(pdfio_dict_t *dict, const char *name, pdfio_ob
extern bool pdfioPageDictAddImage(pdfio_dict_t *dict, const char *name, pdfio_obj_t *obj) _PDFIO_PUBLIC; extern bool pdfioPageDictAddImage(pdfio_dict_t *dict, const char *name, pdfio_obj_t *obj) _PDFIO_PUBLIC;
//
// C++ magic...
//
# ifdef __cplusplus # ifdef __cplusplus
} }
# endif // __cplusplus # endif // __cplusplus

View File

@ -1,7 +1,7 @@
// //
// Cryptographic support functions for PDFio. // Cryptographic support functions for PDFio.
// //
// Copyright © 2021 by Michael R Sweet. // Copyright © 2021-2023 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -446,10 +446,18 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
// Initialize the RC4 context using 40 bits of the digest... // Initialize the RC4 context using 40 bits of the digest...
_pdfioCryptoRC4Init(&ctx->rc4, digest, 5); _pdfioCryptoRC4Init(&ctx->rc4, digest, 5);
*ivlen = 0;
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt); return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
case PDFIO_ENCRYPTION_RC4_128 :
case PDFIO_ENCRYPTION_AES_128 : case PDFIO_ENCRYPTION_AES_128 :
if (*ivlen < 16)
{
*ivlen = 0;
_pdfioFileError(pdf, "Value too short for AES encryption.");
return (NULL);
}
case PDFIO_ENCRYPTION_RC4_128 :
// Copy the key data for the MD5 hash. // Copy the key data for the MD5 hash.
memcpy(data, pdf->file_key, sizeof(pdf->file_key)); memcpy(data, pdf->file_key, sizeof(pdf->file_key));
data[16] = (uint8_t)obj->number; data[16] = (uint8_t)obj->number;

View File

@ -334,6 +334,32 @@ pdfioFileCreateArrayObj(
} }
//
// 'pdfioFileCreateNumberObj()' - Create a new object in a PDF file containing a number.
//
// This function creates a new object with a number value in a PDF file.
// You must call @link pdfioObjClose@ to write the object to the file.
//
pdfio_obj_t * // O - New object
pdfioFileCreateNumberObj(
pdfio_file_t *pdf, // I - PDF file
double number) // I - Number value
{
_pdfio_value_t value; // Object value
// Range check input...
if (!pdf)
return (NULL);
value.type = PDFIO_VALTYPE_NUMBER;
value.value.number = number;
return (_pdfioFileCreateObj(pdf, NULL, &value));
}
// //
// 'pdfioFileCreateObj()' - Create a new object in a PDF file. // 'pdfioFileCreateObj()' - Create a new object in a PDF file.
// //
@ -639,6 +665,32 @@ pdfioFileCreatePage(pdfio_file_t *pdf, // I - PDF file
} }
//
// 'pdfioFileCreateStringObj()' - Create a new object in a PDF file containing a string.
//
// This function creates a new object with a string value in a PDF file.
// You must call @link pdfioObjClose@ to write the object to the file.
//
pdfio_obj_t * // O - New object
pdfioFileCreateStringObj(
pdfio_file_t *pdf, // I - PDF file
const char *string) // I - String
{
_pdfio_value_t value; // Object value
// Range check input...
if (!pdf)
return (NULL);
value.type = PDFIO_VALTYPE_STRING;
value.value.string = string;
return (_pdfioFileCreateObj(pdf, NULL, &value));
}
// //
// 'pdfioFileCreateTemporary()' - Create a temporary PDF file. // 'pdfioFileCreateTemporary()' - Create a temporary PDF file.
// //
@ -1514,6 +1566,7 @@ load_obj_stream(pdfio_obj_t *obj) // I - Object to load
// Skip offset // Skip offset
_pdfioTokenGet(&tb, buffer, sizeof(buffer)); _pdfioTokenGet(&tb, buffer, sizeof(buffer));
PDFIO_DEBUG("load_obj_stream: %ld at offset %s\n", (long)number, buffer);
} }
if (!buffer[0]) if (!buffer[0])
@ -1737,6 +1790,10 @@ load_xref(
return (false); return (false);
} }
PDFIO_DEBUG("load_xref: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[0]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
if (tb.bufptr && tb.bufptr < tb.bufend && (tb.bufptr[0] == 0x0d || tb.bufptr[0] == 0x0a))
tb.bufptr ++; // Skip trailing CR or LF after token
_pdfioTokenFlush(&tb); _pdfioTokenFlush(&tb);
obj->stream_offset = _pdfioFileTell(pdf); obj->stream_offset = _pdfioFileTell(pdf);
@ -1759,9 +1816,9 @@ load_xref(
w_2 = w[0]; w_2 = w[0];
w_3 = w[0] + w[1]; w_3 = w[0] + w[1];
if (w[1] == 0 || w[2] > 2 || w[0] > sizeof(buffer) || w[1] > sizeof(buffer) || w[2] > sizeof(buffer) || w_total > sizeof(buffer)) if (w[1] == 0 || w[2] > 4 || w[0] > sizeof(buffer) || w[1] > sizeof(buffer) || w[2] > sizeof(buffer) || w_total > sizeof(buffer))
{ {
_pdfioFileError(pdf, "Cross-reference stream has invalid W key."); _pdfioFileError(pdf, "Cross-reference stream has invalid W key [%u %u %u].", (unsigned)w[0], (unsigned)w[1], (unsigned)w[2]);
return (false); return (false);
} }
@ -1801,9 +1858,11 @@ load_xref(
} }
} }
// Offset
for (i = 1, offset = buffer[w_2]; i < w[1]; i ++) for (i = 1, offset = buffer[w_2]; i < w[1]; i ++)
offset = (offset << 8) | buffer[w_2 + i]; offset = (offset << 8) | buffer[w_2 + i];
// Generation number
switch (w[2]) switch (w[2])
{ {
default : default :
@ -1815,6 +1874,19 @@ load_xref(
case 2 : case 2 :
generation = (buffer[w_3] << 8) | buffer[w_3 + 1]; generation = (buffer[w_3] << 8) | buffer[w_3 + 1];
break; break;
case 3 :
// Issue #46: Stupid Microsoft PDF generator using 3 bytes to
// encode 16-bit generation numbers == 0 (probably a lazy coder
// stuffing things into an array of 64-bit unsigned integers)
generation = (buffer[w_3] << 16) | (buffer[w_3 + 1] << 8) | buffer[w_3 + 2];
if (generation > 65535)
generation = 65535;
break;
case 4 : // Even stupider :)
generation = (buffer[w_3] << 24) | (buffer[w_3 + 1] << 16) | (buffer[w_3 + 2] << 8) | buffer[w_3 + 3];
if (generation > 65535)
generation = 65535;
break;
} }
// Create a placeholder for the object in memory... // Create a placeholder for the object in memory...
@ -1846,9 +1918,19 @@ load_xref(
break; break;
} }
if (i >= num_sobjs && num_sobjs < (sizeof(sobjs) / sizeof(sobjs[0]))) if (i >= num_sobjs)
{
if (num_sobjs < (sizeof(sobjs) / sizeof(sobjs[0])))
{
sobjs[num_sobjs ++] = (size_t)offset; sobjs[num_sobjs ++] = (size_t)offset;
} }
else
{
_pdfioFileError(pdf, "Too many object streams.");
return (false);
}
}
}
else if (!current) else if (!current)
{ {
// Add this object... // Add this object...
@ -1895,12 +1977,12 @@ load_xref(
} }
} }
} }
else if (!strcmp(line, "xref")) else if (!strncmp(line, "xref", 4) && (!line[4] || isspace(line[4] & 255)))
{ {
// Read the xref tables // Read the xref tables
while (_pdfioFileGets(pdf, line, sizeof(line))) while (_pdfioFileGets(pdf, line, sizeof(line)))
{ {
if (!strcmp(line, "trailer")) if (!strncmp(line, "trailer", 7) && (!line[7] || isspace(line[7] & 255)))
break; break;
else if (!line[0]) else if (!line[0])
continue; continue;
@ -1965,7 +2047,7 @@ load_xref(
} }
} }
if (strcmp(line, "trailer")) if (strncmp(line, "trailer", 7))
{ {
_pdfioFileError(pdf, "Missing trailer."); _pdfioFileError(pdf, "Missing trailer.");
return (false); return (false);

View File

@ -7,10 +7,6 @@
// information. // information.
// //
//
// Include necessary headers...
//
#include "pdfio-private.h" #include "pdfio-private.h"
@ -221,8 +217,13 @@ void
_pdfioObjDelete(pdfio_obj_t *obj) // I - Object _pdfioObjDelete(pdfio_obj_t *obj) // I - Object
{ {
if (obj) if (obj)
{
pdfioStreamClose(obj->stream); pdfioStreamClose(obj->stream);
if (obj->datafree)
(obj->datafree)(obj->data);
}
free(obj); free(obj);
} }
@ -267,6 +268,17 @@ pdfioObjGetDict(pdfio_obj_t *obj) // I - Object
} }
//
// '_pdfioObjGetExtension()' - Get the extension pointer for an object.
//
void * // O - Extension data
_pdfioObjGetExtension(pdfio_obj_t *obj) // I - Object
{
return (obj->data);
}
// //
// 'pdfioObjGetGeneration()' - Get the object's generation number. // 'pdfioObjGetGeneration()' - Get the object's generation number.
// //
@ -420,6 +432,9 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
} }
ptr += 3; ptr += 3;
while (*ptr && isspace(*ptr & 255))
ptr ++;
_pdfioFileConsume(obj->pdf, (size_t)(ptr - line)); _pdfioFileConsume(obj->pdf, (size_t)(ptr - line));
// Then grab the object value... // Then grab the object value...
@ -438,11 +453,15 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
return (false); return (false);
} }
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[0]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
if (tb.bufptr && tb.bufptr < tb.bufend && (tb.bufptr[0] == 0x0d || tb.bufptr[0] == 0x0a))
tb.bufptr ++; // Skip trailing CR or LF after token
_pdfioTokenFlush(&tb); _pdfioTokenFlush(&tb);
if (!strcmp(line, "stream")) if (!strcmp(line, "stream"))
{ {
// Yes, save its location... // Yes, this is an embedded stream so save its location...
obj->stream_offset = _pdfioFileTell(obj->pdf); obj->stream_offset = _pdfioFileTell(obj->pdf);
PDFIO_DEBUG("_pdfioObjLoad: stream_offset=%lu.\n", (unsigned long)obj->stream_offset); PDFIO_DEBUG("_pdfioObjLoad: stream_offset=%lu.\n", (unsigned long)obj->stream_offset);
} }
@ -491,6 +510,21 @@ pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object
} }
//
// '_pdfioObjSetExtension()' - Set extension data for an object.
//
void
_pdfioObjSetExtension(
pdfio_obj_t *obj, // I - Object
void *data, // I - Data
_pdfio_extfree_t datafree) // I - Free function
{
obj->data = data;
obj->datafree = datafree;
}
// //
// 'write_obj_header()' - Write the object header... // 'write_obj_header()' - Write the object header...
// //

View File

@ -1,7 +1,7 @@
// //
// Private header file for PDFio. // Private header file for PDFio.
// //
// Copyright © 2021-2022 by Michael R Sweet. // Copyright © 2021-2023 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -9,41 +9,22 @@
#ifndef PDFIO_PRIVATE_H #ifndef PDFIO_PRIVATE_H
# define PDFIO_PRIVATE_H # define PDFIO_PRIVATE_H
//
// Include necessary headers...
//
# ifdef _WIN32 # ifdef _WIN32
/* # define _CRT_SECURE_NO_WARNINGS // Disable bogus VS warnings/errors...
* Disable bogus VS warnings/errors...
*/
# define _CRT_SECURE_NO_WARNINGS
# endif // _WIN32 # endif // _WIN32
# include "pdfio.h" # include "pdfio.h"
# include <stdarg.h> # include <stdarg.h>
# include <stdint.h> # include <stdint.h>
# include <string.h> # include <string.h>
# include <ctype.h>
# include <errno.h> # include <errno.h>
# include <inttypes.h> # include <inttypes.h>
# include <fcntl.h> # include <fcntl.h>
# ifdef _WIN32 # ifdef _WIN32
# include <io.h> # include <io.h>
# include <direct.h> # include <direct.h>
# include <windows.h> // GetTempPathA
/* # define access _access // Map standard POSIX/C99 names
* Microsoft renames the POSIX functions to _name, and introduces
* a broken compatibility layer using the original names. As a result,
* random crashes can occur when, for example, strdup() allocates memory
* from a different heap than used by malloc() and free().
*
* To avoid moronic problems like this, we #define the POSIX function
* names to the corresponding non-standard Microsoft names.
*/
# define access _access
# define close _close # define close _close
# define fileno _fileno # define fileno _fileno
# define lseek _lseek # define lseek _lseek
@ -56,25 +37,18 @@
# define unlink _unlink # define unlink _unlink
# define vsnprintf _vsnprintf # define vsnprintf _vsnprintf
# define write _write # define write _write
# define F_OK 00 // POSIX parameters/flags
/*
* Map various parameters for POSIX...
*/
# define F_OK 00
# define W_OK 02 # define W_OK 02
# define R_OK 04 # define R_OK 04
# define O_RDONLY _O_RDONLY # define O_RDONLY _O_RDONLY // Map standard POSIX open flags
# define O_WRONLY _O_WRONLY # define O_WRONLY _O_WRONLY
# define O_CREAT _O_CREAT # define O_CREAT _O_CREAT
# define O_TRUNC _O_TRUNC # define O_TRUNC _O_TRUNC
# define O_BINARY _O_BINARY # define O_BINARY _O_BINARY
# else // !_WIN32 # else // !_WIN32
# include <unistd.h> # include <unistd.h>
# define O_BINARY 0 # define O_BINARY 0 // Map Windows-specific open flag
# endif // _WIN32 # endif // _WIN32
# include <string.h>
# include <ctype.h>
# include <zlib.h> # include <zlib.h>
@ -118,6 +92,9 @@
# define PDFIO_MAX_DEPTH 32 // Maximum nesting depth for values # define PDFIO_MAX_DEPTH 32 // Maximum nesting depth for values
typedef void (*_pdfio_extfree_t)(void *);
// Extension data free function
typedef enum _pdfio_mode_e // Read/write mode typedef enum _pdfio_mode_e // Read/write mode
{ {
_PDFIO_MODE_READ, // Read a PDF file _PDFIO_MODE_READ, // Read a PDF file
@ -313,6 +290,8 @@ struct _pdfio_obj_s // Object
size_t stream_length; // Length of stream, if any size_t stream_length; // Length of stream, if any
_pdfio_value_t value; // Dictionary/number/etc. value _pdfio_value_t value; // Dictionary/number/etc. value
pdfio_stream_t *stream; // Open stream, if any pdfio_stream_t *stream; // Open stream, if any
void *data; // Extension data, if any
_pdfio_extfree_t datafree; // Free callback for extension data
}; };
struct _pdfio_stream_s // Stream struct _pdfio_stream_s // Stream
@ -391,7 +370,9 @@ extern off_t _pdfioFileTell(pdfio_file_t *pdf) _PDFIO_INTERNAL;
extern bool _pdfioFileWrite(pdfio_file_t *pdf, const void *buffer, size_t bytes) _PDFIO_INTERNAL; extern bool _pdfioFileWrite(pdfio_file_t *pdf, const void *buffer, size_t bytes) _PDFIO_INTERNAL;
extern void _pdfioObjDelete(pdfio_obj_t *obj) _PDFIO_INTERNAL; extern void _pdfioObjDelete(pdfio_obj_t *obj) _PDFIO_INTERNAL;
extern void *_pdfioObjGetExtension(pdfio_obj_t *obj) _PDFIO_INTERNAL;
extern bool _pdfioObjLoad(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 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, pdfio_filter_t compression) _PDFIO_INTERNAL;
extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL; extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL;
@ -411,4 +392,5 @@ extern void _pdfioValueDelete(_pdfio_value_t *v) _PDFIO_INTERNAL;
extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL; extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
extern bool _pdfioValueWrite(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_value_t *v, off_t *length) _PDFIO_INTERNAL; extern bool _pdfioValueWrite(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_value_t *v, off_t *length) _PDFIO_INTERNAL;
#endif // !PDFIO_PRIVATE_H #endif // !PDFIO_PRIVATE_H

View File

@ -1,7 +1,7 @@
// //
// SHA-256 functions for PDFio. // SHA-256 functions for PDFio.
// //
// Copyright © 2021 by Michael R Sweet. // Copyright © 2021-2023 by Michael R Sweet.
// Copyright © 2011 IETF Trust and the persons identified as authors of the // Copyright © 2011 IETF Trust and the persons identified as authors of the
// code. All rights reserved. // code. All rights reserved.
// //
@ -217,7 +217,7 @@ _pdfioCryptoSHA256Append(_pdfio_sha256_t *context, const uint8_t *message_array,
*/ */
void void
_pdfioCryptoSHA256Finish(_pdfio_sha256_t *context, _pdfioCryptoSHA256Finish(_pdfio_sha256_t *context,
uint8_t Message_Digest[SHA256HashSize]) uint8_t *Message_Digest)
{ {
SHA224_256ResultN(context, Message_Digest, SHA256HashSize); SHA224_256ResultN(context, Message_Digest, SHA256HashSize);
} }

View File

@ -452,6 +452,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
return (NULL); return (NULL);
} }
PDFIO_DEBUG("_pdfioStreamOpen: ivlen=%d\n", (int)ivlen);
if (ivlen > 0) if (ivlen > 0)
_pdfioFileConsume(st->pdf, ivlen); _pdfioFileConsume(st->pdf, ivlen);
@ -464,11 +465,19 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
// Try to decode/decompress the contents of this object... // Try to decode/decompress the contents of this object...
const char *filter = pdfioDictGetName(dict, "Filter"); const char *filter = pdfioDictGetName(dict, "Filter");
// Filter value // Filter value
pdfio_array_t *fa = pdfioDictGetArray(dict, "Filter");
// Filter array
if (!filter && fa && pdfioArrayGetSize(fa) == 1)
{
// Support single-valued arrays...
filter = pdfioArrayGetName(fa, 0);
}
if (!filter) if (!filter)
{ {
// No single filter name, do we have a compound filter? // No single filter name, do we have a compound filter?
if (pdfioDictGetArray(dict, "Filter")) if (fa)
{ {
// TODO: Implement compound filters... // TODO: Implement compound filters...
_pdfioFileError(st->pdf, "Unsupported compound stream filter."); _pdfioFileError(st->pdf, "Unsupported compound stream filter.");
@ -559,6 +568,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
else else
st->predictor = _PDFIO_PREDICTOR_NONE; st->predictor = _PDFIO_PREDICTOR_NONE;
PDFIO_DEBUG("_pdfioStreamOpen: pos=%ld\n", (long)_pdfioFileTell(st->pdf));
if (sizeof(st->cbuffer) > st->remaining) if (sizeof(st->cbuffer) > st->remaining)
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining); rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
else else
@ -579,12 +589,6 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
st->flate.next_in = (Bytef *)st->cbuffer; st->flate.next_in = (Bytef *)st->cbuffer;
st->flate.avail_in = (uInt)rbytes; st->flate.avail_in = (uInt)rbytes;
if (st->cbuffer[0] == 0x0a)
{
st->flate.next_in ++; // Skip newline
st->flate.avail_in --;
}
PDFIO_DEBUG("_pdfioStreamOpen: avail_in=%u, cbuffer=<%02X%02X%02X%02X%02X%02X%02X%02X...>\n", st->flate.avail_in, st->cbuffer[0], st->cbuffer[1], st->cbuffer[2], st->cbuffer[3], st->cbuffer[4], st->cbuffer[5], st->cbuffer[6], st->cbuffer[7]); PDFIO_DEBUG("_pdfioStreamOpen: avail_in=%u, cbuffer=<%02X%02X%02X%02X%02X%02X%02X%02X...>\n", st->flate.avail_in, st->cbuffer[0], st->cbuffer[1], st->cbuffer[2], st->cbuffer[3], st->cbuffer[4], st->cbuffer[5], st->cbuffer[6], st->cbuffer[7]);
if ((status = inflateInit(&(st->flate))) != Z_OK) if ((status = inflateInit(&(st->flate))) != Z_OK)
@ -1008,6 +1012,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
size_t bytes) // I - Number of bytes to read size_t bytes) // I - Number of bytes to read
{ {
ssize_t rbytes; // Bytes read ssize_t rbytes; // Bytes read
uInt avail_in, avail_out; // Previous flate values
if (st->filter == PDFIO_FILTER_NONE) if (st->filter == PDFIO_FILTER_NONE)
@ -1060,11 +1065,19 @@ stream_read(pdfio_stream_t *st, // I - Stream
st->flate.next_out = (Bytef *)buffer; st->flate.next_out = (Bytef *)buffer;
st->flate.avail_out = (uInt)bytes; 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) if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
{ {
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status)); _pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
return (-1); 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); return (st->flate.next_out - (Bytef *)buffer);
} }
@ -1113,12 +1126,15 @@ stream_read(pdfio_stream_t *st, // I - Stream
st->flate.avail_in = (uInt)rbytes; st->flate.avail_in = (uInt)rbytes;
} }
avail_in = st->flate.avail_in;
avail_out = st->flate.avail_out;
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK) if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
{ {
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status)); _pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
return (-1); return (-1);
} }
else if (status == Z_STREAM_END) else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
break; break;
} }
@ -1180,12 +1196,15 @@ stream_read(pdfio_stream_t *st, // I - Stream
st->flate.avail_in = (uInt)rbytes; st->flate.avail_in = (uInt)rbytes;
} }
avail_in = st->flate.avail_in;
avail_out = st->flate.avail_out;
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK) if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
{ {
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status)); _pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
return (-1); return (-1);
} }
else if (status == Z_STREAM_END) else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
break; break;
} }

View File

@ -495,6 +495,13 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
*bufptr++ = (char)ch; *bufptr++ = (char)ch;
break; break;
} }
else if (ch == '>')
{
// Issue #46: Empty hex string from Microsoft PDF generator; treat as
// empty literal string...
*buffer = '(';
break;
}
else if (!isspace(ch & 255) && !isxdigit(ch & 255)) else if (!isspace(ch & 255) && !isxdigit(ch & 255))
{ {
_pdfioFileError(tb->pdf, "Syntax error: '<%c'", ch); _pdfioFileError(tb->pdf, "Syntax error: '<%c'", ch);

View File

@ -383,7 +383,10 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
return (false); return (false);
} }
cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen); ivlen = v->value.binary.datalen;
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL)
return (false);
templen = (cb)(&ctx, temp, v->value.binary.data + ivlen, v->value.binary.datalen - ivlen); templen = (cb)(&ctx, temp, v->value.binary.data + ivlen, v->value.binary.datalen - ivlen);
// Copy the decrypted string back to the value and adjust the length... // Copy the decrypted string back to the value and adjust the length...

26
pdfio.h
View File

@ -1,7 +1,7 @@
// //
// Public header file for PDFio. // Public header file for PDFio.
// //
// Copyright © 2021-2022 by Michael R Sweet. // Copyright © 2021-2023 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -9,27 +9,23 @@
#ifndef PDFIO_H #ifndef PDFIO_H
# define PDFIO_H # define PDFIO_H
//
// Include necessary headers...
//
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
# include <stdbool.h> # include <stdbool.h>
# include <sys/types.h> # include <sys/types.h>
# include <time.h> # include <time.h>
//
// C++ magic...
//
# ifdef __cplusplus # ifdef __cplusplus
extern "C" { extern "C" {
# endif // __cplusplus # endif // __cplusplus
//
// Version number...
//
# define PDFIO_VERSION "1.2.0"
// //
// Visibility and other annotations... // Visibility and other annotations...
// //
@ -184,10 +180,12 @@ extern bool pdfioDictSetStringf(pdfio_dict_t *dict, const char *key, const char
extern bool pdfioFileClose(pdfio_file_t *pdf) _PDFIO_PUBLIC; extern bool pdfioFileClose(pdfio_file_t *pdf) _PDFIO_PUBLIC;
extern pdfio_file_t *pdfioFileCreate(const char *filename, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC; extern pdfio_file_t *pdfioFileCreate(const char *filename, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateArrayObj(pdfio_file_t *pdf, pdfio_array_t *array) _PDFIO_PUBLIC; extern pdfio_obj_t *pdfioFileCreateArrayObj(pdfio_file_t *pdf, pdfio_array_t *array) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateNumberObj(pdfio_file_t *pdf, double number) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC; extern pdfio_obj_t *pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
extern pdfio_file_t *pdfioFileCreateOutput(pdfio_output_cb_t output_cb, void *output_ctx, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC; extern pdfio_file_t *pdfioFileCreateOutput(pdfio_output_cb_t output_cb, void *output_ctx, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
// TODO: Add number, array, string, etc. versions of pdfioFileCreateObject? // TODO: Add number, array, string, etc. versions of pdfioFileCreateObject?
extern pdfio_stream_t *pdfioFileCreatePage(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC; extern pdfio_stream_t *pdfioFileCreatePage(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateStringObj(pdfio_file_t *pdf, const char *s) _PDFIO_PUBLIC;
extern pdfio_file_t *pdfioFileCreateTemporary(char *buffer, size_t bufsize, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC; extern pdfio_file_t *pdfioFileCreateTemporary(char *buffer, size_t bufsize, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileFindObj(pdfio_file_t *pdf, size_t number) _PDFIO_PUBLIC; extern pdfio_obj_t *pdfioFileFindObj(pdfio_file_t *pdf, size_t number) _PDFIO_PUBLIC;
extern const char *pdfioFileGetAuthor(pdfio_file_t *pdf) _PDFIO_PUBLIC; extern const char *pdfioFileGetAuthor(pdfio_file_t *pdf) _PDFIO_PUBLIC;
@ -244,10 +242,6 @@ 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_FORMAT(2,3) _PDFIO_PUBLIC;
//
// C++ magic...
//
# ifdef __cplusplus # ifdef __cplusplus
} }
# endif // __cplusplus # endif // __cplusplus

View File

@ -1,6 +1,13 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: pdfio Name: pdfio
Description: PDF read/write library Description: PDF read/write library
Version: @PDFIO_VERSION@
URL: https://www.msweet.org/pdfio URL: https://www.msweet.org/pdfio
Requires: zlib >= 1.0 Requires: @PKGCONFIG_REQUIRES@
Libs: -L${prefix}/lib -lpdfio -lm Libs: @PKGCONFIG_LIBS@
Cflags: -I${prefix}/include Libs.private: @PKGCONFIG_LIBS_PRIVATE@ -lm
Cflags: @PKGCONFIG_CFLAGS@

View File

@ -87,7 +87,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
</ClCompile> </ClCompile>
<Link> <Link>
@ -101,7 +101,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
</ClCompile> </ClCompile>
<Link> <Link>
@ -115,7 +115,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
</ClCompile> </ClCompile>
<Link> <Link>
@ -130,7 +130,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
</ClCompile> </ClCompile>
<Link> <Link>

View File

@ -372,7 +372,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1.1; CURRENT_PROJECT_VERSION = 1.1.2;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
@ -381,7 +381,6 @@
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
"DEBUG=1", "DEBUG=1",
"'PDFIO_VERSION=\"$(CURRENT_PROJECT_VERSION)\"'",
); );
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -397,7 +396,7 @@
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES; GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14; MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
@ -450,7 +449,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1.1; CURRENT_PROJECT_VERSION = 1.1.2;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
@ -459,7 +458,6 @@
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
"'PDFIO_VERSION=\"$(CURRENT_PROJECT_VERSION)\"'",
); );
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -475,7 +473,7 @@
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES; GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14; MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
RUN_CLANG_STATIC_ANALYZER = YES; RUN_CLANG_STATIC_ANALYZER = YES;
@ -515,7 +513,7 @@
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
MACOSX_DEPLOYMENT_TARGET = 10.14; MACOSX_DEPLOYMENT_TARGET = 11.0;
PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio; PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@ -529,7 +527,7 @@
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14; MACOSX_DEPLOYMENT_TARGET = 11.0;
PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio; PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";

View File

@ -1,5 +1,5 @@
LIBRARY pdfio1 LIBRARY pdfio1
VERSION 1.0 VERSION 1.2
EXPORTS EXPORTS
_pdfioArrayDebug _pdfioArrayDebug
_pdfioArrayDelete _pdfioArrayDelete
@ -47,7 +47,9 @@ _pdfioFileSeek
_pdfioFileTell _pdfioFileTell
_pdfioFileWrite _pdfioFileWrite
_pdfioObjDelete _pdfioObjDelete
_pdfioObjGetExtension
_pdfioObjLoad _pdfioObjLoad
_pdfioObjSetExtension
_pdfioStreamCreate _pdfioStreamCreate
_pdfioStreamOpen _pdfioStreamOpen
_pdfioStringIsAllocated _pdfioStringIsAllocated
@ -136,9 +138,12 @@ pdfioContentSetTextXScaling
pdfioContentStroke pdfioContentStroke
pdfioContentTextBegin pdfioContentTextBegin
pdfioContentTextEnd pdfioContentTextEnd
pdfioContentTextMeasure
pdfioContentTextMoveLine pdfioContentTextMoveLine
pdfioContentTextMoveTo pdfioContentTextMoveTo
pdfioContentTextNextLine pdfioContentTextNewLine
pdfioContentTextNewLineShow
pdfioContentTextNewLineShowf
pdfioContentTextShow pdfioContentTextShow
pdfioContentTextShowJustified pdfioContentTextShowJustified
pdfioContentTextShowf pdfioContentTextShowf
@ -176,9 +181,11 @@ pdfioFileCreateFontObjFromFile
pdfioFileCreateICCObjFromFile pdfioFileCreateICCObjFromFile
pdfioFileCreateImageObjFromData pdfioFileCreateImageObjFromData
pdfioFileCreateImageObjFromFile pdfioFileCreateImageObjFromFile
pdfioFileCreateNumberObj
pdfioFileCreateObj pdfioFileCreateObj
pdfioFileCreateOutput pdfioFileCreateOutput
pdfioFileCreatePage pdfioFileCreatePage
pdfioFileCreateStringObj
pdfioFileCreateTemporary pdfioFileCreateTemporary
pdfioFileFindObj pdfioFileFindObj
pdfioFileGetAuthor pdfioFileGetAuthor

View File

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

View File

@ -3,7 +3,7 @@
<metadata> <metadata>
<id>pdfio_native.redist</id> <id>pdfio_native.redist</id>
<title>PDFio Library for VS2019+</title> <title>PDFio Library for VS2019+</title>
<version>1.1.0</version> <version>1.2.0</version>
<authors>Michael R Sweet</authors> <authors>Michael R Sweet</authors>
<owners>michaelrsweet</owners> <owners>michaelrsweet</owners>
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl> <projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
@ -15,6 +15,9 @@
<summary>PDFio is a simple C library for reading and writing PDF files. This package provides the redistributable content for the PDFio library. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary> <summary>PDFio is a simple C library for reading and writing PDF files. This package provides the redistributable content for the PDFio library. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright> <copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
<tags>pdf file native</tags> <tags>pdf file native</tags>
<dependencies>
<dependency id="zlib_native.redist" version="1.2.11" />
</dependencies>
</metadata> </metadata>
<files> <files>
<file src="doc\pdfio-128.png" target="build\native" /> <file src="doc\pdfio-128.png" target="build\native" />

View File

@ -44,7 +44,7 @@ static int verify_image(pdfio_file_t *pdf, size_t number);
static int write_alpha_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font); static int write_alpha_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
static int write_color_patch(pdfio_stream_t *st, bool device); static int write_color_patch(pdfio_stream_t *st, bool device);
static int write_color_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font); static int write_color_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
static int write_font_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font, bool unicode); static int write_font_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font, const char *textfontfile, bool unicode);
static int write_header_footer(pdfio_stream_t *st, const char *title, int number); static int write_header_footer(pdfio_stream_t *st, const char *title, int number);
static pdfio_obj_t *write_image_object(pdfio_file_t *pdf, _pdfio_predictor_t predictor); static pdfio_obj_t *write_image_object(pdfio_file_t *pdf, _pdfio_predictor_t predictor);
static int write_images_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font); static int write_images_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
@ -406,7 +406,7 @@ do_test_file(const char *filename, // I - PDF filename
filter = pdfioDictGetName(dict, "Filter"); filter = pdfioDictGetName(dict, "Filter");
if ((st = pdfioObjOpenStream(obj, (filter && !strcmp(filter, "FlateDecode")) ? PDFIO_FILTER_FLATE : PDFIO_FILTER_NONE)) == NULL) if ((st = pdfioObjOpenStream(obj, filter && !strcmp(filter, "FlateDecode"))) == NULL)
{ {
_pdfioValueDebug(&obj->value, stdout); _pdfioValueDebug(&obj->value, stdout);
putchar('\n'); putchar('\n');
@ -455,7 +455,7 @@ do_test_file(const char *filename, // I - PDF filename
} }
} }
printf(" Page #%d is %gx%g.\n", (int)n + 1, media_box.x2, media_box.y2); printf(" Page #%d (obj %d) is %gx%g.\n", (int)n + 1, (int)pdfioObjGetNumber(obj), media_box.x2, media_box.y2);
} }
} }
@ -2229,14 +2229,20 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
// //
static int // O - 1 on failure, 0 on success static int // O - 1 on failure, 0 on success
write_font_test(pdfio_file_t *pdf, // I - PDF file write_font_test(
pdfio_file_t *pdf, // I - PDF file
int number, // I - Page number int number, // I - Page number
pdfio_obj_t *font, // I - Page number font pdfio_obj_t *font, // I - Page number font
const char *textfontfile, // I - Text font file
bool unicode) // I - Use Unicode font? bool unicode) // I - Use Unicode font?
{ {
pdfio_dict_t *dict; // Page dictionary pdfio_dict_t *dict; // Page dictionary
pdfio_stream_t *st; // Page contents stream pdfio_stream_t *st; // Page contents stream
pdfio_obj_t *opensans; // OpenSans-Regular font pdfio_obj_t *textfont; // Text font
char title[256], // Page title
textname[256], // Name of text font
*ptr; // Pointer into name
double width; // Text width
int i; // Looping var int i; // Looping var
static const char * const welcomes[] =// "Welcome" in many languages static const char * const welcomes[] =// "Welcome" in many languages
{ {
@ -2387,28 +2393,16 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Märr-ŋamathirri", "Märr-ŋamathirri",
"Ẹ ku abọ", "Ẹ ku abọ",
"Kíimak 'oolal", "Kíimak 'oolal",
"Ngiyakwemukela" "Ngiyakwemukela",
"いらっしゃいませ"
}; };
#if 0 printf("pdfioFileCreateFontObjFromFile(%s): ", textfontfile);
if (unicode) if ((textfont = pdfioFileCreateFontObjFromFile(pdf, textfontfile, unicode)) != NULL)
{
fputs("pdfioFileCreateFontObjFromFile(NotoSansJP-Regular.otf): ", stdout);
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/NotoSansJP-Regular.otf", true)) != NULL)
puts("PASS"); puts("PASS");
else else
return (1); return (1);
}
else
#endif // 0
{
fputs("pdfioFileCreateFontObjFromFile(OpenSans-Regular.ttf): ", stdout);
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/OpenSans-Regular.ttf", unicode)) != NULL)
puts("PASS");
else
return (1);
}
fputs("pdfioDictCreate: ", stdout); fputs("pdfioDictCreate: ", stdout);
if ((dict = pdfioDictCreate(pdf)) != NULL) if ((dict = pdfioDictCreate(pdf)) != NULL)
@ -2423,7 +2417,7 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
return (1); return (1);
fputs("pdfioPageDictAddFont(F2): ", stdout); fputs("pdfioPageDictAddFont(F2): ", stdout);
if (pdfioPageDictAddFont(dict, "F2", opensans)) if (pdfioPageDictAddFont(dict, "F2", textfont))
puts("PASS"); puts("PASS");
else else
return (1); return (1);
@ -2435,7 +2429,21 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
else else
return (1); return (1);
if (write_header_footer(st, unicode ? "Unicode TrueType Font Test" : "CP1252 TrueType Font Test", number)) if ((ptr = strrchr(textfontfile, '/')) != NULL)
strncpy(textname, ptr + 1, sizeof(textname) - 1);
else
strncpy(textname, textfontfile, sizeof(textname) - 1);
textname[sizeof(textname) - 1] = '\0';
if ((ptr = strrchr(textname, '.')) != NULL)
*ptr = '\0';
if (unicode)
snprintf(title, sizeof(title), "Unicode %s Font Test", textname);
else
snprintf(title, sizeof(title), "CP1252 %s Font Test", textname);
if (write_header_footer(st, title, number))
goto error; goto error;
fputs("pdfioContentTextBegin(): ", stdout); fputs("pdfioContentTextBegin(): ", stdout);
@ -2456,8 +2464,8 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
else else
goto error; goto error;
fputs("pdfioContentTextMoveTo(36.0, 702.0): ", stdout); fputs("pdfioContentTextMoveTo(198.0, 702.0): ", stdout);
if (pdfioContentTextMoveTo(st, 36.0, 702.0)) if (pdfioContentTextMoveTo(st, 198.0, 702.0))
puts("PASS"); puts("PASS");
else else
return (1); return (1);
@ -2466,18 +2474,36 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
{ {
if (i > 0 && (i % 50) == 0) if (i > 0 && (i % 50) == 0)
{ {
fputs("pdfioContentTextMoveTo(200.0, 600.0): ", stdout); fputs("pdfioContentTextMoveTo(162.0, 600.0): ", stdout);
if (pdfioContentTextMoveTo(st, 200.0, 600.0)) if (pdfioContentTextMoveTo(st, 162.0, 600.0))
puts("PASS"); puts("PASS");
else else
return (1); return (1);
} }
printf("pdfioContentTextMeasure(\"%s\"): ", welcomes[i]);
if ((width = pdfioContentTextMeasure(textfont, welcomes[i], 10.0)) >= 0.0)
puts("PASS");
else
return (1);
printf("pdfioContextTextMoveTo(%g, 0.0): ", -width);
if (pdfioContentTextMoveTo(st, -width, 0.0))
puts("PASS");
else
return (1);
printf("pdfioContentTextShowf(\"%s\"): ", welcomes[i]); printf("pdfioContentTextShowf(\"%s\"): ", welcomes[i]);
if (pdfioContentTextShowf(st, unicode, "%s\n", welcomes[i])) if (pdfioContentTextShowf(st, unicode, "%s\n", welcomes[i]))
puts("PASS"); puts("PASS");
else else
return (1); return (1);
printf("pdfioContextTextMoveTo(%g, 0.0): ", width);
if (pdfioContentTextMoveTo(st, width, 0.0))
puts("PASS");
else
return (1);
} }
fputs("pdfioContentTextEnd(): ", stdout); fputs("pdfioContentTextEnd(): ", stdout);
@ -3390,14 +3416,17 @@ write_unit_file(
return (1); return (1);
// Test TrueType fonts... // Test TrueType fonts...
if (write_font_test(outpdf, 9, helvetica, false)) if (write_font_test(outpdf, 9, helvetica, "testfiles/OpenSans-Regular.ttf", false))
return (1); return (1);
if (write_font_test(outpdf, 10, helvetica, true)) if (write_font_test(outpdf, 10, helvetica, "testfiles/OpenSans-Regular.ttf", true))
return (1);
if (write_font_test(outpdf, 11, helvetica, "testfiles/NotoSansJP-Regular.otf", true))
return (1); return (1);
// Print this text file... // Print this text file...
if (write_text_test(outpdf, 11, helvetica, "README.md")) if (write_text_test(outpdf, 12, helvetica, "README.md"))
return (1); return (1);
fputs("pdfioFileGetNumPages: ", stdout); fputs("pdfioFileGetNumPages: ", stdout);

304
testttf.c Normal file
View File

@ -0,0 +1,304 @@
//
// Unit test program for TTF library
//
// https://github.com/michaelrsweet/ttf
//
// Copyright © 2018-2023 by Michael R Sweet.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
// Usage:
//
// ./testttf [FILENAME]
//
#include <stdio.h>
#include "ttf.h"
//
// Local functions...
//
static void error_cb(void *data, const char *message);
static int test_font(const char *filename);
//
// 'main()' - Main entry for unit tests.
//
int // O - Exit status
main(int argc, // I - Number of command-line arguments
char *argv[]) // I - Command-line arguments
{
int i; // Looping var
int errors = 0; // Number of errors
if (argc > 1)
{
for (i = 1; i < argc; i ++)
errors += test_font(argv[i]);
}
else
{
// Test with the bundled TrueType files...
errors += test_font("testfiles/OpenSans-Bold.ttf");
errors += test_font("testfiles/OpenSans-Regular.ttf");
errors += test_font("testfiles/NotoSansJP-Regular.otf");
}
if (!errors)
puts("\nALL TESTS PASSED");
else
printf("\n%d TEST(S) FAILED\n", errors);
return (errors);
}
//
// 'error_cb()' - Error callback.
//
static void
error_cb(void *data, // I - User data (not used)
const char *message) // I - Message string
{
fprintf(stderr, "FAIL (%s)\n", message);
}
//
// 'test_font()' - Test a font file.
//
static int // O - Number of errors
test_font(const char *filename) // I - Font filename
{
int i, // Looping var
errors = 0; // Number of errors
ttf_t *font; // Font
const char *value; // Font (string) value
int intvalue; // Font (integer) value
float realvalue; // Font (real) value
ttf_rect_t bounds; // Bounds
ttf_rect_t extents; // Extents
size_t num_fonts; // Number of fonts
ttf_style_t style; // Font style
ttf_weight_t weight; // Font weight
static const char * const stretches[] =
{ // Font stretch strings
"TTF_STRETCH_NORMAL", // normal
"TTF_STRETCH_ULTRA_CONDENSED", // ultra-condensed
"TTF_STRETCH_EXTRA_CONDENSED", // extra-condensed
"TTF_STRETCH_CONDENSED", // condensed
"TTF_STRETCH_SEMI_CONDENSED", // semi-condensed
"TTF_STRETCH_SEMI_EXPANDED", // semi-expanded
"TTF_STRETCH_EXPANDED", // expanded
"TTF_STRETCH_EXTRA_EXPANDED", // extra-expanded
"TTF_STRETCH_ULTRA_EXPANDED" // ultra-expanded
};
static const char * const strings[] = // Test strings
{
"Hello, World!", // English
"مرحبا بالعالم!", // Arabic
"Bonjour le monde!", // French
"Γειά σου Κόσμε!", // Greek
"שלום עולם!", // Hebrew
"Привет мир!", // Russian
"こんにちは世界!" // Japanese
};
static const char * const styles[] = // Font style names
{
"TTF_STYLE_NORMAL",
"TTF_STYLE_ITALIC",
"TTF_STYLE_OBLIQUE"
};
printf("ttfCreate(\"%s\"): ", filename);
if ((font = ttfCreate(filename, 0, error_cb, NULL)) != NULL)
puts("PASS");
else
errors ++;
fputs("ttfGetAscent: ", stdout);
if ((intvalue = ttfGetAscent(font)) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetBounds: ", stdout);
if (ttfGetBounds(font, &bounds))
{
printf("PASS (%g %g %g %g)\n", bounds.left, bounds.bottom, bounds.right, bounds.top);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetCapHeight: ", stdout);
if ((intvalue = ttfGetCapHeight(font)) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetCopyright: ", stdout);
if ((value = ttfGetCopyright(font)) != NULL)
{
printf("PASS (%s)\n", value);
}
else
{
puts("WARNING (no copyright found)");
}
for (i = 0; i < (int)(sizeof(strings) / sizeof(strings[0])); i ++)
{
printf("ttfGetExtents(\"%s\"): ", strings[i]);
if (ttfGetExtents(font, 12.0f, strings[i], &extents))
{
printf("PASS (%.1f %.1f %.1f %.1f)\n", extents.left, extents.bottom, extents.right, extents.top);
}
else
{
puts("FAIL");
errors ++;
}
}
fputs("ttfGetFamily: ", stdout);
if ((value = ttfGetFamily(font)) != NULL)
{
printf("PASS (%s)\n", value);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetItalicAngle: ", stdout);
if ((realvalue = ttfGetItalicAngle(font)) >= -180.0 && realvalue <= 180.0)
{
printf("PASS (%g)\n", realvalue);
}
else
{
printf("FAIL (%g)\n", realvalue);
errors ++;
}
fputs("ttfGetNumFonts: ", stdout);
if ((num_fonts = ttfGetNumFonts(font)) > 0)
{
printf("PASS (%u)\n", (unsigned)num_fonts);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetPostScriptName: ", stdout);
if ((value = ttfGetPostScriptName(font)) != NULL)
{
printf("PASS (%s)\n", value);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetStretch: ", stdout);
if ((intvalue = (int)ttfGetStretch(font)) >= TTF_STRETCH_NORMAL && intvalue <= TTF_STRETCH_ULTRA_EXPANDED)
{
printf("PASS (%s)\n", stretches[intvalue]);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetStyle: ", stdout);
if ((style = ttfGetStyle(font)) >= TTF_STYLE_NORMAL && style <= TTF_STYLE_ITALIC)
{
printf("PASS (%s)\n", styles[style]);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetVersion: ", stdout);
if ((value = ttfGetVersion(font)) != NULL)
{
printf("PASS (%s)\n", value);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetWeight: ", stdout);
if ((weight = ttfGetWeight(font)) >= 0)
{
printf("PASS (%u)\n", (unsigned)weight);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetWidth(' '): ", stdout);
if ((intvalue = ttfGetWidth(font, ' ')) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetXHeight: ", stdout);
if ((intvalue = ttfGetXHeight(font)) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfIsFixedPitch: ", stdout);
if (ttfIsFixedPitch(font))
puts("PASS (true)");
else
puts("PASS (false)");
ttfDelete(font);
return (errors);
}

51
ttf.c
View File

@ -3,16 +3,12 @@
// //
// https://github.com/michaelrsweet/ttf // https://github.com/michaelrsweet/ttf
// //
// Copyright © 2018-2021 by Michael R Sweet. // Copyright © 2018-2023 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
// //
//
// Include necessary headers...
//
#ifdef _WIN32 #ifdef _WIN32
# define _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS
#endif // _WIN32 #endif // _WIN32
@ -75,7 +71,7 @@ typedef __int64 ssize_t; // POSIX type not present on Windows...
// //
// DEBUG is typically defined for debug builds. TTF_DEBUG maps to printf when // DEBUG is typically defined for debug builds. TTF_DEBUG maps to fprintf when
// DEBUG is defined and is a no-op otherwise... // DEBUG is defined and is a no-op otherwise...
// //
@ -481,6 +477,11 @@ ttfCreate(const char *filename, // I - Filename
else else
font->widths[bin][i & 255] = widths[glyph]; font->widths[bin][i & 255] = widths[glyph];
} }
#ifdef DEBUG
if (i >= ' ' && i < 127 && font->widths[0])
TTF_DEBUG("ttfCreate: width['%c']=%d(%d)\n", (char)i, font->widths[0][i].width, font->widths[0][i].left_bearing);
#endif // DEBUG
} }
// Cleanup and return the font... // Cleanup and return the font...
@ -737,17 +738,6 @@ ttfGetFamily(ttf_t *font) // I - Font
} }
//
// 'ttfIsFixedPitch()' - Determine whether a font is fixedpitch.
//
bool // O - `true` if fixed pitch, `false` otherwise
ttfIsFixedPitch(ttf_t *font) // I - Font
{
return (font ? font->is_fixed : false);
}
// //
// 'ttfGetItalicAngle()' - Get the italic angle. // 'ttfGetItalicAngle()' - Get the italic angle.
// //
@ -862,7 +852,8 @@ ttfGetWidth(ttf_t *font, // I - Font
// Range check input... // Range check input...
if (!font || ch < ' ' || ch == 0x7f) if (!font || ch < ' ' || ch == 0x7f)
return (0); return (0);
else if (font->widths[bin])
if (font->widths[bin])
return ((int)(1000.0f * font->widths[bin][ch & 255].width / font->units)); return ((int)(1000.0f * font->widths[bin][ch & 255].width / font->units));
else if (font->widths[0]) // .notdef else if (font->widths[0]) // .notdef
return ((int)(1000.0f * font->widths[0][0].width / font->units)); return ((int)(1000.0f * font->widths[0][0].width / font->units));
@ -882,6 +873,17 @@ ttfGetXHeight(ttf_t *font) // I - Font
} }
//
// 'ttfIsFixedPitch()' - Determine whether a font is fixedpitch.
//
bool // O - `true` if fixed pitch, `false` otherwise
ttfIsFixedPitch(ttf_t *font) // I - Font
{
return (font ? font->is_fixed : false);
}
// //
// 'copy_name()' - Copy a name string from a font. // 'copy_name()' - Copy a name string from a font.
// //
@ -1280,7 +1282,7 @@ read_cmap(ttf_t *font) // I - Font
// Based on the end code of the segent table, allocate space for the // Based on the end code of the segent table, allocate space for the
// uncompressed cmap table... // uncompressed cmap table...
segCount --; // Last segment is not used (sigh) // segCount --; // Last segment is not used (sigh)
font->num_cmap = segments[segCount - 1].endCode + 1; font->num_cmap = segments[segCount - 1].endCode + 1;
font->cmap = cmapptr = (int *)malloc(font->num_cmap * sizeof(int)); font->cmap = cmapptr = (int *)malloc(font->num_cmap * sizeof(int));
@ -1305,17 +1307,18 @@ read_cmap(ttf_t *font) // I - Font
{ {
// Use an "obscure indexing trick" (words from the spec, not // Use an "obscure indexing trick" (words from the spec, not
// mine) to look up the glyph index... // mine) to look up the glyph index...
temp = segment->idRangeOffset / 2 + ch - segment->startCode + seg - segCount - 1; temp = segment->idRangeOffset / 2 - segCount + (ch - segment->startCode) + (segment - segments);
if (temp < 0 || temp >= numGlyphIdArray || !glyphIdArray[temp]) TTF_DEBUG("read_cmap: ch=%d, temp=%d\n", ch, temp);
if (temp < 0 || temp >= numGlyphIdArray)
glyph = -1; glyph = -1;
else else
glyph = ((glyphIdArray[temp] + segment->idDelta) & 65535) - 1; glyph = (glyphIdArray[temp] + segment->idDelta) & 65535;
} }
else else
{ {
// Just use idDelta to compute a glyph index... // Just use idDelta to compute a glyph index...
glyph = ((ch + segment->idDelta) & 65535) - 1; glyph = (ch + segment->idDelta) & 65535;
} }
cmapptr[ch] = glyph; cmapptr[ch] = glyph;
@ -1582,6 +1585,8 @@ read_hmtx(ttf_t *font, // I - Font
{ {
widths[i].width = (short)read_ushort(font); widths[i].width = (short)read_ushort(font);
widths[i].left_bearing = (short)read_short(font); widths[i].left_bearing = (short)read_short(font);
TTF_DEBUG("read_hmtx: widths[%d].width=%d, .left_bearing=%d\n", i, widths[i].width, widths[i].left_bearing);
} }
return (widths); return (widths);

13
ttf.h
View File

@ -3,7 +3,7 @@
// //
// https://github.com/michaelrsweet/ttf // https://github.com/michaelrsweet/ttf
// //
// Copyright © 2018-2021 by Michael R Sweet. // Copyright © 2018-2023 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -11,17 +11,11 @@
#ifndef TTF_H #ifndef TTF_H
# define TTF_H # define TTF_H
//
// Include necessary headers...
//
# include <stdbool.h> # include <stdbool.h>
# include <sys/types.h> # include <sys/types.h>
# ifdef __cplusplus # ifdef __cplusplus
extern "C" { extern "C" {
# endif // # endif // __cplusplus
// //
@ -89,8 +83,8 @@ extern ttf_t *ttfCreate(const char *filename, size_t idx, ttf_err_cb_t err_cb,
extern void ttfDelete(ttf_t *font); extern void ttfDelete(ttf_t *font);
extern int ttfGetAscent(ttf_t *font); extern int ttfGetAscent(ttf_t *font);
extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds); extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds);
extern int ttfGetCapHeight(ttf_t *font);
extern const int *ttfGetCMap(ttf_t *font, size_t *num_cmap); extern const int *ttfGetCMap(ttf_t *font, size_t *num_cmap);
extern int ttfGetCapHeight(ttf_t *font);
extern const char *ttfGetCopyright(ttf_t *font); extern const char *ttfGetCopyright(ttf_t *font);
extern int ttfGetDescent(ttf_t *font); extern int ttfGetDescent(ttf_t *font);
extern ttf_rect_t *ttfGetExtents(ttf_t *font, float size, const char *s, ttf_rect_t *extents); extern ttf_rect_t *ttfGetExtents(ttf_t *font, float size, const char *s, ttf_rect_t *extents);
@ -112,5 +106,4 @@ extern bool ttfIsFixedPitch(ttf_t *font);
# ifdef __cplusplus # ifdef __cplusplus
} }
# endif // __cplusplus # endif // __cplusplus
#endif // !TTF_H #endif // !TTF_H