mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-04-05 16:36:44 +02:00
Compare commits
384 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
130cef8702 | ||
|
0bd9edc845 | ||
|
fe755eac3d | ||
|
8cca645835 | ||
|
b8ea9ea064 | ||
|
2874022aa4 | ||
|
3befcf2fd5 | ||
|
3b2f7e21d9 | ||
|
7e01069c5a | ||
|
88839ccb56 | ||
|
ebd5aab39b | ||
|
71d33c03ff | ||
|
cfe91b4ea2 | ||
|
458f366d78 | ||
|
4165cd23ba | ||
|
7e56d26ff8 | ||
|
712b213ec6 | ||
|
b7b6655db0 | ||
|
e9debcd169 | ||
|
2f925ccd3c | ||
|
89c2a75376 | ||
|
1237599dea | ||
|
6e2e4bbcc6 | ||
|
d535067c91 | ||
|
e996898b57 | ||
|
aa6a20c042 | ||
|
f09105dd3f | ||
|
5be5552b2b | ||
|
492a4f51b2 | ||
|
44827bac1a | ||
|
3fad0d6f15 | ||
|
aeee24b856 | ||
|
8d72f22efe | ||
|
77117ac789 | ||
|
fceb5a807d | ||
|
4f123c2a01 | ||
|
c4c8fa6036 | ||
|
9a5c5ec65d | ||
|
3f4308b68d | ||
|
9e930a7c5d | ||
|
afa010cea2 | ||
|
c26b200a83 | ||
|
eff02198ab | ||
|
5f98c7838c | ||
|
4f880bc0c1 | ||
|
d032483ed4 | ||
|
b2fc82f3a8 | ||
|
b81d01f319 | ||
|
1b35321615 | ||
|
990342f2a5 | ||
|
7f5fc456bc | ||
|
7c527cc908 | ||
|
41d17fc4e3 | ||
|
4e89137689 | ||
|
e686669b9d | ||
|
1e5cc6ffd5 | ||
|
4f1b373232 | ||
|
6f4bfe107f | ||
|
5b5de3aff6 | ||
|
48fe8d1bc9 | ||
|
a4026bfe00 | ||
|
1e945cb750 | ||
|
4cb4ceaadd | ||
|
cca7383c73 | ||
|
6c68b9fa5a | ||
|
dd7ed67ec1 | ||
|
9e2f3aba10 | ||
|
fca4dbd395 | ||
|
41ac7a0b4b | ||
|
5fc571b711 | ||
|
acf27d29c6 | ||
|
8b2b013b36 | ||
|
026f653e07 | ||
|
3bc041e6d3 | ||
|
fbd61d1fe9 | ||
|
ee2794199c | ||
|
31c3400f23 | ||
|
6d65a609e5 | ||
|
e96f9bfa6b | ||
|
10c15fc281 | ||
|
fd8427d68a | ||
|
ed1421287f | ||
|
aa91b141a8 | ||
|
5dc68f3285 | ||
|
52b508bdd2 | ||
|
41ebe39f3b | ||
|
62df5f5c78 | ||
|
a1237db52c | ||
|
a24fdee335 | ||
|
e4081f2ba3 | ||
|
5bc7ebee2c | ||
|
b872df5a1e | ||
|
53967552df | ||
|
f8639fbd64 | ||
|
9020e92928 | ||
|
48e6597337 | ||
|
d4e3bbcf16 | ||
|
2c8a996875 | ||
|
3d6d9e3e3e | ||
|
62fdf48ff9 | ||
|
294f5e07c5 | ||
|
4baafde74b | ||
|
2d175fdf70 | ||
|
56a0f290aa | ||
|
2e5319a623 | ||
|
d3d6683041 | ||
|
0d08dd5f1b | ||
|
00c9905317 | ||
|
b8b9d7ef8a | ||
|
63cdb13b1b | ||
|
72e55b5bd1 | ||
|
dc65eb8d2f | ||
|
a39b01ec9c | ||
|
4b29c9a1c2 | ||
|
5a4afad566 | ||
|
7a45adb7f5 | ||
|
45ac66874c | ||
|
eb9dad9b51 | ||
|
2ecb9cfb2d | ||
|
91a467e55c | ||
|
d705d7eb5d | ||
|
55745bcea8 | ||
|
2ea99597cc | ||
|
a3a3512ed8 | ||
|
afac83530f | ||
|
21ac2b52d1 | ||
|
21b8e3b06f | ||
|
91392a931f | ||
|
1d8bcf4d73 | ||
|
1e55779906 | ||
|
0e45e49ea4 | ||
|
0ab291a78b | ||
|
cac6d4891c | ||
|
4f29ad89da | ||
|
9c04d1dc20 | ||
|
335472023e | ||
|
25834e07ef | ||
|
2d2a7126d2 | ||
|
df1064ff39 | ||
|
853fa4fe8f | ||
|
2cadfd8a1e | ||
|
f5d40a305e | ||
|
eb5be57b4a | ||
|
3de47ea63d | ||
|
8f2c47cb07 | ||
|
74dfefdcc1 | ||
|
ee31096019 | ||
|
121b933307 | ||
|
f4409146e3 | ||
|
4312933409 | ||
|
a19949834b | ||
|
04c4f44324 | ||
|
206f75403a | ||
|
7d22477917 | ||
|
7c3651671b | ||
|
6cb661f0f4 | ||
|
7e01451b18 | ||
|
138f3955d1 | ||
|
82844ad2ce | ||
|
d7cce4dfbc | ||
|
1cec42f399 | ||
|
f3f70e7877 | ||
|
90923c3818 | ||
|
986cc512cd | ||
|
c35ddbec00 | ||
|
e4e1c39578 | ||
|
1d4f77cab1 | ||
|
b035130cde | ||
|
d6d5813b04 | ||
|
6492f210cf | ||
|
207062a996 | ||
|
7d37abb0df | ||
|
0c1122b689 | ||
|
d4f8dd46b5 | ||
|
986c5f0438 | ||
|
a81907bdb9 | ||
|
63a7a2cdbd | ||
|
f040cc41c2 | ||
|
23883268e3 | ||
|
a1e14503fd | ||
|
0766869ad1 | ||
|
6c1db141a1 | ||
|
b117959725 | ||
|
e882622233 | ||
|
c13b5a5e90 | ||
|
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 | ||
|
9fec2195d0 | ||
|
8ccbdaed94 | ||
|
4804db38a5 | ||
|
ddd984215a | ||
|
efe7c01015 | ||
|
600fa4ce59 | ||
|
688810f143 | ||
|
858cc101b6 | ||
|
43114f43bf | ||
|
c4abceef79 | ||
|
2e91e05d7b | ||
|
7e3db6b639 | ||
|
acb6b66bdb | ||
|
b0a66eef78 | ||
|
ed88322496 | ||
|
59959bf0e5 | ||
|
19c45871fa | ||
|
b0e4646f9d | ||
|
12ef2fe2c3 | ||
|
4630060ee7 | ||
|
74a6fb1860 | ||
|
a3ea0a99ff | ||
|
fdfa700442 | ||
|
d759baf11e | ||
|
7f6ffcda22 | ||
|
87ca4db73f | ||
|
a83f7f50ff | ||
|
6a4ce57d09 | ||
|
d4c594cec4 | ||
|
35c674b633 | ||
|
97d4955666 | ||
|
e138232a93 | ||
|
8d8225f4a1 | ||
|
7045d9dad9 | ||
|
4f10021e7e | ||
|
57d5894f33 | ||
|
2b8a1c8481 | ||
|
948ee16b06 | ||
|
c7101ae9dd | ||
|
599640eda1 | ||
|
a3f3bbfe11 | ||
|
26d485cfc5 | ||
|
64d306a322 | ||
|
067683cbcd | ||
|
50f27974cf | ||
|
ae9a91719b | ||
|
1a17933635 | ||
|
acea6fdbed | ||
|
66fa12f928 | ||
|
f4b8983c61 | ||
|
ed4e2fc38a | ||
|
1ed7f0089c | ||
|
563d53edd4 | ||
|
316b0ad559 | ||
|
f8b471acfd | ||
|
cedd7d104f | ||
|
6378047026 | ||
|
54578144a0 | ||
|
f7f2969e3a | ||
|
93a3fcea6c | ||
|
fa20982e5d | ||
|
44d20eba1b | ||
|
c0b7925cdf | ||
|
68dcf021b2 | ||
|
b0a8e60968 | ||
|
9d47745e43 | ||
|
b0bf2e04b9 | ||
|
f030112372 | ||
|
79c4b6f8a8 | ||
|
bd2f9d44d4 | ||
|
3c7a980a0b | ||
|
019c05d04a | ||
|
7ab550254a | ||
|
fa8e54cca2 | ||
|
d92fcb7bfb | ||
|
001dcbb123 | ||
|
a431d7806f | ||
|
ec8e900ea5 | ||
|
c73aa7ae20 | ||
|
c53786e0e1 | ||
|
1d5310a5f3 | ||
|
1e33878506 | ||
|
af07f64bc3 | ||
|
2f0d622873 | ||
|
6432187dea | ||
|
9d121335f5 | ||
|
9014ab7a20 | ||
|
b3ca129a58 | ||
|
fafe24bdb6 | ||
|
b865390b5d | ||
|
1d1ff88ebc | ||
|
8dfc2c6045 | ||
|
895738682e | ||
|
90ad1e694a | ||
|
e2b33a6cbb | ||
|
790cd440ea | ||
|
038046e6d5 | ||
|
45c5a00252 | ||
|
7e9c0afc23 | ||
|
234c3a7381 | ||
|
b7ecaeee07 | ||
|
208c3419ff | ||
|
dd56317635 | ||
|
3af39d5d1f | ||
|
19571d00f2 | ||
|
af13376e6d | ||
|
22c245ffd1 | ||
|
095a4c10d4 | ||
|
f3689d6b3d | ||
|
ea126c7e8d | ||
|
e031254531 | ||
|
493fbca31c | ||
|
c24243a2bc | ||
|
0caea44f32 | ||
|
3de55421b5 | ||
|
61a7964d90 | ||
|
37e80d67b1 | ||
|
953de26f6b | ||
|
2245c9d4f5 | ||
|
27e4ce9f42 | ||
|
9c05f802fc | ||
|
8aef2bfedd | ||
|
f425952f36 | ||
|
0c6b8f49d2 | ||
|
8ad699c93a | ||
|
a259c3a6b9 | ||
|
0ec1dd936f | ||
|
1d63c6edd6 | ||
|
d5173d14da | ||
|
1168fd974f | ||
|
5cff1ca13c | ||
|
835fbda363 | ||
|
494924a78c | ||
|
f23fd8de59 | ||
|
3c702096b7 | ||
|
e67866e29d | ||
|
89d9a7c471 | ||
|
00fb962e84 | ||
|
fd08ce1b1a | ||
|
7fe093f3bd | ||
|
d1e8c966ed | ||
|
85bfab49ab | ||
|
768cb33c47 | ||
|
bb91fb4b13 | ||
|
76b2faee0e | ||
|
2d90b1325b | ||
|
6b9f4ba8c9 | ||
|
43239eaf8a | ||
|
ba9d03ecac | ||
|
7473bc3cd9 | ||
|
d6746c08a4 | ||
|
9f1cadf78b | ||
|
760871b8db |
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1,2 +1,4 @@
|
||||
.git* export-ignore
|
||||
afl-pdf.dict export-ignore
|
||||
afl-input export-ignore
|
||||
makesrcdist export-ignore
|
||||
|
22
.github/codeql.yml
vendored
Normal file
22
.github/codeql.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
paths-ignore:
|
||||
- testpdfio.c
|
||||
|
||||
query-filters:
|
||||
- exclude:
|
||||
id: cpp/commented-out-code
|
||||
- exclude:
|
||||
id: cpp/toctou-race-condition
|
||||
- exclude:
|
||||
id: cpp/weak-cryptographic-algorithm
|
||||
- exclude:
|
||||
id: cpp/world-writable-file-creation
|
||||
- exclude:
|
||||
id: cpp/uncontrolled-allocation-size
|
||||
- exclude:
|
||||
id: cpp/path-injection
|
||||
- exclude:
|
||||
id: cpp/stack-address-escape
|
||||
- exclude:
|
||||
id: cpp/loop-variable-changed
|
||||
- exclude:
|
||||
id: cpp/long-switch
|
43
.github/workflows/build.yml
vendored
43
.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
|
||||
run: sudo apt-get install -y cppcheck zlib1g-dev
|
||||
- name: make
|
||||
- name: Install Prerequisites
|
||||
run: sudo apt-get install -y cppcheck zlib1g-dev libpng-dev
|
||||
- name: Configure PDFio
|
||||
run: ./configure --enable-debug --enable-sanitizer --enable-maintainer
|
||||
- name: Build PDFio
|
||||
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
|
||||
|
50
.github/workflows/codeql.yml
vendored
Normal file
50
.github/workflows/codeql.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: "46 3 * * 0"
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ cpp ]
|
||||
|
||||
steps:
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Update Build Environment
|
||||
run: sudo apt-get update --fix-missing -y
|
||||
|
||||
- name: Install Prerequisites
|
||||
run: sudo apt-get install -y zlib1g-dev libpng-dev
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.github/codeql.yml
|
||||
queries: +security-and-quality
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{ matrix.language }}"
|
43
.github/workflows/coverity.yml
vendored
Normal file
43
.github/workflows/coverity.yml
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
name: Coverity Scan
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
coverity-scan:
|
||||
runs-on: ubuntu-latest
|
||||
environment: Coverity
|
||||
steps:
|
||||
- name: Checkout PDFio sources
|
||||
uses: actions/checkout@v4
|
||||
- name: Update Build Environment
|
||||
run: sudo apt-get update --fix-missing -y
|
||||
- name: Install Prerequisites
|
||||
run: sudo apt-get install -y zlib1g-dev libpng-dev
|
||||
- name: Download Coverity Build Tool
|
||||
run: |
|
||||
wget -q https://scan.coverity.com/download/linux64 --post-data token="$TOKEN&project=$GITHUB_REPOSITORY" -O cov-analysis-linux64.tar.gz
|
||||
mkdir cov-analysis-linux64
|
||||
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
|
||||
env:
|
||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
|
||||
- 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
|
||||
run: |
|
||||
tar czvf cov.tgz cov-int
|
||||
curl \
|
||||
--form token=$TOKEN \
|
||||
--form email=michael.r.sweet@gmail.com \
|
||||
--form file=@cov.tgz \
|
||||
--form version="$GITHUB_REF" \
|
||||
--form description="$GITHUB_SHA" \
|
||||
"https://scan.coverity.com/builds?project=$GITHUB_REPOSITORY"
|
||||
env:
|
||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
20
.gitignore
vendored
20
.gitignore
vendored
@ -1,11 +1,29 @@
|
||||
*.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
|
||||
/examples/pdfiomerge
|
||||
/Makefile
|
||||
/packages
|
||||
/pdfio.pc
|
||||
/pdfio.xcodeproj/xcshareddata
|
||||
/pdfio-*.tar.gz*
|
||||
/pdfio-*.zip*
|
||||
/testpdfio
|
||||
/testpdfio-out.pdf
|
||||
/testpdfio-*.pdf
|
||||
/testttf
|
||||
/x64
|
||||
|
211
CHANGES.md
Normal file
211
CHANGES.md
Normal file
@ -0,0 +1,211 @@
|
||||
Changes in PDFio
|
||||
================
|
||||
|
||||
|
||||
v1.5.2 - YYYY-MM-DD
|
||||
-------------------
|
||||
|
||||
- Updated maximum allowed PDF string size to 64k (Issue #117)
|
||||
- Fixed form detection in `pdfioinfo` example code (Issue #114)
|
||||
- Fixed parsing of certain date/time values (Issue #115)
|
||||
- Fixed support for empty name values (Issue #116)
|
||||
|
||||
|
||||
v1.5.1 - 2025-03-28
|
||||
-------------------
|
||||
|
||||
- Fixed output of special characters in name values (Issue #106)
|
||||
- Fixed output of special characters in string values (Issue #107)
|
||||
- Fixed output of large integers in dictionaries (Issue #108)
|
||||
- Fixed handling of 0-length streams (Issue #111)
|
||||
- Fixed detection of UTF-16 Big-Endian strings (Issue #112)
|
||||
|
||||
|
||||
v1.5.0 - 2025-03-06
|
||||
-------------------
|
||||
|
||||
- Added support for embedded color profiles in JPEG images (Issue #7)
|
||||
- Added `pdfioFileCreateICCObjFromData` API.
|
||||
- Added support for writing cross-reference streams for PDF 1.5 and newer files
|
||||
(Issue #10)
|
||||
- Added `pdfioFileGetModDate()` API (Issue #88)
|
||||
- Added support for using libpng to embed PNG images in PDF output (Issue #90)
|
||||
- Added support for writing the PCLm subset of PDF (Issue #99)
|
||||
- Now support opening damaged PDF files (Issue #45)
|
||||
- Updated documentation (Issue #95)
|
||||
- Updated the pdf2txt example to support font encodings.
|
||||
- Fixed potential heap/integer overflow issues in the TrueType cmap code.
|
||||
- Fixed an output issue for extremely small `double` values with the
|
||||
`pdfioContent` APIs.
|
||||
- Fixed a missing Widths array issue for embedded TrueType fonts.
|
||||
- Fixed some Unicode font embedding issues.
|
||||
|
||||
|
||||
v1.4.1 - 2025-01-24
|
||||
-------------------
|
||||
|
||||
- Added license files for the example fonts now bundled with PDFio (Issue #91)
|
||||
- Fixed the link libraries for the example source code (Issue #86)
|
||||
- Fixed handling of the Info object (Issue #87)
|
||||
- Fixed opening of PDF files less than 1024 bytes in length (Issue #87)
|
||||
- Fixed potential `NULL` dereference when reading (Issue #89)
|
||||
- Fixed reading of compressed object streams (Issue #92)
|
||||
- Fixed reading of UTF-16 string values (Issue #92)
|
||||
|
||||
|
||||
v1.4.0 - 2024-12-26
|
||||
-------------------
|
||||
|
||||
- Added new `pdfioDictGetKey` and `pdfioDictGetNumPairs` APIs (Issue #63)
|
||||
- Added new `pdfioArrayRemove` and `pdfioDictClear` APIs (Issue #74)
|
||||
- Added new `pdfioFileCreateNameObj` and `pdfioObjGetName` APIs for creating and
|
||||
getting name object values (Issue #76)
|
||||
- Updated documentation (Issue #78)
|
||||
- Updated `pdfioContentTextMeasure` to support measuring PDF base fonts created
|
||||
with `pdfioFileCreateFontObjFromBase` (Issue #84)
|
||||
- Fixed reading of PDF files whose trailer is missing a newline (Issue #80)
|
||||
- Fixed builds with some versions of VC++ (Issue #81)
|
||||
- Fixed validation of date/time values (Issue #83)
|
||||
|
||||
|
||||
v1.3.2 - 2024-08-15
|
||||
-------------------
|
||||
|
||||
- Added some more sanity checks to the TrueType font reader.
|
||||
- Updated documentation (Issue #77)
|
||||
- Fixed an issue when opening certain encrypted PDF files (Issue #62)
|
||||
|
||||
|
||||
v1.3.1 - 2024-08-05
|
||||
-------------------
|
||||
|
||||
- CVE 2024-42358: Updated TrueType font reader to avoid large memory
|
||||
allocations.
|
||||
- Fixed some documentation errors and added examples (Issue #68, Issue #69)
|
||||
|
||||
|
||||
v1.3.0 - 2024-06-28
|
||||
-------------------
|
||||
|
||||
- Added `pdfioFileGetCatalog` API for accessing the root/catalog object of a
|
||||
PDF file (Issue #67)
|
||||
- Updated number support to avoid locale issues (Issue #61)
|
||||
- Updated the PDFio private header to allow compilation with MingW; note that
|
||||
MingW is NOT a supported toolchain for PDFio (Issue #66)
|
||||
- Optimized string pool code.
|
||||
|
||||
|
||||
v1.2.0 - 2024-01-24
|
||||
-------------------
|
||||
|
||||
- Now use autoconf to configure the PDFio sources (Issue #54)
|
||||
- Added `pdfioFileCreateNumberObj` and `pdfioFileCreateStringObj` functions
|
||||
(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 - 2023-10-10
|
||||
-------------------
|
||||
|
||||
- Updated `pdfioContentSetDashPattern` to support setting a solid (0 length)
|
||||
dash pattern (Issue #41)
|
||||
- Fixed an issue with broken PDF files containing extra CR and/or LF separators
|
||||
after the object stream token (Issue #40)
|
||||
- Fixed an issue with PDF files produced by Crystal Reports (Issue #45)
|
||||
- Fixed an issue with PDF files produced by Microsoft Reporting Services
|
||||
(Issue #46)
|
||||
- Fixed support for compound filters where the filter array consists of a
|
||||
single named filter (Issue #47)
|
||||
- Fixed builds on Windows - needed windows.h header for temporary files
|
||||
(Issue #48)
|
||||
|
||||
|
||||
v1.1.1 - 2023-03-20
|
||||
-------------------
|
||||
|
||||
- CVE-2023-28428: Fixed a potential denial-of-service with corrupt PDF files.
|
||||
- Fixed a few build issues.
|
||||
|
||||
|
||||
v1.1.0 - 2023-02-06
|
||||
-------------------
|
||||
|
||||
- CVE-2023-24808: Fixed a potential denial-of-service with corrupt PDF files.
|
||||
- Added `pdfioFileCreateTemporary` function (Issue #29)
|
||||
- Added `pdfioDictIterateKeys` function (Issue #31)
|
||||
- Added `pdfioContentPathEnd` function.
|
||||
- Added protection against opening multiple streams in the same file at the
|
||||
same time.
|
||||
- Documentation updates (Issue #37)
|
||||
- Fixed "install-shared" target (Issue #32)
|
||||
- Fixed `pdfioFileGet...` metadata APIs (Issue #33)
|
||||
- Fixed `pdfioContentMatrixRotate` function.
|
||||
|
||||
|
||||
v1.0.1 - 2022-03-02
|
||||
-------------------
|
||||
|
||||
- Added missing `pdfioPageGetNumStreams` and `pdfioPageOpenStream` functions.
|
||||
- Added demo pdfiototext utility.
|
||||
- Fixed bug in `pdfioStreamGetToken`.
|
||||
|
||||
|
||||
v1.0.0 - 2021-12-14
|
||||
-------------------
|
||||
|
||||
- First stable release.
|
||||
|
||||
|
||||
v1.0rc1 - 2021-11-30
|
||||
--------------------
|
||||
|
||||
- Fixed a few stack/buffer overflow bugs discovered via fuzzing.
|
||||
|
||||
|
||||
v1.0b2 - 2021-11-07
|
||||
-------------------
|
||||
|
||||
- Added `pdfioFileCreateOutput` API to support streaming output of PDF
|
||||
(Issue #21)
|
||||
- Fixed `all-shared` target (Issue #22)
|
||||
- Fixed memory leaks (Issue #23)
|
||||
- Updated `pdfioContentSetDashPattern` to accept `double` values (Issue #25)
|
||||
- Added support for reading and writing encrypted PDFs (Issue #26)
|
||||
- Fixed some issues identified by a Coverity scan.
|
||||
|
||||
|
||||
v1.0b1 - 2021-08-30
|
||||
-------------------
|
||||
|
||||
- Initial release
|
13
CODE_OF_CONDUCT.md
Normal file
13
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,13 @@
|
||||
Code of Conduct
|
||||
===============
|
||||
|
||||
My goal is to provide quality open source software that everyone can use.
|
||||
While I may not be able to address every request or accept every contribution
|
||||
to this project, I will do my best to develop and maintain it for the common
|
||||
good. As part of the open source community, I expect everyone to:
|
||||
|
||||
- Be friendly and patient.
|
||||
- Be respectful, even if we disagree.
|
||||
- Be honest.
|
||||
- Be accepting of all people.
|
||||
- Fully explain your concerns, issues, or ideas.
|
399
CONTRIBUTING.md
Normal file
399
CONTRIBUTING.md
Normal file
@ -0,0 +1,399 @@
|
||||
Contributing to PDFio
|
||||
=====================
|
||||
|
||||
PDFio is developed and distributed as open source software under the Apache
|
||||
License, Version 2.0. Contributions should be submitted as pull requests on
|
||||
the Github site:
|
||||
|
||||
http://github.com/michaelrsweet/pdfio/pulls
|
||||
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
- [Build System](#build-system)
|
||||
- [Version Numbering](#version-numbering)
|
||||
- [Coding Guidelines](#coding-guidelines)
|
||||
- [Source Files](#source-files)
|
||||
- [Header Files](#header-files)
|
||||
- [Comments](#comments)
|
||||
- [Indentation](#indentation)
|
||||
- [Spacing](#spacing)
|
||||
- [Return Values](#return-values)
|
||||
- [Functions](#functions)
|
||||
- [Variables](#variables)
|
||||
- [Types](#types)
|
||||
- [Structures](#structures)
|
||||
- [Constants](#constants)
|
||||
- [Shell Script Guidelines](#shell-script-guidelines)
|
||||
- [Makefile Guidelines](#makefile-guidelines)
|
||||
- [General Organization](#general-organization)
|
||||
- [Makefile Documentation](#makefile-documentation)
|
||||
- [Portable Makefile Construction](#portable-makefile-construction)
|
||||
- [Standard Variables](#standard-variables)
|
||||
- [Standard Targets](#standard-targets)
|
||||
- [Object Files](#object-files)
|
||||
- [Programs](#programs)
|
||||
- [Static Libraries](#static-libraries)
|
||||
- [Shared Libraries](#shared-libraries)
|
||||
- [Dependencies](#dependencies)
|
||||
- [Install/Uninstall Support](#installuninstall-support)
|
||||
|
||||
|
||||
Build System
|
||||
------------
|
||||
|
||||
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
|
||||
-----------------
|
||||
|
||||
PDFio uses a three-part version number separated by periods to represent the
|
||||
major, minor, and patch release numbers. Major release numbers indicate large
|
||||
design changes or backwards-incompatible changes to the library. Minor release
|
||||
numbers indicate new features and other smaller changes which are backwards-
|
||||
compatible with previous releases. Patch numbers indicate bug fixes to the
|
||||
previous feature or patch release.
|
||||
|
||||
Production releases use the plain version numbers:
|
||||
|
||||
MAJOR.MINOR.PATCH
|
||||
1.0.0
|
||||
1.0.1
|
||||
1.0.2
|
||||
...
|
||||
1.1.0
|
||||
...
|
||||
2.0.0
|
||||
|
||||
The first production release in a MAJOR.MINOR series (MAJOR.MINOR.0) is called
|
||||
a feature release. Feature releases are the only releases that may contain new
|
||||
features. Subsequent production releases in a MAJOR.MINOR series may only
|
||||
contain bug fixes.
|
||||
|
||||
Beta-test releases are identified by appending the letter B to the major and
|
||||
minor version numbers followed by the beta release number:
|
||||
|
||||
MAJOR.MINORbNUMBER
|
||||
1.0b1
|
||||
|
||||
Release candidates are identified by appending the letters RC to the major and
|
||||
minor version numbers followed by the release candidate number:
|
||||
|
||||
MAJOR.MINORrcNUMBER
|
||||
1.0rc1
|
||||
|
||||
> Note: While the beta/release candidate syntax is *not* strictly compatible
|
||||
> with [Semantic Versioning](https://semver.org), it is better supported by the
|
||||
> various traditional package formats. When packaging a pre-release version of
|
||||
> PDFio in a format that requires the use of semantic version numbers, the
|
||||
> version number should simply be converted to the form "MAJOR.MINOR.0-suffix".
|
||||
|
||||
|
||||
Coding Guidelines
|
||||
-----------------
|
||||
|
||||
Contributed source code must follow the guidelines below. While the examples
|
||||
are for C source files, source code for other languages should conform to the
|
||||
same guidelines as allowed by the language.
|
||||
|
||||
|
||||
### Source Files
|
||||
|
||||
All source files names must be 16 characters or less in length to ensure
|
||||
compatibility with older UNIX filesystems. Source files containing functions
|
||||
have an extension of ".c" for C source files. All "include" files have an
|
||||
extension of ".h". Tabs are set to 8 characters or columns.
|
||||
|
||||
The top of each source file contains a header giving the purpose or nature of
|
||||
the source file and the copyright and licensing notice:
|
||||
|
||||
//
|
||||
// Description of file contents.
|
||||
//
|
||||
// Copyright © YYYY by AUTHOR.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
|
||||
### Header Files
|
||||
|
||||
Private API header files must be named with the suffix "-private", for example
|
||||
the "pdfio.h" header file defines all of the public APIs while the
|
||||
"pdfio-private.h" header file defines all of the private APIs. Typically a
|
||||
private API header file will include the corresponding public API header file.
|
||||
|
||||
|
||||
### Comments
|
||||
|
||||
All source code utilizes block comments within functions to describe the
|
||||
operations being performed by a group of statements; avoid putting a comment
|
||||
per line unless absolutely necessary, and then consider refactoring the code
|
||||
so that it is not necessary. C source files use the C99 comment format
|
||||
("// comment"):
|
||||
|
||||
// Clear the state array before we begin...
|
||||
for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
|
||||
array[i] = PDFIO_STATE_IDLE;
|
||||
|
||||
// Wait for state changes on another thread...
|
||||
do
|
||||
{
|
||||
for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
|
||||
if (array[i] != PDFIO_STATE_IDLE)
|
||||
break;
|
||||
|
||||
if (i == (sizeof(array) / sizeof(array[0])))
|
||||
sleep(1);
|
||||
} while (i == (sizeof(array) / sizeof(array[0])));
|
||||
|
||||
|
||||
### Indentation
|
||||
|
||||
All code blocks enclosed by brackets begin with the opening brace on a new
|
||||
line. The code then follows starting on a new line after the brace and is
|
||||
indented 2 spaces. The closing brace is then placed on a new line following
|
||||
the code at the original indentation:
|
||||
|
||||
{
|
||||
int i; // Looping var
|
||||
|
||||
// Process foobar values from 0 to 999...
|
||||
for (i = 0; i < 1000; i ++)
|
||||
{
|
||||
do_this(i);
|
||||
do_that(i);
|
||||
}
|
||||
}
|
||||
|
||||
Single-line statements following "do", "else", "for", "if", and "while" are
|
||||
indented 2 spaces as well. Blocks of code in a "switch" block are indented 4
|
||||
spaces after each "case" and "default" case:
|
||||
|
||||
switch (array[i])
|
||||
{
|
||||
case PDFIO_STATE_IDLE :
|
||||
do_this(i);
|
||||
do_that(i);
|
||||
break;
|
||||
|
||||
default :
|
||||
do_nothing(i);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
### Spacing
|
||||
|
||||
A space follows each reserved word such as `if`, `while`, etc. Spaces are not
|
||||
inserted between a function name and the arguments in parenthesis.
|
||||
|
||||
|
||||
### Return Values
|
||||
|
||||
Parenthesis surround values returned from a function:
|
||||
|
||||
return (PDFIO_STATE_IDLE);
|
||||
|
||||
|
||||
### Functions
|
||||
|
||||
Functions with a global scope have a lowercase prefix followed by capitalized
|
||||
words, e.g., `pdfioDoThis`, `pdfioDoThat`, `pdfioDoSomethingElse`, etc. Private
|
||||
global functions begin with a leading underscore, e.g., `_pdfioDoThis`,
|
||||
`_pdfioDoThat`, etc.
|
||||
|
||||
Functions with a local scope are declared static with lowercase names and
|
||||
underscores between words, e.g., `do_this`, `do_that`, `do_something_else`, etc.
|
||||
|
||||
Function names follow the following pattern:
|
||||
|
||||
- "pdfioFooCreate" to create a Foo object,
|
||||
- "pdfioFooDelete" to destroy (free) a Foo object,
|
||||
- "pdfioFooGetBar" to get data element Bar from object Foo,
|
||||
- "pdfioFooIsBar" to test condition Bar for object Foo, and
|
||||
- "pdfioFooSetBar" to set data element Bar in object Foo.
|
||||
- "pdfioFooVerb" to take an action with object Foo.
|
||||
|
||||
Each function begins with a comment header describing what the function does,
|
||||
the possible input limits (if any), the possible output values (if any), and
|
||||
any special information needed:
|
||||
|
||||
//
|
||||
// 'pdfioDoThis()' - Short description of function.
|
||||
//
|
||||
// Longer documentation for function with examples using a subset of
|
||||
// markdown. This is a bulleted list:
|
||||
//
|
||||
// - One fish
|
||||
// - Two fish
|
||||
// - Red fish
|
||||
// - Blue fish
|
||||
//
|
||||
// > *Note:* Special notes for developer should be markdown block quotes.
|
||||
//
|
||||
|
||||
float // O - Inverse power value, 0.0 <= y <= 1.1
|
||||
pdfioDoThis(float x) // I - Power value (0.0 <= x <= 1.1)
|
||||
{
|
||||
...
|
||||
return (y);
|
||||
}
|
||||
|
||||
Return/output values are indicated using an "O" prefix, input values are
|
||||
indicated using the "I" prefix, and values that are both input and output use
|
||||
the "IO" prefix for the corresponding in-line comment.
|
||||
|
||||
The [`codedoc` documentation generator][1] also understands the following
|
||||
special text in the function description comment:
|
||||
|
||||
@deprecated@ - Marks the function as deprecated (not recommended
|
||||
for new development and scheduled for removal)
|
||||
@since version@ - Marks the function as new in the specified version.
|
||||
@private@ - Marks the function as private (same as starting the
|
||||
function name with an underscore)
|
||||
|
||||
[1]: https://www.msweet.org/codedoc
|
||||
|
||||
|
||||
### Variables
|
||||
|
||||
Variables with a global scope are capitalized, e.g., `ThisVariable`,
|
||||
`ThatVariable`, `ThisStateVariable`, etc. Globals *must not* be used in the
|
||||
PDFio library.
|
||||
|
||||
Variables with a local scope are lowercase with underscores between words,
|
||||
e.g., `this_variable`, `that_variable`, etc. Any "local global" variables
|
||||
shared by functions within a source file are declared static.
|
||||
|
||||
Each variable is declared on a separate line and is immediately followed by a
|
||||
comment block describing the variable:
|
||||
|
||||
int ThisVariable; // The current state of this
|
||||
static int that_variable; // The current state of that
|
||||
|
||||
|
||||
### Types
|
||||
|
||||
All type names are lowercase with underscores between words and `_t` appended
|
||||
to the end of the name, e.g., `pdfio_this_type_t`, `pdfio_that_type_t`, etc.
|
||||
Type names start with the "pdfio\_" prefix to avoid conflicts with system types.
|
||||
Private type names start with an underscore, e.g., `_pdfio_this_t`,
|
||||
`_pdfio_that_t`, etc.
|
||||
|
||||
Each type has a comment block immediately after the typedef:
|
||||
|
||||
typedef int pdfio_this_type_t; // This type is for foobar options.
|
||||
|
||||
|
||||
### Structures
|
||||
|
||||
All structure names are lowercase with underscores between words and `_s`
|
||||
appended to the end of the name, e.g., `pdfio_this_s`, `pdfio_that_s`, etc.
|
||||
Structure names start with the "pdfio\_" prefix to avoid conflicts with system
|
||||
types. Private structure names start with an underscore, e.g., `_pdfio_this_s`,
|
||||
`_pdfio_that_s`, etc.
|
||||
|
||||
Each structure has a comment block immediately after the struct and each member
|
||||
is documented similar to the variable naming policy above:
|
||||
|
||||
struct pdfio_this_struct_s // This structure is for foobar options.
|
||||
{
|
||||
int this_member; // Current state for this
|
||||
int that_member; // Current state for that
|
||||
};
|
||||
|
||||
One common design pattern is to define a private structure with a public
|
||||
typedef, for example:
|
||||
|
||||
// In public header
|
||||
typedef struct _pdfio_foo_s pdfio_foo_t // Foo object
|
||||
|
||||
// In private header
|
||||
struct _pdfio_foo_s // Foo object
|
||||
{
|
||||
int this_member; // Current state for this
|
||||
int that_member; // Current state for that
|
||||
};
|
||||
|
||||
|
||||
### Constants
|
||||
|
||||
All constant names are uppercase with underscores between words, e.g.,
|
||||
`PDFIO_THIS_CONSTANT`, `PDFIO_THAT_CONSTANT`, etc. Constants begin with the
|
||||
"PDFIO\_" prefix to avoid conflicts with system constants. Private constants
|
||||
start with an underscore, e.g., `_PDFIO_THIS_CONSTANT`,
|
||||
`_PDFIO_THAT_CONSTANT`, etc.
|
||||
|
||||
Typed enumerations should be used whenever possible to allow for type checking
|
||||
by the compiler. The constants for typed enumerations must match the type name
|
||||
in uppercase, for example a `pdfio_foo_e` enumeration has constant names
|
||||
starting with `PDFIO_FOO_`.
|
||||
|
||||
Comment blocks immediately follow each constant:
|
||||
|
||||
typedef enum pdfio_style_e // Style enumerations
|
||||
{
|
||||
PDFIO_STYLE_THIS, // This style
|
||||
PDFIO_STYLE_THAT // That style
|
||||
} pdfio_style_t;
|
||||
|
||||
|
||||
Shell Script Guidelines
|
||||
-----------------------
|
||||
|
||||
All shell scripts in PDFio must conform to the [POSIX shell][POSIX-SHELL]
|
||||
command language and should restrict their dependence on non-POSIX utility
|
||||
commands.
|
||||
|
||||
[POSIX-SHELL]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18
|
||||
|
||||
|
||||
Makefile Guidelines
|
||||
-------------------
|
||||
|
||||
PDFio uses a single [POSIX makefile][POSIX-MAKE] to build it. GNU make
|
||||
extensions MUST NOT be used.
|
||||
|
||||
[POSIX-MAKE]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html
|
||||
|
||||
The following variables are defined in the makefile:
|
||||
|
||||
- `AR`; the static library archiver command,
|
||||
- `ARFLAGS`; options for the static library archiver,
|
||||
- `CC`; the C compiler command,
|
||||
- `CFLAGS`; options for the C compiler,
|
||||
- `CODESIGN_IDENTITY`: the code signing identity,
|
||||
- `CPPFLAGS`; options for the C preprocessor,
|
||||
- `DESTDIR`/`DSTROOT`: the destination root directory when installing.
|
||||
- `DSO`; the shared library building command,
|
||||
- `DSOFLAGS`; options for the shared library building command,
|
||||
- `LDFLAGS`; options for the linker,
|
||||
- `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,
|
||||
- `VERSION`: the library version number.
|
||||
|
||||
The following standard targets are defined in the makefile:
|
||||
|
||||
- `all`; creates the static library and unit test program.
|
||||
- `clean`; removes all target programs libraries, documentation files, and
|
||||
object files,
|
||||
- `install`; installs all distribution files in their corresponding locations.
|
||||
- `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.
|
17
FAQ.md
17
FAQ.md
@ -1,17 +0,0 @@
|
||||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
Why Don't You Support Writing a PDF File with Encryption?
|
||||
---------------------------------------------------------
|
||||
|
||||
PDF encryption offers very little protection:
|
||||
|
||||
- PDF encryption keys are reused and derived from the user password (padded
|
||||
with a standard base string) and the object numbers in the file.
|
||||
- RC4 encryption (40- and 128-bit) was broken years ago.
|
||||
- AES encryption (128- and 256-bit) is better, but PDF uses Cipher Block
|
||||
Chaining (CBC) which enables attacks that allow the original encryption key
|
||||
to be recovered.
|
||||
|
||||
In addition, PDF usage controls (no print, no copy, etc.) are tied to this
|
||||
encryption, making them trivial to bypass.
|
190
Makefile
190
Makefile
@ -1,190 +0,0 @@
|
||||
#
|
||||
# Makefile for PDFio.
|
||||
#
|
||||
# Copyright © 2021 by Michael R Sweet.
|
||||
#
|
||||
# Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
# information.
|
||||
#
|
||||
|
||||
# POSIX makefile
|
||||
.POSIX:
|
||||
|
||||
# Variables...
|
||||
AR = ar
|
||||
ARFLAGS = cr
|
||||
CC = cc
|
||||
CFLAGS =
|
||||
CODESIGN_IDENTITY = Developer ID
|
||||
COMMONFLAGS = -Os -g
|
||||
CPPFLAGS = '-DPDFIO_VERSION="$(VERSION)"'
|
||||
DESTDIR = $(DSTROOT)
|
||||
DSO = cc
|
||||
DSOFLAGS =
|
||||
DSONAME =
|
||||
LDFLAGS =
|
||||
LIBS = -lm -lz
|
||||
RANLIB = ranlib
|
||||
VERSION = 1.0b1
|
||||
prefix = /usr/local
|
||||
|
||||
|
||||
# Base rules
|
||||
.SUFFIXES: .c .h .o
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(COMMONFLAGS) -c $<
|
||||
|
||||
|
||||
# Files
|
||||
PUBHEADERS = \
|
||||
pdfio.h \
|
||||
pdfio-content.h
|
||||
PUBOBJS = \
|
||||
pdfio-array.o \
|
||||
pdfio-common.o \
|
||||
pdfio-content.o \
|
||||
pdfio-dict.o \
|
||||
pdfio-file.o \
|
||||
pdfio-object.o \
|
||||
pdfio-page.o \
|
||||
pdfio-stream.o \
|
||||
pdfio-string.o \
|
||||
pdfio-token.o \
|
||||
pdfio-value.o
|
||||
LIBOBJS = \
|
||||
$(PUBOBJS) \
|
||||
ttf.o
|
||||
OBJS = \
|
||||
$(LIBOBJS) \
|
||||
testpdfio.o
|
||||
TARGETS = \
|
||||
$(DSONAME) \
|
||||
libpdfio.a \
|
||||
testpdfio
|
||||
|
||||
|
||||
# Make everything
|
||||
all: $(TARGETS)
|
||||
|
||||
all-shared:
|
||||
if test `uname` = Darwin; then \
|
||||
$(MAKE) DSONAME="libpdfio.1.dylib" -$(MAKEFLAGS) all; \
|
||||
else
|
||||
$(MAKE) DSONAME="libpdfio.so.1" -$(MAKEFLAGS) all; \
|
||||
fi
|
||||
|
||||
debug:
|
||||
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-g -fsanitize=address -DDEBUG=1" clean all
|
||||
|
||||
|
||||
# Clean everything
|
||||
clean:
|
||||
rm -f $(TARGETS) $(OBJS)
|
||||
|
||||
|
||||
# Install everything
|
||||
install: $(TARGETS)
|
||||
-mkdir -p $(DESTDIR)$(prefix)/include
|
||||
cp $(PUBHEADERS) $(DESTDIR)$(prefix)/include
|
||||
-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
|
||||
-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
|
||||
-mkdir -p $(DESTDIR)$(prefix)/share/doc/pdfio
|
||||
cp doc/pdfio.html doc/pdfio-512.png LICENSE NOTICE $(DESTDIR)$(prefix)/share/doc/pdfio
|
||||
-mkdir -p $(DESTDIR)$(prefix)/share/man/man3
|
||||
cp doc/pdfio.3 $(DESTDIR)$(prefix)/share/man/man3
|
||||
|
||||
install-shared:
|
||||
if test `uname` = Darwin; then \
|
||||
$(MAKE) DSONAME="libpdfio.1.dylib" -$(MAKEFLAGS) install; \
|
||||
else
|
||||
$(MAKE) DSONAME="libpdfio.so.1" -$(MAKEFLAGS) install; \
|
||||
fi
|
||||
|
||||
|
||||
# Test everything
|
||||
test: testpdfio
|
||||
./testpdfio
|
||||
|
||||
|
||||
# pdfio library
|
||||
libpdfio.a: $(LIBOBJS)
|
||||
$(AR) $(ARFLAGS) $@ $(LIBOBJS)
|
||||
$(RANLIB) $@
|
||||
|
||||
libpdfio.so.1: $(LIBOBJS)
|
||||
$(CC) $(DSOFLAGS) $(COMMONFLAGS) -shared -o $@ -Wl,soname,$@ $(LIBOBJS) $(LIBS)
|
||||
|
||||
libpdfio.1.dylib: $(LIBOBJS)
|
||||
$(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' | grep -v '^__' | sed -e '1,$$s/^_//'; \
|
||||
echo pdfioAdobeRGBGamma; echo pdfioAdobeRGBMatrix; \
|
||||
echo pdfioAdobeRGBWhitePoint; \
|
||||
echo pdfioDisplayP3Gamma; echo pdfioDisplayP3Matrix; \
|
||||
echo pdfioDisplayP3WhitePoint; \
|
||||
echo pdfioSRGBGamma; echo pdfioSRGBMatrix; \
|
||||
echo pdfioSRGBWhitePoint; \
|
||||
echo _pdfioTokenInit; \
|
||||
echo _pdfioValueDebug; echo _pdfioValueRead) | sort >>$@
|
||||
|
||||
|
||||
# pdfio test program
|
||||
testpdfio: testpdfio.o libpdfio.a
|
||||
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
|
||||
|
||||
|
||||
# Dependencies
|
||||
$(OBJS): pdfio.h Makefile
|
||||
$(LIBOBJS): pdfio-private.h
|
||||
pdfio-content.o: pdfio-content.h ttf.h
|
||||
ttf.o: ttf.h
|
||||
|
||||
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
||||
DOCFLAGS = \
|
||||
--author "Michael R Sweet" \
|
||||
--copyright "Copyright (c) 2021 by Michael R Sweet" \
|
||||
--docversion $(VERSION)
|
||||
|
||||
.PHONY: doc
|
||||
doc:
|
||||
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 "pdf read/write library" --man pdfio --section 3 --body doc/pdfio.md pdfio.xml >doc/pdfio.3
|
||||
rm -f pdfio.xml
|
||||
|
||||
|
||||
# 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
|
281
Makefile.in
Normal file
281
Makefile.in
Normal file
@ -0,0 +1,281 @@
|
||||
#
|
||||
# Makefile for PDFio.
|
||||
#
|
||||
# Copyright © 2021-2025 by Michael R Sweet.
|
||||
#
|
||||
# Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
# information.
|
||||
#
|
||||
|
||||
# POSIX makefile
|
||||
.POSIX:
|
||||
|
||||
|
||||
# Build silently
|
||||
.SILENT:
|
||||
|
||||
|
||||
# Version numbers...
|
||||
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-LICENSE.txt \
|
||||
examples/Roboto-Bold.ttf \
|
||||
examples/Roboto-Italic.ttf \
|
||||
examples/Roboto-Regular.ttf \
|
||||
examples/RobotoMono-Regular.ttf \
|
||||
examples/code128.c \
|
||||
examples/code128.ttf \
|
||||
examples/code128-LICENSE.txt \
|
||||
examples/image2pdf.c \
|
||||
examples/md2pdf.c \
|
||||
examples/md2pdf.md \
|
||||
examples/mmd.c \
|
||||
examples/mmd.h \
|
||||
examples/pdf2text.c \
|
||||
examples/pdfioinfo.c
|
||||
|
||||
|
||||
# Make everything
|
||||
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-2025 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 by Michael R Sweet.
|
||||
Copyright © 2021-2025 by Michael R Sweet.
|
||||
|
||||
(Optional) Exceptions to the Apache 2.0 License:
|
||||
================================================
|
||||
|
81
README.md
81
README.md
@ -3,18 +3,15 @@ pdfio - PDF Read/Write Library
|
||||
|
||||

|
||||

|
||||

|
||||
[](https://github.com/michaelrsweet/pdfio/actions/workflows/build.yml)
|
||||
[](https://scan.coverity.com/projects/michaelrsweet-pdfio)
|
||||
[](https://lgtm.com/projects/g/michaelrsweet/pdfio/context:cpp)
|
||||
[](https://lgtm.com/projects/g/michaelrsweet/pdfio/)
|
||||
|
||||
PDFio is a simple C library for reading and writing PDF files. The primary
|
||||
goals of PDFio are:
|
||||
|
||||
- Read and write any version of PDF file
|
||||
- Provide access to pages, objects, and streams within a PDF file
|
||||
- Support reading encrypted PDF files
|
||||
- Support writing PDF files with digital signatures
|
||||
- Support reading and writing of encrypted PDF files
|
||||
- Extract or embed useful metadata (author, creator, page information, etc.)
|
||||
- "Filter" PDF files, for example to extract a range of pages or to embed fonts
|
||||
that are missing from a PDF
|
||||
@ -31,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.
|
||||
|
||||
@ -39,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
|
||||
|
||||
@ -57,53 +66,15 @@ 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
|
||||
---------------------
|
||||
|
||||
The Visual Studio solution ("pdfio.sln") is provided for Windows developers and
|
||||
generates both a static library and DLL. You can also use NuGet to install the
|
||||
`pdfio_native` package.
|
||||
generates the PDFIO1 DLL. You can also use NuGet to install the `pdfio_native`
|
||||
package.
|
||||
|
||||
|
||||
Xcode Project
|
||||
@ -114,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 'COMMONFLAGS="-Os -mmacosx-version-min=10.14 -arch x86_64 -arch arm64"' install
|
||||
|
||||
|
||||
Legal Stuff
|
||||
-----------
|
||||
|
||||
PDFio is Copyright © 2021 by Michael R Sweet.
|
||||
PDFio is Copyright © 2021-2025 by Michael R Sweet.
|
||||
|
||||
This software is licensed under the Apache License Version 2.0 with an
|
||||
(optional) exception to allow linking against GPL2/LGPL2 software. See the
|
||||
|
132
SECURITY.md
Normal file
132
SECURITY.md
Normal file
@ -0,0 +1,132 @@
|
||||
Security Policy
|
||||
===============
|
||||
|
||||
This file describes how security issues are reported and handled, and what the
|
||||
expectations are for security issues reported to this project.
|
||||
|
||||
|
||||
Reporting a Security Bug
|
||||
------------------------
|
||||
|
||||
For the purposes of this project, a security bug is a software defect that
|
||||
allows a *local or remote user* to gain unauthorized access or privileges on the
|
||||
host computer or to cause the software to crash. Such defects should be
|
||||
reported to the project security advisory page at
|
||||
<https://github.com/michaelrsweet/pdfio/security/advisories>.
|
||||
|
||||
Alternately, security bugs can be reported to "security AT msweet.org" using the
|
||||
PGP public key below. Expect a response within 5 business days. Any proposed
|
||||
embargo date should be at least 30 days and no more than 90 days in the future.
|
||||
|
||||
> *Note:* If you've found a software defect that allows a *program* to gain
|
||||
> unauthorized access or privileges on the host computer or causes the program
|
||||
> to crash, that defect should be reported as an ordinary project issue at
|
||||
> <https://github.com/michaelrsweet/pdfio/issues>.
|
||||
|
||||
|
||||
Responsible Disclosure
|
||||
----------------------
|
||||
|
||||
With *responsible disclosure*, a security issue (and its fix) is disclosed only
|
||||
after a mutually-agreed period of time (the "embargo date"). The issue and fix
|
||||
are shared amongst and reviewed by the key stakeholders (Linux distributions,
|
||||
OS vendors, etc.) and the CERT/CC. Fixes are released to the public on the
|
||||
agreed-upon date.
|
||||
|
||||
> Responsible disclosure applies only to production releases. A security
|
||||
> vulnerability that only affects unreleased code can be fixed immediately
|
||||
> without coordination. Vendors *should not* package and release unstable
|
||||
> snapshots, beta releases, or release candidates of this software.
|
||||
|
||||
|
||||
Supported Versions
|
||||
------------------
|
||||
|
||||
All production releases of this software are subject to this security policy. A
|
||||
production release is tagged and given a semantic version number of the form:
|
||||
|
||||
MAJOR.MINOR.PATCH
|
||||
|
||||
where "MAJOR" is an integer starting at 1 and "MINOR" and "PATCH" are integers
|
||||
starting at 0. A feature release has a "PATCH" value of 0, for example:
|
||||
|
||||
1.0.0
|
||||
1.1.0
|
||||
2.0.0
|
||||
|
||||
Beta releases and release candidates are *not* production releases and use
|
||||
semantic version numbers of the form:
|
||||
|
||||
MAJOR.MINORbNUMBER
|
||||
MAJOR.MINORrcNUMBER
|
||||
|
||||
where "MAJOR" and "MINOR" identify the new feature release version number and
|
||||
"NUMBER" identifies a beta or release candidate number starting at 1, for
|
||||
example:
|
||||
|
||||
1.0b1
|
||||
1.0b2
|
||||
1.0rc1
|
||||
|
||||
|
||||
PGP Public Key
|
||||
--------------
|
||||
|
||||
The following PGP public key can be used for signing security messages.
|
||||
|
||||
```
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Comment: GPGTools - https://gpgtools.org
|
||||
|
||||
mQINBF6L0RgBEAC8FTqc/1Al+pWW+ULE0OB2qdbiA2NBjEm0X0WhvpjkqihS1Oih
|
||||
ij3fzFxKJ+DgutQyDb4QFD8tCFL0f0rtNL1Iz8TtiAJjvlhL4kG5cdq5HYEchO10
|
||||
qFeZ1DqvnHXB4pbKouEQ7Q/FqB1PG+m6y2q1ntgW+VPKm/nFUWBCmhTQicY3FOEG
|
||||
q9r90enc8vhQGOX4p01KR0+izI/g+97pWgMMj5N4zHuXV/GrPhlVgo3Wn1OfEuX4
|
||||
9vmv7GX4G17Me3E3LOo0c6fmPHJsrRG5oifLpvEJXVZW/RhJR3/pKMPSI5gW8Sal
|
||||
lKAkNeV7aZG3U0DCiIVL6E4FrqXP4PPj1KBixtxOHqzQW8EJwuqbszNN3vp9w6jM
|
||||
GvGtl8w5Qrw/BwnGC6Dmw+Qv04p9JRY2lygzZYcKuwZbLzBdC2CYy7P2shoKiymX
|
||||
ARv+i+bUl6OmtDe2aYaqRkNDgJkpuVInBlMHwOyLP6fN2o7ETXQZ+0a1vQsgjmD+
|
||||
Mngkc44HRnzsIJ3Ga4WwW8ggnAwUzJ/DgJFYOSbRUF/djBT4/EFoU+/kjXRqq8/d
|
||||
c8HjZtz2L27njmMw68/bYmY1TliLp50PXGzJA/KeY90stwKtTI0ufwAyi9i9BaYq
|
||||
cGbdq5jnfSNMDdKW2kLCNTQeUWSSytMTsdU0Av3Jrv5KQF8x5GaXcpCOTwARAQAB
|
||||
tExNaWNoYWVsIFN3ZWV0IChzZWN1cml0eUBtc3dlZXQub3JnKSAoU2VjdXJpdHkg
|
||||
UEdQIEtleSkgPHNlY3VyaXR5QG1zd2VldC5vcmc+iQJUBBMBCgA+FiEEOElfSXYU
|
||||
h91AF0sBpZiItz2feQIFAl6L0RgCGwMFCQeGH4AFCwkIBwMFFQoJCAsFFgIDAQAC
|
||||
HgECF4AACgkQpZiItz2feQIhjhAAqZHuQJkPBsAKUvJtPiyunpR6JENTUIDxnVXG
|
||||
nue+Zev+B7PzQ7C4CAx7vXwuWTt/BXoyQFKRUrm+YGiBTvLYQ8fPqudDnycSaf/A
|
||||
n01Ushdlhyg1wmCBGHTgt29IkEZphNj6BebRd675RTOSD5y14jrqUb+gxRNuNDa5
|
||||
ZiZBlBE4A8TV6nvlCyLP5oXyTvKQRFCh4dEiL5ZvpoxnhNvJpSe1ohL8iJ9aeAd5
|
||||
JdakOKi8MmidRPYC5IldXwduW7VC7dtqSiPqT5aSN0GJ8nIhSpn/ZkOEAPHAtxxa
|
||||
0VgjltXwUDktu74MUUghdg2vC1df2Z+PqHLsGEqOmxoBIJYXroIqSEpO3Ma7hz0r
|
||||
Xg1AWHMR/xxiLXLxgaZRvTp7AlaNjbqww8JDG8g+nDIeGsgIwWN/6uPczledvDQa
|
||||
HtlMfN97i+rt6sCu13UMZHpBKOGg7eAGRhgpOwpUqmlW1b+ojRHGkmZ8oJSE7sFT
|
||||
gzSGNkmfVgA1ILl0mi8OBVZ4jlUg6EgVsiPlzolH92iscK7g50PdjzpQe0m3gmcL
|
||||
dpOmSL8Fti05dPfamJzIvJd28kMZ6yMnACKj9rq/VpfgYBLK8dbNUjEOQ2oq7PyR
|
||||
Ye/LE1OmAJwfZQkyQNI8yAFXoRJ8u3/bRb3SPvGGWquGBDKHv2K1XiCW65uyLe5B
|
||||
RNJWmme5Ag0EXovRGAEQAJZMFeIMt/ocLskrp89ZyBTTiavFKn9+QW7C2Mb36A73
|
||||
J2g9vRFBSRizb+t8lSzP/T1GbKS0cEmfEpQppWImTbOMV6ZgxrM0IUy1Yd7Kyc0K
|
||||
oNMZvykRYwVMzxB5hiQ88kCLfqTNCveIvu1xcB9pWkf+cuDmGCxA3I+yc3Eh/SOP
|
||||
urDsHObt7fyEmJpSxCXlMFHRCuWyGXhMNvhR186t9mANW0PyxKJ8efr+2Vhm1+pA
|
||||
Vk9JESac/lREvx9PVFmlPdqgqRkQ0TQB5+ROo9Wy77cxQr5+rvSZZff630I1YgZf
|
||||
Ph6xOV1/q6vJ3RBNA2nPSTjPeeWQ7pTn7PZGJwCjIUjhMbO+EJVKUJNOAEg033mG
|
||||
tLfbFUYdhA/dRgFuKz90loCMfsnf3e4o/TFydSHUuwBUtOWkL1BBWEbk95M/Zr00
|
||||
w5fD9knas1u5Lc4ogXzTFPnvJ6hM1RAFJEd+FYzJZIvzwrIx4Ag1DOKViVBpeLTu
|
||||
HWj+xckEgvxEBglplALzfSIJ0CLQSNL8iMFbzCnPeUoQfPkqu37KHrB9syAA06Tb
|
||||
qw1Ax0qBqKInGIgBd0w6dFLF3s04xVcPAXWyJ0w4I7h2bs+aD6YwwK6xxCtXxtN5
|
||||
Q1LQM8s3tKNXER3mZ8zfwgwjsdLVwhXhysFi6Dlkvk/Vrbn1QDfJnzq+F9LsGRGb
|
||||
ABEBAAGJAjwEGAEKACYWIQQ4SV9JdhSH3UAXSwGlmIi3PZ95AgUCXovRGAIbDAUJ
|
||||
B4YfgAAKCRClmIi3PZ95AhDZD/40fShzDS/smZZL0oXN4GgZ62FrXWBdLjontkXo
|
||||
d8hDh1wJZwqsLVbtO2Gu0CPeH9GclQ3bYsR19sGMM4FDgjMu57O/TU6GZl2Ywcjh
|
||||
ayhRTHyAq/BKZn71AM0N7LS8MdNTaLbTbzEu5oGbAmOVv5f0SUnQoGxbeF8ih5bo
|
||||
hR3ZcORujWMgnymL3+cerNyIDQAtfMAUTfpVcwem4CvquA9Wjtur8YN1t+N7I3o2
|
||||
eMTNSyNUL9Yx3NxbyJ0yrrMvASo+ZVRaPW5+ET9Iqd68ILSY04Gnar3URJssggX8
|
||||
+cuyEbP9bAG8qYqcr2aSC2dW84mL/RnZGR//1dfS0Ugk6Osj0LSF5i+mz0CbIjYQ
|
||||
PKgLlgpycuGZBC5kG3RWWfanM0HxPDx10a7vEWA1A5Q+csx4yi3CW/giC1zAdhUO
|
||||
cJ1l4Uj/oxpGeLN7BnT/2NzU/px2fpbaG+xU4HlwjzFM2cIOUIohHFhdvFZbFIIA
|
||||
mePqTBnEB3HtXYRTgMoYDXLWhlOXjyVnMR45WDfvEA3KqbAz6sNMtaOJ6rHBWnR1
|
||||
1YbpvDWUeaGSLXBoGyo3RgTrN9jON8lE/oUxFobnEdfZGD+uwIniylc5rw3+VkBU
|
||||
+QGZDfgPgxjSmKsWq1cK6rNfBacGYrdyqf90VemEsvR8r0Ump0RPzBMlAAq0Xkup
|
||||
WkiKlA==
|
||||
=0GzT
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
```
|
BIN
afl-input/PDFBOX-1010-0.pdf
Normal file
BIN
afl-input/PDFBOX-1010-0.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1018-0.pdf
Normal file
BIN
afl-input/PDFBOX-1018-0.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1023-2.pdf
Normal file
BIN
afl-input/PDFBOX-1023-2.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1029-0.pdf
Normal file
BIN
afl-input/PDFBOX-1029-0.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1036-0.pdf
Normal file
BIN
afl-input/PDFBOX-1036-0.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1036-2.pdf
Normal file
BIN
afl-input/PDFBOX-1036-2.pdf
Normal file
Binary file not shown.
55
afl-input/PDFBOX-1037-0.pdf
Normal file
55
afl-input/PDFBOX-1037-0.pdf
Normal file
@ -0,0 +1,55 @@
|
||||
%PDF-1.3
|
||||
1 0 obj<</Type/Catalog/Pages 5 0 R>>
endobj
3 0 obj<</ModDate(D:20110505091515-05'00')/CreationDate(2011/05/05 09:15)/Creator(PaperPort 11.0)/Producer(PaperPort 11.0)/Subject()/Author()/Keywords()/Title()>>
endobj
4 0 obj<</Type/Page/MediaBox[0 0 622.0799 756]/Parent 5 0 R/CropBox[0 0 622.0799 756]/Contents 7 0 R/Resources<</ProcSet[/PDF/Text/ImageB/ImageC/ImageI]/XObject<</Z_Im0 6 0 R>>>>>>
endobj
5 0 obj<</Count 1/Type/Pages/Kids[ 4 0 R]>>
endobj
6 0 obj<</Type/XObject/Subtype/Image/Name/XImg/Width 1728/Height 2100/BitsPerComponent 1/ColorSpace/DeviceGray/Intent//Filter[/CCITTFaxDecode]/DecodeParms[<</Colors 1/Columns 1728/Rows 2100/K -1>>]/Length 81592>>stream
|
||||
endstream
endobj
7 0 obj<</Length 72>>stream
|
||||
q
|
||||
622.07996 0 0 756 0 0 cm
|
||||
0 g
|
||||
[]0 d 1 w 10 M 0 i 0 J 0 j
|
||||
/Z_Im0 Do
|
||||
Q
|
||||
|
||||
endstream
endobj
xref
0 8
0000000002 65535 f
0000000010 00000 n
0000000000 00000 f
0000000054 00000 n
0000000224 00000 n
0000000412 00000 n
0000000463 00000 n
0000082294 00000 n
trailer
<</Size 8/Info 3 0 R/Root 1 0 R/ID[<c48c2a5922382dc456a05f8e3ccbb9f8><94a076a2f82a754598b70200e827ac8b>]>>
startxref
82414
%%EOF
%PaperPortPDFversion3 0 obj<</ModDate(D:20110505091515-05'00')/CreationDate(2011/05/05 09:15)/Creator(PaperPort 11.0)/Producer(PaperPort 11.0)/Subject()/Author()/Keywords()/Title()>>
endobj
5 0 obj<</Count 2/Type/Pages/Kids[ 4 0 R 8 0 R]>>
endobj
8 0 obj<</Type/Page/MediaBox[0 0 622.0799 757.4399]/Parent 5 0 R/CropBox[0 0 622.0799 757.4399]/Contents 10 0 R/Resources<</ProcSet[/PDF/Text/ImageB/ImageC/ImageI]/XObject<</Z_Im0 9 0 R>>>>>>
endobj
9 0 obj<</Type/XObject/Subtype/Image/Name/XImg/Width 1728/Height 2104/BitsPerComponent 1/ColorSpace/DeviceGray/Intent//Filter[/CCITTFaxDecode]/DecodeParms[<</Colors 1/Columns 1728/Rows 2104/K -1>>]/Length 78404>>stream
|
||||
endstream
endobj
10 0 obj<</Length 78>>stream
|
||||
q
|
||||
622.07996 0 0 757.44001 0 0 cm
|
||||
0 g
|
||||
[]0 d 1 w 10 M 0 i 0 J 0 j
|
||||
/Z_Im0 Do
|
||||
Q
|
||||
|
||||
endstream
endobj
xref
3 1
0000082740 00000 n
5 1
0000082910 00000 n
8 3
0000082967 00000 n
0000083166 00000 n
0000161809 00000 n
trailer
<</Size 11/Info 3 0 R/Root 1 0 R/Prev 82414/ID[<c48c2a5922382dc456a05f8e3ccbb9f8><f24b17829b5b7d0a1c465f420f329749>]/ModDate<323031312f30352f30352030393a3135>>>
startxref
161936
%%EOF
%PaperPortPDFversion3 0 obj<</ModDate(D:20110505091515-05'00')/CreationDate(2011/05/05 09:15)/Creator(PaperPort 11.0)/Producer(PaperPort 11.0)/Subject()/Author()/Keywords()/Title()>>
endobj
5 0 obj<</Count 3/Type/Pages/Kids[ 4 0 R 8 0 R 11 0 R]>>
endobj
11 0 obj<</Type/Page/MediaBox[0 0 622.0799 756]/Parent 5 0 R/CropBox[0 0 622.0799 756]/Contents 13 0 R/Resources<</ProcSet[/PDF/Text/ImageB/ImageC/ImageI]/XObject<</Z_Im0 12 0 R>>>>>>
endobj
12 0 obj<</Type/XObject/Subtype/Image/Name/XImg/Width 1728/Height 2100/BitsPerComponent 1/ColorSpace/DeviceGray/Intent//Filter[/CCITTFaxDecode]/DecodeParms[<</Colors 1/Columns 1728/Rows 2100/K -1>>]/Length 54254>>stream
|
||||
endstream
endobj
13 0 obj<</Length 72>>stream
|
||||
q
|
||||
622.07996 0 0 756 0 0 cm
|
||||
0 g
|
||||
[]0 d 1 w 10 M 0 i 0 J 0 j
|
||||
/Z_Im0 Do
|
||||
Q
|
||||
|
||||
endstream
endobj
xref
3 1
0000162265 00000 n
5 1
0000162435 00000 n
11 3
0000162499 00000 n
0000162690 00000 n
0000217184 00000 n
trailer
<</Size 14/Info 3 0 R/Root 1 0 R/Prev 161936/ID[<c48c2a5922382dc456a05f8e3ccbb9f8><9aa5e9665a233edacdaf8c59bb333297>]/ModDate<323031312f30352f30352030393a3135>>>
startxref
217305
%%EOF
%PaperPortPDFversion3 0 obj<</ModDate(D:20110505091515-05'00')/CreationDate(2011/05/05 09:15)/Creator(PaperPort 11.0)/Producer(PaperPort 11.0)/Subject()/Author()/Keywords()/Title()>>
endobj
5 0 obj<</Count 4/Type/Pages/Kids[ 4 0 R 8 0 R 11 0 R 14 0 R]>>
endobj
14 0 obj<</Type/Page/MediaBox[0 0 622.0799 756.7199]/Parent 5 0 R/CropBox[0 0 622.0799 756.7199]/Contents 16 0 R/Resources<</ProcSet[/PDF/Text/ImageB/ImageC/ImageI]/XObject<</Z_Im0 15 0 R>>>>>>
endobj
15 0 obj<</Type/XObject/Subtype/Image/Name/XImg/Width 1728/Height 2102/BitsPerComponent 1/ColorSpace/DeviceGray/Intent//Filter[/CCITTFaxDecode]/DecodeParms[<</Colors 1/Columns 1728/Rows 2102/K -1>>]/Length 34868>>stream
|
||||
endstream
endobj
16 0 obj<</Length 78>>stream
|
||||
q
|
||||
622.07996 0 0 756.71997 0 0 cm
|
||||
0 g
|
||||
[]0 d 1 w 10 M 0 i 0 J 0 j
|
||||
/Z_Im0 Do
|
||||
Q
|
||||
|
||||
endstream
endobj
xref
3 1
0000217636 00000 n
5 1
0000217806 00000 n
14 3
0000217877 00000 n
0000218078 00000 n
0000253186 00000 n
trailer
<</Size 17/Info 3 0 R/Root 1 0 R/Prev 217305/ID[<c48c2a5922382dc456a05f8e3ccbb9f8><2f1845afe4a234a536a5f4a6f4a3ab07>]/ModDate<323031312f30352f30352030393a3135>>>
startxref
253313
%%EOF
%PaperPortPDFversion3 0 obj<</ModDate(D:20110505091515-05'00')/CreationDate(2011/05/05 09:15)/Creator(PaperPort 11.0)/Producer(PaperPort 11.0)/Subject()/Author()/Keywords()/Title()>>
endobj
5 0 obj<</Count 5/Type/Pages/Kids[ 4 0 R 8 0 R 11 0 R 14 0 R 17 0 R]>>
endobj
17 0 obj<</Type/Page/MediaBox[0 0 622.0799 757.7999]/Parent 5 0 R/CropBox[0 0 622.0799 757.7999]/Contents 19 0 R/Resources<</ProcSet[/PDF/Text/ImageB/ImageC/ImageI]/XObject<</Z_Im0 18 0 R>>>>>>
endobj
18 0 obj<</Type/XObject/Subtype/Image/Name/XImg/Width 1728/Height 2105/BitsPerComponent 1/ColorSpace/DeviceGray/Intent//Filter[/CCITTFaxDecode]/DecodeParms[<</Colors 1/Columns 1728/Rows 2105/K -1>>]/Length 32754>>stream
|
||||
endstream
endobj
19 0 obj<</Length 78>>stream
|
||||
q
|
||||
622.07996 0 0 757.79999 0 0 cm
|
||||
0 g
|
||||
[]0 d 1 w 10 M 0 i 0 J 0 j
|
||||
/Z_Im0 Do
|
||||
Q
|
||||
|
||||
endstream
endobj
xref
3 1
0000253644 00000 n
5 1
0000253814 00000 n
17 3
0000253892 00000 n
0000254093 00000 n
0000287087 00000 n
trailer
<</Size 20/Info 3 0 R/Root 1 0 R/Prev 253313/ID[<c48c2a5922382dc456a05f8e3ccbb9f8><ddbf432ecb92ee136898cc6a6aa59d25>]/ModDate<323031312f30352f30352030393a3135>>>
startxref
287214
%%EOF
%PaperPortPDFversion3 0 obj<</ModDate(D:20110505091515-05'00')/CreationDate(2011/05/05 09:15)/Creator(PaperPort 11.0)/Producer(PaperPort 11.0)/Subject()/Author()/Keywords()/Title()>>
endobj
5 0 obj<</Count 6/Type/Pages/Kids[ 4 0 R 8 0 R 11 0 R 14 0 R 17 0 R 20 0 R]>>
endobj
20 0 obj<</Type/Page/MediaBox[0 0 622.0799 766.4399]/Parent 5 0 R/CropBox[0 0 622.0799 766.4399]/Contents 22 0 R/Resources<</ProcSet[/PDF/Text/ImageB/ImageC/ImageI]/XObject<</Z_Im0 21 0 R>>>>>>
endobj
endstream
endobj
22 0 obj<</Length 78>>stream
|
||||
q
|
||||
622.07996 0 0 766.44001 0 0 cm
|
||||
0 g
|
||||
[]0 d 1 w 10 M 0 i 0 J 0 j
|
||||
/Z_Im0 Do
|
||||
Q
|
||||
|
||||
endstream
endobj
xref
3 1
0000287545 00000 n
5 1
0000287715 00000 n
20 3
0000287800 00000 n
0000288001 00000 n
0000310229 00000 n
trailer
<</Size 23/Info 3 0 R/Root 1 0 R/Prev 287214/ID[<c48c2a5922382dc456a05f8e3ccbb9f8><bf0eb2735397b3aa034aea285fb8ec4a>]/ModDate<323031312f30352f30352030393a3135>>>
startxref
310356
%%EOF
%PaperPortPDFversion
|
BIN
afl-input/PDFBOX-1039-0.pdf
Normal file
BIN
afl-input/PDFBOX-1039-0.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1047-0.pdf
Normal file
BIN
afl-input/PDFBOX-1047-0.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1048-1.pdf
Normal file
BIN
afl-input/PDFBOX-1048-1.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1065-0.pdf
Normal file
BIN
afl-input/PDFBOX-1065-0.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1065-1.pdf
Normal file
BIN
afl-input/PDFBOX-1065-1.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1067-1.pdf
Normal file
BIN
afl-input/PDFBOX-1067-1.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1068-1.pdf
Normal file
BIN
afl-input/PDFBOX-1068-1.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1074-1.pdf
Normal file
BIN
afl-input/PDFBOX-1074-1.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1074-3.pdf
Normal file
BIN
afl-input/PDFBOX-1074-3.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1094-10.pdf
Normal file
BIN
afl-input/PDFBOX-1094-10.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1094-13.pdf
Normal file
BIN
afl-input/PDFBOX-1094-13.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1094-15.pdf
Normal file
BIN
afl-input/PDFBOX-1094-15.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1094-3.pdf
Normal file
BIN
afl-input/PDFBOX-1094-3.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1094-33.pdf
Normal file
BIN
afl-input/PDFBOX-1094-33.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1094-4.pdf
Normal file
BIN
afl-input/PDFBOX-1094-4.pdf
Normal file
Binary file not shown.
BIN
afl-input/PDFBOX-1095-2.pdf
Normal file
BIN
afl-input/PDFBOX-1095-2.pdf
Normal file
Binary file not shown.
1466
afl-pdf.dict
Normal file
1466
afl-pdf.dict
Normal file
File diff suppressed because it is too large
Load Diff
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
320
configure.ac
Normal file
320
configure.ac
Normal file
@ -0,0 +1,320 @@
|
||||
dnl
|
||||
dnl Configuration script for PDFio
|
||||
dnl
|
||||
dnl Copyright © 2023-2025 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.5.2], [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 date/time functionality...
|
||||
AC_CHECK_FUNC([timegm], [
|
||||
AC_DEFINE([HAVE_TIMEGM], [1], [Do we have the timegm function?])
|
||||
CPPFLAGS="-DHAVE_TIMEGM=1 $CPPFLAGS"
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING([for tm_gmtoff member in tm structure])
|
||||
AC_COMPILE_IFELSE([
|
||||
AC_LANG_PROGRAM([[#include <time.h>]], [[
|
||||
struct tm t;
|
||||
int o = t.tm_gmtoff;
|
||||
]])
|
||||
], [
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([HAVE_TM_GMTOFF], [1], [Have tm_gmtoff member in struct tm?])
|
||||
CPPFLAGS="-DHAVE_TM_GMTOFF=1 $CPPFLAGS"
|
||||
], [
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
|
||||
|
||||
dnl Check for pkg-config, which is used for some other tests later on...
|
||||
AC_PATH_TOOL([PKGCONFIG], [pkg-config])
|
||||
|
||||
PKGCONFIG_CFLAGS="-I\${includedir}"
|
||||
PKGCONFIG_LIBS="-L\${libdir} -lpdfio"
|
||||
PKGCONFIG_LIBS_PRIVATE="-lm"
|
||||
PKGCONFIG_REQUIRES="zlib"
|
||||
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 libpng...
|
||||
AC_ARG_ENABLE([libpng], AS_HELP_STRING([--enable-libpng], [use libpng for pdfioFileCreateImageObjFromFile, default=auto]))
|
||||
|
||||
PKGCONFIG_LIBPNG=""
|
||||
AC_SUBST([PKGCONFIG_LIBPNG])
|
||||
|
||||
AS_IF([test "x$PKGCONFIG" != x -a x$enable_libpng != xno], [
|
||||
AC_MSG_CHECKING([for libpng-1.6.x])
|
||||
AS_IF([$PKGCONFIG --exists libpng16], [
|
||||
AC_MSG_RESULT([yes]);
|
||||
AC_DEFINE([HAVE_LIBPNG], 1, [Have PNG library?])
|
||||
CPPFLAGS="$($PKGCONFIG --cflags libpng16) -DHAVE_LIBPNG=1 $CPPFLAGS"
|
||||
LIBS="$($PKGCONFIG --libs libpng16) -lz $LIBS"
|
||||
PKGCONFIG_LIBS_PRIVATE="$($PKGCONFIG --libs libpng16) $PKGCONFIG_LIBS_PRIVATE"
|
||||
PKGCONFIG_REQUIRES="libpng >= 1.6,$PKGCONFIG_REQUIRES"
|
||||
], [
|
||||
AC_MSG_RESULT([no]);
|
||||
AS_IF([test x$enable_libpng = xyes], [
|
||||
AC_MSG_ERROR([libpng-dev 1.6 or later required for --enable-libpng.])
|
||||
])
|
||||
])
|
||||
], [test x$enable_libpng = xyes], [
|
||||
AC_MSG_ERROR([libpng-dev 1.6 or later required for --enable-libpng.])
|
||||
])
|
||||
|
||||
|
||||
dnl Library target...
|
||||
AC_ARG_ENABLE([static], AS_HELP_STRING([--disable-static], [do not install static library]))
|
||||
AC_ARG_ENABLE([shared], AS_HELP_STRING([--enable-shared], [install shared library]))
|
||||
|
||||
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
|
Binary file not shown.
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
BIN
doc/pdfio-epub.png
Normal file
BIN
doc/pdfio-epub.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 788 KiB |
2379
doc/pdfio.3
2379
doc/pdfio.3
File diff suppressed because it is too large
Load Diff
2500
doc/pdfio.html
2500
doc/pdfio.html
File diff suppressed because it is too large
Load Diff
1987
doc/pdfio.md
1987
doc/pdfio.md
File diff suppressed because it is too large
Load Diff
71
examples/Makefile
Normal file
71
examples/Makefile
Normal file
@ -0,0 +1,71 @@
|
||||
#
|
||||
# Makefile for PDFio examples.
|
||||
#
|
||||
# Copyright © 2024-2025 by Michael R Sweet.
|
||||
#
|
||||
# Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
# information.
|
||||
#
|
||||
|
||||
# POSIX makefile
|
||||
.POSIX:
|
||||
|
||||
|
||||
# Common options
|
||||
CFLAGS = -g $(CPPFLAGS)
|
||||
#CFLAGS = -g -fsanitize=address $(CPPFLAGS)
|
||||
CPPFLAGS = -I.. $(shell PKG_CONFIG_PATH="..:$(PKG_CONFIG_PATH)" pkg-config pdfio --cflags)
|
||||
LIBS = -L.. $(shell PKG_CONFIG_PATH="..:$(PKG_CONFIG_PATH)" pkg-config pdfio --libs)
|
||||
|
||||
|
||||
# Targets
|
||||
TARGETS = \
|
||||
code128 \
|
||||
image2pdf \
|
||||
md2pdf \
|
||||
pdf2text \
|
||||
pdfioinfo \
|
||||
pdfiomerge
|
||||
|
||||
|
||||
# Make everything
|
||||
all: $(TARGETS)
|
||||
|
||||
|
||||
# Clean everything
|
||||
clean:
|
||||
rm -f $(TARGETS)
|
||||
|
||||
|
||||
# code128
|
||||
code128: code128.c
|
||||
$(CC) $(CFLAGS) -o $@ code128.c $(LIBS)
|
||||
|
||||
|
||||
# image2pdf
|
||||
image2pdf: image2pdf.c
|
||||
$(CC) $(CFLAGS) -o $@ image2pdf.c $(LIBS)
|
||||
|
||||
|
||||
# md2pdf
|
||||
md2pdf: md2pdf.c mmd.c mmd.h
|
||||
$(CC) $(CFLAGS) -o $@ md2pdf.c mmd.c $(LIBS)
|
||||
|
||||
|
||||
# pdfio text extraction (demo, doesn't handle a lot of things yet)
|
||||
pdf2text: pdf2text.c
|
||||
$(CC) $(CFLAGS) -o $@ pdf2text.c $(LIBS)
|
||||
|
||||
|
||||
# pdfioinfo
|
||||
pdfioinfo: pdfioinfo.c
|
||||
$(CC) $(CFLAGS) -o $@ pdfioinfo.c $(LIBS)
|
||||
|
||||
|
||||
# pdfiomerge
|
||||
pdfiomerge: pdfiomerge.c
|
||||
$(CC) $(CFLAGS) -o $@ pdfiomerge.c $(LIBS)
|
||||
|
||||
|
||||
# Common dependencies...
|
||||
$(TARGETS): Makefile ../pdfio.h ../pdfio-content.h
|
BIN
examples/Roboto-Bold.ttf
Normal file
BIN
examples/Roboto-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.
93
examples/Roboto-LICENSE.txt
Normal file
93
examples/Roboto-LICENSE.txt
Normal file
@ -0,0 +1,93 @@
|
||||
Copyright 2011 The Roboto Project Authors (https://github.com/googlefonts/roboto-classic)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
examples/Roboto-Regular.ttf
Normal file
BIN
examples/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.
343
examples/code128-LICENSE.txt
Normal file
343
examples/code128-LICENSE.txt
Normal file
@ -0,0 +1,343 @@
|
||||
Copyright 2003 Grandzebu, All Rights Reserved
|
||||
|
||||
http://grandzebu.net/informatique/codbar-en/code128.htm
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
208
examples/code128.c
Normal file
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.
148
examples/image2pdf.c
Normal file
148
examples/image2pdf.c
Normal file
@ -0,0 +1,148 @@
|
||||
//
|
||||
// Image example for PDFio.
|
||||
//
|
||||
// Copyright © 2023-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./image2pdf FILENAME.{jpg,png} FILENAME.pdf ["TEXT"]
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <pdfio-content.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//
|
||||
// 'create_pdf_image_file()' - Create a PDF file of an image with optional caption.
|
||||
//
|
||||
|
||||
bool // O - True on success, false on failure
|
||||
create_pdf_image_file(
|
||||
const char *imagename, // I - Image filename
|
||||
const char *pdfname, // I - PDF filename
|
||||
const char *caption) // I - Caption filename
|
||||
{
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
pdfio_obj_t *font; // Caption font
|
||||
pdfio_obj_t *image; // Image
|
||||
pdfio_dict_t *dict; // Page dictionary
|
||||
pdfio_stream_t *page; // Page stream
|
||||
double width, height; // Width and height of image
|
||||
double swidth, sheight; // Scaled width and height on page
|
||||
double tx, ty; // Position on page
|
||||
|
||||
|
||||
// Default the caption...
|
||||
if (!caption)
|
||||
{
|
||||
if ((caption = strrchr(imagename, '/')) != NULL)
|
||||
caption ++;
|
||||
else
|
||||
caption = imagename;
|
||||
}
|
||||
|
||||
// Create the PDF file...
|
||||
pdf = pdfioFileCreate(pdfname, /*version*/NULL, /*media_box*/NULL,
|
||||
/*crop_box*/NULL, /*error_cb*/NULL,
|
||||
/*error_cbdata*/NULL);
|
||||
if (!pdf)
|
||||
return (false);
|
||||
|
||||
// Create a Courier base font for the caption
|
||||
font = pdfioFileCreateFontObjFromBase(pdf, "Courier");
|
||||
|
||||
if (!font)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Create an image object from the JPEG/PNG image file...
|
||||
image = pdfioFileCreateImageObjFromFile(pdf, imagename, true);
|
||||
|
||||
if (!image)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Create a page dictionary with the font and image...
|
||||
dict = pdfioDictCreate(pdf);
|
||||
pdfioPageDictAddFont(dict, "F1", font);
|
||||
pdfioPageDictAddImage(dict, "IM1", image);
|
||||
|
||||
// Create the page and its content stream...
|
||||
page = pdfioFileCreatePage(pdf, dict);
|
||||
|
||||
// Position and scale the image on the page...
|
||||
width = pdfioImageGetWidth(image);
|
||||
height = pdfioImageGetHeight(image);
|
||||
|
||||
// Default media_box is "universal" 595.28x792 points (8.27x11in or
|
||||
// 210x279mm). Use margins of 36 points (0.5in or 12.7mm) with another
|
||||
// 36 points for the caption underneath...
|
||||
swidth = 595.28 - 72.0;
|
||||
sheight = swidth * height / width;
|
||||
if (sheight > (792.0 - 36.0 - 72.0))
|
||||
{
|
||||
sheight = 792.0 - 36.0 - 72.0;
|
||||
swidth = sheight * width / height;
|
||||
}
|
||||
|
||||
tx = 0.5 * (595.28 - swidth);
|
||||
ty = 0.5 * (792 - 36 - sheight);
|
||||
|
||||
pdfioContentDrawImage(page, "IM1", tx, ty + 36.0, swidth, sheight);
|
||||
|
||||
// Draw the caption in black...
|
||||
pdfioContentSetFillColorDeviceGray(page, 0.0);
|
||||
|
||||
// Compute the starting point for the text - Courier is monospaced
|
||||
// with a nominal width of 0.6 times the text height...
|
||||
tx = 0.5 * (595.28 - 18.0 * 0.6 * strlen(caption));
|
||||
|
||||
// Position and draw the caption underneath...
|
||||
pdfioContentTextBegin(page);
|
||||
pdfioContentSetTextFont(page, "F1", 18.0);
|
||||
pdfioContentTextMoveTo(page, tx, ty);
|
||||
pdfioContentTextShow(page, /*unicode*/false, caption);
|
||||
pdfioContentTextEnd(page);
|
||||
|
||||
// Close the page stream and the PDF file...
|
||||
pdfioStreamClose(page);
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Produce a single-page file from an image.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // I - Command-line arguments
|
||||
{
|
||||
const char *imagefile, // Image filename
|
||||
*pdffile, // PDF filename
|
||||
*caption; // Caption text
|
||||
|
||||
|
||||
// Get the image file, PDF file, and optional caption text from the command-line...
|
||||
if (argc < 3 || argc > 4)
|
||||
{
|
||||
fputs("Usage: image2pdf FILENAME.{jpg,png} FILENAME.pdf [\"TEXT\"]\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
imagefile = argv[1];
|
||||
pdffile = argv[2];
|
||||
caption = argv[3];
|
||||
|
||||
return (create_pdf_image_file(imagefile, pdffile, caption) ? 0 : 1);
|
||||
}
|
1865
examples/md2pdf.c
Normal file
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
|
1420
examples/pdf2text.c
Normal file
1420
examples/pdf2text.c
Normal file
File diff suppressed because it is too large
Load Diff
162
examples/pdfioinfo.c
Normal file
162
examples/pdfioinfo.c
Normal file
@ -0,0 +1,162 @@
|
||||
//
|
||||
// PDF metadata example for PDFio.
|
||||
//
|
||||
// Copyright © 2023-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./pdfioinfo FILENAME.pdf
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Open a PDF file and show its metadata.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // Command-line arguments
|
||||
{
|
||||
const char *filename; // PDF filename
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
pdfio_dict_t *catalog; // Catalog dictionary
|
||||
const char *author, // Author name
|
||||
*creator, // Creator name
|
||||
*producer, // Producer name
|
||||
*title; // Title
|
||||
time_t creation_date, // Creation date
|
||||
modification_date; // Modification date
|
||||
struct tm *creation_tm, // Creation date/time information
|
||||
*modification_tm; // Modification date/time information
|
||||
char creation_text[256], // Creation date/time as a string
|
||||
modification_text[256], // Modification date/time human fmt string
|
||||
range_text[255]; // Page range text
|
||||
size_t num_pages; // PDF number of pages
|
||||
bool has_acroform; // Does the file have an AcroForm?
|
||||
pdfio_obj_t *page; // Object
|
||||
pdfio_dict_t *page_dict; // Object dictionary
|
||||
size_t cur, // Current page index
|
||||
prev; // Previous page index
|
||||
pdfio_rect_t cur_box, // Current MediaBox
|
||||
prev_box; // Previous MediaBox
|
||||
|
||||
|
||||
// Get the filename from the command-line...
|
||||
if (argc != 2)
|
||||
{
|
||||
fputs("Usage: ./pdfioinfo FILENAME.pdf\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
filename = argv[1];
|
||||
|
||||
// Open the PDF file with the default callbacks...
|
||||
pdf = pdfioFileOpen(filename, /*password_cb*/NULL,
|
||||
/*password_cbdata*/NULL, /*error_cb*/NULL,
|
||||
/*error_cbdata*/NULL);
|
||||
if (pdf == NULL)
|
||||
return (1);
|
||||
|
||||
// Get the title, author, etc...
|
||||
catalog = pdfioFileGetCatalog(pdf);
|
||||
author = pdfioFileGetAuthor(pdf);
|
||||
creator = pdfioFileGetCreator(pdf);
|
||||
has_acroform = pdfioDictGetType(catalog, "AcroForm") != PDFIO_VALTYPE_NONE;
|
||||
num_pages = pdfioFileGetNumPages(pdf);
|
||||
producer = pdfioFileGetProducer(pdf);
|
||||
title = pdfioFileGetTitle(pdf);
|
||||
|
||||
// Get the creation date and convert to a string...
|
||||
if ((creation_date = pdfioFileGetCreationDate(pdf)) > 0)
|
||||
{
|
||||
creation_tm = localtime(&creation_date);
|
||||
strftime(creation_text, sizeof(creation_text), "%c", creation_tm);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(creation_text, sizeof(creation_text), "-- not set --");
|
||||
}
|
||||
|
||||
// Get the modification date and convert to a string...
|
||||
if ((modification_date = pdfioFileGetModificationDate(pdf)) > 0)
|
||||
{
|
||||
modification_tm = localtime(&modification_date);
|
||||
strftime(modification_text, sizeof(modification_text), "%c", modification_tm);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(modification_text, sizeof(modification_text), "-- not set --");
|
||||
}
|
||||
|
||||
// Print file information to stdout...
|
||||
printf("%s:\n", filename);
|
||||
printf(" Title: %s\n", title ? title : "-- not set --");
|
||||
printf(" Author: %s\n", author ? author : "-- not set --");
|
||||
printf(" Creator: %s\n", creator ? creator : "-- not set --");
|
||||
printf(" Producer: %s\n", producer ? producer : "-- not set --");
|
||||
printf(" Created On: %s\n", creation_text);
|
||||
printf(" Modified On: %s\n", modification_text);
|
||||
printf(" Version: %s\n", pdfioFileGetVersion(pdf));
|
||||
printf(" AcroForm: %s\n", has_acroform ? "Yes" : "No");
|
||||
printf(" Number of Pages: %u\n", (unsigned)num_pages);
|
||||
|
||||
// Report the MediaBox for all of the pages
|
||||
prev_box.x1 = prev_box.x2 = prev_box.y1 = prev_box.y2 = 0.0;
|
||||
|
||||
for (cur = 0, prev = 0; cur < num_pages; cur ++)
|
||||
{
|
||||
// Find the MediaBox for this page in the page tree...
|
||||
for (page = pdfioFileGetPage(pdf, cur);
|
||||
page != NULL;
|
||||
page = pdfioDictGetObj(page_dict, "Parent"))
|
||||
{
|
||||
cur_box.x1 = cur_box.x2 = cur_box.y1 = cur_box.y2 = 0.0;
|
||||
page_dict = pdfioObjGetDict(page);
|
||||
|
||||
if (pdfioDictGetRect(page_dict, "MediaBox", &cur_box))
|
||||
break;
|
||||
}
|
||||
|
||||
// If this MediaBox is different from the previous one, show the range of
|
||||
// pages that have that size...
|
||||
if (cur == 0 ||
|
||||
fabs(cur_box.x1 - prev_box.x1) > 0.01 ||
|
||||
fabs(cur_box.y1 - prev_box.y1) > 0.01 ||
|
||||
fabs(cur_box.x2 - prev_box.x2) > 0.01 ||
|
||||
fabs(cur_box.y2 - prev_box.y2) > 0.01)
|
||||
{
|
||||
if (cur > prev)
|
||||
{
|
||||
snprintf(range_text, sizeof(range_text), "Pages %u-%u",
|
||||
(unsigned)(prev + 1), (unsigned)cur);
|
||||
printf("%16s: [%g %g %g %g]\n", range_text,
|
||||
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
|
||||
}
|
||||
|
||||
// Start a new series of pages with the new size...
|
||||
prev = cur;
|
||||
prev_box = cur_box;
|
||||
}
|
||||
}
|
||||
|
||||
// Show the last range as needed...
|
||||
if (cur > prev)
|
||||
{
|
||||
snprintf(range_text, sizeof(range_text), "Pages %u-%u",
|
||||
(unsigned)(prev + 1), (unsigned)cur);
|
||||
printf("%16s: [%g %g %g %g]\n", range_text,
|
||||
prev_box.x1, prev_box.y1, prev_box.x2, prev_box.y2);
|
||||
}
|
||||
|
||||
// Close the PDF file...
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
return (0);
|
||||
}
|
146
examples/pdfiomerge.c
Normal file
146
examples/pdfiomerge.c
Normal file
@ -0,0 +1,146 @@
|
||||
//
|
||||
// PDF merge program for PDFio.
|
||||
//
|
||||
// Copyright © 2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./pdfmerge [-o OUTPUT.pdf] INPUT.pdf [... INPUT.pdf]
|
||||
// ./pdfmerge INPUT.pdf [... INPUT.pdf] >OUTPUT.pdf
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
static ssize_t output_cb(void *output_cbdata, const void *buffer, size_t bytes);
|
||||
static int usage(FILE *out);
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Main entry.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // I - Command-line arguments
|
||||
{
|
||||
int i; // Looping var
|
||||
const char *opt; // Current option
|
||||
pdfio_file_t *inpdf, // Input PDF file
|
||||
*outpdf = NULL; // Output PDF file
|
||||
|
||||
|
||||
// Parse command-line...
|
||||
for (i = 1; i < argc; i ++)
|
||||
{
|
||||
if (!strcmp(argv[i], "--help"))
|
||||
{
|
||||
return (usage(stdout));
|
||||
}
|
||||
else if (!strncmp(argv[i], "--", 2))
|
||||
{
|
||||
fprintf(stderr, "pdfmerge: Unknown option '%s'.\n", argv[i]);
|
||||
return (usage(stderr));
|
||||
}
|
||||
else if (argv[i][0] == '-')
|
||||
{
|
||||
for (opt = argv[i] + 1; *opt; opt ++)
|
||||
{
|
||||
switch (*opt)
|
||||
{
|
||||
case 'o' : // -o OUTPUT.pdf
|
||||
if (outpdf)
|
||||
{
|
||||
fputs("pdfmerge: Only one output file can be specified.\n", stderr);
|
||||
return (usage(stderr));
|
||||
}
|
||||
|
||||
i ++;
|
||||
if (i >= argc)
|
||||
{
|
||||
fputs("pdfmerge: Missing output filename after '-o'.\n", stderr);
|
||||
return (usage(stderr));
|
||||
}
|
||||
|
||||
if ((outpdf = pdfioFileCreate(argv[i], /*version*/NULL, /*media_box*/NULL, /*crop_box*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
return (1);
|
||||
break;
|
||||
|
||||
default :
|
||||
fprintf(stderr, "pdfmerge: Unknown option '-%c'.\n", *opt);
|
||||
return (usage(stderr));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((inpdf = pdfioFileOpen(argv[i], /*password_cb*/NULL, /*password_data*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy PDF file...
|
||||
size_t p, // Current page
|
||||
nump; // Number of pages
|
||||
|
||||
if (!outpdf)
|
||||
{
|
||||
if ((outpdf = pdfioFileCreateOutput(output_cb, /*output_cbdata*/NULL, /*version*/NULL, /*media_box*/NULL, /*crop_box*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
return (1);
|
||||
}
|
||||
|
||||
for (p = 0, nump = pdfioFileGetNumPages(inpdf); p < nump; p ++)
|
||||
{
|
||||
if (!pdfioPageCopy(outpdf, pdfioFileGetPage(inpdf, p)))
|
||||
return (1);
|
||||
}
|
||||
|
||||
pdfioFileClose(inpdf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!outpdf)
|
||||
return (usage(stderr));
|
||||
|
||||
pdfioFileClose(outpdf);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'output_cb()' - Write PDF data to the standard output...
|
||||
//
|
||||
|
||||
static ssize_t // O - Number of bytes written
|
||||
output_cb(void *output_cbdata, // I - Callback data (not used)
|
||||
const void *buffer, // I - Buffer to write
|
||||
size_t bytes) // I - Number of bytes to write
|
||||
{
|
||||
(void)output_cbdata;
|
||||
|
||||
return ((ssize_t)fwrite(buffer, 1, bytes, stdout));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'usage()' - Show program usage.
|
||||
//
|
||||
|
||||
static int // O - Exit status
|
||||
usage(FILE *out) // I - stdout or stderr
|
||||
{
|
||||
fputs("Usage: pdfmerge [OPTIONS] INPUT.pdf [... INPUT.pdf] >OUTPUT.pdf\n", out);
|
||||
fputs("Options:\n", out);
|
||||
fputs(" --help Show help.\n", out);
|
||||
fputs(" -o OUTPUT.pdf Send output to filename instead of stdout.\n", out);
|
||||
|
||||
return (out == stdout ? 0 : 1);
|
||||
}
|
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
|
84
makesrcdist
84
makesrcdist
@ -2,18 +2,90 @@
|
||||
#
|
||||
# makesrcdist - make a source distribution of pdfio.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ./makesrcdist [--snapshot] VERSION
|
||||
#
|
||||
|
||||
if test $# != 1; then
|
||||
echo "Usage: ./makesrcdist version"
|
||||
exit 1
|
||||
# Support "--snapshot" option...
|
||||
if test "$1" == "--snapshot"; then
|
||||
shift
|
||||
snapshot=1
|
||||
else
|
||||
snapshot=0
|
||||
fi
|
||||
|
||||
# Get version...
|
||||
if test $# != 1; then
|
||||
echo "Usage: ./makesrcdist [--snapshot] VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
status=0
|
||||
version=$1
|
||||
version_major=$(echo $1 | awk -F. '{print $1}')
|
||||
version_minor=$(echo $1 | awk -F. '{print $2}')
|
||||
|
||||
echo Creating tag for release...
|
||||
git tag -m "Tag $version" v$version
|
||||
git push origin v$version
|
||||
# Check that version number has been updated everywhere...
|
||||
if test $(grep AC_INIT configure.ac | awk '{print $2}') != "[$version],"; then
|
||||
echo "Still need to update AC_INIT version in 'configure.ac'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(head -4 CHANGES.md | tail -1 | awk '{print $1}') != "v$version"; then
|
||||
echo "Still need to update CHANGES.md version number."
|
||||
status=1
|
||||
fi
|
||||
if test $(head -4 CHANGES.md | tail -1 | awk '{print $3}') = "YYYY-MM-DD"; then
|
||||
echo "Still need to update CHANGES.md release date."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(grep PDFIO_VERSION= configure | awk -F \" '{print $2}') != "$version"; then
|
||||
echo "Still need to run 'autoconf -f'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(grep '<version>' pdfio_native.nuspec | sed -E -e '1,$s/^.*<version>([0-9.]+).*$/\1/') != "$version"; then
|
||||
echo "Still need to update version in 'pdfio_native.nuspec'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(grep '<version>' pdfio_native.redist.nuspec | sed -E -e '1,$s/^.*<version>([0-9.]+).*$/\1/') != "$version"; then
|
||||
echo "Still need to update version in 'pdfio_native.redist.nuspec'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(grep PDFIO_VERSION pdfio.h | awk -F \" '{print $2}') != "$version"; then
|
||||
echo "Still need to update PDFIO_VERSION in 'pdfio.h'."
|
||||
status=1
|
||||
fi
|
||||
if test $(grep PDFIO_VERSION_MAJOR pdfio.h | awk '{print $4}') != "$version_major"; then
|
||||
echo "Still need to update PDFIO_VERSION_MAJOR in 'pdfio.h'."
|
||||
status=1
|
||||
fi
|
||||
if test $(grep PDFIO_VERSION_MINOR pdfio.h | awk '{print $4}') != "$version_minor"; then
|
||||
echo "Still need to update PDFIO_VERSION_MINOR in 'pdfio.h'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(grep VERSION pdfio1.def | awk '{print $2}') != "$version_major.$version_minor"; then
|
||||
echo "Still need to update VERSION in 'pdfio1.def'."
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $status = 1; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Tag release...
|
||||
if test $snapshot = 0; then
|
||||
echo Creating tag for release...
|
||||
git tag -m "Tag $version" v$version
|
||||
git push origin v$version
|
||||
fi
|
||||
|
||||
# Make source archives...
|
||||
echo Creating pdfio-$version.tar.gz...
|
||||
git archive --format tar --prefix=pdfio-$version/ HEAD | gzip -v9 >pdfio-$version.tar.gz
|
||||
gpg --detach-sign pdfio-$version.tar.gz
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="libpng_native" version="1.6.30" targetFramework="native" />
|
||||
<package id="libpng_native.redist" version="1.6.30" targetFramework="native" />
|
||||
<package id="zlib_native" version="1.2.11" targetFramework="native" />
|
||||
<package id="zlib_native.redist" version="1.2.11" targetFramework="native" />
|
||||
</packages>
|
570
pdfio-aes.c
Normal file
570
pdfio-aes.c
Normal file
@ -0,0 +1,570 @@
|
||||
//
|
||||
// AES functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// AES code is adapted from the "tiny-AES-c" project
|
||||
// (<https://github.com/kokke/tiny-AES-c>)
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
//
|
||||
// Local types...
|
||||
//
|
||||
|
||||
typedef uint8_t state_t[4][4]; // 4x4 AES state table @private@
|
||||
|
||||
|
||||
//
|
||||
// Local globals...
|
||||
//
|
||||
|
||||
static const uint8_t sbox[256] = // S-box lookup table
|
||||
{
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||
};
|
||||
static const uint8_t rsbox[256] = // Reverse S-box lookup table
|
||||
{
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||
};
|
||||
|
||||
// The round constant word array, Rcon[i], contains the values given by
|
||||
// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
|
||||
static const uint8_t Rcon[11] = // Round constants
|
||||
{
|
||||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
static void add_round_key(size_t round, state_t *state, const uint8_t *round_key);
|
||||
static void sub_bytes(state_t *state);
|
||||
static void shift_rows(state_t *state);
|
||||
static uint8_t xtime(uint8_t x);
|
||||
static void mix_columns(state_t *state);
|
||||
static uint8_t multiply(uint8_t x, uint8_t y);
|
||||
static void inv_mix_columns(state_t *state);
|
||||
static void inv_sub_bytes(state_t *state);
|
||||
static void inv_shift_rows(state_t *state);
|
||||
static void cipher(state_t *state, const _pdfio_aes_t *ctx);
|
||||
static void inv_cipher(state_t *state, const _pdfio_aes_t *ctx);
|
||||
static void xor_with_iv(uint8_t *buf, const uint8_t *Iv);
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioCryptoAESInit()' - Initialize an AES context.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioCryptoAESInit(
|
||||
_pdfio_aes_t *ctx, // I - AES context
|
||||
const uint8_t *key, // I - Key
|
||||
size_t keylen, // I - Length of key (must be 16 or 32)
|
||||
const uint8_t *iv) // I - 16-byte initialization vector
|
||||
{
|
||||
size_t i; // Looping var
|
||||
uint8_t *rkptr0, // Previous round_key values
|
||||
*rkptr, // Current round_key values
|
||||
*rkend, // End of round_key values
|
||||
tempa[4]; // Used for the column/row operations
|
||||
size_t nwords = keylen / 4; // Number of 32-bit words in key
|
||||
|
||||
|
||||
// Clear context
|
||||
memset(ctx, 0, sizeof(_pdfio_aes_t));
|
||||
ctx->round_size = keylen / 4 + 6;
|
||||
|
||||
// The first round key is the key itself.
|
||||
memcpy(ctx->round_key, key, keylen);
|
||||
|
||||
// All other round keys are found from the previous round keys.
|
||||
for (rkptr0 = ctx->round_key, rkptr = rkptr0 + keylen, rkend = rkptr + 16 * ctx->round_size, i = nwords; rkptr < rkend; i ++)
|
||||
{
|
||||
if ((i % nwords) == 0)
|
||||
{
|
||||
// Shifts word left once - [a0,a1,a2,a3] becomes [a1,a2,a3,a0], then
|
||||
// apply the S-box to each of the four bytes to produce an output word.
|
||||
tempa[0] = sbox[rkptr[-3]] ^ Rcon[i / nwords];
|
||||
tempa[1] = sbox[rkptr[-2]];
|
||||
tempa[2] = sbox[rkptr[-1]];
|
||||
tempa[3] = sbox[rkptr[-4]];
|
||||
}
|
||||
else if (keylen == 32 && (i % nwords) == 4)
|
||||
{
|
||||
// Apply the S-box to each of the four bytes to produce an output word.
|
||||
tempa[0] = sbox[rkptr[-4]];
|
||||
tempa[1] = sbox[rkptr[-3]];
|
||||
tempa[2] = sbox[rkptr[-2]];
|
||||
tempa[3] = sbox[rkptr[-1]];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use unshifted values without S-box...
|
||||
tempa[0] = rkptr[-4];
|
||||
tempa[1] = rkptr[-3];
|
||||
tempa[2] = rkptr[-2];
|
||||
tempa[3] = rkptr[-1];
|
||||
}
|
||||
|
||||
// TODO: Optimize to incorporate this into previous steps
|
||||
*rkptr++ = *rkptr0++ ^ tempa[0];
|
||||
*rkptr++ = *rkptr0++ ^ tempa[1];
|
||||
*rkptr++ = *rkptr0++ ^ tempa[2];
|
||||
*rkptr++ = *rkptr0++ ^ tempa[3];
|
||||
}
|
||||
|
||||
// Copy the initialization vector...
|
||||
if (iv)
|
||||
memcpy(ctx->iv, iv, sizeof(ctx->iv));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioCryptoAESDecrypt()' - Decrypt a block of bytes with AES.
|
||||
//
|
||||
// "inbuffer" and "outbuffer" can point to the same memory. Length must be a
|
||||
// multiple of 16 bytes (excess is not decrypted).
|
||||
//
|
||||
|
||||
size_t // O - Number of bytes in output buffer
|
||||
_pdfioCryptoAESDecrypt(
|
||||
_pdfio_aes_t *ctx, // I - AES context
|
||||
uint8_t *outbuffer, // I - Output buffer
|
||||
const uint8_t *inbuffer, // I - Input buffer
|
||||
size_t len) // I - Number of bytes to decrypt
|
||||
{
|
||||
uint8_t next_iv[16]; // Next IV value
|
||||
size_t outbytes = 0; // Output bytes
|
||||
|
||||
|
||||
if (inbuffer != outbuffer)
|
||||
{
|
||||
// Not the most efficient, but we can optimize later - the sample AES code
|
||||
// manipulates the data directly in memory and doesn't support separate
|
||||
// input and output buffers...
|
||||
memcpy(outbuffer, inbuffer, len);
|
||||
}
|
||||
|
||||
while (len > 15)
|
||||
{
|
||||
memcpy(next_iv, outbuffer, 16);
|
||||
inv_cipher((state_t *)outbuffer, ctx);
|
||||
xor_with_iv(outbuffer, ctx->iv);
|
||||
memcpy(ctx->iv, next_iv, 16);
|
||||
outbuffer += 16;
|
||||
len -= 16;
|
||||
outbytes += 16;
|
||||
}
|
||||
|
||||
return (outbytes);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioCryptoAESEncrypt()' - Encrypt a block of bytes with AES.
|
||||
//
|
||||
// "inbuffer" and "outbuffer" can point to the same memory. "outbuffer" must
|
||||
// be a multiple of 16 bytes.
|
||||
//
|
||||
|
||||
size_t // O - Number of bytes in output buffer
|
||||
_pdfioCryptoAESEncrypt(
|
||||
_pdfio_aes_t *ctx, // I - AES context
|
||||
uint8_t *outbuffer, // I - Output buffer
|
||||
const uint8_t *inbuffer, // I - Input buffer
|
||||
size_t len) // I - Number of bytes to decrypt
|
||||
{
|
||||
uint8_t *iv = ctx->iv; // Current IV for CBC
|
||||
size_t outbytes = 0; // Output bytes
|
||||
|
||||
|
||||
if (len == 0)
|
||||
return (0);
|
||||
|
||||
if (inbuffer != outbuffer)
|
||||
{
|
||||
// Not the most efficient, but we can optimize later - the sample AES code
|
||||
// manipulates the data directly in memory and doesn't support separate
|
||||
// input and output buffers...
|
||||
memcpy(outbuffer, inbuffer, len);
|
||||
}
|
||||
|
||||
while (len > 15)
|
||||
{
|
||||
xor_with_iv(outbuffer, iv);
|
||||
cipher((state_t*)outbuffer, ctx);
|
||||
iv = outbuffer;
|
||||
outbuffer += 16;
|
||||
len -= 16;
|
||||
outbytes += 16;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
// Pad the final buffer with (16 - len)...
|
||||
memset(outbuffer + len, (int)(16 - len), 16 - len);
|
||||
|
||||
xor_with_iv(outbuffer, iv);
|
||||
cipher((state_t*)outbuffer, ctx);
|
||||
iv = outbuffer;
|
||||
outbytes += 16;
|
||||
}
|
||||
|
||||
/* store Iv in ctx for next call */
|
||||
memcpy(ctx->iv, iv, 16);
|
||||
|
||||
return (outbytes);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'add_round_key()' - Add the round key to state.
|
||||
//
|
||||
// The round key is added to the state by an XOR function.
|
||||
//
|
||||
|
||||
static void
|
||||
add_round_key(size_t round, // I - Which round
|
||||
state_t *state, // I - Current state
|
||||
const uint8_t *round_key) // I - Key
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
|
||||
|
||||
for (round_key += round * 16, i = 16; i > 0; i --, sptr ++, round_key ++)
|
||||
*sptr ^= *round_key;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'sub_bytes()' - Substitute the values in the state matrix with values in an S-box.
|
||||
//
|
||||
|
||||
static void
|
||||
sub_bytes(state_t *state) // I - Current state
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
|
||||
|
||||
for (i = 16; i > 0; i --, sptr ++)
|
||||
*sptr = sbox[*sptr];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'shift_rows()' - Shift the rows in the state to the left.
|
||||
//
|
||||
// Each row is shifted with different offset.
|
||||
// Offset = Row number. So the first row is not shifted.
|
||||
//
|
||||
|
||||
static void
|
||||
shift_rows(state_t *state) // I - Current state
|
||||
{
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
uint8_t temp; // Temporary value
|
||||
|
||||
|
||||
// Rotate first row 1 columns to left
|
||||
temp = sptr[1];
|
||||
sptr[1] = sptr[5];
|
||||
sptr[5] = sptr[9];
|
||||
sptr[9] = sptr[13];
|
||||
sptr[13] = temp;
|
||||
|
||||
// Rotate second row 2 columns to left
|
||||
temp = sptr[2];
|
||||
sptr[2] = sptr[10];
|
||||
sptr[10] = temp;
|
||||
|
||||
temp = sptr[6];
|
||||
sptr[6] = sptr[14];
|
||||
sptr[14] = temp;
|
||||
|
||||
// Rotate third row 3 columns to left
|
||||
temp = sptr[3];
|
||||
sptr[3] = sptr[15];
|
||||
sptr[15] = sptr[11];
|
||||
sptr[11] = sptr[7];
|
||||
sptr[7] = temp;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'xtime()' - Compute the AES xtime function.
|
||||
//
|
||||
|
||||
static uint8_t // O - xtime(x)
|
||||
xtime(uint8_t x) // I - Column value
|
||||
{
|
||||
return ((uint8_t)((x << 1) ^ ((x >> 7) * 0x1b)));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'mix_columns()' - Mix the columns of the state matrix.
|
||||
//
|
||||
|
||||
static void
|
||||
mix_columns(state_t *state) // I - Current state
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
uint8_t Tmp, Tm, t; // Temporary values
|
||||
|
||||
|
||||
for (i = 4; i > 0; i --, sptr += 4)
|
||||
{
|
||||
t = sptr[0];
|
||||
Tmp = sptr[0] ^ sptr[1] ^ sptr[2] ^ sptr[3];
|
||||
Tm = sptr[0] ^ sptr[1];
|
||||
Tm = xtime(Tm);
|
||||
sptr[0] ^= Tm ^ Tmp;
|
||||
|
||||
Tm = sptr[1] ^ sptr[2];
|
||||
Tm = xtime(Tm);
|
||||
sptr[1] ^= Tm ^ Tmp;
|
||||
|
||||
Tm = sptr[2] ^ sptr[3];
|
||||
Tm = xtime(Tm);
|
||||
sptr[2] ^= Tm ^ Tmp;
|
||||
|
||||
Tm = sptr[3] ^ t;
|
||||
Tm = xtime(Tm);
|
||||
sptr[3] ^= Tm ^ Tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'multiply()' - Multiply numbers in the field GF(2^8)
|
||||
//
|
||||
// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary
|
||||
// The compiler seems to be able to vectorize the operation better this way.
|
||||
// See https://github.com/kokke/tiny-AES-c/pull/34
|
||||
//
|
||||
|
||||
static uint8_t multiply(uint8_t x, uint8_t y)
|
||||
{
|
||||
return (((y & 1) * x) ^
|
||||
((y>>1 & 1) * xtime(x)) ^
|
||||
((y>>2 & 1) * xtime(xtime(x))) ^
|
||||
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^
|
||||
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'mix_columns()' - Mix the columns of the state matrix.
|
||||
//
|
||||
// The method used to multiply may be difficult to understand for the inexperienced.
|
||||
// Please use the references to gain more information.
|
||||
//
|
||||
|
||||
static void
|
||||
inv_mix_columns(state_t *state) // I - Current state
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
uint8_t a, b, c, d; // Temporary values
|
||||
|
||||
|
||||
for (i = 4; i > 0; i --)
|
||||
{
|
||||
a = sptr[0];
|
||||
b = sptr[1];
|
||||
c = sptr[2];
|
||||
d = sptr[3];
|
||||
|
||||
*sptr++ = multiply(a, 0x0e) ^ multiply(b, 0x0b) ^ multiply(c, 0x0d) ^ multiply(d, 0x09);
|
||||
*sptr++ = multiply(a, 0x09) ^ multiply(b, 0x0e) ^ multiply(c, 0x0b) ^ multiply(d, 0x0d);
|
||||
*sptr++ = multiply(a, 0x0d) ^ multiply(b, 0x09) ^ multiply(c, 0x0e) ^ multiply(d, 0x0b);
|
||||
*sptr++ = multiply(a, 0x0b) ^ multiply(b, 0x0d) ^ multiply(c, 0x09) ^ multiply(d, 0x0e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'sub_bytes()' - Substitute the values in the state matrix with values in an S-box.
|
||||
//
|
||||
|
||||
static void
|
||||
inv_sub_bytes(state_t *state) // I - Current state
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
|
||||
|
||||
for (i = 16; i > 0; i --, sptr ++)
|
||||
*sptr = rsbox[*sptr];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'inv_shift_rows()' - Shift the rows in the state to the right.
|
||||
//
|
||||
|
||||
static void
|
||||
inv_shift_rows(state_t *state) // I - Current state
|
||||
{
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
uint8_t temp; // Temporary value
|
||||
|
||||
|
||||
// Rotate first row 1 columns to right
|
||||
temp = sptr[13];
|
||||
sptr[13] = sptr[9];
|
||||
sptr[9] = sptr[5];
|
||||
sptr[5] = sptr[1];
|
||||
sptr[1] = temp;
|
||||
|
||||
// Rotate second row 2 columns to right
|
||||
temp = sptr[2];
|
||||
sptr[2] = sptr[10];
|
||||
sptr[10] = temp;
|
||||
|
||||
temp = sptr[6];
|
||||
sptr[6] = sptr[14];
|
||||
sptr[14] = temp;
|
||||
|
||||
// Rotate third row 3 columns to right
|
||||
temp = sptr[3];
|
||||
sptr[3] = sptr[7];
|
||||
sptr[7] = sptr[11];
|
||||
sptr[11] = sptr[15];
|
||||
sptr[15] = temp;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'cipher()' - Encrypt the PlainText.
|
||||
//
|
||||
|
||||
static void
|
||||
cipher(state_t *state, // I - Current state
|
||||
const _pdfio_aes_t *ctx) // I - AES context
|
||||
{
|
||||
size_t round = 0; // Current round
|
||||
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
add_round_key(0, state, ctx->round_key);
|
||||
|
||||
// There will be Nr rounds.
|
||||
// The first Nr-1 rounds are identical.
|
||||
// These Nr rounds are executed in the loop below.
|
||||
// Last one without mix_columns()
|
||||
for (round = 1; round < ctx->round_size; round ++)
|
||||
{
|
||||
sub_bytes(state);
|
||||
shift_rows(state);
|
||||
mix_columns(state);
|
||||
add_round_key(round, state, ctx->round_key);
|
||||
}
|
||||
|
||||
// Add round key to last round
|
||||
sub_bytes(state);
|
||||
shift_rows(state);
|
||||
add_round_key(ctx->round_size, state, ctx->round_key);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'inv_cipher()' - Decrypt the CipherText.
|
||||
//
|
||||
|
||||
static void
|
||||
inv_cipher(state_t *state, // I - Current state
|
||||
const _pdfio_aes_t *ctx) // I - AES context
|
||||
{
|
||||
size_t round; // Current round
|
||||
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
add_round_key(ctx->round_size, state, ctx->round_key);
|
||||
|
||||
// There will be Nr rounds.
|
||||
// The first Nr-1 rounds are identical.
|
||||
// These Nr rounds are executed in the loop below.
|
||||
// Last one without InvMixColumn()
|
||||
for (round = ctx->round_size - 1; ; round --)
|
||||
{
|
||||
inv_shift_rows(state);
|
||||
inv_sub_bytes(state);
|
||||
add_round_key(round, state, ctx->round_key);
|
||||
|
||||
if (round == 0)
|
||||
break;
|
||||
|
||||
inv_mix_columns(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'xor_with_iv()' - XOR a block with the initialization vector.
|
||||
//
|
||||
|
||||
static void
|
||||
xor_with_iv(uint8_t *buf, // I - Block
|
||||
const uint8_t *Iv) // I - Initialization vector
|
||||
{
|
||||
// 16-byte block...
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
*buf++ ^= *Iv++;
|
||||
}
|
@ -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);
|
||||
@ -357,9 +380,16 @@ _pdfioArrayDebug(pdfio_array_t *a, // I - Array
|
||||
void
|
||||
_pdfioArrayDelete(pdfio_array_t *a) // I - Array
|
||||
{
|
||||
if (a)
|
||||
free(a->values);
|
||||
size_t i; // Looping var
|
||||
|
||||
|
||||
for (i = 0; i < a->num_values; i ++)
|
||||
{
|
||||
if (a->values[i].type == PDFIO_VALTYPE_BINARY)
|
||||
free(a->values[i].value.binary.data);
|
||||
}
|
||||
|
||||
free(a->values);
|
||||
free(a);
|
||||
}
|
||||
|
||||
@ -389,17 +419,26 @@ pdfioArrayGetBinary(
|
||||
size_t n, // I - Index
|
||||
size_t *length) // O - Length of string
|
||||
{
|
||||
if (!a || n >= a->num_values || a->values[n].type != PDFIO_VALTYPE_BINARY || !length)
|
||||
if (!a || n >= a->num_values || (a->values[n].type != PDFIO_VALTYPE_BINARY && a->values[n].type != PDFIO_VALTYPE_STRING))
|
||||
{
|
||||
if (length)
|
||||
*length = 0;
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
else if (a->values[n].type == PDFIO_VALTYPE_BINARY)
|
||||
{
|
||||
if (length)
|
||||
*length = a->values[n].value.binary.datalen;
|
||||
|
||||
return (a->values[n].value.binary.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
*length = a->values[n].value.binary.datalen;
|
||||
return (a->values[n].value.binary.data);
|
||||
if (length)
|
||||
*length = strlen(a->values[n].value.string);
|
||||
|
||||
return ((unsigned char *)a->values[n].value.string);
|
||||
}
|
||||
}
|
||||
|
||||
@ -558,7 +597,9 @@ _pdfioArrayGetValue(pdfio_array_t *a, // I - Array
|
||||
|
||||
pdfio_array_t * // O - New array
|
||||
_pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfio_token_t *tb) // I - Token buffer/stack
|
||||
pdfio_obj_t *obj, // I - Object, if any
|
||||
_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
size_t depth) // I - Depth of array
|
||||
{
|
||||
pdfio_array_t *array; // New array
|
||||
char token[8192]; // Token from file
|
||||
@ -568,7 +609,8 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
|
||||
PDFIO_DEBUG("_pdfioArrayRead(pdf=%p, tb=%p)\n", pdf, tb);
|
||||
|
||||
// Create an array...
|
||||
array = pdfioArrayCreate(pdf);
|
||||
if ((array = pdfioArrayCreate(pdf)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
// Read until we get "]" to end the array...
|
||||
while (_pdfioTokenGet(tb, token, sizeof(token)))
|
||||
@ -581,7 +623,7 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
// Push the token and decode the value...
|
||||
_pdfioTokenPush(tb, token);
|
||||
if (!_pdfioValueRead(pdf, tb, &value))
|
||||
if (!_pdfioValueRead(pdf, obj, tb, &value, depth))
|
||||
break;
|
||||
|
||||
// PDFIO_DEBUG("_pdfioArrayRead(%p): Appending ", (void *)array);
|
||||
@ -595,12 +637,35 @@ _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.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` otherwise
|
||||
_pdfioArrayWrite(pdfio_array_t *a) // I - Array
|
||||
_pdfioArrayWrite(pdfio_array_t *a, // I - Array
|
||||
pdfio_obj_t *obj) // I - Object, if any
|
||||
{
|
||||
pdfio_file_t *pdf = a->pdf; // PDF file
|
||||
size_t i; // Looping var
|
||||
@ -614,7 +679,7 @@ _pdfioArrayWrite(pdfio_array_t *a) // I - Array
|
||||
// Write each value...
|
||||
for (i = a->num_values, v = a->values; i > 0; i --, v ++)
|
||||
{
|
||||
if (!_pdfioValueWrite(pdf, v, NULL))
|
||||
if (!_pdfioValueWrite(pdf, obj, v, NULL))
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
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 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -38,6 +34,8 @@ _pdfioFileConsume(pdfio_file_t *pdf, // I - PDF file
|
||||
else if (_pdfioFileSeek(pdf, (off_t)bytes, SEEK_CUR) < 0)
|
||||
return (false);
|
||||
|
||||
PDFIO_DEBUG("_pdfioFileConsume: pos=%ld\n", (long)(pdf->bufpos + pdf->bufptr - pdf->buffer));
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
@ -100,7 +98,7 @@ _pdfioFileFlush(pdfio_file_t *pdf) // I - PDF file
|
||||
if (!write_buffer(pdf, pdf->buffer, (size_t)(pdf->bufptr - pdf->buffer)))
|
||||
return (false);
|
||||
|
||||
pdf->bufpos += pdf->bufptr - pdf->buffer;
|
||||
pdf->bufpos += (off_t)(pdf->bufptr - pdf->buffer);
|
||||
}
|
||||
|
||||
pdf->bufptr = pdf->buffer;
|
||||
@ -143,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)
|
||||
{
|
||||
@ -218,7 +216,7 @@ _pdfioFilePeek(pdfio_file_t *pdf, // I - PDF file
|
||||
PDFIO_DEBUG("_pdfioFilePeek: Sliding buffer, total=%ld\n", (long)total);
|
||||
|
||||
memmove(pdf->buffer, pdf->bufptr, total);
|
||||
pdf->bufpos += pdf->bufptr - pdf->buffer;
|
||||
pdf->bufpos += (off_t)(pdf->bufptr - pdf->buffer);
|
||||
pdf->bufptr = pdf->buffer;
|
||||
pdf->bufend = pdf->buffer + total;
|
||||
|
||||
@ -263,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...
|
||||
@ -319,16 +317,21 @@ _pdfioFileRead(pdfio_file_t *pdf, // I - PDF file
|
||||
// Advance current position in file as needed...
|
||||
if (pdf->bufend)
|
||||
{
|
||||
pdf->bufpos += pdf->bufend - pdf->buffer;
|
||||
pdf->bufpos += (off_t)(pdf->bufend - pdf->buffer);
|
||||
pdf->bufptr = pdf->bufend = NULL;
|
||||
}
|
||||
|
||||
// Read directly from the file...
|
||||
if ((rbytes = read_buffer(pdf, bufptr, bytes)) > 0)
|
||||
{
|
||||
pdf->bufpos += rbytes;
|
||||
pdf->bufpos += (off_t)rbytes;
|
||||
continue;
|
||||
}
|
||||
else if (rbytes < 0 && (errno == EINTR || errno == EAGAIN))
|
||||
{
|
||||
rbytes = 0;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
@ -353,30 +356,35 @@ _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 + (off_t)(pdf->bufptr - pdf->buffer);
|
||||
whence = SEEK_SET;
|
||||
}
|
||||
|
||||
if (pdf->mode == _PDFIO_MODE_READ)
|
||||
{
|
||||
// Reading, see if we already have the data we need...
|
||||
if (whence != SEEK_END && offset >= pdf->bufpos && offset < (pdf->bufpos + pdf->bufend - pdf->buffer))
|
||||
if (whence != SEEK_END && offset >= pdf->bufpos && pdf->bufend && offset < (off_t)(pdf->bufpos + pdf->bufend - pdf->buffer))
|
||||
{
|
||||
// Yes, seek within existing buffer...
|
||||
pdf->bufptr = pdf->buffer + offset - pdf->bufpos;
|
||||
pdf->bufptr = pdf->buffer + (offset - pdf->bufpos);
|
||||
PDFIO_DEBUG("_pdfioFileSeek: Seek within buffer, bufpos=%ld.\n", (long)pdf->bufpos);
|
||||
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p, bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufend);
|
||||
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p(<%02X%02X...>), bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufptr[0] & 255, pdf->bufptr[1] & 255, pdf->bufend);
|
||||
return (offset);
|
||||
}
|
||||
|
||||
// No, reset the read buffer
|
||||
pdf->bufptr = pdf->bufend = NULL;
|
||||
}
|
||||
else if (pdf->output_cb)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to seek within output stream.");
|
||||
return (-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Writing, make sure we write any buffered data...
|
||||
@ -390,13 +398,16 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
// Seek within the file...
|
||||
if ((offset = lseek(pdf->fd, offset, whence)) < 0)
|
||||
if ((offset = lseek(pdf->fd, offset, whence)) < 0 && whence == SEEK_END && errno == EINVAL)
|
||||
offset = lseek(pdf->fd, 0, SEEK_SET);
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to seek within file - %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
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;
|
||||
@ -515,7 +526,7 @@ read_buffer(pdfio_file_t *pdf, // I - PDF file
|
||||
return (rbytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// 'write_buffer()' - Write a buffer to a PDF file.
|
||||
//
|
||||
@ -530,25 +541,37 @@ write_buffer(pdfio_file_t *pdf, // I - PDF file
|
||||
ssize_t wbytes; // Bytes written...
|
||||
|
||||
|
||||
// Write to the file...
|
||||
while (bytes > 0)
|
||||
if (pdf->output_cb)
|
||||
{
|
||||
while ((wbytes = write(pdf->fd, bufptr, bytes)) < 0)
|
||||
// Write to a stream...
|
||||
if ((pdf->output_cb)(pdf->output_ctx, buffer, bytes) < 0)
|
||||
{
|
||||
// Stop if we have an error that shouldn't be retried...
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
break;
|
||||
}
|
||||
|
||||
if (wbytes < 0)
|
||||
{
|
||||
// Hard error...
|
||||
_pdfioFileError(pdf, "Unable to write to file - %s", strerror(errno));
|
||||
_pdfioFileError(pdf, "Unable to write to output callback.");
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write to the file...
|
||||
while (bytes > 0)
|
||||
{
|
||||
while ((wbytes = write(pdf->fd, bufptr, bytes)) < 0)
|
||||
{
|
||||
// Stop if we have an error that shouldn't be retried...
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
break;
|
||||
}
|
||||
|
||||
bufptr += wbytes;
|
||||
bytes -= (size_t)wbytes;
|
||||
if (wbytes < 0)
|
||||
{
|
||||
// Hard error...
|
||||
_pdfioFileError(pdf, "Unable to write to file - %s", strerror(errno));
|
||||
return (false);
|
||||
}
|
||||
|
||||
bufptr += wbytes;
|
||||
bytes -= (size_t)wbytes;
|
||||
}
|
||||
}
|
||||
|
||||
return (true);
|
||||
|
1922
pdfio-content.c
1922
pdfio-content.c
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Public content header file for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -9,18 +9,7 @@
|
||||
|
||||
#ifndef PDFIO_CONTENT_H
|
||||
# define PDFIO_CONTENT_H
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
# include "pdfio.h"
|
||||
|
||||
|
||||
//
|
||||
// C++ magic...
|
||||
//
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif // __cplusplus
|
||||
@ -91,12 +80,13 @@ extern bool pdfioContentPathClose(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentPathCurve(pdfio_stream_t *st, double x1, double y1, double x2, double y2, double x3, double y3) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentPathCurve13(pdfio_stream_t *st, double x1, double y1, double x3, double y3) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentPathCurve23(pdfio_stream_t *st, double x2, double y2, double x3, double y3) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentPathEnd(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentPathLineTo(pdfio_stream_t *st, double x, double y) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentPathMoveTo(pdfio_stream_t *st, double x, double y) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentPathRect(pdfio_stream_t *st, double x, double y, double width, double height) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentRestore(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentSave(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentSetDashPattern(pdfio_stream_t *st, int phase, int on, int off) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentSetDashPattern(pdfio_stream_t *st, double phase, double on, double off) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentSetFillColorDeviceCMYK(pdfio_stream_t *st, double c, double m, double y, double k) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentSetFillColorDeviceGray(pdfio_stream_t *st, double g) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentSetFillColorDeviceRGB(pdfio_stream_t *st, double r, double g, double b) _PDFIO_PUBLIC;
|
||||
@ -125,16 +115,21 @@ 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;
|
||||
extern bool pdfioContentTextNextLine(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextShow(pdfio_stream_t *st, bool unicode, const char *s) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextShowf(pdfio_stream_t *st, bool unicode, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(3,4);
|
||||
extern bool pdfioContentTextShowf(pdfio_stream_t *st, bool unicode, const char *format, ...) _PDFIO_PUBLIC;
|
||||
extern bool pdfioContentTextShowJustified(pdfio_stream_t *st, bool unicode, size_t num_fragments, const double *offsets, const char * const *fragments) _PDFIO_PUBLIC;
|
||||
|
||||
// Resource helpers...
|
||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromBase(pdfio_file_t *pdf, const char *name) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromFile(pdfio_file_t *pdf, const char *filename, bool unicode) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateICCObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t datalen, size_t num_colors) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateICCObjFromFile(pdfio_file_t *pdf, const char *filename, size_t num_colors) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateImageObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t width, size_t height, size_t num_colors, pdfio_array_t *color_data, bool alpha, bool interpolate) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateImageObjFromFile(pdfio_file_t *pdf, const char *filename, bool interpolate) _PDFIO_PUBLIC;
|
||||
@ -150,10 +145,6 @@ extern bool pdfioPageDictAddFont(pdfio_dict_t *dict, const char *name, pdfio_ob
|
||||
extern bool pdfioPageDictAddImage(pdfio_dict_t *dict, const char *name, pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
|
||||
|
||||
//
|
||||
// C++ magic...
|
||||
//
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif // __cplusplus
|
||||
|
1120
pdfio-crypto.c
Normal file
1120
pdfio-crypto.c
Normal file
File diff suppressed because it is too large
Load Diff
333
pdfio-dict.c
333
pdfio-dict.c
@ -1,16 +1,12 @@
|
||||
//
|
||||
// PDF dictionary functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -21,6 +17,49 @@
|
||||
static int compare_pairs(_pdfio_pair_t *a, _pdfio_pair_t *b);
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictClear()' - Remove a key/value pair from a dictionary.
|
||||
//
|
||||
|
||||
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);
|
||||
|
||||
if (!dict || !key)
|
||||
return (false);
|
||||
|
||||
// See if the key is already set...
|
||||
if (dict->num_pairs > 0)
|
||||
{
|
||||
pkey.key = key;
|
||||
|
||||
if ((pair = (_pdfio_pair_t *)bsearch(&pkey, dict->pairs, dict->num_pairs, sizeof(_pdfio_pair_t), (int (*)(const void *, const void *))compare_pairs)) != NULL)
|
||||
{
|
||||
// Yes, remove it...
|
||||
if (pair->value.type == PDFIO_VALTYPE_BINARY)
|
||||
free(pair->value.value.binary.data);
|
||||
|
||||
idx = (size_t)(pair - dict->pairs);
|
||||
dict->num_pairs --;
|
||||
|
||||
if (idx < dict->num_pairs)
|
||||
memmove(pair, pair + 1, (dict->num_pairs - idx) * sizeof(_pdfio_pair_t));
|
||||
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictCopy()' - Copy a dictionary to a PDF file.
|
||||
//
|
||||
@ -126,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.
|
||||
//
|
||||
@ -138,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);
|
||||
@ -154,7 +220,18 @@ void
|
||||
_pdfioDictDelete(pdfio_dict_t *dict) // I - Dictionary
|
||||
{
|
||||
if (dict)
|
||||
{
|
||||
size_t i; // Looping var
|
||||
_pdfio_pair_t *pair; // Current pair
|
||||
|
||||
for (i = dict->num_pairs, pair = dict->pairs; i > 0; i --, pair ++)
|
||||
{
|
||||
if (pair->value.type == PDFIO_VALTYPE_BINARY)
|
||||
free(pair->value.value.binary.data);
|
||||
}
|
||||
|
||||
free(dict->pairs);
|
||||
}
|
||||
|
||||
free(dict);
|
||||
}
|
||||
@ -198,6 +275,11 @@ pdfioDictGetBinary(pdfio_dict_t *dict, // I - Dictionary
|
||||
*length = value->value.binary.datalen;
|
||||
return (value->value.binary.data);
|
||||
}
|
||||
else if (value && value->type == PDFIO_VALTYPE_STRING)
|
||||
{
|
||||
*length = strlen(value->value.string);
|
||||
return ((unsigned char *)value->value.string);
|
||||
}
|
||||
else
|
||||
{
|
||||
*length = 0;
|
||||
@ -260,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.
|
||||
//
|
||||
@ -278,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.
|
||||
//
|
||||
@ -354,9 +459,151 @@ pdfioDictGetString(pdfio_dict_t *dict, // I - Dictionary
|
||||
|
||||
|
||||
if (value && value->type == PDFIO_VALTYPE_STRING)
|
||||
{
|
||||
return (value->value.string);
|
||||
}
|
||||
else if (value && value->type == PDFIO_VALTYPE_BINARY && value->value.binary.datalen < 4096)
|
||||
{
|
||||
// Convert binary string to regular string...
|
||||
char temp[4096], // Temporary string
|
||||
*tempptr; // Pointer into temporary string
|
||||
unsigned char *dataptr; // Pointer into the data string
|
||||
|
||||
if (!(value->value.binary.datalen & 1) && !memcmp(value->value.binary.data, "\376\377", 2))
|
||||
{
|
||||
// Copy UTF-16 BE
|
||||
int ch; // Unicode character
|
||||
size_t remaining; // Remaining bytes
|
||||
|
||||
for (dataptr = value->value.binary.data + 2, remaining = value->value.binary.datalen - 2, tempptr = temp; remaining > 1 && tempptr < (temp + sizeof(temp) - 5); dataptr += 2, remaining -= 2)
|
||||
{
|
||||
ch = (dataptr[0] << 8) | dataptr[1];
|
||||
|
||||
if (ch >= 0xd800 && ch <= 0xdbff && remaining > 3)
|
||||
{
|
||||
// Multi-word UTF-16 char...
|
||||
int lch; // Lower bits
|
||||
|
||||
lch = (dataptr[2] << 8) | dataptr[3];
|
||||
|
||||
if (lch < 0xdc00 || lch >= 0xdfff)
|
||||
break;
|
||||
|
||||
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
|
||||
dataptr += 2;
|
||||
remaining -= 2;
|
||||
}
|
||||
else if (ch >= 0xfffe)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*tempptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 4096)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*tempptr++ = (char)(0xc0 | (ch >> 6));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else if (ch < 65536)
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 12));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 18));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
*tempptr = '\0';
|
||||
}
|
||||
else if (!(value->value.binary.datalen & 1) && !memcmp(value->value.binary.data, "\377\376", 2))
|
||||
{
|
||||
// Copy UTF-16 LE
|
||||
int ch; // Unicode character
|
||||
size_t remaining; // Remaining bytes
|
||||
|
||||
for (dataptr = value->value.binary.data + 2, remaining = value->value.binary.datalen - 2, tempptr = temp; remaining > 1 && tempptr < (temp + sizeof(temp) - 5); dataptr += 2, remaining -= 2)
|
||||
{
|
||||
ch = (dataptr[1] << 8) | dataptr[0];
|
||||
|
||||
if (ch >= 0xd800 && ch <= 0xdbff && remaining > 3)
|
||||
{
|
||||
// Multi-word UTF-16 char...
|
||||
int lch; // Lower bits
|
||||
|
||||
lch = (dataptr[3] << 8) | dataptr[2];
|
||||
|
||||
if (lch < 0xdc00 || lch >= 0xdfff)
|
||||
break;
|
||||
|
||||
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
|
||||
dataptr += 2;
|
||||
remaining -= 2;
|
||||
}
|
||||
else if (ch >= 0xfffe)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*tempptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 4096)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*tempptr++ = (char)(0xc0 | (ch >> 6));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else if (ch < 65536)
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 12));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 18));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
*tempptr = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy as-is...
|
||||
memcpy(temp, value->value.binary.data, value->value.binary.datalen);
|
||||
temp[value->value.binary.datalen] = '\0';
|
||||
}
|
||||
|
||||
free(value->value.binary.data);
|
||||
value->type = PDFIO_VALTYPE_STRING;
|
||||
value->value.string = pdfioStringCreate(dict->pdf, temp);
|
||||
|
||||
return (value->value.string);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -412,6 +659,47 @@ _pdfioDictGetValue(pdfio_dict_t *dict, // I - Dictionary
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictIterateKeys()' - Iterate the keys in a dictionary.
|
||||
//
|
||||
// This function iterates the keys in a dictionary, calling the supplied
|
||||
// function "cb":
|
||||
//
|
||||
// ```
|
||||
// bool
|
||||
// my_dict_cb(pdfio_dict_t *dict, const char *key, void *cb_data)
|
||||
// {
|
||||
// ... "key" contains the dictionary key ...
|
||||
// ... return true to continue or false to stop ...
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// The iteration continues as long as the callback returns `true` or all keys
|
||||
// have been iterated.
|
||||
//
|
||||
|
||||
void
|
||||
pdfioDictIterateKeys(
|
||||
pdfio_dict_t *dict, // I - Dictionary
|
||||
pdfio_dict_cb_t cb, // I - Callback function
|
||||
void *cb_data) // I - Callback data
|
||||
{
|
||||
size_t i; // Looping var
|
||||
_pdfio_pair_t *pair; // Current pair
|
||||
|
||||
|
||||
// Range check input...
|
||||
if (!dict || !cb)
|
||||
return;
|
||||
|
||||
for (i = dict->num_pairs, pair = dict->pairs; i > 0; i --, pair ++)
|
||||
{
|
||||
if (!(cb)(dict, pair->key, cb_data))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioDictRead()' - Read a dictionary from a PDF file.
|
||||
//
|
||||
@ -420,14 +708,16 @@ _pdfioDictGetValue(pdfio_dict_t *dict, // I - Dictionary
|
||||
|
||||
pdfio_dict_t * // O - New dictionary
|
||||
_pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfio_token_t *tb) // I - Token buffer/stack
|
||||
pdfio_obj_t *obj, // I - Object, if any
|
||||
_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
size_t depth) // I - Depth of dictionary
|
||||
{
|
||||
pdfio_dict_t *dict; // New dictionary
|
||||
char key[256]; // Dictionary key
|
||||
_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)
|
||||
@ -439,6 +729,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] != '/')
|
||||
@ -446,18 +737,25 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfioFileError(pdf, "Invalid dictionary contents.");
|
||||
break;
|
||||
}
|
||||
else if (_pdfioDictGetValue(dict, key + 1))
|
||||
{
|
||||
_pdfioFileError(pdf, "Duplicate dictionary key '%s'.", key + 1);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
// Then get the next value...
|
||||
if (!_pdfioValueRead(pdf, tb, &value))
|
||||
PDFIO_DEBUG("_pdfioDictRead: Reading value for '%s'.\n", key + 1);
|
||||
|
||||
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
|
||||
@ -653,7 +951,7 @@ pdfioDictSetNull(pdfio_dict_t *dict, // I - Dictionary
|
||||
bool // O - `true` on success, `false` on failure
|
||||
pdfioDictSetNumber(pdfio_dict_t *dict, // I - Dictionary
|
||||
const char *key, // I - Key
|
||||
double value) // I - Value
|
||||
double value) // I - Value
|
||||
{
|
||||
_pdfio_value_t temp; // New value
|
||||
|
||||
@ -802,6 +1100,8 @@ _pdfioDictSetValue(
|
||||
{
|
||||
// Yes, replace the value...
|
||||
PDFIO_DEBUG("_pdfioDictSetValue: Replacing existing value.\n");
|
||||
if (pair->value.type == PDFIO_VALTYPE_BINARY)
|
||||
free(pair->value.value.binary.data);
|
||||
pair->value = *value;
|
||||
return (true);
|
||||
}
|
||||
@ -835,9 +1135,9 @@ _pdfioDictSetValue(
|
||||
|
||||
#ifdef DEBUG
|
||||
PDFIO_DEBUG("_pdfioDictSetValue(%p): %lu pairs\n", (void *)dict, (unsigned long)dict->num_pairs);
|
||||
PDFIO_DEBUG("_pdfioDictSetValue(%p): ", (void *)dict);
|
||||
PDFIO_DEBUG_DICT(dict);
|
||||
PDFIO_DEBUG("\n");
|
||||
// PDFIO_DEBUG("_pdfioDictSetValue(%p): ", (void *)dict);
|
||||
// PDFIO_DEBUG_DICT(dict);
|
||||
// PDFIO_DEBUG("\n");
|
||||
#endif // DEBUG
|
||||
|
||||
return (true);
|
||||
@ -850,6 +1150,7 @@ _pdfioDictSetValue(
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
_pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary
|
||||
pdfio_obj_t *obj, // I - Object, if any
|
||||
off_t *length) // I - Offset to length value
|
||||
{
|
||||
pdfio_file_t *pdf = dict->pdf; // PDF file
|
||||
@ -867,7 +1168,7 @@ _pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary
|
||||
// Write all of the key/value pairs...
|
||||
for (i = dict->num_pairs, pair = dict->pairs; i > 0; i --, pair ++)
|
||||
{
|
||||
if (!_pdfioFilePrintf(pdf, "/%s", pair->key))
|
||||
if (!_pdfioFilePrintf(pdf, "%N", pair->key))
|
||||
return (false);
|
||||
|
||||
if (length && !strcmp(pair->key, "Length") && pair->value.type == PDFIO_VALTYPE_NUMBER && pair->value.value.number <= 0.0)
|
||||
@ -877,7 +1178,7 @@ _pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary
|
||||
if (!_pdfioFilePuts(pdf, " 9999999999"))
|
||||
return (false);
|
||||
}
|
||||
else if (!_pdfioValueWrite(pdf, &pair->value, NULL))
|
||||
else if (!_pdfioValueWrite(pdf, obj, &pair->value, NULL))
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
1534
pdfio-file.c
1534
pdfio-file.c
File diff suppressed because it is too large
Load Diff
392
pdfio-md5.c
Normal file
392
pdfio-md5.c
Normal file
@ -0,0 +1,392 @@
|
||||
//
|
||||
// MD5 functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
// Copyright © 1999 Aladdin Enterprises. All rights reserved.
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
// L. Peter Deutsch
|
||||
// ghost@aladdin.com
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321.
|
||||
It is derived directly from the text of the RFC and not from the
|
||||
reference implementation.
|
||||
|
||||
The original and principal author of md5.c is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
#define T1 0xd76aa478
|
||||
#define T2 0xe8c7b756
|
||||
#define T3 0x242070db
|
||||
#define T4 0xc1bdceee
|
||||
#define T5 0xf57c0faf
|
||||
#define T6 0x4787c62a
|
||||
#define T7 0xa8304613
|
||||
#define T8 0xfd469501
|
||||
#define T9 0x698098d8
|
||||
#define T10 0x8b44f7af
|
||||
#define T11 0xffff5bb1
|
||||
#define T12 0x895cd7be
|
||||
#define T13 0x6b901122
|
||||
#define T14 0xfd987193
|
||||
#define T15 0xa679438e
|
||||
#define T16 0x49b40821
|
||||
#define T17 0xf61e2562
|
||||
#define T18 0xc040b340
|
||||
#define T19 0x265e5a51
|
||||
#define T20 0xe9b6c7aa
|
||||
#define T21 0xd62f105d
|
||||
#define T22 0x02441453
|
||||
#define T23 0xd8a1e681
|
||||
#define T24 0xe7d3fbc8
|
||||
#define T25 0x21e1cde6
|
||||
#define T26 0xc33707d6
|
||||
#define T27 0xf4d50d87
|
||||
#define T28 0x455a14ed
|
||||
#define T29 0xa9e3e905
|
||||
#define T30 0xfcefa3f8
|
||||
#define T31 0x676f02d9
|
||||
#define T32 0x8d2a4c8a
|
||||
#define T33 0xfffa3942
|
||||
#define T34 0x8771f681
|
||||
#define T35 0x6d9d6122
|
||||
#define T36 0xfde5380c
|
||||
#define T37 0xa4beea44
|
||||
#define T38 0x4bdecfa9
|
||||
#define T39 0xf6bb4b60
|
||||
#define T40 0xbebfbc70
|
||||
#define T41 0x289b7ec6
|
||||
#define T42 0xeaa127fa
|
||||
#define T43 0xd4ef3085
|
||||
#define T44 0x04881d05
|
||||
#define T45 0xd9d4d039
|
||||
#define T46 0xe6db99e5
|
||||
#define T47 0x1fa27cf8
|
||||
#define T48 0xc4ac5665
|
||||
#define T49 0xf4292244
|
||||
#define T50 0x432aff97
|
||||
#define T51 0xab9423a7
|
||||
#define T52 0xfc93a039
|
||||
#define T53 0x655b59c3
|
||||
#define T54 0x8f0ccc92
|
||||
#define T55 0xffeff47d
|
||||
#define T56 0x85845dd1
|
||||
#define T57 0x6fa87e4f
|
||||
#define T58 0xfe2ce6e0
|
||||
#define T59 0xa3014314
|
||||
#define T60 0x4e0811a1
|
||||
#define T61 0xf7537e82
|
||||
#define T62 0xbd3af235
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T64 0xeb86d391
|
||||
|
||||
|
||||
//
|
||||
// Use the unoptimized (big-endian) implementation if we don't know the
|
||||
// endian-ness of the platform.
|
||||
//
|
||||
|
||||
#ifdef __BYTE_ORDER__
|
||||
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define ARCH_IS_BIG_ENDIAN 0 // Use little endian optimized version
|
||||
# else
|
||||
# define ARCH_IS_BIG_ENDIAN 1 // Use generic version
|
||||
# endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#elif !defined(ARCH_IS_BIG_ENDIAN)
|
||||
# define ARCH_IS_BIG_ENDIAN 1 // Use generic version
|
||||
#endif // !ARCH_IS_BIG_ENDIAN
|
||||
|
||||
|
||||
//
|
||||
// 'md5_process()' - Hash a block of data.
|
||||
//
|
||||
|
||||
static void
|
||||
md5_process(_pdfio_md5_t *pms, // I - MD5 state
|
||||
const uint8_t *data/*[64]*/)// I - Data
|
||||
{
|
||||
uint32_t a = pms->abcd[0], // First word of state
|
||||
b = pms->abcd[1], // Second word of state
|
||||
c = pms->abcd[2], // Third word of state
|
||||
d = pms->abcd[3]; // Fourth word of state
|
||||
uint32_t t; // Temporary state
|
||||
|
||||
|
||||
#if ARCH_IS_BIG_ENDIAN
|
||||
// On big-endian machines, we must arrange the bytes in the right
|
||||
// order. (This also works on machines of unknown byte order.)
|
||||
uint32_t X[16]; // Little-endian representation
|
||||
const uint8_t *xp; // Pointer into data
|
||||
int i; // Looping var
|
||||
|
||||
for (i = 0, xp = data; i < 16; i ++, xp += 4)
|
||||
X[i] = xp[0] + (unsigned)(xp[1] << 8) + (unsigned)(xp[2] << 16) + (unsigned)(xp[3] << 24);
|
||||
|
||||
#else /* !ARCH_IS_BIG_ENDIAN */
|
||||
// On little-endian machines, we can process properly aligned data without copying it.
|
||||
uint32_t xbuf[16]; // Aligned buffer
|
||||
const uint32_t *X; // Pointer to little-endian representation
|
||||
|
||||
if (!((data - (const uint8_t *)0) & 3))
|
||||
{
|
||||
// data is properly aligned, use it directly...
|
||||
X = (const uint32_t *)data;
|
||||
}
|
||||
else
|
||||
{
|
||||
// data is not aligned, copy to the aligned buffer...
|
||||
memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
#endif // ARCH_IS_BIG_ENDIAN
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
// Round 1.
|
||||
// Let [abcd k s i] denote the operation
|
||||
// a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s).
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) t = a + F(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
// Do the following 16 operations.
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
|
||||
#undef SET
|
||||
|
||||
// Round 2.
|
||||
// Let [abcd k s i] denote the operation
|
||||
// a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s).
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) t = a + G(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
// Do the following 16 operations.
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
|
||||
#undef SET
|
||||
|
||||
// Round 3.
|
||||
// Let [abcd k s t] denote the operation
|
||||
// a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s).
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti) t = a + H(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
// Do the following 16 operations.
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
|
||||
#undef SET
|
||||
|
||||
// Round 4.
|
||||
// Let [abcd k s t] denote the operation
|
||||
// a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s).
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) t = a + I(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
// Do the following 16 operations.
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
|
||||
#undef SET
|
||||
|
||||
// Then perform the following additions. (That is increment each of the four
|
||||
// registers by the value it had before this block was started.)
|
||||
pms->abcd[0] += a;
|
||||
pms->abcd[1] += b;
|
||||
pms->abcd[2] += c;
|
||||
pms->abcd[3] += d;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioCryptoMD5Init()' - Initialize an MD5 hash.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioCryptoMD5Init(_pdfio_md5_t *pms) // I - MD5 state
|
||||
{
|
||||
pms->count[0] = pms->count[1] = 0;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = 0xefcdab89;
|
||||
pms->abcd[2] = 0x98badcfe;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioCryptoMD5Append()' - Append bytes to the MD5 hash.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioCryptoMD5Append(
|
||||
_pdfio_md5_t *pms, // I - MD5 state
|
||||
const uint8_t *data, // I - Data to add
|
||||
size_t nbytes) // I - Number of bytes
|
||||
{
|
||||
const uint8_t *p = data; // Pointer into data
|
||||
size_t left = nbytes; // Remaining bytes
|
||||
size_t offset = (pms->count[0] >> 3) & 63;
|
||||
// Offset into state
|
||||
uint32_t nbits = (uint32_t)(nbytes << 3);
|
||||
// Number of bits to add
|
||||
|
||||
|
||||
if (nbytes == 0)
|
||||
return;
|
||||
|
||||
// Update the message length.
|
||||
pms->count[1] += (unsigned)(nbytes >> 29);
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1] ++;
|
||||
|
||||
// Process an initial partial block.
|
||||
if (offset)
|
||||
{
|
||||
size_t copy = ((offset + nbytes) > 64 ? 64 - offset : nbytes);
|
||||
// Number of bytes to copy
|
||||
|
||||
memcpy(pms->buf + offset, p, copy);
|
||||
|
||||
if ((offset + copy) < 64)
|
||||
return;
|
||||
|
||||
p += copy;
|
||||
left -= copy;
|
||||
|
||||
md5_process(pms, pms->buf);
|
||||
}
|
||||
|
||||
// Process full blocks.
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(pms, p);
|
||||
|
||||
// Copy a final partial block.
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioCryptoMD5Finish()' - Finalize the MD5 hash.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioCryptoMD5Finish(
|
||||
_pdfio_md5_t *pms, // I - MD5 state
|
||||
uint8_t digest[16]) // O - Digest value
|
||||
{
|
||||
int i; // Looping var
|
||||
uint8_t data[8]; // Digest length data
|
||||
static const uint8_t pad[64] = // Padding bytes
|
||||
{
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
|
||||
// Save the length before padding.
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
|
||||
// Pad to 56 bytes mod 64.
|
||||
_pdfioCryptoMD5Append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
|
||||
// Append the length.
|
||||
_pdfioCryptoMD5Append(pms, data, 8);
|
||||
|
||||
// Copy the digest from the state...
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
183
pdfio-object.c
183
pdfio-object.c
@ -1,26 +1,15 @@
|
||||
//
|
||||
// PDF object functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
//
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
static bool write_obj_header(pdfio_obj_t *obj);
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioObjClose()' - Close an object, writing any data as needed to the PDF
|
||||
// file.
|
||||
@ -33,14 +22,20 @@ pdfioObjClose(pdfio_obj_t *obj) // I - Object
|
||||
if (!obj)
|
||||
return (false);
|
||||
|
||||
// Clear the current object pointer...
|
||||
obj->pdf->current_obj = NULL;
|
||||
|
||||
if (obj->pdf->mode != _PDFIO_MODE_WRITE)
|
||||
return (true); // Nothing to do when reading
|
||||
{
|
||||
// Nothing to do when reading
|
||||
return (true);
|
||||
}
|
||||
|
||||
// Write what remains for the object...
|
||||
if (!obj->offset)
|
||||
{
|
||||
// Write the object value
|
||||
if (!write_obj_header(obj))
|
||||
if (!_pdfioObjWriteHeader(obj))
|
||||
return (false);
|
||||
|
||||
// Write the "endobj" line...
|
||||
@ -96,6 +91,9 @@ pdfioObjCopy(pdfio_file_t *pdf, // I - PDF file
|
||||
if (!_pdfioValueCopy(pdf, &dstobj->value, srcobj->pdf, &srcobj->value))
|
||||
return (NULL);
|
||||
|
||||
if (dstobj->value.type == PDFIO_VALTYPE_DICT)
|
||||
pdfioDictClear(dstobj->value.value.dict, "Length");
|
||||
|
||||
if (srcobj->stream_offset)
|
||||
{
|
||||
// Copy stream data...
|
||||
@ -143,6 +141,9 @@ pdfioObjCreateStream(
|
||||
pdfio_obj_t *obj, // I - Object
|
||||
pdfio_filter_t filter) // I - Type of compression to apply
|
||||
{
|
||||
pdfio_obj_t *length_obj = NULL; // Length object, if any
|
||||
|
||||
|
||||
// Range check input
|
||||
if (!obj || obj->pdf->mode != _PDFIO_MODE_WRITE || obj->value.type != PDFIO_VALTYPE_DICT)
|
||||
return (NULL);
|
||||
@ -159,24 +160,45 @@ pdfioObjCreateStream(
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (obj->pdf->current_obj)
|
||||
{
|
||||
_pdfioFileError(obj->pdf, "Another object (%u) is already open.", (unsigned)obj->pdf->current_obj->number);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
// Write the header...
|
||||
if (!_pdfioDictGetValue(obj->value.value.dict, "Length"))
|
||||
{
|
||||
// Need a Length key for the stream, add a placeholder that we can fill in
|
||||
// later...
|
||||
pdfioDictSetNumber(obj->value.value.dict, "Length", 0.0);
|
||||
if (obj->pdf->output_cb)
|
||||
{
|
||||
// Streaming via an output callback, so add a placeholder length object
|
||||
_pdfio_value_t length_value; // Length value
|
||||
|
||||
length_value.type = PDFIO_VALTYPE_NUMBER;
|
||||
length_value.value.number = 0.0f;
|
||||
|
||||
length_obj = _pdfioFileCreateObj(obj->pdf, obj->pdf, &length_value);
|
||||
pdfioDictSetObj(obj->value.value.dict, "Length", length_obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need a Length key for the stream, add a placeholder that we can fill in
|
||||
// later...
|
||||
pdfioDictSetNumber(obj->value.value.dict, "Length", 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!write_obj_header(obj))
|
||||
if (!_pdfioObjWriteHeader(obj))
|
||||
return (NULL);
|
||||
|
||||
if (!_pdfioFilePuts(obj->pdf, "stream\n"))
|
||||
return (NULL);
|
||||
|
||||
obj->stream_offset = _pdfioFileTell(obj->pdf);
|
||||
obj->stream_offset = _pdfioFileTell(obj->pdf);
|
||||
obj->pdf->current_obj = obj;
|
||||
|
||||
// Return the new stream...
|
||||
return (_pdfioStreamCreate(obj, filter));
|
||||
return (_pdfioStreamCreate(obj, length_obj, 0, filter));
|
||||
}
|
||||
|
||||
|
||||
@ -188,8 +210,13 @@ void
|
||||
_pdfioObjDelete(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
if (obj)
|
||||
{
|
||||
pdfioStreamClose(obj->stream);
|
||||
|
||||
if (obj->datafree)
|
||||
(obj->datafree)(obj->data);
|
||||
}
|
||||
|
||||
free(obj);
|
||||
}
|
||||
|
||||
@ -234,6 +261,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.
|
||||
//
|
||||
@ -269,7 +307,8 @@ pdfioObjGetLength(pdfio_obj_t *obj) // I - Object
|
||||
|
||||
if ((lenobj = pdfioDictGetObj(obj->value.value.dict, "Length")) == NULL)
|
||||
{
|
||||
_pdfioFileError(obj->pdf, "Unable to get length of stream.");
|
||||
if (!_pdfioDictGetValue(obj->value.value.dict, "Length"))
|
||||
_pdfioFileError(obj->pdf, "Unable to get length of stream.");
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -288,6 +327,26 @@ pdfioObjGetLength(pdfio_obj_t *obj) // I - Object
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioObjGetName()' - Get the name value associated with an object.
|
||||
//
|
||||
|
||||
const char * // O - Dictionary or `NULL` on error
|
||||
pdfioObjGetName(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
if (!obj)
|
||||
return (NULL);
|
||||
|
||||
if (obj->value.type == PDFIO_VALTYPE_NONE)
|
||||
_pdfioObjLoad(obj);
|
||||
|
||||
if (obj->value.type == PDFIO_VALTYPE_NAME)
|
||||
return (obj->value.value.name);
|
||||
else
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioObjGetNumber()' - Get the object's number.
|
||||
//
|
||||
@ -302,8 +361,21 @@ pdfioObjGetNumber(pdfio_obj_t *obj) // I - Object
|
||||
//
|
||||
// 'pdfioObjGetSubtype()' - Get an object's subtype.
|
||||
//
|
||||
// This function returns an object's PDF subtype name, if any. Common subtype
|
||||
// names include:
|
||||
//
|
||||
// - "CIDFontType0": A CID Type0 font
|
||||
// - "CIDFontType2": A CID TrueType font
|
||||
// - "Image": An image or image mask
|
||||
// - "Form": A fillable form
|
||||
// - "OpenType": An OpenType font
|
||||
// - "Type0": A composite font
|
||||
// - "Type1": A PostScript Type1 font
|
||||
// - "Type3": A PDF Type3 font
|
||||
// - "TrueType": A TrueType font
|
||||
//
|
||||
|
||||
const char * // O - Object subtype
|
||||
const char * // O - Object subtype name or `NULL` for none
|
||||
pdfioObjGetSubtype(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
pdfio_dict_t *dict; // Object dictionary
|
||||
@ -319,8 +391,21 @@ pdfioObjGetSubtype(pdfio_obj_t *obj) // I - Object
|
||||
//
|
||||
// 'pdfioObjGetType()' - Get an object's type.
|
||||
//
|
||||
// This function returns an object's PDF type name, if any. Common type names
|
||||
// include:
|
||||
//
|
||||
// - "CMap": A character map for composite fonts
|
||||
// - "Font": An embedded font (@link pdfioObjGetSubtype@ will tell you the
|
||||
// font format)
|
||||
// - "FontDescriptor": A font descriptor
|
||||
// - "Page": A (visible) page
|
||||
// - "Pages": A page tree node
|
||||
// - "Template": An invisible template page
|
||||
// - "XObject": An image, image mask, or form (@link pdfioObjGetSubtype@ will
|
||||
// tell you which)
|
||||
//
|
||||
|
||||
const char * // O - Object type
|
||||
const char * // O - Object type name or `NULL` for none
|
||||
pdfioObjGetType(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
pdfio_dict_t *dict; // Object dictionary
|
||||
@ -387,12 +472,15 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
||||
}
|
||||
|
||||
ptr += 3;
|
||||
while (*ptr && isspace(*ptr & 255))
|
||||
ptr ++;
|
||||
|
||||
_pdfioFileConsume(obj->pdf, (size_t)(ptr - line));
|
||||
|
||||
// Then grab the object value...
|
||||
_pdfioTokenInit(&tb, obj->pdf, (_pdfio_tconsume_cb_t)_pdfioFileConsume, (_pdfio_tpeek_cb_t)_pdfioFilePeek, obj->pdf);
|
||||
|
||||
if (!_pdfioValueRead(obj->pdf, &tb, &obj->value))
|
||||
if (!_pdfioValueRead(obj->pdf, obj, &tb, &obj->value, 0))
|
||||
{
|
||||
_pdfioFileError(obj->pdf, "Unable to read value for object %lu.", (unsigned long)obj->number);
|
||||
return (false);
|
||||
@ -405,15 +493,29 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
||||
return (false);
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[1]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
|
||||
|
||||
_pdfioTokenFlush(&tb);
|
||||
|
||||
if (!strcmp(line, "stream"))
|
||||
{
|
||||
// Yes, save its location...
|
||||
// Yes, this is an embedded stream so save its location...
|
||||
obj->stream_offset = _pdfioFileTell(obj->pdf);
|
||||
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");
|
||||
@ -434,6 +536,12 @@ pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object
|
||||
if (!obj)
|
||||
return (NULL);
|
||||
|
||||
if (obj->pdf->current_obj)
|
||||
{
|
||||
_pdfioFileError(obj->pdf, "Another object (%u) is already open.", (unsigned)obj->pdf->current_obj->number);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
// Make sure we've loaded the object dictionary...
|
||||
if (!obj->value.type)
|
||||
{
|
||||
@ -446,23 +554,40 @@ pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object
|
||||
return (NULL);
|
||||
|
||||
// Open the stream...
|
||||
obj->pdf->current_obj = obj;
|
||||
|
||||
return (_pdfioStreamOpen(obj, decode));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'write_obj_header()' - Write the object header...
|
||||
// '_pdfioObjSetExtension()' - Set extension data for an object.
|
||||
//
|
||||
|
||||
static bool // O - `true` on success, `false` on failure
|
||||
write_obj_header(pdfio_obj_t *obj) // I - 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;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioObjWriteHeader()' - Write the object header...
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
_pdfioObjWriteHeader(pdfio_obj_t *obj) // I - Object
|
||||
{
|
||||
obj->offset = _pdfioFileTell(obj->pdf);
|
||||
|
||||
if (!_pdfioFilePrintf(obj->pdf, "%lu %u obj\n", (unsigned long)obj->number, obj->generation))
|
||||
return (false);
|
||||
|
||||
if (!_pdfioValueWrite(obj->pdf, &obj->value, &obj->length_offset))
|
||||
if (!_pdfioValueWrite(obj->pdf, obj, &obj->value, &obj->length_offset))
|
||||
return (false);
|
||||
|
||||
return (_pdfioFilePuts(obj->pdf, "\n"));
|
||||
|
80
pdfio-page.c
80
pdfio-page.c
@ -1,17 +1,20 @@
|
||||
//
|
||||
// PDF page functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2022 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 _pdfio_value_t *get_contents(pdfio_obj_t *page);
|
||||
|
||||
|
||||
//
|
||||
@ -47,3 +50,74 @@ pdfioPageCopy(pdfio_file_t *pdf, // I - PDF file
|
||||
else
|
||||
return (_pdfioFileAddPage(pdf, dstpage));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioPageGetNumStreams()' - Get the number of content streams for a page object.
|
||||
//
|
||||
|
||||
size_t // O - Number of streams
|
||||
pdfioPageGetNumStreams(
|
||||
pdfio_obj_t *page) // I - Page object
|
||||
{
|
||||
_pdfio_value_t *contents = get_contents(page);
|
||||
// Contents value
|
||||
|
||||
|
||||
if (!contents)
|
||||
return (0);
|
||||
else if (contents->type == PDFIO_VALTYPE_ARRAY)
|
||||
return (pdfioArrayGetSize(contents->value.array));
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioPageOpenStream()' - Open a content stream for a page.
|
||||
//
|
||||
|
||||
pdfio_stream_t * // O - Stream
|
||||
pdfioPageOpenStream(
|
||||
pdfio_obj_t *page, // I - Page object
|
||||
size_t n, // I - Stream index (0-based)
|
||||
bool decode) // I - `true` to decode/decompress stream
|
||||
{
|
||||
_pdfio_value_t *contents = get_contents(page);
|
||||
// Contents value
|
||||
|
||||
|
||||
if (!contents)
|
||||
return (NULL);
|
||||
else if (contents->type == PDFIO_VALTYPE_ARRAY && n < pdfioArrayGetSize(contents->value.array))
|
||||
return (pdfioObjOpenStream(pdfioArrayGetObj(contents->value.array, n), decode));
|
||||
else if (n)
|
||||
return (NULL);
|
||||
else
|
||||
return (pdfioObjOpenStream(pdfioFileFindObj(page->pdf, contents->value.indirect.number), decode));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'get_contents()' - Get a page's Contents value.
|
||||
//
|
||||
|
||||
static _pdfio_value_t * // O - Value or NULL on error
|
||||
get_contents(pdfio_obj_t *page) // I - Page object
|
||||
{
|
||||
// Range check input...
|
||||
if (!page)
|
||||
return (NULL);
|
||||
|
||||
// Load the page object as needed...
|
||||
if (page->value.type == PDFIO_VALTYPE_NONE)
|
||||
{
|
||||
if (!_pdfioObjLoad(page))
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (page->value.type != PDFIO_VALTYPE_DICT)
|
||||
return (NULL);
|
||||
|
||||
return (_pdfioDictGetValue(page->value.value.dict, "Contents"));
|
||||
}
|
||||
|
192
pdfio-private.h
192
pdfio-private.h
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Private header file for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -9,40 +9,23 @@
|
||||
|
||||
#ifndef PDFIO_PRIVATE_H
|
||||
# define PDFIO_PRIVATE_H
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
# ifdef _WIN32
|
||||
/*
|
||||
* Disable bogus VS warnings/errors...
|
||||
*/
|
||||
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_WARNINGS // Disable bogus VS warnings/errors...
|
||||
# endif // _WIN32
|
||||
|
||||
# include "pdfio.h"
|
||||
# include <stdarg.h>
|
||||
# include <stdint.h>
|
||||
# include <string.h>
|
||||
# include <ctype.h>
|
||||
# include <errno.h>
|
||||
# include <inttypes.h>
|
||||
# include <fcntl.h>
|
||||
# include <locale.h>
|
||||
# ifdef _WIN32
|
||||
# include <io.h>
|
||||
# include <direct.h>
|
||||
|
||||
/*
|
||||
* Microsoft renames the POSIX functions to _name, and introduces
|
||||
* a broken compatibility layer using the original names. As a result,
|
||||
* random crashes can occur when, for example, strdup() allocates memory
|
||||
* from a different heap than used by malloc() and free().
|
||||
*
|
||||
* To avoid moronic problems like this, we #define the POSIX function
|
||||
* names to the corresponding non-standard Microsoft names.
|
||||
*/
|
||||
|
||||
# define access _access
|
||||
# include <windows.h> // GetTempPathA
|
||||
# define access _access // Map standard POSIX/C99 names
|
||||
# define close _close
|
||||
# define fileno _fileno
|
||||
# define lseek _lseek
|
||||
@ -55,25 +38,20 @@
|
||||
# define unlink _unlink
|
||||
# define vsnprintf _vsnprintf
|
||||
# define write _write
|
||||
|
||||
/*
|
||||
* Map various parameters for POSIX...
|
||||
*/
|
||||
|
||||
# define F_OK 00
|
||||
# define W_OK 02
|
||||
# define R_OK 04
|
||||
# define O_RDONLY _O_RDONLY
|
||||
# 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
|
||||
# define O_TRUNC _O_TRUNC
|
||||
# define O_BINARY _O_BINARY
|
||||
# else // !_WIN32
|
||||
# include <unistd.h>
|
||||
# define O_BINARY 0
|
||||
# define O_BINARY 0 // Map Windows-specific open flag
|
||||
# endif // _WIN32
|
||||
# include <string.h>
|
||||
# include <ctype.h>
|
||||
# include <zlib.h>
|
||||
|
||||
|
||||
@ -115,6 +93,12 @@
|
||||
// Types and constants...
|
||||
//
|
||||
|
||||
# define PDFIO_MAX_DEPTH 32 // Maximum nesting depth for values
|
||||
# define PDFIO_MAX_STRING 65536 // Maximum length of string
|
||||
|
||||
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
|
||||
@ -124,7 +108,7 @@ typedef enum _pdfio_mode_e // Read/write mode
|
||||
typedef enum _pdfio_predictor_e // PNG predictor constants
|
||||
{
|
||||
_PDFIO_PREDICTOR_NONE = 1, // No predictor (default)
|
||||
_PDFIO_PREDICTOR_TIFF2 = 2, // TIFF2 predictor (???)
|
||||
_PDFIO_PREDICTOR_TIFF2 = 2, // TIFF predictor 2 (difference from left neighbor)
|
||||
_PDFIO_PREDICTOR_PNG_NONE = 10, // PNG None predictor (same as `_PDFIO_PREDICTOR_NONE`)
|
||||
_PDFIO_PREDICTOR_PNG_SUB = 11, // PNG Sub predictor
|
||||
_PDFIO_PREDICTOR_PNG_UP = 12, // PNG Up predictor
|
||||
@ -174,6 +158,44 @@ typedef struct _pdfio_value_s // Value structure
|
||||
} value; // Value union
|
||||
} _pdfio_value_t;
|
||||
|
||||
typedef struct _pdfio_aes_s // AES encryption state
|
||||
{
|
||||
size_t round_size; // Size of round key
|
||||
uint8_t round_key[240], // Round key
|
||||
iv[16]; // Initialization vector
|
||||
} _pdfio_aes_t;
|
||||
|
||||
typedef struct _pdfio_md5_s // MD5 hash state
|
||||
{
|
||||
uint32_t count[2]; // Message length in bits, lsw first
|
||||
uint32_t abcd[4]; // Digest buffer
|
||||
uint8_t buf[64]; // Accumulate block
|
||||
} _pdfio_md5_t;
|
||||
|
||||
typedef struct _pdfio_rc4_s // RC4 encryption state
|
||||
{
|
||||
uint8_t sbox[256]; // S boxes for encryption
|
||||
uint8_t i, j; // Current indices into S boxes
|
||||
} _pdfio_rc4_t;
|
||||
|
||||
typedef struct _pdfio_sha265_s // SHA-256 hash state
|
||||
{
|
||||
uint32_t Intermediate_Hash[8]; // Message Digest
|
||||
uint32_t Length_High; // Message length in bits
|
||||
uint32_t Length_Low; // Message length in bits
|
||||
int Message_Block_Index; // Message_Block array index
|
||||
uint8_t Message_Block[64]; // 512-bit message blocks
|
||||
int Computed; // Is the hash computed?
|
||||
int Corrupted; // Cumulative corruption code
|
||||
} _pdfio_sha256_t;
|
||||
|
||||
typedef union _pdfio_crypto_ctx_u // Cryptographic contexts
|
||||
{
|
||||
_pdfio_aes_t aes; // AES-128/256 context
|
||||
_pdfio_rc4_t rc4; // RC4-40/128 context
|
||||
} _pdfio_crypto_ctx_t;
|
||||
typedef size_t (*_pdfio_crypto_cb_t)(_pdfio_crypto_ctx_t *ctx, uint8_t *outbuffer, const uint8_t *inbuffer, size_t len);
|
||||
|
||||
struct _pdfio_array_s
|
||||
{
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
@ -203,27 +225,48 @@ typedef struct _pdfio_objmap_s // PDF object map
|
||||
size_t src_number; // Source object number
|
||||
} _pdfio_objmap_t;
|
||||
|
||||
typedef struct _pdfio_strbuf_s // PDF string buffer
|
||||
{
|
||||
struct _pdfio_strbuf_s *next; // Next string buffer
|
||||
bool bufused; // Is this string buffer being used?
|
||||
char buffer[PDFIO_MAX_STRING + 32];
|
||||
// String buffer
|
||||
} _pdfio_strbuf_t;
|
||||
|
||||
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
|
||||
_pdfio_mode_t mode; // Read/write mode
|
||||
pdfio_output_cb_t output_cb; // Output callback
|
||||
void *output_ctx; // Context for output callback
|
||||
pdfio_error_cb_t error_cb; // Error callback
|
||||
void *error_data; // Data for error callback
|
||||
|
||||
pdfio_encryption_t encryption; // Encryption mode
|
||||
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
|
||||
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
|
||||
|
||||
// Active file data
|
||||
int fd; // File descriptor
|
||||
char buffer[8192], // Read/write buffer
|
||||
*bufptr, // Pointer into buffer
|
||||
*bufend; // End of buffer
|
||||
off_t bufpos; // Position in file for start of buffer
|
||||
pdfio_dict_t *trailer; // Trailer dictionary
|
||||
pdfio_obj_t *root; // Root object/dictionary
|
||||
pdfio_obj_t *info; // Information object
|
||||
pdfio_obj_t *pages_root; // Root pages object
|
||||
pdfio_obj_t *encrypt; // Encryption object/dictionary
|
||||
pdfio_dict_t *trailer_dict; // Trailer dictionary
|
||||
pdfio_obj_t *root_obj; // Root object/dictionary
|
||||
pdfio_obj_t *info_obj; // Information object
|
||||
pdfio_obj_t *pages_obj; // Root pages object
|
||||
pdfio_obj_t *encrypt_obj; // De/Encryption object/dictionary
|
||||
pdfio_obj_t *cp1252_obj, // CP1252 font encoding object
|
||||
*unicode_obj; // Unicode font encoding object
|
||||
pdfio_array_t *id_array; // ID array
|
||||
@ -236,8 +279,10 @@ 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
|
||||
pdfio_obj_t **objs; // 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
|
||||
alloc_objmaps; // Allocated object maps
|
||||
_pdfio_objmap_t *objmaps; // Object maps
|
||||
@ -247,6 +292,7 @@ struct _pdfio_file_s // PDF file structure
|
||||
size_t num_strings, // Number of strings
|
||||
alloc_strings; // Allocated strings
|
||||
char **strings; // Nul-terminated strings
|
||||
_pdfio_strbuf_t *strbuffers; // String buffers
|
||||
};
|
||||
|
||||
struct _pdfio_obj_s // Object
|
||||
@ -260,12 +306,15 @@ 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
|
||||
{
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
pdfio_obj_t *obj; // Object
|
||||
pdfio_obj_t *length_obj; // Length object, if any
|
||||
pdfio_filter_t filter; // Compression/decompression filter
|
||||
size_t remaining; // Remaining bytes in stream
|
||||
char buffer[8192], // Read/write buffer
|
||||
@ -274,10 +323,13 @@ struct _pdfio_stream_s // Stream
|
||||
z_stream flate; // Flate filter state
|
||||
_pdfio_predictor_t predictor; // Predictor function, if any
|
||||
size_t pbpixel, // Size of a pixel in bytes
|
||||
pbsize; // Predictor buffer size, if any
|
||||
unsigned char cbuffer[4096], // Compressed data buffer
|
||||
pbsize, // Predictor buffer size, if any
|
||||
cbsize; // Compressed data buffer size
|
||||
unsigned char *cbuffer, // Compressed data buffer
|
||||
*prbuffer, // Raw buffer (previous line), as needed
|
||||
*psbuffer; // PNG filter buffer, as needed
|
||||
_pdfio_crypto_cb_t crypto_cb; // Encryption/descryption callback, if any
|
||||
_pdfio_crypto_ctx_t crypto_ctx; // Cryptographic context
|
||||
};
|
||||
|
||||
|
||||
@ -285,31 +337,54 @@ struct _pdfio_stream_s // Stream
|
||||
// Functions...
|
||||
//
|
||||
|
||||
extern size_t _pdfio_strlcpy(char *dst, const char *src, size_t dstsize) _PDFIO_INTERNAL;
|
||||
extern double _pdfio_strtod(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
|
||||
extern ssize_t _pdfio_vsnprintf(pdfio_file_t *pdf, char *buffer, size_t bufsize, const char *format, va_list ap) _PDFIO_INTERNAL;
|
||||
|
||||
extern bool _pdfioArrayDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_array_t *a, size_t depth) _PDFIO_INTERNAL;
|
||||
extern void _pdfioArrayDebug(pdfio_array_t *a, FILE *fp) _PDFIO_INTERNAL;
|
||||
extern void _pdfioArrayDelete(pdfio_array_t *a) _PDFIO_INTERNAL;
|
||||
extern _pdfio_value_t *_pdfioArrayGetValue(pdfio_array_t *a, size_t n) _PDFIO_INTERNAL;
|
||||
extern pdfio_array_t *_pdfioArrayRead(pdfio_file_t *pdf, _pdfio_token_t *ts) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioArrayWrite(pdfio_array_t *a) _PDFIO_INTERNAL;
|
||||
extern pdfio_array_t *_pdfioArrayRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, size_t depth) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioArrayWrite(pdfio_array_t *a, pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
|
||||
extern void _pdfioCryptoAESInit(_pdfio_aes_t *ctx, const uint8_t *key, size_t keylen, const uint8_t *iv) _PDFIO_INTERNAL;
|
||||
extern size_t _pdfioCryptoAESDecrypt(_pdfio_aes_t *ctx, uint8_t *outbuffer, const uint8_t *inbuffer, size_t len) _PDFIO_INTERNAL;
|
||||
extern size_t _pdfioCryptoAESEncrypt(_pdfio_aes_t *ctx, uint8_t *outbuffer, const uint8_t *inbuffer, size_t len) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioCryptoLock(pdfio_file_t *pdf, pdfio_permission_t permissions, pdfio_encryption_t encryption, const char *owner_password, const char *user_password) _PDFIO_INTERNAL;
|
||||
extern void _pdfioCryptoMakeRandom(uint8_t *buffer, size_t bytes) _PDFIO_INTERNAL;
|
||||
extern _pdfio_crypto_cb_t _pdfioCryptoMakeReader(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_crypto_ctx_t *ctx, uint8_t *iv, size_t *ivlen) _PDFIO_INTERNAL;
|
||||
extern _pdfio_crypto_cb_t _pdfioCryptoMakeWriter(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_crypto_ctx_t *ctx, uint8_t *iv, size_t *ivlen) _PDFIO_INTERNAL;
|
||||
extern void _pdfioCryptoMD5Append(_pdfio_md5_t *pms, const uint8_t *data, size_t nbytes) _PDFIO_INTERNAL;
|
||||
extern void _pdfioCryptoMD5Finish(_pdfio_md5_t *pms, uint8_t digest[16]) _PDFIO_INTERNAL;
|
||||
extern void _pdfioCryptoMD5Init(_pdfio_md5_t *pms) _PDFIO_INTERNAL;
|
||||
extern void _pdfioCryptoRC4Init(_pdfio_rc4_t *ctx, const uint8_t *key, size_t keylen) _PDFIO_INTERNAL;
|
||||
extern size_t _pdfioCryptoRC4Crypt(_pdfio_rc4_t *ctx, uint8_t *outbuffer, const uint8_t *inbuffer, size_t len) _PDFIO_INTERNAL;
|
||||
extern void _pdfioCryptoSHA256Append(_pdfio_sha256_t *, const uint8_t *bytes, size_t bytecount) _PDFIO_INTERNAL;
|
||||
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 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;
|
||||
extern pdfio_dict_t *_pdfioDictRead(pdfio_file_t *pdf, _pdfio_token_t *ts) _PDFIO_INTERNAL;
|
||||
extern pdfio_dict_t *_pdfioDictRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, size_t depth) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioDictSetValue(pdfio_dict_t *dict, const char *key, _pdfio_value_t *value) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioDictWrite(pdfio_dict_t *dict, off_t *length) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioDictWrite(pdfio_dict_t *dict, pdfio_obj_t *obj, off_t *length) _PDFIO_INTERNAL;
|
||||
|
||||
extern bool _pdfioFileAddMappedObj(pdfio_file_t *pdf, pdfio_obj_t *dst_obj, pdfio_obj_t *src_obj) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileAddPage(pdfio_file_t *pdf, pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileConsume(pdfio_file_t *pdf, size_t bytes) _PDFIO_INTERNAL;
|
||||
extern pdfio_obj_t *_pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_file_t *srcpdf, _pdfio_value_t *value) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileDefaultError(pdfio_file_t *pdf, const char *message, void *data) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileError(pdfio_file_t *pdf, const char *format, ...) _PDFIO_FORMAT(2,3) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileError(pdfio_file_t *pdf, const char *format, ...) _PDFIO_INTERNAL;
|
||||
extern pdfio_obj_t *_pdfioFileFindMappedObj(pdfio_file_t *pdf, pdfio_file_t *src_pdf, size_t src_number) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileFlush(pdfio_file_t *pdf) _PDFIO_INTERNAL;
|
||||
extern int _pdfioFileGetChar(pdfio_file_t *pdf) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileGets(pdfio_file_t *pdf, char *buffer, size_t bufsize) _PDFIO_INTERNAL;
|
||||
extern ssize_t _pdfioFilePeek(pdfio_file_t *pdf, void *buffer, size_t bytes) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFilePrintf(pdfio_file_t *pdf, const char *format, ...) _PDFIO_FORMAT(2,3) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFilePrintf(pdfio_file_t *pdf, const char *format, ...) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFilePuts(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
|
||||
extern ssize_t _pdfioFileRead(pdfio_file_t *pdf, void *buffer, size_t bytes) _PDFIO_INTERNAL;
|
||||
extern off_t _pdfioFileSeek(pdfio_file_t *pdf, off_t offset, int whence) _PDFIO_INTERNAL;
|
||||
@ -317,11 +392,16 @@ 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 bool _pdfioObjWriteHeader(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
|
||||
extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_filter_t compression) _PDFIO_INTERNAL;
|
||||
extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, size_t cbsize, pdfio_filter_t compression) _PDFIO_INTERNAL;
|
||||
extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL;
|
||||
|
||||
extern char *_pdfioStringAllocBuffer(pdfio_file_t *pdf);
|
||||
extern void _pdfioStringFreeBuffer(pdfio_file_t *pdf, char *buffer);
|
||||
extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
|
||||
|
||||
extern void _pdfioTokenClear(_pdfio_token_t *tb) _PDFIO_INTERNAL;
|
||||
@ -332,9 +412,11 @@ 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_token_t *ts, _pdfio_value_t *v) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioValueWrite(pdfio_file_t *pdf, _pdfio_value_t *v, off_t *length) _PDFIO_INTERNAL;
|
||||
extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioValueWrite(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_value_t *v, off_t *length) _PDFIO_INTERNAL;
|
||||
|
||||
|
||||
#endif // !PDFIO_PRIVATE_H
|
||||
|
113
pdfio-rc4.c
Normal file
113
pdfio-rc4.c
Normal file
@ -0,0 +1,113 @@
|
||||
//
|
||||
// RC4 functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
//
|
||||
// Original code by Tim Martin
|
||||
// Copyright © 1999 by Carnegie Mellon University, All Rights Reserved
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software and its
|
||||
// documentation for any purpose and without fee is hereby granted,
|
||||
// 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 Carnegie Mellon
|
||||
// University not be used in advertising or publicity pertaining to
|
||||
// distribution of the software without specific, written prior
|
||||
// permission.
|
||||
//
|
||||
// CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||
// THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
|
||||
// ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
// OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioCryptoRC4Init()' - Initialize an RC4 context with the specified key.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioCryptoRC4Init(
|
||||
_pdfio_rc4_t *ctx, // IO - Context
|
||||
const uint8_t *key, // I - Key
|
||||
size_t keylen) // I - Length of key
|
||||
{
|
||||
size_t i; // Looping var
|
||||
uint8_t j, // S box counter
|
||||
tmp; // Temporary variable
|
||||
|
||||
|
||||
// Fill in linearly s0=0, s1=1, ...
|
||||
for (i = 0; i < 256; i ++)
|
||||
ctx->sbox[i] = (uint8_t)i;
|
||||
|
||||
for (i = 0, j = 0; i < 256; i ++)
|
||||
{
|
||||
// j = (j + Si + Ki) mod 256
|
||||
j += ctx->sbox[i] + key[i % keylen];
|
||||
|
||||
// Swap Si and Sj...
|
||||
tmp = ctx->sbox[i];
|
||||
ctx->sbox[i] = ctx->sbox[j];
|
||||
ctx->sbox[j] = tmp;
|
||||
}
|
||||
|
||||
// Initialize counters to 0 and return...
|
||||
ctx->i = 0;
|
||||
ctx->j = 0;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioCryptoRC4Crypt()' - De/encrypt the given buffer.
|
||||
//
|
||||
// "inbuffer" and "outbuffer" can point to the same memory.
|
||||
//
|
||||
|
||||
size_t // O - Number of output bytes
|
||||
_pdfioCryptoRC4Crypt(
|
||||
_pdfio_rc4_t *ctx, // I - Context
|
||||
uint8_t *outbuffer, // I - Output buffer
|
||||
const uint8_t *inbuffer, // I - Input buffer
|
||||
size_t len) // I - Size of buffers
|
||||
{
|
||||
uint8_t tmp, // Swap variable
|
||||
i, j, // Looping vars
|
||||
t; // Current S box
|
||||
size_t outbytes = len; // Number of output bytes
|
||||
|
||||
|
||||
// Loop through the entire buffer...
|
||||
i = ctx->i;
|
||||
j = ctx->j;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
// Get the next S box indices...
|
||||
i ++;
|
||||
j += ctx->sbox[i];
|
||||
|
||||
// Swap Si and Sj...
|
||||
tmp = ctx->sbox[i];
|
||||
ctx->sbox[i] = ctx->sbox[j];
|
||||
ctx->sbox[j] = tmp;
|
||||
|
||||
// Get the S box index for this byte...
|
||||
t = ctx->sbox[i] + ctx->sbox[j];
|
||||
|
||||
// Encrypt using the S box...
|
||||
*outbuffer++ = *inbuffer++ ^ ctx->sbox[t];
|
||||
len --;
|
||||
}
|
||||
|
||||
// Copy current S box indices back to context...
|
||||
ctx->i = i;
|
||||
ctx->j = j;
|
||||
|
||||
return (outbytes);
|
||||
}
|
480
pdfio-sha256.c
Normal file
480
pdfio-sha256.c
Normal file
@ -0,0 +1,480 @@
|
||||
//
|
||||
// SHA-256 functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2011 IETF Trust and the persons identified as authors of the
|
||||
// code. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or
|
||||
// without modification, are permitted provided that the following
|
||||
// conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above
|
||||
// copyright notice, this list of conditions and
|
||||
// the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// - Neither the name of Internet Society, IETF or IETF Trust, nor
|
||||
// the names of specific contributors, may be used to endorse or
|
||||
// promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
/*
|
||||
* Description:
|
||||
* This file implements the Secure Hash Algorithms SHA-224 and
|
||||
* SHA-256 as defined in the U.S. National Institute of Standards
|
||||
* and Technology Federal Information Processing Standards
|
||||
* Publication (FIPS PUB) 180-3 published in October 2008
|
||||
* and formerly defined in its predecessors, FIPS PUB 180-1
|
||||
* and FIP PUB 180-2.
|
||||
*
|
||||
* A combined document showing all algorithms is available at
|
||||
* http://csrc.nist.gov/publications/fips/
|
||||
* fips180-3/fips180-3_final.pdf
|
||||
*
|
||||
* The SHA-224 and SHA-256 algorithms produce 224-bit and 256-bit
|
||||
* message digests for a given data stream. It should take about
|
||||
* 2**n steps to find a message with the same digest as a given
|
||||
* message and 2**(n/2) to find any two messages with the same
|
||||
* digest, when n is the digest size in bits. Therefore, this
|
||||
* algorithm can serve as a means of providing a
|
||||
* "fingerprint" for a message.
|
||||
*
|
||||
* Portability Issues:
|
||||
* SHA-224 and SHA-256 are defined in terms of 32-bit "words".
|
||||
* This code uses <stdint.h> (included via "sha.h") to define 32-
|
||||
* and 8-bit unsigned integer types. If your C compiler does not
|
||||
* support 32-bit unsigned integers, this code is not
|
||||
* appropriate.
|
||||
*
|
||||
* Caveats:
|
||||
* SHA-224 and SHA-256 are designed to work with messages less
|
||||
* than 2^64 bits long. This implementation uses SHA224/256Input()
|
||||
* to hash the bits that are a multiple of the size of an 8-bit
|
||||
* octet, and then optionally uses SHA224/256FinalBits()
|
||||
* to hash the final few bits of the input.
|
||||
*/
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
/* Constants from sha.h */
|
||||
enum {
|
||||
SHA256_Message_Block_Size = 64,
|
||||
SHA256HashSize = 32,
|
||||
SHA256HashSizeBits = 256
|
||||
};
|
||||
|
||||
enum {
|
||||
shaSuccess = 0,
|
||||
shaNull, /* Null pointer parameter */
|
||||
shaInputTooLong, /* input data too long */
|
||||
shaStateError, /* called Input after FinalBits or Result */
|
||||
shaBadParam /* passed a bad parameter */
|
||||
};
|
||||
|
||||
/* Macros from sha-private.h */
|
||||
#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z))
|
||||
#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
|
||||
#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z))
|
||||
|
||||
/* Define the SHA shift, rotate left, and rotate right macros */
|
||||
#define SHA256_SHR(bits,word) ((word) >> (bits))
|
||||
#define SHA256_ROTL(bits,word) \
|
||||
(((word) << (bits)) | ((word) >> (32-(bits))))
|
||||
#define SHA256_ROTR(bits,word) \
|
||||
(((word) >> (bits)) | ((word) << (32-(bits))))
|
||||
|
||||
/* Define the SHA SIGMA and sigma macros */
|
||||
#define SHA256_SIGMA0(word) \
|
||||
(SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word))
|
||||
#define SHA256_SIGMA1(word) \
|
||||
(SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word))
|
||||
#define SHA256_sigma0(word) \
|
||||
(SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word))
|
||||
#define SHA256_sigma1(word) \
|
||||
(SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word))
|
||||
|
||||
/*
|
||||
* Add "length" to the length.
|
||||
* Set Corrupted when overflow has occurred.
|
||||
*/
|
||||
static uint32_t addTemp;
|
||||
#define SHA224_256AddLength(context, length) \
|
||||
(addTemp = (context)->Length_Low, (context)->Corrupted = \
|
||||
(((context)->Length_Low += (length)) < addTemp) && \
|
||||
(++(context)->Length_High == 0) ? shaInputTooLong : \
|
||||
(context)->Corrupted )
|
||||
|
||||
/* Local Function Prototypes */
|
||||
static int SHA224_256Reset(_pdfio_sha256_t *context, uint32_t *H0);
|
||||
static void SHA224_256ProcessMessageBlock(_pdfio_sha256_t *context);
|
||||
static void SHA224_256Finalize(_pdfio_sha256_t *context,
|
||||
uint8_t Pad_Byte);
|
||||
static void SHA224_256PadMessage(_pdfio_sha256_t *context,
|
||||
uint8_t Pad_Byte);
|
||||
static int SHA224_256ResultN(_pdfio_sha256_t *context,
|
||||
uint8_t Message_Digest[ ], int HashSize);
|
||||
|
||||
/* Initial Hash Values: FIPS 180-3 section 5.3.3 */
|
||||
static uint32_t SHA256_H0[SHA256HashSize/4] = {
|
||||
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
||||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
|
||||
};
|
||||
|
||||
/*
|
||||
* _pdfioCryptoSHA256Init
|
||||
*
|
||||
* Description:
|
||||
* This function will initialize the _pdfio_sha256_t in preparation
|
||||
* for computing a new SHA256 message digest.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to reset.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*/
|
||||
void _pdfioCryptoSHA256Init(_pdfio_sha256_t *context)
|
||||
{
|
||||
SHA224_256Reset(context, SHA256_H0);
|
||||
}
|
||||
|
||||
/*
|
||||
* _pdfioCryptoSHA256Append
|
||||
*
|
||||
* Description:
|
||||
* This function accepts an array of octets as the next portion
|
||||
* of the message.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The SHA context to update.
|
||||
* message_array[ ]: [in]
|
||||
* An array of octets representing the next portion of
|
||||
* the message.
|
||||
* length: [in]
|
||||
* The length of the message in message_array.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*/
|
||||
void
|
||||
_pdfioCryptoSHA256Append(_pdfio_sha256_t *context, const uint8_t *message_array,
|
||||
size_t length)
|
||||
{
|
||||
if (!length) return;
|
||||
|
||||
while (length--) {
|
||||
context->Message_Block[context->Message_Block_Index++] =
|
||||
*message_array;
|
||||
|
||||
if ((SHA224_256AddLength(context, 8) == shaSuccess) &&
|
||||
(context->Message_Block_Index == SHA256_Message_Block_Size))
|
||||
SHA224_256ProcessMessageBlock(context);
|
||||
|
||||
message_array++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* _pdfioCryptoSHA256Finish
|
||||
*
|
||||
* Description:
|
||||
* This function will return the 256-bit message digest
|
||||
* into the Message_Digest array provided by the caller.
|
||||
* NOTE:
|
||||
* The first octet of hash is stored in the element with index 0,
|
||||
* the last octet of hash in the element with index 31.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to use to calculate the SHA hash.
|
||||
* Message_Digest[ ]: [out]
|
||||
* Where the digest is returned.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*/
|
||||
void
|
||||
_pdfioCryptoSHA256Finish(_pdfio_sha256_t *context,
|
||||
uint8_t *Message_Digest)
|
||||
{
|
||||
SHA224_256ResultN(context, Message_Digest, SHA256HashSize);
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA224_256Reset
|
||||
*
|
||||
* Description:
|
||||
* This helper function will initialize the _pdfio_sha256_t in
|
||||
* preparation for computing a new SHA-224 or SHA-256 message digest.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to reset.
|
||||
* H0[ ]: [in]
|
||||
* The initial hash value array to use.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*/
|
||||
static int SHA224_256Reset(_pdfio_sha256_t *context, uint32_t *H0)
|
||||
{
|
||||
if (!context) return shaNull;
|
||||
|
||||
context->Length_High = context->Length_Low = 0;
|
||||
context->Message_Block_Index = 0;
|
||||
|
||||
context->Intermediate_Hash[0] = H0[0];
|
||||
context->Intermediate_Hash[1] = H0[1];
|
||||
context->Intermediate_Hash[2] = H0[2];
|
||||
context->Intermediate_Hash[3] = H0[3];
|
||||
context->Intermediate_Hash[4] = H0[4];
|
||||
context->Intermediate_Hash[5] = H0[5];
|
||||
context->Intermediate_Hash[6] = H0[6];
|
||||
context->Intermediate_Hash[7] = H0[7];
|
||||
|
||||
context->Computed = 0;
|
||||
context->Corrupted = shaSuccess;
|
||||
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA224_256ProcessMessageBlock
|
||||
*
|
||||
* Description:
|
||||
* This helper function will process the next 512 bits of the
|
||||
* message stored in the Message_Block array.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The SHA context to update.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
* Many of the variable names in this code, especially the
|
||||
* single character names, were used because those were the
|
||||
* names used in the Secure Hash Standard.
|
||||
*/
|
||||
static void SHA224_256ProcessMessageBlock(_pdfio_sha256_t *context)
|
||||
{
|
||||
/* Constants defined in FIPS 180-3, section 4.2.2 */
|
||||
static const uint32_t K[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,
|
||||
0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,
|
||||
0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,
|
||||
0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,
|
||||
0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
|
||||
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
|
||||
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
|
||||
0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
|
||||
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
int t, t4; /* Loop counter */
|
||||
uint32_t temp1, temp2; /* Temporary word value */
|
||||
uint32_t W[64]; /* Word sequence */
|
||||
uint32_t A, B, C, D, E, F, G, H; /* Word buffers */
|
||||
|
||||
/*
|
||||
* Initialize the first 16 words in the array W
|
||||
*/
|
||||
for (t = t4 = 0; t < 16; t++, t4 += 4)
|
||||
W[t] = (((uint32_t)context->Message_Block[t4]) << 24) |
|
||||
(((uint32_t)context->Message_Block[t4 + 1]) << 16) |
|
||||
(((uint32_t)context->Message_Block[t4 + 2]) << 8) |
|
||||
(((uint32_t)context->Message_Block[t4 + 3]));
|
||||
|
||||
for (t = 16; t < 64; t++)
|
||||
W[t] = SHA256_sigma1(W[t-2]) + W[t-7] +
|
||||
SHA256_sigma0(W[t-15]) + W[t-16];
|
||||
|
||||
A = context->Intermediate_Hash[0];
|
||||
B = context->Intermediate_Hash[1];
|
||||
C = context->Intermediate_Hash[2];
|
||||
D = context->Intermediate_Hash[3];
|
||||
E = context->Intermediate_Hash[4];
|
||||
F = context->Intermediate_Hash[5];
|
||||
G = context->Intermediate_Hash[6];
|
||||
H = context->Intermediate_Hash[7];
|
||||
|
||||
for (t = 0; t < 64; t++) {
|
||||
temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t];
|
||||
temp2 = SHA256_SIGMA0(A) + SHA_Maj(A,B,C);
|
||||
H = G;
|
||||
G = F;
|
||||
F = E;
|
||||
E = D + temp1;
|
||||
D = C;
|
||||
C = B;
|
||||
B = A;
|
||||
A = temp1 + temp2;
|
||||
}
|
||||
|
||||
context->Intermediate_Hash[0] += A;
|
||||
context->Intermediate_Hash[1] += B;
|
||||
context->Intermediate_Hash[2] += C;
|
||||
context->Intermediate_Hash[3] += D;
|
||||
context->Intermediate_Hash[4] += E;
|
||||
context->Intermediate_Hash[5] += F;
|
||||
context->Intermediate_Hash[6] += G;
|
||||
context->Intermediate_Hash[7] += H;
|
||||
|
||||
context->Message_Block_Index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA224_256Finalize
|
||||
*
|
||||
* Description:
|
||||
* This helper function finishes off the digest calculations.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The SHA context to update.
|
||||
* Pad_Byte: [in]
|
||||
* The last byte to add to the message block before the 0-padding
|
||||
* and length. This will contain the last bits of the message
|
||||
* followed by another single bit. If the message was an
|
||||
* exact multiple of 8-bits long, Pad_Byte will be 0x80.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*/
|
||||
static void SHA224_256Finalize(_pdfio_sha256_t *context,
|
||||
uint8_t Pad_Byte)
|
||||
{
|
||||
int i;
|
||||
SHA224_256PadMessage(context, Pad_Byte);
|
||||
/* message may be sensitive, so clear it out */
|
||||
for (i = 0; i < SHA256_Message_Block_Size; ++i)
|
||||
context->Message_Block[i] = 0;
|
||||
context->Length_High = 0; /* and clear length */
|
||||
context->Length_Low = 0;
|
||||
context->Computed = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA224_256PadMessage
|
||||
*
|
||||
* Description:
|
||||
* According to the standard, the message must be padded to the next
|
||||
* even multiple of 512 bits. The first padding bit must be a '1'.
|
||||
* The last 64 bits represent the length of the original message.
|
||||
* All bits in between should be 0. This helper function will pad
|
||||
* the message according to those rules by filling the
|
||||
* Message_Block array accordingly. When it returns, it can be
|
||||
* assumed that the message digest has been computed.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to pad.
|
||||
* Pad_Byte: [in]
|
||||
* The last byte to add to the message block before the 0-padding
|
||||
* and length. This will contain the last bits of the message
|
||||
* followed by another single bit. If the message was an
|
||||
* exact multiple of 8-bits long, Pad_Byte will be 0x80.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*/
|
||||
static void SHA224_256PadMessage(_pdfio_sha256_t *context,
|
||||
uint8_t Pad_Byte)
|
||||
{
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second
|
||||
* block.
|
||||
*/
|
||||
if (context->Message_Block_Index >= (SHA256_Message_Block_Size-8)) {
|
||||
context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
|
||||
while (context->Message_Block_Index < SHA256_Message_Block_Size)
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
SHA224_256ProcessMessageBlock(context);
|
||||
} else
|
||||
context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
|
||||
|
||||
while (context->Message_Block_Index < (SHA256_Message_Block_Size-8))
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
|
||||
/*
|
||||
* Store the message length as the last 8 octets
|
||||
*/
|
||||
context->Message_Block[56] = (uint8_t)(context->Length_High >> 24);
|
||||
context->Message_Block[57] = (uint8_t)(context->Length_High >> 16);
|
||||
context->Message_Block[58] = (uint8_t)(context->Length_High >> 8);
|
||||
context->Message_Block[59] = (uint8_t)(context->Length_High);
|
||||
context->Message_Block[60] = (uint8_t)(context->Length_Low >> 24);
|
||||
context->Message_Block[61] = (uint8_t)(context->Length_Low >> 16);
|
||||
context->Message_Block[62] = (uint8_t)(context->Length_Low >> 8);
|
||||
context->Message_Block[63] = (uint8_t)(context->Length_Low);
|
||||
|
||||
SHA224_256ProcessMessageBlock(context);
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA224_256ResultN
|
||||
*
|
||||
* Description:
|
||||
* This helper function will return the 224-bit or 256-bit message
|
||||
* digest into the Message_Digest array provided by the caller.
|
||||
* NOTE:
|
||||
* The first octet of hash is stored in the element with index 0,
|
||||
* the last octet of hash in the element with index 27/31.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to use to calculate the SHA hash.
|
||||
* Message_Digest[ ]: [out]
|
||||
* Where the digest is returned.
|
||||
* HashSize: [in]
|
||||
* The size of the hash, either 28 or 32.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*/
|
||||
static int SHA224_256ResultN(_pdfio_sha256_t *context,
|
||||
uint8_t Message_Digest[ ], int HashSize)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!context) return shaNull;
|
||||
if (!Message_Digest) return shaNull;
|
||||
if (context->Corrupted) return context->Corrupted;
|
||||
|
||||
if (!context->Computed)
|
||||
SHA224_256Finalize(context, 0x80);
|
||||
|
||||
for (i = 0; i < HashSize; ++i)
|
||||
Message_Digest[i] = (uint8_t)
|
||||
(context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ));
|
||||
|
||||
return shaSuccess;
|
||||
}
|
385
pdfio-stream.c
385
pdfio-stream.c
@ -1,16 +1,12 @@
|
||||
//
|
||||
// PDF stream functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -54,6 +50,10 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
|
||||
while ((status = deflate(&st->flate, Z_FINISH)) != Z_STREAM_END)
|
||||
{
|
||||
size_t bytes = st->cbsize - st->flate.avail_out,
|
||||
// Bytes to write
|
||||
outbytes; // Actual bytes written
|
||||
|
||||
if (status < Z_OK && status != Z_BUF_ERROR)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Flate compression failed: %s", zstrerror(status));
|
||||
@ -61,25 +61,70 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!_pdfioFileWrite(st->pdf, st->cbuffer, sizeof(st->cbuffer) - st->flate.avail_out))
|
||||
if (st->crypto_cb)
|
||||
{
|
||||
// Encrypt it first...
|
||||
outbytes = (st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, bytes & (size_t)~15);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No encryption
|
||||
outbytes = bytes;
|
||||
}
|
||||
|
||||
if (!_pdfioFileWrite(st->pdf, st->cbuffer, outbytes))
|
||||
{
|
||||
ret = false;
|
||||
goto done;
|
||||
}
|
||||
|
||||
st->flate.next_out = (Bytef *)st->cbuffer;
|
||||
st->flate.avail_out = (uInt)sizeof(st->cbuffer);
|
||||
if (bytes > outbytes)
|
||||
{
|
||||
bytes -= outbytes;
|
||||
memmove(st->cbuffer, st->cbuffer + outbytes, bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
st->flate.next_out = (Bytef *)st->cbuffer + bytes;
|
||||
st->flate.avail_out = (uInt)(st->cbsize - bytes);
|
||||
}
|
||||
|
||||
if (st->flate.avail_out < (uInt)sizeof(st->cbuffer))
|
||||
if (st->flate.avail_out < (uInt)st->cbsize)
|
||||
{
|
||||
// Write any residuals...
|
||||
if (!_pdfioFileWrite(st->pdf, st->cbuffer, sizeof(st->cbuffer) - st->flate.avail_out))
|
||||
size_t bytes = st->cbsize - st->flate.avail_out;
|
||||
// Bytes to write
|
||||
|
||||
if (st->crypto_cb)
|
||||
{
|
||||
// Encrypt it first...
|
||||
bytes = (st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, bytes);
|
||||
}
|
||||
|
||||
if (!_pdfioFileWrite(st->pdf, st->cbuffer, bytes))
|
||||
{
|
||||
ret = false;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
deflateEnd(&st->flate);
|
||||
}
|
||||
else if (st->crypto_cb && st->bufptr > st->buffer)
|
||||
{
|
||||
// Encrypt and flush
|
||||
uint8_t temp[8192]; // Temporary buffer
|
||||
size_t outbytes; // Output bytes
|
||||
|
||||
outbytes = (st->crypto_cb)(&st->crypto_ctx, temp, (uint8_t *)st->buffer, (size_t)(st->bufptr - st->buffer));
|
||||
if (!_pdfioFileWrite(st->pdf, temp, outbytes))
|
||||
{
|
||||
ret = false;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the length of this stream...
|
||||
@ -93,7 +138,12 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
}
|
||||
|
||||
// Update the length as needed...
|
||||
if (st->obj->length_offset)
|
||||
if (st->length_obj)
|
||||
{
|
||||
st->length_obj->value.value.number = (double)st->obj->stream_length;
|
||||
pdfioObjClose(st->length_obj);
|
||||
}
|
||||
else if (st->obj->length_offset)
|
||||
{
|
||||
// Seek back to the "/Length 9999999999" we wrote...
|
||||
if (_pdfioFileSeek(st->pdf, st->obj->length_offset, SEEK_SET) < 0)
|
||||
@ -120,6 +170,9 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
|
||||
done:
|
||||
|
||||
st->pdf->current_obj = NULL;
|
||||
|
||||
free(st->cbuffer);
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
@ -137,6 +190,8 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
pdfio_stream_t * // O - Stream or `NULL` on error
|
||||
_pdfioStreamCreate(
|
||||
pdfio_obj_t *obj, // I - Object
|
||||
pdfio_obj_t *length_obj, // I - Length object, if any
|
||||
size_t cbsize, // I - Size of compression buffer
|
||||
pdfio_filter_t compression) // I - Compression to apply
|
||||
{
|
||||
pdfio_stream_t *st; // Stream
|
||||
@ -149,9 +204,28 @@ _pdfioStreamCreate(
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
st->pdf = obj->pdf;
|
||||
st->obj = obj;
|
||||
st->filter = compression;
|
||||
st->pdf = obj->pdf;
|
||||
st->obj = obj;
|
||||
st->length_obj = length_obj;
|
||||
st->filter = compression;
|
||||
st->bufptr = st->buffer;
|
||||
st->bufend = st->buffer + sizeof(st->buffer);
|
||||
|
||||
if (obj->pdf->encryption)
|
||||
{
|
||||
uint8_t iv[64]; // Initialization vector
|
||||
size_t ivlen = sizeof(iv); // Length of initialization vector, if any
|
||||
|
||||
if ((st->crypto_cb = _pdfioCryptoMakeWriter(st->pdf, obj, &st->crypto_ctx, iv, &ivlen)) == NULL)
|
||||
{
|
||||
// TODO: Add error message?
|
||||
free(st);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (ivlen > 0)
|
||||
_pdfioFileWrite(st->pdf, iv, ivlen);
|
||||
}
|
||||
|
||||
if (compression == PDFIO_FILTER_FLATE)
|
||||
{
|
||||
@ -230,8 +304,21 @@ _pdfioStreamCreate(
|
||||
else
|
||||
st->predictor = _PDFIO_PREDICTOR_NONE;
|
||||
|
||||
if (cbsize == 0)
|
||||
cbsize = 4096;
|
||||
|
||||
st->cbsize = cbsize;
|
||||
if ((st->cbuffer = malloc(cbsize)) == NULL)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Flate output buffer: %s", (unsigned long)cbsize, strerror(errno));
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
st->flate.next_out = (Bytef *)st->cbuffer;
|
||||
st->flate.avail_out = (uInt)sizeof(st->cbuffer);
|
||||
st->flate.avail_out = (uInt)cbsize;
|
||||
|
||||
if ((status = deflateInit(&(st->flate), 9)) != Z_OK)
|
||||
{
|
||||
@ -290,14 +377,23 @@ pdfioStreamConsume(pdfio_stream_t *st, // I - Stream
|
||||
//
|
||||
// 'pdfioStreamGetToken()' - Read a single PDF token from a stream.
|
||||
//
|
||||
// This function reads a single PDF token from a stream, skipping all whitespace
|
||||
// and comments. Operator tokens, boolean values, and numbers are returned
|
||||
// as-is in the provided string buffer. String values start with the opening
|
||||
// parenthesis ('(') but have all escaping resolved and the terminating
|
||||
// parenthesis removed. Hexadecimal string values start with the opening angle
|
||||
// bracket ('<') and have all whitespace and the terminating angle bracket
|
||||
// removed.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on EOF
|
||||
bool // O - `true` on success, `false` on end-of-stream or error
|
||||
pdfioStreamGetToken(
|
||||
pdfio_stream_t *st, // I - Stream
|
||||
char *buffer, // I - String buffer
|
||||
size_t bufsize) // I - Size of string buffer
|
||||
{
|
||||
_pdfio_token_t tb; // Token buffer/stack
|
||||
bool ret; // Return value
|
||||
|
||||
|
||||
// Range check input...
|
||||
@ -307,7 +403,10 @@ pdfioStreamGetToken(
|
||||
// Read using the token engine...
|
||||
_pdfioTokenInit(&tb, st->pdf, (_pdfio_tconsume_cb_t)pdfioStreamConsume, (_pdfio_tpeek_cb_t)pdfioStreamPeek, st);
|
||||
|
||||
return (_pdfioTokenRead(&tb, buffer, bufsize));
|
||||
ret = _pdfioTokenRead(&tb, buffer, bufsize);
|
||||
_pdfioTokenFlush(&tb);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
@ -325,6 +424,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
pdfio_stream_t *st; // Stream
|
||||
pdfio_dict_t *dict = pdfioObjGetDict(obj);
|
||||
// Object dictionary
|
||||
const char *type; // Object type
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen(obj=%p(%u), decode=%s)\n", obj, (unsigned)obj->number, decode ? "true" : "false");
|
||||
@ -339,16 +439,36 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
st->pdf = obj->pdf;
|
||||
st->obj = obj;
|
||||
|
||||
if ((st->remaining = pdfioObjGetLength(obj)) == 0)
|
||||
if ((st->remaining = pdfioObjGetLength(obj)) == 0 && !_pdfioDictGetValue(pdfioObjGetDict(obj), "Length"))
|
||||
{
|
||||
free(st);
|
||||
return (NULL);
|
||||
_pdfioFileError(obj->pdf, "No stream data.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (_pdfioFileSeek(st->pdf, obj->stream_offset, SEEK_SET) != obj->stream_offset)
|
||||
{
|
||||
free(st);
|
||||
return (NULL);
|
||||
_pdfioFileError(obj->pdf, "Unable to seek to stream data.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
ivlen = (size_t)_pdfioFilePeek(st->pdf, iv, sizeof(iv));
|
||||
|
||||
if ((st->crypto_cb = _pdfioCryptoMakeReader(st->pdf, obj, &st->crypto_ctx, iv, &ivlen)) == NULL)
|
||||
goto error;
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen: ivlen=%d\n", (int)ivlen);
|
||||
if (ivlen > 0)
|
||||
_pdfioFileConsume(st->pdf, ivlen);
|
||||
|
||||
if (st->pdf->encryption >= PDFIO_ENCRYPTION_AES_128)
|
||||
st->remaining = (st->remaining + 15) & (size_t)~15;
|
||||
}
|
||||
|
||||
if (decode)
|
||||
@ -356,16 +476,23 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
// Try to decode/decompress the contents of this object...
|
||||
const char *filter = pdfioDictGetName(dict, "Filter");
|
||||
// Filter value
|
||||
pdfio_array_t *fa = pdfioDictGetArray(dict, "Filter");
|
||||
// Filter array
|
||||
|
||||
if (!filter && fa && pdfioArrayGetSize(fa) == 1)
|
||||
{
|
||||
// Support single-valued arrays...
|
||||
filter = pdfioArrayGetName(fa, 0);
|
||||
}
|
||||
|
||||
if (!filter)
|
||||
{
|
||||
// No single filter name, do we have a compound filter?
|
||||
if (pdfioDictGetArray(dict, "Filter"))
|
||||
if (fa)
|
||||
{
|
||||
// TODO: Implement compound filters...
|
||||
_pdfioFileError(st->pdf, "Unsupported compound stream filter.");
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// No filter, read as-is...
|
||||
@ -398,8 +525,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
else if (bpc < 1 || bpc == 3 || (bpc > 4 && bpc < 8) || (bpc > 8 && bpc < 16) || bpc > 16)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported BitsPerColor value %d.", bpc);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (colors == 0)
|
||||
@ -409,8 +535,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
else if (colors < 0 || colors > 4)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Colors value %d.", colors);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (columns == 0)
|
||||
@ -420,15 +545,13 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
else if (columns < 0)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Columns value %d.", columns);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((predictor > 2 && predictor < 10) || predictor > 15)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Predictor function %d.", predictor);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
else if (predictor > 1)
|
||||
{
|
||||
@ -442,47 +565,45 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
if ((st->prbuffer = calloc(1, st->pbsize - 1)) == NULL || (st->psbuffer = calloc(1, st->pbsize)) == NULL)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Predictor buffers.", (unsigned long)st->pbsize);
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
st->predictor = _PDFIO_PREDICTOR_NONE;
|
||||
}
|
||||
|
||||
if (sizeof(st->cbuffer) > st->remaining)
|
||||
st->cbsize = 4096;
|
||||
if ((st->cbuffer = malloc(st->cbsize)) == NULL)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Flate compression buffer.", (unsigned long)st->cbsize);
|
||||
goto error;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen: pos=%ld\n", (long)_pdfioFileTell(st->pdf));
|
||||
if (st->cbsize > st->remaining)
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
||||
else
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer));
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
||||
|
||||
if (rbytes <= 0)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to read bytes for stream.");
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (st->crypto_cb)
|
||||
rbytes = (ssize_t)(st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, (size_t)rbytes);
|
||||
|
||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
||||
st->flate.avail_in = (uInt)rbytes;
|
||||
|
||||
if (st->cbuffer[0] == 0x0a)
|
||||
{
|
||||
st->flate.next_in ++; // Skip newline
|
||||
st->flate.avail_in --;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen: avail_in=%u, cbuffer=<%02X%02X%02X%02X%02X%02X%02X%02X...>\n", st->flate.avail_in, st->cbuffer[0], st->cbuffer[1], st->cbuffer[2], st->cbuffer[3], st->cbuffer[4], st->cbuffer[5], st->cbuffer[6], st->cbuffer[7]);
|
||||
|
||||
if ((status = inflateInit(&(st->flate))) != Z_OK)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to start Flate filter: %s", zstrerror(status));
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
return (NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
st->remaining -= st->flate.avail_in;
|
||||
@ -495,9 +616,8 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
else
|
||||
{
|
||||
// Something else we don't support
|
||||
_pdfioFileError(st->pdf, "Unsupported stream filter '/%s'.", filter);
|
||||
free(st);
|
||||
return (NULL);
|
||||
_pdfioFileError(st->pdf, "Unsupported stream filter '%N'.", filter);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -507,6 +627,16 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
}
|
||||
|
||||
return (st);
|
||||
|
||||
// If we get here something went wrong...
|
||||
error:
|
||||
|
||||
free(st->cbuffer);
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
return (NULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -559,6 +689,10 @@ pdfioStreamPeek(pdfio_stream_t *st, // I - Stream
|
||||
//
|
||||
// 'pdfioStreamPrintf()' - Write a formatted string to a stream.
|
||||
//
|
||||
// This function writes a formatted string to a stream. In addition to the
|
||||
// standard `printf` format characters, you can use "%N" to format a PDF name
|
||||
// value ("/Name") and "%S" to format a PDF string ("(String)") value.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
pdfioStreamPrintf(
|
||||
@ -576,7 +710,7 @@ pdfioStreamPrintf(
|
||||
|
||||
// Format the string...
|
||||
va_start(ap, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||
_pdfio_vsnprintf(st->pdf, buffer, sizeof(buffer), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Write the string...
|
||||
@ -585,7 +719,7 @@ pdfioStreamPrintf(
|
||||
|
||||
|
||||
//
|
||||
// '()' - Write a single character to a stream.
|
||||
// 'pdfioStreamPutChar()' - Write a single character to a stream.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
@ -715,8 +849,63 @@ pdfioStreamWrite(
|
||||
// Write it...
|
||||
if (st->filter == PDFIO_FILTER_NONE)
|
||||
{
|
||||
// No filtering so just write it...
|
||||
return (_pdfioFileWrite(st->pdf, buffer, bytes));
|
||||
// No filtering...
|
||||
if (st->crypto_cb)
|
||||
{
|
||||
// Encrypt data before writing...
|
||||
uint8_t temp[8192]; // Temporary buffer
|
||||
size_t cbytes, // Current bytes
|
||||
outbytes; // Output bytes
|
||||
|
||||
bufptr = (const unsigned char *)buffer;
|
||||
|
||||
while (bytes > 0)
|
||||
{
|
||||
if (st->bufptr > st->buffer || bytes < 16)
|
||||
{
|
||||
// Write through the stream's buffer...
|
||||
if ((cbytes = bytes) > (size_t)(st->bufend - st->bufptr))
|
||||
cbytes = (size_t)(st->bufend - st->bufptr);
|
||||
|
||||
memcpy(st->bufptr, bufptr, cbytes);
|
||||
st->bufptr += cbytes;
|
||||
if (st->bufptr >= st->bufend)
|
||||
{
|
||||
// Encrypt and flush
|
||||
outbytes = (st->crypto_cb)(&st->crypto_ctx, temp, (uint8_t *)st->buffer, sizeof(st->buffer));
|
||||
if (!_pdfioFileWrite(st->pdf, temp, outbytes))
|
||||
return (false);
|
||||
|
||||
st->bufptr = st->buffer;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write directly up to sizeof(temp) bytes...
|
||||
if ((cbytes = bytes) > sizeof(temp))
|
||||
cbytes = sizeof(temp);
|
||||
if (cbytes & 15)
|
||||
{
|
||||
// AES has a 16-byte block size, so save the last few bytes...
|
||||
cbytes &= (size_t)~15;
|
||||
}
|
||||
|
||||
outbytes = (st->crypto_cb)(&st->crypto_ctx, temp, bufptr, cbytes);
|
||||
if (!_pdfioFileWrite(st->pdf, temp, outbytes))
|
||||
return (false);
|
||||
}
|
||||
|
||||
bytes -= cbytes;
|
||||
bufptr += cbytes;
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write unencrypted...
|
||||
return (_pdfioFileWrite(st->pdf, buffer, bytes));
|
||||
}
|
||||
}
|
||||
|
||||
pbline = st->pbsize - 1;
|
||||
@ -842,6 +1031,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
size_t bytes) // I - Number of bytes to read
|
||||
{
|
||||
ssize_t rbytes; // Bytes read
|
||||
uInt avail_in, avail_out; // Previous flate values
|
||||
|
||||
|
||||
if (st->filter == PDFIO_FILTER_NONE)
|
||||
@ -853,8 +1043,13 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
rbytes = _pdfioFileRead(st->pdf, buffer, bytes);
|
||||
|
||||
if (rbytes > 0)
|
||||
{
|
||||
st->remaining -= (size_t)rbytes;
|
||||
|
||||
if (st->crypto_cb)
|
||||
(st->crypto_cb)(&st->crypto_ctx, (uint8_t *)buffer, (uint8_t *)buffer, (size_t)rbytes);
|
||||
}
|
||||
|
||||
return (rbytes);
|
||||
}
|
||||
else if (st->filter == PDFIO_FILTER_FLATE)
|
||||
@ -870,14 +1065,17 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
if (st->flate.avail_in == 0)
|
||||
{
|
||||
// Read more from the file...
|
||||
if (sizeof(st->cbuffer) > st->remaining)
|
||||
if (st->cbsize > st->remaining)
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
||||
else
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer));
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
||||
|
||||
if (rbytes <= 0)
|
||||
return (-1); // End of file...
|
||||
|
||||
if (st->crypto_cb)
|
||||
rbytes = (ssize_t)(st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, (size_t)rbytes);
|
||||
|
||||
st->remaining -= (size_t)rbytes;
|
||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
||||
st->flate.avail_in = (uInt)rbytes;
|
||||
@ -888,7 +1086,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);
|
||||
}
|
||||
|
||||
@ -923,25 +1121,31 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
if (st->flate.avail_in == 0)
|
||||
{
|
||||
// Read more from the file...
|
||||
if (sizeof(st->cbuffer) > st->remaining)
|
||||
if (st->cbsize > st->remaining)
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
||||
else
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer));
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
||||
|
||||
if (rbytes <= 0)
|
||||
return (-1); // End of file...
|
||||
|
||||
if (st->crypto_cb)
|
||||
rbytes = (ssize_t)(st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, (size_t)rbytes);
|
||||
|
||||
st->remaining -= (size_t)rbytes;
|
||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
||||
st->flate.avail_in = (uInt)rbytes;
|
||||
}
|
||||
|
||||
avail_in = st->flate.avail_in;
|
||||
avail_out = st->flate.avail_out;
|
||||
|
||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %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)
|
||||
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
||||
break;
|
||||
}
|
||||
|
||||
@ -987,25 +1191,31 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
if (st->flate.avail_in == 0)
|
||||
{
|
||||
// Read more from the file...
|
||||
if (sizeof(st->cbuffer) > st->remaining)
|
||||
if (st->cbsize > st->remaining)
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
||||
else
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer));
|
||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
|
||||
|
||||
if (rbytes <= 0)
|
||||
return (-1); // End of file...
|
||||
|
||||
if (st->crypto_cb)
|
||||
rbytes = (ssize_t)(st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, (size_t)rbytes);
|
||||
|
||||
st->remaining -= (size_t)rbytes;
|
||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
||||
st->flate.avail_in = (uInt)rbytes;
|
||||
}
|
||||
|
||||
avail_in = st->flate.avail_in;
|
||||
avail_out = st->flate.avail_out;
|
||||
|
||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %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)
|
||||
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1088,14 +1298,39 @@ stream_write(pdfio_stream_t *st, // I - Stream
|
||||
|
||||
while (st->flate.avail_in > 0)
|
||||
{
|
||||
if (st->flate.avail_out < (sizeof(st->cbuffer) / 8))
|
||||
if (st->flate.avail_out < (st->cbsize / 8))
|
||||
{
|
||||
// Flush the compression buffer...
|
||||
if (!_pdfioFileWrite(st->pdf, st->cbuffer, sizeof(st->cbuffer) - st->flate.avail_out))
|
||||
size_t cbytes = st->cbsize - st->flate.avail_out,
|
||||
outbytes;
|
||||
|
||||
if (st->crypto_cb)
|
||||
{
|
||||
// Encrypt it first...
|
||||
outbytes = (st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, cbytes & (size_t)~15);
|
||||
}
|
||||
else
|
||||
{
|
||||
outbytes = cbytes;
|
||||
}
|
||||
|
||||
// fprintf(stderr, "stream_write: bytes=%u, outbytes=%u\n", (unsigned)bytes, (unsigned)outbytes);
|
||||
|
||||
if (!_pdfioFileWrite(st->pdf, st->cbuffer, outbytes))
|
||||
return (false);
|
||||
|
||||
st->flate.next_out = (Bytef *)st->cbuffer;
|
||||
st->flate.avail_out = sizeof(st->cbuffer);
|
||||
if (cbytes > outbytes)
|
||||
{
|
||||
cbytes -= outbytes;
|
||||
memmove(st->cbuffer, st->cbuffer + outbytes, cbytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
cbytes = 0;
|
||||
}
|
||||
|
||||
st->flate.next_out = (Bytef *)st->cbuffer + cbytes;
|
||||
st->flate.avail_out = (uInt)(st->cbsize - cbytes);
|
||||
}
|
||||
|
||||
// Deflate what we can this time...
|
||||
|
677
pdfio-string.c
677
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-2025 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,557 @@
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
static int compare_strings(char **a, char **b);
|
||||
static size_t find_string(pdfio_file_t *pdf, const char *s, int *rdiff);
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_strlcpy()' - Safe string copy.
|
||||
//
|
||||
|
||||
size_t // O - Length of source string
|
||||
_pdfio_strlcpy(char *dst, // I - Destination string buffer
|
||||
const char *src, // I - Source string
|
||||
size_t dstsize) // I - Size of destination
|
||||
{
|
||||
size_t srclen; // Length of source string
|
||||
|
||||
|
||||
// Range check input...
|
||||
if (!dst || !src || dstsize == 0)
|
||||
{
|
||||
if (dst)
|
||||
*dst = '\0';
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Figure out how much room is needed...
|
||||
dstsize --;
|
||||
|
||||
srclen = strlen(src);
|
||||
|
||||
// Copy the appropriate amount...
|
||||
if (srclen <= dstsize)
|
||||
{
|
||||
// Source string will fit...
|
||||
memmove(dst, src, srclen);
|
||||
dst[srclen] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Source string too big, copy what we can and clean up the end...
|
||||
char *ptr = dst + dstsize - 1, // Pointer into string
|
||||
*end = ptr + 1; // Pointer to end of string
|
||||
|
||||
memmove(dst, src, dstsize);
|
||||
dst[dstsize] = '\0';
|
||||
|
||||
// Validate last character in destination buffer...
|
||||
if (ptr > dst && *ptr & 0x80)
|
||||
{
|
||||
while ((*ptr & 0xc0) == 0x80 && ptr > dst)
|
||||
ptr --;
|
||||
|
||||
if ((*ptr & 0xe0) == 0xc0)
|
||||
{
|
||||
// Verify 2-byte UTF-8 sequence...
|
||||
if ((end - ptr) != 2)
|
||||
*ptr = '\0';
|
||||
}
|
||||
else if ((*ptr & 0xf0) == 0xe0)
|
||||
{
|
||||
// Verify 3-byte UTF-8 sequence...
|
||||
if ((end - ptr) != 3)
|
||||
*ptr = '\0';
|
||||
}
|
||||
else if ((*ptr & 0xf8) == 0xf0)
|
||||
{
|
||||
// Verify 4-byte UTF-8 sequence...
|
||||
if ((end - ptr) != 4)
|
||||
*ptr = '\0';
|
||||
}
|
||||
else if (*ptr & 0x80)
|
||||
{
|
||||
// Invalid sequence at end...
|
||||
*ptr = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (srclen);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_strtod()' - Convert a string to a double value.
|
||||
//
|
||||
// This function wraps strtod() to avoid locale issues.
|
||||
//
|
||||
|
||||
double // O - Double value
|
||||
_pdfio_strtod(pdfio_file_t *pdf, // I - PDF file
|
||||
const char *s) // I - String
|
||||
{
|
||||
char temp[64], // Temporary buffer
|
||||
*tempptr; // Pointer into temporary buffer
|
||||
|
||||
|
||||
// See if the locale has a special decimal point string...
|
||||
if (!pdf->loc)
|
||||
return (strtod(s, NULL));
|
||||
|
||||
// Copy leading sign, numbers, period, and then numbers...
|
||||
tempptr = temp;
|
||||
temp[sizeof(temp) - 1] = '\0';
|
||||
|
||||
while (*s && *s != '.')
|
||||
{
|
||||
if (tempptr < (temp + sizeof(temp) - 1))
|
||||
*tempptr++ = *s++;
|
||||
else
|
||||
return (0.0);
|
||||
}
|
||||
|
||||
if (*s == '.')
|
||||
{
|
||||
// Convert decimal point to locale equivalent...
|
||||
size_t declen = strlen(pdf->loc->decimal_point);
|
||||
// Length of decimal point
|
||||
s ++;
|
||||
|
||||
if (declen <= (sizeof(temp) - (size_t)(tempptr - temp)))
|
||||
{
|
||||
memcpy(tempptr, pdf->loc->decimal_point, declen);
|
||||
tempptr += declen;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy any remaining characters...
|
||||
while (*s)
|
||||
{
|
||||
if (tempptr < (temp + sizeof(temp) - 1))
|
||||
*tempptr++ = *s++;
|
||||
else
|
||||
return (0.0);
|
||||
}
|
||||
|
||||
// Nul-terminate the temporary string and convert the string...
|
||||
*tempptr = '\0';
|
||||
|
||||
return (strtod(temp, NULL));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_vsnprintf()' - Format a string.
|
||||
//
|
||||
// This function emulates vsnprintf() to avoid locale issues.
|
||||
//
|
||||
|
||||
ssize_t // O - Number of bytes
|
||||
_pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
char *buffer, // I - Output buffer
|
||||
size_t bufsize, // I - Size of output buffer
|
||||
const char *format, // I - printf-style format string
|
||||
va_list ap) // I - Pointer to additional arguments
|
||||
{
|
||||
char *bufptr, // Pointer to position in buffer
|
||||
*bufend, // Pointer to end of buffer
|
||||
size, // Size character (h, l, L)
|
||||
type; // Format type character
|
||||
int width, // Width of field
|
||||
prec; // Number of characters of precision
|
||||
char tformat[100], // Temporary format string for snprintf()
|
||||
*tptr, // Pointer into temporary format
|
||||
temp[1024], // Buffer for formatted numbers
|
||||
*tempptr; // Pointer into buffer
|
||||
char *s; // Pointer to string
|
||||
ssize_t bytes; // Total number of bytes needed
|
||||
const char *dec = pdf->loc ? pdf->loc->decimal_point : ".";
|
||||
// Decimal point string
|
||||
char *decptr; // Pointer to decimal point
|
||||
|
||||
|
||||
// Loop through the format string, formatting as needed...
|
||||
bufptr = buffer;
|
||||
bufend = buffer + bufsize - 1;
|
||||
bytes = 0;
|
||||
|
||||
while (*format)
|
||||
{
|
||||
if (*format == '%')
|
||||
{
|
||||
// Format character...
|
||||
tptr = tformat;
|
||||
*tptr++ = *format++;
|
||||
|
||||
if (*format == '%')
|
||||
{
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *format;
|
||||
bytes ++;
|
||||
format ++;
|
||||
continue;
|
||||
}
|
||||
else if (strchr(" -+#\'", *format))
|
||||
{
|
||||
*tptr++ = *format++;
|
||||
}
|
||||
|
||||
if (*format == '*')
|
||||
{
|
||||
// Get width from argument...
|
||||
format ++;
|
||||
width = va_arg(ap, int);
|
||||
|
||||
snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", width);
|
||||
tptr += strlen(tptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
width = 0;
|
||||
|
||||
while (isdigit(*format & 255))
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
width = width * 10 + *format++ - '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (*format == '.')
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
format ++;
|
||||
|
||||
if (*format == '*')
|
||||
{
|
||||
// Get precision from argument...
|
||||
format ++;
|
||||
prec = va_arg(ap, int);
|
||||
|
||||
snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", prec);
|
||||
tptr += strlen(tptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (isdigit(*format & 255))
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
format ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*format == 'l' && format[1] == 'l')
|
||||
{
|
||||
size = 'L';
|
||||
|
||||
if (tptr < (tformat + sizeof(tformat) - 2))
|
||||
{
|
||||
*tptr++ = 'l';
|
||||
*tptr++ = 'l';
|
||||
}
|
||||
|
||||
format += 2;
|
||||
}
|
||||
else if (*format == 'h' || *format == 'l' || *format == 'L')
|
||||
{
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
size = *format++;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = 0;
|
||||
}
|
||||
|
||||
if (!*format)
|
||||
break;
|
||||
|
||||
if (tptr < (tformat + sizeof(tformat) - 1))
|
||||
*tptr++ = *format;
|
||||
|
||||
type = *format++;
|
||||
*tptr = '\0';
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 'E' : // Floating point formats
|
||||
case 'G' :
|
||||
case 'e' :
|
||||
case 'f' :
|
||||
case 'g' :
|
||||
if ((size_t)(width + 2) > sizeof(temp))
|
||||
break;
|
||||
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, double));
|
||||
|
||||
if ((decptr = strstr(temp, dec)) != NULL)
|
||||
{
|
||||
// Convert locale decimal point to "."
|
||||
PDFIO_DEBUG("_pdfio_vsnprintf: Before \"%s\"\n", temp);
|
||||
tempptr = decptr + strlen(dec);
|
||||
if (tempptr > (decptr + 1))
|
||||
memmove(decptr + 1, tempptr, strlen(tempptr) + 1);
|
||||
*decptr = '.';
|
||||
|
||||
// Strip trailing 0's...
|
||||
for (tempptr = temp + strlen(temp) - 1; tempptr > temp && *tempptr == '0'; tempptr --)
|
||||
*tempptr = '\0';
|
||||
|
||||
if (*tempptr == '.')
|
||||
*tempptr = '\0'; // Strip trailing decimal point
|
||||
|
||||
PDFIO_DEBUG("_pdfio_vsnprintf: After \"%s\"\n", temp);
|
||||
}
|
||||
|
||||
// Copy to the output buffer
|
||||
bytes += (int)strlen(temp);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'B' : // Integer formats
|
||||
case 'X' :
|
||||
case 'b' :
|
||||
case 'd' :
|
||||
case 'i' :
|
||||
case 'o' :
|
||||
case 'u' :
|
||||
case 'x' :
|
||||
if ((size_t)(width + 2) > sizeof(temp))
|
||||
break;
|
||||
|
||||
# ifdef HAVE_LONG_LONG
|
||||
if (size == 'L')
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, long long));
|
||||
else
|
||||
# endif // HAVE_LONG_LONG
|
||||
if (size == 'l')
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, long));
|
||||
else
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, int));
|
||||
|
||||
bytes += (int)strlen(temp);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p' : // Pointer value
|
||||
if ((size_t)(width + 2) > sizeof(temp))
|
||||
break;
|
||||
|
||||
snprintf(temp, sizeof(temp), tformat, va_arg(ap, void *));
|
||||
|
||||
bytes += (int)strlen(temp);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c' : // Character or character array
|
||||
bytes += width;
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
if (width <= 1)
|
||||
{
|
||||
*bufptr++ = (char)va_arg(ap, int);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((bufptr + width) > bufend)
|
||||
width = (int)(bufend - bufptr);
|
||||
|
||||
memcpy(bufptr, va_arg(ap, char *), (size_t)width);
|
||||
bufptr += width;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S' : // PDF string
|
||||
if ((s = va_arg(ap, char *)) == NULL)
|
||||
s = "(null)";
|
||||
|
||||
// PDF strings start with "("...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = '(';
|
||||
|
||||
bytes ++;
|
||||
|
||||
// Loop through the literal string...
|
||||
while (*s)
|
||||
{
|
||||
// Escape special characters
|
||||
if (*s == '\\' || *s == '(' || *s == ')')
|
||||
{
|
||||
// Simple escape...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = '\\';
|
||||
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *s;
|
||||
|
||||
bytes += 2;
|
||||
}
|
||||
else if (*s < ' ')
|
||||
{
|
||||
// Octal escape...
|
||||
snprintf(bufptr, (size_t)(bufend - bufptr + 1), "\\%03o", *s & 255);
|
||||
bufptr += strlen(bufptr);
|
||||
bytes += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal character...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *s;
|
||||
bytes ++;
|
||||
}
|
||||
|
||||
s ++;
|
||||
}
|
||||
|
||||
// PDF strings end with ")"...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = ')';
|
||||
|
||||
bytes ++;
|
||||
break;
|
||||
|
||||
case 's' : // Literal string
|
||||
if ((s = va_arg(ap, char *)) == NULL)
|
||||
s = "(null)";
|
||||
|
||||
if (width != 0)
|
||||
{
|
||||
// Format string to fit inside the specified width...
|
||||
if ((size_t)(width + 1) > sizeof(temp))
|
||||
break;
|
||||
|
||||
snprintf(temp, sizeof(temp), tformat, s);
|
||||
s = temp;
|
||||
}
|
||||
|
||||
bytes += strlen(s);
|
||||
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, s, (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N' : // Output name string with proper escaping
|
||||
if ((s = va_arg(ap, char *)) == NULL)
|
||||
s = "(null)";
|
||||
|
||||
// PDF names start with "/"...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = '/';
|
||||
|
||||
bytes ++;
|
||||
|
||||
// Loop through the name string...
|
||||
while (*s)
|
||||
{
|
||||
if (*s < 0x21 || *s > 0x7e || *s == '#')
|
||||
{
|
||||
// Output #XX for character...
|
||||
snprintf(bufptr, (size_t)(bufend - bufptr + 1), "#%02X", *s & 255);
|
||||
bufptr += strlen(bufptr);
|
||||
bytes += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Output literal character...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *s;
|
||||
bytes ++;
|
||||
}
|
||||
|
||||
s ++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n' : // Output number of chars so far
|
||||
*(va_arg(ap, int *)) = (int)bytes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal character...
|
||||
bytes ++;
|
||||
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *format++;
|
||||
}
|
||||
}
|
||||
|
||||
// Nul-terminate the string and return the number of characters needed.
|
||||
*bufptr = '\0';
|
||||
|
||||
PDFIO_DEBUG("_pdfio_vsnprintf: Returning %ld \"%s\"\n", (long)bytes, buffer);
|
||||
|
||||
return (bytes);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioStringAllocBuffer()' - Allocate a string buffer.
|
||||
//
|
||||
|
||||
char * // O - Buffer or `NULL` on error
|
||||
_pdfioStringAllocBuffer(
|
||||
pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
_pdfio_strbuf_t *current; // Current string buffer
|
||||
|
||||
|
||||
// See if we have an available string buffer...
|
||||
for (current = pdf->strbuffers; current; current = current->next)
|
||||
{
|
||||
if (!current->bufused)
|
||||
{
|
||||
current->bufused = true;
|
||||
return (current->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find one, allocate a new one...
|
||||
if ((current = calloc(1, sizeof(_pdfio_strbuf_t))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
// Add to the linked list of string buffers...
|
||||
current->next = pdf->strbuffers;
|
||||
current->bufused = true;
|
||||
|
||||
pdf->strbuffers = current;
|
||||
|
||||
return (current->buffer);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
@ -36,8 +582,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 +594,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 +625,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);
|
||||
|
||||
@ -115,6 +677,29 @@ pdfioStringCreatef(
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioStringFreeBuffer()' - Free a string buffer.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfioStringFreeBuffer(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
char *buffer) // I - String buffer
|
||||
{
|
||||
_pdfio_strbuf_t *current; // Current string buffer
|
||||
|
||||
|
||||
for (current = pdf->strbuffers; current; current = current->next)
|
||||
{
|
||||
if (current->buffer == buffer)
|
||||
{
|
||||
current->bufused = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioStringIsAllocated()' - Check whether a string has been allocated.
|
||||
//
|
||||
@ -124,17 +709,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);
|
||||
}
|
||||
|
136
pdfio-token.c
136
pdfio-token.c
@ -1,16 +1,12 @@
|
||||
//
|
||||
// PDF token parsing functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
@ -129,9 +125,20 @@ _pdfioTokenGet(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
if (tb->num_tokens > 0)
|
||||
{
|
||||
// Yes, return it...
|
||||
size_t len; // Length of token
|
||||
|
||||
tb->num_tokens --;
|
||||
strncpy(buffer, tb->tokens[tb->num_tokens], bufsize - 1);
|
||||
buffer[bufsize - 1] = '\0';
|
||||
|
||||
if ((len = strlen(tb->tokens[tb->num_tokens])) > (bufsize - 1))
|
||||
{
|
||||
// Value too large...
|
||||
PDFIO_DEBUG("_pdfioTokenGet(tb=%p, buffer=%p, bufsize=%u): Token '%s' from stack too large.\n", tb, buffer, (unsigned)bufsize, tb->tokens[tb->num_tokens]);
|
||||
*buffer = '\0';
|
||||
return (false);
|
||||
}
|
||||
|
||||
memcpy(buffer, tb->tokens[tb->num_tokens], len);
|
||||
buffer[len] = '\0';
|
||||
|
||||
PDFIO_DEBUG("_pdfioTokenGet(tb=%p, buffer=%p, bufsize=%u): Popping '%s' from stack.\n", tb, buffer, (unsigned)bufsize, buffer);
|
||||
|
||||
@ -200,9 +207,11 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
char *bufptr, // Pointer into buffer
|
||||
*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
|
||||
@ -221,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)
|
||||
@ -255,11 +288,16 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
*bufptr++ = (char)ch;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioTokenRead: state='%c'\n", state);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case '(' : // Literal string
|
||||
while ((ch = get_char(tb)) != EOF)
|
||||
{
|
||||
if (ch == 0)
|
||||
saw_nul = true;
|
||||
|
||||
if (ch == '\\')
|
||||
{
|
||||
// Quoted character...
|
||||
@ -280,7 +318,9 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
int tch = get_char(tb); // Next char
|
||||
|
||||
if (tch >= '0' && tch <= '7')
|
||||
{
|
||||
ch = (char)((ch << 3) | (tch - '0'));
|
||||
}
|
||||
else
|
||||
{
|
||||
tb->bufptr --;
|
||||
@ -341,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);
|
||||
}
|
||||
}
|
||||
@ -348,8 +389,40 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
if (ch != ')')
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Unterminated string literal.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (saw_nul)
|
||||
{
|
||||
// Convert to a hex (binary) string...
|
||||
char *litptr, // Pointer to literal character
|
||||
*hexptr; // Pointer to hex character
|
||||
size_t bytes = (size_t)(bufptr - buffer - 1);
|
||||
// Bytes of data...
|
||||
static const char *hexchars = "0123456789ABCDEF";
|
||||
// Hex digits
|
||||
|
||||
PDFIO_DEBUG("_pdfioTokenRead: Converting nul-containing string to binary.\n");
|
||||
|
||||
if ((2 * (bytes + 1)) > bufsize)
|
||||
{
|
||||
// Out of space...
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
|
||||
*buffer = '<';
|
||||
for (litptr = bufptr - 1, hexptr = buffer + 2 * bytes - 1; litptr > buffer; litptr --, hexptr -= 2)
|
||||
{
|
||||
int litch = *litptr; // Grab the character
|
||||
|
||||
hexptr[0] = hexchars[(litch >> 4) & 15];
|
||||
hexptr[1] = hexchars[litch & 15];
|
||||
}
|
||||
bufptr = buffer + 2 * bytes + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'K' : // keyword
|
||||
@ -370,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
|
||||
@ -381,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;
|
||||
}
|
||||
@ -393,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);
|
||||
}
|
||||
}
|
||||
@ -419,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,6 +524,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
{
|
||||
// Out of space
|
||||
_pdfioFileError(tb->pdf, "Token too large.");
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
@ -448,13 +537,23 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
*bufptr++ = (char)ch;
|
||||
break;
|
||||
}
|
||||
else if (ch == '>')
|
||||
{
|
||||
// Issue #46: Empty hex string from Microsoft PDF generator; treat as
|
||||
// empty literal string...
|
||||
*buffer = '(';
|
||||
break;
|
||||
}
|
||||
else if (!isspace(ch & 255) && !isxdigit(ch & 255))
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Syntax error: '<%c'", ch);
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
|
||||
while ((ch = get_char(tb)) != EOF && ch != '>')
|
||||
count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (isxdigit(ch))
|
||||
{
|
||||
@ -462,24 +561,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;
|
||||
@ -492,14 +606,12 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
else
|
||||
{
|
||||
_pdfioFileError(tb->pdf, "Syntax error: '>%c'.", ch);
|
||||
*bufptr = '\0';
|
||||
return (false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
while (tb->bufptr < tb->bufend && isspace(*(tb->bufptr)))
|
||||
tb->bufptr ++;
|
||||
|
||||
*bufptr = '\0';
|
||||
|
||||
PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
||||
|
562
pdfio-value.c
562
pdfio-value.c
@ -1,17 +1,20 @@
|
||||
//
|
||||
// PDF value functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
#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,108 @@ _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 = NULL; // 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 > PDFIO_MAX_STRING)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted binary string - too long.");
|
||||
return (false);
|
||||
}
|
||||
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted binary string - out of memory.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
ivlen = v->value.binary.datalen;
|
||||
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL)
|
||||
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;
|
||||
|
||||
_pdfioStringFreeBuffer(pdf, (char *)temp);
|
||||
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 +222,9 @@ void
|
||||
_pdfioValueDebug(_pdfio_value_t *v, // I - Value
|
||||
FILE *fp) // I - Output file
|
||||
{
|
||||
if (!v)
|
||||
return;
|
||||
|
||||
switch (v->type)
|
||||
{
|
||||
case PDFIO_VALTYPE_ARRAY :
|
||||
@ -194,10 +302,15 @@ _pdfioValueDelete(_pdfio_value_t *v) // I - Value
|
||||
|
||||
_pdfio_value_t * // O - Value or `NULL` on error/EOF
|
||||
_pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
pdfio_obj_t *obj, // I - Object, if any
|
||||
_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
_pdfio_value_t *v) // I - Value
|
||||
_pdfio_value_t *v, // I - Value
|
||||
size_t depth) // I - Depth of value
|
||||
{
|
||||
char token[32768]; // Token buffer
|
||||
_pdfio_value_t *ret = NULL; // Return value
|
||||
char *token = _pdfioStringAllocBuffer(pdf);
|
||||
// Token buffer
|
||||
time_t timeval; // Date/time value
|
||||
#ifdef DEBUG
|
||||
static const char * const valtypes[] =
|
||||
{
|
||||
@ -216,101 +329,63 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioValueRead(pdf=%p, v=%p)\n", pdf, v);
|
||||
PDFIO_DEBUG("_pdfioValueRead(pdf=%p, obj=%p, v=%p)\n", pdf, obj, v);
|
||||
|
||||
if (!_pdfioTokenGet(tb, token, sizeof(token)))
|
||||
return (NULL);
|
||||
if (!token)
|
||||
goto done;
|
||||
|
||||
if (!_pdfioTokenGet(tb, token, PDFIO_MAX_STRING))
|
||||
goto done;
|
||||
|
||||
if (!strcmp(token, "["))
|
||||
{
|
||||
// Start of array
|
||||
if (depth >= PDFIO_MAX_DEPTH)
|
||||
{
|
||||
_pdfioFileError(pdf, "Too many nested arrays.");
|
||||
goto done;
|
||||
}
|
||||
|
||||
v->type = PDFIO_VALTYPE_ARRAY;
|
||||
if ((v->value.array = _pdfioArrayRead(pdf, tb)) == NULL)
|
||||
return (NULL);
|
||||
if ((v->value.array = _pdfioArrayRead(pdf, obj, tb, depth + 1)) == NULL)
|
||||
goto done;
|
||||
|
||||
ret = v;
|
||||
}
|
||||
else if (!strcmp(token, "<<"))
|
||||
{
|
||||
// Start of dictionary
|
||||
if (depth >= PDFIO_MAX_DEPTH)
|
||||
{
|
||||
_pdfioFileError(pdf, "Too many nested dictionaries.");
|
||||
goto done;
|
||||
}
|
||||
|
||||
v->type = PDFIO_VALTYPE_DICT;
|
||||
if ((v->value.dict = _pdfioDictRead(pdf, tb)) == NULL)
|
||||
return (NULL);
|
||||
if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL)
|
||||
goto done;
|
||||
|
||||
ret = v;
|
||||
}
|
||||
else if (!strncmp(token, "(D:", 3))
|
||||
else if ((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...
|
||||
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;
|
||||
ret = v;
|
||||
}
|
||||
else if (token[0] == '(')
|
||||
{
|
||||
// String
|
||||
v->type = PDFIO_VALTYPE_STRING;
|
||||
v->value.string = pdfioStringCreate(pdf, token + 1);
|
||||
ret = v;
|
||||
}
|
||||
else if (token[0] == '/')
|
||||
{
|
||||
// Name
|
||||
v->type = PDFIO_VALTYPE_NAME;
|
||||
v->value.name = pdfioStringCreate(pdf, token + 1);
|
||||
ret = v;
|
||||
}
|
||||
else if (token[0] == '<')
|
||||
{
|
||||
@ -323,7 +398,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
if ((v->value.binary.data = (unsigned char *)malloc(v->value.binary.datalen)) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Out of memory for hex string.");
|
||||
return (NULL);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Convert hex to binary...
|
||||
@ -350,6 +425,8 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
*dataptr++ = (unsigned char)d;
|
||||
}
|
||||
|
||||
ret = v;
|
||||
}
|
||||
else if (strchr("0123456789-+.", token[0]) != NULL)
|
||||
{
|
||||
@ -396,6 +473,9 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
tempptr = tb->bufptr;
|
||||
|
||||
while (tempptr < tb->bufend && isspace(*tempptr & 255))
|
||||
tempptr ++; // Skip whitespace as needed...
|
||||
|
||||
if (tempptr < tb->bufend && isdigit(*tempptr & 255))
|
||||
{
|
||||
// Integer...
|
||||
@ -408,7 +488,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
while (tempptr < tb->bufend && isspace(*tempptr & 255))
|
||||
tempptr ++;
|
||||
tempptr ++; // Skip whitespace
|
||||
|
||||
if (tempptr < tb->bufend && *tempptr == 'R')
|
||||
{
|
||||
@ -434,35 +514,50 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
PDFIO_DEBUG("_pdfioValueRead: Returning indirect value %lu %u R.\n", (unsigned long)v->value.indirect.number, v->value.indirect.generation);
|
||||
|
||||
return (v);
|
||||
ret = v;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
ret = v;
|
||||
}
|
||||
else if (!strcmp(token, "true") || !strcmp(token, "false"))
|
||||
{
|
||||
// Boolean value
|
||||
v->type = PDFIO_VALTYPE_BOOLEAN;
|
||||
v->value.boolean = !strcmp(token, "true");
|
||||
ret = v;
|
||||
}
|
||||
else if (!strcmp(token, "null"))
|
||||
{
|
||||
// null value
|
||||
v->type = PDFIO_VALTYPE_NULL;
|
||||
ret = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
_pdfioFileError(pdf, "Unexpected '%s' token seen.", token);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioValueRead: Returning %s value.\n", valtypes[v->type]);
|
||||
done:
|
||||
|
||||
return (v);
|
||||
if (token)
|
||||
_pdfioStringFreeBuffer(pdf, token);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioValueRead: Returning %s value.\n", valtypes[ret->type]);
|
||||
return (ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioValueRead: Returning NULL.\n");
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -472,6 +567,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
_pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
pdfio_obj_t *obj, // I - Object, if any
|
||||
_pdfio_value_t *v, // I - Value
|
||||
off_t *length)// O - Offset to /Length value, if any
|
||||
{
|
||||
@ -481,26 +577,64 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
return (false);
|
||||
|
||||
case PDFIO_VALTYPE_ARRAY :
|
||||
return (_pdfioArrayWrite(v->value.array));
|
||||
return (_pdfioArrayWrite(v->value.array, obj));
|
||||
|
||||
case PDFIO_VALTYPE_BINARY :
|
||||
{
|
||||
size_t i; // Looping var
|
||||
unsigned char *dataptr; // Pointer into data
|
||||
size_t databytes; // Bytes to write
|
||||
uint8_t *temp = NULL, // Temporary buffer for encryption
|
||||
*dataptr; // Pointer into data
|
||||
bool ret = false; // Return value
|
||||
|
||||
if (!_pdfioFilePuts(pdf, "<"))
|
||||
return (false);
|
||||
|
||||
for (i = v->value.binary.datalen, dataptr = v->value.binary.data; i > 1; i -= 2, dataptr += 2)
|
||||
if (obj && pdf->encryption)
|
||||
{
|
||||
if (!_pdfioFilePrintf(pdf, "%02X%02X", dataptr[0], dataptr[1]))
|
||||
return (false);
|
||||
// Write encrypted string...
|
||||
_pdfio_crypto_ctx_t ctx; // Encryption context
|
||||
_pdfio_crypto_cb_t cb; // Encryption callback
|
||||
size_t ivlen; // Number of initialization vector bytes
|
||||
|
||||
if (v->value.binary.datalen > PDFIO_MAX_STRING)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to write encrypted binary string - too long.");
|
||||
return (false);
|
||||
}
|
||||
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to write encrypted binary string - out of memory.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
|
||||
databytes = (cb)(&ctx, temp + ivlen, v->value.binary.data, v->value.binary.datalen) + ivlen;
|
||||
dataptr = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
dataptr = v->value.binary.data;
|
||||
databytes = v->value.binary.datalen;
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
return (_pdfioFilePrintf(pdf, "%02X>", dataptr[0]));
|
||||
else
|
||||
return (_pdfioFilePuts(pdf, ">"));
|
||||
if (!_pdfioFilePuts(pdf, "<"))
|
||||
goto bindone;
|
||||
|
||||
for (; databytes > 1; databytes -= 2, dataptr += 2)
|
||||
{
|
||||
if (!_pdfioFilePrintf(pdf, "%02X%02X", dataptr[0], dataptr[1]))
|
||||
goto bindone;
|
||||
}
|
||||
|
||||
if (databytes > 0 && !_pdfioFilePrintf(pdf, "%02X", dataptr[0]))
|
||||
goto bindone;
|
||||
|
||||
ret = _pdfioFilePuts(pdf, ">");
|
||||
|
||||
bindone:
|
||||
|
||||
if (temp)
|
||||
_pdfioStringFreeBuffer(pdf, (char *)temp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
case PDFIO_VALTYPE_BOOLEAN :
|
||||
@ -512,6 +646,7 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
case PDFIO_VALTYPE_DATE :
|
||||
{
|
||||
struct tm date; // Date values
|
||||
char datestr[32]; // Formatted date value
|
||||
|
||||
#ifdef _WIN32
|
||||
gmtime_s(&date, &v->value.date);
|
||||
@ -519,69 +654,226 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
gmtime_r(&v->value.date, &date);
|
||||
#endif // _WIN32
|
||||
|
||||
return (_pdfioFilePrintf(pdf, "(D:%04d%02d%02d%02d%02d%02dZ)", date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, date.tm_hour, date.tm_min, date.tm_sec));
|
||||
snprintf(datestr, sizeof(datestr), "D:%04d%02d%02d%02d%02d%02dZ", date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, date.tm_hour, date.tm_min, date.tm_sec);
|
||||
|
||||
if (obj && pdf->encryption)
|
||||
{
|
||||
// Write encrypted string...
|
||||
uint8_t temp[64], // Encrypted bytes
|
||||
*tempptr; // Pointer into encrypted bytes
|
||||
_pdfio_crypto_ctx_t ctx; // Encryption context
|
||||
_pdfio_crypto_cb_t cb; // Encryption callback
|
||||
size_t len = strlen(datestr),
|
||||
// Length of value
|
||||
ivlen, // Number of initialization vector bytes
|
||||
tempbytes; // Number of output bytes
|
||||
|
||||
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
|
||||
tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)datestr, len) + ivlen;
|
||||
|
||||
if (!_pdfioFilePuts(pdf, "<"))
|
||||
return (false);
|
||||
|
||||
for (tempptr = temp; tempbytes > 1; tempbytes -= 2, tempptr += 2)
|
||||
{
|
||||
if (!_pdfioFilePrintf(pdf, "%02X%02X", tempptr[0], tempptr[1]))
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (tempbytes > 0)
|
||||
return (_pdfioFilePrintf(pdf, "%02X>", *tempptr));
|
||||
else
|
||||
return (_pdfioFilePuts(pdf, ">"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (_pdfioFilePrintf(pdf, "%S", datestr));
|
||||
}
|
||||
}
|
||||
|
||||
case PDFIO_VALTYPE_DICT :
|
||||
return (_pdfioDictWrite(v->value.dict, length));
|
||||
return (_pdfioDictWrite(v->value.dict, obj, length));
|
||||
|
||||
case PDFIO_VALTYPE_INDIRECT :
|
||||
return (_pdfioFilePrintf(pdf, " %lu %u R", (unsigned long)v->value.indirect.number, v->value.indirect.generation));
|
||||
|
||||
case PDFIO_VALTYPE_NAME :
|
||||
return (_pdfioFilePrintf(pdf, "/%s", v->value.name));
|
||||
return (_pdfioFilePrintf(pdf, "%N", v->value.name));
|
||||
|
||||
case PDFIO_VALTYPE_NULL :
|
||||
return (_pdfioFilePuts(pdf, " null"));
|
||||
|
||||
case PDFIO_VALTYPE_NUMBER :
|
||||
return (_pdfioFilePrintf(pdf, " %g", v->value.number));
|
||||
return (_pdfioFilePrintf(pdf, " %.6f", v->value.number));
|
||||
|
||||
case PDFIO_VALTYPE_STRING :
|
||||
if (obj && pdf->encryption)
|
||||
{
|
||||
const char *start, // Start of fragment
|
||||
*end; // End of fragment
|
||||
// Write encrypted string...
|
||||
uint8_t *temp = NULL, // Encrypted bytes
|
||||
*tempptr; // Pointer into encrypted bytes
|
||||
_pdfio_crypto_ctx_t ctx; // Encryption context
|
||||
_pdfio_crypto_cb_t cb; // Encryption callback
|
||||
size_t len = strlen(v->value.string),
|
||||
// Length of value
|
||||
ivlen, // Number of initialization vector bytes
|
||||
tempbytes; // Number of output bytes
|
||||
bool ret = false; // Return value
|
||||
|
||||
if (!_pdfioFilePuts(pdf, "("))
|
||||
return (false);
|
||||
|
||||
// Write a quoted string value...
|
||||
for (start = v->value.string; *start; start = end)
|
||||
if (len > PDFIO_MAX_STRING)
|
||||
{
|
||||
// Find the next character that needs to be quoted...
|
||||
for (end = start; *end; end ++)
|
||||
{
|
||||
if (*end == '\\' || *end == ')' || (*end & 255) < ' ')
|
||||
break;
|
||||
}
|
||||
|
||||
if (end > start)
|
||||
{
|
||||
// Write unquoted (safe) characters...
|
||||
if (!_pdfioFileWrite(pdf, start, (size_t)(end - start)))
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (*end)
|
||||
{
|
||||
// Quote this character...
|
||||
bool success; // Did the write work?
|
||||
|
||||
if (*end == '\\' || *end == ')')
|
||||
success = _pdfioFilePrintf(pdf, "\\%c", *end);
|
||||
else
|
||||
success = _pdfioFilePrintf(pdf, "\\%03o", *end);
|
||||
|
||||
if (!success)
|
||||
return (false);
|
||||
|
||||
end ++;
|
||||
}
|
||||
_pdfioFileError(pdf, "Unable to write encrypted string - too long.");
|
||||
return (false);
|
||||
}
|
||||
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to write encrypted string - out of memory.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (_pdfioFilePuts(pdf, ")"));
|
||||
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
|
||||
tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)v->value.string, len) + ivlen;
|
||||
|
||||
if (!_pdfioFilePuts(pdf, "<"))
|
||||
goto strdone;
|
||||
|
||||
for (tempptr = temp; tempbytes > 1; tempbytes -= 2, tempptr += 2)
|
||||
{
|
||||
if (!_pdfioFilePrintf(pdf, "%02X%02X", tempptr[0], tempptr[1]))
|
||||
goto strdone;
|
||||
}
|
||||
|
||||
if (tempbytes > 0 && !_pdfioFilePrintf(pdf, "%02X", *tempptr))
|
||||
goto strdone;
|
||||
|
||||
ret = _pdfioFilePuts(pdf, ">");
|
||||
|
||||
strdone :
|
||||
|
||||
_pdfioStringFreeBuffer(pdf, (char *)temp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write unencrypted string...
|
||||
return (_pdfioFilePrintf(pdf, "%S", v->value.string));
|
||||
}
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'get_date_time()' - Convert PDF date/time value to time_t.
|
||||
//
|
||||
|
||||
static time_t // O - Time in seconds or `0` for none
|
||||
get_date_time(const char *s) // I - PDF date/time value
|
||||
{
|
||||
int i; // Looping var
|
||||
struct tm dateval; // Date value
|
||||
int offset = 0; // Date offset in seconds
|
||||
time_t t; // Time value
|
||||
|
||||
|
||||
PDFIO_DEBUG("get_date_time(s=\"%s\")\n", s);
|
||||
|
||||
// Possible date value of the form:
|
||||
//
|
||||
// D:YYYYMMDDhhmmssZ
|
||||
// D:YYYYMMDDhhmmss+HH'mm
|
||||
// D:YYYYMMDDhhmmss-HH'mm
|
||||
//
|
||||
|
||||
if (strncmp(s, "D:", 2))
|
||||
return (0);
|
||||
|
||||
for (i = 2; i < 16; i ++)
|
||||
{
|
||||
// Look for date/time digits...
|
||||
if (!isdigit(s[i] & 255) || !s[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < 6 || (i & 1))
|
||||
{
|
||||
// Short year or missing digit...
|
||||
return (0);
|
||||
}
|
||||
|
||||
memset(&dateval, 0, sizeof(dateval));
|
||||
|
||||
dateval.tm_year = (s[2] - '0') * 1000 + (s[3] - '0') * 100 + (s[4] - '0') * 10 + s[5] - '0' - 1900;
|
||||
if (i > 6)
|
||||
dateval.tm_mon = (s[6] - '0') * 10 + s[7] - '0' - 1;
|
||||
if (i > 8)
|
||||
dateval.tm_mday = (s[8] - '0') * 10 + s[9] - '0';
|
||||
else
|
||||
dateval.tm_mday = 1;
|
||||
if (i > 10)
|
||||
dateval.tm_hour = (s[10] - '0') * 10 + s[11] - '0';
|
||||
if (i > 12)
|
||||
dateval.tm_min = (s[12] - '0') * 10 + s[13] - '0';
|
||||
if (i > 14)
|
||||
dateval.tm_sec = (s[14] - '0') * 10 + s[15] - '0';
|
||||
|
||||
if (i >= 16 && s[i])
|
||||
{
|
||||
// Get zone info...
|
||||
if (s[i] == 'Z')
|
||||
{
|
||||
// UTC...
|
||||
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))
|
||||
{
|
||||
offset = (s[i + 1] - '0') * 36000 + (s[i + 2] - '0') * 3600 + (s[i + 4] - '0') * 600 + (s[i + 5] - '0') * 60;
|
||||
if (s[i] == '-')
|
||||
offset = -offset;
|
||||
|
||||
i += 6;
|
||||
|
||||
// Accept trailing quote, per PDF spec...
|
||||
if (s[i] == '\'')
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Random zone info, invalid date string...
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (s[i])
|
||||
{
|
||||
// Just a string...
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Convert date value to time_t...
|
||||
#if _WIN32
|
||||
if ((t = _mkgmtime(&dateval)) < 0)
|
||||
return (0);
|
||||
#elif defined(HAVE_TIMEGM)
|
||||
if ((t = timegm(&dateval)) < 0)
|
||||
return (0);
|
||||
#else
|
||||
if ((t = mktime(&dateval)) < 0)
|
||||
return (0);
|
||||
|
||||
# if defined(HAVE_TM_GMTOFF)
|
||||
localtime_r(&t, &dateval);
|
||||
t -= dateval.tm_gmtoff;
|
||||
# else
|
||||
t -= timezone;
|
||||
# endif // HAVE_TM_GMTOFF
|
||||
#endif // _WIN32
|
||||
|
||||
return (t + offset);
|
||||
}
|
||||
|
82
pdfio.h
82
pdfio.h
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Public header file for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -9,37 +9,35 @@
|
||||
|
||||
#ifndef PDFIO_H
|
||||
# define PDFIO_H
|
||||
|
||||
//
|
||||
// Include necessary headers...
|
||||
//
|
||||
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdbool.h>
|
||||
# include <sys/types.h>
|
||||
# include <time.h>
|
||||
|
||||
|
||||
//
|
||||
// C++ magic...
|
||||
//
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif // __cplusplus
|
||||
|
||||
|
||||
//
|
||||
// Version numbers...
|
||||
//
|
||||
|
||||
# define PDFIO_VERSION "1.5.2"
|
||||
# define PDFIO_VERSION_MAJOR 1
|
||||
# define PDFIO_VERSION_MINOR 5
|
||||
|
||||
|
||||
//
|
||||
// Visibility and other annotations...
|
||||
//
|
||||
|
||||
# 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__
|
||||
|
||||
|
||||
@ -55,10 +53,20 @@ typedef struct _pdfio_array_s pdfio_array_t;
|
||||
// Array of PDF values
|
||||
typedef struct _pdfio_dict_s pdfio_dict_t;
|
||||
// Key/value dictionary
|
||||
typedef bool (*pdfio_dict_cb_t)(pdfio_dict_t *dict, const char *key, void *cb_data);
|
||||
// Dictionary iterator callback
|
||||
typedef struct _pdfio_file_s pdfio_file_t;
|
||||
// PDF file
|
||||
typedef bool (*pdfio_error_cb_t)(pdfio_file_t *pdf, const char *message, void *data);
|
||||
// Error callback
|
||||
typedef enum pdfio_encryption_e // PDF encryption modes
|
||||
{
|
||||
PDFIO_ENCRYPTION_NONE = 0, // No encryption
|
||||
PDFIO_ENCRYPTION_RC4_40, // 40-bit RC4 encryption (PDF 1.3)
|
||||
PDFIO_ENCRYPTION_RC4_128, // 128-bit RC4 encryption (PDF 1.4)
|
||||
PDFIO_ENCRYPTION_AES_128, // 128-bit AES encryption (PDF 1.6)
|
||||
PDFIO_ENCRYPTION_AES_256 // 256-bit AES encryption (PDF 2.0) @exclude all@
|
||||
} pdfio_encryption_t;
|
||||
typedef enum pdfio_filter_e // Compression/decompression filters for streams
|
||||
{
|
||||
PDFIO_FILTER_NONE, // No filter
|
||||
@ -74,6 +82,24 @@ typedef enum pdfio_filter_e // Compression/decompression filters for streams
|
||||
PDFIO_FILTER_RUNLENGTH, // RunLengthDecode filter (reading only)
|
||||
} pdfio_filter_t;
|
||||
typedef struct _pdfio_obj_s pdfio_obj_t;// Numbered object in PDF file
|
||||
typedef ssize_t (*pdfio_output_cb_t)(void *ctx, const void *data, size_t datalen);
|
||||
// Output callback for pdfioFileCreateOutput
|
||||
typedef const char *(*pdfio_password_cb_t)(void *data, const char *filename);
|
||||
// Password callback for pdfioFileOpen
|
||||
enum pdfio_permission_e // PDF permission bits
|
||||
{
|
||||
PDFIO_PERMISSION_NONE = 0, // No permissions
|
||||
PDFIO_PERMISSION_PRINT = 0x0004, // PDF allows printing
|
||||
PDFIO_PERMISSION_MODIFY = 0x0008, // PDF allows modification
|
||||
PDFIO_PERMISSION_COPY = 0x0010, // PDF allows copying
|
||||
PDFIO_PERMISSION_ANNOTATE = 0x0020, // PDF allows annotation
|
||||
PDFIO_PERMISSION_FORMS = 0x0100, // PDF allows filling in forms
|
||||
PDFIO_PERMISSION_READING = 0x0200, // PDF allows screen reading/accessibility (deprecated in PDF 2.0)
|
||||
PDFIO_PERMISSION_ASSEMBLE = 0x0400, // PDF allows assembly (insert, delete, or rotate pages, add document outlines and thumbnails)
|
||||
PDFIO_PERMISSION_PRINT_HIGH = 0x0800, // PDF allows high quality printing
|
||||
PDFIO_PERMISSION_ALL = ~0 // All permissions
|
||||
};
|
||||
typedef int pdfio_permission_t; // PDF permission bitfield
|
||||
typedef struct pdfio_rect_s // PDF rectangle
|
||||
{
|
||||
double x1; // Lower-left X coordinate
|
||||
@ -125,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;
|
||||
@ -133,12 +161,15 @@ 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;
|
||||
extern const char *pdfioDictGetString(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern pdfio_valtype_t pdfioDictGetType(pdfio_dict_t *dict, const char *key) _PDFIO_PUBLIC;
|
||||
extern void pdfioDictIterateKeys(pdfio_dict_t *dict, pdfio_dict_cb_t cb, void *cb_data) _PDFIO_PUBLIC;
|
||||
extern bool pdfioDictSetArray(pdfio_dict_t *dict, const char *key, pdfio_array_t *value) _PDFIO_PUBLIC;
|
||||
extern bool pdfioDictSetBinary(pdfio_dict_t *dict, const char *key, const unsigned char *value, size_t valuelen) _PDFIO_PUBLIC;
|
||||
extern bool pdfioDictSetBoolean(pdfio_dict_t *dict, const char *key, bool value) _PDFIO_PUBLIC;
|
||||
@ -150,34 +181,44 @@ extern bool pdfioDictSetNumber(pdfio_dict_t *dict, const char *key, double valu
|
||||
extern bool pdfioDictSetObj(pdfio_dict_t *dict, const char *key, pdfio_obj_t *value) _PDFIO_PUBLIC;
|
||||
extern bool pdfioDictSetRect(pdfio_dict_t *dict, const char *key, pdfio_rect_t *value) _PDFIO_PUBLIC;
|
||||
extern bool pdfioDictSetString(pdfio_dict_t *dict, const char *key, const char *value) _PDFIO_PUBLIC;
|
||||
extern bool pdfioDictSetStringf(pdfio_dict_t *dict, const char *key, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(3,4);
|
||||
extern bool pdfioDictSetStringf(pdfio_dict_t *dict, const char *key, const char *format, ...) _PDFIO_PUBLIC;
|
||||
|
||||
extern bool pdfioFileClose(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_file_t *pdfioFileCreate(const char *filename, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateArrayObj(pdfio_file_t *pdf, pdfio_array_t *array) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateNameObj(pdfio_file_t *pdf, const char *name) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateNumberObj(pdfio_file_t *pdf, double number) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
|
||||
extern pdfio_file_t *pdfioFileCreateOutput(pdfio_output_cb_t output_cb, void *output_ctx, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||
// 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;
|
||||
extern const char *pdfioFileGetKeywords(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern time_t pdfioFileGetModificationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetName(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioFileGetNumObjs(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioFileGetNumPages(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileGetObj(pdfio_file_t *pdf, size_t n) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileGetPage(pdfio_file_t *pdf, size_t n) _PDFIO_PUBLIC;
|
||||
extern pdfio_permission_t pdfioFileGetPermissions(pdfio_file_t *pdf, pdfio_encryption_t *encryption) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetProducer(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetSubject(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetTitle(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetVersion(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_file_t *pdfioFileOpen(const char *filename, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||
extern pdfio_file_t *pdfioFileOpen(const char *filename, pdfio_password_cb_t password_cb, void *password_data, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetAuthor(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetCreationDate(pdfio_file_t *pdf, time_t value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetCreator(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetKeywords(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetModificationDate(pdfio_file_t *pdf, time_t value) _PDFIO_PUBLIC;
|
||||
extern bool pdfioFileSetPermissions(pdfio_file_t *pdf, pdfio_permission_t permissions, pdfio_encryption_t encryption, const char *owner_password, const char *user_password) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetSubject(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetTitle(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
|
||||
@ -188,6 +229,7 @@ extern pdfio_array_t *pdfioObjGetArray(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern pdfio_dict_t *pdfioObjGetDict(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern unsigned short pdfioObjGetGeneration(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioObjGetLength(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioObjGetName(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioObjGetNumber(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioObjGetSubtype(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioObjGetType(pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||
@ -201,20 +243,16 @@ extern bool pdfioStreamClose(pdfio_stream_t *st) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamConsume(pdfio_stream_t *st, size_t bytes) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamGetToken(pdfio_stream_t *st, char *buffer, size_t bufsize) _PDFIO_PUBLIC;
|
||||
extern ssize_t pdfioStreamPeek(pdfio_stream_t *st, void *buffer, size_t bytes) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamPrintf(pdfio_stream_t *st, const char *format, ...) _PDFIO_PUBLIC _PDFIO_FORMAT(2,3);
|
||||
extern bool pdfioStreamPrintf(pdfio_stream_t *st, const char *format, ...) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamPutChar(pdfio_stream_t *st, int ch) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamPuts(pdfio_stream_t *st, const char *s) _PDFIO_PUBLIC;
|
||||
extern ssize_t pdfioStreamRead(pdfio_stream_t *st, void *buffer, size_t bytes) _PDFIO_PUBLIC;
|
||||
extern bool pdfioStreamWrite(pdfio_stream_t *st, const void *buffer, size_t bytes) _PDFIO_PUBLIC;
|
||||
|
||||
extern char *pdfioStringCreate(pdfio_file_t *pdf, const char *s) _PDFIO_PUBLIC;
|
||||
extern char *pdfioStringCreatef(pdfio_file_t *pdf, const char *format, ...) _PDFIO_FORMAT(2,3) _PDFIO_PUBLIC;
|
||||
extern char *pdfioStringCreatef(pdfio_file_t *pdf, const char *format, ...) _PDFIO_PUBLIC;
|
||||
|
||||
|
||||
//
|
||||
// C++ magic...
|
||||
//
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif // __cplusplus
|
||||
|
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
|
||||
Cflags: -I${prefix}/include
|
||||
Cflags: @PKGCONFIG_CFLAGS@
|
||||
Libs: @PKGCONFIG_LIBS@
|
||||
Libs.private: @PKGCONFIG_LIBS_PRIVATE@
|
||||
Requires: @PKGCONFIG_REQUIRES@
|
||||
|
@ -87,7 +87,7 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0b1";WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -101,7 +101,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0b1";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -115,7 +115,7 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0b1";_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HAVE_LIBPNG;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -130,7 +130,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0b1";NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HAVE_LIBPNG;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -148,13 +148,18 @@
|
||||
<ClInclude Include="ttf.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pdfio-aes.c" />
|
||||
<ClCompile Include="pdfio-array.c" />
|
||||
<ClCompile Include="pdfio-common.c" />
|
||||
<ClCompile Include="pdfio-content.c" />
|
||||
<ClCompile Include="pdfio-crypto.c" />
|
||||
<ClCompile Include="pdfio-dict.c" />
|
||||
<ClCompile Include="pdfio-file.c" />
|
||||
<ClCompile Include="pdfio-md5.c" />
|
||||
<ClCompile Include="pdfio-object.c" />
|
||||
<ClCompile Include="pdfio-page.c" />
|
||||
<ClCompile Include="pdfio-rc4.c" />
|
||||
<ClCompile Include="pdfio-sha256.c" />
|
||||
<ClCompile Include="pdfio-stream.c" />
|
||||
<ClCompile Include="pdfio-string.c" />
|
||||
<ClCompile Include="pdfio-token.c" />
|
||||
@ -167,6 +172,8 @@
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="packages\libpng_native.redist.1.6.30\build\native\libpng_native.redist.targets" Condition="Exists('packages\libpng_native.redist.1.6.30\build\native\libpng_native.redist.targets')" />
|
||||
<Import Project="packages\libpng_native.1.6.30\build\native\libpng_native.targets" Condition="Exists('packages\libpng_native.1.6.30\build\native\libpng_native.targets')" />
|
||||
<Import Project="packages\zlib_native.redist.1.2.11\build\native\zlib_native.redist.targets" Condition="Exists('packages\zlib_native.redist.1.2.11\build\native\zlib_native.redist.targets')" />
|
||||
<Import Project="packages\zlib_native.1.2.11\build\native\zlib_native.targets" Condition="Exists('packages\zlib_native.1.2.11\build\native\zlib_native.targets')" />
|
||||
</ImportGroup>
|
||||
|
@ -65,6 +65,21 @@
|
||||
<ClCompile Include="ttf.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pdfio-aes.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pdfio-crypto.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pdfio-md5.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pdfio-rc4.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pdfio-sha256.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@ -25,7 +25,13 @@
|
||||
279E1035267D043B00D3A349 /* ttf.h in Headers */ = {isa = PBXBuildFile; fileRef = 279E1033267D043B00D3A349 /* ttf.h */; };
|
||||
279E1036267D043B00D3A349 /* ttf.c in Sources */ = {isa = PBXBuildFile; fileRef = 279E1034267D043B00D3A349 /* ttf.c */; };
|
||||
279E103B267D04E600D3A349 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 279E103A267D04E600D3A349 /* libz.tbd */; };
|
||||
27CF90442711DFFE00E50FE4 /* pdfio-aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 27CF90432711DFFE00E50FE4 /* pdfio-aes.c */; };
|
||||
27ECBD8926419DAB0025312A /* libpdfio.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 273440B0263D6FE200FBFD63 /* libpdfio.a */; };
|
||||
27F2F0602710BE92008ECD36 /* pdfio-md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 27F2F05D2710BE92008ECD36 /* pdfio-md5.c */; };
|
||||
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 */
|
||||
@ -79,6 +85,12 @@
|
||||
279E1033267D043B00D3A349 /* ttf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ttf.h; sourceTree = "<group>"; };
|
||||
279E1034267D043B00D3A349 /* ttf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ttf.c; sourceTree = "<group>"; };
|
||||
279E103A267D04E600D3A349 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
27CF90432711DFFE00E50FE4 /* pdfio-aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-aes.c"; sourceTree = "<group>"; };
|
||||
27F2F05D2710BE92008ECD36 /* pdfio-md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-md5.c"; sourceTree = "<group>"; };
|
||||
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 */
|
||||
@ -150,19 +162,25 @@
|
||||
279E1038267D045C00D3A349 /* Library */ = {
|
||||
isa = PBXGroup;
|
||||
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 */,
|
||||
273440BE263D727800FBFD63 /* pdfio-dict.c */,
|
||||
273440BD263D727800FBFD63 /* pdfio-file.c */,
|
||||
27F2F05D2710BE92008ECD36 /* pdfio-md5.c */,
|
||||
273440BC263D727800FBFD63 /* pdfio-object.c */,
|
||||
273440C2263D727800FBFD63 /* pdfio-page.c */,
|
||||
27F2F05E2710BE92008ECD36 /* pdfio-rc4.c */,
|
||||
27F2F0632711243D008ECD36 /* pdfio-sha256.c */,
|
||||
273440BF263D727800FBFD63 /* pdfio-stream.c */,
|
||||
273440B9263D727800FBFD63 /* pdfio-string.c */,
|
||||
273440E3263DD7EA00FBFD63 /* pdfio-token.c */,
|
||||
273440C0263D727800FBFD63 /* pdfio-value.c */,
|
||||
279E1033267D043B00D3A349 /* ttf.h */,
|
||||
279E1034267D043B00D3A349 /* ttf.c */,
|
||||
279E1033267D043B00D3A349 /* ttf.h */,
|
||||
);
|
||||
name = Library;
|
||||
sourceTree = "<group>";
|
||||
@ -190,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 */,
|
||||
@ -241,7 +260,8 @@
|
||||
273440A8263D6FE200FBFD63 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1250;
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1600;
|
||||
TargetAttributes = {
|
||||
273440AF263D6FE200FBFD63 = {
|
||||
CreatedOnToolsVersion = 12.5;
|
||||
@ -281,11 +301,16 @@
|
||||
273440CB263D727800FBFD63 /* pdfio-value.c in Sources */,
|
||||
273440CA263D727800FBFD63 /* pdfio-stream.c in Sources */,
|
||||
273440CD263D727800FBFD63 /* pdfio-page.c in Sources */,
|
||||
27F2F0622710BE92008ECD36 /* pdfio-crypto.c in Sources */,
|
||||
27F2F0642711243D008ECD36 /* pdfio-sha256.c in Sources */,
|
||||
273440C5263D727800FBFD63 /* pdfio-array.c in Sources */,
|
||||
273440E4263DD7EA00FBFD63 /* pdfio-token.c in Sources */,
|
||||
273440C7263D727800FBFD63 /* pdfio-object.c in Sources */,
|
||||
27F2F0602710BE92008ECD36 /* pdfio-md5.c in Sources */,
|
||||
273440C4263D727800FBFD63 /* pdfio-string.c in Sources */,
|
||||
27CF90442711DFFE00E50FE4 /* pdfio-aes.c in Sources */,
|
||||
271EA705265B2B1000ACDD39 /* pdfio-content.c in Sources */,
|
||||
27F2F0612710BE92008ECD36 /* pdfio-rc4.c in Sources */,
|
||||
273440C6263D727800FBFD63 /* pdfio-common.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -350,18 +375,19 @@
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.0;
|
||||
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 = (
|
||||
"$(inherited)",
|
||||
"DEBUG=1",
|
||||
"'PDFIO_VERSION=\"$(CURRENT_PROJECT_VERSION)\"'",
|
||||
);
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
@ -377,7 +403,7 @@
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
@ -428,19 +454,18 @@
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.0;
|
||||
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)",
|
||||
"'PDFIO_VERSION=\"$(CURRENT_PROJECT_VERSION)\"'",
|
||||
);
|
||||
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;
|
||||
@ -455,7 +480,7 @@
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
@ -468,6 +493,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RU58A2256H;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -479,6 +505,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RU58A2256H;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -491,11 +518,12 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -507,9 +535,10 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
37
pdfio1.def
37
pdfio1.def
@ -1,6 +1,17 @@
|
||||
LIBRARY pdfio1
|
||||
VERSION 1.0
|
||||
VERSION 1.5
|
||||
EXPORTS
|
||||
_pdfioCryptoAESDecrypt
|
||||
_pdfioCryptoAESEncrypt
|
||||
_pdfioCryptoAESInit
|
||||
_pdfioCryptoMD5Append
|
||||
_pdfioCryptoMD5Finish
|
||||
_pdfioCryptoMD5Init
|
||||
_pdfioCryptoRC4Crypt
|
||||
_pdfioCryptoRC4Init
|
||||
_pdfioCryptoSHA256Append
|
||||
_pdfioCryptoSHA256Finish
|
||||
_pdfioCryptoSHA256Init
|
||||
_pdfioTokenInit
|
||||
_pdfioValueDebug
|
||||
_pdfioValueRead
|
||||
@ -31,6 +42,7 @@ pdfioArrayGetObj
|
||||
pdfioArrayGetSize
|
||||
pdfioArrayGetString
|
||||
pdfioArrayGetType
|
||||
pdfioArrayRemove
|
||||
pdfioContentClip
|
||||
pdfioContentDrawImage
|
||||
pdfioContentFill
|
||||
@ -43,6 +55,7 @@ pdfioContentPathClose
|
||||
pdfioContentPathCurve
|
||||
pdfioContentPathCurve13
|
||||
pdfioContentPathCurve23
|
||||
pdfioContentPathEnd
|
||||
pdfioContentPathLineTo
|
||||
pdfioContentPathMoveTo
|
||||
pdfioContentPathRect
|
||||
@ -77,12 +90,17 @@ pdfioContentSetTextXScaling
|
||||
pdfioContentStroke
|
||||
pdfioContentTextBegin
|
||||
pdfioContentTextEnd
|
||||
pdfioContentTextMeasure
|
||||
pdfioContentTextMoveLine
|
||||
pdfioContentTextMoveTo
|
||||
pdfioContentTextNewLine
|
||||
pdfioContentTextNewLineShow
|
||||
pdfioContentTextNewLineShowf
|
||||
pdfioContentTextNextLine
|
||||
pdfioContentTextShow
|
||||
pdfioContentTextShowJustified
|
||||
pdfioContentTextShowf
|
||||
pdfioDictClear
|
||||
pdfioDictCopy
|
||||
pdfioDictCreate
|
||||
pdfioDictGetArray
|
||||
@ -90,12 +108,15 @@ pdfioDictGetBinary
|
||||
pdfioDictGetBoolean
|
||||
pdfioDictGetDate
|
||||
pdfioDictGetDict
|
||||
pdfioDictGetKey
|
||||
pdfioDictGetName
|
||||
pdfioDictGetNumPairs
|
||||
pdfioDictGetNumber
|
||||
pdfioDictGetObj
|
||||
pdfioDictGetRect
|
||||
pdfioDictGetString
|
||||
pdfioDictGetType
|
||||
pdfioDictIterateKeys
|
||||
pdfioDictSetArray
|
||||
pdfioDictSetBinary
|
||||
pdfioDictSetBoolean
|
||||
@ -113,22 +134,31 @@ pdfioFileCreate
|
||||
pdfioFileCreateArrayObj
|
||||
pdfioFileCreateFontObjFromBase
|
||||
pdfioFileCreateFontObjFromFile
|
||||
pdfioFileCreateICCObjFromData
|
||||
pdfioFileCreateICCObjFromFile
|
||||
pdfioFileCreateImageObjFromData
|
||||
pdfioFileCreateImageObjFromFile
|
||||
pdfioFileCreateNameObj
|
||||
pdfioFileCreateNumberObj
|
||||
pdfioFileCreateObj
|
||||
pdfioFileCreateOutput
|
||||
pdfioFileCreatePage
|
||||
pdfioFileCreateStringObj
|
||||
pdfioFileCreateTemporary
|
||||
pdfioFileFindObj
|
||||
pdfioFileGetAuthor
|
||||
pdfioFileGetCatalog
|
||||
pdfioFileGetCreationDate
|
||||
pdfioFileGetCreator
|
||||
pdfioFileGetID
|
||||
pdfioFileGetKeywords
|
||||
pdfioFileGetModificationDate
|
||||
pdfioFileGetName
|
||||
pdfioFileGetNumObjs
|
||||
pdfioFileGetNumPages
|
||||
pdfioFileGetObj
|
||||
pdfioFileGetPage
|
||||
pdfioFileGetPermissions
|
||||
pdfioFileGetProducer
|
||||
pdfioFileGetSubject
|
||||
pdfioFileGetTitle
|
||||
@ -138,6 +168,8 @@ pdfioFileSetAuthor
|
||||
pdfioFileSetCreationDate
|
||||
pdfioFileSetCreator
|
||||
pdfioFileSetKeywords
|
||||
pdfioFileSetModificationDate
|
||||
pdfioFileSetPermissions
|
||||
pdfioFileSetSubject
|
||||
pdfioFileSetTitle
|
||||
pdfioImageGetBytesPerLine
|
||||
@ -150,6 +182,7 @@ pdfioObjGetArray
|
||||
pdfioObjGetDict
|
||||
pdfioObjGetGeneration
|
||||
pdfioObjGetLength
|
||||
pdfioObjGetName
|
||||
pdfioObjGetNumber
|
||||
pdfioObjGetSubtype
|
||||
pdfioObjGetType
|
||||
@ -158,6 +191,8 @@ pdfioPageCopy
|
||||
pdfioPageDictAddColorSpace
|
||||
pdfioPageDictAddFont
|
||||
pdfioPageDictAddImage
|
||||
pdfioPageGetNumStreams
|
||||
pdfioPageOpenStream
|
||||
pdfioStreamClose
|
||||
pdfioStreamConsume
|
||||
pdfioStreamGetToken
|
||||
|
@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.0.0-b2</version>
|
||||
<version>1.5.1</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
@ -12,9 +12,14 @@
|
||||
<readme>build/native/README.md</readme>
|
||||
<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 exception to allow linking against GNU GPL2-only software.</summary>
|
||||
<copyright>Copyright © 2019-2021 by Michael R Sweet</copyright>
|
||||
<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-2025 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
<dependencies>
|
||||
<dependency id="pdfio_native.redist" version="1.5.1" />
|
||||
<dependency id="libpng_native.redist" version="1.6.30" />
|
||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="doc\pdfio-128.png" target="build\native" />
|
||||
@ -22,7 +27,7 @@
|
||||
<file src="pdfio_native.props" target="build\native" />
|
||||
<file src="pdfio.h" target="build\native\include" />
|
||||
<file src="pdfio-content.h" target="build\native\include" />
|
||||
<!--<file src="Win32\**\pdfio*.lib" target="build\native\lib\Win32" />-->
|
||||
<file src="x64\**\pdfio.lib" target="build\native\lib\x64" />
|
||||
<!--<file src="Win32\**\pdfio1.lib" target="build\native\lib\Win32" />-->
|
||||
<file src="x64\**\pdfio1.lib" target="build\native\lib\x64" />
|
||||
</files>
|
||||
</package>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)\include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)\lib\$(Platform)\$(Configuration)\pdfio.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)\lib\$(Platform)\$(Configuration)\pdfio1.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
</Project>
|
||||
|
29
pdfio_native.redist.nuspec
Normal file
29
pdfio_native.redist.nuspec
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>pdfio_native.redist</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.5.1</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
<license type="expression">Apache-2.0</license>
|
||||
<icon>build/native/pdfio-128.png</icon>
|
||||
<readme>build/native/README.md</readme>
|
||||
<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-2025 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
<dependencies>
|
||||
<dependency id="libpng_native.redist" version="1.6.30" />
|
||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="doc\pdfio-128.png" target="build\native" />
|
||||
<file src="README.md" target="build\native" />
|
||||
<!--<file src="Win32\**\pdfio1.dll" target="build\native\bin\Win32" />-->
|
||||
<file src="x64\**\pdfio1.dll" target="build\native\bin\x64" />
|
||||
</files>
|
||||
</package>
|
18
runtests.bat
Normal file
18
runtests.bat
Normal file
@ -0,0 +1,18 @@
|
||||
:: Script to run unit test program
|
||||
::
|
||||
:: Usage:
|
||||
::
|
||||
:: .\runtests.bat x64\{Debug|Release}
|
||||
::
|
||||
|
||||
:: Copy dependent DLLs to the named build directory
|
||||
echo Copying DLLs
|
||||
copy packages\libpng_native.redist.1.6.30\build\native\bin\x64\Debug\*.dll %1
|
||||
copy packages\libpng_native.redist.1.6.30\build\native\bin\x64\Release\*.dll %1
|
||||
copy packages\zlib_native.redist.1.2.11\build\native\bin\x64\Debug\*.dll %1
|
||||
copy packages\zlib_native.redist.1.2.11\build\native\bin\x64\Release\*.dll %1
|
||||
|
||||
:: Run unit test program
|
||||
echo Running %1\testpdfio.exe
|
||||
cd %1
|
||||
testpdfio.exe
|
@ -1,3 +1,7 @@
|
||||
https://www.color.org/chardata/rgb/rommrgb.xalter
|
||||
|
||||
Copyright © 2006 Hewlett-Packard
|
||||
|
||||
Terms of use
|
||||
|
||||
This profile is made available by ICC, and may be copied, distributed, embedded, made, used, and sold without restriction. Altered versions of this profile shall have the original identification and copyright information removed and shall not be misrepresented as the original profile.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user