mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-07-13 14:34:28 +02:00
Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
7045d9dad9 | |||
4f10021e7e | |||
57d5894f33 | |||
2b8a1c8481 | |||
948ee16b06 | |||
c7101ae9dd | |||
599640eda1 | |||
a3f3bbfe11 | |||
26d485cfc5 | |||
64d306a322 | |||
067683cbcd | |||
50f27974cf | |||
ae9a91719b | |||
1a17933635 | |||
acea6fdbed | |||
66fa12f928 | |||
f4b8983c61 | |||
ed4e2fc38a | |||
1ed7f0089c | |||
563d53edd4 | |||
316b0ad559 | |||
f8b471acfd | |||
cedd7d104f |
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
|
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
|
||||
uses: actions/checkout@v3
|
||||
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
|
||||
|
||||
- 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 }}"
|
19
CHANGES.md
19
CHANGES.md
@ -2,8 +2,23 @@ Changes in PDFio
|
||||
================
|
||||
|
||||
|
||||
v1.0.1 (Month DD, YYYY)
|
||||
-----------------------
|
||||
v1.1.0 (February 3, 2023)
|
||||
-------------------------
|
||||
|
||||
- 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 (March 2, 2022)
|
||||
----------------------
|
||||
|
||||
- Added missing `pdfioPageGetNumStreams` and `pdfioPageOpenStream` functions.
|
||||
- Added demo pdfiototext utility.
|
||||
|
23
Makefile
23
Makefile
@ -1,7 +1,7 @@
|
||||
#
|
||||
# Makefile for PDFio.
|
||||
#
|
||||
# Copyright © 2021-2022 by Michael R Sweet.
|
||||
# Copyright © 2021-2023 by Michael R Sweet.
|
||||
#
|
||||
# Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
# information.
|
||||
@ -10,7 +10,10 @@
|
||||
# POSIX makefile
|
||||
.POSIX:
|
||||
|
||||
# Variables...
|
||||
# Build silently
|
||||
.SILENT:
|
||||
|
||||
# Variables
|
||||
AR = ar
|
||||
ARFLAGS = cr
|
||||
CC = cc
|
||||
@ -26,13 +29,14 @@ DSONAME =
|
||||
LDFLAGS =
|
||||
LIBS = -lm -lz
|
||||
RANLIB = ranlib
|
||||
VERSION = 1.0.1
|
||||
VERSION = 1.1.0
|
||||
prefix = /usr/local
|
||||
|
||||
|
||||
# Base rules
|
||||
.SUFFIXES: .c .h .o
|
||||
.c.o:
|
||||
echo Compiling $<...
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(COMMONFLAGS) -c $<
|
||||
|
||||
|
||||
@ -95,8 +99,10 @@ clean:
|
||||
|
||||
# Install everything
|
||||
install: $(TARGETS)
|
||||
echo Installing header files to $(DESTDIR)$(prefix)/include...
|
||||
-mkdir -p $(DESTDIR)$(prefix)/include
|
||||
cp $(PUBHEADERS) $(DESTDIR)$(prefix)/include
|
||||
echo Installing library files to $(DESTDIR)$(prefix)/lib...
|
||||
-mkdir -p $(DESTDIR)$(prefix)/lib
|
||||
cp libpdfio.a $(DESTDIR)$(prefix)/lib
|
||||
$(RANLIB) $(DESTDIR)$(prefix)/lib/libpdfio.a
|
||||
@ -108,19 +114,22 @@ install: $(TARGETS)
|
||||
codesign -s "$(CODESIGN_IDENTITY)" -o runtime --timestamp $(DESTDIR)$(prefix)/lib/libpdfio.1.dylib; \
|
||||
ln -sf libpdfio.1.dylib $(DESTDIR)$(prefix)/lib/libpdfio.dylib; \
|
||||
fi
|
||||
echo Installing pkg-config files to $(DESTDIR)$(prefix)/lib/pkgconfig...
|
||||
-mkdir -p $(DESTDIR)$(prefix)/lib/pkgconfig
|
||||
echo 'prefix="$(prefix)"' >$(DESTDIR)$(prefix)/lib/pkgconfig/pdfio.pc
|
||||
echo 'Version: $(VERSION)' >>$(DESTDIR)$(prefix)/lib/pkgconfig/pdfio.pc
|
||||
cat pdfio.pc.in >>$(DESTDIR)$(prefix)/lib/pkgconfig/pdfio.pc
|
||||
echo Installing documentation to $(DESTDIR)$(prefix)/share/doc/pdfio...
|
||||
-mkdir -p $(DESTDIR)$(prefix)/share/doc/pdfio
|
||||
cp doc/pdfio.html doc/pdfio-512.png LICENSE NOTICE $(DESTDIR)$(prefix)/share/doc/pdfio
|
||||
echo Installing man page to $(DESTDIR)$(prefix)/share/man/man3...
|
||||
-mkdir -p $(DESTDIR)$(prefix)/share/man/man3
|
||||
cp doc/pdfio.3 $(DESTDIR)$(prefix)/share/man/man3
|
||||
|
||||
install-shared:
|
||||
if test `uname` = Darwin; then \
|
||||
$(MAKE) DSONAME="libpdfio.1.dylib" -$(MAKEFLAGS) install; \
|
||||
else
|
||||
else \
|
||||
$(MAKE) DSONAME="libpdfio.so.1" -$(MAKEFLAGS) install; \
|
||||
fi
|
||||
|
||||
@ -135,13 +144,16 @@ valgrind: testpdfio
|
||||
|
||||
# pdfio library
|
||||
libpdfio.a: $(LIBOBJS)
|
||||
echo Archiving $@...
|
||||
$(AR) $(ARFLAGS) $@ $(LIBOBJS)
|
||||
$(RANLIB) $@
|
||||
|
||||
libpdfio.so.1: $(LIBOBJS)
|
||||
echo Linking $@...
|
||||
$(CC) $(DSOFLAGS) $(COMMONFLAGS) -shared -o $@ -Wl,-soname,$@ $(LIBOBJS) $(LIBS)
|
||||
|
||||
libpdfio.1.dylib: $(LIBOBJS)
|
||||
echo Linking $@...
|
||||
$(CC) $(DSOFLAGS) $(COMMONFLAGS) -dynamiclib -o $@ -install_name $(prefix)/lib/$@ -current_version $(VERSION) -compatibility_version 1.0 $(LIBOBJS) $(LIBS)
|
||||
|
||||
|
||||
@ -161,11 +173,13 @@ pdfio1.def: $(LIBOBJS) Makefile
|
||||
|
||||
# pdfio text extraction (demo, doesn't handle a lot of things yet)
|
||||
pdfiototext: pdfiototext.o libpdfio.a
|
||||
echo Linking $@...
|
||||
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ pdfiototext.o libpdfio.a $(LIBS)
|
||||
|
||||
|
||||
# pdfio test program
|
||||
testpdfio: testpdfio.o libpdfio.a
|
||||
echo Linking $@...
|
||||
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
|
||||
|
||||
|
||||
@ -182,6 +196,7 @@ DOCFLAGS = \
|
||||
|
||||
.PHONY: doc
|
||||
doc:
|
||||
echo Generating documentation...
|
||||
codedoc $(DOCFLAGS) --title "PDFio Programming Manual v$(VERSION)" $(PUBHEADERS) $(PUBOBJS:.o=.c) --body doc/pdfio.md --coverimage doc/pdfio-512.png pdfio.xml >doc/pdfio.html
|
||||
codedoc $(DOCFLAGS) --title "PDFio Programming Manual v$(VERSION)" --body doc/pdfio.md --coverimage doc/pdfio-epub.png pdfio.xml --epub doc/pdfio.epub
|
||||
codedoc $(DOCFLAGS) --title "pdf read/write library" --man pdfio --section 3 --body doc/pdfio.md pdfio.xml >doc/pdfio.3
|
||||
|
2
NOTICE
2
NOTICE
@ -1,6 +1,6 @@
|
||||
PDFio - PDF Read/Write Library
|
||||
|
||||
Copyright © 2021 by Michael R Sweet.
|
||||
Copyright © 2021-2023 by Michael R Sweet.
|
||||
|
||||
(Optional) Exceptions to the Apache 2.0 License:
|
||||
================================================
|
||||
|
@ -3,7 +3,7 @@ pdfio - PDF Read/Write Library
|
||||
|
||||

