mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-07-13 14:34:28 +02:00
Compare commits
154 Commits
Author | SHA1 | Date | |
---|---|---|---|
6d65a609e5 | |||
e96f9bfa6b | |||
10c15fc281 | |||
fd8427d68a | |||
ed1421287f | |||
aa91b141a8 | |||
5dc68f3285 | |||
52b508bdd2 | |||
41ebe39f3b | |||
62df5f5c78 | |||
a1237db52c | |||
a24fdee335 | |||
e4081f2ba3 | |||
5bc7ebee2c | |||
b872df5a1e | |||
53967552df | |||
f8639fbd64 | |||
9020e92928 | |||
48e6597337 | |||
d4e3bbcf16 | |||
2c8a996875 | |||
3d6d9e3e3e | |||
62fdf48ff9 | |||
294f5e07c5 | |||
4baafde74b | |||
2d175fdf70 | |||
56a0f290aa | |||
2e5319a623 | |||
d3d6683041 | |||
0d08dd5f1b | |||
00c9905317 | |||
b8b9d7ef8a | |||
63cdb13b1b | |||
72e55b5bd1 | |||
dc65eb8d2f | |||
a39b01ec9c | |||
4b29c9a1c2 | |||
5a4afad566 | |||
7a45adb7f5 | |||
45ac66874c | |||
eb9dad9b51 | |||
2ecb9cfb2d | |||
91a467e55c | |||
d705d7eb5d | |||
55745bcea8 | |||
2ea99597cc | |||
a3a3512ed8 | |||
afac83530f | |||
21ac2b52d1 | |||
21b8e3b06f | |||
91392a931f | |||
1d8bcf4d73 | |||
1e55779906 | |||
0e45e49ea4 | |||
0ab291a78b | |||
cac6d4891c | |||
4f29ad89da | |||
9c04d1dc20 | |||
335472023e | |||
25834e07ef | |||
2d2a7126d2 | |||
df1064ff39 | |||
853fa4fe8f | |||
2cadfd8a1e | |||
f5d40a305e | |||
eb5be57b4a | |||
3de47ea63d | |||
8f2c47cb07 | |||
74dfefdcc1 | |||
ee31096019 | |||
121b933307 | |||
f4409146e3 | |||
4312933409 | |||
a19949834b | |||
04c4f44324 | |||
206f75403a | |||
7d22477917 | |||
7c3651671b | |||
6cb661f0f4 | |||
7e01451b18 | |||
138f3955d1 | |||
82844ad2ce | |||
d7cce4dfbc | |||
1cec42f399 | |||
f3f70e7877 | |||
90923c3818 | |||
986cc512cd | |||
c35ddbec00 | |||
e4e1c39578 | |||
1d4f77cab1 | |||
b035130cde | |||
d6d5813b04 | |||
6492f210cf | |||
207062a996 | |||
7d37abb0df | |||
0c1122b689 | |||
d4f8dd46b5 | |||
986c5f0438 | |||
a81907bdb9 | |||
63a7a2cdbd | |||
f040cc41c2 | |||
23883268e3 | |||
a1e14503fd | |||
0766869ad1 | |||
6c1db141a1 | |||
b117959725 | |||
e882622233 | |||
c13b5a5e90 | |||
cd1406e158 | |||
59deee020a | |||
476013706e | |||
a43a9d9e32 | |||
abc69b3361 | |||
83bfb135c6 | |||
2dfb560f8b | |||
7330cc35ba | |||
5d760e7315 | |||
2a85baaf81 | |||
2b92044504 | |||
f4aa951165 | |||
038fd8686b | |||
7084105dc4 | |||
9f06f22281 | |||
cb6b493df6 | |||
2753a82eb9 | |||
ddb8ddff9c | |||
c992b2ba89 | |||
ed723a46dc | |||
6906a9a708 | |||
6a381a55fe | |||
fc3580a948 | |||
6b5c30b4be | |||
a0cdb261ff | |||
34dbf6c2fe | |||
86d842167a | |||
16c8b830b8 | |||
7ff051fc8b | |||
927452d1eb | |||
f1ad982fd1 | |||
c188cb8dad | |||
4919783da5 | |||
86281750e5 | |||
d92b72ed02 | |||
a195c023af | |||
43000ff01f | |||
c6f17cc20f | |||
41146adbdf | |||
cd80c3037d | |||
97934ab995 | |||
088646e1cf | |||
3f0aad7564 | |||
d36df63b57 | |||
a5dfac7495 | |||
0258384d53 |
41
.github/workflows/build.yml
vendored
41
.github/workflows/build.yml
vendored
@ -9,23 +9,26 @@ on:
|
||||
jobs:
|
||||
build-linux:
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: update build environment
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
- name: Update Build Environment
|
||||
run: sudo apt-get update --fix-missing -y
|
||||
- name: install prerequisites
|
||||
- name: Install Prerequisites
|
||||
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"
|
||||
- name: test
|
||||
- name: Test PDFio
|
||||
env:
|
||||
ASAN_OPTIONS: leak_check_at_exit=false
|
||||
run: make test
|
||||
- name: clang static analyzer
|
||||
- name: Run Clang Static Analyzer
|
||||
run: make CC=clang "GHA_ERROR=::error::" clang
|
||||
- name: cppcheck
|
||||
- name: Run cppcheck
|
||||
run: make "GHA_ERROR=::error::" cppcheck
|
||||
|
||||
build-macos:
|
||||
@ -33,12 +36,15 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure PDFio
|
||||
run: ./configure --enable-debug --enable-sanitizer --enable-maintainer
|
||||
- name: Build PDFio
|
||||
run: make "COMMONFLAGS=-g -fsanitize=address"
|
||||
- name: test
|
||||
- name: Test PDFio
|
||||
run: make test
|
||||
- name: clang static analyzer
|
||||
- name: Run Clang Static Analyzer
|
||||
run: make CC=clang "GHA_ERROR=::error::" clang
|
||||
|
||||
build-windows:
|
||||
@ -46,10 +52,13 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: setup-msbuild
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup MSBuild
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
- name: nuget restore
|
||||
- name: Nuget Restore
|
||||
run: nuget restore pdfio.sln
|
||||
- name: msbuild
|
||||
- name: Build PDFio
|
||||
run: msbuild pdfio.sln
|
||||
- name: Test PDFio
|
||||
run: .\runtests.bat x64\Debug
|
||||
|
8
.github/workflows/codeql.yml
vendored
8
.github/workflows/codeql.yml
vendored
@ -23,15 +23,15 @@ jobs:
|
||||
language: [ cpp ]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Update build environment
|
||||
- name: Update Build Environment
|
||||
run: sudo apt-get update --fix-missing -y
|
||||
|
||||
- name: Install prerequisites
|
||||
- name: Install Prerequisites
|
||||
run: sudo apt-get install -y zlib1g-dev
|
||||
|
||||
- name: Initialize CodeQL
|
||||
|
15
.github/workflows/coverity.yml
vendored
15
.github/workflows/coverity.yml
vendored
@ -7,10 +7,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
environment: Coverity
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: update build environment
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
- name: Update Build Environment
|
||||
run: sudo apt-get update --fix-missing -y
|
||||
- name: install prerequisites
|
||||
- name: Install Prerequisites
|
||||
run: sudo apt-get install -y zlib1g-dev
|
||||
- name: Download Coverity Build Tool
|
||||
run: |
|
||||
@ -20,11 +21,15 @@ jobs:
|
||||
env:
|
||||
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: |
|
||||
export PATH=`pwd`/cov-analysis-linux64/bin:$PATH
|
||||
cov-build --dir cov-int make
|
||||
- name: Submit the result to Coverity Scan
|
||||
|
||||
- name: Submit the Result to Coverity Scan
|
||||
run: |
|
||||
tar czvf cov.tgz cov-int
|
||||
curl \
|
||||
|
13
.gitignore
vendored
13
.gitignore
vendored
@ -1,16 +1,27 @@
|
||||
*.1.dylib
|
||||
*.a
|
||||
*.dSYM
|
||||
*.log
|
||||
*.o
|
||||
*.so.1
|
||||
/.vs
|
||||
/afl-output
|
||||
/autom4te.cache
|
||||
/config.log
|
||||
/config.status
|
||||
/configure~
|
||||
/doc/pdfio.epub
|
||||
/examples/code128
|
||||
/examples/image2pdf
|
||||
/examples/md2pdf
|
||||
/examples/pdf2text
|
||||
/examples/pdfioinfo
|
||||
/Makefile
|
||||
/packages
|
||||
/pdfio.pc
|
||||
/pdfio.xcodeproj/xcshareddata
|
||||
/pdfio-*.tar.gz*
|
||||
/pdfio-*.zip*
|
||||
/pdfiototext
|
||||
/testpdfio
|
||||
/testpdfio-*.pdf
|
||||
/testttf
|
||||
|
111
CHANGES.md
111
CHANGES.md
@ -2,15 +2,90 @@ Changes in PDFio
|
||||
================
|
||||
|
||||
|
||||
v1.1.3 (November 15, 2023)
|
||||
--------------------------
|
||||
v1.4.0 - YYYY-MM-DD
|
||||
-------------------
|
||||
|
||||
- Added new `pdfioDictGetKey` and `pdfioDictGetNumPairs` APIs (Issue #63)
|
||||
- Added new `pdfioArrayRemove` and `pdfioDictClear` APIs (Issue #74)
|
||||
- Added new `pdfioFileCreateNameObj` and `pdfioObjGetName` APIs for creating and
|
||||
getting name object values (Issue #76)
|
||||
- Updated documentation (Issue #78)
|
||||
- Updated `pdfioContentTextMeasure` to support measuring PDF base fonts created
|
||||
with `pdfioFileCreateFontObjFromBase` (Issue #84)
|
||||
- Fixed reading of PDF files whose trailer is missing a newline (Issue #80)
|
||||
- Fixed builds with some versions of VC++ (Issue #81)
|
||||
- Fixed validation of date/time values (Issue #83)
|
||||
|
||||
|
||||
v1.3.2 - 2024-08-15
|
||||
-------------------
|
||||
|
||||
- Added some more sanity checks to the TrueType font reader.
|
||||
- Updated documentation (Issue #77)
|
||||
- Fixed an issue when opening certain encrypted PDF files (Issue #62)
|
||||
|
||||
|
||||
v1.3.1 - 2024-08-05
|
||||
-------------------
|
||||
|
||||
- CVE 2024-42358: Updated TrueType font reader to avoid large memory
|
||||
allocations.
|
||||
- Fixed some documentation errors and added examples (Issue #68, Issue #69)
|
||||
|
||||
|
||||
v1.3.0 - 2024-06-28
|
||||
-------------------
|
||||
|
||||
- Added `pdfioFileGetCatalog` API for accessing the root/catalog object of a
|
||||
PDF file (Issue #67)
|
||||
- Updated number support to avoid locale issues (Issue #61)
|
||||
- Updated the PDFio private header to allow compilation with MingW; note that
|
||||
MingW is NOT a supported toolchain for PDFio (Issue #66)
|
||||
- Optimized string pool code.
|
||||
|
||||
|
||||
v1.2.0 - 2024-01-24
|
||||
-------------------
|
||||
|
||||
- Now use autoconf to configure the PDFio sources (Issue #54)
|
||||
- Added `pdfioFileCreateNumberObj` and `pdfioFileCreateStringObj` functions
|
||||
(Issue #14)
|
||||
- Added `pdfioContentTextMeasure` function (Issue #17)
|
||||
- Added `pdfioContentTextNewLineShow` and `pdfioContentTextNewLineShowf`
|
||||
functions (Issue #24)
|
||||
- Renamed `pdfioContentTextNextLine` to `pdfioContentTextNewLine`.
|
||||
- Updated the maximum number of object streams in a single file from 4096 to
|
||||
8192 (Issue #58)
|
||||
- Updated the token reading code to protect against some obvious abuses of the
|
||||
PDF format.
|
||||
- Updated the xref reading code to protect against loops.
|
||||
- Updated the object handling code to use a binary insertion algorithm -
|
||||
provides a significant (~800x) improvement in open times.
|
||||
- Fixed handling of encrypted PDFs with per-object file IDs (Issue #42)
|
||||
- Fixed handling of of trailer dictionaries that started immediately after the
|
||||
"trailer" keyword (Issue #58)
|
||||
- Fixed handling of invalid, but common, PDF files with a generation number of
|
||||
65536 in the xref table (Issue #59)
|
||||
|
||||
|
||||
v1.1.4 - 2023-12-03
|
||||
-------------------
|
||||
|
||||
- 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 - 2023-11-15
|
||||
-------------------
|
||||
|
||||
- Fixed Unicode font support (Issue #16)
|
||||
- Fixed missing initializer for 40-bit RC4 encryption (Issue #51)
|
||||
|
||||
|
||||
v1.1.2 (October 10, 2023)
|
||||
-------------------------
|
||||
v1.1.2 - 2023-10-10
|
||||
-------------------
|
||||
|
||||
- Updated `pdfioContentSetDashPattern` to support setting a solid (0 length)
|
||||
dash pattern (Issue #41)
|
||||
@ -25,15 +100,15 @@ v1.1.2 (October 10, 2023)
|
||||
(Issue #48)
|
||||
|
||||
|
||||
v1.1.1 (March 20, 2023)
|
||||
-----------------------
|
||||
v1.1.1 - 2023-03-20
|
||||
-------------------
|
||||
|
||||
- CVE-2023-28428: Fixed a potential denial-of-service with corrupt PDF files.
|
||||
- Fixed a few build issues.
|
||||
|
||||
|
||||
v1.1.0 (February 6, 2023)
|
||||
-------------------------
|
||||
v1.1.0 - 2023-02-06
|
||||
-------------------
|
||||
|
||||
- CVE-2023-24808: Fixed a potential denial-of-service with corrupt PDF files.
|
||||
- Added `pdfioFileCreateTemporary` function (Issue #29)
|
||||
@ -47,28 +122,28 @@ v1.1.0 (February 6, 2023)
|
||||
- Fixed `pdfioContentMatrixRotate` function.
|
||||
|
||||
|
||||
v1.0.1 (March 2, 2022)
|
||||
----------------------
|
||||
v1.0.1 - 2022-03-02
|
||||
-------------------
|
||||
|
||||
- Added missing `pdfioPageGetNumStreams` and `pdfioPageOpenStream` functions.
|
||||
- Added demo pdfiototext utility.
|
||||
- Fixed bug in `pdfioStreamGetToken`.
|
||||
|
||||
|
||||
v1.0.0 (December 14, 2021)
|
||||
--------------------------
|
||||
v1.0.0 - 2021-12-14
|
||||
-------------------
|
||||
|
||||
- First stable release.
|
||||
|
||||
|
||||
v1.0rc1 (November 30, 2021)
|
||||
---------------------------
|
||||
v1.0rc1 - 2021-11-30
|
||||
--------------------
|
||||
|
||||
- Fixed a few stack/buffer overflow bugs discovered via fuzzing.
|
||||
|
||||
|
||||
v1.0b2 (November 7, 2021)
|
||||
-------------------------
|
||||
v1.0b2 - 2021-11-07
|
||||
-------------------
|
||||
|
||||
- Added `pdfioFileCreateOutput` API to support streaming output of PDF
|
||||
(Issue #21)
|
||||
@ -79,7 +154,7 @@ v1.0b2 (November 7, 2021)
|
||||
- Fixed some issues identified by a Coverity scan.
|
||||
|
||||
|
||||
v1.0b1 (August 30, 2021)
|
||||
------------------------
|
||||
v1.0b1 - 2021-08-30
|
||||
-------------------
|
||||
|
||||
- Initial release
|
||||
|
@ -43,14 +43,17 @@ Contents
|
||||
Build System
|
||||
------------
|
||||
|
||||
The build system uses a simple POSIX makefile to build a static or shared
|
||||
library. To improve portability, makefiles *must not* make use of features
|
||||
unique to GNU make. See the [Makefile Guidelines](#makefile-guidelines) section
|
||||
for a description of the allowed make features and makefile guidelines.
|
||||
The build system uses [GNU autoconf][AUTOCONF] to create a simple POSIX makefile
|
||||
to build static and/or shared libraries. To improve portability, makefiles
|
||||
*must not* make use of features unique to GNU make. See the
|
||||
[Makefile Guidelines](#makefile-guidelines) section for a description of the
|
||||
allowed make features and makefile guidelines.
|
||||
|
||||
An Xcode project is provided for macOS/iOS developers, and a Visual Studio
|
||||
solution and projects for Windows developers.
|
||||
|
||||
[AUTOCONF]: https://www.gnu.org/software/autoconf/
|
||||
|
||||
|
||||
Version Numbering
|
||||
-----------------
|
||||
@ -373,14 +376,15 @@ The following variables are defined in the makefile:
|
||||
- `CC`; the C compiler command,
|
||||
- `CFLAGS`; options for the C compiler,
|
||||
- `CODESIGN_IDENTITY`: the code signing identity,
|
||||
- `COMMONFLAGS`; common compiler optimization options,
|
||||
- `CPPFLAGS`; options for the C preprocessor,
|
||||
- `DESTDIR`/`DSTROOT`: the destination root directory when installing.
|
||||
- `DSO`; the shared library building command,
|
||||
- `DSOFLAGS`; options for the shared library building command,
|
||||
- `DSONAME`: the root name of the shared library
|
||||
- `LDFLAGS`; options for the linker,
|
||||
- `LIBPDFIO`: the name of the primary (shared or static) library
|
||||
- `LIBPDFIO_STATIC`: the name of the secondary (static) library
|
||||
- `LIBS`; libraries for all programs,
|
||||
- `OPTIM`; common compiler optimization options,
|
||||
- `prefix`; the installation prefix directory,
|
||||
- `RANLIB`; the static library indexing command,
|
||||
- `SHELL`; the sh (POSIX shell) command,
|
||||
@ -389,12 +393,7 @@ The following variables are defined in the makefile:
|
||||
The following standard targets are defined in the makefile:
|
||||
|
||||
- `all`; creates the static library and unit test program.
|
||||
- `all-shared`; creates a shared library appropriate for the local system.
|
||||
- `clean`; removes all target programs libraries, documentation files, and
|
||||
object files,
|
||||
- `debug`: creates a clean build of the static library and unit test program
|
||||
with debug printfs and the clang address sanitizer enabled.
|
||||
- `install`; installs all distribution files in their corresponding locations.
|
||||
- `install-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.
|
||||
|
18
EXAMPLES.md
Normal file
18
EXAMPLES.md
Normal file
@ -0,0 +1,18 @@
|
||||
PDFio Examples
|
||||
==============
|
||||
|
||||
The "examples" subdirectory contains example code showing how to do different
|
||||
things with PDFio.
|
||||
|
||||
|
||||
code128.c
|
||||
---------
|
||||
|
||||
This example shows how to embed and use a barcode font.
|
||||
|
||||
|
||||
md2pdf.c
|
||||
--------
|
||||
|
||||
This example shows how to generate pages with multiple fonts, embedded images,
|
||||
and headers and footers.
|
233
Makefile
233
Makefile
@ -1,233 +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 =
|
||||
DESTDIR = $(DSTROOT)
|
||||
DSO = cc
|
||||
DSOFLAGS =
|
||||
DSONAME =
|
||||
LDFLAGS =
|
||||
LIBS = -lm -lz
|
||||
RANLIB = ranlib
|
||||
VERSION = 1.1.3
|
||||
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 \
|
||||
testttf.o
|
||||
TARGETS = \
|
||||
$(DSONAME) \
|
||||
libpdfio.a \
|
||||
pdfiototext \
|
||||
testpdfio \
|
||||
testttf
|
||||
|
||||
|
||||
# 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=11 -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
|
||||
./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) $(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)
|
||||
|
||||
# TTF test program
|
||||
testttf: ttf.o testttf.o
|
||||
echo Linking $@...
|
||||
$(CC) $(LDFLAGS) $(COMMONFLAGS) -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 $(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
|
279
Makefile.in
Normal file
279
Makefile.in
Normal file
@ -0,0 +1,279 @@
|
||||
#
|
||||
# Makefile for PDFio.
|
||||
#
|
||||
# Copyright © 2021-2024 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) \
|
||||
testpdfio.o \
|
||||
testttf.o
|
||||
TARGETS = \
|
||||
$(LIBPDFIO) \
|
||||
$(LIBPDFIO_STATIC) \
|
||||
testpdfio \
|
||||
testttf
|
||||
DOCFILES = \
|
||||
doc/pdfio.html \
|
||||
doc/pdfio-512.png \
|
||||
LICENSE \
|
||||
NOTICE
|
||||
EXAMPLES = \
|
||||
examples/Makefile \
|
||||
examples/Roboto-Bold.ttf \
|
||||
examples/Roboto-Italic.ttf \
|
||||
examples/Roboto-Regular.ttf \
|
||||
examples/RobotoMono-Regular.ttf \
|
||||
examples/code128.c \
|
||||
examples/code128.ttf \
|
||||
examples/image2pdf.c \
|
||||
examples/md2pdf.c \
|
||||
examples/md2pdf.md \
|
||||
examples/mmd.c \
|
||||
examples/mmd.h \
|
||||
examples/pdf2text.c \
|
||||
examples/pdfioinfo.c
|
||||
|
||||
|
||||
# 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 $(DOCFILES); do \
|
||||
$(INSTALL) -c -m 644 $$file $(BUILDROOT)$(datadir)/doc/pdfio; \
|
||||
done
|
||||
echo Installing examples to $(BUILDROOT)$(datadir)/doc/pdfio/examples...
|
||||
$(INSTALL) -d -m 755 $(BUILDROOT)$(datadir)/doc/pdfio/examples
|
||||
for file in $(EXAMPLES); do \
|
||||
$(INSTALL) -c -m 644 $$file $(BUILDROOT)$(datadir)/doc/pdfio/examples; \
|
||||
done
|
||||
echo Installing man page to $(BUILDROOT)$(mandir)/man3...
|
||||
$(INSTALL) -d -m 755 $(BUILDROOT)$(mandir)/man3
|
||||
$(INSTALL) -c -m 644 doc/pdfio.3 $(BUILDROOT)$(mandir)/man3
|
||||
|
||||
|
||||
# Test everything
|
||||
test: testpdfio testttf
|
||||
./testttf 2>test.log
|
||||
./testpdfio 2>>test.log
|
||||
LANG=fr_FR.UTF-8 ./testpdfio 2>>test.log
|
||||
|
||||
|
||||
valgrind: testpdfio
|
||||
valgrind --leak-check=full ./testpdfio
|
||||
|
||||
|
||||
# pdfio library
|
||||
libpdfio.a: $(LIBOBJS)
|
||||
echo Archiving $@...
|
||||
$(RM) $@
|
||||
$(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 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-2024 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 --suppressions-list=.cppcheck $(OBJS:.o=.c) 2>cppcheck.log
|
||||
test -s cppcheck.log && (echo "$(GHA_ERROR)Cppcheck detected issues."; echo ""; cat cppcheck.log; exit 1) || exit 0
|
2
NOTICE
2
NOTICE
@ -1,6 +1,6 @@
|
||||
PDFio - PDF Read/Write Library
|
||||
|
||||
Copyright © 2021-2023 by Michael R Sweet.
|
||||
Copyright © 2021-2024 by Michael R Sweet.
|
||||
|
||||
(Optional) Exceptions to the Apache 2.0 License:
|
||||
================================================
|
||||
|
70
README.md
70
README.md
@ -28,7 +28,7 @@ PDFio requires the following to build the software:
|
||||
|
||||
- A C99 compiler such as Clang, GCC, or MS Visual C
|
||||
- A POSIX-compliant `make` program
|
||||
- ZLIB (<https://www.zlib.net>) 1.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.
|
||||
|
||||
@ -36,15 +36,27 @@ IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
See the man page (`pdfio.3`), frequently ask questions (`FAQ.md`), and full HTML
|
||||
documentation (`pdfio.html`) for information on using PDFio.
|
||||
See the man page (`pdfio.3`) and full HTML documentation (`pdfio.html`) for
|
||||
information on using PDFio.
|
||||
|
||||
|
||||
Installing pdfio
|
||||
Installing PDFio
|
||||
----------------
|
||||
|
||||
PDFio comes with a portable makefile that will work on any POSIX-compliant
|
||||
system with ZLIB installed. To make it, run:
|
||||
PDFio uses a configure script on Unix systems to generate a makefile:
|
||||
|
||||
./configure
|
||||
|
||||
If you want a shared library, run:
|
||||
|
||||
./configure --enable-shared
|
||||
|
||||
The default installation location is "/usr/local". Pass the `--prefix` option
|
||||
to make to install it to another location:
|
||||
|
||||
./configure --prefix=/some/other/directory
|
||||
|
||||
Once configured, run the following to make the library:
|
||||
|
||||
make all
|
||||
|
||||
@ -54,45 +66,7 @@ To test it, run:
|
||||
|
||||
To install it, run:
|
||||
|
||||
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")
|
||||
sudo make install
|
||||
|
||||
|
||||
Visual Studio Project
|
||||
@ -111,15 +85,11 @@ generates a static library that will be installed under "/usr/local" with:
|
||||
|
||||
sudo xcodebuild install
|
||||
|
||||
You can reproduce this with the makefile using:
|
||||
|
||||
sudo make macos install
|
||||
|
||||
|
||||
Legal Stuff
|
||||
-----------
|
||||
|
||||
PDFio is Copyright © 2021-2023 by Michael R Sweet.
|
||||
PDFio is Copyright © 2021-2024 by Michael R Sweet.
|
||||
|
||||
This software is licensed under the Apache License Version 2.0 with an
|
||||
(optional) exception to allow linking against GPL2/LGPL2 software. See the
|
||||
|
@ -54,7 +54,7 @@ starting at 0. A feature release has a "PATCH" value of 0, for example:
|
||||
1.1.0
|
||||
2.0.0
|
||||
|
||||
Beta releases and release candidates are *not* prodution releases and use
|
||||
Beta releases and release candidates are *not* production releases and use
|
||||
semantic version numbers of the form:
|
||||
|
||||
MAJOR.MINORbNUMBER
|
||||
|
1774
config.guess
vendored
Executable file
1774
config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1907
config.sub
vendored
Executable file
1907
config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
273
configure.ac
Normal file
273
configure.ac
Normal file
@ -0,0 +1,273 @@
|
||||
dnl
|
||||
dnl Configuration script for PDFio
|
||||
dnl
|
||||
dnl Copyright © 2023-2024 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.4.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([$PKGCONFIG --exists zlib], [
|
||||
AC_MSG_RESULT([yes])
|
||||
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
||||
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
||||
],[
|
||||
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_REQUIRES=""
|
||||
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
|
1740
doc/pdfio.3
1740
doc/pdfio.3
File diff suppressed because it is too large
Load Diff
1883
doc/pdfio.html
1883
doc/pdfio.html
File diff suppressed because it is too large
Load Diff
1628
doc/pdfio.md
1628
doc/pdfio.md
File diff suppressed because it is too large
Load Diff
65
examples/Makefile
Normal file
65
examples/Makefile
Normal file
@ -0,0 +1,65 @@
|
||||
#
|
||||
# Makefile for PDFio examples.
|
||||
#
|
||||
# Copyright © 2024 by Michael R Sweet.
|
||||
#
|
||||
# Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
# information.
|
||||
#
|
||||
|
||||
# POSIX makefile
|
||||
.POSIX:
|
||||
|
||||
|
||||
# Common options
|
||||
CFLAGS = -g $(CPPFLAGS)
|
||||
#CFLAGS = -g -fsanitize=address $(CPPFLAGS)
|
||||
CPPFLAGS = -I.. -I/usr/local/include
|
||||
LIBS = -L.. -L/usr/local/lib -lpdfio -lz
|
||||
|
||||
|
||||
# Targets
|
||||
TARGETS = \
|
||||
code128 \
|
||||
image2pdf \
|
||||
md2pdf \
|
||||
pdf2text \
|
||||
pdfioinfo
|
||||
|
||||
|
||||
# Make everything
|
||||
all: $(TARGETS)
|
||||
|
||||
|
||||
# Clean everything
|
||||
clean:
|
||||
rm -f $(TARGETS)
|
||||
|
||||
|
||||
# code128
|
||||
code128: code128.c
|
||||
$(CC) $(CFLAGS) -o $@ code128.c $(LIBS)
|
||||
|
||||
|
||||
# image2pdf
|
||||
image2pdf: image2pdf.c
|
||||
$(CC) $(CFLAGS) -o $@ image2pdf.c $(LIBS)
|
||||
|
||||
|
||||
# md2pdf
|
||||
md2pdf: md2pdf.c mmd.c mmd.h
|
||||
$(CC) $(CFLAGS) -o $@ md2pdf.c mmd.c $(LIBS)
|
||||
|
||||
|
||||
# pdfio text extraction (demo, doesn't handle a lot of things yet)
|
||||
pdf2text: pdf2text.c
|
||||
$(CC) $(CFLAGS) -o $@ pdf2text.c $(LIBS)
|
||||
|
||||
|
||||
# pdfioinfo
|
||||
pdfioinfo: pdfioinfo.c
|
||||
$(CC) $(CFLAGS) -o $@ pdfioinfo.c $(LIBS)
|
||||
|
||||
|
||||
# Common dependencies...
|
||||
$(TARGETS): Makefile ../pdfio.h ../pdfio-content.h
|
BIN
examples/Roboto-Bold.ttf
Normal file
BIN
examples/Roboto-Bold.ttf
Normal file
Binary file not shown.
BIN
examples/Roboto-Italic.ttf
Normal file
BIN
examples/Roboto-Italic.ttf
Normal file
Binary file not shown.
BIN
examples/Roboto-Regular.ttf
Normal file
BIN
examples/Roboto-Regular.ttf
Normal file
Binary file not shown.
BIN
examples/RobotoMono-Regular.ttf
Normal file
BIN
examples/RobotoMono-Regular.ttf
Normal file
Binary file not shown.
208
examples/code128.c
Normal file
208
examples/code128.c
Normal file
@ -0,0 +1,208 @@
|
||||
//
|
||||
// Code 128 barcode example for PDFio.
|
||||
//
|
||||
// Copyright © 2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./code128 "BARCODE" ["TEXT"] >FILENAME.pdf
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <pdfio-content.h>
|
||||
|
||||
|
||||
//
|
||||
// 'make_code128()' - Make a Code 128 barcode string.
|
||||
//
|
||||
// This function produces a Code B (printable ASCII) representation of the
|
||||
// source string and doesn't try to optimize using Code C. Non-printable and
|
||||
// extended characters are ignored in the source string.
|
||||
//
|
||||
|
||||
static char * // O - Output string
|
||||
make_code128(char *dst, // I - Destination buffer
|
||||
const char *src, // I - Source string
|
||||
size_t dstsize) // I - Size of destination buffer
|
||||
{
|
||||
char *dstptr, // Pointer into destination buffer
|
||||
*dstend; // End of destination buffer
|
||||
int sum; // Weighted sum
|
||||
static const char *code128_chars = // Code 128 characters
|
||||
" !\"#$%&'()*+,-./0123456789:;<=>?"
|
||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
|
||||
"`abcdefghijklmnopqrstuvwxyz{|}~\303"
|
||||
"\304\305\306\307\310\311\312";
|
||||
static const char code128_fnc_3 = '\304';
|
||||
// FNC 3
|
||||
static const char code128_fnc_2 = '\305';
|
||||
// FNC 2
|
||||
static const char code128_shift_b = '\306';
|
||||
// Shift B (for lowercase)
|
||||
static const char code128_code_c = '\307';
|
||||
// Code C
|
||||
static const char code128_code_b = '\310';
|
||||
// Code B
|
||||
static const char code128_fnc_4 = '\311';
|
||||
// FNC 4
|
||||
static const char code128_fnc_1 = '\312';
|
||||
// FNC 1
|
||||
static const char code128_start_code_a = '\313';
|
||||
// Start code A
|
||||
static const char code128_start_code_b = '\314';
|
||||
// Start code B
|
||||
static const char code128_start_code_c = '\315';
|
||||
// Start code C
|
||||
static const char code128_stop = '\316';
|
||||
// Stop pattern
|
||||
|
||||
|
||||
// Start a Code B barcode...
|
||||
dstptr = dst;
|
||||
dstend = dst + dstsize - 3;
|
||||
|
||||
*dstptr++ = code128_start_code_b;
|
||||
sum = code128_start_code_b - 100;
|
||||
|
||||
while (*src && dstptr < dstend)
|
||||
{
|
||||
if (*src >= ' ' && *src < 0x7f)
|
||||
{
|
||||
sum += (dstptr - dst) * (*src - ' ');
|
||||
*dstptr++ = *src;
|
||||
}
|
||||
|
||||
src ++;
|
||||
}
|
||||
|
||||
// Add the weighted sum modulo 103
|
||||
*dstptr++ = code128_chars[sum % 103];
|
||||
|
||||
// Add the stop pattern and return...
|
||||
*dstptr++ = code128_stop;
|
||||
*dstptr = '\0';
|
||||
|
||||
return (dst);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'output_cb()' - Write PDF data to the standard output...
|
||||
//
|
||||
|
||||
static ssize_t // O - Number of bytes written
|
||||
output_cb(void *output_cbdata, // I - Callback data (not used)
|
||||
const void *buffer, // I - Buffer to write
|
||||
size_t bytes) // I - Number of bytes to write
|
||||
{
|
||||
(void)output_cbdata;
|
||||
|
||||
return ((ssize_t)fwrite(buffer, 1, bytes, stdout));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Produce a single-page barcode file.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // I - Command-line arguments
|
||||
{
|
||||
const char *barcode, // Barcode to show
|
||||
*text; // Text to display under barcode
|
||||
pdfio_file_t *pdf; // Output PDF file
|
||||
pdfio_obj_t *barcode_font; // Barcode font object
|
||||
pdfio_obj_t *text_font = NULL; // Text font object
|
||||
pdfio_dict_t *page_dict; // Page dictionary
|
||||
pdfio_rect_t media_box; // Media/CropBox for page
|
||||
pdfio_stream_t *page_st; // Page stream
|
||||
char barcode_temp[256]; // Barcode buffer
|
||||
double barcode_height = 36.0, // Height of barcode
|
||||
barcode_width, // Width of barcode
|
||||
text_height = 0.0, // Height of text
|
||||
text_width = 0.0; // Width of text
|
||||
|
||||
|
||||
// Get the barcode and optional text from the command-line...
|
||||
if (argc < 2 || argc > 3)
|
||||
{
|
||||
fputs("Usage: code128 \"BARCODE\" [\"TEXT\"] >FILENAME.pdf\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
barcode = argv[1];
|
||||
text = argv[2];
|
||||
|
||||
// Output a PDF file to the standard output...
|
||||
#ifdef _WIN32
|
||||
setmode(1, O_BINARY); // Force binary output on Windows
|
||||
#endif // _WIN32
|
||||
|
||||
if ((pdf = pdfioFileCreateOutput(output_cb, /*output_cbdata*/NULL, /*version*/NULL, /*media_box*/NULL, /*crop_box*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
return (1);
|
||||
|
||||
// Load fonts...
|
||||
barcode_font = pdfioFileCreateFontObjFromFile(pdf, "code128.ttf", /*unicode*/false);
|
||||
if (text)
|
||||
text_font = pdfioFileCreateFontObjFromBase(pdf, "Helvetica");
|
||||
|
||||
// Generate Code128 characters for the desired barcode...
|
||||
if (!(barcode[0] & 0x80))
|
||||
barcode = make_code128(barcode_temp, barcode, sizeof(barcode_temp));
|
||||
|
||||
// Compute sizes of the text...
|
||||
barcode_width = pdfioContentTextMeasure(barcode_font, barcode, barcode_height);
|
||||
if (text && text_font)
|
||||
{
|
||||
text_height = 9.0;
|
||||
text_width = pdfioContentTextMeasure(text_font, text, text_height);
|
||||
}
|
||||
|
||||
// Compute the size of the PDF page...
|
||||
media_box.x1 = 0.0;
|
||||
media_box.y1 = 0.0;
|
||||
media_box.x2 = (barcode_width > text_width ? barcode_width : text_width) + 18.0;
|
||||
media_box.y2 = barcode_height + text_height + 18.0;
|
||||
|
||||
// Start a page for the barcode...
|
||||
page_dict = pdfioDictCreate(pdf);
|
||||
|
||||
pdfioDictSetRect(page_dict, "MediaBox", &media_box);
|
||||
pdfioDictSetRect(page_dict, "CropBox", &media_box);
|
||||
|
||||
pdfioPageDictAddFont(page_dict, "B128", barcode_font);
|
||||
if (text_font)
|
||||
pdfioPageDictAddFont(page_dict, "TEXT", text_font);
|
||||
|
||||
page_st = pdfioFileCreatePage(pdf, page_dict);
|
||||
|
||||
// Draw the page...
|
||||
pdfioContentSetFillColorGray(page_st, 0.0);
|
||||
|
||||
pdfioContentSetTextFont(page_st, "B128", barcode_height);
|
||||
pdfioContentTextBegin(page_st);
|
||||
pdfioContentTextMoveTo(page_st, 0.5 * (media_box.x2 - barcode_width), 9.0 + text_height);
|
||||
pdfioContentTextShow(page_st, /*unicode*/false, barcode);
|
||||
pdfioContentTextEnd(page_st);
|
||||
|
||||
if (text && text_font)
|
||||
{
|
||||
pdfioContentSetTextFont(page_st, "TEXT", text_height);
|
||||
pdfioContentTextBegin(page_st);
|
||||
pdfioContentTextMoveTo(page_st, 0.5 * (media_box.x2 - text_width), 9.0);
|
||||
pdfioContentTextShow(page_st, /*unicode*/false, text);
|
||||
pdfioContentTextEnd(page_st);
|
||||
}
|
||||
|
||||
pdfioStreamClose(page_st);
|
||||
|
||||
// Close and return...
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
BIN
examples/code128.ttf
Normal file
BIN
examples/code128.ttf
Normal file
Binary file not shown.
139
examples/image2pdf.c
Normal file
139
examples/image2pdf.c
Normal file
@ -0,0 +1,139 @@
|
||||
//
|
||||
// Image example for PDFio.
|
||||
//
|
||||
// Copyright © 2023-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./image2pdf FILENAME.{jpg,png} FILENAME.pdf ["TEXT"]
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <pdfio-content.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//
|
||||
// 'create_pdf_image_file()' - Create a PDF file of an image with optional caption.
|
||||
//
|
||||
|
||||
bool // O - True on success, false on failure
|
||||
create_pdf_image_file(
|
||||
const char *pdfname, // I - PDF filename
|
||||
const char *imagename, // I - Image filename
|
||||
const char *caption) // I - Caption filename
|
||||
{
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
pdfio_obj_t *font; // Caption font
|
||||
pdfio_obj_t *image; // Image
|
||||
pdfio_dict_t *dict; // Page dictionary
|
||||
pdfio_stream_t *page; // Page stream
|
||||
double width, height; // Width and height of image
|
||||
double swidth, sheight; // Scaled width and height on page
|
||||
double tx, ty; // Position on page
|
||||
|
||||
|
||||
// Create the PDF file...
|
||||
pdf = pdfioFileCreate(pdfname, /*version*/NULL, /*media_box*/NULL,
|
||||
/*crop_box*/NULL, /*error_cb*/NULL,
|
||||
/*error_cbdata*/NULL);
|
||||
if (!pdf)
|
||||
return (false);
|
||||
|
||||
// Create a Courier base font for the caption
|
||||
font = pdfioFileCreateFontObjFromBase(pdf, "Courier");
|
||||
|
||||
if (!font)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Create an image object from the JPEG/PNG image file...
|
||||
image = pdfioFileCreateImageObjFromFile(pdf, imagename, true);
|
||||
|
||||
if (!image)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Create a page dictionary with the font and image...
|
||||
dict = pdfioDictCreate(pdf);
|
||||
pdfioPageDictAddFont(dict, "F1", font);
|
||||
pdfioPageDictAddImage(dict, "IM1", image);
|
||||
|
||||
// Create the page and its content stream...
|
||||
page = pdfioFileCreatePage(pdf, dict);
|
||||
|
||||
// Position and scale the image on the page...
|
||||
width = pdfioImageGetWidth(image);
|
||||
height = pdfioImageGetHeight(image);
|
||||
|
||||
// Default media_box is "universal" 595.28x792 points (8.27x11in or
|
||||
// 210x279mm). Use margins of 36 points (0.5in or 12.7mm) with another
|
||||
// 36 points for the caption underneath...
|
||||
swidth = 595.28 - 72.0;
|
||||
sheight = swidth * height / width;
|
||||
if (sheight > (792.0 - 36.0 - 72.0))
|
||||
{
|
||||
sheight = 792.0 - 36.0 - 72.0;
|
||||
swidth = sheight * width / height;
|
||||
}
|
||||
|
||||
tx = 0.5 * (595.28 - swidth);
|
||||
ty = 0.5 * (792 - 36 - sheight);
|
||||
|
||||
pdfioContentDrawImage(page, "IM1", tx, ty + 36.0, swidth, sheight);
|
||||
|
||||
// Draw the caption in black...
|
||||
pdfioContentSetFillColorDeviceGray(page, 0.0);
|
||||
|
||||
// Compute the starting point for the text - Courier is monospaced
|
||||
// with a nominal width of 0.6 times the text height...
|
||||
tx = 0.5 * (595.28 - 18.0 * 0.6 * strlen(caption));
|
||||
|
||||
// Position and draw the caption underneath...
|
||||
pdfioContentTextBegin(page);
|
||||
pdfioContentSetTextFont(page, "F1", 18.0);
|
||||
pdfioContentTextMoveTo(page, tx, ty);
|
||||
pdfioContentTextShow(page, /*unicode*/false, caption);
|
||||
pdfioContentTextEnd(page);
|
||||
|
||||
// Close the page stream and the PDF file...
|
||||
pdfioStreamClose(page);
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Produce a single-page file from an image.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // I - Command-line arguments
|
||||
{
|
||||
const char *imagefile, // Image filename
|
||||
*pdffile, // PDF filename
|
||||
*caption; // Caption text
|
||||
|
||||
|
||||
// Get the image file, PDF file, and optional caption text from the command-line...
|
||||
if (argc < 3 || argc > 4)
|
||||
{
|
||||
fputs("Usage: image2pdf FILENAME.{jpg,png} FILENAME.pdf [\"TEXT\"]\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
imagefile = argv[1];
|
||||
pdffile = argv[2];
|
||||
caption = argv[3];
|
||||
|
||||
return (create_pdf_image_file(imagefile, pdffile, caption) ? 0 : 1);
|
||||
}
|
1865
examples/md2pdf.c
Normal file
1865
examples/md2pdf.c
Normal file
File diff suppressed because it is too large
Load Diff
84
examples/md2pdf.md
Normal file
84
examples/md2pdf.md
Normal file
@ -0,0 +1,84 @@
|
||||
---
|
||||
title: Markdown to PDF Converter Test File
|
||||
...
|
||||
|
||||
|
||||
Markdown to PDF Converter Test File
|
||||
===================================
|
||||
|
||||
The `md2pdf` program is organized into three source files: `md2pdf.c` which
|
||||
contains the code to format the markdown content and `mmd.h` and `mmd.c` (from
|
||||
the [Miniature Markdown Library][MMD] project) which load the markdown content.
|
||||
|
||||
[MMD]: https://www.msweet.org/mmd/
|
||||
|
||||
This is a test file for `md2pdf`. Here is a bullet list:
|
||||
|
||||
- Embed base and TrueType fonts,
|
||||
- Format text with embedded JPEG and PNG images and check boxes, with support
|
||||
for wrapping, alignment in table cells, leader text (as used for lists), and
|
||||
variable line height,
|
||||
- Add headers and footers, and
|
||||
- Add hyperlinks and document platform.
|
||||
|
||||
And here is an ordered list:
|
||||
|
||||
1. Embed base and TrueType fonts,
|
||||
2. Format text with embedded JPEG and PNG images and check boxes, with support
|
||||
for wrapping, alignment in table cells, leader text (as used for lists), and
|
||||
variable line height,
|
||||
3. Add headers and footers, and
|
||||
4. Add hyperlinks and document platform.
|
||||
|
||||
|
||||
Code Blocks
|
||||
-----------
|
||||
|
||||
```
|
||||
0 1 2 3 4 5 6 7 8
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
```
|
||||
|
||||
|
||||
Images
|
||||
------
|
||||
|
||||
PDFio book cover image:
|
||||
|
||||

|
||||
|
||||
|
||||
Tables
|
||||
------
|
||||
|
||||
Table with leading/trailing pipes:
|
||||
|
||||
| Heading 1 | Heading 2 | Heading 3 |
|
||||
| --------- | --------- | --------- |
|
||||
| Cell 1,1 | Cell 1,2 | Cell 1,3 |
|
||||
| Cell 2,1 | Cell 2,2 | Cell 2,3 |
|
||||
| Cell 3,1 | Cell 3,2 | Cell 3,3 |
|
||||
|
||||
Table without leading/trailing pipes:
|
||||
|
||||
Heading 1 | Heading 2 | Heading 3
|
||||
--------- | --------- | ---------
|
||||
Cell 1,1 | Cell 1,2 | Cell 1,3
|
||||
Cell 2,1 | Cell 2,2 | Cell 2,3
|
||||
Cell 3,1 | Cell 3,2 | Cell 3,3
|
||||
|
||||
Table with alignment:
|
||||
|
||||
Left Alignment | Center Alignment | Right Alignment
|
||||
:-------- | :-------: | --------:
|
||||
Cell 1,1 | Cell 1,2 | 1
|
||||
Cell 2,1 | Cell 2,2 | 12
|
||||
Cell 3,1 | Cell 3,2 | 123
|
||||
|
||||
Table in block quote:
|
||||
|
||||
> Heading 1 | Heading 2 | Heading 3
|
||||
> --------- | --------- | ---------
|
||||
> Cell 1,1 | Cell 1,2 | Cell 1,3
|
||||
> Cell 2,1 | Cell 2,2 | Cell 2,3
|
||||
> Cell 3,1 | Cell 3,2 | Cell 3,3
|
2381
examples/mmd.c
Normal file
2381
examples/mmd.c
Normal file
File diff suppressed because it is too large
Load Diff
112
examples/mmd.h
Normal file
112
examples/mmd.h
Normal file
@ -0,0 +1,112 @@
|
||||
//
|
||||
// Header file for miniature markdown library.
|
||||
//
|
||||
// https://www.msweet.org/mmd
|
||||
//
|
||||
// Copyright © 2017-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
#ifndef MMD_H
|
||||
# define MMD_H
|
||||
# include <stdio.h>
|
||||
# include <stdbool.h>
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif // __cplusplus
|
||||
|
||||
|
||||
//
|
||||
// Constants...
|
||||
//
|
||||
|
||||
enum mmd_option_e
|
||||
{
|
||||
MMD_OPTION_NONE = 0x00, // No markdown extensions
|
||||
MMD_OPTION_METADATA = 0x01, // Jekyll metadata extension
|
||||
MMD_OPTION_TABLES = 0x02, // Github table extension
|
||||
MMD_OPTION_TASKS = 0x04, // Github task item extension (check boxes)
|
||||
MMD_OPTION_ALL = 0x07 // All supported markdown extensions
|
||||
};
|
||||
typedef unsigned mmd_option_t;
|
||||
|
||||
typedef enum mmd_type_e
|
||||
{
|
||||
MMD_TYPE_NONE = -1,
|
||||
MMD_TYPE_DOCUMENT, // The document root
|
||||
MMD_TYPE_METADATA, // Document metadata
|
||||
MMD_TYPE_BLOCK_QUOTE, // <blockquote>
|
||||
MMD_TYPE_ORDERED_LIST, // <ol>
|
||||
MMD_TYPE_UNORDERED_LIST, // <ul>
|
||||
MMD_TYPE_LIST_ITEM, // <li>
|
||||
MMD_TYPE_TABLE, // <table>
|
||||
MMD_TYPE_TABLE_HEADER, // <thead>
|
||||
MMD_TYPE_TABLE_BODY, // <tbody>
|
||||
MMD_TYPE_TABLE_ROW, // <tr>
|
||||
MMD_TYPE_HEADING_1 = 10, // <h1>
|
||||
MMD_TYPE_HEADING_2, // <h2>
|
||||
MMD_TYPE_HEADING_3, // <h3>
|
||||
MMD_TYPE_HEADING_4, // <h4>
|
||||
MMD_TYPE_HEADING_5, // <h5>
|
||||
MMD_TYPE_HEADING_6, // <h6>
|
||||
MMD_TYPE_PARAGRAPH, // <p>
|
||||
MMD_TYPE_CODE_BLOCK, // <pre><code>
|
||||
MMD_TYPE_THEMATIC_BREAK, // <hr />
|
||||
MMD_TYPE_TABLE_HEADER_CELL, // <th>
|
||||
MMD_TYPE_TABLE_BODY_CELL_LEFT, // <td align="left">
|
||||
MMD_TYPE_TABLE_BODY_CELL_CENTER, // <td align="center">
|
||||
MMD_TYPE_TABLE_BODY_CELL_RIGHT, // <td align="right">
|
||||
MMD_TYPE_NORMAL_TEXT = 100, // Normal text
|
||||
MMD_TYPE_EMPHASIZED_TEXT, // <em>text</em>
|
||||
MMD_TYPE_STRONG_TEXT, // <strong>text</strong>
|
||||
MMD_TYPE_STRUCK_TEXT, // <del>text</del>
|
||||
MMD_TYPE_LINKED_TEXT, // <a href="link">text</a>
|
||||
MMD_TYPE_CODE_TEXT, // <code>text</code>
|
||||
MMD_TYPE_IMAGE, // <img src="link" />
|
||||
MMD_TYPE_HARD_BREAK, // <br />
|
||||
MMD_TYPE_SOFT_BREAK, // <wbr />
|
||||
MMD_TYPE_METADATA_TEXT, // name: value
|
||||
MMD_TYPE_CHECKBOX // [ ] or [x]
|
||||
} mmd_type_t;
|
||||
|
||||
|
||||
//
|
||||
// Types...
|
||||
//
|
||||
|
||||
typedef struct _mmd_s mmd_t; // Markdown node
|
||||
typedef size_t (*mmd_iocb_t)(void *cbdata, char *buffer, size_t bytes);
|
||||
// mmdLoadIO callback function
|
||||
|
||||
//
|
||||
// Functions...
|
||||
//
|
||||
|
||||
extern char *mmdCopyAllText(mmd_t *node);
|
||||
extern void mmdFree(mmd_t *node);
|
||||
extern const char *mmdGetExtra(mmd_t *node);
|
||||
extern mmd_t *mmdGetFirstChild(mmd_t *node);
|
||||
extern mmd_t *mmdGetLastChild(mmd_t *node);
|
||||
extern const char *mmdGetMetadata(mmd_t *doc, const char *keyword);
|
||||
extern mmd_t *mmdGetNextSibling(mmd_t *node);
|
||||
extern mmd_option_t mmdGetOptions(void);
|
||||
extern mmd_t *mmdGetParent(mmd_t *node);
|
||||
extern mmd_t *mmdGetPrevSibling(mmd_t *node);
|
||||
extern const char *mmdGetText(mmd_t *node);
|
||||
extern mmd_type_t mmdGetType(mmd_t *node);
|
||||
extern const char *mmdGetURL(mmd_t *node);
|
||||
extern bool mmdGetWhitespace(mmd_t *node);
|
||||
extern bool mmdIsBlock(mmd_t *node);
|
||||
extern mmd_t *mmdLoad(mmd_t *root, const char *filename);
|
||||
extern mmd_t *mmdLoadFile(mmd_t *root, FILE *fp);
|
||||
extern mmd_t *mmdLoadIO(mmd_t *root, mmd_iocb_t cb, void *cbdata);
|
||||
extern mmd_t *mmdLoadString(mmd_t *root, const char *s);
|
||||
extern void mmdSetOptions(mmd_option_t options);
|
||||
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif // __cplusplus
|
||||
#endif // !MMD_H
|
@ -1,17 +1,17 @@
|
||||
//
|
||||
// PDF to text program for PDFio.
|
||||
//
|
||||
// Copyright © 2022 by Michael R Sweet.
|
||||
// Copyright © 2022-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./pdfiototext FILENAME.pdf > FILENAME.txt
|
||||
// ./pdf2text FILENAME.pdf > FILENAME.txt
|
||||
//
|
||||
|
||||
#include "pdfio.h"
|
||||
#include <pdfio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@ -36,16 +36,14 @@ main(int argc, // I - Number of command-line arguments
|
||||
// Verify command-line arguments...
|
||||
if (argc != 2)
|
||||
{
|
||||
puts("Usage: pdfiototext FILENAME.pdf > FILENAME.txt");
|
||||
puts("Usage: pdf2text FILENAME.pdf > FILENAME.txt");
|
||||
return (1);
|
||||
}
|
||||
|
||||
// Open the PDF file...
|
||||
if ((file = pdfioFileOpen(argv[1], NULL, NULL, NULL, NULL)) == NULL)
|
||||
if ((file = pdfioFileOpen(argv[1], /*password_cb*/NULL, /*password_data*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
return (1);
|
||||
|
||||
// printf("%s: %u pages\n", argv[1], (unsigned)pdfioFileGetNumPages(file));
|
||||
|
||||
// Try grabbing content from all of the pages...
|
||||
for (i = 0, num_pages = pdfioFileGetNumPages(file); i < num_pages; i ++)
|
||||
{
|
||||
@ -54,29 +52,28 @@ main(int argc, // I - Number of command-line arguments
|
||||
|
||||
num_streams = pdfioPageGetNumStreams(obj);
|
||||
|
||||
// printf("%s: page%u=%p, num_streams=%u\n", argv[1], (unsigned)i, obj, (unsigned)num_streams);
|
||||
|
||||
for (j = 0; j < num_streams; j ++)
|
||||
{
|
||||
if ((st = pdfioPageOpenStream(obj, j, true)) == NULL)
|
||||
continue;
|
||||
|
||||
// printf("%s: page%u st%u=%p\n", argv[1], (unsigned)i, (unsigned)j, st);
|
||||
|
||||
// Read PDF tokens from the page stream...
|
||||
first = true;
|
||||
while (pdfioStreamGetToken(st, buffer, sizeof(buffer)))
|
||||
{
|
||||
if (buffer[0] == '(')
|
||||
{
|
||||
// Text string using an 8-bit encoding
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
else if (buffer[1] != ' ')
|
||||
putchar(' ');
|
||||
|
||||
fputs(buffer + 1, stdout);
|
||||
}
|
||||
else if (!strcmp(buffer, "Td") || !strcmp(buffer, "TD") || !strcmp(buffer, "T*") || !strcmp(buffer, "\'") || !strcmp(buffer, "\""))
|
||||
{
|
||||
// Text operators that advance to the next line in the block
|
||||
putchar('\n');
|
||||
first = true;
|
||||
}
|
65
examples/pdfioinfo.c
Normal file
65
examples/pdfioinfo.c
Normal file
@ -0,0 +1,65 @@
|
||||
//
|
||||
// PDF metadata example for PDFio.
|
||||
//
|
||||
// Copyright © 2023-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./pdfioinfo FILENAME.pdf
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Open a PDF file and show its metadata.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // Command-line arguments
|
||||
{
|
||||
const char *filename; // PDF filename
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
time_t creation_date; // Creation date
|
||||
struct tm *creation_tm; // Creation date/time information
|
||||
char creation_text[256]; // Creation date/time as a string
|
||||
|
||||
|
||||
// Get the filename from the command-line...
|
||||
if (argc != 2)
|
||||
{
|
||||
fputs("Usage: ./pdfioinfo FILENAME.pdf\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
filename = argv[1];
|
||||
|
||||
// Open the PDF file with the default callbacks...
|
||||
pdf = pdfioFileOpen(filename, /*password_cb*/NULL,
|
||||
/*password_cbdata*/NULL, /*error_cb*/NULL,
|
||||
/*error_cbdata*/NULL);
|
||||
if (pdf == NULL)
|
||||
return (1);
|
||||
|
||||
// Get the creation date and convert to a string...
|
||||
creation_date = pdfioFileGetCreationDate(pdf);
|
||||
creation_tm = localtime(&creation_date);
|
||||
strftime(creation_text, sizeof(creation_text), "%c", creation_tm);
|
||||
|
||||
// Print file information to stdout...
|
||||
printf("%s:\n", filename);
|
||||
printf(" Title: %s\n", pdfioFileGetTitle(pdf));
|
||||
printf(" Author: %s\n", pdfioFileGetAuthor(pdf));
|
||||
printf(" Created On: %s\n", creation_text);
|
||||
printf(" Number Pages: %u\n", (unsigned)pdfioFileGetNumPages(pdf));
|
||||
|
||||
// Close the PDF file...
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
return (0);
|
||||
}
|
232
install-sh
Executable file
232
install-sh
Executable 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
|
53
makesrcdist
53
makesrcdist
@ -2,18 +2,61 @@
|
||||
#
|
||||
# makesrcdist - make a source distribution of pdfio.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ./makesrcdist [--snapshot] VERSION
|
||||
#
|
||||
|
||||
# Support "--snapshot" option...
|
||||
if test "$1" == "--snapshot"; then
|
||||
shift
|
||||
snapshot=1
|
||||
else
|
||||
snapshot=0
|
||||
fi
|
||||
|
||||
# Get version...
|
||||
if test $# != 1; then
|
||||
echo "Usage: ./makesrcdist version"
|
||||
exit 1
|
||||
echo "Usage: ./makesrcdist [--snapshot] VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
version=$1
|
||||
|
||||
echo Creating tag for release...
|
||||
git tag -m "Tag $version" v$version
|
||||
git push origin v$version
|
||||
# Check that version number has been updated everywhere...
|
||||
if test $(grep AC_INIT configure.ac | awk '{print $2}') != "[$version],"; then
|
||||
echo "Still need to update AC_INIT version in 'configure.ac'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $(grep PDFIO_VERSION= configure | awk -F \" '{print $2}') != "$version"; then
|
||||
echo "Still need to run 'autoconf -f'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $(grep '<version>' pdfio_native.nuspec | sed -E -e '1,$s/^.*<version>([0-9.]+).*$/\1/') != "$version"; then
|
||||
echo "Still need to update version in 'pdfio_native.nuspec'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $(grep '<version>' pdfio_native.redist.nuspec | sed -E -e '1,$s/^.*<version>([0-9.]+).*$/\1/') != "$version"; then
|
||||
echo "Still need to update version in 'pdfio_native.redist.nuspec'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $(grep PDFIO_VERSION pdfio.h | awk -F \" '{print $2}') != "$version"; then
|
||||
echo "Still need to update PDFIO_VERSION in 'pdfio.h'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Tag release...
|
||||
if test $snapshot = 0; then
|
||||
echo Creating tag for release...
|
||||
git tag -m "Tag $version" v$version
|
||||
git push origin v$version
|
||||
fi
|
||||
|
||||
# Make source archives...
|
||||
echo Creating pdfio-$version.tar.gz...
|
||||
git archive --format tar --prefix=pdfio-$version/ HEAD | gzip -v9 >pdfio-$version.tar.gz
|
||||
gpg --detach-sign pdfio-$version.tar.gz
|
||||
|
@ -10,10 +10,6 @@
|
||||
// (<https://github.com/kokke/tiny-AES-c>)
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -21,7 +17,7 @@
|
||||
// Local types...
|
||||
//
|
||||
|
||||
typedef uint8_t state_t[4][4]; // 4x4 AES state table
|
||||
typedef uint8_t state_t[4][4]; // 4x4 AES state table @private@
|
||||
|
||||
|
||||
//
|
||||
|
@ -1,16 +1,12 @@
|
||||
//
|
||||
// PDF array functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -331,6 +327,30 @@ pdfioArrayCreate(pdfio_file_t *pdf) // I - PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioArrayDecrypt()' - Decrypt values in an array.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on error
|
||||
_pdfioArrayDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||
pdfio_obj_t *obj, // I - Object
|
||||
pdfio_array_t *a, // I - Array
|
||||
size_t depth) // I - Depth
|
||||
{
|
||||
size_t i; // Looping var
|
||||
_pdfio_value_t *v; // Current value
|
||||
|
||||
|
||||
for (i = a->num_values, v = a->values; i > 0; i --, v ++)
|
||||
{
|
||||
if (!_pdfioValueDecrypt(pdf, obj, v, depth))
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioArrayDebug()' - Print the contents of an array.
|
||||
//
|
||||
@ -343,6 +363,9 @@ _pdfioArrayDebug(pdfio_array_t *a, // I - Array
|
||||
_pdfio_value_t *v; // Current value
|
||||
|
||||
|
||||
if (!a)
|
||||
return;
|
||||
|
||||
putc('[', fp);
|
||||
for (i = a->num_values, v = a->values; i > 0; i --, v ++)
|
||||
_pdfioValueDebug(v, fp);
|
||||
@ -614,6 +637,28 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioArrayRemove()' - Remove an array entry.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` otherwise
|
||||
pdfioArrayRemove(pdfio_array_t *a, // I - Array
|
||||
size_t n) // I - Index
|
||||
{
|
||||
if (!a || n >= a->num_values)
|
||||
return (false);
|
||||
|
||||
if (a->values[n].type == PDFIO_VALTYPE_BINARY)
|
||||
free(a->values[n].value.binary.data);
|
||||
|
||||
a->num_values --;
|
||||
if (n < a->num_values)
|
||||
memmove(a->values + n, a->values + n + 1, (a->num_values - n) * sizeof(_pdfio_value_t));
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioArrayWrite()' - Write an array to a PDF file.
|
||||
//
|
||||
|
308
pdfio-base-font-widths.h
Normal file
308
pdfio-base-font-widths.h
Normal file
@ -0,0 +1,308 @@
|
||||
//
|
||||
// PDF base font widths for PDFio.
|
||||
//
|
||||
// Copyright © 2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
#ifndef PDFIO_BASE_FONT_WIDTHS_H
|
||||
# define PDFIO_BASE_FONT_WIDTHS_H 1
|
||||
|
||||
|
||||
static short courier_bold_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short courier_boldoblique_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short courier_oblique_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short courier_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_bold_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611,
|
||||
975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556,
|
||||
333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611,
|
||||
611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0,
|
||||
556, 0, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 351, 351, 333, 611, 556, 278, 333, 351, 365, 556, 869, 869, 869, 611,
|
||||
722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_boldoblique_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611,
|
||||
975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556,
|
||||
333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611,
|
||||
611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0,
|
||||
556, 0, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 444, 444, 333, 611, 556, 278, 333, 444, 365, 556, 1055, 1055, 1055, 611,
|
||||
722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_oblique_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556,
|
||||
1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556,
|
||||
333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556,
|
||||
556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0,
|
||||
556, 0, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 390, 390, 333, 556, 537, 278, 333, 390, 365, 556, 947, 947, 947, 611,
|
||||
667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556,
|
||||
1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556,
|
||||
333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556,
|
||||
556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0,
|
||||
556, 0, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 222, 221, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 351, 351, 333, 556, 537, 278, 333, 351, 365, 556, 869, 869, 869, 611,
|
||||
667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 666, 666, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 555, 500
|
||||
};
|
||||
|
||||
|
||||
static short symbol_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
250, 333, 713, 500, 549, 833, 778, 439, 333, 333, 500, 549, 250, 549, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444,
|
||||
549, 722, 667, 722, 612, 611, 763, 603, 722, 333, 631, 722, 686, 889, 722, 722,
|
||||
768, 741, 556, 592, 611, 690, 439, 768, 645, 795, 611, 333, 863, 333, 658, 500,
|
||||
500, 631, 549, 549, 494, 439, 521, 411, 603, 329, 603, 549, 549, 576, 521, 549,
|
||||
549, 521, 549, 603, 439, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
762, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603,
|
||||
400, 549, 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658,
|
||||
823, 686, 795, 987, 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713,
|
||||
768, 713, 790, 790, 890, 823, 549, 250, 713, 603, 603, 1042, 987, 603, 987, 603,
|
||||
494, 329, 790, 790, 786, 713, 384, 384, 384, 384, 384, 384, 494, 494, 494, 494,
|
||||
0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494, 494, 494, 0
|
||||
};
|
||||
|
||||
|
||||
static short times_bold_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
250, 333, 555, 500, 500, 1000, 833, 278, 333, 333, 500, 570, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500,
|
||||
930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778,
|
||||
611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500,
|
||||
333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500,
|
||||
556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 0,
|
||||
500, 0, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 1000, 0, 667, 0,
|
||||
0, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 0, 444, 722,
|
||||
0, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 570, 747, 333,
|
||||
400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500,
|
||||
722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389,
|
||||
722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556,
|
||||
500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500
|
||||
};
|
||||
|
||||
|
||||
static short times_bolditalic_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
250, 389, 555, 500, 500, 833, 778, 278, 333, 333, 500, 570, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500,
|
||||
832, 667, 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611, 889, 722, 722,
|
||||
611, 722, 667, 556, 611, 722, 667, 889, 667, 611, 611, 333, 278, 333, 570, 500,
|
||||
333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778, 556, 500,
|
||||
500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570, 0,
|
||||
500, 0, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 944, 0, 611, 0,
|
||||
0, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 0, 389, 611,
|
||||
0, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 606, 606, 747, 333,
|
||||
400, 570, 300, 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500,
|
||||
667, 667, 667, 667, 667, 667, 944, 667, 667, 667, 667, 667, 389, 389, 389, 389,
|
||||
722, 722, 722, 722, 722, 722, 722, 570, 722, 722, 722, 722, 722, 611, 611, 500,
|
||||
500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500, 444
|
||||
};
|
||||
|
||||
|
||||
static short times_italic_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
250, 333, 420, 500, 500, 833, 778, 214, 333, 333, 500, 675, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500,
|
||||
920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722,
|
||||
611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500,
|
||||
333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500,
|
||||
500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 0,
|
||||
500, 0, 333, 500, 556, 889, 500, 500, 333, 1000, 500, 333, 944, 0, 556, 0,
|
||||
0, 333, 333, 556, 556, 350, 500, 889, 333, 980, 389, 333, 667, 0, 389, 556,
|
||||
0, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 675, 760, 333,
|
||||
400, 675, 300, 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500,
|
||||
611, 611, 611, 611, 611, 611, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333,
|
||||
722, 667, 722, 722, 722, 722, 722, 675, 722, 722, 722, 722, 722, 556, 611, 500,
|
||||
500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500, 444
|
||||
};
|
||||
|
||||
|
||||
static short times_roman_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
250, 333, 408, 500, 500, 833, 778, 180, 333, 333, 500, 564, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444,
|
||||
921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722,
|
||||
556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500,
|
||||
333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500,
|
||||
500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 0,
|
||||
500, 0, 333, 500, 444, 1000, 500, 500, 333, 1000, 556, 333, 889, 0, 611, 0,
|
||||
0, 333, 333, 444, 444, 350, 500, 1000, 333, 980, 389, 333, 722, 0, 444, 722,
|
||||
0, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 564, 760, 333,
|
||||
400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444,
|
||||
722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333,
|
||||
722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500,
|
||||
444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500
|
||||
};
|
||||
|
||||
|
||||
static short zapfdingbats_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933,
|
||||
911, 945, 974, 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537,
|
||||
577, 692, 786, 788, 788, 790, 793, 794, 816, 823, 789, 841, 823, 833, 816, 831,
|
||||
923, 744, 723, 749, 790, 792, 695, 776, 768, 792, 759, 707, 708, 682, 701, 826,
|
||||
815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785, 791, 873, 761, 762,
|
||||
762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788, 788, 788, 788,
|
||||
788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788,
|
||||
788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788,
|
||||
788, 788, 788, 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834,
|
||||
873, 828, 924, 924, 917, 930, 931, 463, 883, 836, 836, 867, 867, 696, 696, 874,
|
||||
0, 874, 760, 946, 771, 865, 771, 888, 967, 888, 831, 873, 927, 970, 918, 0
|
||||
};
|
||||
|
||||
|
||||
#endif // !PDFIO_BASE_FONT_WIDTHS_H
|
@ -1,16 +1,12 @@
|
||||
//
|
||||
// Common support functions for pdfio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -145,7 +141,7 @@ _pdfioFileGets(pdfio_file_t *pdf, // I - PDF file
|
||||
*bufend = buffer + bufsize - 1; // Pointer to end of buffer
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioFileGets(pdf=%p, buffer=%p, bufsize=%lu) bufpos=%ld, buffer=%p, bufptr=%p, bufend=%p\n", pdf, buffer, (unsigned long)bufsize, (long)pdf->bufpos, pdf->buffer, pdf->bufptr, pdf->bufend);
|
||||
PDFIO_DEBUG("_pdfioFileGets(pdf=%p, buffer=%p, bufsize=%lu) bufpos=%ld, buffer=%p, bufptr=%p, bufend=%p, offset=%lu\n", pdf, buffer, (unsigned long)bufsize, (long)pdf->bufpos, pdf->buffer, pdf->bufptr, pdf->bufend, (unsigned long)(pdf->bufpos + (pdf->bufptr - pdf->buffer)));
|
||||
|
||||
while (!eol)
|
||||
{
|
||||
@ -265,7 +261,7 @@ _pdfioFilePrintf(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
// Format the string...
|
||||
va_start(ap, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||
_pdfio_vsnprintf(pdf, buffer, sizeof(buffer), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Write it...
|
||||
@ -360,12 +356,12 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
||||
off_t offset, // I - Offset
|
||||
int whence) // I - Offset base
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioFileSeek(pdf=%p, offset=%ld, whence=%d)\n", pdf, (long)offset, whence);
|
||||
PDFIO_DEBUG("_pdfioFileSeek(pdf=%p, offset=%ld, whence=%d) pdf->bufpos=%lu\n", pdf, (long)offset, whence, (unsigned long)(pdf ? pdf->bufpos : 0));
|
||||
|
||||
// Adjust offset for relative seeks...
|
||||
if (whence == SEEK_CUR)
|
||||
{
|
||||
offset += pdf->bufpos;
|
||||
offset += pdf->bufpos + (pdf->bufptr - pdf->buffer);
|
||||
whence = SEEK_SET;
|
||||
}
|
||||
|
||||
@ -408,7 +404,7 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
||||
return (-1);
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioFileSeek: Reset bufpos=%ld.\n", (long)pdf->bufpos);
|
||||
PDFIO_DEBUG("_pdfioFileSeek: Reset bufpos=%ld, offset=%lu.\n", (long)pdf->bufpos, (unsigned long)offset);
|
||||
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p, bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufend);
|
||||
|
||||
pdf->bufpos = offset;
|
||||
|
466
pdfio-content.c
466
pdfio-content.c
@ -1,18 +1,15 @@
|
||||
//
|
||||
// Content helper functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
#include "pdfio-content.h"
|
||||
#include "pdfio-base-font-widths.h"
|
||||
#include "ttf.h"
|
||||
#include <math.h>
|
||||
#ifndef M_PI
|
||||
@ -1064,6 +1061,138 @@ 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 *basefont; // Base font name
|
||||
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 (!ttf && (basefont = pdfioDictGetName(pdfioObjGetDict(font), "BaseFont")) != NULL)
|
||||
{
|
||||
// Measure the width using the compiled-in base font tables...
|
||||
const short *widths; // Widths
|
||||
int width = 0; // Current width
|
||||
|
||||
if (strcmp(basefont, "Symbol") && strcmp(basefont, "Zapf-Dingbats"))
|
||||
{
|
||||
// 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 = (int)(i + 0x80); // Extra characters from 0x80 to 0x9f
|
||||
else
|
||||
ch = '?'; // Unsupported chars map to ?
|
||||
}
|
||||
|
||||
*tempptr++ = (char)ch;
|
||||
}
|
||||
|
||||
*tempptr = '\0';
|
||||
s = temp;
|
||||
}
|
||||
|
||||
// Choose the appropriate table...
|
||||
if (!strcmp(basefont, "Courier"))
|
||||
widths = courier_widths;
|
||||
else if (!strcmp(basefont, "Courier-Bold"))
|
||||
widths = courier_bold_widths;
|
||||
else if (!strcmp(basefont, "Courier-BoldOblique"))
|
||||
widths = courier_boldoblique_widths;
|
||||
else if (!strcmp(basefont, "Courier-Oblique"))
|
||||
widths = courier_oblique_widths;
|
||||
else if (!strcmp(basefont, "Helvetica"))
|
||||
widths = helvetica_widths;
|
||||
else if (!strcmp(basefont, "Helvetica-Bold"))
|
||||
widths = helvetica_bold_widths;
|
||||
else if (!strcmp(basefont, "Helvetica-BoldOblique"))
|
||||
widths = helvetica_boldoblique_widths;
|
||||
else if (!strcmp(basefont, "Helvetica-Oblique"))
|
||||
widths = helvetica_oblique_widths;
|
||||
else if (!strcmp(basefont, "Symbol"))
|
||||
widths = symbol_widths;
|
||||
else if (!strcmp(basefont, "Times-Bold"))
|
||||
widths = times_bold_widths;
|
||||
else if (!strcmp(basefont, "Times-BoldItalic"))
|
||||
widths = times_bolditalic_widths;
|
||||
else if (!strcmp(basefont, "Times-Italic"))
|
||||
widths = times_italic_widths;
|
||||
else if (!strcmp(basefont, "Times-Roman"))
|
||||
widths = times_roman_widths;
|
||||
else if (!strcmp(basefont, "ZapfDingbats"))
|
||||
widths = zapfdingbats_widths;
|
||||
else
|
||||
return (0.0);
|
||||
|
||||
// Calculate the width using the corresponding table...
|
||||
while (*s)
|
||||
{
|
||||
width += widths[*s & 255];
|
||||
s ++;
|
||||
}
|
||||
|
||||
return (size * 0.001 * width);
|
||||
}
|
||||
|
||||
// If we get here then we need to measure using the TrueType library...
|
||||
ttfGetExtents(ttf, (float)size, s, &extents);
|
||||
|
||||
return (extents.right - extents.left);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioContentTextMoveLine()' - Move to the next line and offset.
|
||||
//
|
||||
@ -1093,7 +1222,21 @@ pdfioContentTextMoveTo(
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioContentTextNextLine()' - Move to the next line.
|
||||
// 'pdfioContentTextNewLine()' - Move to the next line.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
pdfioContentTextNewLine(
|
||||
pdfio_stream_t *st) // I - Stream
|
||||
{
|
||||
return (pdfioStreamPuts(st, "T*\n"));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioContentTextNextLine()' - Legacy function name preserved for binary compatibility.
|
||||
//
|
||||
// @private@
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
@ -1104,6 +1247,86 @@ pdfioContentTextNextLine(
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioContentTextNewLineShow()' - Move to the next line and show text.
|
||||
//
|
||||
// This function moves to the next line and then shows some text with optional
|
||||
// word and character spacing in a PDF content stream. The "unicode" argument
|
||||
// specifies that the current font maps to full Unicode. The "s" argument
|
||||
// specifies a UTF-8 encoded string.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
pdfioContentTextNewLineShow(
|
||||
pdfio_stream_t *st, // I - Stream
|
||||
double ws, // I - Word spacing or `0.0` for none
|
||||
double cs, // I - Character spacing or `0.0` for none
|
||||
bool unicode, // I - Unicode text?
|
||||
const char *s) // I - String to show
|
||||
{
|
||||
bool newline = false; // New line?
|
||||
char op; // Text operator
|
||||
|
||||
|
||||
// Write word and/or character spacing as needed...
|
||||
if (ws > 0.0 || cs > 0.0)
|
||||
{
|
||||
// Use " operator to show text with word and character spacing...
|
||||
if (!pdfioStreamPrintf(st, "%g %g", ws, cs))
|
||||
return (false);
|
||||
|
||||
op = '\"';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use ' operator to show text with the defaults...
|
||||
op = '\'';
|
||||
}
|
||||
|
||||
// Write the string...
|
||||
if (!write_string(st, unicode, s, &newline))
|
||||
return (false);
|
||||
|
||||
// Draw it...
|
||||
if (newline)
|
||||
return (pdfioStreamPrintf(st, "%c T*\n", op));
|
||||
else
|
||||
return (pdfioStreamPrintf(st, "%c\n", op));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioContentTextNewLineShowf()' - Show formatted text.
|
||||
//
|
||||
// This function moves to the next line and shows some formatted text with
|
||||
// optional word and character spacing in a PDF content stream. The "unicode"
|
||||
// argument specifies that the current font maps to full Unicode. The "format"
|
||||
// argument specifies a UTF-8 encoded `printf`-style format string.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
pdfioContentTextNewLineShowf(
|
||||
pdfio_stream_t *st, // I - Stream
|
||||
double ws, // I - Word spacing or `0.0` for none
|
||||
double cs, // I - Character spacing or `0.0` for none
|
||||
bool unicode, // I - Unicode text?
|
||||
const char *format, // I - `printf`-style format string
|
||||
...) // I - Additional arguments as needed
|
||||
{
|
||||
char buffer[8192]; // Text buffer
|
||||
va_list ap; // Argument pointer
|
||||
|
||||
|
||||
// Format the string...
|
||||
va_start(ap, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Show it...
|
||||
return (pdfioContentTextNewLineShow(st, ws, cs, unicode, buffer));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioContentTextShow()' - Show text.
|
||||
//
|
||||
@ -1136,9 +1359,9 @@ pdfioContentTextShow(
|
||||
//
|
||||
// 'pdfioContentTextShowf()' - Show formatted text.
|
||||
//
|
||||
// This function shows some text 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.
|
||||
// This function shows some formatted text 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
|
||||
@ -1233,8 +1456,9 @@ pdfioContentTextShowJustified(
|
||||
// - "Times-Roman"
|
||||
// - "ZapfDingbats"
|
||||
//
|
||||
// Base fonts always use the Windows CP1252 (ISO-8859-1 with additional
|
||||
// characters such as the Euro symbol) subset of Unicode.
|
||||
// Aside from "Symbol" and "Zapf-Dingbats", Base fonts use the Windows CP1252
|
||||
// (ISO-8859-1 with additional characters such as the Euro symbol) subset of
|
||||
// Unicode.
|
||||
//
|
||||
|
||||
pdfio_obj_t * // O - Font object
|
||||
@ -1289,13 +1513,13 @@ pdfioFileCreateFontObjFromFile(
|
||||
pdfio_dict_t *dict, // Font dictionary
|
||||
*desc, // Font descriptor
|
||||
*file; // Font file dictionary
|
||||
pdfio_obj_t *obj, // Font object
|
||||
pdfio_obj_t *obj = NULL, // Font object
|
||||
*desc_obj, // Font descriptor object
|
||||
*file_obj; // Font file object
|
||||
const char *basefont; // Base font name
|
||||
pdfio_array_t *bbox; // Font bounding box array
|
||||
pdfio_stream_t *st; // Font stream
|
||||
int fd; // File
|
||||
int fd = -1; // File
|
||||
unsigned char buffer[16384]; // Read buffer
|
||||
ssize_t bytes; // Bytes read
|
||||
|
||||
@ -1324,48 +1548,32 @@ pdfioFileCreateFontObjFromFile(
|
||||
|
||||
// Create the font file dictionary and object...
|
||||
if ((file = pdfioDictCreate(pdf)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
close(fd);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
pdfioDictSetName(file, "Filter", "FlateDecode");
|
||||
|
||||
if ((file_obj = pdfioFileCreateObj(pdf, file)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
close(fd);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
if ((st = pdfioObjCreateStream(file_obj, PDFIO_FILTER_FLATE)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
close(fd);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
|
||||
{
|
||||
if (!pdfioStreamWrite(st, buffer, (size_t)bytes))
|
||||
{
|
||||
ttfDelete(font);
|
||||
close(fd);
|
||||
pdfioStreamClose(st);
|
||||
return (NULL);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
fd = -1;
|
||||
pdfioStreamClose(st);
|
||||
|
||||
// Create the font descriptor dictionary and object...
|
||||
if ((bbox = pdfioArrayCreate(pdf)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
ttfGetBounds(font, &bounds);
|
||||
|
||||
@ -1375,10 +1583,7 @@ pdfioFileCreateFontObjFromFile(
|
||||
pdfioArrayAppendNumber(bbox, bounds.top);
|
||||
|
||||
if ((desc = pdfioDictCreate(pdf)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
basefont = pdfioStringCreate(pdf, ttfGetPostScriptName(font));
|
||||
|
||||
@ -1397,22 +1602,24 @@ pdfioFileCreateFontObjFromFile(
|
||||
pdfioDictSetNumber(desc, "StemV", ttfGetWeight(font) / 4 + 25);
|
||||
|
||||
if ((desc_obj = pdfioFileCreateObj(pdf, desc)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
pdfioObjClose(desc_obj);
|
||||
|
||||
if (unicode)
|
||||
{
|
||||
// Unicode (CID) font...
|
||||
pdfio_dict_t *cid2gid; // CIDToGIDMap dictionary
|
||||
pdfio_obj_t *cid2gid_obj; // CIDToGIDMap object
|
||||
pdfio_dict_t *cid2gid, // CIDToGIDMap dictionary
|
||||
*to_unicode; // ToUnicode dictionary
|
||||
pdfio_obj_t *cid2gid_obj, // CIDToGIDMap object
|
||||
*to_unicode_obj;// ToUnicode object
|
||||
size_t i, // Looping var
|
||||
start, // Start character
|
||||
num_cmap; // Number of 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
|
||||
*bufend; // End of buffer
|
||||
pdfio_dict_t *type2; // CIDFontType2 font dictionary
|
||||
@ -1423,34 +1630,36 @@ pdfioFileCreateFontObjFromFile(
|
||||
*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...
|
||||
if ((cid2gid = pdfioDictCreate(pdf)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
#ifndef DEBUG
|
||||
pdfioDictSetName(cid2gid, "Filter", "FlateDecode");
|
||||
#endif // !DEBUG
|
||||
|
||||
if ((cid2gid_obj = pdfioFileCreateObj(pdf, cid2gid)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
#ifdef DEBUG
|
||||
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_NONE)) == NULL)
|
||||
#else
|
||||
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_FLATE)) == NULL)
|
||||
#endif // DEBUG
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
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);
|
||||
|
||||
@ -1468,6 +1677,12 @@ pdfioFileCreateFontObjFromFile(
|
||||
// Map to specified glyph...
|
||||
*bufptr++ = (unsigned char)(cmap[i] >> 8);
|
||||
*bufptr++ = (unsigned char)(cmap[i] & 255);
|
||||
|
||||
glyphs[cmap[i]] = (unsigned short)i;
|
||||
if (cmap[i] < min_glyph)
|
||||
min_glyph = cmap[i];
|
||||
if (cmap[i] > max_glyph)
|
||||
max_glyph = cmap[i];
|
||||
}
|
||||
|
||||
if (bufptr >= bufend)
|
||||
@ -1476,8 +1691,7 @@ pdfioFileCreateFontObjFromFile(
|
||||
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
|
||||
{
|
||||
pdfioStreamClose(st);
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
goto done;
|
||||
}
|
||||
|
||||
bufptr = buffer;
|
||||
@ -1490,36 +1704,68 @@ pdfioFileCreateFontObjFromFile(
|
||||
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
|
||||
{
|
||||
pdfioStreamClose(st);
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
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...
|
||||
if ((type2 = pdfioDictCreate(pdf)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((sidict = pdfioDictCreate(pdf)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
// Width array
|
||||
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
for (start = 0, w0 = ttfGetWidth(font, 0), i = 1; i < 65536; start = i, w0 = w1, i ++)
|
||||
for (start = 0, w0 = ttfGetWidth(font, 0), w1 = 0, i = 1; i < 65536; start = i, w0 = w1, i ++)
|
||||
{
|
||||
while (i < 65536 && (w1 = ttfGetWidth(font, i)) == w0)
|
||||
while (i < 65536 && (w1 = ttfGetWidth(font, (int)i)) == w0)
|
||||
i ++;
|
||||
|
||||
if ((i - start) > 1)
|
||||
@ -1535,15 +1781,12 @@ pdfioFileCreateFontObjFromFile(
|
||||
pdfioArrayAppendNumber(w_array, start);
|
||||
|
||||
if ((temp_array = pdfioArrayCreate(pdf)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
pdfioArrayAppendNumber(temp_array, w0);
|
||||
for (w0 = w1, i ++; i < 65536; w0 = w1, i ++)
|
||||
{
|
||||
if ((w1 = ttfGetWidth(font, i)) == w0 && i < 65535)
|
||||
if ((w1 = ttfGetWidth(font, (int)i)) == w0 && i < 65535)
|
||||
break;
|
||||
|
||||
pdfioArrayAppendNumber(temp_array, w0);
|
||||
@ -1558,11 +1801,6 @@ pdfioFileCreateFontObjFromFile(
|
||||
}
|
||||
}
|
||||
|
||||
// CIDSystemInfo mapping to Adobe UCS2 v0 (Unicode)
|
||||
pdfioDictSetString(sidict, "Registry", "Adobe");
|
||||
pdfioDictSetString(sidict, "Ordering", "Identity");
|
||||
pdfioDictSetNumber(sidict, "Supplement", 0);
|
||||
|
||||
// Then the dictionary for the CID base font...
|
||||
pdfioDictSetName(type2, "Type", "Font");
|
||||
pdfioDictSetName(type2, "Subtype", "CIDFontType2");
|
||||
@ -1573,54 +1811,38 @@ pdfioFileCreateFontObjFromFile(
|
||||
pdfioDictSetArray(type2, "W", w_array);
|
||||
|
||||
if ((type2_obj = pdfioFileCreateObj(pdf, type2)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
pdfioObjClose(type2_obj);
|
||||
|
||||
// Create a Type 0 font object...
|
||||
if ((descendants = pdfioArrayCreate(pdf)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
pdfioArrayAppendObj(descendants, type2_obj);
|
||||
|
||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
pdfioDictSetName(dict, "Type", "Font");
|
||||
pdfioDictSetName(dict, "Subtype", "Type0");
|
||||
pdfioDictSetName(dict, "BaseFont", basefont);
|
||||
pdfioDictSetArray(dict, "DescendantFonts", descendants);
|
||||
pdfioDictSetName(dict, "Encoding", "Identity-H");
|
||||
pdfioDictSetObj(dict, "ToUnicode", to_unicode_obj);
|
||||
|
||||
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
pdfioObjClose(obj);
|
||||
if ((obj = pdfioFileCreateObj(pdf, dict)) != NULL)
|
||||
pdfioObjClose(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple (CP1282 or custom encoding) 8-bit font...
|
||||
if (ttfGetMaxChar(font) >= 255 && !pdf->cp1252_obj && !create_cp1252(pdf))
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
// Create a TrueType font object...
|
||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
goto done;
|
||||
|
||||
pdfioDictSetName(dict, "Type", "Font");
|
||||
pdfioDictSetName(dict, "Subtype", "TrueType");
|
||||
@ -1630,16 +1852,16 @@ pdfioFileCreateFontObjFromFile(
|
||||
|
||||
pdfioDictSetObj(dict, "FontDescriptor", desc_obj);
|
||||
|
||||
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
|
||||
{
|
||||
ttfDelete(font);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
pdfioObjClose(obj);
|
||||
if ((obj = pdfioFileCreateObj(pdf, dict)) != NULL)
|
||||
pdfioObjClose(obj);
|
||||
}
|
||||
|
||||
ttfDelete(font);
|
||||
done:
|
||||
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
_pdfioObjSetExtension(obj, font, (_pdfio_extfree_t)ttfDelete);
|
||||
|
||||
return (obj);
|
||||
}
|
||||
@ -2163,7 +2385,7 @@ pdfioPageDictAddColorSpace(
|
||||
bool // O - `true` on success, `false` on failure
|
||||
pdfioPageDictAddFont(
|
||||
pdfio_dict_t *dict, // I - Page dictionary
|
||||
const char *name, // I - Font name
|
||||
const char *name, // I - Font name; must not contain spaces
|
||||
pdfio_obj_t *obj) // I - Font object
|
||||
{
|
||||
pdfio_dict_t *resources; // Resource dictionary
|
||||
@ -3053,7 +3275,7 @@ write_string(pdfio_stream_t *st, // I - Stream
|
||||
|
||||
|
||||
// Start the string...
|
||||
if (!pdfioStreamPuts(st, unicode ? "<FEFF" : "("))
|
||||
if (!pdfioStreamPuts(st, unicode ? "<" : "("))
|
||||
return (false);
|
||||
|
||||
// Loop through the string, handling UTF-8 as needed...
|
||||
|
@ -115,8 +115,12 @@ extern bool pdfioContentSetTextXScaling(pdfio_stream_t *st, double percent) _PD
|
||||
extern bool pdfioContentStroke(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 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 pdfioContentTextMoveTo(pdfio_stream_t *st, double tx, double ty) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextNewLine(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextNewLineShow(pdfio_stream_t *st, double ws, double cs, bool unicode, const char *s) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextNewLineShowf(pdfio_stream_t *st, double ws, double cs, bool unicode, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(5,6);
|
||||
extern bool pdfioContentTextNextLine(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool 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);
|
||||
|
104
pdfio-crypto.c
104
pdfio-crypto.c
@ -7,10 +7,6 @@
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
#if _WIN32
|
||||
# include <windows.h>
|
||||
@ -403,16 +399,23 @@ _pdfioCryptoMakeRandom(uint8_t *buffer, // I - Buffer
|
||||
//
|
||||
|
||||
_pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
||||
_pdfioCryptoMakeReader(
|
||||
_pdfioCryptoMakeReader(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
pdfio_obj_t *obj, // I - PDF object
|
||||
_pdfio_crypto_ctx_t *ctx, // I - Pointer to crypto context
|
||||
uint8_t *iv, // I - Buffer for initialization vector
|
||||
size_t *ivlen) // IO - Size of initialization vector
|
||||
{
|
||||
uint8_t data[21]; /* Key data */
|
||||
_pdfio_md5_t md5; /* MD5 state */
|
||||
uint8_t digest[16]; /* MD5 digest value */
|
||||
uint8_t data[21]; // Key data
|
||||
_pdfio_md5_t md5; // MD5 state
|
||||
uint8_t digest[16]; // MD5 digest value
|
||||
#if PDFIO_OBJ_CRYPT
|
||||
pdfio_array_t *id_array; // Object ID array
|
||||
unsigned char *id_value; // Object ID value
|
||||
size_t id_len; // Length of object ID
|
||||
uint8_t temp_key[16]; // File key for object
|
||||
#endif // PDFIO_OBJ_CRYPT
|
||||
uint8_t *file_key; // Computed file key to use
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeReader(pdf=%p, obj=%p(%d), ctx=%p, iv=%p, ivlen=%p(%d))\n", pdf, obj, (int)obj->number, ctx, iv, ivlen, (int)*ivlen);
|
||||
@ -424,6 +427,59 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#if PDFIO_OBJ_CRYPT
|
||||
if ((id_array = pdfioDictGetArray(pdfioObjGetDict(obj), "ID")) != NULL)
|
||||
{
|
||||
// Object has its own ID that will get used for encryption...
|
||||
_pdfio_md5_t md5; // MD5 context
|
||||
uint8_t file_digest[16]; // MD5 digest of file ID and pad
|
||||
uint8_t user_pad[32], // Padded user password
|
||||
own_user_key[32], // Calculated user key
|
||||
pdf_user_key[32]; // Decrypted user key
|
||||
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeReader: Per-object file ID.\n");
|
||||
|
||||
if ((id_value = pdfioArrayGetBinary(id_array, 0, &id_len)) == NULL)
|
||||
{
|
||||
*ivlen = 0;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
_pdfioCryptoMD5Init(&md5);
|
||||
_pdfioCryptoMD5Append(&md5, pdf_passpad, 32);
|
||||
_pdfioCryptoMD5Append(&md5, id_value, id_len);
|
||||
_pdfioCryptoMD5Finish(&md5, file_digest);
|
||||
|
||||
make_owner_key(pdf->encryption, pdf->password, pdf->owner_key, user_pad);
|
||||
make_file_key(pdf->encryption, pdf->permissions, id_value, id_len, user_pad, pdf->owner_key, temp_key);
|
||||
make_user_key(id_value, id_len, own_user_key);
|
||||
|
||||
if (memcmp(own_user_key, pdf->user_key, sizeof(own_user_key)))
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeReader: Not user password, trying owner password.\n");
|
||||
|
||||
make_file_key(pdf->encryption, pdf->permissions, id_value, id_len, pdf->password, pdf->owner_key, temp_key);
|
||||
make_user_key(id_value, id_len, own_user_key);
|
||||
|
||||
memcpy(pdf_user_key, pdf->user_key, sizeof(pdf_user_key));
|
||||
decrypt_user_key(pdf->encryption, temp_key, pdf_user_key);
|
||||
|
||||
if (memcmp(pdf->password, pdf_user_key, 32) && memcmp(own_user_key, pdf_user_key, 16))
|
||||
{
|
||||
*ivlen = 0;
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
file_key = temp_key;
|
||||
}
|
||||
else
|
||||
#endif // PDFIO_OBJ_CRYPT
|
||||
{
|
||||
// Use the default file key...
|
||||
file_key = pdf->file_key;
|
||||
}
|
||||
|
||||
switch (pdf->encryption)
|
||||
{
|
||||
default :
|
||||
@ -432,7 +488,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
||||
|
||||
case PDFIO_ENCRYPTION_RC4_40 :
|
||||
// Copy the key data for the MD5 hash.
|
||||
memcpy(data, pdf->file_key, sizeof(pdf->file_key));
|
||||
memcpy(data, file_key, 16);
|
||||
data[16] = (uint8_t)obj->number;
|
||||
data[17] = (uint8_t)(obj->number >> 8);
|
||||
data[18] = (uint8_t)(obj->number >> 16);
|
||||
@ -449,10 +505,17 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
||||
*ivlen = 0;
|
||||
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
|
||||
|
||||
case PDFIO_ENCRYPTION_RC4_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.
|
||||
memcpy(data, pdf->file_key, sizeof(pdf->file_key));
|
||||
memcpy(data, file_key, 16);
|
||||
data[16] = (uint8_t)obj->number;
|
||||
data[17] = (uint8_t)(obj->number >> 8);
|
||||
data[18] = (uint8_t)(obj->number >> 16);
|
||||
@ -488,7 +551,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
||||
//
|
||||
|
||||
_pdfio_crypto_cb_t // O - Encryption callback or `NULL` for none
|
||||
_pdfioCryptoMakeWriter(
|
||||
_pdfioCryptoMakeWriter(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
pdfio_obj_t *obj, // I - PDF object
|
||||
_pdfio_crypto_ctx_t *ctx, // I - Pointer to crypto context
|
||||
@ -593,6 +656,8 @@ _pdfioCryptoUnlock(
|
||||
revision = (int)pdfioDictGetNumber(encrypt_dict, "R");
|
||||
length = (int)pdfioDictGetNumber(encrypt_dict, "Length");
|
||||
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: handler=%p(%s), version=%d, revision=%d, length=%d\n", (void *)handler, handler ? handler : "(null)", version, revision, length);
|
||||
|
||||
if (!handler || strcmp(handler, "Standard"))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unsupported security handler '%s'.", handler ? handler : "(null)");
|
||||
@ -641,6 +706,8 @@ _pdfioCryptoUnlock(
|
||||
}
|
||||
else
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: CFM=\"%s\"\n", cfm);
|
||||
|
||||
if (length < 40 || length > 128)
|
||||
length = 128; // Default to 128 bits
|
||||
|
||||
@ -766,17 +833,16 @@ _pdfioCryptoUnlock(
|
||||
{
|
||||
// Matches!
|
||||
memcpy(pdf->file_key, file_key, sizeof(pdf->file_key));
|
||||
memcpy(pdf->password, pad, sizeof(pdf->password));
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Not the owner password, try the user password...
|
||||
*/
|
||||
|
||||
// Not the owner password, try the user password...
|
||||
make_file_key(pdf->encryption, pdf->permissions, file_id, file_idlen, pad, pdf->owner_key, file_key);
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Fuse=%02X%02X%02X%02X...%02X%02X%02X%02X\n", file_key[0], file_key[1], file_key[2], file_key[3], file_key[12], file_key[13], file_key[14], file_key[15]);
|
||||
|
||||
make_user_key(file_id, file_idlen, user_key);
|
||||
make_user_key(file_id, file_idlen, own_user_key);
|
||||
|
||||
memcpy(pdf_user_key, pdf->user_key, sizeof(pdf_user_key));
|
||||
decrypt_user_key(pdf->encryption, file_key, pdf_user_key);
|
||||
@ -784,10 +850,12 @@ _pdfioCryptoUnlock(
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Uuse=%02X%02X%02X%02X...%02X%02X%02X%02X\n", user_key[0], user_key[1], user_key[2], user_key[3], user_key[28], user_key[29], user_key[30], user_key[31]);
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Updf=%02X%02X%02X%02X...%02X%02X%02X%02X\n", pdf_user_key[0], pdf_user_key[1], pdf_user_key[2], pdf_user_key[3], pdf_user_key[28], pdf_user_key[29], pdf_user_key[30], pdf_user_key[31]);
|
||||
|
||||
if (!memcmp(pad, pdf_user_key, 32) || !memcmp(user_key, pdf_user_key, 16))
|
||||
if (!memcmp(pad, pdf_user_key, 32) || !memcmp(own_user_key, pdf_user_key, 16))
|
||||
{
|
||||
// Matches!
|
||||
memcpy(pdf->file_key, file_key, sizeof(pdf->file_key));
|
||||
memcpy(pdf->password, pad, sizeof(pdf->password));
|
||||
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
|
98
pdfio-dict.c
98
pdfio-dict.c
@ -1,16 +1,12 @@
|
||||
//
|
||||
// PDF dictionary functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -22,19 +18,22 @@ static int compare_pairs(_pdfio_pair_t *a, _pdfio_pair_t *b);
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioDictClear()' - Remove a key/value pair from a dictionary.
|
||||
// 'pdfioDictClear()' - Remove a key/value pair from a dictionary.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioDictClear(pdfio_dict_t *dict, // I - Dictionary
|
||||
const char *key) // I - Key
|
||||
bool // O - `true` if cleared, `false` otherwise
|
||||
pdfioDictClear(pdfio_dict_t *dict, // I - Dictionary
|
||||
const char *key) // I - Key
|
||||
{
|
||||
size_t idx; // Index into pairs
|
||||
_pdfio_pair_t *pair, // Current pair
|
||||
pkey; // Search key
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioDictClear(dict=%p, key=\"%s\")\n", dict, key);
|
||||
PDFIO_DEBUG("pdfioDictClear(dict=%p, key=\"%s\")\n", dict, key);
|
||||
|
||||
if (!dict || !key)
|
||||
return (false);
|
||||
|
||||
// See if the key is already set...
|
||||
if (dict->num_pairs > 0)
|
||||
@ -52,8 +51,12 @@ _pdfioDictClear(pdfio_dict_t *dict, // I - Dictionary
|
||||
|
||||
if (idx < dict->num_pairs)
|
||||
memmove(pair, pair + 1, (dict->num_pairs - idx) * sizeof(_pdfio_pair_t));
|
||||
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
@ -162,6 +165,30 @@ pdfioDictCreate(pdfio_file_t *pdf) // I - PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioDictDecrypt()' - Decrypt the values in a dictionary.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on error
|
||||
_pdfioDictDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||
pdfio_obj_t *obj, // I - Object
|
||||
pdfio_dict_t *dict, // I - Dictionary
|
||||
size_t depth) // I - Depth
|
||||
{
|
||||
size_t i; // Looping var
|
||||
_pdfio_pair_t *pair; // Current pair
|
||||
|
||||
|
||||
for (i = dict->num_pairs, pair = dict->pairs; i > 0; i --, pair ++)
|
||||
{
|
||||
if (strcmp(pair->key, "ID") && !_pdfioValueDecrypt(pdf, obj, &pair->value, depth + 1))
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioDictDebug()' - Dump a dictionary to stderr.
|
||||
//
|
||||
@ -174,6 +201,9 @@ _pdfioDictDebug(pdfio_dict_t *dict, // I - Dictionary
|
||||
_pdfio_pair_t *pair; // Current pair
|
||||
|
||||
|
||||
if (!dict)
|
||||
return;
|
||||
|
||||
for (i = dict->num_pairs, pair = dict->pairs; i > 0; i --, pair ++)
|
||||
{
|
||||
fprintf(fp, "/%s", pair->key);
|
||||
@ -312,6 +342,18 @@ pdfioDictGetDict(pdfio_dict_t *dict, // I - Dictionary
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictGetKey()' - Get the key for the specified pair.
|
||||
//
|
||||
|
||||
const char * // O - Key for specified pair
|
||||
pdfioDictGetKey(pdfio_dict_t *dict, // I - Dictionary
|
||||
size_t n) // I - Pair index (`0`-based)
|
||||
{
|
||||
return ((dict && n < dict->num_pairs) ? dict->pairs[n].key : NULL);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictGetName()' - Get a key name value from a dictionary.
|
||||
//
|
||||
@ -330,6 +372,17 @@ pdfioDictGetName(pdfio_dict_t *dict, // I - Dictionary
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictGetNumPairs()' - Get the number of key/value pairs in a dictionary.
|
||||
//
|
||||
|
||||
size_t // O - Number of pairs
|
||||
pdfioDictGetNumPairs(pdfio_dict_t *dict)// I - Dictionary
|
||||
{
|
||||
return (dict ? dict->num_pairs : 0);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictGetNumber()' - Get a key number value from a dictionary.
|
||||
//
|
||||
@ -406,9 +459,27 @@ pdfioDictGetString(pdfio_dict_t *dict, // I - Dictionary
|
||||
|
||||
|
||||
if (value && value->type == PDFIO_VALTYPE_STRING)
|
||||
{
|
||||
return (value->value.string);
|
||||
}
|
||||
else if (value && value->type == PDFIO_VALTYPE_BINARY && value->value.binary.datalen < 4096)
|
||||
{
|
||||
// Convert binary string to regular string...
|
||||
char temp[4096]; // Temporary string
|
||||
|
||||
memcpy(temp, value->value.binary.data, value->value.binary.datalen);
|
||||
temp[value->value.binary.datalen] = '\0';
|
||||
|
||||
free(value->value.binary.data);
|
||||
value->type = PDFIO_VALTYPE_STRING;
|
||||
value->value.string = pdfioStringCreate(dict->pdf, temp);
|
||||
|
||||
return (value->value.string);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -522,7 +593,7 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfio_value_t value; // Dictionary value
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioDictRead(pdf=%p)\n", pdf);
|
||||
PDFIO_DEBUG("_pdfioDictRead(pdf=%p, obj=%p, tb=%p, depth=%lu)\n", pdf, obj, tb, (unsigned long)depth);
|
||||
|
||||
// Create a dictionary and start reading...
|
||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||
@ -534,6 +605,7 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
||||
if (!strcmp(key, ">>"))
|
||||
{
|
||||
// End of dictionary...
|
||||
PDFIO_DEBUG("_pdfioDictRead: Returning dictionary value...\n");
|
||||
return (dict);
|
||||
}
|
||||
else if (key[0] != '/')
|
||||
@ -552,14 +624,14 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
if (!_pdfioValueRead(pdf, obj, tb, &value, depth))
|
||||
{
|
||||
_pdfioFileError(pdf, "Missing value for dictionary key.");
|
||||
_pdfioFileError(pdf, "Missing value for dictionary key '%s'.", key + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_pdfioDictSetValue(dict, pdfioStringCreate(pdf, key + 1), &value))
|
||||
break;
|
||||
|
||||
// PDFIO_DEBUG("_pdfioDictRead: Set %s.\n", key);
|
||||
PDFIO_DEBUG("_pdfioDictRead: Set %s.\n", key);
|
||||
}
|
||||
|
||||
// Dictionary is invalid - pdfioFileClose will free the memory, return NULL
|
||||
|
906
pdfio-file.c
906
pdfio-file.c
File diff suppressed because it is too large
Load Diff
105
pdfio-object.c
105
pdfio-object.c
@ -1,16 +1,12 @@
|
||||
//
|
||||
// PDF object functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -103,7 +99,7 @@ pdfioObjCopy(pdfio_file_t *pdf, // I - PDF file
|
||||
return (NULL);
|
||||
|
||||
if (dstobj->value.type == PDFIO_VALTYPE_DICT)
|
||||
_pdfioDictClear(dstobj->value.value.dict, "Length");
|
||||
pdfioDictClear(dstobj->value.value.dict, "Length");
|
||||
|
||||
if (srcobj->stream_offset)
|
||||
{
|
||||
@ -221,8 +217,13 @@ void
|
||||
_pdfioObjDelete(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
if (obj)
|
||||
{
|
||||
pdfioStreamClose(obj->stream);
|
||||
|
||||
if (obj->datafree)
|
||||
(obj->datafree)(obj->data);
|
||||
}
|
||||
|
||||
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.
|
||||
//
|
||||
@ -321,6 +333,26 @@ pdfioObjGetLength(pdfio_obj_t *obj) // I - Object
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioObjGetName()' - Get the name value associated with an object.
|
||||
//
|
||||
|
||||
const char * // O - Dictionary or `NULL` on error
|
||||
pdfioObjGetName(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
if (!obj)
|
||||
return (NULL);
|
||||
|
||||
if (obj->value.type == PDFIO_VALTYPE_NONE)
|
||||
_pdfioObjLoad(obj);
|
||||
|
||||
if (obj->value.type == PDFIO_VALTYPE_NAME)
|
||||
return (obj->value.value.name);
|
||||
else
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioObjGetNumber()' - Get the object's number.
|
||||
//
|
||||
@ -335,8 +367,21 @@ pdfioObjGetNumber(pdfio_obj_t *obj) // I - Object
|
||||
//
|
||||
// 'pdfioObjGetSubtype()' - Get an object's subtype.
|
||||
//
|
||||
// This function returns an object's PDF subtype name, if any. Common subtype
|
||||
// names include:
|
||||
//
|
||||
// - "CIDFontType0": A CID Type0 font
|
||||
// - "CIDFontType2": A CID TrueType font
|
||||
// - "Image": An image or image mask
|
||||
// - "Form": A fillable form
|
||||
// - "OpenType": An OpenType font
|
||||
// - "Type0": A composite font
|
||||
// - "Type1": A PostScript Type1 font
|
||||
// - "Type3": A PDF Type3 font
|
||||
// - "TrueType": A TrueType font
|
||||
//
|
||||
|
||||
const char * // O - Object subtype
|
||||
const char * // O - Object subtype name or `NULL` for none
|
||||
pdfioObjGetSubtype(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
pdfio_dict_t *dict; // Object dictionary
|
||||
@ -352,8 +397,21 @@ pdfioObjGetSubtype(pdfio_obj_t *obj) // I - Object
|
||||
//
|
||||
// 'pdfioObjGetType()' - Get an object's type.
|
||||
//
|
||||
// This function returns an object's PDF type name, if any. Common type names
|
||||
// include:
|
||||
//
|
||||
// - "CMap": A character map for composite fonts
|
||||
// - "Font": An embedded font (@link pdfioObjGetSubtype@ will tell you the
|
||||
// font format)
|
||||
// - "FontDescriptor": A font descriptor
|
||||
// - "Page": A (visible) page
|
||||
// - "Pages": A page tree node
|
||||
// - "Template": An invisible template page
|
||||
// - "XObject": An image, image mask, or form (@link pdfioObjGetSubtype@ will
|
||||
// tell you which)
|
||||
//
|
||||
|
||||
const char * // O - Object type
|
||||
const char * // O - Object type name or `NULL` for none
|
||||
pdfioObjGetType(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
pdfio_dict_t *dict; // Object dictionary
|
||||
@ -441,9 +499,7 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
||||
return (false);
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[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
|
||||
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[1]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
|
||||
|
||||
_pdfioTokenFlush(&tb);
|
||||
|
||||
@ -454,6 +510,18 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
||||
PDFIO_DEBUG("_pdfioObjLoad: stream_offset=%lu.\n", (unsigned long)obj->stream_offset);
|
||||
}
|
||||
|
||||
// Decrypt as needed...
|
||||
if (obj->pdf->encryption)
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioObjLoad: Decrypting value...\n");
|
||||
|
||||
if (!_pdfioValueDecrypt(obj->pdf, obj, &obj->value, 0))
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioObjLoad: Failed to decrypt.\n");
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioObjLoad: ");
|
||||
PDFIO_DEBUG_VALUE(&obj->value);
|
||||
PDFIO_DEBUG("\n");
|
||||
@ -498,6 +566,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...
|
||||
//
|
||||
|
@ -7,10 +7,6 @@
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Private header file for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -20,6 +20,7 @@
|
||||
# include <errno.h>
|
||||
# include <inttypes.h>
|
||||
# include <fcntl.h>
|
||||
# include <locale.h>
|
||||
# ifdef _WIN32
|
||||
# include <io.h>
|
||||
# include <direct.h>
|
||||
@ -37,9 +38,11 @@
|
||||
# define unlink _unlink
|
||||
# define vsnprintf _vsnprintf
|
||||
# define write _write
|
||||
# define F_OK 00 // POSIX parameters/flags
|
||||
# define W_OK 02
|
||||
# define R_OK 04
|
||||
# ifndef F_OK
|
||||
# define F_OK 00 // POSIX parameters/flags
|
||||
# define W_OK 02
|
||||
# define R_OK 04
|
||||
# endif // !F_OK
|
||||
# define O_RDONLY _O_RDONLY // Map standard POSIX open flags
|
||||
# define O_WRONLY _O_WRONLY
|
||||
# define O_CREAT _O_CREAT
|
||||
@ -92,6 +95,9 @@
|
||||
|
||||
# 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
|
||||
{
|
||||
_PDFIO_MODE_READ, // Read a PDF file
|
||||
@ -221,6 +227,7 @@ typedef struct _pdfio_objmap_s // PDF object map
|
||||
struct _pdfio_file_s // PDF file structure
|
||||
{
|
||||
char *filename; // Filename
|
||||
struct lconv *loc; // Locale data
|
||||
char *version; // Version number
|
||||
pdfio_rect_t media_box, // Default MediaBox value
|
||||
crop_box; // Default CropBox value
|
||||
@ -234,7 +241,8 @@ struct _pdfio_file_s // PDF file structure
|
||||
pdfio_permission_t permissions; // Access permissions (encrypted PDF files)
|
||||
uint8_t file_key[16], // File encryption key
|
||||
owner_key[32], // Owner encryption key
|
||||
user_key[32]; // User encryption key
|
||||
user_key[32], // User encryption key
|
||||
password[32]; // Padded password
|
||||
size_t file_keylen, // Length of file encryption key
|
||||
owner_keylen, // Length of owner encryption key
|
||||
user_keylen; // Length of user encryption key
|
||||
@ -262,7 +270,8 @@ struct _pdfio_file_s // PDF file structure
|
||||
alloc_dicts; // Allocated dictionaries
|
||||
pdfio_dict_t **dicts; // Dictionaries
|
||||
size_t num_objs, // Number of objects
|
||||
alloc_objs; // Allocated objects
|
||||
alloc_objs, // Allocated objects
|
||||
last_obj; // Last object added
|
||||
pdfio_obj_t **objs, // Objects
|
||||
*current_obj; // Current object being written/read
|
||||
size_t num_objmaps, // Number of object maps
|
||||
@ -287,6 +296,8 @@ struct _pdfio_obj_s // Object
|
||||
size_t stream_length; // Length of stream, if any
|
||||
_pdfio_value_t value; // Dictionary/number/etc. value
|
||||
pdfio_stream_t *stream; // Open stream, if any
|
||||
void *data; // Extension data, if any
|
||||
_pdfio_extfree_t datafree; // Free callback for extension data
|
||||
};
|
||||
|
||||
struct _pdfio_stream_s // Stream
|
||||
@ -315,6 +326,10 @@ struct _pdfio_stream_s // Stream
|
||||
// Functions...
|
||||
//
|
||||
|
||||
extern double _pdfio_strtod(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
|
||||
extern ssize_t _pdfio_vsnprintf(pdfio_file_t *pdf, char *buffer, size_t bufsize, const char *format, va_list ap) _PDFIO_INTERNAL;
|
||||
|
||||
extern bool _pdfioArrayDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_array_t *a, size_t depth) _PDFIO_INTERNAL;
|
||||
extern void _pdfioArrayDebug(pdfio_array_t *a, FILE *fp) _PDFIO_INTERNAL;
|
||||
extern void _pdfioArrayDelete(pdfio_array_t *a) _PDFIO_INTERNAL;
|
||||
extern _pdfio_value_t *_pdfioArrayGetValue(pdfio_array_t *a, size_t n) _PDFIO_INTERNAL;
|
||||
@ -338,7 +353,7 @@ extern void _pdfioCryptoSHA256Init(_pdfio_sha256_t *ctx) _PDFIO_INTERNAL;
|
||||
extern void _pdfioCryptoSHA256Finish(_pdfio_sha256_t *ctx, uint8_t *Message_Digest) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioCryptoUnlock(pdfio_file_t *pdf, pdfio_password_cb_t password_cb, void *password_data) _PDFIO_INTERNAL;
|
||||
|
||||
extern void _pdfioDictClear(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioDictDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_dict_t *dict, size_t depth) _PDFIO_INTERNAL;
|
||||
extern void _pdfioDictDebug(pdfio_dict_t *dict, FILE *fp) _PDFIO_INTERNAL;
|
||||
extern void _pdfioDictDelete(pdfio_dict_t *dict) _PDFIO_INTERNAL;
|
||||
extern _pdfio_value_t *_pdfioDictGetValue(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
||||
@ -365,7 +380,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 void _pdfioObjDelete(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
extern void *_pdfioObjGetExtension(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioObjLoad(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
extern void _pdfioObjSetExtension(pdfio_obj_t *obj, void *data, _pdfio_extfree_t datafree) _PDFIO_INTERNAL;
|
||||
|
||||
extern 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;
|
||||
@ -380,6 +397,7 @@ extern void _pdfioTokenPush(_pdfio_token_t *tb, const char *token) _PDFIO_INTER
|
||||
extern bool _pdfioTokenRead(_pdfio_token_t *tb, char *buffer, size_t bufsize);
|
||||
|
||||
extern _pdfio_value_t *_pdfioValueCopy(pdfio_file_t *pdfdst, _pdfio_value_t *vdst, pdfio_file_t *pdfsrc, _pdfio_value_t *vsrc) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioValueDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
|
||||
extern void _pdfioValueDebug(_pdfio_value_t *v, FILE *fp) _PDFIO_INTERNAL;
|
||||
extern void _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;
|
||||
|
@ -1,16 +1,12 @@
|
||||
//
|
||||
// PDF stream functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -412,6 +408,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
pdfio_stream_t *st; // Stream
|
||||
pdfio_dict_t *dict = pdfioObjGetDict(obj);
|
||||
// Object dictionary
|
||||
const char *type; // Object type
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen(obj=%p(%u), decode=%s)\n", obj, (unsigned)obj->number, decode ? "true" : "false");
|
||||
@ -438,7 +435,9 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (obj->pdf->encryption)
|
||||
type = pdfioObjGetType(obj);
|
||||
|
||||
if (obj->pdf->encryption && (!type || strcmp(type, "XRef")))
|
||||
{
|
||||
uint8_t iv[64]; // Initialization vector
|
||||
size_t ivlen; // Length of initialization vector, if any
|
||||
@ -691,7 +690,7 @@ pdfioStreamPrintf(
|
||||
|
||||
// Format the string...
|
||||
va_start(ap, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||
_pdfio_vsnprintf(st->pdf, buffer, sizeof(buffer), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Write the string...
|
||||
@ -1065,17 +1064,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
st->flate.next_out = (Bytef *)buffer;
|
||||
st->flate.avail_out = (uInt)bytes;
|
||||
|
||||
avail_in = st->flate.avail_in;
|
||||
avail_out = st->flate.avail_out;
|
||||
|
||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
||||
return (-1);
|
||||
}
|
||||
else if (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Corrupt stream data.");
|
||||
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -1131,7 +1122,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
|
||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
||||
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
||||
return (-1);
|
||||
}
|
||||
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
||||
@ -1201,7 +1192,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
|
||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
||||
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
||||
return (-1);
|
||||
}
|
||||
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
||||
|
457
pdfio-string.c
457
pdfio-string.c
@ -1,16 +1,12 @@
|
||||
//
|
||||
// PDF dictionary functions for PDFio.
|
||||
// PDF string functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -18,7 +14,360 @@
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
static int compare_strings(char **a, char **b);
|
||||
static size_t find_string(pdfio_file_t *pdf, const char *s, int *rdiff);
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_strtod()' - Convert a string to a double value.
|
||||
//
|
||||
// This function wraps strtod() to avoid locale issues.
|
||||
//
|
||||
|
||||
double // O - Double value
|
||||
_pdfio_strtod(pdfio_file_t *pdf, // I - PDF file
|
||||
const char *s) // I - String
|
||||
{
|
||||
char temp[64], // Temporary buffer
|
||||
*tempptr; // Pointer into temporary buffer
|
||||
|
||||
|
||||
// See if the locale has a special decimal point string...
|
||||
if (!pdf->loc)
|
||||
return (strtod(s, NULL));
|
||||
|
||||
// Copy leading sign, numbers, period, and then numbers...
|
||||
tempptr = temp;
|
||||
temp[sizeof(temp) - 1] = '\0';
|
||||
|
||||
while (*s && *s != '.')
|
||||
{
|
||||
if (tempptr < (temp + sizeof(temp) - 1))
|
||||
*tempptr++ = *s++;
|
||||
else
|
||||
return (0.0);
|
||||
}
|
||||
|
||||
if (*s == '.')
|
||||
{
|
||||
// Convert decimal point to locale equivalent...
|
||||
size_t declen = strlen(pdf->loc->decimal_point);
|
||||
// Length of decimal point
|
||||
s ++;
|
||||
|
||||
if (declen <= (sizeof(temp) - (size_t)(tempptr - temp)))
|
||||
{
|
||||
memcpy(tempptr, pdf->loc->decimal_point, declen);
|
||||
tempptr += declen;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy any remaining characters...
|
||||
while (*s)
|
||||
{
|
||||
if (tempptr < (temp + sizeof(temp) - 1))
|
||||
*tempptr++ = *s++;
|
||||
else
|
||||
return (0.0);
|
||||
}
|
||||
|
||||
// Nul-terminate the temporary string and convert the string...
|
||||
*tempptr = '\0';
|
||||
|
||||
return (strtod(temp, NULL));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_vsnprintf()' - Format a string.
|
||||
//
|
||||
// This function emulates vsnprintf() to avoid locale issues.
|
||||
//
|
||||
|
||||
ssize_t // O - Number of bytes
|
||||
_pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
char *buffer, // I - Output buffer
|
||||
size_t bufsize, // I - Size of output buffer
|
||||
const char *format, // I - printf-style format string
|
||||
va_list ap) // I - Pointer to additional arguments
|
||||
{
|
||||
char *bufptr, // Pointer to position in buffer
|
||||
*bufend, // Pointer to end of buffer
|
||||
size, // Size character (h, l, L)
|
||||
type; // Format type character
|
||||
int width, // Width of field
|
||||
prec; // Number of characters of precision
|
||||
char tformat[100], // Temporary format string for snprintf()
|
||||
*tptr, // Pointer into temporary format
|
||||
temp[1024], // Buffer for formatted numbers
|
||||
*tempptr; // Pointer into buffer
|
||||
char *s; // Pointer to string
|
||||
ssize_t bytes; // Total number of bytes needed
|
||||
const char *dec = pdf->loc ? pdf->loc->decimal_point : ".";
|
||||
// Decimal point string
|
||||
char *decptr; // Pointer to decimal point
|
||||
|
||||
|
||||
// Loop through the format string, formatting as needed...
|
||||
bufptr = buffer;
|
||||
bufend = buffer + bufsize - 1;
|
||||
*bufend = '\0';
|
||||
bytes = 0;
|
||||
|
||||
while (*format)
|
||||
{
|
||||
if (*format == '%')
|
||||
{
|
||||
// Format character...
|
||||
tptr = tformat;
|
||||
*tptr++ = *format++;
|
||||
|
||||
if (*format == '%')
|
||||
{
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *format;
|
||||
bytes ++;
|
||||
format ++;
|
||||
continue;
|
||||
}
|
||||
else if (strchr(" -+#\'", *format))
|
||||
{
|
||||
*tptr++ = *format++;
|
||||
}
|
||||
|
||||
if (*format == '*')
|
||||
{
|
||||
// Get width from argument...
|
||||
format ++;
|
||||
width = va_arg(ap, int);
|
||||
|
||||
snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", width);
|
||||
tptr += strlen(tptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
width = 0;
|
||||
|
||||
while (isdigit(*format & 255))
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
width = width * 10 + *format++ - '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (*format == '.')
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
format ++;
|
||||
|
||||
if (*format == '*')
|
||||
{
|
||||
// Get precision from argument...
|
||||
format ++;
|
||||
prec = va_arg(ap, int);
|
||||
|
||||
snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", prec);
|
||||
tptr += strlen(tptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
prec = 0;
|
||||
|
||||
while (isdigit(*format & 255))
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
prec = prec * 10 + *format++ - '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*format == 'l' && format[1] == 'l')
|
||||
{
|
||||
size = 'L';
|
||||
|
||||
if (tptr < (tformat + sizeof(tformat) - 2))
|
||||
{
|
||||
*tptr++ = 'l';
|
||||
*tptr++ = 'l';
|
||||
}
|
||||
|
||||
format += 2;
|
||||
}
|
||||
else if (*format == 'h' || *format == 'l' || *format == 'L')
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
size = *format++;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = 0;
|
||||
}
|
||||
|
||||
if (!*format)
|
||||
break;
|
||||
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
type = *format++;
|
||||
*tptr = '\0';
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 'E' : // Floating point formats
|
||||
case 'G' :
|
||||
case 'e' :
|
||||
case 'f' :
|
||||
case 'g' :
|
||||
if ((size_t)(width + 2) > sizeof(temp))
|
||||
break;
|
||||
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, double));
|
||||
|
||||
if ((decptr = strstr(temp, dec)) != NULL)
|
||||
{
|
||||
// Convert locale decimal point to "."
|
||||
PDFIO_DEBUG("_pdfio_vsnprintf: Before \"%s\"\n", temp);
|
||||
tempptr = decptr + strlen(dec);
|
||||
if (tempptr > (decptr + 1))
|
||||
memmove(decptr + 1, tempptr, strlen(tempptr) + 1);
|
||||
*decptr = '.';
|
||||
|
||||
// Strip trailing 0's...
|
||||
for (tempptr = temp + strlen(temp) - 1; tempptr > temp && *tempptr == '0'; tempptr --)
|
||||
*tempptr = '\0';
|
||||
|
||||
if (*tempptr == '.')
|
||||
*tempptr = '\0'; // Strip trailing decimal point
|
||||
|
||||
PDFIO_DEBUG("_pdfio_vsnprintf: After \"%s\"\n", temp);
|
||||
}
|
||||
|
||||
// Copy to the output buffer
|
||||
bytes += (int)strlen(temp);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
strncpy(bufptr, temp, (size_t)(bufend - bufptr - 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'B' : // Integer formats
|
||||
case 'X' :
|
||||
case 'b' :
|
||||
case 'd' :
|
||||
case 'i' :
|
||||
case 'o' :
|
||||
case 'u' :
|
||||
case 'x' :
|
||||
if ((size_t)(width + 2) > sizeof(temp))
|
||||
break;
|
||||
|
||||
# ifdef HAVE_LONG_LONG
|
||||
if (size == 'L')
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, long long));
|
||||
else
|
||||
# endif // HAVE_LONG_LONG
|
||||
if (size == 'l')
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, long));
|
||||
else
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, int));
|
||||
|
||||
bytes += (int)strlen(temp);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
strncpy(bufptr, temp, (size_t)(bufend - bufptr - 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p' : // Pointer value
|
||||
if ((size_t)(width + 2) > sizeof(temp))
|
||||
break;
|
||||
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, void *));
|
||||
|
||||
bytes += (int)strlen(temp);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
strncpy(bufptr, temp, (size_t)(bufend - bufptr - 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c' : // Character or character array
|
||||
bytes += width;
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
if (width <= 1)
|
||||
{
|
||||
*bufptr++ = (char)va_arg(ap, int);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((bufptr + width) > bufend)
|
||||
width = (int)(bufend - bufptr);
|
||||
|
||||
memcpy(bufptr, va_arg(ap, char *), (size_t)width);
|
||||
bufptr += width;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 's' : // String
|
||||
if ((s = va_arg(ap, char *)) == NULL)
|
||||
s = "(null)";
|
||||
|
||||
bytes += strlen(s);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
strncpy(bufptr, s, (size_t)(bufend - bufptr - 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n' : // Output number of chars so far
|
||||
*(va_arg(ap, int *)) = (int)bytes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal character...
|
||||
bytes ++;
|
||||
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *format++;
|
||||
}
|
||||
}
|
||||
|
||||
// Nul-terminate the string and return the number of characters needed.
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
// Everything fit in the buffer...
|
||||
*bufptr = '\0';
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfio_vsnprintf: Returning %ld \"%s\"\n", (long)bytes, buffer);
|
||||
|
||||
return (bytes);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
@ -36,8 +385,9 @@ pdfioStringCreate(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
const char *s) // I - Nul-terminated string
|
||||
{
|
||||
char *news; // New string
|
||||
char **match; // Matching string
|
||||
char *news; // New string
|
||||
size_t idx; // Index into strings
|
||||
int diff; // Different
|
||||
|
||||
|
||||
PDFIO_DEBUG("pdfioStringCreate(pdf=%p, s=\"%s\")\n", pdf, s);
|
||||
@ -47,8 +397,17 @@ pdfioStringCreate(
|
||||
return (NULL);
|
||||
|
||||
// See if the string has already been added...
|
||||
if (pdf->num_strings > 0 && (match = (char **)bsearch(&s, pdf->strings, pdf->num_strings, sizeof(char *), (int (*)(const void *, const void *))compare_strings)) != NULL)
|
||||
return (*match);
|
||||
if (pdf->num_strings > 0)
|
||||
{
|
||||
idx = find_string(pdf, s, &diff);
|
||||
if (diff == 0)
|
||||
return (pdf->strings[idx]);
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = 0;
|
||||
diff = -1;
|
||||
}
|
||||
|
||||
// Not already added, so add it...
|
||||
if ((news = strdup(s)) == NULL)
|
||||
@ -69,11 +428,17 @@ pdfioStringCreate(
|
||||
pdf->alloc_strings += 128;
|
||||
}
|
||||
|
||||
// TODO: Change to insertion sort as needed...
|
||||
pdf->strings[pdf->num_strings ++] = news;
|
||||
// Insert the string...
|
||||
if (diff > 0)
|
||||
idx ++;
|
||||
|
||||
if (pdf->num_strings > 1)
|
||||
qsort(pdf->strings, pdf->num_strings, sizeof(char *), (int (*)(const void *, const void *))compare_strings);
|
||||
PDFIO_DEBUG("pdfioStringCreate: Inserting \"%s\" at %u\n", news, (unsigned)idx);
|
||||
|
||||
if (idx < pdf->num_strings)
|
||||
memmove(pdf->strings + idx + 1, pdf->strings + idx, (pdf->num_strings - idx) * sizeof(char *));
|
||||
|
||||
pdf->strings[idx] = news;
|
||||
pdf->num_strings ++;
|
||||
|
||||
PDFIO_DEBUG("pdfioStringCreate: %lu strings\n", (unsigned long)pdf->num_strings);
|
||||
|
||||
@ -124,17 +489,67 @@ _pdfioStringIsAllocated(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
const char *s) // I - String
|
||||
{
|
||||
return (pdf->num_strings > 0 && bsearch(&s, pdf->strings, pdf->num_strings, sizeof(char *), (int (*)(const void *, const void *))compare_strings) != NULL);
|
||||
int diff; // Difference
|
||||
|
||||
|
||||
if (pdf->num_strings == 0)
|
||||
return (false);
|
||||
|
||||
find_string(pdf, s, &diff);
|
||||
|
||||
return (diff == 0);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'compare_strings()' - Compare two strings.
|
||||
// 'find_string()' - Find an element in the array.
|
||||
//
|
||||
|
||||
static int // O - Result of comparison
|
||||
compare_strings(char **a, // I - First string
|
||||
char **b) // I - Second string
|
||||
static size_t // O - Index of match
|
||||
find_string(pdfio_file_t *pdf, // I - PDF file
|
||||
const char *s, // I - String to find
|
||||
int *rdiff) // O - Difference of match
|
||||
{
|
||||
return (strcmp(*a, *b));
|
||||
size_t left, // Left side of search
|
||||
right, // Right side of search
|
||||
current; // Current element
|
||||
int diff; // Comparison with current element
|
||||
|
||||
|
||||
// Do a binary search for the string...
|
||||
left = 0;
|
||||
right = pdf->num_strings - 1;
|
||||
|
||||
do
|
||||
{
|
||||
current = (left + right) / 2;
|
||||
diff = strcmp(s, pdf->strings[current]);
|
||||
|
||||
if (diff == 0)
|
||||
break;
|
||||
else if (diff < 0)
|
||||
right = current;
|
||||
else
|
||||
left = current;
|
||||
}
|
||||
while ((right - left) > 1);
|
||||
|
||||
if (diff != 0)
|
||||
{
|
||||
// Check the last 1 or 2 elements...
|
||||
if ((diff = strcmp(s, pdf->strings[left])) <= 0)
|
||||
{
|
||||
current = left;
|
||||
}
|
||||
else
|
||||
{
|
||||
diff = strcmp(s, pdf->strings[right]);
|
||||
current = right;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the closest string and the difference...
|
||||
*rdiff = diff;
|
||||
|
||||
return (current);
|
||||
}
|
||||
|
@ -7,10 +7,6 @@
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -212,9 +208,10 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
*bufend, // End of buffer
|
||||
state = '\0'; // Current state
|
||||
bool saw_nul = false; // Did we see a nul character?
|
||||
size_t count = 0; // Number of whitespace/comment bytes
|
||||
|
||||
|
||||
|
||||
//
|
||||
// "state" is:
|
||||
//
|
||||
// - '\0' for idle
|
||||
@ -233,21 +230,45 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
// Skip leading whitespace...
|
||||
while ((ch = get_char(tb)) != EOF)
|
||||
{
|
||||
count ++;
|
||||
|
||||
if (ch == '%')
|
||||
{
|
||||
// Skip comment
|
||||
PDFIO_DEBUG("_pdfioTokenRead: Skipping comment...\n");
|
||||
while ((ch = get_char(tb)) != EOF)
|
||||
{
|
||||
count ++;
|
||||
|
||||
if (ch == '\n' || ch == '\r')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (count > 2048)
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Comment too long.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!isspace(ch))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (count > 2048)
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Too much whitespace.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == EOF)
|
||||
{
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Check for delimiters...
|
||||
if (strchr(PDFIO_DELIM_CHARS, ch) != NULL)
|
||||
@ -267,6 +288,8 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
*bufptr++ = (char)ch;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioTokenRead: state='%c'\n", state);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case '(' : // Literal string
|
||||
@ -358,6 +381,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
{
|
||||
// Out of space
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
@ -365,6 +389,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
if (ch != ')')
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Unterminated string literal.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
|
||||
@ -384,6 +409,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
{
|
||||
// Out of space...
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
|
||||
@ -417,9 +443,17 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
{
|
||||
// Out of space...
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == '\r')
|
||||
{
|
||||
// Look for a trailing LF
|
||||
if ((ch = get_char(tb)) != EOF && ch != '\n')
|
||||
tb->bufptr --;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N' : // number
|
||||
@ -428,6 +462,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
if (!isdigit(ch) && ch != '.')
|
||||
{
|
||||
// End of number...
|
||||
PDFIO_DEBUG("_pdfioTokenRead: End of number with ch=0x%02x\n", ch);
|
||||
tb->bufptr --;
|
||||
break;
|
||||
}
|
||||
@ -440,6 +475,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
{
|
||||
// Out of space...
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
@ -466,12 +502,17 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
if (!isxdigit(tch & 255))
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Bad # escape in name.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
else if (isdigit(tch))
|
||||
{
|
||||
ch = ((ch & 255) << 4) | (tch - '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = ((ch & 255) << 4) | (tolower(tch) - 'a' + 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -483,9 +524,17 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
{
|
||||
// Out of space
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
if (bufptr == (buffer + 1))
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Empty name.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
break;
|
||||
|
||||
case '<' : // Potential hex string
|
||||
@ -505,9 +554,12 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
else if (!isspace(ch & 255) && !isxdigit(ch & 255))
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Syntax error: '<%c'", ch);
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (isxdigit(ch))
|
||||
@ -516,25 +568,39 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
{
|
||||
// Hex digit
|
||||
*bufptr++ = (char)ch;
|
||||
count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Too large
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
else if (!isspace(ch))
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Invalid hex string character '%c'.", ch);
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
else
|
||||
{
|
||||
count ++;
|
||||
if (count > 2048)
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Too much whitespace.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((ch = get_char(tb)) != EOF && ch != '>');
|
||||
|
||||
if (ch == EOF)
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Unterminated hex string.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
break;
|
||||
@ -547,6 +613,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
else
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Syntax error: '>%c'.", ch);
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
break;
|
||||
@ -554,7 +621,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
|
||||
*bufptr = '\0';
|
||||
|
||||
// PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
||||
PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
||||
|
||||
return (bufptr > buffer);
|
||||
}
|
||||
@ -591,7 +658,6 @@ get_char(_pdfio_token_t *tb) // I - Token buffer
|
||||
tb->bufptr = tb->buffer;
|
||||
tb->bufend = tb->buffer + bytes;
|
||||
|
||||
#if 0
|
||||
#ifdef DEBUG
|
||||
unsigned char *ptr; // Pointer into buffer
|
||||
|
||||
@ -605,7 +671,6 @@ get_char(_pdfio_token_t *tb) // I - Token buffer
|
||||
}
|
||||
PDFIO_DEBUG("'\n");
|
||||
#endif // DEBUG
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
// Return the next character...
|
||||
|
288
pdfio-value.c
288
pdfio-value.c
@ -1,17 +1,20 @@
|
||||
//
|
||||
// PDF value functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
static time_t get_date_time(const char *s);
|
||||
|
||||
|
||||
//
|
||||
@ -109,6 +112,101 @@ _pdfioValueCopy(pdfio_file_t *pdfdst, // I - Destination PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioValueDecrypt()' - Decrypt a value.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on error
|
||||
_pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||
pdfio_obj_t *obj, // I - Object
|
||||
_pdfio_value_t *v, // I - Value
|
||||
size_t depth)// I - Depth
|
||||
{
|
||||
_pdfio_crypto_ctx_t ctx; // Decryption context
|
||||
_pdfio_crypto_cb_t cb; // Decryption callback
|
||||
size_t ivlen; // Number of initialization vector bytes
|
||||
uint8_t temp[32768]; // Temporary buffer for decryption
|
||||
size_t templen; // Number of actual data bytes
|
||||
time_t timeval; // Date/time value
|
||||
|
||||
|
||||
if (depth > PDFIO_MAX_DEPTH)
|
||||
{
|
||||
_pdfioFileError(pdf, "Value too deep.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
switch (v->type)
|
||||
{
|
||||
default :
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case PDFIO_VALTYPE_ARRAY :
|
||||
return (_pdfioArrayDecrypt(pdf, obj, v->value.array, depth + 1));
|
||||
break;
|
||||
|
||||
case PDFIO_VALTYPE_DICT :
|
||||
return (_pdfioDictDecrypt(pdf, obj, v->value.dict, depth + 1));
|
||||
break;
|
||||
|
||||
case PDFIO_VALTYPE_BINARY :
|
||||
// Decrypt the binary string...
|
||||
if (v->value.binary.datalen > (sizeof(temp) - 32))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted binary string - too long.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
ivlen = v->value.binary.datalen;
|
||||
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL)
|
||||
return (false);
|
||||
|
||||
templen = (cb)(&ctx, temp, v->value.binary.data + ivlen, v->value.binary.datalen - ivlen);
|
||||
|
||||
// Copy the decrypted string back to the value and adjust the length...
|
||||
memcpy(v->value.binary.data, temp, templen);
|
||||
|
||||
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128)
|
||||
v->value.binary.datalen = templen - temp[templen - 1];
|
||||
else
|
||||
v->value.binary.datalen = templen;
|
||||
break;
|
||||
|
||||
case PDFIO_VALTYPE_STRING :
|
||||
// Decrypt regular string...
|
||||
templen = strlen(v->value.string);
|
||||
if (templen > (sizeof(temp) - 33))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted string - too long.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
ivlen = templen;
|
||||
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, (uint8_t *)v->value.string, &ivlen)) == NULL)
|
||||
return (false);
|
||||
|
||||
templen = (cb)(&ctx, temp, (uint8_t *)v->value.string + ivlen, templen - ivlen);
|
||||
temp[templen] = '\0';
|
||||
|
||||
if ((timeval = get_date_time((char *)temp)) != 0)
|
||||
{
|
||||
// Change the type to date...
|
||||
v->type = PDFIO_VALTYPE_DATE;
|
||||
v->value.date = timeval;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the decrypted string back to the value...
|
||||
v->value.string = pdfioStringCreate(pdf, (char *)temp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioValueDebug()' - Print the contents of a value.
|
||||
//
|
||||
@ -117,6 +215,9 @@ void
|
||||
_pdfioValueDebug(_pdfio_value_t *v, // I - Value
|
||||
FILE *fp) // I - Output file
|
||||
{
|
||||
if (!v)
|
||||
return;
|
||||
|
||||
switch (v->type)
|
||||
{
|
||||
case PDFIO_VALTYPE_ARRAY :
|
||||
@ -200,6 +301,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
size_t depth) // I - Depth of value
|
||||
{
|
||||
char token[32768]; // Token buffer
|
||||
time_t timeval; // Date/time value
|
||||
#ifdef DEBUG
|
||||
static const char * const valtypes[] =
|
||||
{
|
||||
@ -249,73 +351,10 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
else if (!strncmp(token, "(D:", 3))
|
||||
else if (!strncmp(token, "(D:", 3) && (timeval = get_date_time(token + 1)) != 0)
|
||||
{
|
||||
// Possible date value of the form:
|
||||
//
|
||||
// (D:YYYYMMDDhhmmssZ)
|
||||
// (D:YYYYMMDDhhmmss+HH'mm)
|
||||
// (D:YYYYMMDDhhmmss-HH'mm)
|
||||
//
|
||||
int i; // Looping var
|
||||
struct tm dateval; // Date value
|
||||
int offset; // Date offset
|
||||
|
||||
for (i = 3; i < 17; i ++)
|
||||
{
|
||||
if (!isdigit(token[i] & 255))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= 17)
|
||||
{
|
||||
if (token[i] == 'Z')
|
||||
{
|
||||
i ++;
|
||||
}
|
||||
else if (token[i] == '-' || token[i] == '+')
|
||||
{
|
||||
if (isdigit(token[i + 1] & 255) && isdigit(token[i + 2] & 255) && token[i + 3] == '\'' && isdigit(token[i + 4] & 255) && isdigit(token[i + 5] & 255))
|
||||
{
|
||||
i += 6;
|
||||
if (token[i] == '\'')
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (token[i])
|
||||
{
|
||||
// Just a string...
|
||||
v->type = PDFIO_VALTYPE_STRING;
|
||||
v->value.string = pdfioStringCreate(pdf, token + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Date value...
|
||||
memset(&dateval, 0, sizeof(dateval));
|
||||
|
||||
dateval.tm_year = (token[3] - '0') * 1000 + (token[4] - '0') * 100 + (token[5] - '0') * 10 + token[6] - '0' - 1900;
|
||||
dateval.tm_mon = (token[7] - '0') * 10 + token[8] - '0' - 1;
|
||||
dateval.tm_mday = (token[9] - '0') * 10 + token[10] - '0';
|
||||
dateval.tm_hour = (token[11] - '0') * 10 + token[12] - '0';
|
||||
dateval.tm_min = (token[13] - '0') * 10 + token[14] - '0';
|
||||
dateval.tm_sec = (token[15] - '0') * 10 + token[16] - '0';
|
||||
|
||||
if (token[17] == 'Z')
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = (token[18] - '0') * 600 + (token[19] - '0') * 60 + (token[20] - '0') * 10 + token[21] - '0';
|
||||
if (token[17] == '-')
|
||||
offset = -offset;
|
||||
}
|
||||
|
||||
v->type = PDFIO_VALTYPE_DATE;
|
||||
v->value.date = mktime(&dateval) + offset;
|
||||
}
|
||||
v->type = PDFIO_VALTYPE_DATE;
|
||||
v->value.date = timeval;
|
||||
}
|
||||
else if (token[0] == '(')
|
||||
{
|
||||
@ -367,33 +406,6 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
*dataptr++ = (unsigned char)d;
|
||||
}
|
||||
|
||||
if (obj && pdf->encryption)
|
||||
{
|
||||
// Decrypt the string...
|
||||
_pdfio_crypto_ctx_t ctx; // Decryption context
|
||||
_pdfio_crypto_cb_t cb; // Decryption callback
|
||||
size_t ivlen; // Number of initialization vector bytes
|
||||
uint8_t temp[32768]; // Temporary buffer for decryption
|
||||
size_t templen; // Number of actual data bytes
|
||||
|
||||
if (v->value.binary.datalen > (sizeof(temp) - 32))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted binary string - too long.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &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...
|
||||
memcpy(v->value.binary.data, temp, templen);
|
||||
|
||||
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128)
|
||||
v->value.binary.datalen = templen - temp[templen - 1];
|
||||
else
|
||||
v->value.binary.datalen = templen;
|
||||
}
|
||||
}
|
||||
else if (strchr("0123456789-+.", token[0]) != NULL)
|
||||
{
|
||||
@ -488,7 +500,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
// If we get here, we have a number...
|
||||
v->type = PDFIO_VALTYPE_NUMBER;
|
||||
v->value.number = (double)strtod(token, NULL);
|
||||
v->value.number = _pdfio_strtod(pdf, token);
|
||||
}
|
||||
else if (!strcmp(token, "true") || !strcmp(token, "false"))
|
||||
{
|
||||
@ -729,3 +741,85 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'get_date_time()' - Convert PDF date/time value to time_t.
|
||||
//
|
||||
|
||||
static time_t // O - Time in seconds
|
||||
get_date_time(const char *s) // I - PDF date/time value
|
||||
{
|
||||
int i; // Looping var
|
||||
struct tm dateval; // Date value
|
||||
int offset; // Date offset
|
||||
|
||||
|
||||
PDFIO_DEBUG("get_date_time(s=\"%s\")\n", s);
|
||||
|
||||
// Possible date value of the form:
|
||||
//
|
||||
// (D:YYYYMMDDhhmmssZ)
|
||||
// (D:YYYYMMDDhhmmss+HH'mm)
|
||||
// (D:YYYYMMDDhhmmss-HH'mm)
|
||||
//
|
||||
|
||||
for (i = 2; i < 16; i ++)
|
||||
{
|
||||
if (!isdigit(s[i] & 255) || !s[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= 16)
|
||||
{
|
||||
if (s[i] == 'Z')
|
||||
{
|
||||
// UTC...
|
||||
i ++;
|
||||
}
|
||||
else if (s[i] == '-' || s[i] == '+')
|
||||
{
|
||||
// Timezone offset from UTC...
|
||||
if (isdigit(s[i + 1] & 255) && isdigit(s[i + 2] & 255) && s[i + 3] == '\'' && isdigit(s[i + 4] & 255) && isdigit(s[i + 5] & 255))
|
||||
{
|
||||
i += 6;
|
||||
if (s[i] == '\'')
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
else if (!s[i])
|
||||
{
|
||||
// Missing zone info, invalid date string...
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (s[i])
|
||||
{
|
||||
// Just a string...
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Date value...
|
||||
memset(&dateval, 0, sizeof(dateval));
|
||||
|
||||
dateval.tm_year = (s[2] - '0') * 1000 + (s[3] - '0') * 100 + (s[4] - '0') * 10 + s[5] - '0' - 1900;
|
||||
dateval.tm_mon = (s[6] - '0') * 10 + s[7] - '0' - 1;
|
||||
dateval.tm_mday = (s[8] - '0') * 10 + s[9] - '0';
|
||||
dateval.tm_hour = (s[10] - '0') * 10 + s[11] - '0';
|
||||
dateval.tm_min = (s[12] - '0') * 10 + s[13] - '0';
|
||||
dateval.tm_sec = (s[14] - '0') * 10 + s[15] - '0';
|
||||
|
||||
if (s[16] == 'Z')
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = (s[17] - '0') * 600 + (s[18] - '0') * 60 + (s[19] - '0') * 10 + s[20] - '0';
|
||||
if (s[16] == '-')
|
||||
offset = -offset;
|
||||
}
|
||||
|
||||
return (mktime(&dateval) + offset);
|
||||
}
|
||||
|
17
pdfio.h
17
pdfio.h
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Public header file for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -23,7 +23,7 @@ extern "C" {
|
||||
// Version number...
|
||||
//
|
||||
|
||||
# define PDFIO_VERSION "1.1.3"
|
||||
# define PDFIO_VERSION "1.4.0"
|
||||
|
||||
|
||||
//
|
||||
@ -33,9 +33,11 @@ extern "C" {
|
||||
# if defined(__has_extension) || defined(__GNUC__)
|
||||
# define _PDFIO_PUBLIC __attribute__ ((visibility("default")))
|
||||
# define _PDFIO_FORMAT(a,b) __attribute__ ((__format__(__printf__, a,b)))
|
||||
# define _PDFIO_DEPRECATED __attribute__ ((deprecated)) _PDFIO_PUBLIC
|
||||
# else
|
||||
# define _PDFIO_PUBLIC
|
||||
# define _PDFIO_FORMAT(a,b)
|
||||
# define _PDFIO_DEPRECATED
|
||||
# endif // __has_extension || __GNUC__
|
||||
|
||||
|
||||
@ -63,7 +65,7 @@ typedef enum pdfio_encryption_e // PDF encryption modes
|
||||
PDFIO_ENCRYPTION_RC4_40, // 40-bit RC4 encryption (PDF 1.3)
|
||||
PDFIO_ENCRYPTION_RC4_128, // 128-bit RC4 encryption (PDF 1.4)
|
||||
PDFIO_ENCRYPTION_AES_128, // 128-bit AES encryption (PDF 1.6)
|
||||
PDFIO_ENCRYPTION_AES_256 // 256-bit AES encryption (PDF 2.0)
|
||||
PDFIO_ENCRYPTION_AES_256 // 256-bit AES encryption (PDF 2.0) @exclude all@
|
||||
} pdfio_encryption_t;
|
||||
typedef enum pdfio_filter_e // Compression/decompression filters for streams
|
||||
{
|
||||
@ -149,7 +151,9 @@ extern pdfio_obj_t *pdfioArrayGetObj(pdfio_array_t *a, size_t n) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioArrayGetSize(pdfio_array_t *a) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioArrayGetString(pdfio_array_t *a, size_t n) _PDFIO_PUBLIC;
|
||||
extern pdfio_valtype_t pdfioArrayGetType(pdfio_array_t *a, size_t n) _PDFIO_PUBLIC;
|
||||
extern bool pdfioArrayRemove(pdfio_array_t *a, size_t n) _PDFIO_PUBLIC;
|
||||
|
||||
extern bool pdfioDictClear(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern pdfio_dict_t *pdfioDictCopy(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
||||
extern pdfio_dict_t *pdfioDictCreate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_array_t *pdfioDictGetArray(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
@ -157,7 +161,9 @@ extern unsigned char *pdfioDictGetBinary(pdfio_dict_t *dict, const char *key, si
|
||||
extern bool pdfioDictGetBoolean(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern time_t pdfioDictGetDate(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern pdfio_dict_t *pdfioDictGetDict(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioDictGetKey(pdfio_dict_t *dict, size_t n) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioDictGetName(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioDictGetNumPairs(pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
||||
extern double pdfioDictGetNumber(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioDictGetObj(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern pdfio_rect_t *pdfioDictGetRect(pdfio_dict_t *dict, const char *key, pdfio_rect_t *rect) _PDFIO_PUBLIC;
|
||||
@ -180,13 +186,17 @@ extern bool pdfioDictSetStringf(pdfio_dict_t *dict, const char *key, const char
|
||||
extern bool pdfioFileClose(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_file_t *pdfioFileCreate(const char *filename, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateArrayObj(pdfio_file_t *pdf, pdfio_array_t *array) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateNameObj(pdfio_file_t *pdf, const char *name) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateNumberObj(pdfio_file_t *pdf, double number) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
||||
extern pdfio_file_t *pdfioFileCreateOutput(pdfio_output_cb_t output_cb, void *output_ctx, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||
// 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_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_obj_t *pdfioFileFindObj(pdfio_file_t *pdf, size_t number) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetAuthor(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_dict_t *pdfioFileGetCatalog(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern time_t pdfioFileGetCreationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetCreator(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_array_t *pdfioFileGetID(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
@ -217,6 +227,7 @@ extern pdfio_array_t *pdfioObjGetArray(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern pdfio_dict_t *pdfioObjGetDict(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern unsigned short pdfioObjGetGeneration(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioObjGetLength(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioObjGetName(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioObjGetNumber(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioObjGetSubtype(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioObjGetType(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
|
13
pdfio.pc.in
13
pdfio.pc.in
@ -1,6 +1,13 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: pdfio
|
||||
Description: PDF read/write library
|
||||
Version: @PDFIO_VERSION@
|
||||
URL: https://www.msweet.org/pdfio
|
||||
Requires: zlib >= 1.0
|
||||
Libs: -L${prefix}/lib -lpdfio -lm
|
||||
Cflags: -I${prefix}/include
|
||||
Requires: @PKGCONFIG_REQUIRES@
|
||||
Libs: @PKGCONFIG_LIBS@
|
||||
Libs.private: @PKGCONFIG_LIBS_PRIVATE@
|
||||
Cflags: @PKGCONFIG_CFLAGS@
|
||||
|
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@ -31,6 +31,7 @@
|
||||
27F2F0612710BE92008ECD36 /* pdfio-rc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 27F2F05E2710BE92008ECD36 /* pdfio-rc4.c */; };
|
||||
27F2F0622710BE92008ECD36 /* pdfio-crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 27F2F05F2710BE92008ECD36 /* pdfio-crypto.c */; };
|
||||
27F2F0642711243D008ECD36 /* pdfio-sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = 27F2F0632711243D008ECD36 /* pdfio-sha256.c */; };
|
||||
27FCBDE42D19F9B300485EEE /* pdfio-base-font-widths.h in Headers */ = {isa = PBXBuildFile; fileRef = 27FCBDE32D19F9B300485EEE /* pdfio-base-font-widths.h */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -89,6 +90,7 @@
|
||||
27F2F05E2710BE92008ECD36 /* pdfio-rc4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-rc4.c"; sourceTree = "<group>"; };
|
||||
27F2F05F2710BE92008ECD36 /* pdfio-crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-crypto.c"; sourceTree = "<group>"; };
|
||||
27F2F0632711243D008ECD36 /* pdfio-sha256.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-sha256.c"; sourceTree = "<group>"; };
|
||||
27FCBDE32D19F9B300485EEE /* pdfio-base-font-widths.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "pdfio-base-font-widths.h"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -162,6 +164,7 @@
|
||||
children = (
|
||||
27CF90432711DFFE00E50FE4 /* pdfio-aes.c */,
|
||||
273440BA263D727800FBFD63 /* pdfio-array.c */,
|
||||
27FCBDE32D19F9B300485EEE /* pdfio-base-font-widths.h */,
|
||||
273440BB263D727800FBFD63 /* pdfio-common.c */,
|
||||
271EA703265B2B1000ACDD39 /* pdfio-content.c */,
|
||||
27F2F05F2710BE92008ECD36 /* pdfio-crypto.c */,
|
||||
@ -205,6 +208,7 @@
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
27FCBDE42D19F9B300485EEE /* pdfio-base-font-widths.h in Headers */,
|
||||
273440CC263D727800FBFD63 /* pdfio.h in Headers */,
|
||||
271EA706265B2B1000ACDD39 /* pdfio-content.h in Headers */,
|
||||
273440C3263D727800FBFD63 /* pdfio-private.h in Headers */,
|
||||
@ -256,7 +260,8 @@
|
||||
273440A8263D6FE200FBFD63 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1300;
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1600;
|
||||
TargetAttributes = {
|
||||
273440AF263D6FE200FBFD63 = {
|
||||
CreatedOnToolsVersion = 12.5;
|
||||
@ -373,9 +378,11 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.1.2;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@ -450,15 +457,15 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.1.2;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
@ -486,6 +493,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RU58A2256H;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -497,6 +505,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RU58A2256H;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -509,6 +518,7 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
@ -525,6 +535,7 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
|
23
pdfio1.def
23
pdfio1.def
@ -1,7 +1,8 @@
|
||||
LIBRARY pdfio1
|
||||
VERSION 1.0
|
||||
VERSION 1.4
|
||||
EXPORTS
|
||||
_pdfioArrayDebug
|
||||
_pdfioArrayDecrypt
|
||||
_pdfioArrayDelete
|
||||
_pdfioArrayGetValue
|
||||
_pdfioArrayRead
|
||||
@ -22,8 +23,8 @@ _pdfioCryptoSHA256Append
|
||||
_pdfioCryptoSHA256Finish
|
||||
_pdfioCryptoSHA256Init
|
||||
_pdfioCryptoUnlock
|
||||
_pdfioDictClear
|
||||
_pdfioDictDebug
|
||||
_pdfioDictDecrypt
|
||||
_pdfioDictDelete
|
||||
_pdfioDictGetValue
|
||||
_pdfioDictRead
|
||||
@ -47,7 +48,9 @@ _pdfioFileSeek
|
||||
_pdfioFileTell
|
||||
_pdfioFileWrite
|
||||
_pdfioObjDelete
|
||||
_pdfioObjGetExtension
|
||||
_pdfioObjLoad
|
||||
_pdfioObjSetExtension
|
||||
_pdfioStreamCreate
|
||||
_pdfioStreamOpen
|
||||
_pdfioStringIsAllocated
|
||||
@ -59,9 +62,12 @@ _pdfioTokenPush
|
||||
_pdfioTokenRead
|
||||
_pdfioValueCopy
|
||||
_pdfioValueDebug
|
||||
_pdfioValueDecrypt
|
||||
_pdfioValueDelete
|
||||
_pdfioValueRead
|
||||
_pdfioValueWrite
|
||||
_pdfio_strtod
|
||||
_pdfio_vsnprintf
|
||||
pdfioArrayAppendArray
|
||||
pdfioArrayAppendBinary
|
||||
pdfioArrayAppendBoolean
|
||||
@ -89,6 +95,7 @@ pdfioArrayGetObj
|
||||
pdfioArrayGetSize
|
||||
pdfioArrayGetString
|
||||
pdfioArrayGetType
|
||||
pdfioArrayRemove
|
||||
pdfioContentClip
|
||||
pdfioContentDrawImage
|
||||
pdfioContentFill
|
||||
@ -136,12 +143,17 @@ pdfioContentSetTextXScaling
|
||||
pdfioContentStroke
|
||||
pdfioContentTextBegin
|
||||
pdfioContentTextEnd
|
||||
pdfioContentTextMeasure
|
||||
pdfioContentTextMoveLine
|
||||
pdfioContentTextMoveTo
|
||||
pdfioContentTextNewLine
|
||||
pdfioContentTextNewLineShow
|
||||
pdfioContentTextNewLineShowf
|
||||
pdfioContentTextNextLine
|
||||
pdfioContentTextShow
|
||||
pdfioContentTextShowJustified
|
||||
pdfioContentTextShowf
|
||||
pdfioDictClear
|
||||
pdfioDictCopy
|
||||
pdfioDictCreate
|
||||
pdfioDictGetArray
|
||||
@ -149,7 +161,9 @@ pdfioDictGetBinary
|
||||
pdfioDictGetBoolean
|
||||
pdfioDictGetDate
|
||||
pdfioDictGetDict
|
||||
pdfioDictGetKey
|
||||
pdfioDictGetName
|
||||
pdfioDictGetNumPairs
|
||||
pdfioDictGetNumber
|
||||
pdfioDictGetObj
|
||||
pdfioDictGetRect
|
||||
@ -176,12 +190,16 @@ pdfioFileCreateFontObjFromFile
|
||||
pdfioFileCreateICCObjFromFile
|
||||
pdfioFileCreateImageObjFromData
|
||||
pdfioFileCreateImageObjFromFile
|
||||
pdfioFileCreateNameObj
|
||||
pdfioFileCreateNumberObj
|
||||
pdfioFileCreateObj
|
||||
pdfioFileCreateOutput
|
||||
pdfioFileCreatePage
|
||||
pdfioFileCreateStringObj
|
||||
pdfioFileCreateTemporary
|
||||
pdfioFileFindObj
|
||||
pdfioFileGetAuthor
|
||||
pdfioFileGetCatalog
|
||||
pdfioFileGetCreationDate
|
||||
pdfioFileGetCreator
|
||||
pdfioFileGetID
|
||||
@ -214,6 +232,7 @@ pdfioObjGetArray
|
||||
pdfioObjGetDict
|
||||
pdfioObjGetGeneration
|
||||
pdfioObjGetLength
|
||||
pdfioObjGetName
|
||||
pdfioObjGetNumber
|
||||
pdfioObjGetSubtype
|
||||
pdfioObjGetType
|
||||
|
@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.1.3</version>
|
||||
<version>1.4.0</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
@ -13,10 +13,10 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>PDFio Library for VS2019+</description>
|
||||
<summary>PDFio is a simple C library for reading and writing PDF files. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
||||
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
||||
<copyright>Copyright © 2019-2024 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
<dependencies>
|
||||
<dependency id="pdfio_native.redist" version="1.1.3" />
|
||||
<dependency id="pdfio_native.redist" version="1.4.0" />
|
||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native.redist</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.1.3</version>
|
||||
<version>1.4.0</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
@ -13,7 +13,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>PDFio Library for VS2019+</description>
|
||||
<summary>PDFio is a simple C library for reading and writing PDF files. This package provides the redistributable content for the PDFio library. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
||||
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
||||
<copyright>Copyright © 2019-2024 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
<dependencies>
|
||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||
|
16
runtests.bat
Normal file
16
runtests.bat
Normal file
@ -0,0 +1,16 @@
|
||||
:: Script to run unit test program
|
||||
::
|
||||
:: Usage:
|
||||
::
|
||||
:: .\runtests.bat x64\{Debug|Release}
|
||||
::
|
||||
|
||||
:: Copy dependent DLLs to the named build directory
|
||||
echo Copying DLLs
|
||||
copy packages\zlib_native.redist.1.2.11\build\native\bin\x64\Debug\*.dll %1
|
||||
copy packages\zlib_native.redist.1.2.11\build\native\bin\x64\Release\*.dll %1
|
||||
|
||||
:: Run unit test program
|
||||
echo Running %1\testpdfio.exe
|
||||
cd %1
|
||||
testpdfio.exe
|
257
testpdfio.c
257
testpdfio.c
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Test program for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -10,16 +10,13 @@
|
||||
//
|
||||
// ./testpdfio
|
||||
//
|
||||
// ./testpdfio FILENAME [OBJECT-NUMBER] [FILENAME [OBJECT-NUMBER]] ...
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
// ./testpdfio [--verbose] FILENAME [OBJECT-NUMBER] [FILENAME [OBJECT-NUMBER]] ...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
#include "pdfio-content.h"
|
||||
#include <math.h>
|
||||
#include <locale.h>
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846264338327950288
|
||||
#endif // M_PI
|
||||
@ -30,7 +27,7 @@
|
||||
//
|
||||
|
||||
static int do_crypto_tests(void);
|
||||
static int do_test_file(const char *filename, int objnum, bool verbose);
|
||||
static int do_test_file(const char *filename, int objnum, const char *password, bool verbose);
|
||||
static int do_unit_tests(void);
|
||||
static int draw_image(pdfio_stream_t *st, const char *name, double x, double y, double w, double h, const char *label);
|
||||
static bool error_cb(pdfio_file_t *pdf, const char *message, bool *error);
|
||||
@ -40,18 +37,19 @@ static const char *password_cb(void *data, const char *filename);
|
||||
static int read_unit_file(const char *filename, size_t num_pages, size_t first_image, bool is_output);
|
||||
static ssize_t token_consume_cb(const char **s, size_t bytes);
|
||||
static ssize_t token_peek_cb(const char **s, char *buffer, size_t bytes);
|
||||
static int usage(FILE *fp);
|
||||
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_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_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 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_jpeg_test(pdfio_file_t *pdf, const char *title, int number, pdfio_obj_t *font, pdfio_obj_t *image);
|
||||
static int write_png_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
||||
static int write_text_test(pdfio_file_t *pdf, int first_page, pdfio_obj_t *font, const char *filename);
|
||||
static int write_unit_file(pdfio_file_t *inpdf, pdfio_file_t *outpdf, size_t *num_pages, size_t *first_image);
|
||||
static int write_unit_file(pdfio_file_t *inpdf, const char *outname, pdfio_file_t *outpdf, size_t *num_pages, size_t *first_image);
|
||||
|
||||
|
||||
//
|
||||
@ -62,20 +60,33 @@ int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // I - Command-line arguments
|
||||
{
|
||||
int ret = 0; // Return value
|
||||
int ret = 0; // Return value
|
||||
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
int i; // Looping var
|
||||
const char *password = NULL; // Password
|
||||
bool verbose = false; // Be verbose?
|
||||
|
||||
for (i = 1; i < argc; i ++)
|
||||
{
|
||||
if (!strcmp(argv[i], "--help"))
|
||||
{
|
||||
puts("Usage: ./testpdfio [--help] [--verbose] [filename [objnum] ...]");
|
||||
return (0);
|
||||
return (usage(stdout));
|
||||
}
|
||||
else if (!strcmp(argv[i], "--password"))
|
||||
{
|
||||
i ++;
|
||||
if (i < argc)
|
||||
{
|
||||
password = argv[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
fputs("testpdfio: Missing password after '--password'.\n", stderr);
|
||||
return (usage(stderr));
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[i], "--verbose"))
|
||||
{
|
||||
@ -83,24 +94,27 @@ main(int argc, // I - Number of command-line arguments
|
||||
}
|
||||
else if (argv[i][0] == '-')
|
||||
{
|
||||
printf("Unknown option '%s'.\n\n", argv[i]);
|
||||
puts("Usage: ./testpdfio [--help] [--verbose] [filename [objnum] ...]");
|
||||
return (1);
|
||||
fprintf(stderr, "testpdfio: Unknown option '%s'.\n", argv[i]);
|
||||
return (usage(stderr));
|
||||
}
|
||||
else if ((i + 1) < argc && isdigit(argv[i + 1][0] & 255))
|
||||
{
|
||||
// filename.pdf object-number
|
||||
if (do_test_file(argv[i], atoi(argv[i + 1]), verbose))
|
||||
if (do_test_file(argv[i], atoi(argv[i + 1]), password, verbose))
|
||||
ret = 1;
|
||||
|
||||
i ++;
|
||||
}
|
||||
else if (do_test_file(argv[i], 0, verbose))
|
||||
else if (do_test_file(argv[i], 0, password, verbose))
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "testpdfio: Test locale is \"%s\".\n", setlocale(LC_ALL, getenv("LANG")));
|
||||
|
||||
#if _WIN32
|
||||
// Windows puts executables in Platform/Configuration subdirs...
|
||||
if (!_access("../../testfiles", 0))
|
||||
@ -364,6 +378,7 @@ do_crypto_tests(void)
|
||||
static int // O - Exit status
|
||||
do_test_file(const char *filename, // I - PDF filename
|
||||
int objnum, // I - Object number to dump, if any
|
||||
const char *password, // I - Password for file
|
||||
bool verbose) // I - Be verbose?
|
||||
{
|
||||
bool error = false; // Have we shown an error yet?
|
||||
@ -382,7 +397,7 @@ do_test_file(const char *filename, // I - PDF filename
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if ((pdf = pdfioFileOpen(filename, /*password_cb*/NULL, /*password_data*/NULL, (pdfio_error_cb_t)error_cb, &error)) != NULL)
|
||||
if ((pdf = pdfioFileOpen(filename, password_cb, (void *)password, (pdfio_error_cb_t)error_cb, &error)) != NULL)
|
||||
{
|
||||
if (objnum)
|
||||
{
|
||||
@ -1045,7 +1060,7 @@ do_unit_tests(void)
|
||||
else
|
||||
goto fail;
|
||||
|
||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
||||
if (write_unit_file(inpdf, "testpdfio-out.pdf", outpdf, &num_pages, &first_image))
|
||||
goto fail;
|
||||
|
||||
if (read_unit_file("testpdfio-out.pdf", num_pages, first_image, false))
|
||||
@ -1064,7 +1079,7 @@ do_unit_tests(void)
|
||||
else
|
||||
goto fail;
|
||||
|
||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
||||
if (write_unit_file(inpdf, "testpdfio-out2.pdf", outpdf, &num_pages, &first_image))
|
||||
goto fail;
|
||||
|
||||
close(outfd);
|
||||
@ -1085,7 +1100,7 @@ do_unit_tests(void)
|
||||
else
|
||||
return (1);
|
||||
|
||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
||||
if (write_unit_file(inpdf, "testpdfio-rc4.pdf", outpdf, &num_pages, &first_image))
|
||||
return (1);
|
||||
|
||||
if (read_unit_file("testpdfio-rc4.pdf", num_pages, first_image, false))
|
||||
@ -1104,7 +1119,7 @@ do_unit_tests(void)
|
||||
else
|
||||
return (1);
|
||||
|
||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
||||
if (write_unit_file(inpdf, "testpdfio-rc4p.pdf", outpdf, &num_pages, &first_image))
|
||||
return (1);
|
||||
|
||||
if (read_unit_file("testpdfio-rc4p.pdf", num_pages, first_image, false))
|
||||
@ -1122,7 +1137,7 @@ do_unit_tests(void)
|
||||
else
|
||||
return (1);
|
||||
|
||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
||||
if (write_unit_file(inpdf, "testpdfio-aes.pdf", outpdf, &num_pages, &first_image))
|
||||
return (1);
|
||||
|
||||
if (read_unit_file("testpdfio-aes.pdf", num_pages, first_image, false))
|
||||
@ -1140,7 +1155,7 @@ do_unit_tests(void)
|
||||
else
|
||||
return (1);
|
||||
|
||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
||||
if (write_unit_file(inpdf, "testpdfio-aesp.pdf", outpdf, &num_pages, &first_image))
|
||||
return (1);
|
||||
|
||||
if (read_unit_file("testpdfio-aesp.pdf", num_pages, first_image, false))
|
||||
@ -1152,7 +1167,7 @@ do_unit_tests(void)
|
||||
else
|
||||
return (1);
|
||||
|
||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
||||
if (write_unit_file(inpdf, "<temporary>", outpdf, &num_pages, &first_image))
|
||||
return (1);
|
||||
|
||||
if (read_unit_file(temppdf, num_pages, first_image, false))
|
||||
@ -1309,6 +1324,7 @@ read_unit_file(const char *filename, // I - File to read
|
||||
bool is_output) // I - File written with output callback?
|
||||
{
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
pdfio_dict_t *catalog; // Catalog dictionary
|
||||
size_t i; // Looping var
|
||||
const char *s; // String
|
||||
bool error = false; // Error callback data
|
||||
@ -1321,6 +1337,83 @@ read_unit_file(const char *filename, // I - File to read
|
||||
else
|
||||
return (1);
|
||||
|
||||
// Get the root object/catalog dictionary
|
||||
fputs("pdfioFileGetCatalog: ", stdout);
|
||||
if ((catalog = pdfioFileGetCatalog(pdf)) != NULL)
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL (got NULL, expected dictionary)");
|
||||
return (1);
|
||||
}
|
||||
|
||||
// Verify some catalog values...
|
||||
fputs("pdfioDictGetName(PageLayout): ", stdout);
|
||||
if ((s = pdfioDictGetName(catalog, "PageLayout")) != NULL && !strcmp(s, "SinglePage"))
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else if (s)
|
||||
{
|
||||
printf("FAIL (got '%s', expected 'SinglePage')\n", s);
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL (got NULL, expected 'SinglePage')");
|
||||
return (1);
|
||||
}
|
||||
|
||||
fputs("pdfioDictGetName(PageLayout): ", stdout);
|
||||
if ((s = pdfioDictGetName(catalog, "PageLayout")) != NULL && !strcmp(s, "SinglePage"))
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else if (s)
|
||||
{
|
||||
printf("FAIL (got '%s', expected 'SinglePage')\n", s);
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL (got NULL, expected 'SinglePage')");
|
||||
return (1);
|
||||
}
|
||||
|
||||
fputs("pdfioDictGetName(PageMode): ", stdout);
|
||||
if ((s = pdfioDictGetName(catalog, "PageMode")) != NULL && !strcmp(s, "UseThumbs"))
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else if (s)
|
||||
{
|
||||
printf("FAIL (got '%s', expected 'UseThumbs')\n", s);
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL (got NULL, expected 'UseThumbs')");
|
||||
return (1);
|
||||
}
|
||||
|
||||
fputs("pdfioDictGetString(Lang): ", stdout);
|
||||
if ((s = pdfioDictGetString(catalog, "Lang")) != NULL && !strcmp(s, "en"))
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else if (s)
|
||||
{
|
||||
printf("FAIL (got '%s', expected 'en')\n", s);
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL (got NULL, expected 'en')");
|
||||
return (1);
|
||||
}
|
||||
|
||||
// Verify metadata...
|
||||
fputs("pdfioFileGetAuthor: ", stdout);
|
||||
if ((s = pdfioFileGetAuthor(pdf)) != NULL && !strcmp(s, "Michael R Sweet"))
|
||||
@ -1482,6 +1575,23 @@ token_peek_cb(const char **s, // IO - Test string
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'usage()' - Show program usage.
|
||||
//
|
||||
|
||||
static int // O - Exit status
|
||||
usage(FILE *fp) // I - Output file
|
||||
{
|
||||
fputs("Usage: ./testpdfio [OPTIONS] [FILENAME [OBJNUM]] ...\n", fp);
|
||||
fputs("Options:\n", fp);
|
||||
fputs(" --help Show program help.\n", fp);
|
||||
fputs(" --password PASSWORD Set PDF password.\n", fp);
|
||||
fputs(" --verbose Be verbose.\n", fp);
|
||||
|
||||
return (fp != stdout);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'verify_image()' - Verify an image object.
|
||||
//
|
||||
@ -2229,14 +2339,20 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
|
||||
//
|
||||
|
||||
static int // O - 1 on failure, 0 on success
|
||||
write_font_test(pdfio_file_t *pdf, // I - PDF file
|
||||
int number, // I - Page number
|
||||
pdfio_obj_t *font, // I - Page number font
|
||||
bool unicode) // I - Use Unicode font?
|
||||
write_font_test(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
int number, // I - Page number
|
||||
pdfio_obj_t *font, // I - Page number font
|
||||
const char *textfontfile, // I - Text font file
|
||||
bool unicode) // I - Use Unicode font?
|
||||
{
|
||||
pdfio_dict_t *dict; // Page dictionary
|
||||
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
|
||||
static const char * const welcomes[] =// "Welcome" in many languages
|
||||
{
|
||||
@ -2387,12 +2503,13 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
|
||||
"Märr-ŋamathirri",
|
||||
"Ẹ ku abọ",
|
||||
"Kíimak 'oolal",
|
||||
"Ngiyakwemukela"
|
||||
"Ngiyakwemukela",
|
||||
"いらっしゃいませ"
|
||||
};
|
||||
|
||||
|
||||
fputs("pdfioFileCreateFontObjFromFile(OpenSans-Regular.ttf): ", stdout);
|
||||
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/OpenSans-Regular.ttf", unicode)) != NULL)
|
||||
printf("pdfioFileCreateFontObjFromFile(%s): ", textfontfile);
|
||||
if ((textfont = pdfioFileCreateFontObjFromFile(pdf, textfontfile, unicode)) != NULL)
|
||||
puts("PASS");
|
||||
else
|
||||
return (1);
|
||||
@ -2410,7 +2527,7 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
|
||||
return (1);
|
||||
|
||||
fputs("pdfioPageDictAddFont(F2): ", stdout);
|
||||
if (pdfioPageDictAddFont(dict, "F2", opensans))
|
||||
if (pdfioPageDictAddFont(dict, "F2", textfont))
|
||||
puts("PASS");
|
||||
else
|
||||
return (1);
|
||||
@ -2422,7 +2539,21 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
|
||||
else
|
||||
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;
|
||||
|
||||
fputs("pdfioContentTextBegin(): ", stdout);
|
||||
@ -2443,8 +2574,8 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
|
||||
else
|
||||
goto error;
|
||||
|
||||
fputs("pdfioContentTextMoveTo(36.0, 702.0): ", stdout);
|
||||
if (pdfioContentTextMoveTo(st, 36.0, 702.0))
|
||||
fputs("pdfioContentTextMoveTo(198.0, 702.0): ", stdout);
|
||||
if (pdfioContentTextMoveTo(st, 198.0, 702.0))
|
||||
puts("PASS");
|
||||
else
|
||||
return (1);
|
||||
@ -2453,18 +2584,36 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
|
||||
{
|
||||
if (i > 0 && (i % 50) == 0)
|
||||
{
|
||||
fputs("pdfioContentTextMoveTo(200.0, 600.0): ", stdout);
|
||||
if (pdfioContentTextMoveTo(st, 200.0, 600.0))
|
||||
fputs("pdfioContentTextMoveTo(162.0, 600.0): ", stdout);
|
||||
if (pdfioContentTextMoveTo(st, 162.0, 600.0))
|
||||
puts("PASS");
|
||||
else
|
||||
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]);
|
||||
if (pdfioContentTextShowf(st, unicode, "%s\n", welcomes[i]))
|
||||
puts("PASS");
|
||||
else
|
||||
return (1);
|
||||
|
||||
printf("pdfioContextTextMoveTo(%g, 0.0): ", width);
|
||||
if (pdfioContentTextMoveTo(st, width, 0.0))
|
||||
puts("PASS");
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
fputs("pdfioContentTextEnd(): ", stdout);
|
||||
@ -3208,6 +3357,7 @@ write_text_test(pdfio_file_t *pdf, // I - PDF file
|
||||
static int // O - Exit status
|
||||
write_unit_file(
|
||||
pdfio_file_t *inpdf, // I - Input PDF file
|
||||
const char *outname, // I - Output PDF file name
|
||||
pdfio_file_t *outpdf, // I - Output PDF file
|
||||
size_t *num_pages, // O - Number of pages
|
||||
size_t *first_image) // O - First image object
|
||||
@ -3217,8 +3367,26 @@ write_unit_file(
|
||||
*gray_jpg, // gray.jpg image
|
||||
*helvetica, // Helvetica font
|
||||
*page; // Page from test PDF file
|
||||
pdfio_dict_t *catalog; // Catalog dictionary
|
||||
|
||||
|
||||
// Get the root object/catalog dictionary
|
||||
fputs("pdfioFileGetCatalog: ", stdout);
|
||||
if ((catalog = pdfioFileGetCatalog(outpdf)) != NULL)
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL (got NULL, expected dictionary)");
|
||||
return (1);
|
||||
}
|
||||
|
||||
// Set some catalog values...
|
||||
pdfioDictSetName(catalog, "PageLayout", "SinglePage");
|
||||
pdfioDictSetName(catalog, "PageMode", "UseThumbs");
|
||||
pdfioDictSetString(catalog, "Lang", "en");
|
||||
|
||||
// Set info values...
|
||||
fputs("pdfioFileGet/SetAuthor: ", stdout);
|
||||
pdfioFileSetAuthor(outpdf, "Michael R Sweet");
|
||||
@ -3377,14 +3545,17 @@ write_unit_file(
|
||||
return (1);
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
// Print this text file...
|
||||
if (write_text_test(outpdf, 11, helvetica, "README.md"))
|
||||
if (write_text_test(outpdf, 12, helvetica, "README.md"))
|
||||
return (1);
|
||||
|
||||
fputs("pdfioFileGetNumPages: ", stdout);
|
||||
@ -3399,7 +3570,7 @@ write_unit_file(
|
||||
}
|
||||
|
||||
// Close the new PDF file...
|
||||
fputs("pdfioFileClose(...): ", stdout);
|
||||
printf("pdfioFileClose(\"%s\"): ", outname);
|
||||
if (pdfioFileClose(outpdf))
|
||||
puts("PASS");
|
||||
else
|
||||
|
@ -3,7 +3,7 @@
|
||||
//
|
||||
// https://github.com/michaelrsweet/ttf
|
||||
//
|
||||
// Copyright © 2018-2023 by Michael R Sweet.
|
||||
// Copyright © 2018-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -120,6 +120,7 @@ test_font(const char *filename) // I - Font filename
|
||||
|
||||
|
||||
printf("ttfCreate(\"%s\"): ", filename);
|
||||
fflush(stdout);
|
||||
if ((font = ttfCreate(filename, 0, error_cb, NULL)) != NULL)
|
||||
puts("PASS");
|
||||
else
|
||||
@ -165,8 +166,7 @@ test_font(const char *filename) // I - Font filename
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL");
|
||||
errors ++;
|
||||
puts("WARNING (no copyright found)");
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)(sizeof(strings) / sizeof(strings[0])); i ++)
|
||||
@ -195,7 +195,7 @@ test_font(const char *filename) // I - Font filename
|
||||
}
|
||||
|
||||
fputs("ttfGetItalicAngle: ", stdout);
|
||||
if ((realvalue = ttfGetItalicAngle(font)) >= 0.0)
|
||||
if ((realvalue = ttfGetItalicAngle(font)) >= -180.0 && realvalue <= 180.0)
|
||||
{
|
||||
printf("PASS (%g)\n", realvalue);
|
||||
}
|
||||
|
132
ttf.c
132
ttf.c
@ -3,7 +3,7 @@
|
||||
//
|
||||
// https://github.com/michaelrsweet/ttf
|
||||
//
|
||||
// Copyright © 2018-2023 by Michael R Sweet.
|
||||
// Copyright © 2018-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -62,7 +62,7 @@
|
||||
# define O_CREAT _O_CREAT
|
||||
# define O_TRUNC _O_TRUNC
|
||||
|
||||
typedef __int64 ssize_t; // POSIX type not present on Windows...
|
||||
typedef __int64 ssize_t; // POSIX type not present on Windows... @private@
|
||||
|
||||
#else
|
||||
# include <unistd.h>
|
||||
@ -99,6 +99,8 @@ typedef __int64 ssize_t; // POSIX type not present on Windows...
|
||||
//
|
||||
|
||||
#define TTF_FONT_MAX_CHAR 262144 // Maximum number of character values
|
||||
#define TTF_FONT_MAX_GROUPS 65536 // Maximum number of sub-groups
|
||||
#define TTF_FONT_MAX_NAMES 16777216// Maximum size of names table we support
|
||||
|
||||
|
||||
//
|
||||
@ -254,7 +256,7 @@ typedef struct _ttf_off_hhea_s // Horizontal header
|
||||
{
|
||||
short ascender, // Ascender
|
||||
descender; // Descender
|
||||
int numberOfHMetrics; // Number of horizontal metrics
|
||||
unsigned short numberOfHMetrics; // Number of horizontal metrics
|
||||
} _ttf_off_hhea_t;
|
||||
|
||||
typedef struct _ttf_off_os_2_s // OS/2 information
|
||||
@ -297,7 +299,28 @@ static unsigned seek_table(ttf_t *font, unsigned tag, unsigned offset, bool requ
|
||||
|
||||
|
||||
//
|
||||
// 'ttfCreate()' - Create a new font object for the named font family.
|
||||
// 'ttfCreate()' - Create a new font object for the named font file.
|
||||
//
|
||||
// This function creates a new font object for the named TrueType or OpenType
|
||||
// font file or collection. The "filename" argument specifies the name of the
|
||||
// file to read.
|
||||
//
|
||||
// The "idx" argument specifies the font to load from a collection - the first
|
||||
// font is number `0`. Once created, you can call the @link ttfGetNumFonts@
|
||||
// function to determine whether the loaded font file is a collection with more
|
||||
// than one font.
|
||||
//
|
||||
// The "err_cb" and "err_data" arguments specify a callback function and data
|
||||
// pointer for receiving error messages. If `NULL`, errors are sent to the
|
||||
// `stderr` file. The callback function receives the data pointer and a text
|
||||
// message string, for example:
|
||||
//
|
||||
// ```
|
||||
// void my_err_cb(void *err_data, const char *message)
|
||||
// {
|
||||
// fprintf(stderr, "ERROR: %s\n", message);
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
|
||||
ttf_t * // O - New font object
|
||||
@ -479,7 +502,7 @@ ttfCreate(const char *filename, // I - Filename
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (i >= ' ' && i < 127)
|
||||
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
|
||||
}
|
||||
@ -550,6 +573,10 @@ ttfGetAscent(ttf_t *font) // I - Font
|
||||
//
|
||||
// 'ttfGetBounds()' - Get the bounds of all characters in a font.
|
||||
//
|
||||
// This function gets the bounds of all characters in a font. The "bounds"
|
||||
// argument is a pointer to a `ttf_rect_t` structure that will be filled with
|
||||
// the limits for characters in the font scaled to a 1000x1000 unit square.
|
||||
//
|
||||
|
||||
ttf_rect_t * // O - Bounds or `NULL` on error
|
||||
ttfGetBounds(ttf_t *font, // I - Font
|
||||
@ -631,8 +658,11 @@ ttfGetDescent(ttf_t *font) // I - Font
|
||||
//
|
||||
// 'ttfGetExtents()' - Get the extents of a UTF-8 string.
|
||||
//
|
||||
// This function computes the extents of a UTF-8 string when rendered using the
|
||||
// specified font and size.
|
||||
// This function computes the extents of the UTF-8 string "s" when rendered
|
||||
// using the specified font "font" and size "size". The "extents" argument is
|
||||
// a pointer to a `ttf_rect_t` structure that is filled with the extents of a
|
||||
// simple rendering of the string with no kerning or rewriting applied. The
|
||||
// values are scaled using the specified font size.
|
||||
//
|
||||
|
||||
ttf_rect_t * // O - Pointer to extents or `NULL` on error
|
||||
@ -1272,20 +1302,38 @@ read_cmap(ttf_t *font) // I - Font
|
||||
for (i = 0; i < numGlyphIdArray; i ++)
|
||||
glyphIdArray[i] = read_ushort(font);
|
||||
|
||||
#ifdef DEBUG
|
||||
for (i = 0; i < segCount; i ++)
|
||||
TTF_DEBUG("read_cmap: segment[%d].startCode=%d, endCode=%d, idDelta=%d, idRangeOffset=%d\n", i, segments[i].startCode, segments[i].endCode, segments[i].idDelta, segments[i].idRangeOffset);
|
||||
for (i = 0, segment = segments; i < segCount; i ++, segment ++)
|
||||
{
|
||||
TTF_DEBUG("read_cmap: segment[%d].startCode=%d, endCode=%d, idDelta=%d, idRangeOffset=%d\n", i, segment->startCode, segment->endCode, segment->idDelta, segment->idRangeOffset);
|
||||
|
||||
if (segment->startCode > segment->endCode)
|
||||
{
|
||||
errorf(font, "Bad cmap table segment %u to %u.", segments->startCode, segment->endCode);
|
||||
free(segments);
|
||||
free(glyphIdArray);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Based on the end code of the segment table, allocate space for the
|
||||
// uncompressed cmap table...
|
||||
if (segment->endCode >= font->num_cmap)
|
||||
font->num_cmap = segment->endCode + 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (i = 0; i < numGlyphIdArray; i ++)
|
||||
TTF_DEBUG("read_cmap: glyphIdArray[%d]=%d\n", i, glyphIdArray[i]);
|
||||
#endif /* DEBUG */
|
||||
|
||||
// Based on the end code of the segent table, allocate space for the
|
||||
// uncompressed cmap table...
|
||||
segCount --; // Last segment is not used (sigh)
|
||||
if (font->num_cmap == 0 || font->num_cmap > TTF_FONT_MAX_CHAR)
|
||||
{
|
||||
errorf(font, "Invalid cmap table with %u characters.", (unsigned)font->num_cmap);
|
||||
free(segments);
|
||||
free(glyphIdArray);
|
||||
return (false);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
if (!font->cmap)
|
||||
{
|
||||
@ -1307,8 +1355,9 @@ read_cmap(ttf_t *font) // I - Font
|
||||
{
|
||||
// Use an "obscure indexing trick" (words from the spec, not
|
||||
// mine) to look up the glyph index...
|
||||
temp = segment->idRangeOffset / 2 + ch - segment->startCode + seg - segCount;
|
||||
temp = (int)(segment->idRangeOffset / 2 - segCount + (ch - segment->startCode) + (segment - segments));
|
||||
|
||||
TTF_DEBUG("read_cmap: ch=%d, temp=%d\n", ch, temp);
|
||||
if (temp < 0 || temp >= numGlyphIdArray)
|
||||
glyph = -1;
|
||||
else
|
||||
@ -1355,6 +1404,12 @@ read_cmap(ttf_t *font) // I - Font
|
||||
|
||||
TTF_DEBUG("read_cmap: nGroups=%u\n", nGroups);
|
||||
|
||||
if (nGroups > TTF_FONT_MAX_GROUPS)
|
||||
{
|
||||
errorf(font, "Invalid cmap table with %u groups.", nGroups);
|
||||
return (false);
|
||||
}
|
||||
|
||||
if ((groups = (_ttf_off_cmap12_t *)calloc(nGroups, sizeof(_ttf_off_cmap12_t))) == NULL)
|
||||
{
|
||||
errorf(font, "Unable to allocate memory for cmap.");
|
||||
@ -1368,6 +1423,13 @@ read_cmap(ttf_t *font) // I - Font
|
||||
group->startGlyphID = read_ulong(font);
|
||||
TTF_DEBUG("read_cmap: [%u] startCharCode=%u, endCharCode=%u, startGlyphID=%u\n", gidx, group->startCharCode, group->endCharCode, group->startGlyphID);
|
||||
|
||||
if (group->startCharCode > group->endCharCode)
|
||||
{
|
||||
errorf(font, "Bad cmap table segment %u to %u.", group->startCharCode, group->endCharCode);
|
||||
free(groups);
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (group->endCharCode >= font->num_cmap)
|
||||
font->num_cmap = group->endCharCode + 1;
|
||||
}
|
||||
@ -1375,6 +1437,14 @@ read_cmap(ttf_t *font) // I - Font
|
||||
// Based on the end code of the segent table, allocate space for the
|
||||
// uncompressed cmap table...
|
||||
TTF_DEBUG("read_cmap: num_cmap=%u\n", (unsigned)font->num_cmap);
|
||||
|
||||
if (font->num_cmap == 0 || font->num_cmap > TTF_FONT_MAX_CHAR)
|
||||
{
|
||||
errorf(font, "Invalid cmap table with %u characters.", (unsigned)font->num_cmap);
|
||||
free(groups);
|
||||
return (false);
|
||||
}
|
||||
|
||||
font->cmap = cmapptr = (int *)malloc(font->num_cmap * sizeof(int));
|
||||
|
||||
if (!font->cmap)
|
||||
@ -1425,6 +1495,12 @@ read_cmap(ttf_t *font) // I - Font
|
||||
|
||||
TTF_DEBUG("read_cmap: nGroups=%u\n", nGroups);
|
||||
|
||||
if (nGroups > TTF_FONT_MAX_GROUPS)
|
||||
{
|
||||
errorf(font, "Invalid cmap table with %u groups.", nGroups);
|
||||
return (false);
|
||||
}
|
||||
|
||||
if ((groups = (_ttf_off_cmap13_t *)calloc(nGroups, sizeof(_ttf_off_cmap13_t))) == NULL)
|
||||
{
|
||||
errorf(font, "Unable to allocate memory for cmap.");
|
||||
@ -1438,6 +1514,13 @@ read_cmap(ttf_t *font) // I - Font
|
||||
group->glyphID = read_ulong(font);
|
||||
TTF_DEBUG("read_cmap: [%u] startCharCode=%u, endCharCode=%u, glyphID=%u\n", gidx, group->startCharCode, group->endCharCode, group->glyphID);
|
||||
|
||||
if (group->startCharCode > group->endCharCode)
|
||||
{
|
||||
errorf(font, "Bad cmap table segment %u to %u.", group->startCharCode, group->endCharCode);
|
||||
free(groups);
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (group->endCharCode >= font->num_cmap)
|
||||
font->num_cmap = group->endCharCode + 1;
|
||||
}
|
||||
@ -1445,6 +1528,14 @@ read_cmap(ttf_t *font) // I - Font
|
||||
// Based on the end code of the segent table, allocate space for the
|
||||
// uncompressed cmap table...
|
||||
TTF_DEBUG("read_cmap: num_cmap=%u\n", (unsigned)font->num_cmap);
|
||||
|
||||
if (font->num_cmap == 0 || font->num_cmap > TTF_FONT_MAX_CHAR)
|
||||
{
|
||||
errorf(font, "Invalid cmap table with %u characters.", (unsigned)font->num_cmap);
|
||||
free(groups);
|
||||
return (false);
|
||||
}
|
||||
|
||||
font->cmap = cmapptr = (int *)malloc(font->num_cmap * sizeof(int));
|
||||
|
||||
if (!font->cmap)
|
||||
@ -1564,7 +1655,7 @@ read_hmtx(ttf_t *font, // I - Font
|
||||
_ttf_off_hhea_t *hhea) // O - hhea table data
|
||||
{
|
||||
unsigned length; // Length of hmtx table
|
||||
int i; // Looping var
|
||||
unsigned i; // Looping var
|
||||
_ttf_metric_t *widths; // Glyph metrics array
|
||||
|
||||
|
||||
@ -1643,8 +1734,15 @@ read_names(ttf_t *font) // I - Font
|
||||
return (false);
|
||||
|
||||
font->names.storage_size = length - (unsigned)offset;
|
||||
if (font->names.storage_size > TTF_FONT_MAX_NAMES)
|
||||
{
|
||||
errorf(font, "Name table too large - %u bytes.", (unsigned)font->names.storage_size);
|
||||
return (false);
|
||||
}
|
||||
|
||||
if ((font->names.storage = malloc(font->names.storage_size)) == NULL)
|
||||
return (false);
|
||||
|
||||
memset(font->names.storage, 'A', font->names.storage_size);
|
||||
|
||||
for (i = font->names.num_names, name = font->names.names; i > 0; i --, name ++)
|
||||
|
17
ttf.h
17
ttf.h
@ -3,7 +3,7 @@
|
||||
//
|
||||
// https://github.com/michaelrsweet/ttf
|
||||
//
|
||||
// Copyright © 2018-2023 by Michael R Sweet.
|
||||
// Copyright © 2018-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
#ifndef TTF_H
|
||||
# define TTF_H
|
||||
# include <stddef.h>
|
||||
# include <stdbool.h>
|
||||
# include <sys/types.h>
|
||||
# ifdef __cplusplus
|
||||
@ -22,12 +23,12 @@ extern "C" {
|
||||
// Types...
|
||||
//
|
||||
|
||||
typedef struct _ttf_s ttf_t; //// Font object
|
||||
typedef struct _ttf_s ttf_t; // Font object
|
||||
|
||||
typedef void (*ttf_err_cb_t)(void *data, const char *message);
|
||||
//// Font error callback
|
||||
// Font error callback
|
||||
|
||||
typedef enum ttf_stretch_e //// Font stretch
|
||||
typedef enum ttf_stretch_e // Font stretch
|
||||
{
|
||||
TTF_STRETCH_NORMAL, // normal
|
||||
TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed
|
||||
@ -40,20 +41,20 @@ typedef enum ttf_stretch_e //// Font stretch
|
||||
TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded
|
||||
} ttf_stretch_t;
|
||||
|
||||
typedef enum ttf_style_e //// Font style
|
||||
typedef enum ttf_style_e // Font style
|
||||
{
|
||||
TTF_STYLE_NORMAL, // Normal font
|
||||
TTF_STYLE_ITALIC, // Italic font
|
||||
TTF_STYLE_OBLIQUE // Oblique (angled) font
|
||||
} ttf_style_t;
|
||||
|
||||
typedef enum ttf_variant_e //// Font variant
|
||||
typedef enum ttf_variant_e // Font variant
|
||||
{
|
||||
TTF_VARIANT_NORMAL, // Normal font
|
||||
TTF_VARIANT_SMALL_CAPS // Font whose lowercase letters are small capitals
|
||||
} ttf_variant_t;
|
||||
|
||||
typedef enum ttf_weight_e //// Font weight
|
||||
typedef enum ttf_weight_e // Font weight
|
||||
{
|
||||
TTF_WEIGHT_100 = 100, // Weight 100 (Thin)
|
||||
TTF_WEIGHT_200 = 200, // Weight 200 (Extra/Ultra-Light)
|
||||
@ -66,7 +67,7 @@ typedef enum ttf_weight_e //// Font weight
|
||||
TTF_WEIGHT_900 = 900 // Weight 900 (Black/Heavy)
|
||||
} ttf_weight_t;
|
||||
|
||||
typedef struct ttf_rect_s //// Bounding rectangle
|
||||
typedef struct ttf_rect_s // Bounding rectangle
|
||||
{
|
||||
float left; // Left offset
|
||||
float top; // Top offset
|
||||
|
Reference in New Issue
Block a user