|
||||

|
||||
[](https://github.com/michaelrsweet/pdfio/actions/workflows/build.yml)
|
||||
[](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/)
|
||||
@ -115,13 +115,13 @@ generates a static library that will be installed under "/usr/local" with:
|
||||
|
||||
You can reproduce this with the makefile using:
|
||||
|
||||
sudo make COMMONFLAGS="-Os -mmacosx-version-min=10.14 -arch x86_64 -arch arm64" install
|
||||
sudo make macos install
|
||||
|
||||
|
||||
Legal Stuff
|
||||
-----------
|
||||
|
||||
PDFio is Copyright © 2021 by Michael R Sweet.
|
||||
PDFio is Copyright © 2021-2022 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
|
||||
|
55
doc/pdfio.3
55
doc/pdfio.3
@ -1,4 +1,4 @@
|
||||
.TH pdfio 3 "pdf read/write library" "2022-03-02" "pdf read/write library"
|
||||
.TH pdfio 3 "pdf read/write library" "2022-07-03" "pdf read/write library"
|
||||
.SH NAME
|
||||
pdfio \- pdf read/write library
|
||||
.SH Introduction
|
||||
@ -1440,6 +1440,14 @@ bool pdfioContentPathCurve23 (
|
||||
double y3
|
||||
);
|
||||
.fi
|
||||
.SS pdfioContentPathEnd
|
||||
Clear the current path.
|
||||
.PP
|
||||
.nf
|
||||
bool pdfioContentPathEnd (
|
||||
pdfio_stream_t *st
|
||||
);
|
||||
.fi
|
||||
.SS pdfioContentPathLineTo
|
||||
Add a straight line to the current path.
|
||||
.PP
|
||||
@ -1950,6 +1958,31 @@ pdfio_valtype_t pdfioDictGetType (
|
||||
const char *key
|
||||
);
|
||||
.fi
|
||||
.SS pdfioDictIterateKeys
|
||||
Iterate the keys in a dictionary.
|
||||
.PP
|
||||
.nf
|
||||
void pdfioDictIterateKeys (
|
||||
pdfio_dict_t *dict,
|
||||
pdfio_dict_cb_t cb,
|
||||
void *cb_data
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
This function iterates the keys in a dictionary, calling the supplied
|
||||
function "cb":
|
||||
.PP
|
||||
.nf
|
||||
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 ...
|
||||
}
|
||||
|
||||
.fi
|
||||
The iteration continues as long as the callback returns \fBtrue\fR or all keys
|
||||
have been iterated.
|
||||
.SS pdfioDictSetArray
|
||||
Set a key array in a dictionary.
|
||||
.PP
|
||||
@ -2302,6 +2335,20 @@ pdfio_stream_t * pdfioFileCreatePage (
|
||||
pdfio_dict_t *dict
|
||||
);
|
||||
.fi
|
||||
.SS pdfioFileCreateTemporary
|
||||
|
||||
.PP
|
||||
.nf
|
||||
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
|
||||
);
|
||||
.fi
|
||||
.SS pdfioFileFindObj
|
||||
Find an object using its object number.
|
||||
.PP
|
||||
@ -2875,6 +2922,12 @@ Standard color spaces
|
||||
.nf
|
||||
typedef enum pdfio_cs_e pdfio_cs_t;
|
||||
.fi
|
||||
.SS pdfio_dict_cb_t
|
||||
Dictionary iterator callback
|
||||
.PP
|
||||
.nf
|
||||
typedef bool(*)(pdfio_dict_t *dict, const char *key, void *cb_data) pdfio_dict_cb_t;
|
||||
.fi
|
||||
.SS pdfio_dict_t
|
||||
Key/value dictionary
|
||||
.PP
|
||||
|
@ -1,13 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<title>PDFio Programming Manual v1.0.1</title>
|
||||
<title>PDFio Programming Manual v1.1</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
<meta name="generator" content="codedoc v3.7">
|
||||
<meta name="author" content="Michael R Sweet">
|
||||
<meta name="language" content="en-US">
|
||||
<meta name="copyright" content="Copyright © 2021-2022 by Michael R Sweet">
|
||||
<meta name="version" content="1.0.1">
|
||||
<meta name="version" content="1.1">
|
||||
<style type="text/css"><!--
|
||||
body {
|
||||
background: white;
|
||||
@ -245,7 +245,7 @@ span.string {
|
||||
<body>
|
||||
<div class="header">
|
||||
<p><img class="title" src="pdfio-512.png"></p>
|
||||
<h1 class="title">PDFio Programming Manual v1.0.1</h1>
|
||||
<h1 class="title">PDFio Programming Manual v1.1</h1>
|
||||
<p>Michael R Sweet</p>
|
||||
<p>Copyright © 2021-2022 by Michael R Sweet</p>
|
||||
</div>
|
||||
@ -307,6 +307,7 @@ span.string {
|
||||
<li><a href="#pdfioContentPathCurve">pdfioContentPathCurve</a></li>
|
||||
<li><a href="#pdfioContentPathCurve13">pdfioContentPathCurve13</a></li>
|
||||
<li><a href="#pdfioContentPathCurve23">pdfioContentPathCurve23</a></li>
|
||||
<li><a href="#pdfioContentPathEnd">pdfioContentPathEnd</a></li>
|
||||
<li><a href="#pdfioContentPathLineTo">pdfioContentPathLineTo</a></li>
|
||||
<li><a href="#pdfioContentPathMoveTo">pdfioContentPathMoveTo</a></li>
|
||||
<li><a href="#pdfioContentPathRect">pdfioContentPathRect</a></li>
|
||||
@ -360,6 +361,7 @@ span.string {
|
||||
<li><a href="#pdfioDictGetRect">pdfioDictGetRect</a></li>
|
||||
<li><a href="#pdfioDictGetString">pdfioDictGetString</a></li>
|
||||
<li><a href="#pdfioDictGetType">pdfioDictGetType</a></li>
|
||||
<li><a href="#pdfioDictIterateKeys">pdfioDictIterateKeys</a></li>
|
||||
<li><a href="#pdfioDictSetArray">pdfioDictSetArray</a></li>
|
||||
<li><a href="#pdfioDictSetBinary">pdfioDictSetBinary</a></li>
|
||||
<li><a href="#pdfioDictSetBoolean">pdfioDictSetBoolean</a></li>
|
||||
@ -383,6 +385,7 @@ span.string {
|
||||
<li><a href="#pdfioFileCreateObj">pdfioFileCreateObj</a></li>
|
||||
<li><a href="#pdfioFileCreateOutput">pdfioFileCreateOutput</a></li>
|
||||
<li><a href="#pdfioFileCreatePage">pdfioFileCreatePage</a></li>
|
||||
<li><a href="#pdfioFileCreateTemporary">pdfioFileCreateTemporary</a></li>
|
||||
<li><a href="#pdfioFileFindObj">pdfioFileFindObj</a></li>
|
||||
<li><a href="#pdfioFileGetAuthor">pdfioFileGetAuthor</a></li>
|
||||
<li><a href="#pdfioFileGetCreationDate">pdfioFileGetCreationDate</a></li>
|
||||
@ -442,6 +445,7 @@ span.string {
|
||||
<li><a href="#TYPES">Data Types</a><ul class="subcontents">
|
||||
<li><a href="#pdfio_array_t">pdfio_array_t</a></li>
|
||||
<li><a href="#pdfio_cs_t">pdfio_cs_t</a></li>
|
||||
<li><a href="#pdfio_dict_cb_t">pdfio_dict_cb_t</a></li>
|
||||
<li><a href="#pdfio_dict_t">pdfio_dict_t</a></li>
|
||||
<li><a href="#pdfio_encryption_t">pdfio_encryption_t</a></li>
|
||||
<li><a href="#pdfio_error_cb_t">pdfio_error_cb_t</a></li>
|
||||
@ -1511,6 +1515,17 @@ bool pdfioContentPathCurve23(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, d
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
||||
<h3 class="function"><a id="pdfioContentPathEnd">pdfioContentPathEnd</a></h3>
|
||||
<p class="description">Clear the current path.</p>
|
||||
<p class="code">
|
||||
bool pdfioContentPathEnd(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>st</th>
|
||||
<td class="description">Stream</td></tr>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
||||
<h3 class="function"><a id="pdfioContentPathLineTo">pdfioContentPathLineTo</a></h3>
|
||||
<p class="description">Add a straight line to the current path.</p>
|
||||
<p class="code">
|
||||
@ -2261,6 +2276,33 @@ const char *pdfioDictGetString(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, c
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Value type</p>
|
||||
<h3 class="function"><a id="pdfioDictIterateKeys">pdfioDictIterateKeys</a></h3>
|
||||
<p class="description">Iterate the keys in a dictionary.</p>
|
||||
<p class="code">
|
||||
void pdfioDictIterateKeys(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, <a href="#pdfio_dict_cb_t">pdfio_dict_cb_t</a> cb, void *cb_data);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>dict</th>
|
||||
<td class="description">Dictionary</td></tr>
|
||||
<tr><th>cb</th>
|
||||
<td class="description">Callback function</td></tr>
|
||||
<tr><th>cb_data</th>
|
||||
<td class="description">Callback data</td></tr>
|
||||
</tbody></table>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function iterates the keys in a dictionary, calling the supplied
|
||||
function "cb":
|
||||
|
||||
<pre>
|
||||
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 ...
|
||||
}
|
||||
</pre>
|
||||
The iteration continues as long as the callback returns <code>true</code> or all keys
|
||||
have been iterated.</p>
|
||||
<h3 class="function"><a id="pdfioDictSetArray">pdfioDictSetArray</a></h3>
|
||||
<p class="description">Set a key array in a dictionary.</p>
|
||||
<p class="code">
|
||||
@ -2730,6 +2772,35 @@ stored as indirect object references.</blockquote>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Contents stream</p>
|
||||
<h3 class="function"><a id="pdfioFileCreateTemporary">pdfioFileCreateTemporary</a></h3>
|
||||
<p class="description"></p>
|
||||
<p class="code">
|
||||
<a href="#pdfio_file_t">pdfio_file_t</a> *pdfioFileCreateTemporary(char *buffer, size_t bufsize, const char *version, <a href="#pdfio_rect_t">pdfio_rect_t</a> *media_box, <a href="#pdfio_rect_t">pdfio_rect_t</a> *crop_box, <a href="#pdfio_error_cb_t">pdfio_error_cb_t</a> error_cb, void *error_data);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>buffer</th>
|
||||
<td class="description">Filename buffer</td></tr>
|
||||
<tr><th>bufsize</th>
|
||||
<td class="description">Size of filename buffer</td></tr>
|
||||
<tr><th>version</th>
|
||||
<td class="description">PDF version number or <code>NULL</code> for default (2.0)</td></tr>
|
||||
<tr><th>media_box</th>
|
||||
<td class="description">Default MediaBox for pages</td></tr>
|
||||
<tr><th>crop_box</th>
|
||||
<td class="description">Default CropBox for pages</td></tr>
|
||||
<tr><th>error_cb</th>
|
||||
<td class="description">Error callback or <code>NULL</code> for default</td></tr>
|
||||
<tr><th>error_data</th>
|
||||
<td class="description">Error callback data, if any</td></tr>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Create a temporary PDF file.</p>
|
||||
<p class="discussion">This function creates a PDF file with a unique filename in the current
|
||||
temporary directory. The temporary file is stored in the string "buffer" an
|
||||
will have a ".pdf" extension. Otherwise, this function works the same as
|
||||
the <a href="#pdfioFileCreate"><code>pdfioFileCreate</code></a> function.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><a id="pdfioFileFindObj">pdfioFileFindObj</a></h3>
|
||||
<p class="description">Find an object using its object number.</p>
|
||||
<p class="code">
|
||||
@ -3484,6 +3555,11 @@ typedef struct _pdfio_array_s pdfio_array_t;
|
||||
<p class="code">
|
||||
typedef enum <a href="#pdfio_cs_e">pdfio_cs_e</a> pdfio_cs_t;
|
||||
</p>
|
||||
<h3 class="typedef"><a id="pdfio_dict_cb_t">pdfio_dict_cb_t</a></h3>
|
||||
<p class="description">Dictionary iterator callback</p>
|
||||
<p class="code">
|
||||
typedef bool (*pdfio_dict_cb_t)(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, const char *key, void *cb_data);
|
||||
</p>
|
||||
<h3 class="typedef"><a id="pdfio_dict_t">pdfio_dict_t</a></h3>
|
||||
<p class="description">Key/value dictionary</p>
|
||||
<p class="code">
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Common support functions for pdfio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -38,6 +38,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);
|
||||
}
|
||||
|
||||
|
@ -489,8 +489,11 @@ pdfioContentMatrixRotate(
|
||||
pdfio_stream_t *st, // I - Stream
|
||||
double degrees) // I - Rotation angle in degrees counter-clockwise
|
||||
{
|
||||
double dcos = cos(degrees / M_PI); // Cosine
|
||||
double dsin = sin(degrees / M_PI); // Sine
|
||||
double dcos = cos(M_PI * degrees / 180.0);
|
||||
// Cosine
|
||||
double dsin = sin(M_PI * degrees / 180.0);
|
||||
// Sine
|
||||
|
||||
|
||||
return (pdfioStreamPrintf(st, "%g %g %g %g 0 0 cm\n", dcos, -dsin, dsin, dcos));
|
||||
}
|
||||
@ -586,6 +589,17 @@ pdfioContentPathCurve23(
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioContentPathEnd()' - Clear the current path.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
pdfioContentPathEnd(pdfio_stream_t *st) // I - Stream
|
||||
{
|
||||
return (pdfioStreamPuts(st, "n\n"));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioContentPathLineTo()' - Add a straight line to the current path.
|
||||
//
|
||||
|
@ -91,6 +91,7 @@ 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;
|
||||
|
56
pdfio-dict.c
56
pdfio-dict.c
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF dictionary functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -464,6 +464,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.
|
||||
//
|
||||
@ -500,8 +541,15 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
||||
_pdfioFileError(pdf, "Invalid dictionary contents.");
|
||||
break;
|
||||
}
|
||||
else if (_pdfioDictGetValue(dict, key + 1))
|
||||
{
|
||||
_pdfioFileError(pdf, "Duplicate dictionary key '%s'.", key + 1);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
// Then get the next value...
|
||||
PDFIO_DEBUG("_pdfioDictRead: Reading value for '%s'.\n", key + 1);
|
||||
|
||||
if (!_pdfioValueRead(pdf, obj, tb, &value, depth))
|
||||
{
|
||||
_pdfioFileError(pdf, "Missing value for dictionary key.");
|
||||
@ -891,9 +939,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);
|
||||
|
323
pdfio-file.c
323
pdfio-file.c
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF file functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -24,6 +24,7 @@
|
||||
static pdfio_obj_t *add_obj(pdfio_file_t *pdf, size_t number, unsigned short generation, off_t offset);
|
||||
static int compare_objmaps(_pdfio_objmap_t *a, _pdfio_objmap_t *b);
|
||||
static int compare_objs(pdfio_obj_t **a, pdfio_obj_t **b);
|
||||
static const char *get_info_string(pdfio_file_t *pdf, const char *key);
|
||||
static bool load_obj_stream(pdfio_obj_t *obj);
|
||||
static bool load_pages(pdfio_file_t *pdf, pdfio_obj_t *obj, size_t depth);
|
||||
static bool load_xref(pdfio_file_t *pdf, off_t xref_offset, pdfio_password_cb_t password_cb, void *password_data);
|
||||
@ -264,46 +265,26 @@ pdfioFileCreate(
|
||||
|
||||
// Write a standard PDF header...
|
||||
if (!_pdfioFilePrintf(pdf, "%%PDF-%s\n%%\342\343\317\323\n", version))
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
unlink(filename);
|
||||
return (NULL);
|
||||
}
|
||||
goto error;
|
||||
|
||||
// Create the pages object...
|
||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
unlink(filename);
|
||||
return (NULL);
|
||||
}
|
||||
goto error;
|
||||
|
||||
pdfioDictSetName(dict, "Type", "Pages");
|
||||
|
||||
if ((pdf->pages_obj = pdfioFileCreateObj(pdf, dict)) == NULL)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
unlink(filename);
|
||||
return (NULL);
|
||||
}
|
||||
goto error;
|
||||
|
||||
// Create the info object...
|
||||
if ((info_dict = pdfioDictCreate(pdf)) == NULL)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
unlink(filename);
|
||||
return (NULL);
|
||||
}
|
||||
goto error;
|
||||
|
||||
pdfioDictSetDate(info_dict, "CreationDate", time(NULL));
|
||||
pdfioDictSetString(info_dict, "Producer", "pdfio/" PDFIO_VERSION);
|
||||
|
||||
if ((pdf->info_obj = pdfioFileCreateObj(pdf, info_dict)) == NULL)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
unlink(filename);
|
||||
return (NULL);
|
||||
}
|
||||
goto error;
|
||||
|
||||
// Create random file ID values...
|
||||
_pdfioCryptoMakeRandom(id_value, sizeof(id_value));
|
||||
@ -315,6 +296,15 @@ pdfioFileCreate(
|
||||
}
|
||||
|
||||
return (pdf);
|
||||
|
||||
// Common error handling code...
|
||||
error:
|
||||
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
unlink(filename);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -535,41 +525,26 @@ pdfioFileCreateOutput(
|
||||
|
||||
// Write a standard PDF header...
|
||||
if (!_pdfioFilePrintf(pdf, "%%PDF-%s\n%%\342\343\317\323\n", version))
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (NULL);
|
||||
}
|
||||
goto error;
|
||||
|
||||
// Create the pages object...
|
||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (NULL);
|
||||
}
|
||||
goto error;
|
||||
|
||||
pdfioDictSetName(dict, "Type", "Pages");
|
||||
|
||||
if ((pdf->pages_obj = pdfioFileCreateObj(pdf, dict)) == NULL)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (NULL);
|
||||
}
|
||||
goto error;
|
||||
|
||||
// Create the info object...
|
||||
if ((info_dict = pdfioDictCreate(pdf)) == NULL)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (NULL);
|
||||
}
|
||||
goto error;
|
||||
|
||||
pdfioDictSetDate(info_dict, "CreationDate", time(NULL));
|
||||
pdfioDictSetString(info_dict, "Producer", "pdfio/" PDFIO_VERSION);
|
||||
|
||||
if ((pdf->info_obj = pdfioFileCreateObj(pdf, info_dict)) == NULL)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (NULL);
|
||||
}
|
||||
goto error;
|
||||
|
||||
// Create random file ID values...
|
||||
_pdfioCryptoMakeRandom(id_value, sizeof(id_value));
|
||||
@ -581,6 +556,13 @@ pdfioFileCreateOutput(
|
||||
}
|
||||
|
||||
return (pdf);
|
||||
|
||||
// Common error handling code...
|
||||
error:
|
||||
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -657,6 +639,194 @@ pdfioFileCreatePage(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioFileCreateTemporary()' - Create a temporary PDF file.
|
||||
//
|
||||
// This function creates a PDF file with a unique filename in the current
|
||||
// temporary directory. The temporary file is stored in the string "buffer" an
|
||||
// will have a ".pdf" extension. Otherwise, this function works the same as
|
||||
// the @link pdfioFileCreate@ function.
|
||||
//
|
||||
// @since PDFio v1.1@
|
||||
//
|
||||
|
||||
pdfio_file_t *
|
||||
pdfioFileCreateTemporary(
|
||||
char *buffer, // I - Filename buffer
|
||||
size_t bufsize, // I - Size of filename buffer
|
||||
const char *version, // I - PDF version number or `NULL` for default (2.0)
|
||||
pdfio_rect_t *media_box, // I - Default MediaBox for pages
|
||||
pdfio_rect_t *crop_box, // I - Default CropBox for pages
|
||||
pdfio_error_cb_t error_cb, // I - Error callback or `NULL` for default
|
||||
void *error_data) // I - Error callback data, if any
|
||||
{
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
pdfio_dict_t *dict; // Dictionary for pages object
|
||||
pdfio_dict_t *info_dict; // Dictionary for information object
|
||||
unsigned char id_value[16]; // File ID value
|
||||
int i; // Looping var
|
||||
const char *tmpdir; // Temporary directory
|
||||
#if _WIN32 || defined(__APPLE__)
|
||||
char tmppath[256]; // Temporary directory path
|
||||
#endif // _WIN32 || __APPLE__
|
||||
unsigned tmpnum; // Temporary filename number
|
||||
|
||||
|
||||
// Range check input...
|
||||
if (!buffer || bufsize < 32)
|
||||
{
|
||||
if (buffer)
|
||||
*buffer = '\0';
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (!version)
|
||||
version = "2.0";
|
||||
|
||||
if (!error_cb)
|
||||
{
|
||||
error_cb = _pdfioFileDefaultError;
|
||||
error_data = NULL;
|
||||
}
|
||||
|
||||
// Allocate a PDF file structure...
|
||||
if ((pdf = (pdfio_file_t *)calloc(1, sizeof(pdfio_file_t))) == NULL)
|
||||
{
|
||||
pdfio_file_t temp; // Dummy file
|
||||
char message[8192]; // Message string
|
||||
|
||||
temp.filename = (char *)"temporary.pdf";
|
||||
snprintf(message, sizeof(message), "Unable to allocate memory for PDF file - %s", strerror(errno));
|
||||
(error_cb)(&temp, message, error_data);
|
||||
|
||||
*buffer = '\0';
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
// Create the file...
|
||||
#if _WIN32
|
||||
if ((tmpdir = getenv("TEMP")) == NULL)
|
||||
{
|
||||
GetTempPathA(sizeof(tmppath), tmppath);
|
||||
tmpdir = tmppath;
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
if ((tmpdir = getenv("TMPDIR")) != NULL && access(tmpdir, W_OK))
|
||||
tmpdir = NULL;
|
||||
|
||||
if (!tmpdir)
|
||||
{
|
||||
// Grab the per-process temporary directory for sandboxed apps...
|
||||
# ifdef _CS_DARWIN_USER_TEMP_DIR
|
||||
if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmppath, sizeof(tmppath)))
|
||||
tmpdir = tmppath;
|
||||
else
|
||||
# endif // _CS_DARWIN_USER_TEMP_DIR
|
||||
tmpdir = "/private/tmp";
|
||||
}
|
||||
|
||||
#else
|
||||
if ((tmpdir = getenv("TMPDIR")) == NULL || access(tmpdir, W_OK))
|
||||
tmpdir = "/tmp";
|
||||
#endif // _WIN32
|
||||
|
||||
for (i = 0; i < 1000; i ++)
|
||||
{
|
||||
_pdfioCryptoMakeRandom((uint8_t *)&tmpnum, sizeof(tmpnum));
|
||||
snprintf(buffer, bufsize, "%s/%08x.pdf", tmpdir, tmpnum);
|
||||
if ((pdf->fd = open(buffer, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC | O_EXCL, 0666)) >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
pdf->filename = strdup(buffer);
|
||||
|
||||
if (i >= 1000)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to create file - %s", strerror(errno));
|
||||
free(pdf->filename);
|
||||
free(pdf);
|
||||
*buffer = '\0';
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
pdf->version = strdup(version);
|
||||
pdf->mode = _PDFIO_MODE_WRITE;
|
||||
pdf->error_cb = error_cb;
|
||||
pdf->error_data = error_data;
|
||||
pdf->permissions = PDFIO_PERMISSION_ALL;
|
||||
pdf->bufptr = pdf->buffer;
|
||||
pdf->bufend = pdf->buffer + sizeof(pdf->buffer);
|
||||
|
||||
if (media_box)
|
||||
{
|
||||
pdf->media_box = *media_box;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default to "universal" size (intersection of A4 and US Letter)
|
||||
pdf->media_box.x2 = 210.0 * 72.0f / 25.4f;
|
||||
pdf->media_box.y2 = 11.0f * 72.0f;
|
||||
}
|
||||
|
||||
if (crop_box)
|
||||
{
|
||||
pdf->crop_box = *crop_box;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default to "universal" size (intersection of A4 and US Letter)
|
||||
pdf->crop_box.x2 = 210.0 * 72.0f / 25.4f;
|
||||
pdf->crop_box.y2 = 11.0f * 72.0f;
|
||||
}
|
||||
|
||||
// Write a standard PDF header...
|
||||
if (!_pdfioFilePrintf(pdf, "%%PDF-%s\n%%\342\343\317\323\n", version))
|
||||
goto error;
|
||||
|
||||
// Create the pages object...
|
||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||
goto error;
|
||||
|
||||
pdfioDictSetName(dict, "Type", "Pages");
|
||||
|
||||
if ((pdf->pages_obj = pdfioFileCreateObj(pdf, dict)) == NULL)
|
||||
goto error;
|
||||
|
||||
// Create the info object...
|
||||
if ((info_dict = pdfioDictCreate(pdf)) == NULL)
|
||||
goto error;
|
||||
|
||||
pdfioDictSetDate(info_dict, "CreationDate", time(NULL));
|
||||
pdfioDictSetString(info_dict, "Producer", "pdfio/" PDFIO_VERSION);
|
||||
|
||||
if ((pdf->info_obj = pdfioFileCreateObj(pdf, info_dict)) == NULL)
|
||||
goto error;
|
||||
|
||||
// Create random file ID values...
|
||||
_pdfioCryptoMakeRandom(id_value, sizeof(id_value));
|
||||
|
||||
if ((pdf->id_array = pdfioArrayCreate(pdf)) != NULL)
|
||||
{
|
||||
pdfioArrayAppendBinary(pdf->id_array, id_value, sizeof(id_value));
|
||||
pdfioArrayAppendBinary(pdf->id_array, id_value, sizeof(id_value));
|
||||
}
|
||||
|
||||
return (pdf);
|
||||
|
||||
// Common error handling code...
|
||||
error:
|
||||
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
unlink(buffer);
|
||||
*buffer = '\0';
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioFileFindMappedObj()' - Find a mapped object.
|
||||
//
|
||||
@ -723,7 +893,7 @@ pdfioFileFindObj(
|
||||
const char * // O - Author or `NULL` for none
|
||||
pdfioFileGetAuthor(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
return (pdf && pdf->info_obj ? pdfioDictGetString(pdf->info_obj->value.value.dict, "Author") : NULL);
|
||||
return (get_info_string(pdf, "Author"));
|
||||
}
|
||||
|
||||
|
||||
@ -735,7 +905,7 @@ time_t // O - Creation date or `0` for none
|
||||
pdfioFileGetCreationDate(
|
||||
pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
return (pdf && pdf->info_obj ? pdfioDictGetDate(pdf->info_obj->value.value.dict, "CreationDate") : 0);
|
||||
return (pdf && pdf->info_obj ? pdfioDictGetDate(pdfioObjGetDict(pdf->info_obj), "CreationDate") : 0);
|
||||
}
|
||||
|
||||
|
||||
@ -746,7 +916,7 @@ pdfioFileGetCreationDate(
|
||||
const char * // O - Creator string or `NULL` for none
|
||||
pdfioFileGetCreator(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
return (pdf && pdf->info_obj ? pdfioDictGetString(pdf->info_obj->value.value.dict, "Creator") : NULL);
|
||||
return (get_info_string(pdf, "Creator"));
|
||||
}
|
||||
|
||||
|
||||
@ -768,7 +938,7 @@ pdfioFileGetID(pdfio_file_t *pdf) // I - PDF file
|
||||
const char * // O - Keywords string or `NULL` for none
|
||||
pdfioFileGetKeywords(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
return (pdf && pdf->info_obj ? pdfioDictGetString(pdf->info_obj->value.value.dict, "Keywords") : NULL);
|
||||
return (get_info_string(pdf, "Keywords"));
|
||||
}
|
||||
|
||||
|
||||
@ -872,7 +1042,7 @@ pdfioFileGetPermissions(
|
||||
const char * // O - Producer string or `NULL` for none
|
||||
pdfioFileGetProducer(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
return (pdf && pdf->info_obj ? pdfioDictGetString(pdf->info_obj->value.value.dict, "Producer") : NULL);
|
||||
return (get_info_string(pdf, "Producer"));
|
||||
}
|
||||
|
||||
|
||||
@ -883,7 +1053,7 @@ pdfioFileGetProducer(pdfio_file_t *pdf) // I - PDF file
|
||||
const char * // O - Subject or `NULL` for none
|
||||
pdfioFileGetSubject(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
return (pdf && pdf->info_obj ? pdfioDictGetString(pdf->info_obj->value.value.dict, "Subject") : NULL);
|
||||
return (get_info_string(pdf, "Subject"));
|
||||
}
|
||||
|
||||
|
||||
@ -894,7 +1064,7 @@ pdfioFileGetSubject(pdfio_file_t *pdf) // I - PDF file
|
||||
const char * // O - Title or `NULL` for none
|
||||
pdfioFileGetTitle(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
return (pdf && pdf->info_obj ? pdfioDictGetString(pdf->info_obj->value.value.dict, "Title") : NULL);
|
||||
return (get_info_string(pdf, "Title"));
|
||||
}
|
||||
|
||||
|
||||
@ -1237,6 +1407,51 @@ compare_objs(pdfio_obj_t **a, // I - First object
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'get_info_string()' - Get a string value from the Info dictionary.
|
||||
//
|
||||
// This function also handles converting binary strings to C strings, which
|
||||
// occur in encrypted PDF files.
|
||||
//
|
||||
|
||||
static const char * // O - String or `NULL` if not found
|
||||
get_info_string(pdfio_file_t *pdf, // I - PDF file
|
||||
const char *key) // I - Dictionary key
|
||||
{
|
||||
pdfio_dict_t *dict; // Info dictionary
|
||||
_pdfio_value_t *value; // Value
|
||||
|
||||
// Range check input...
|
||||
if (!pdf || !pdf->info_obj || (dict = pdfioObjGetDict(pdf->info_obj)) == NULL || (value = _pdfioDictGetValue(dict, key)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
// If we already have a value, return it...
|
||||
if (value->type == PDFIO_VALTYPE_NAME || value->type == PDFIO_VALTYPE_STRING)
|
||||
{
|
||||
return (value->value.string);
|
||||
}
|
||||
else if (value->type == PDFIO_VALTYPE_BINARY && value->value.binary.datalen < 4096)
|
||||
{
|
||||
// Convert binary string to regular string...
|
||||
char temp[4096]; // Temporary string
|
||||
|
||||
memcpy(temp, value->value.binary.data, value->value.binary.datalen);
|
||||
temp[value->value.binary.datalen] = '\0';
|
||||
|
||||
free(value->value.binary.data);
|
||||
value->type = PDFIO_VALTYPE_STRING;
|
||||
value->value.string = pdfioStringCreate(pdf, temp);
|
||||
|
||||
return (value->value.string);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something else that is not a string...
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'load_obj_stream()' - Load an object stream.
|
||||
//
|
||||
@ -1769,6 +1984,8 @@ load_xref(
|
||||
return (false);
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("load_xref: Got trailer dict.\n");
|
||||
|
||||
_pdfioTokenFlush(&tb);
|
||||
|
||||
if (!pdf->trailer_dict)
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF object functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -33,8 +33,14 @@ 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)
|
||||
@ -165,6 +171,12 @@ 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"))
|
||||
{
|
||||
@ -194,6 +206,7 @@ pdfioObjCreateStream(
|
||||
return (NULL);
|
||||
|
||||
obj->stream_offset = _pdfioFileTell(obj->pdf);
|
||||
obj->pdf->current_obj = obj;
|
||||
|
||||
// Return the new stream...
|
||||
return (_pdfioStreamCreate(obj, length_obj, filter));
|
||||
@ -454,6 +467,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)
|
||||
{
|
||||
@ -466,6 +485,8 @@ pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object
|
||||
return (NULL);
|
||||
|
||||
// Open the stream...
|
||||
obj->pdf->current_obj = obj;
|
||||
|
||||
return (_pdfioStreamOpen(obj, decode));
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Private header file 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.
|
||||
@ -289,7 +289,8 @@ struct _pdfio_file_s // PDF file structure
|
||||
pdfio_dict_t **dicts; // Dictionaries
|
||||
size_t num_objs, // Number of objects
|
||||
alloc_objs; // Allocated objects
|
||||
pdfio_obj_t **objs; // Objects
|
||||
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
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF stream functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2022 by Michael R Sweet.
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -174,6 +174,8 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
|
||||
done:
|
||||
|
||||
st->pdf->current_obj = NULL;
|
||||
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
@ -364,6 +366,13 @@ pdfioStreamConsume(pdfio_stream_t *st, // I - Stream
|
||||
//
|
||||
// 'pdfioStreamGetToken()' - Read a single PDF token from a stream.
|
||||
//
|
||||
// This function reads a single PDF token from a stream. Operator tokens,
|
||||
// boolean values, and numbers are returned as-is in the provided string buffer.
|
||||
// String values start with the opening parenthesis ('(') but have all escaping
|
||||
// resolved and the terminating parenthesis removed. Hexadecimal string values
|
||||
// start with the opening angle bracket ('<') and have all whitespace and the
|
||||
// terminating angle bracket removed.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on EOF
|
||||
pdfioStreamGetToken(
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF token parsing functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -129,9 +129,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);
|
||||
|
||||
@ -536,7 +547,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
|
||||
*bufptr = '\0';
|
||||
|
||||
PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
||||
// PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
||||
|
||||
return (bufptr > buffer);
|
||||
}
|
||||
@ -573,6 +584,7 @@ get_char(_pdfio_token_t *tb) // I - Token buffer
|
||||
tb->bufptr = tb->buffer;
|
||||
tb->bufend = tb->buffer + bytes;
|
||||
|
||||
#if 0
|
||||
#ifdef DEBUG
|
||||
unsigned char *ptr; // Pointer into buffer
|
||||
|
||||
@ -586,6 +598,7 @@ get_char(_pdfio_token_t *tb) // I - Token buffer
|
||||
}
|
||||
PDFIO_DEBUG("'\n");
|
||||
#endif // DEBUG
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
// Return the next character...
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF value functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 by Michael R Sweet.
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -219,7 +219,6 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioValueRead(pdf=%p, obj=%p, v=%p)\n", pdf, obj, v);
|
||||
(void)obj; // TODO: Implement decryption
|
||||
|
||||
if (!_pdfioTokenGet(tb, token, sizeof(token)))
|
||||
return (NULL);
|
||||
@ -284,6 +283,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (token[i])
|
||||
{
|
||||
// Just a string...
|
||||
@ -367,6 +367,33 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
*dataptr++ = (unsigned char)d;
|
||||
}
|
||||
|
||||
if (obj && pdf->encryption)
|
||||
{
|
||||
// Decrypt the string...
|
||||
_pdfio_crypto_ctx_t ctx; // Decryption context
|
||||
_pdfio_crypto_cb_t cb; // Decryption callback
|
||||
size_t ivlen; // Number of initialization vector bytes
|
||||
uint8_t temp[32768]; // Temporary buffer for decryption
|
||||
size_t templen; // Number of actual data bytes
|
||||
|
||||
if (v->value.binary.datalen > (sizeof(temp) - 32))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted binary string - too long.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen);
|
||||
templen = (cb)(&ctx, temp, v->value.binary.data + ivlen, v->value.binary.datalen - ivlen);
|
||||
|
||||
// Copy the decrypted string back to the value and adjust the length...
|
||||
memcpy(v->value.binary.data, temp, templen);
|
||||
|
||||
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128)
|
||||
v->value.binary.datalen = templen - temp[templen - 1];
|
||||
else
|
||||
v->value.binary.datalen = templen;
|
||||
}
|
||||
}
|
||||
else if (strchr("0123456789-+.", token[0]) != NULL)
|
||||
{
|
||||
|
6
pdfio.h
6
pdfio.h
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Public header file 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.
|
||||
@ -55,6 +55,8 @@ 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);
|
||||
@ -165,6 +167,7 @@ extern pdfio_obj_t *pdfioDictGetObj(pdfio_dict_t *dict, const char *key) _PDFIO_
|
||||
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;
|
||||
@ -185,6 +188,7 @@ extern pdfio_obj_t *pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_dict_t *dict) _P
|
||||
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_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 time_t pdfioFileGetCreationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
|
@ -87,7 +87,7 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0.1";WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";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.0.1";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";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.0.1";_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";_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.0.1";NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
@ -372,7 +372,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.0.1;
|
||||
CURRENT_PROJECT_VERSION = 1.1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@ -450,7 +450,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.0.1;
|
||||
CURRENT_PROJECT_VERSION = 1.1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
|
@ -101,6 +101,7 @@ pdfioContentPathClose
|
||||
pdfioContentPathCurve
|
||||
pdfioContentPathCurve13
|
||||
pdfioContentPathCurve23
|
||||
pdfioContentPathEnd
|
||||
pdfioContentPathLineTo
|
||||
pdfioContentPathMoveTo
|
||||
pdfioContentPathRect
|
||||
@ -154,6 +155,7 @@ pdfioDictGetObj
|
||||
pdfioDictGetRect
|
||||
pdfioDictGetString
|
||||
pdfioDictGetType
|
||||
pdfioDictIterateKeys
|
||||
pdfioDictSetArray
|
||||
pdfioDictSetBinary
|
||||
pdfioDictSetBoolean
|
||||
@ -177,6 +179,7 @@ pdfioFileCreateImageObjFromFile
|
||||
pdfioFileCreateObj
|
||||
pdfioFileCreateOutput
|
||||
pdfioFileCreatePage
|
||||
pdfioFileCreateTemporary
|
||||
pdfioFileFindObj
|
||||
pdfioFileGetAuthor
|
||||
pdfioFileGetCreationDate
|
||||
|
@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.0.1</version>
|
||||
<version>1.1.0</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
@ -13,10 +13,10 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>PDFio Library for VS2019+</description>
|
||||
<summary>PDFio is a simple C library for reading and writing PDF files. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
||||
<copyright>Copyright © 2019-2022 by Michael R Sweet</copyright>
|
||||
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
<dependencies>
|
||||
<dependency id="pdfio_native.redist" version="1.0.1" />
|
||||
<dependency id="pdfio_native.redist" version="1.1.0" />
|
||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native.redist</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.0.1</version>
|
||||
<version>1.1.0</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
@ -13,7 +13,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>PDFio Library for VS2019+</description>
|
||||
<summary>PDFio is a simple C library for reading and writing PDF files. This package provides the redistributable content for the PDFio library. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
||||
<copyright>Copyright © 2019-2022 by Michael R Sweet</copyright>
|
||||
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
|
158
testpdfio.c
158
testpdfio.c
@ -34,6 +34,7 @@ static int do_test_file(const char *filename, int objnum, bool verbose);
|
||||
static int do_unit_tests(void);
|
||||
static int draw_image(pdfio_stream_t *st, const char *name, double x, double y, double w, double h, const char *label);
|
||||
static bool error_cb(pdfio_file_t *pdf, const char *message, bool *error);
|
||||
static bool iterate_cb(pdfio_dict_t *dict, const char *key, void *cb_data);
|
||||
static ssize_t output_cb(int *fd, const void *buffer, size_t bytes);
|
||||
static const char *password_cb(void *data, const char *filename);
|
||||
static int read_unit_file(const char *filename, size_t num_pages, size_t first_image, bool is_output);
|
||||
@ -506,6 +507,9 @@ do_unit_tests(void)
|
||||
_pdfio_value_t value; // Value
|
||||
size_t first_image, // First image object
|
||||
num_pages; // Number of pages written
|
||||
char temppdf[1024]; // Temporary PDF file
|
||||
pdfio_dict_t *dict; // Test dictionary
|
||||
int count = 0; // Number of key/value pairs
|
||||
static const char *complex_dict = // Complex dictionary value
|
||||
"<</Annots 5457 0 R/Contents 5469 0 R/CropBox[0 0 595.4 842]/Group 725 0 R"
|
||||
"/MediaBox[0 0 595.4 842]/Parent 23513 0 R/Resources<</ColorSpace<<"
|
||||
@ -967,6 +971,41 @@ do_unit_tests(void)
|
||||
|
||||
// TODO: Test for known values in this test file.
|
||||
|
||||
// Test dictionary APIs
|
||||
fputs("pdfioDictCreate: ", stdout);
|
||||
if ((dict = pdfioDictCreate(inpdf)) != NULL)
|
||||
{
|
||||
puts("PASS");
|
||||
|
||||
fputs("pdfioDictSet*: ", stdout);
|
||||
if (pdfioDictSetBoolean(dict, "Boolean", true) && pdfioDictSetName(dict, "Name", "Name") && pdfioDictSetNumber(dict, "Number", 42.0) && pdfioDictSetString(dict, "String", "String"))
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL");
|
||||
return (1);
|
||||
}
|
||||
|
||||
fputs("pdfioDictIterateKeys: ", stdout);
|
||||
pdfioDictIterateKeys(dict, iterate_cb, &count);
|
||||
if (count == 4)
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("FAIL (got %d, expected 4)\n", count);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL");
|
||||
return (1);
|
||||
}
|
||||
|
||||
// Test the value parsers for edge cases...
|
||||
fputs("_pdfioValueRead(complex_dict): ", stdout);
|
||||
s = complex_dict;
|
||||
@ -1107,6 +1146,18 @@ do_unit_tests(void)
|
||||
if (read_unit_file("testpdfio-aesp.pdf", num_pages, first_image, false))
|
||||
return (1);
|
||||
|
||||
fputs("pdfioFileCreateTemporary: ", stdout);
|
||||
if ((outpdf = pdfioFileCreateTemporary(temppdf, sizeof(temppdf), NULL, NULL, NULL, (pdfio_error_cb_t)error_cb, &error)) != NULL)
|
||||
printf("PASS (%s)\n", temppdf);
|
||||
else
|
||||
return (1);
|
||||
|
||||
if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
|
||||
return (1);
|
||||
|
||||
if (read_unit_file(temppdf, num_pages, first_image, false))
|
||||
return (1);
|
||||
|
||||
pdfioFileClose(inpdf);
|
||||
|
||||
return (0);
|
||||
@ -1199,6 +1250,27 @@ error_cb(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'iterate_cb()' - Test pdfioDictIterateKeys function.
|
||||
//
|
||||
|
||||
static bool // O - `true` to continue, `false` to stop
|
||||
iterate_cb(pdfio_dict_t *dict, // I - Dictionary
|
||||
const char *key, // I - Key
|
||||
void *cb_data) // I - Callback data
|
||||
{
|
||||
int *count = (int *)cb_data; // Pointer to counter
|
||||
|
||||
|
||||
if (!dict || !key || !cb_data)
|
||||
return (false);
|
||||
|
||||
(*count)++;
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'output_cb()' - Write output to a file.
|
||||
//
|
||||
@ -1238,6 +1310,7 @@ read_unit_file(const char *filename, // I - File to read
|
||||
{
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
size_t i; // Looping var
|
||||
const char *s; // String
|
||||
bool error = false; // Error callback data
|
||||
|
||||
|
||||
@ -1248,6 +1321,87 @@ read_unit_file(const char *filename, // I - File to read
|
||||
else
|
||||
return (1);
|
||||
|
||||
// Verify metadata...
|
||||
fputs("pdfioFileGetAuthor: ", stdout);
|
||||
if ((s = pdfioFileGetAuthor(pdf)) != NULL && !strcmp(s, "Michael R Sweet"))
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else if (s)
|
||||
{
|
||||
printf("FAIL (got '%s', expected 'Michael R Sweet')\n", s);
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL (got NULL, expected 'Michael R Sweet')");
|
||||
return (1);
|
||||
}
|
||||
|
||||
fputs("pdfioFileGetCreator: ", stdout);
|
||||
if ((s = pdfioFileGetCreator(pdf)) != NULL && !strcmp(s, "testpdfio"))
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else if (s)
|
||||
{
|
||||
printf("FAIL (got '%s', expected 'testpdfio')\n", s);
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL (got NULL, expected 'testpdfio')");
|
||||
return (1);
|
||||
}
|
||||
|
||||
fputs("pdfioFileGetKeywords: ", stdout);
|
||||
if ((s = pdfioFileGetKeywords(pdf)) != NULL && !strcmp(s, "one fish,two fish,red fish,blue fish"))
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else if (s)
|
||||
{
|
||||
printf("FAIL (got '%s', expected 'one fish,two fish,red fish,blue fish')\n", s);
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL (got NULL, expected 'one fish,two fish,red fish,blue fish')");
|
||||
return (1);
|
||||
}
|
||||
|
||||
fputs("pdfioFileGetSubject: ", stdout);
|
||||
if ((s = pdfioFileGetSubject(pdf)) != NULL && !strcmp(s, "Unit test document"))
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else if (s)
|
||||
{
|
||||
printf("FAIL (got '%s', expected 'Unit test document')\n", s);
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL (got NULL, expected 'Unit test document')");
|
||||
return (1);
|
||||
}
|
||||
|
||||
fputs("pdfioFileGetTitle: ", stdout);
|
||||
if ((s = pdfioFileGetTitle(pdf)) != NULL && !strcmp(s, "Test Document"))
|
||||
{
|
||||
puts("PASS");
|
||||
}
|
||||
else if (s)
|
||||
{
|
||||
printf("FAIL (got '%s', expected 'Test Document')\n", s);
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL (got NULL, expected 'Test Document')");
|
||||
return (1);
|
||||
}
|
||||
|
||||
// Verify the number of pages is the same...
|
||||
fputs("pdfioFileGetNumPages: ", stdout);
|
||||
if (num_pages == pdfioFileGetNumPages(pdf))
|
||||
@ -3167,13 +3321,13 @@ write_unit_file(
|
||||
// Create some image objects...
|
||||
fputs("pdfioFileCreateImageObjFromFile(\"testfiles/color.jpg\"): ", stdout);
|
||||
if ((color_jpg = pdfioFileCreateImageObjFromFile(outpdf, "testfiles/color.jpg", true)) != NULL)
|
||||
puts("PASS");
|
||||
printf("PASS (%u)\n", (unsigned)pdfioObjGetNumber(color_jpg));
|
||||
else
|
||||
return (1);
|
||||
|
||||
fputs("pdfioFileCreateImageObjFromFile(\"testfiles/gray.jpg\"): ", stdout);
|
||||
if ((gray_jpg = pdfioFileCreateImageObjFromFile(outpdf, "testfiles/gray.jpg", true)) != NULL)
|
||||
puts("PASS");
|
||||
printf("PASS (%u)\n", (unsigned)pdfioObjGetNumber(gray_jpg));
|
||||
else
|
||||
return (1);
|
||||
|
||||
|
6
ttf.c
6
ttf.c
@ -420,7 +420,7 @@ ttfCreate(const char *filename, // I - Filename
|
||||
if (read_os_2(font, &os_2))
|
||||
{
|
||||
// Copy key values from OS/2 table...
|
||||
static const ttf_stretch_t widths[] =
|
||||
static const ttf_stretch_t stretches[] =
|
||||
{
|
||||
TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed
|
||||
TTF_STRETCH_EXTRA_CONDENSED, // extra-condensed
|
||||
@ -433,8 +433,8 @@ ttfCreate(const char *filename, // I - Filename
|
||||
TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded
|
||||
};
|
||||
|
||||
if (os_2.usWidthClass >= 1 && os_2.usWidthClass <= (int)(sizeof(widths) / sizeof(widths[0])))
|
||||
font->stretch = widths[os_2.usWidthClass - 1];
|
||||
if (os_2.usWidthClass >= 1 && os_2.usWidthClass <= (int)(sizeof(stretches) / sizeof(stretches[0])))
|
||||
font->stretch = stretches[os_2.usWidthClass - 1];
|
||||
|
||||
font->weight = (short)os_2.usWeightClass;
|
||||
font->cap_height = os_2.sCapHeight;
|
||||
|
Reference in New Issue
Block a user