mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-07-13 06:24:25 +02:00
Compare commits
120 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 | |||
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
|
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 }}"
|
38
.github/workflows/coverity.yml
vendored
Normal file
38
.github/workflows/coverity.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: Coverity Scan
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
coverity-scan:
|
||||
runs-on: ubuntu-latest
|
||||
environment: Coverity
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: update build environment
|
||||
run: sudo apt-get update --fix-missing -y
|
||||
- name: install prerequisites
|
||||
run: sudo apt-get install -y zlib1g-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: Build 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 }}
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -4,8 +4,11 @@
|
||||
*.o
|
||||
*.so.1
|
||||
/.vs
|
||||
/afl-output
|
||||
/doc/pdfio.epub
|
||||
/packages
|
||||
/pdfio.xcodeproj/xcshareddata
|
||||
/pdfiototext
|
||||
/testpdfio
|
||||
/testpdfio-out.pdf
|
||||
/testpdfio-*.pdf
|
||||
/x64
|
||||
|
55
CHANGES.md
Normal file
55
CHANGES.md
Normal file
@ -0,0 +1,55 @@
|
||||
Changes in PDFio
|
||||
================
|
||||
|
||||
|
||||
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.
|
||||
- Fixed bug in `pdfioStreamGetToken`.
|
||||
|
||||
|
||||
v1.0.0 (December 14, 2021)
|
||||
--------------------------
|
||||
|
||||
- First stable release.
|
||||
|
||||
|
||||
v1.0rc1 (November 30, 2021)
|
||||
---------------------------
|
||||
|
||||
- Fixed a few stack/buffer overflow bugs discovered via fuzzing.
|
||||
|
||||
|
||||
v1.0b2 (November 7, 2021)
|
||||
-------------------------
|
||||
|
||||
- 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 (August 30, 2021)
|
||||
------------------------
|
||||
|
||||
- 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.
|
398
CONTRIBUTING.md
Normal file
398
CONTRIBUTING.md
Normal file
@ -0,0 +1,398 @@
|
||||
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 a simple POSIX makefile to build a static or shared
|
||||
library. To improve portability, makefiles *must not* make use of features
|
||||
unique to GNU make. See the [Makefile Guidelines](#makefile-guidelines) section
|
||||
for a description of the allowed make features and makefile guidelines.
|
||||
|
||||
An Xcode project is provided for macOS/iOS developers, and a Visual Studio
|
||||
solution and projects for Windows developers.
|
||||
|
||||
|
||||
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 command,
|
||||
- `CC`; the C compiler command,
|
||||
- `CFLAGS`; options for the C compiler command,
|
||||
- `CODESIGN_IDENTITY`: the code signing identity,
|
||||
- `COMMONFLAGS`; common compiler optimization options,
|
||||
- `DESTDIR`/`DSTROOT`: the destination root directory when installing.
|
||||
- `DSO`; the shared library building command,
|
||||
- `DSOFLAGS`; options for the shared library building command,
|
||||
- `DSONAME`: the root name of the shared library
|
||||
- `LDFLAGS`; options for the linker,
|
||||
- `LIBS`; libraries for all programs,
|
||||
- `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.
|
||||
- `all-shared`; creates a shared library appropriate for the local system.
|
||||
- `clean`; removes all target programs libraries, documentation files, and
|
||||
object files,
|
||||
- `debug`: creates a clean build of the static library and unit test program
|
||||
with debug printfs and the clang address sanitizer enabled.
|
||||
- `install`; installs all distribution files in their corresponding locations.
|
||||
- `install-shared`; same as `install` but also installs the shared library.
|
||||
- `test`; runs the unit test program, building it as needed.
|
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.
|
74
Makefile
74
Makefile
@ -1,7 +1,7 @@
|
||||
#
|
||||
# Makefile 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.
|
||||
@ -10,13 +10,17 @@
|
||||
# POSIX makefile
|
||||
.POSIX:
|
||||
|
||||
# Variables...
|
||||
# Build silently
|
||||
.SILENT:
|
||||
|
||||
# Variables
|
||||
AR = ar
|
||||
ARFLAGS = cr
|
||||
CC = cc
|
||||
CFLAGS =
|
||||
CODESIGN_IDENTITY = Developer ID
|
||||
COMMONFLAGS = -Os -g
|
||||
#COMMONFLAGS = -O0 -g -fsanitize=address
|
||||
CPPFLAGS = '-DPDFIO_VERSION="$(VERSION)"'
|
||||
DESTDIR = $(DSTROOT)
|
||||
DSO = cc
|
||||
@ -25,13 +29,14 @@ DSONAME =
|
||||
LDFLAGS =
|
||||
LIBS = -lm -lz
|
||||
RANLIB = ranlib
|
||||
VERSION = 1.0b1
|
||||
VERSION = 1.1.0
|
||||
prefix = /usr/local
|
||||
|
||||
|
||||
# Base rules
|
||||
.SUFFIXES: .c .h .o
|
||||
.c.o:
|
||||
echo Compiling $<...
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(COMMONFLAGS) -c $<
|
||||
|
||||
|
||||
@ -40,13 +45,18 @@ 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 \
|
||||
@ -56,10 +66,12 @@ LIBOBJS = \
|
||||
ttf.o
|
||||
OBJS = \
|
||||
$(LIBOBJS) \
|
||||
pdfiototext.o \
|
||||
testpdfio.o
|
||||
TARGETS = \
|
||||
$(DSONAME) \
|
||||
libpdfio.a \
|
||||
pdfiototext \
|
||||
testpdfio
|
||||
|
||||
|
||||
@ -69,13 +81,16 @@ all: $(TARGETS)
|
||||
all-shared:
|
||||
if test `uname` = Darwin; then \
|
||||
$(MAKE) DSONAME="libpdfio.1.dylib" -$(MAKEFLAGS) all; \
|
||||
else
|
||||
$(MAKE) DSONAME="libpdfio.so.1" -$(MAKEFLAGS) all; \
|
||||
else \
|
||||
$(MAKE) COMMONFLAGS="-g -Os -fPIC" DSONAME="libpdfio.so.1" -$(MAKEFLAGS) all; \
|
||||
fi
|
||||
|
||||
debug:
|
||||
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-g -fsanitize=address -DDEBUG=1" clean all
|
||||
|
||||
macos:
|
||||
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-Os -mmacosx-version-min=10.14 -arch x86_64 -arch arm64" clean all
|
||||
|
||||
|
||||
# Clean everything
|
||||
clean:
|
||||
@ -84,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
|
||||
@ -97,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
|
||||
|
||||
@ -118,16 +138,22 @@ install-shared:
|
||||
test: testpdfio
|
||||
./testpdfio
|
||||
|
||||
valgrind: testpdfio
|
||||
valgrind --leak-check=full ./testpdfio
|
||||
|
||||
|
||||
# pdfio library
|
||||
libpdfio.a: $(LIBOBJS)
|
||||
echo Archiving $@...
|
||||
$(AR) $(ARFLAGS) $@ $(LIBOBJS)
|
||||
$(RANLIB) $@
|
||||
|
||||
libpdfio.so.1: $(LIBOBJS)
|
||||
$(CC) $(DSOFLAGS) $(COMMONFLAGS) -shared -o $@ -Wl,soname,$@ $(LIBOBJS) $(LIBS)
|
||||
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)
|
||||
|
||||
|
||||
@ -141,42 +167,50 @@ pdfio1.def: $(LIBOBJS) Makefile
|
||||
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 >>$@
|
||||
nm $(LIBOBJS) 2>/dev/null | grep "T _" | awk '{print $$3}' | \
|
||||
grep -v '^_ttf' | sed -e '1,$$s/^_//' | sort >>$@
|
||||
|
||||
|
||||
# pdfio text extraction (demo, doesn't handle a lot of things yet)
|
||||
pdfiototext: pdfiototext.o libpdfio.a
|
||||
echo Linking $@...
|
||||
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ pdfiototext.o libpdfio.a $(LIBS)
|
||||
|
||||
|
||||
# pdfio test program
|
||||
testpdfio: testpdfio.o libpdfio.a
|
||||
echo Linking $@...
|
||||
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
|
||||
|
||||
|
||||
# Dependencies
|
||||
$(OBJS): pdfio.h Makefile
|
||||
$(LIBOBJS): pdfio-private.h
|
||||
$(OBJS): pdfio.h pdfio-private.h Makefile
|
||||
pdfio-content.o: pdfio-content.h ttf.h
|
||||
ttf.o: ttf.h
|
||||
|
||||
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
||||
DOCFLAGS = \
|
||||
--author "Michael R Sweet" \
|
||||
--copyright "Copyright (c) 2021 by Michael R Sweet" \
|
||||
--copyright "Copyright (c) 2021-2022 by Michael R Sweet" \
|
||||
--docversion $(VERSION)
|
||||
|
||||
.PHONY: doc
|
||||
doc:
|
||||
echo Generating documentation...
|
||||
codedoc $(DOCFLAGS) --title "PDFio Programming Manual v$(VERSION)" $(PUBHEADERS) $(PUBOBJS:.o=.c) --body doc/pdfio.md --coverimage doc/pdfio-512.png pdfio.xml >doc/pdfio.html
|
||||
codedoc $(DOCFLAGS) --title "PDFio Programming Manual v$(VERSION)" --body doc/pdfio.md --coverimage doc/pdfio-epub.png pdfio.xml --epub doc/pdfio.epub
|
||||
codedoc $(DOCFLAGS) --title "pdf read/write library" --man pdfio --section 3 --body doc/pdfio.md pdfio.xml >doc/pdfio.3
|
||||
rm -f pdfio.xml
|
||||
|
||||
|
||||
# Fuzz-test the library <>
|
||||
.PHONY: afl
|
||||
afl:
|
||||
$(MAKE) -$(MAKEFLAGS) CC="afl-clang-fast" COMMONFLAGS="-g" clean all
|
||||
test afl-output || rm -rf afl-output
|
||||
afl-fuzz -x afl-pdf.dict -i afl-input -o afl-output -V 600 -e pdf -t 5000 ./testpdfio @@
|
||||
|
||||
|
||||
# Analyze code with the Clang static analyzer <https://clang-analyzer.llvm.org>
|
||||
clang:
|
||||
clang $(CPPFLAGS) --analyze $(OBJS:.o=.c) 2>clang.log
|
||||
|
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:
|
||||
================================================
|
||||
|
13
README.md
13
README.md
@ -3,7 +3,7 @@ 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/)
|
||||
@ -13,8 +13,7 @@ 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
|
||||
@ -102,8 +101,8 @@ 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
|
||||
@ -116,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
|
||||
|
121
SECURITY.md
Normal file
121
SECURITY.md
Normal file
@ -0,0 +1,121 @@
|
||||
Security Policy
|
||||
===============
|
||||
|
||||
This file describes how security issues are reported and handled, and what the
|
||||
expectations are for security issues reported to this project.
|
||||
|
||||
|
||||
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* prodution 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
|
||||
|
||||
|
||||
Reporting a Vulnerability
|
||||
-------------------------
|
||||
|
||||
Report all security issues to "security AT msweet.org". Expect a response
|
||||
within 5 business days. Any proposed embargo date should be at least 30 days
|
||||
and no more than 90 days in the future.
|
||||
|
||||
|
||||
PGP Public Key
|
||||
--------------
|
||||
|
||||
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
|
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
BIN
doc/pdfio-epub.png
Normal file
BIN
doc/pdfio-epub.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 788 KiB |
336
doc/pdfio.3
336
doc/pdfio.3
@ -1,4 +1,4 @@
|
||||
.TH pdfio 3 "pdf read/write library" "2021-08-30" "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
|
||||
@ -6,11 +6,15 @@ pdfio \- pdf read/write library
|
||||
PDFio is a simple C library for reading and writing PDF files. The primary goals of pdfio are:
|
||||
.IP \(bu 5
|
||||
.PP
|
||||
Read any PDF file with or without encryption or linearization
|
||||
Read and write any version of PDF file
|
||||
|
||||
.IP \(bu 5
|
||||
.PP
|
||||
Write PDF files without encryption or linearization
|
||||
Provide access to pages, objects, and streams within a PDF file
|
||||
|
||||
.IP \(bu 5
|
||||
.PP
|
||||
Support reading and writing of encrypted PDF files
|
||||
|
||||
.IP \(bu 5
|
||||
.PP
|
||||
@ -30,7 +34,7 @@ PDFio is
|
||||
.I not
|
||||
concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.
|
||||
.PP
|
||||
PDFio is Copyright \[co] 2021 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
||||
PDFio is Copyright \[co] 2021\-2022 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
||||
.SS Requirements
|
||||
.PP
|
||||
PDFio requires the following to build the software:
|
||||
@ -152,7 +156,7 @@ There is also an Xcode project ("pdfio.xcodeproj") you can use on macOS which ge
|
||||
You can reproduce this with the makefile using:
|
||||
.nf
|
||||
|
||||
sudo make 'COMMONFLAGS="\-Os \-mmacosx\-version\-min=10.14 \-arch x86_64 \-arch arm64"' install
|
||||
sudo make macos install
|
||||
.fi
|
||||
.SS Detecting PDFio
|
||||
.PP
|
||||
@ -160,7 +164,7 @@ PDFio can be detected using the pkg\-config command, for example:
|
||||
.nf
|
||||
|
||||
if pkg\-config \-\-exists pdfio; then
|
||||
...
|
||||
...
|
||||
fi
|
||||
.fi
|
||||
.PP
|
||||
@ -171,7 +175,7 @@ In a makefile you can add the necessary compiler and linker options with:
|
||||
LIBS += `pkg\-config \-\-libs pdfio`
|
||||
.fi
|
||||
.PP
|
||||
On Windows, you need to link to the PDFIO.LIB (static) or PDFIO1.LIB (DLL) libraries and include the "zlib" NuGet package dependency.
|
||||
On Windows, you need to link to the PDFIO1.LIB (DLL) library and include the zlib_native NuGet package dependency. You can also use the published pdfio_native NuGet package.
|
||||
.SS Header Files
|
||||
.PP
|
||||
PDFio provides a primary header file that is always used:
|
||||
@ -250,7 +254,7 @@ Each PDF file contains one or more pages. The pdfioFileGetNumPages function retu
|
||||
}
|
||||
.fi
|
||||
.PP
|
||||
Each page is represented by a "page tree" object (what pdfioFileGetPage returns) that specifies information about the page and one or more "content" objects that contain the images, fonts, text, and graphics that appear on the page.
|
||||
Each page is represented by a "page tree" object (what pdfioFileGetPage returns) that specifies information about the page and one or more "content" objects that contain the images, fonts, text, and graphics that appear on the page. Use the pdfioPageGetNumStreams and pdfioPageOpenStream functions to access the content streams for each page.
|
||||
.PP
|
||||
The pdfioFileClose function closes a PDF file and frees all memory that was used for it:
|
||||
.nf
|
||||
@ -270,6 +274,15 @@ You create a new PDF file using the pdfioFileCreate function:
|
||||
.PP
|
||||
where the six arguments to the function are the filename ("myoutputfile.pdf"), PDF version ("2.0"), media box (media_box), crop box (crop_box), an optional error callback function (error_cb), and an optional pointer value for the error callback function (error_data). The units for the media and crop boxes are points (1/72nd of an inch).
|
||||
.PP
|
||||
Alternately you can stream a PDF file using the pdfioFileCreateOutput function:
|
||||
.nf
|
||||
|
||||
pdfio_rect_t media_box = { 0.0, 0.0, 612.0, 792.0 }; // US Letter
|
||||
pdfio_rect_t crop_box = { 36.0, 36.0, 576.0, 756.0 }; // w/0.5" margins
|
||||
|
||||
pdfio_file_t *pdf = pdfioFileCreateOutput(output_cb, output_ctx, "2.0", &media_box, &crop_box, error_cb, error_data);
|
||||
.fi
|
||||
.PP
|
||||
Once the file is created, use the pdfioFileCreateObj, pdfioFileCreatePage, and pdfioPageCopy functions to create objects and pages in the file.
|
||||
.PP
|
||||
Finally, the pdfioFileClose function writes the PDF cross\-reference and "trailer" information, closes the file, and frees all memory that was used for it.
|
||||
@ -311,6 +324,14 @@ Some PDF objects have an associated data stream, such as for pages, images, ICC
|
||||
.PP
|
||||
The first argument is the object pointer. The second argument is a boolean value that specifies whether you want to decode (typically decompress) the stream data or return it as\-is.
|
||||
.PP
|
||||
When reading a page stream you'll use the pdfioPageOpenStream function instead:
|
||||
.nf
|
||||
|
||||
pdfio_file_t *pdf = pdfioFileOpen(...);
|
||||
pdfio_obj_t *obj = pdfioFileGetPage(pdf, number);
|
||||
pdfio_stream_t *st = pdfioPageOpenStream(obj, 0, true);
|
||||
.fi
|
||||
.PP
|
||||
Once you have the stream open, you can use one of several functions to read from it:
|
||||
.IP \(bu 5
|
||||
.PP
|
||||
@ -340,12 +361,21 @@ To create a stream for a new object, call the pdfioObjCreateStream function:
|
||||
.nf
|
||||
|
||||
pdfio_file_t *pdf = pdfioFileCreate(...);
|
||||
pdfio_obj_t *pdfioFileCreateObj(pdf, ...);
|
||||
pdfio_stream_t *pdfioObjCreateStream(obj, PDFIO_FILTER_FLATE);
|
||||
pdfio_obj_t *obj = pdfioFileCreateObj(pdf, ...);
|
||||
pdfio_stream_t *st = pdfioObjCreateStream(obj, PDFIO_FILTER_FLATE);
|
||||
.fi
|
||||
.PP
|
||||
The first argument is the newly created object. The second argument is either PDFIO_FILTER_NONE to specify that any encoding is done by your program or PDFIO_FILTER_FLATE to specify that PDFio should Flate compress the stream.
|
||||
.PP
|
||||
To create a page content stream call the pdfioFileCreatePage function:
|
||||
.nf
|
||||
|
||||
pdfio_file_t *pdf = pdfioFileCreate(...);
|
||||
pdfio_dict_t *dict = pdfioDictCreate(pdf);
|
||||
\... set page dictionary keys and values ...
|
||||
pdfio_stream_t *st = pdfioFileCreatePage(pdf, dict);
|
||||
.fi
|
||||
.PP
|
||||
Once you have created the stream, use any of the following functions to write to the stream:
|
||||
.IP \(bu 5
|
||||
.PP
|
||||
@ -800,6 +830,28 @@ Display P3
|
||||
PDFIO_CS_SRGB
|
||||
.br
|
||||
sRGB
|
||||
.SS pdfio_encryption_e
|
||||
PDF encryption modes
|
||||
.TP 5
|
||||
PDFIO_ENCRYPTION_AES_128
|
||||
.br
|
||||
128-bit AES encryption (PDF 1.6)
|
||||
.TP 5
|
||||
PDFIO_ENCRYPTION_AES_256
|
||||
.br
|
||||
256-bit AES encryption (PDF 2.0)
|
||||
.TP 5
|
||||
PDFIO_ENCRYPTION_NONE
|
||||
.br
|
||||
No encryption
|
||||
.TP 5
|
||||
PDFIO_ENCRYPTION_RC4_128
|
||||
.br
|
||||
128-bit RC4 encryption (PDF 1.4)
|
||||
.TP 5
|
||||
PDFIO_ENCRYPTION_RC4_40
|
||||
.br
|
||||
40-bit RC4 encryption (PDF 1.3)
|
||||
.SS pdfio_filter_e
|
||||
Compression/decompression filters for streams
|
||||
.TP 5
|
||||
@ -874,6 +926,51 @@ Miter joint
|
||||
PDFIO_LINEJOIN_ROUND
|
||||
.br
|
||||
Round joint
|
||||
.SS pdfio_permission_e
|
||||
PDF permission bits
|
||||
.TP 5
|
||||
PDFIO_PERMISSION_ALL
|
||||
.br
|
||||
.TP 5
|
||||
PDFIO_PERMISSION_ANNOTATE
|
||||
.br
|
||||
PDF allows annotation
|
||||
.TP 5
|
||||
PDFIO_PERMISSION_ASSEMBLE
|
||||
.br
|
||||
PDF allows assembly (insert, delete, or rotate pages, add document outlines and thumbnails)
|
||||
.TP 5
|
||||
PDFIO_PERMISSION_COPY
|
||||
.br
|
||||
PDF allows copying
|
||||
.TP 5
|
||||
PDFIO_PERMISSION_FORMS
|
||||
.br
|
||||
PDF allows filling in forms
|
||||
.TP 5
|
||||
PDFIO_PERMISSION_MODIFY
|
||||
.br
|
||||
PDF allows modification
|
||||
.TP 5
|
||||
PDFIO_PERMISSION_NONE
|
||||
.br
|
||||
No permissions
|
||||
.TP 5
|
||||
PDFIO_PERMISSION_PRINT
|
||||
.br
|
||||
PDF allows printing
|
||||
.TP 5
|
||||
PDFIO_PERMISSION_PRINT_HIGH
|
||||
.br
|
||||
PDF allows high quality printing
|
||||
.TP 5
|
||||
PDFIO_PERMISSION_READING
|
||||
.br
|
||||
PDF allows screen reading/accessibility (deprecated in PDF 2.0)
|
||||
.TP 5
|
||||
~0
|
||||
.br
|
||||
All permissions
|
||||
.SS pdfio_textrendering_e
|
||||
Text rendering modes
|
||||
.TP 5
|
||||
@ -1343,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
|
||||
@ -1397,9 +1502,9 @@ Set the stroke pattern.
|
||||
.nf
|
||||
bool pdfioContentSetDashPattern (
|
||||
pdfio_stream_t *st,
|
||||
int phase,
|
||||
int on,
|
||||
int off
|
||||
double phase,
|
||||
double on,
|
||||
double off
|
||||
);
|
||||
.fi
|
||||
.SS pdfioContentSetFillColorDeviceCMYK
|
||||
@ -1853,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
|
||||
@ -1995,6 +2125,20 @@ pdfio_file_t * pdfioFileCreate (
|
||||
void *error_data
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
This function creates a new PDF file. The "filename" argument specifies the
|
||||
name of the PDF file to create.
|
||||
.PP
|
||||
The "version" argument specifies the PDF version number for the file or
|
||||
\fBNULL\fR for the default ("2.0").
|
||||
.PP
|
||||
The "media_box" and "crop_box" arguments specify the default MediaBox and
|
||||
CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size
|
||||
of 8.27x11in (the intersection of US Letter and ISO A4) is used.
|
||||
.PP
|
||||
The "error_cb" and "error_data" arguments specify an error handler callback
|
||||
and its data pointer - if \fBNULL\fR the default error handler is used that
|
||||
writes error messages to \fBstderr\fR.
|
||||
.SS pdfioFileCreateArrayObj
|
||||
Create a new object in a PDF file containing an array.
|
||||
.PP
|
||||
@ -2137,6 +2281,51 @@ pdfio_obj_t * pdfioFileCreateObj (
|
||||
pdfio_dict_t *dict
|
||||
);
|
||||
.fi
|
||||
.SS pdfioFileCreateOutput
|
||||
Create a PDF file through an output callback.
|
||||
.PP
|
||||
.nf
|
||||
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
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
This function creates a new PDF file that is streamed though an output
|
||||
callback. The "output_cb" and "output_ctx" arguments specify the output
|
||||
callback and its context pointer which is called whenever data needs to be
|
||||
written:
|
||||
.PP
|
||||
.nf
|
||||
ssize_t
|
||||
output_cb(void *output_ctx, const void *buffer, size_t bytes)
|
||||
{
|
||||
// Write buffer to output and return the number of bytes written
|
||||
}
|
||||
|
||||
.fi
|
||||
The "version" argument specifies the PDF version number for the file or
|
||||
\fBNULL\fR for the default ("2.0").
|
||||
.PP
|
||||
The "media_box" and "crop_box" arguments specify the default MediaBox and
|
||||
CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size
|
||||
of 8.27x11in (the intersection of US Letter and ISO A4) is used.
|
||||
.PP
|
||||
The "error_cb" and "error_data" arguments specify an error handler callback
|
||||
and its data pointer - if \fBNULL\fR the default error handler is used that
|
||||
writes error messages to \fBstderr\fR.
|
||||
.PP
|
||||
.IP 5
|
||||
\fINote\fR: Files created using this API are slightly larger than those
|
||||
.IP 5
|
||||
created using the \fIpdfioFileCreate\fR function since stream lengths are
|
||||
.IP 5
|
||||
stored as indirect object references.
|
||||
.SS pdfioFileCreatePage
|
||||
Create a page in a PDF file.
|
||||
.PP
|
||||
@ -2146,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
|
||||
@ -2240,6 +2443,18 @@ pdfio_obj_t * pdfioFileGetPage (
|
||||
size_t n
|
||||
);
|
||||
.fi
|
||||
.SS pdfioFileGetPermissions
|
||||
Get the access permissions of a PDF file.
|
||||
.PP
|
||||
.nf
|
||||
pdfio_permission_t pdfioFileGetPermissions (
|
||||
pdfio_file_t *pdf,
|
||||
pdfio_encryption_t *encryption
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
This function returns the access permissions of a PDF file and (optionally)
|
||||
the type of encryption that has been used.
|
||||
.SS pdfioFileGetProducer
|
||||
Get the producer string for a PDF file.
|
||||
.PP
|
||||
@ -2278,10 +2493,25 @@ Open a PDF file for reading.
|
||||
.nf
|
||||
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
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
This function opens an existing PDF file. The "filename" argument specifies
|
||||
the name of the PDF file to create.
|
||||
.PP
|
||||
The "password_cb" and "password_data" arguments specify a password callback
|
||||
and its data pointer for PDF files that use one of the standard Adobe
|
||||
"security" handlers. The callback returns a password string or \fBNULL\fR to
|
||||
cancel the open. If \fBNULL\fR is specified for the callback function and the
|
||||
PDF file requires a password, the open will always fail.
|
||||
.PP
|
||||
The "error_cb" and "error_data" arguments specify an error handler callback
|
||||
and its data pointer - if \fBNULL\fR the default error handler is used that
|
||||
writes error messages to \fBstderr\fR.
|
||||
.SS pdfioFileSetAuthor
|
||||
Set the author for a PDF file.
|
||||
.PP
|
||||
@ -2318,6 +2548,30 @@ void pdfioFileSetKeywords (
|
||||
const char *value
|
||||
);
|
||||
.fi
|
||||
.SS pdfioFileSetPermissions
|
||||
Set the PDF permissions, encryption mode, and passwords.
|
||||
.PP
|
||||
.nf
|
||||
bool pdfioFileSetPermissions (
|
||||
pdfio_file_t *pdf,
|
||||
pdfio_permission_t permissions,
|
||||
pdfio_encryption_t encryption,
|
||||
const char *owner_password,
|
||||
const char *user_password
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
This function sets the PDF usage permissions, encryption mode, and
|
||||
passwords.
|
||||
.PP
|
||||
.IP 5
|
||||
\fINote\fR: This function must be called before creating or copying any
|
||||
.IP 5
|
||||
objects. Due to fundamental limitations in the PDF format, PDF encryption
|
||||
.IP 5
|
||||
offers little protection from disclosure. Permissions are not enforced in
|
||||
.IP 5
|
||||
any meaningful way.
|
||||
.SS pdfioFileSetSubject
|
||||
Set the subject for a PDF file.
|
||||
.PP
|
||||
@ -2503,6 +2757,24 @@ bool pdfioPageDictAddImage (
|
||||
pdfio_obj_t *obj
|
||||
);
|
||||
.fi
|
||||
.SS pdfioPageGetNumStreams
|
||||
Get the number of content streams for a page object.
|
||||
.PP
|
||||
.nf
|
||||
size_t pdfioPageGetNumStreams (
|
||||
pdfio_obj_t *page
|
||||
);
|
||||
.fi
|
||||
.SS pdfioPageOpenStream
|
||||
Open a content stream for a page.
|
||||
.PP
|
||||
.nf
|
||||
pdfio_stream_t * pdfioPageOpenStream (
|
||||
pdfio_obj_t *page,
|
||||
size_t n,
|
||||
bool decode
|
||||
);
|
||||
.fi
|
||||
.SS pdfioStreamClose
|
||||
Close a (data) stream in a PDF file.
|
||||
.PP
|
||||
@ -2650,12 +2922,24 @@ 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
|
||||
.nf
|
||||
typedef struct _pdfio_dict_s pdfio_dict_t;
|
||||
.fi
|
||||
.SS pdfio_encryption_t
|
||||
PDF encryption modes
|
||||
.PP
|
||||
.nf
|
||||
typedef enum pdfio_encryption_e pdfio_encryption_t;
|
||||
.fi
|
||||
.SS pdfio_error_cb_t
|
||||
Error callback
|
||||
.PP
|
||||
@ -2698,6 +2982,24 @@ Numbered object in PDF file
|
||||
.nf
|
||||
typedef struct _pdfio_obj_s pdfio_obj_t;
|
||||
.fi
|
||||
.SS pdfio_output_cb_t
|
||||
Output callback for pdfioFileCreateOutput
|
||||
.PP
|
||||
.nf
|
||||
typedef ssize_t(*)(void *ctx const void *data size_t datalen) pdfio_output_cb_t;
|
||||
.fi
|
||||
.SS pdfio_password_cb_t
|
||||
Password callback for pdfioFileOpen
|
||||
.PP
|
||||
.nf
|
||||
typedef const char *(*)(void *data const char *filename) pdfio_password_cb_t;
|
||||
.fi
|
||||
.SS pdfio_permission_t
|
||||
PDF permission bitfield
|
||||
.PP
|
||||
.nf
|
||||
typedef int pdfio_permission_t;
|
||||
.fi
|
||||
.SS pdfio_rect_t
|
||||
PDF rectangle
|
||||
.PP
|
||||
@ -2722,9 +3024,15 @@ PDF value types
|
||||
.nf
|
||||
typedef enum pdfio_valtype_e pdfio_valtype_t;
|
||||
.fi
|
||||
.SS state_t[4][4]
|
||||
4x4 AES state table
|
||||
.PP
|
||||
.nf
|
||||
typedef uint8_t state_t[4][4];
|
||||
.fi
|
||||
.SH AUTHOR
|
||||
.PP
|
||||
Michael R Sweet
|
||||
.SH COPYRIGHT
|
||||
.PP
|
||||
Copyright (c) 2021 by Michael R Sweet
|
||||
Copyright (c) 2021-2022 by Michael R Sweet
|
||||
|
341
doc/pdfio.html
341
doc/pdfio.html
@ -1,13 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<title>PDFio Programming Manual v1.0b1</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 by Michael R Sweet">
|
||||
<meta name="version" content="1.0b1">
|
||||
<meta name="copyright" content="Copyright © 2021-2022 by Michael R Sweet">
|
||||
<meta name="version" content="1.1">
|
||||
<style type="text/css"><!--
|
||||
body {
|
||||
background: white;
|
||||
@ -245,9 +245,9 @@ span.string {
|
||||
<body>
|
||||
<div class="header">
|
||||
<p><img class="title" src="pdfio-512.png"></p>
|
||||
<h1 class="title">PDFio Programming Manual v1.0b1</h1>
|
||||
<h1 class="title">PDFio Programming Manual v1.1</h1>
|
||||
<p>Michael R Sweet</p>
|
||||
<p>Copyright © 2021 by Michael R Sweet</p>
|
||||
<p>Copyright © 2021-2022 by Michael R Sweet</p>
|
||||
</div>
|
||||
<div class="contents">
|
||||
<h2 class="title">Contents</h2>
|
||||
@ -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>
|
||||
@ -381,7 +383,9 @@ span.string {
|
||||
<li><a href="#pdfioFileCreateImageObjFromData">pdfioFileCreateImageObjFromData</a></li>
|
||||
<li><a href="#pdfioFileCreateImageObjFromFile">pdfioFileCreateImageObjFromFile</a></li>
|
||||
<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>
|
||||
@ -393,6 +397,7 @@ span.string {
|
||||
<li><a href="#pdfioFileGetNumPages">pdfioFileGetNumPages</a></li>
|
||||
<li><a href="#pdfioFileGetObj">pdfioFileGetObj</a></li>
|
||||
<li><a href="#pdfioFileGetPage">pdfioFileGetPage</a></li>
|
||||
<li><a href="#pdfioFileGetPermissions">pdfioFileGetPermissions</a></li>
|
||||
<li><a href="#pdfioFileGetProducer">pdfioFileGetProducer</a></li>
|
||||
<li><a href="#pdfioFileGetSubject">pdfioFileGetSubject</a></li>
|
||||
<li><a href="#pdfioFileGetTitle">pdfioFileGetTitle</a></li>
|
||||
@ -402,6 +407,7 @@ span.string {
|
||||
<li><a href="#pdfioFileSetCreationDate">pdfioFileSetCreationDate</a></li>
|
||||
<li><a href="#pdfioFileSetCreator">pdfioFileSetCreator</a></li>
|
||||
<li><a href="#pdfioFileSetKeywords">pdfioFileSetKeywords</a></li>
|
||||
<li><a href="#pdfioFileSetPermissions">pdfioFileSetPermissions</a></li>
|
||||
<li><a href="#pdfioFileSetSubject">pdfioFileSetSubject</a></li>
|
||||
<li><a href="#pdfioFileSetTitle">pdfioFileSetTitle</a></li>
|
||||
<li><a href="#pdfioImageGetBytesPerLine">pdfioImageGetBytesPerLine</a></li>
|
||||
@ -422,6 +428,8 @@ span.string {
|
||||
<li><a href="#pdfioPageDictAddColorSpace">pdfioPageDictAddColorSpace</a></li>
|
||||
<li><a href="#pdfioPageDictAddFont">pdfioPageDictAddFont</a></li>
|
||||
<li><a href="#pdfioPageDictAddImage">pdfioPageDictAddImage</a></li>
|
||||
<li><a href="#pdfioPageGetNumStreams">pdfioPageGetNumStreams</a></li>
|
||||
<li><a href="#pdfioPageOpenStream">pdfioPageOpenStream</a></li>
|
||||
<li><a href="#pdfioStreamClose">pdfioStreamClose</a></li>
|
||||
<li><a href="#pdfioStreamConsume">pdfioStreamConsume</a></li>
|
||||
<li><a href="#pdfioStreamGetToken">pdfioStreamGetToken</a></li>
|
||||
@ -437,7 +445,9 @@ 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>
|
||||
<li><a href="#pdfio_file_t">pdfio_file_t</a></li>
|
||||
<li><a href="#pdfio_filter_t">pdfio_filter_t</a></li>
|
||||
@ -445,19 +455,25 @@ span.string {
|
||||
<li><a href="#pdfio_linejoin_t">pdfio_linejoin_t</a></li>
|
||||
<li><a href="#pdfio_matrix_t[3][2]">pdfio_matrix_t[3][2]</a></li>
|
||||
<li><a href="#pdfio_obj_t">pdfio_obj_t</a></li>
|
||||
<li><a href="#pdfio_output_cb_t">pdfio_output_cb_t</a></li>
|
||||
<li><a href="#pdfio_password_cb_t">pdfio_password_cb_t</a></li>
|
||||
<li><a href="#pdfio_permission_t">pdfio_permission_t</a></li>
|
||||
<li><a href="#pdfio_rect_t">pdfio_rect_t</a></li>
|
||||
<li><a href="#pdfio_stream_t">pdfio_stream_t</a></li>
|
||||
<li><a href="#pdfio_textrendering_t">pdfio_textrendering_t</a></li>
|
||||
<li><a href="#pdfio_valtype_t">pdfio_valtype_t</a></li>
|
||||
<li><a href="#state_t[4][4]">state_t[4][4]</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#STRUCTURES">Structures</a><ul class="subcontents">
|
||||
<li><a href="#pdfio_rect_s">pdfio_rect_s</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#ENUMERATIONS">Enumerations</a><ul class="subcontents">
|
||||
<li><a href="#pdfio_cs_e">pdfio_cs_e</a></li>
|
||||
<li><a href="#pdfio_encryption_e">pdfio_encryption_e</a></li>
|
||||
<li><a href="#pdfio_filter_e">pdfio_filter_e</a></li>
|
||||
<li><a href="#pdfio_linecap_e">pdfio_linecap_e</a></li>
|
||||
<li><a href="#pdfio_linejoin_e">pdfio_linejoin_e</a></li>
|
||||
<li><a href="#pdfio_permission_e">pdfio_permission_e</a></li>
|
||||
<li><a href="#pdfio_textrendering_e">pdfio_textrendering_e</a></li>
|
||||
<li><a href="#pdfio_valtype_e">pdfio_valtype_e</a></li>
|
||||
</ul></li>
|
||||
@ -467,9 +483,11 @@ span.string {
|
||||
<h2 class="title" id="introduction">Introduction</h2>
|
||||
<p>PDFio is a simple C library for reading and writing PDF files. The primary goals of pdfio are:</p>
|
||||
<ul>
|
||||
<li><p>Read any PDF file with or without encryption or linearization</p>
|
||||
<li><p>Read and write any version of PDF file</p>
|
||||
</li>
|
||||
<li><p>Write PDF files without encryption or linearization</p>
|
||||
<li><p>Provide access to pages, objects, and streams within a PDF file</p>
|
||||
</li>
|
||||
<li><p>Support reading and writing of encrypted PDF files</p>
|
||||
</li>
|
||||
<li><p>Extract or embed useful metadata (author, creator, page information, etc.)</p>
|
||||
</li>
|
||||
@ -479,7 +497,7 @@ span.string {
|
||||
</li>
|
||||
</ul>
|
||||
<p>PDFio is <em>not</em> concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.</p>
|
||||
<p>PDFio is Copyright © 2021 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.</p>
|
||||
<p>PDFio is Copyright © 2021-2022 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.</p>
|
||||
<h3 class="title" id="requirements">Requirements</h3>
|
||||
<p>PDFio requires the following to build the software:</p>
|
||||
<ul>
|
||||
@ -545,19 +563,19 @@ make install-shared
|
||||
<pre><code>sudo xcodebuild install
|
||||
</code></pre>
|
||||
<p>You can reproduce this with the makefile using:</p>
|
||||
<pre><code>sudo make 'COMMONFLAGS="-Os -mmacosx-version-min=10.14 -arch x86_64 -arch arm64"' install
|
||||
<pre><code>sudo make macos install
|
||||
</code></pre>
|
||||
<h3 class="title" id="detecting-pdfio">Detecting PDFio</h3>
|
||||
<p>PDFio can be detected using the <code>pkg-config</code> command, for example:</p>
|
||||
<pre><code>if pkg-config --exists pdfio; then
|
||||
...
|
||||
...
|
||||
fi
|
||||
</code></pre>
|
||||
<p>In a makefile you can add the necessary compiler and linker options with:</p>
|
||||
<pre><code class="language-make">CFLAGS += `pkg-config --cflags pdfio`
|
||||
LIBS += `pkg-config --libs pdfio`
|
||||
</code></pre>
|
||||
<p>On Windows, you need to link to the <code>PDFIO.LIB</code> (static) or <code>PDFIO1.LIB</code> (DLL) libraries and include the "zlib" NuGet package dependency.</p>
|
||||
<p>On Windows, you need to link to the <code>PDFIO1.LIB</code> (DLL) library and include the <code>zlib_native</code> NuGet package dependency. You can also use the published <code>pdfio_native</code> NuGet package.</p>
|
||||
<h3 class="title" id="header-files">Header Files</h3>
|
||||
<p>PDFio provides a primary header file that is always used:</p>
|
||||
<pre><code class="language-c"><span class="directive">#include <pdfio.h></span>
|
||||
@ -609,7 +627,7 @@ pdfio_obj_t *page; <span class="comment">// Current page</span>
|
||||
<span class="comment">// do something with page</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>Each page is represented by a "page tree" object (what <a href="#pdfioFileGetPage"><code>pdfioFileGetPage</code></a> returns) that specifies information about the page and one or more "content" objects that contain the images, fonts, text, and graphics that appear on the page.</p>
|
||||
<p>Each page is represented by a "page tree" object (what <a href="#pdfioFileGetPage"><code>pdfioFileGetPage</code></a> returns) that specifies information about the page and one or more "content" objects that contain the images, fonts, text, and graphics that appear on the page. Use the <a href="#pdfioPageGetNumStreams"><code>pdfioPageGetNumStreams</code></a> and <a href="#pdfioPageOpenStream"><code>pdfioPageOpenStream</code></a> functions to access the content streams for each page.</p>
|
||||
<p>The <a href="#pdfioFileClose"><code>pdfioFileClose</code></a> function closes a PDF file and frees all memory that was used for it:</p>
|
||||
<pre><code class="language-c">pdfioFileClose(pdf);
|
||||
</code></pre>
|
||||
@ -621,6 +639,12 @@ pdfio_rect_t crop_box = { <span class="number">36.0</span>, <span class="number"
|
||||
pdfio_file_t *pdf = pdfioFileCreate(<span class="string">"myoutputfile.pdf"</span>, <span class="string">"2.0"</span>, &media_box, &crop_box, error_cb, error_data);
|
||||
</code></pre>
|
||||
<p>where the six arguments to the function are the filename ("myoutputfile.pdf"), PDF version ("2.0"), media box (<code>media_box</code>), crop box (<code>crop_box</code>), an optional error callback function (<code>error_cb</code>), and an optional pointer value for the error callback function (<code>error_data</code>). The units for the media and crop boxes are points (1/72nd of an inch).</p>
|
||||
<p>Alternately you can stream a PDF file using the <a href="#pdfioFileCreateOutput"><code>pdfioFileCreateOutput</code></a> function:</p>
|
||||
<pre><code class="language-c">pdfio_rect_t media_box = { <span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">612.0</span>, <span class="number">792.0</span> }; <span class="comment">// US Letter</span>
|
||||
pdfio_rect_t crop_box = { <span class="number">36.0</span>, <span class="number">36.0</span>, <span class="number">576.0</span>, <span class="number">756.0</span> }; <span class="comment">// w/0.5" margins</span>
|
||||
|
||||
pdfio_file_t *pdf = pdfioFileCreateOutput(output_cb, output_ctx, <span class="string">"2.0"</span>, &media_box, &crop_box, error_cb, error_data);
|
||||
</code></pre>
|
||||
<p>Once the file is created, use the <a href="#pdfioFileCreateObj"><code>pdfioFileCreateObj</code></a>, <a href="#pdfioFileCreatePage"><code>pdfioFileCreatePage</code></a>, and <a href="#pdfioPageCopy"><code>pdfioPageCopy</code></a> functions to create objects and pages in the file.</p>
|
||||
<p>Finally, the <a href="#pdfioFileClose"><code>pdfioFileClose</code></a> function writes the PDF cross-reference and "trailer" information, closes the file, and frees all memory that was used for it.</p>
|
||||
<h3 class="title" id="pdf-objects">PDF Objects</h3>
|
||||
@ -645,6 +669,11 @@ pdfio_obj_t *obj = pdfioFileFindObj(pdf, number);
|
||||
pdfio_stream_t *st = pdfioObjOpenStream(obj, <span class="reserved">true</span>);
|
||||
</code></pre>
|
||||
<p>The first argument is the object pointer. The second argument is a boolean value that specifies whether you want to decode (typically decompress) the stream data or return it as-is.</p>
|
||||
<p>When reading a page stream you'll use the <a href="#pdfioPageOpenStream"><code>pdfioPageOpenStream</code></a> function instead:</p>
|
||||
<pre><code class="language-c">pdfio_file_t *pdf = pdfioFileOpen(...);
|
||||
pdfio_obj_t *obj = pdfioFileGetPage(pdf, number);
|
||||
pdfio_stream_t *st = pdfioPageOpenStream(obj, <span class="number">0</span>, <span class="reserved">true</span>);
|
||||
</code></pre>
|
||||
<p>Once you have the stream open, you can use one of several functions to read from it:</p>
|
||||
<ul>
|
||||
<li><p><a href="#pdfioStreamConsume"><code>pdfioStreamConsume</code></a> reads and discards a number of bytes in the stream</p>
|
||||
@ -661,10 +690,16 @@ pdfio_stream_t *st = pdfioObjOpenStream(obj, <span class="reserved">true</span>)
|
||||
</code></pre>
|
||||
<p>To create a stream for a new object, call the <a href="#pdfioObjCreateStream"><code>pdfioObjCreateStream</code></a> function:</p>
|
||||
<pre><code class="language-c">pdfio_file_t *pdf = pdfioFileCreate(...);
|
||||
pdfio_obj_t *pdfioFileCreateObj(pdf, ...);
|
||||
pdfio_stream_t *pdfioObjCreateStream(obj, PDFIO_FILTER_FLATE);
|
||||
pdfio_obj_t *obj = pdfioFileCreateObj(pdf, ...);
|
||||
pdfio_stream_t *st = pdfioObjCreateStream(obj, PDFIO_FILTER_FLATE);
|
||||
</code></pre>
|
||||
<p>The first argument is the newly created object. The second argument is either <code>PDFIO_FILTER_NONE</code> to specify that any encoding is done by your program or <code>PDFIO_FILTER_FLATE</code> to specify that PDFio should Flate compress the stream.</p>
|
||||
<p>To create a page content stream call the <a href="#pdfioFileCreatePage"><code>pdfioFileCreatePage</code></a> function:</p>
|
||||
<pre><code class="language-c">pdfio_file_t *pdf = pdfioFileCreate(...);
|
||||
pdfio_dict_t *dict = pdfioDictCreate(pdf);
|
||||
... set page dictionary keys <span class="reserved">and</span> values ...
|
||||
pdfio_stream_t *st = pdfioFileCreatePage(pdf, dict);
|
||||
</code></pre>
|
||||
<p>Once you have created the stream, use any of the following functions to write to the stream:</p>
|
||||
<ul>
|
||||
<li><p><a href="#pdfioStreamPrintf"><code>pdfioStreamPrintf</code></a> writes a formatted string to the stream</p>
|
||||
@ -1480,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">
|
||||
@ -1554,7 +1600,7 @@ bool pdfioContentSave(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);</p>
|
||||
<h3 class="function"><a id="pdfioContentSetDashPattern">pdfioContentSetDashPattern</a></h3>
|
||||
<p class="description">Set the stroke pattern.</p>
|
||||
<p class="code">
|
||||
bool pdfioContentSetDashPattern(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, int phase, int on, int off);</p>
|
||||
bool pdfioContentSetDashPattern(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, double phase, double on, double off);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>st</th>
|
||||
@ -2230,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">
|
||||
@ -2444,6 +2517,20 @@ bool pdfioFileClose(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf);</p>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">PDF file or <code>NULL</code> on error</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function creates a new PDF file. The "filename" argument specifies the
|
||||
name of the PDF file to create.<br>
|
||||
<br>
|
||||
The "version" argument specifies the PDF version number for the file or
|
||||
<code>NULL</code> for the default ("2.0").<br>
|
||||
<br>
|
||||
The "media_box" and "crop_box" arguments specify the default MediaBox and
|
||||
CropBox for pages in the PDF file - if <code>NULL</code> then a default "Universal" size
|
||||
of 8.27x11in (the intersection of US Letter and ISO A4) is used.<br>
|
||||
<br>
|
||||
The "error_cb" and "error_data" arguments specify an error handler callback
|
||||
and its data pointer - if <code>NULL</code> the default error handler is used that
|
||||
writes error messages to <code>stderr</code>.</p>
|
||||
<h3 class="function"><a id="pdfioFileCreateArrayObj">pdfioFileCreateArrayObj</a></h3>
|
||||
<p class="description">Create a new object in a PDF file containing an array.</p>
|
||||
<p class="code">
|
||||
@ -2621,6 +2708,57 @@ is supported.</blockquote>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">New object</p>
|
||||
<h3 class="function"><a id="pdfioFileCreateOutput">pdfioFileCreateOutput</a></h3>
|
||||
<p class="description">Create a PDF file through an output callback.</p>
|
||||
<p class="code">
|
||||
<a href="#pdfio_file_t">pdfio_file_t</a> *pdfioFileCreateOutput(<a href="#pdfio_output_cb_t">pdfio_output_cb_t</a> output_cb, void *output_ctx, 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>output_cb</th>
|
||||
<td class="description">Output callback</td></tr>
|
||||
<tr><th>output_ctx</th>
|
||||
<td class="description">Output context</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">PDF file or <code>NULL</code> on error</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function creates a new PDF file that is streamed though an output
|
||||
callback. The "output_cb" and "output_ctx" arguments specify the output
|
||||
callback and its context pointer which is called whenever data needs to be
|
||||
written:
|
||||
|
||||
<pre>
|
||||
ssize_t
|
||||
output_cb(void *output_ctx, const void *buffer, size_t bytes)
|
||||
{
|
||||
// Write buffer to output and return the number of bytes written
|
||||
}
|
||||
</pre>
|
||||
The "version" argument specifies the PDF version number for the file or
|
||||
<code>NULL</code> for the default ("2.0").<br>
|
||||
<br>
|
||||
The "media_box" and "crop_box" arguments specify the default MediaBox and
|
||||
CropBox for pages in the PDF file - if <code>NULL</code> then a default "Universal" size
|
||||
of 8.27x11in (the intersection of US Letter and ISO A4) is used.<br>
|
||||
<br>
|
||||
The "error_cb" and "error_data" arguments specify an error handler callback
|
||||
and its data pointer - if <code>NULL</code> the default error handler is used that
|
||||
writes error messages to <code>stderr</code>.<br>
|
||||
<br>
|
||||
</p><blockquote>
|
||||
<em>Note</em>: Files created using this API are slightly larger than those
|
||||
created using the <a href="#pdfioFileCreate"><code>pdfioFileCreate</code></a> function since stream lengths are
|
||||
stored as indirect object references.</blockquote>
|
||||
<h3 class="function"><a id="pdfioFileCreatePage">pdfioFileCreatePage</a></h3>
|
||||
<p class="description">Create a page in a PDF file.</p>
|
||||
<p class="code">
|
||||
@ -2634,6 +2772,35 @@ is supported.</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">
|
||||
@ -2764,6 +2931,22 @@ size_t pdfioFileGetNumPages(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf);</p>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Object</p>
|
||||
<h3 class="function"><a id="pdfioFileGetPermissions">pdfioFileGetPermissions</a></h3>
|
||||
<p class="description">Get the access permissions of a PDF file.</p>
|
||||
<p class="code">
|
||||
<a href="#pdfio_permission_t">pdfio_permission_t</a> pdfioFileGetPermissions(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <a href="#pdfio_encryption_t">pdfio_encryption_t</a> *encryption);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>pdf</th>
|
||||
<td class="description">PDF file</td></tr>
|
||||
<tr><th>encryption</th>
|
||||
<td class="description">Type of encryption used or <code>NULL</code> to ignore</td></tr>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Permission bits</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function returns the access permissions of a PDF file and (optionally)
|
||||
the type of encryption that has been used.</p>
|
||||
<h3 class="function"><a id="pdfioFileGetProducer">pdfioFileGetProducer</a></h3>
|
||||
<p class="description">Get the producer string for a PDF file.</p>
|
||||
<p class="code">
|
||||
@ -2811,11 +2994,15 @@ const char *pdfioFileGetVersion(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf);<
|
||||
<h3 class="function"><a id="pdfioFileOpen">pdfioFileOpen</a></h3>
|
||||
<p class="description">Open a PDF file for reading.</p>
|
||||
<p class="code">
|
||||
<a href="#pdfio_file_t">pdfio_file_t</a> *pdfioFileOpen(const char *filename, <a href="#pdfio_error_cb_t">pdfio_error_cb_t</a> error_cb, void *error_data);</p>
|
||||
<a href="#pdfio_file_t">pdfio_file_t</a> *pdfioFileOpen(const char *filename, <a href="#pdfio_password_cb_t">pdfio_password_cb_t</a> password_cb, void *password_data, <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>filename</th>
|
||||
<td class="description">Filename</td></tr>
|
||||
<tr><th>password_cb</th>
|
||||
<td class="description">Password callback or <code>NULL</code> for none</td></tr>
|
||||
<tr><th>password_data</th>
|
||||
<td class="description">Password callback data, if any</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>
|
||||
@ -2823,6 +3010,19 @@ const char *pdfioFileGetVersion(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf);<
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">PDF file</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function opens an existing PDF file. The "filename" argument specifies
|
||||
the name of the PDF file to create.<br>
|
||||
<br>
|
||||
The "password_cb" and "password_data" arguments specify a password callback
|
||||
and its data pointer for PDF files that use one of the standard Adobe
|
||||
"security" handlers. The callback returns a password string or <code>NULL</code> to
|
||||
cancel the open. If <code>NULL</code> is specified for the callback function and the
|
||||
PDF file requires a password, the open will always fail.<br>
|
||||
<br>
|
||||
The "error_cb" and "error_data" arguments specify an error handler callback
|
||||
and its data pointer - if <code>NULL</code> the default error handler is used that
|
||||
writes error messages to <code>stderr</code>.</p>
|
||||
<h3 class="function"><a id="pdfioFileSetAuthor">pdfioFileSetAuthor</a></h3>
|
||||
<p class="description">Set the author for a PDF file.</p>
|
||||
<p class="code">
|
||||
@ -2867,6 +3067,34 @@ void pdfioFileSetKeywords(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, const c
|
||||
<tr><th>value</th>
|
||||
<td class="description">Value</td></tr>
|
||||
</tbody></table>
|
||||
<h3 class="function"><a id="pdfioFileSetPermissions">pdfioFileSetPermissions</a></h3>
|
||||
<p class="description">Set the PDF permissions, encryption mode, and passwords.</p>
|
||||
<p class="code">
|
||||
bool pdfioFileSetPermissions(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <a href="#pdfio_permission_t">pdfio_permission_t</a> permissions, <a href="#pdfio_encryption_t">pdfio_encryption_t</a> encryption, const char *owner_password, const char *user_password);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>pdf</th>
|
||||
<td class="description">PDF file</td></tr>
|
||||
<tr><th>permissions</th>
|
||||
<td class="description">Use permissions</td></tr>
|
||||
<tr><th>encryption</th>
|
||||
<td class="description">Type of encryption to use</td></tr>
|
||||
<tr><th>owner_password</th>
|
||||
<td class="description">Owner password, if any</td></tr>
|
||||
<tr><th>user_password</th>
|
||||
<td class="description">User password, if any</td></tr>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description"><code>true</code> on success, <code>false</code> otherwise</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function sets the PDF usage permissions, encryption mode, and
|
||||
passwords.<br>
|
||||
<br>
|
||||
</p><blockquote>
|
||||
<em>Note</em>: This function must be called before creating or copying any
|
||||
objects. Due to fundamental limitations in the PDF format, PDF encryption
|
||||
offers little protection from disclosure. Permissions are not enforced in
|
||||
any meaningful way.</blockquote>
|
||||
<h3 class="function"><a id="pdfioFileSetSubject">pdfioFileSetSubject</a></h3>
|
||||
<p class="description">Set the subject for a PDF file.</p>
|
||||
<p class="code">
|
||||
@ -3120,6 +3348,32 @@ bool pdfioPageDictAddImage(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, const
|
||||
</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="pdfioPageGetNumStreams">pdfioPageGetNumStreams</a></h3>
|
||||
<p class="description">Get the number of content streams for a page object.</p>
|
||||
<p class="code">
|
||||
size_t pdfioPageGetNumStreams(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>page</th>
|
||||
<td class="description">Page object</td></tr>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Number of streams</p>
|
||||
<h3 class="function"><a id="pdfioPageOpenStream">pdfioPageOpenStream</a></h3>
|
||||
<p class="description">Open a content stream for a page.</p>
|
||||
<p class="code">
|
||||
<a href="#pdfio_stream_t">pdfio_stream_t</a> *pdfioPageOpenStream(<a href="#pdfio_obj_t">pdfio_obj_t</a> *page, size_t n, bool decode);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>page</th>
|
||||
<td class="description">Page object</td></tr>
|
||||
<tr><th>n</th>
|
||||
<td class="description">Stream index (0-based)</td></tr>
|
||||
<tr><th>decode</th>
|
||||
<td class="description"><code>true</code> to decode/decompress stream</td></tr>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Stream</p>
|
||||
<h3 class="function"><a id="pdfioStreamClose">pdfioStreamClose</a></h3>
|
||||
<p class="description">Close a (data) stream in a PDF file.</p>
|
||||
<p class="code">
|
||||
@ -3301,11 +3555,21 @@ 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">
|
||||
typedef struct _pdfio_dict_s pdfio_dict_t;
|
||||
</p>
|
||||
<h3 class="typedef"><a id="pdfio_encryption_t">pdfio_encryption_t</a></h3>
|
||||
<p class="description">PDF encryption modes</p>
|
||||
<p class="code">
|
||||
typedef enum <a href="#pdfio_encryption_e">pdfio_encryption_e</a> pdfio_encryption_t;
|
||||
</p>
|
||||
<h3 class="typedef"><a id="pdfio_error_cb_t">pdfio_error_cb_t</a></h3>
|
||||
<p class="description">Error callback</p>
|
||||
<p class="code">
|
||||
@ -3341,6 +3605,21 @@ typedef double pdfio_matrix_t[3][2];
|
||||
<p class="code">
|
||||
typedef struct _pdfio_obj_s pdfio_obj_t;
|
||||
</p>
|
||||
<h3 class="typedef"><a id="pdfio_output_cb_t">pdfio_output_cb_t</a></h3>
|
||||
<p class="description">Output callback for pdfioFileCreateOutput</p>
|
||||
<p class="code">
|
||||
typedef ssize_t (*pdfio_output_cb_t)(void *ctx const void *data size_t datalen);
|
||||
</p>
|
||||
<h3 class="typedef"><a id="pdfio_password_cb_t">pdfio_password_cb_t</a></h3>
|
||||
<p class="description">Password callback for pdfioFileOpen</p>
|
||||
<p class="code">
|
||||
typedef const char *(*pdfio_password_cb_t)(void *data const char *filename);
|
||||
</p>
|
||||
<h3 class="typedef"><a id="pdfio_permission_t">pdfio_permission_t</a></h3>
|
||||
<p class="description">PDF permission bitfield</p>
|
||||
<p class="code">
|
||||
typedef int pdfio_permission_t;
|
||||
</p>
|
||||
<h3 class="typedef"><a id="pdfio_rect_t">pdfio_rect_t</a></h3>
|
||||
<p class="description">PDF rectangle</p>
|
||||
<p class="code">
|
||||
@ -3361,6 +3640,11 @@ typedef enum <a href="#pdfio_textrendering_e">pdfio_textrendering_e</a> pdfio_te
|
||||
<p class="code">
|
||||
typedef enum <a href="#pdfio_valtype_e">pdfio_valtype_e</a> pdfio_valtype_t;
|
||||
</p>
|
||||
<h3 class="typedef"><a id="state_t[4][4]">state_t[4][4]</a></h3>
|
||||
<p class="description">4x4 AES state table</p>
|
||||
<p class="code">
|
||||
typedef uint8_t state_t[4][4];
|
||||
</p>
|
||||
<h2 class="title"><a id="STRUCTURES">Structures</a></h2>
|
||||
<h3 class="struct"><a id="pdfio_rect_s">pdfio_rect_s</a></h3>
|
||||
<p class="description">PDF rectangle</p>
|
||||
@ -3390,6 +3674,16 @@ typedef enum <a href="#pdfio_valtype_e">pdfio_valtype_e</a> pdfio_valtype_t;
|
||||
<tr><th>PDFIO_CS_P3_D65 </th><td class="description">Display P3</td></tr>
|
||||
<tr><th>PDFIO_CS_SRGB </th><td class="description">sRGB</td></tr>
|
||||
</tbody></table>
|
||||
<h3 class="enumeration"><a id="pdfio_encryption_e">pdfio_encryption_e</a></h3>
|
||||
<p class="description">PDF encryption modes</p>
|
||||
<h4 class="constants">Constants</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>PDFIO_ENCRYPTION_AES_128 </th><td class="description">128-bit AES encryption (PDF 1.6)</td></tr>
|
||||
<tr><th>PDFIO_ENCRYPTION_AES_256 </th><td class="description">256-bit AES encryption (PDF 2.0)</td></tr>
|
||||
<tr><th>PDFIO_ENCRYPTION_NONE </th><td class="description">No encryption</td></tr>
|
||||
<tr><th>PDFIO_ENCRYPTION_RC4_128 </th><td class="description">128-bit RC4 encryption (PDF 1.4)</td></tr>
|
||||
<tr><th>PDFIO_ENCRYPTION_RC4_40 </th><td class="description">40-bit RC4 encryption (PDF 1.3)</td></tr>
|
||||
</tbody></table>
|
||||
<h3 class="enumeration"><a id="pdfio_filter_e">pdfio_filter_e</a></h3>
|
||||
<p class="description">Compression/decompression filters for streams</p>
|
||||
<h4 class="constants">Constants</h4>
|
||||
@ -3422,6 +3716,21 @@ typedef enum <a href="#pdfio_valtype_e">pdfio_valtype_e</a> pdfio_valtype_t;
|
||||
<tr><th>PDFIO_LINEJOIN_MITER </th><td class="description">Miter joint</td></tr>
|
||||
<tr><th>PDFIO_LINEJOIN_ROUND </th><td class="description">Round joint</td></tr>
|
||||
</tbody></table>
|
||||
<h3 class="enumeration"><a id="pdfio_permission_e">pdfio_permission_e</a></h3>
|
||||
<p class="description">PDF permission bits</p>
|
||||
<h4 class="constants">Constants</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>PDFIO_PERMISSION_ANNOTATE </th><td class="description">PDF allows annotation</td></tr>
|
||||
<tr><th>PDFIO_PERMISSION_ASSEMBLE </th><td class="description">PDF allows assembly (insert, delete, or rotate pages, add document outlines and thumbnails)</td></tr>
|
||||
<tr><th>PDFIO_PERMISSION_COPY </th><td class="description">PDF allows copying</td></tr>
|
||||
<tr><th>PDFIO_PERMISSION_FORMS </th><td class="description">PDF allows filling in forms</td></tr>
|
||||
<tr><th>PDFIO_PERMISSION_MODIFY </th><td class="description">PDF allows modification</td></tr>
|
||||
<tr><th>PDFIO_PERMISSION_NONE </th><td class="description">No permissions</td></tr>
|
||||
<tr><th>PDFIO_PERMISSION_PRINT </th><td class="description">PDF allows printing</td></tr>
|
||||
<tr><th>PDFIO_PERMISSION_PRINT_HIGH </th><td class="description">PDF allows high quality printing</td></tr>
|
||||
<tr><th>PDFIO_PERMISSION_READING </th><td class="description">PDF allows screen reading/accessibility (deprecated in PDF 2.0)</td></tr>
|
||||
<tr><th>~0 </th><td class="description">All permissions</td></tr>
|
||||
</tbody></table>
|
||||
<h3 class="enumeration"><a id="pdfio_textrendering_e">pdfio_textrendering_e</a></h3>
|
||||
<p class="description">Text rendering modes</p>
|
||||
<h4 class="constants">Constants</h4>
|
||||
|
53
doc/pdfio.md
53
doc/pdfio.md
@ -4,8 +4,9 @@ Introduction
|
||||
PDFio is a simple C library for reading and writing PDF files. The primary
|
||||
goals of pdfio are:
|
||||
|
||||
- Read any PDF file with or without encryption or linearization
|
||||
- Write PDF files without encryption or linearization
|
||||
- Read and write any version of PDF file
|
||||
- Provide access to pages, objects, and streams within a PDF file
|
||||
- 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
|
||||
@ -14,8 +15,8 @@ goals of pdfio are:
|
||||
PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF
|
||||
RIP or viewer could be written using it.
|
||||
|
||||
PDFio is Copyright © 2021 by Michael R Sweet and is licensed under the Apache
|
||||
License Version 2.0 with an (optional) exception to allow linking against
|
||||
PDFio is Copyright © 2021-2022 by Michael R Sweet and is licensed under the
|
||||
Apache License Version 2.0 with an (optional) exception to allow linking against
|
||||
GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
||||
|
||||
|
||||
@ -103,7 +104,7 @@ 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
|
||||
|
||||
|
||||
Detecting PDFio
|
||||
@ -112,7 +113,7 @@ Detecting PDFio
|
||||
PDFio can be detected using the `pkg-config` command, for example:
|
||||
|
||||
if pkg-config --exists pdfio; then
|
||||
...
|
||||
...
|
||||
fi
|
||||
|
||||
In a makefile you can add the necessary compiler and linker options with:
|
||||
@ -122,8 +123,9 @@ CFLAGS += `pkg-config --cflags pdfio`
|
||||
LIBS += `pkg-config --libs pdfio`
|
||||
```
|
||||
|
||||
On Windows, you need to link to the `PDFIO.LIB` (static) or `PDFIO1.LIB` (DLL)
|
||||
libraries and include the "zlib" NuGet package dependency.
|
||||
On Windows, you need to link to the `PDFIO1.LIB` (DLL) library and include the
|
||||
`zlib_native` NuGet package dependency. You can also use the published
|
||||
`pdfio_native` NuGet package.
|
||||
|
||||
|
||||
Header Files
|
||||
@ -207,7 +209,8 @@ for (i = 0, count = pdfioFileGetNumPages(pdf); i < count; i ++)
|
||||
Each page is represented by a "page tree" object (what [`pdfioFileGetPage`](@@)
|
||||
returns) that specifies information about the page and one or more "content"
|
||||
objects that contain the images, fonts, text, and graphics that appear on the
|
||||
page.
|
||||
page. Use the [`pdfioPageGetNumStreams`](@@) and [`pdfioPageOpenStream`](@@)
|
||||
functions to access the content streams for each page.
|
||||
|
||||
The [`pdfioFileClose`](@@) function closes a PDF file and frees all memory that
|
||||
was used for it:
|
||||
@ -235,6 +238,16 @@ error callback function (`error_cb`), and an optional pointer value for the
|
||||
error callback function (`error_data`). The units for the media and crop boxes
|
||||
are points (1/72nd of an inch).
|
||||
|
||||
Alternately you can stream a PDF file using the [`pdfioFileCreateOutput`](@@)
|
||||
function:
|
||||
|
||||
```c
|
||||
pdfio_rect_t media_box = { 0.0, 0.0, 612.0, 792.0 }; // US Letter
|
||||
pdfio_rect_t crop_box = { 36.0, 36.0, 576.0, 756.0 }; // w/0.5" margins
|
||||
|
||||
pdfio_file_t *pdf = pdfioFileCreateOutput(output_cb, output_ctx, "2.0", &media_box, &crop_box, error_cb, error_data);
|
||||
```
|
||||
|
||||
Once the file is created, use the [`pdfioFileCreateObj`](@@),
|
||||
[`pdfioFileCreatePage`](@@), and [`pdfioPageCopy`](@@) functions to create
|
||||
objects and pages in the file.
|
||||
@ -282,6 +295,15 @@ The first argument is the object pointer. The second argument is a boolean
|
||||
value that specifies whether you want to decode (typically decompress) the
|
||||
stream data or return it as-is.
|
||||
|
||||
When reading a page stream you'll use the [`pdfioPageOpenStream`](@@) function
|
||||
instead:
|
||||
|
||||
```c
|
||||
pdfio_file_t *pdf = pdfioFileOpen(...);
|
||||
pdfio_obj_t *obj = pdfioFileGetPage(pdf, number);
|
||||
pdfio_stream_t *st = pdfioPageOpenStream(obj, 0, true);
|
||||
```
|
||||
|
||||
Once you have the stream open, you can use one of several functions to read
|
||||
from it:
|
||||
|
||||
@ -303,14 +325,23 @@ function:
|
||||
|
||||
```c
|
||||
pdfio_file_t *pdf = pdfioFileCreate(...);
|
||||
pdfio_obj_t *pdfioFileCreateObj(pdf, ...);
|
||||
pdfio_stream_t *pdfioObjCreateStream(obj, PDFIO_FILTER_FLATE);
|
||||
pdfio_obj_t *obj = pdfioFileCreateObj(pdf, ...);
|
||||
pdfio_stream_t *st = pdfioObjCreateStream(obj, PDFIO_FILTER_FLATE);
|
||||
```
|
||||
|
||||
The first argument is the newly created object. The second argument is either
|
||||
`PDFIO_FILTER_NONE` to specify that any encoding is done by your program or
|
||||
`PDFIO_FILTER_FLATE` to specify that PDFio should Flate compress the stream.
|
||||
|
||||
To create a page content stream call the [`pdfioFileCreatePage`](@@) function:
|
||||
|
||||
```c
|
||||
pdfio_file_t *pdf = pdfioFileCreate(...);
|
||||
pdfio_dict_t *dict = pdfioDictCreate(pdf);
|
||||
... set page dictionary keys and values ...
|
||||
pdfio_stream_t *st = pdfioFileCreatePage(pdf, dict);
|
||||
```
|
||||
|
||||
Once you have created the stream, use any of the following functions to write
|
||||
to the stream:
|
||||
|
||||
|
523
pdfio-aes.c
Normal file
523
pdfio-aes.c
Normal file
@ -0,0 +1,523 @@
|
||||
//
|
||||
// AES functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 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 necessary headers...
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
//
|
||||
// Local types...
|
||||
//
|
||||
|
||||
typedef uint8_t state_t[4][4]; // 4x4 AES state table
|
||||
|
||||
|
||||
//
|
||||
// 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 AddRoundKey(size_t round, state_t *state, const uint8_t *RoundKey);
|
||||
static void SubBytes(state_t *state);
|
||||
static void ShiftRows(state_t *state);
|
||||
static uint8_t xtime(uint8_t x);
|
||||
static void MixColumns(state_t *state);
|
||||
static uint8_t Multiply(uint8_t x, uint8_t y);
|
||||
static void InvMixColumns(state_t *state);
|
||||
static void InvSubBytes(state_t *state);
|
||||
static void InvShiftRows(state_t *state);
|
||||
static void Cipher(state_t *state, const _pdfio_aes_t *ctx);
|
||||
static void InvCipher(state_t *state, const _pdfio_aes_t *ctx);
|
||||
static void XorWithIv(uint8_t *buf, const uint8_t *Iv);
|
||||
|
||||
|
||||
//
|
||||
// '_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 roundlen = keylen + 24; // Length of round_key
|
||||
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);
|
||||
InvCipher((state_t *)outbuffer, ctx);
|
||||
XorWithIv(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)
|
||||
{
|
||||
XorWithIv(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, 16 - len, 16 - len);
|
||||
|
||||
XorWithIv(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);
|
||||
}
|
||||
|
||||
|
||||
// This function adds the round key to state.
|
||||
// The round key is added to the state by an XOR function.
|
||||
static void
|
||||
AddRoundKey(size_t round, state_t *state, const uint8_t *RoundKey)
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
|
||||
|
||||
for (RoundKey += round * 16, i = 16; i > 0; i --, sptr ++, RoundKey ++)
|
||||
*sptr ^= *RoundKey;
|
||||
}
|
||||
|
||||
|
||||
// The SubBytes Function Substitutes the values in the
|
||||
// state matrix with values in an S-box.
|
||||
static void
|
||||
SubBytes(state_t *state)
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
|
||||
|
||||
for (i = 16; i > 0; i --, sptr ++)
|
||||
*sptr = sbox[*sptr];
|
||||
}
|
||||
|
||||
// The ShiftRows() function shifts the rows in the state to the left.
|
||||
// Each row is shifted with different offset.
|
||||
// Offset = Row number. So the first row is not shifted.
|
||||
static void
|
||||
ShiftRows(state_t *state)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
xtime(uint8_t x)
|
||||
{
|
||||
return ((uint8_t)((x << 1) ^ ((x >> 7) * 0x1b)));
|
||||
}
|
||||
|
||||
|
||||
// MixColumns function mixes the columns of the state matrix
|
||||
static void
|
||||
MixColumns(state_t *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 is used to 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 */
|
||||
}
|
||||
|
||||
|
||||
// MixColumns function mixes the columns of the state matrix.
|
||||
// The method used to multiply may be difficult to understand for the inexperienced.
|
||||
// Please use the references to gain more information.
|
||||
static void
|
||||
InvMixColumns(state_t *state)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The SubBytes Function Substitutes the values in the
|
||||
// state matrix with values in an S-box.
|
||||
static void
|
||||
InvSubBytes(state_t *state)
|
||||
{
|
||||
unsigned i; // Looping var
|
||||
uint8_t *sptr = (*state)[0]; // Pointer into state
|
||||
|
||||
|
||||
for (i = 16; i > 0; i --, sptr ++)
|
||||
*sptr = rsbox[*sptr];
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
InvShiftRows(state_t *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 is the main function that encrypts the PlainText.
|
||||
static void
|
||||
Cipher(state_t *state, const _pdfio_aes_t *ctx)
|
||||
{
|
||||
size_t round = 0;
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
AddRoundKey(0, state, ctx->round_key);
|
||||
|
||||
// There will be Nr rounds.
|
||||
// The first Nr-1 rounds are identical.
|
||||
// These Nr rounds are executed in the loop below.
|
||||
// Last one without MixColumns()
|
||||
for (round = 1; round < ctx->round_size; round ++)
|
||||
{
|
||||
SubBytes(state);
|
||||
ShiftRows(state);
|
||||
MixColumns(state);
|
||||
AddRoundKey(round, state, ctx->round_key);
|
||||
}
|
||||
// Add round key to last round
|
||||
SubBytes(state);
|
||||
ShiftRows(state);
|
||||
AddRoundKey(ctx->round_size, state, ctx->round_key);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
InvCipher(state_t *state, const _pdfio_aes_t *ctx)
|
||||
{
|
||||
size_t round;
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
AddRoundKey(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 --)
|
||||
{
|
||||
InvShiftRows(state);
|
||||
InvSubBytes(state);
|
||||
AddRoundKey(round, state, ctx->round_key);
|
||||
|
||||
if (round == 0)
|
||||
break;
|
||||
|
||||
InvMixColumns(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
XorWithIv(uint8_t *buf, const uint8_t *Iv)
|
||||
{
|
||||
// 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++;
|
||||
}
|
@ -357,9 +357,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 +396,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 +574,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 +586,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 +600,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);
|
||||
@ -600,7 +619,8 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - 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 +634,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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
@ -329,6 +331,11 @@ _pdfioFileRead(pdfio_file_t *pdf, // I - PDF file
|
||||
pdf->bufpos += rbytes;
|
||||
continue;
|
||||
}
|
||||
else if (rbytes < 0 && (errno == EINTR || errno == EAGAIN))
|
||||
{
|
||||
rbytes = 0;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
@ -377,6 +384,11 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
||||
// 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...
|
||||
@ -515,7 +527,7 @@ read_buffer(pdfio_file_t *pdf, // I - PDF file
|
||||
return (rbytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// 'write_buffer()' - Write a buffer to a PDF file.
|
||||
//
|
||||
@ -530,25 +542,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);
|
||||
|
@ -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.
|
||||
//
|
||||
@ -660,11 +674,11 @@ pdfioContentSave(pdfio_stream_t *st) // I - Stream
|
||||
bool // O - `true` on success, `false` on failure
|
||||
pdfioContentSetDashPattern(
|
||||
pdfio_stream_t *st, // I - Stream
|
||||
int phase, // I - Phase (offset within pattern)
|
||||
int on, // I - On length
|
||||
int off) // I - Off length
|
||||
double phase, // I - Phase (offset within pattern)
|
||||
double on, // I - On length
|
||||
double off) // I - Off length
|
||||
{
|
||||
return (pdfioStreamPrintf(st, "[%d %d] %d d\n", on, off, phase));
|
||||
return (pdfioStreamPrintf(st, "[%g %g] %g d\n", on, off, phase));
|
||||
}
|
||||
|
||||
|
||||
@ -2358,7 +2372,7 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
|
||||
PDFIO_DEBUG("copy_png: Adding %s ColorSpace value.\n", color_type == _PDFIO_PNG_TYPE_GRAY ? "CalGray" : "CalRGB");
|
||||
|
||||
if (wx != 0.0)
|
||||
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromPrimaries(dict->pdf, color_type == _PDFIO_PNG_TYPE_GRAY ? 1 : 3, gamma, wx, wy, rx, ry, bx, by, gx, gy));
|
||||
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromPrimaries(dict->pdf, color_type == _PDFIO_PNG_TYPE_GRAY ? 1 : 3, gamma, wx, wy, rx, ry, gx, gy, bx, by));
|
||||
else
|
||||
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromStandard(dict->pdf, color_type == _PDFIO_PNG_TYPE_GRAY ? 1 : 3, PDFIO_CS_SRGB));
|
||||
}
|
||||
|
@ -91,12 +91,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;
|
||||
|
1049
pdfio-crypto.c
Normal file
1049
pdfio-crypto.c
Normal file
File diff suppressed because it is too large
Load Diff
121
pdfio-dict.c
121
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.
|
||||
@ -21,6 +21,42 @@
|
||||
static int compare_pairs(_pdfio_pair_t *a, _pdfio_pair_t *b);
|
||||
|
||||
|
||||
//
|
||||
// '_pdfioDictClear()' - Remove a key/value pair from a dictionary.
|
||||
//
|
||||
|
||||
void
|
||||
_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);
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioDictCopy()' - Copy a dictionary to a PDF file.
|
||||
//
|
||||
@ -154,7 +190,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 +245,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;
|
||||
@ -412,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.
|
||||
//
|
||||
@ -420,7 +513,9 @@ _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
|
||||
@ -446,9 +541,16 @@ _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.");
|
||||
break;
|
||||
@ -653,7 +755,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 +904,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 +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);
|
||||
@ -850,6 +954,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
|
||||
@ -877,7 +982,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);
|
||||
}
|
||||
|
||||
|
758
pdfio-file.c
758
pdfio-file.c
File diff suppressed because it is too large
Load Diff
338
pdfio-md5.c
Normal file
338
pdfio-md5.c
Normal file
@ -0,0 +1,338 @@
|
||||
//
|
||||
// MD5 functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021 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
|
||||
|
||||
static void
|
||||
md5_process(_pdfio_md5_t *pms, const uint8_t *data /*[64]*/)
|
||||
{
|
||||
uint32_t
|
||||
a = pms->abcd[0], b = pms->abcd[1],
|
||||
c = pms->abcd[2], d = pms->abcd[3];
|
||||
uint32_t t;
|
||||
|
||||
#ifndef ARCH_IS_BIG_ENDIAN
|
||||
# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */
|
||||
#endif
|
||||
#if ARCH_IS_BIG_ENDIAN
|
||||
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the right
|
||||
* order. (This also works on machines of unknown byte order.)
|
||||
*/
|
||||
uint32_t X[16];
|
||||
const uint8_t *xp = data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
X[i] = xp[0] + (unsigned)(xp[1] << 8) + (unsigned)(xp[2] << 16) + (unsigned)(xp[3] << 24);
|
||||
|
||||
#else /* !ARCH_IS_BIG_ENDIAN */
|
||||
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned data
|
||||
* without copying it.
|
||||
*/
|
||||
uint32_t xbuf[16];
|
||||
const uint32_t *X;
|
||||
|
||||
if (!((data - (const uint8_t *)0) & 3)) {
|
||||
/* data are properly aligned */
|
||||
X = (const uint32_t *)data;
|
||||
} else {
|
||||
/* not aligned */
|
||||
memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
void
|
||||
_pdfioCryptoMD5Init(_pdfio_md5_t *pms)
|
||||
{
|
||||
pms->count[0] = pms->count[1] = 0;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = 0xefcdab89;
|
||||
pms->abcd[2] = 0x98badcfe;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void
|
||||
_pdfioCryptoMD5Append(_pdfio_md5_t *pms, const uint8_t *data, size_t nbytes)
|
||||
{
|
||||
const uint8_t *p = data;
|
||||
size_t left = nbytes;
|
||||
size_t offset = (pms->count[0] >> 3) & 63;
|
||||
uint32_t nbits = (uint32_t)(nbytes << 3);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
}
|
||||
|
||||
void
|
||||
_pdfioCryptoMD5Finish(_pdfio_md5_t *pms, uint8_t digest[16])
|
||||
{
|
||||
static const uint8_t pad[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
uint8_t data[8];
|
||||
int i;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
_pdfioCryptoMD5Append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
_pdfioCryptoMD5Append(pms, data, 8);
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
@ -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)
|
||||
@ -96,6 +102,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 +152,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,12 +171,32 @@ 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))
|
||||
@ -173,10 +205,11 @@ pdfioObjCreateStream(
|
||||
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, filter));
|
||||
}
|
||||
|
||||
|
||||
@ -392,7 +425,7 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
||||
// 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);
|
||||
@ -434,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)
|
||||
{
|
||||
@ -446,6 +485,8 @@ pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object
|
||||
return (NULL);
|
||||
|
||||
// Open the stream...
|
||||
obj->pdf->current_obj = obj;
|
||||
|
||||
return (_pdfioStreamOpen(obj, decode));
|
||||
}
|
||||
|
||||
@ -462,7 +503,7 @@ write_obj_header(pdfio_obj_t *obj) // I - Object
|
||||
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,7 +1,7 @@
|
||||
//
|
||||
// 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.
|
||||
@ -14,6 +14,13 @@
|
||||
#include "pdfio-private.h"
|
||||
|
||||
|
||||
//
|
||||
// Local functions...
|
||||
//
|
||||
|
||||
static _pdfio_value_t *get_contents(pdfio_obj_t *page);
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioPageCopy()' - Copy a page to a PDF file.
|
||||
//
|
||||
@ -47,3 +54,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"));
|
||||
}
|
||||
|
102
pdfio-private.h
102
pdfio-private.h
@ -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.
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
# include "pdfio.h"
|
||||
# include <stdarg.h>
|
||||
# include <stdint.h>
|
||||
# include <string.h>
|
||||
# include <errno.h>
|
||||
# include <inttypes.h>
|
||||
@ -115,6 +116,8 @@
|
||||
// Types and constants...
|
||||
//
|
||||
|
||||
# define PDFIO_MAX_DEPTH 32 // Maximum nesting depth for values
|
||||
|
||||
typedef enum _pdfio_mode_e // Read/write mode
|
||||
{
|
||||
_PDFIO_MODE_READ, // Read a PDF file
|
||||
@ -174,6 +177,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
|
||||
@ -210,20 +251,31 @@ struct _pdfio_file_s // PDF file structure
|
||||
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
|
||||
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
|
||||
@ -237,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
|
||||
@ -266,6 +319,7 @@ 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
|
||||
@ -278,6 +332,8 @@ struct _pdfio_stream_s // Stream
|
||||
unsigned char cbuffer[4096], // 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
|
||||
};
|
||||
|
||||
|
||||
@ -288,15 +344,33 @@ struct _pdfio_stream_s // Stream
|
||||
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 void _pdfioDictClear(pdfio_dict_t *dict, const char *key) _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;
|
||||
@ -319,7 +393,7 @@ extern bool _pdfioFileWrite(pdfio_file_t *pdf, const void *buffer, size_t bytes
|
||||
extern void _pdfioObjDelete(pdfio_obj_t *obj) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioObjLoad(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, pdfio_filter_t compression) _PDFIO_INTERNAL;
|
||||
extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL;
|
||||
|
||||
extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
|
||||
@ -334,7 +408,7 @@ 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 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 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[SHA256HashSize])
|
||||
{
|
||||
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;
|
||||
}
|
237
pdfio-stream.c
237
pdfio-stream.c
@ -1,7 +1,7 @@
|
||||
//
|
||||
// PDF stream 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.
|
||||
@ -54,6 +54,10 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
|
||||
while ((status = deflate(&st->flate, Z_FINISH)) != Z_STREAM_END)
|
||||
{
|
||||
size_t bytes = sizeof(st->cbuffer) - st->flate.avail_out,
|
||||
// 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 +65,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)(sizeof(st->cbuffer) - bytes);
|
||||
}
|
||||
|
||||
if (st->flate.avail_out < (uInt)sizeof(st->cbuffer))
|
||||
{
|
||||
// Write any residuals...
|
||||
if (!_pdfioFileWrite(st->pdf, st->cbuffer, sizeof(st->cbuffer) - st->flate.avail_out))
|
||||
size_t bytes = sizeof(st->cbuffer) - 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 +142,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 = 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 +174,8 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
||||
|
||||
done:
|
||||
|
||||
st->pdf->current_obj = NULL;
|
||||
|
||||
free(st->prbuffer);
|
||||
free(st->psbuffer);
|
||||
free(st);
|
||||
@ -137,6 +193,7 @@ 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
|
||||
pdfio_filter_t compression) // I - Compression to apply
|
||||
{
|
||||
pdfio_stream_t *st; // Stream
|
||||
@ -149,9 +206,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)
|
||||
{
|
||||
@ -290,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(
|
||||
@ -298,6 +381,7 @@ pdfioStreamGetToken(
|
||||
size_t bufsize) // I - Size of string buffer
|
||||
{
|
||||
_pdfio_token_t tb; // Token buffer/stack
|
||||
bool ret; // Return value
|
||||
|
||||
|
||||
// Range check input...
|
||||
@ -307,7 +391,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);
|
||||
}
|
||||
|
||||
|
||||
@ -351,6 +438,27 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (obj->pdf->encryption)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// TODO: Add error message?
|
||||
free(st);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Try to decode/decompress the contents of this object...
|
||||
@ -465,6 +573,9 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -585,7 +696,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 +826,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;
|
||||
@ -853,8 +1019,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)
|
||||
@ -878,6 +1049,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
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;
|
||||
@ -931,6 +1105,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
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;
|
||||
@ -995,6 +1172,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
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;
|
||||
@ -1091,11 +1271,36 @@ stream_write(pdfio_stream_t *st, // I - Stream
|
||||
if (st->flate.avail_out < (sizeof(st->cbuffer) / 8))
|
||||
{
|
||||
// Flush the compression buffer...
|
||||
if (!_pdfioFileWrite(st->pdf, st->cbuffer, sizeof(st->cbuffer) - st->flate.avail_out))
|
||||
size_t cbytes = sizeof(st->cbuffer) - 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)(sizeof(st->cbuffer) - cbytes);
|
||||
}
|
||||
|
||||
// Deflate what we can this time...
|
||||
|
@ -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);
|
||||
|
||||
@ -200,6 +211,7 @@ _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?
|
||||
|
||||
|
||||
//
|
||||
@ -260,6 +272,9 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
case '(' : // Literal string
|
||||
while ((ch = get_char(tb)) != EOF)
|
||||
{
|
||||
if (ch == 0)
|
||||
saw_nul = true;
|
||||
|
||||
if (ch == '\\')
|
||||
{
|
||||
// Quoted character...
|
||||
@ -280,7 +295,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 --;
|
||||
@ -350,6 +367,36 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
_pdfioFileError(tb->pdf, "Unterminated string literal.");
|
||||
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.");
|
||||
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
|
||||
@ -454,7 +501,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
return (false);
|
||||
}
|
||||
|
||||
while ((ch = get_char(tb)) != EOF && ch != '>')
|
||||
do
|
||||
{
|
||||
if (isxdigit(ch))
|
||||
{
|
||||
@ -476,6 +523,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
while ((ch = get_char(tb)) != EOF && ch != '>');
|
||||
|
||||
if (ch == EOF)
|
||||
{
|
||||
@ -497,12 +545,9 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
||||
break;
|
||||
}
|
||||
|
||||
while (tb->bufptr < tb->bufend && isspace(*(tb->bufptr)))
|
||||
tb->bufptr ++;
|
||||
|
||||
*bufptr = '\0';
|
||||
|
||||
PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
||||
// PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
|
||||
|
||||
return (bufptr > buffer);
|
||||
}
|
||||
@ -539,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
|
||||
|
||||
@ -552,6 +598,7 @@ get_char(_pdfio_token_t *tb) // I - Token buffer
|
||||
}
|
||||
PDFIO_DEBUG("'\n");
|
||||
#endif // DEBUG
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
// Return the next character...
|
||||
|
170
pdfio-value.c
170
pdfio-value.c
@ -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.
|
||||
@ -194,8 +194,10 @@ _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
|
||||
#ifdef DEBUG
|
||||
@ -216,7 +218,7 @@ _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);
|
||||
@ -224,15 +226,27 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
if (!strcmp(token, "["))
|
||||
{
|
||||
// Start of array
|
||||
if (depth >= PDFIO_MAX_DEPTH)
|
||||
{
|
||||
_pdfioFileError(pdf, "Too many nested arrays.");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
v->type = PDFIO_VALTYPE_ARRAY;
|
||||
if ((v->value.array = _pdfioArrayRead(pdf, tb)) == NULL)
|
||||
if ((v->value.array = _pdfioArrayRead(pdf, obj, tb, depth + 1)) == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
else if (!strcmp(token, "<<"))
|
||||
{
|
||||
// Start of dictionary
|
||||
if (depth >= PDFIO_MAX_DEPTH)
|
||||
{
|
||||
_pdfioFileError(pdf, "Too many nested dictionaries.");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
v->type = PDFIO_VALTYPE_DICT;
|
||||
if ((v->value.dict = _pdfioDictRead(pdf, tb)) == NULL)
|
||||
if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
else if (!strncmp(token, "(D:", 3))
|
||||
@ -269,6 +283,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (token[i])
|
||||
{
|
||||
// Just a string...
|
||||
@ -278,6 +293,8 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
else
|
||||
{
|
||||
// Date value...
|
||||
memset(&dateval, 0, sizeof(dateval));
|
||||
|
||||
dateval.tm_year = (token[3] - '0') * 1000 + (token[4] - '0') * 100 + (token[5] - '0') * 10 + token[6] - '0' - 1900;
|
||||
dateval.tm_mon = (token[7] - '0') * 10 + token[8] - '0' - 1;
|
||||
dateval.tm_mday = (token[9] - '0') * 10 + token[10] - '0';
|
||||
@ -350,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)
|
||||
{
|
||||
@ -396,6 +440,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 +455,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')
|
||||
{
|
||||
@ -472,6 +519,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,23 +529,47 @@ _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[32768], // Temporary buffer for encryption
|
||||
*dataptr; // Pointer into data
|
||||
|
||||
if (obj && pdf->encryption)
|
||||
{
|
||||
// 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 > (sizeof(temp) - 32))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to write encrypted binary string - too long.");
|
||||
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 (!_pdfioFilePuts(pdf, "<"))
|
||||
return (false);
|
||||
|
||||
for (i = v->value.binary.datalen, dataptr = v->value.binary.data; i > 1; i -= 2, dataptr += 2)
|
||||
for (; databytes > 1; databytes -= 2, dataptr += 2)
|
||||
{
|
||||
if (!_pdfioFilePrintf(pdf, "%02X%02X", dataptr[0], dataptr[1]))
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
if (databytes > 0)
|
||||
return (_pdfioFilePrintf(pdf, "%02X>", dataptr[0]));
|
||||
else
|
||||
return (_pdfioFilePuts(pdf, ">"));
|
||||
@ -512,6 +584,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,11 +592,45 @@ _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[32768], // 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));
|
||||
@ -538,7 +645,44 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
return (_pdfioFilePrintf(pdf, " %g", v->value.number));
|
||||
|
||||
case PDFIO_VALTYPE_STRING :
|
||||
if (obj && pdf->encryption)
|
||||
{
|
||||
// Write encrypted string...
|
||||
uint8_t temp[32768], // 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
|
||||
|
||||
if (len > (sizeof(temp) - 32))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to write encrypted string - too long.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
|
||||
tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)v->value.string, 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
|
||||
{
|
||||
// Write unencrypted string...
|
||||
const char *start, // Start of fragment
|
||||
*end; // End of fragment
|
||||
|
||||
|
37
pdfio.h
37
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,10 +55,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)
|
||||
} pdfio_encryption_t;
|
||||
typedef enum pdfio_filter_e // Compression/decompression filters for streams
|
||||
{
|
||||
PDFIO_FILTER_NONE, // No filter
|
||||
@ -74,6 +84,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
|
||||
@ -139,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;
|
||||
@ -156,8 +185,10 @@ 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 *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_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;
|
||||
@ -169,15 +200,17 @@ 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 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;
|
||||
|
||||
|
@ -2,5 +2,5 @@ Name: pdfio
|
||||
Description: PDF read/write library
|
||||
URL: https://www.msweet.org/pdfio
|
||||
Requires: zlib >= 1.0
|
||||
Libs: -L${prefix}/lib -lpdfio
|
||||
Libs: -L${prefix}/lib -lpdfio -lm
|
||||
Cflags: -I${prefix}/include
|
||||
|
@ -87,7 +87,7 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0b1";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.0b1";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.0b1";_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.0b1";NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";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" />
|
||||
|
@ -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" />
|
||||
|
@ -25,7 +25,12 @@
|
||||
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 */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -79,6 +84,11 @@
|
||||
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>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -150,19 +160,24 @@
|
||||
279E1038267D045C00D3A349 /* Library */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
27CF90432711DFFE00E50FE4 /* pdfio-aes.c */,
|
||||
273440BA263D727800FBFD63 /* pdfio-array.c */,
|
||||
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>";
|
||||
@ -241,7 +256,7 @@
|
||||
273440A8263D6FE200FBFD63 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1250;
|
||||
LastUpgradeCheck = 1300;
|
||||
TargetAttributes = {
|
||||
273440AF263D6FE200FBFD63 = {
|
||||
CreatedOnToolsVersion = 12.5;
|
||||
@ -281,11 +296,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,9 +370,9 @@
|
||||
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;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@ -428,9 +448,9 @@
|
||||
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;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
|
66
pdfio1.def
66
pdfio1.def
@ -1,9 +1,67 @@
|
||||
LIBRARY pdfio1
|
||||
VERSION 1.0
|
||||
EXPORTS
|
||||
_pdfioArrayDebug
|
||||
_pdfioArrayDelete
|
||||
_pdfioArrayGetValue
|
||||
_pdfioArrayRead
|
||||
_pdfioArrayWrite
|
||||
_pdfioCryptoAESDecrypt
|
||||
_pdfioCryptoAESEncrypt
|
||||
_pdfioCryptoAESInit
|
||||
_pdfioCryptoLock
|
||||
_pdfioCryptoMD5Append
|
||||
_pdfioCryptoMD5Finish
|
||||
_pdfioCryptoMD5Init
|
||||
_pdfioCryptoMakeRandom
|
||||
_pdfioCryptoMakeReader
|
||||
_pdfioCryptoMakeWriter
|
||||
_pdfioCryptoRC4Crypt
|
||||
_pdfioCryptoRC4Init
|
||||
_pdfioCryptoSHA256Append
|
||||
_pdfioCryptoSHA256Finish
|
||||
_pdfioCryptoSHA256Init
|
||||
_pdfioCryptoUnlock
|
||||
_pdfioDictClear
|
||||
_pdfioDictDebug
|
||||
_pdfioDictDelete
|
||||
_pdfioDictGetValue
|
||||
_pdfioDictRead
|
||||
_pdfioDictSetValue
|
||||
_pdfioDictWrite
|
||||
_pdfioFileAddMappedObj
|
||||
_pdfioFileAddPage
|
||||
_pdfioFileConsume
|
||||
_pdfioFileCreateObj
|
||||
_pdfioFileDefaultError
|
||||
_pdfioFileError
|
||||
_pdfioFileFindMappedObj
|
||||
_pdfioFileFlush
|
||||
_pdfioFileGetChar
|
||||
_pdfioFileGets
|
||||
_pdfioFilePeek
|
||||
_pdfioFilePrintf
|
||||
_pdfioFilePuts
|
||||
_pdfioFileRead
|
||||
_pdfioFileSeek
|
||||
_pdfioFileTell
|
||||
_pdfioFileWrite
|
||||
_pdfioObjDelete
|
||||
_pdfioObjLoad
|
||||
_pdfioStreamCreate
|
||||
_pdfioStreamOpen
|
||||
_pdfioStringIsAllocated
|
||||
_pdfioTokenClear
|
||||
_pdfioTokenFlush
|
||||
_pdfioTokenGet
|
||||
_pdfioTokenInit
|
||||
_pdfioTokenPush
|
||||
_pdfioTokenRead
|
||||
_pdfioValueCopy
|
||||
_pdfioValueDebug
|
||||
_pdfioValueDelete
|
||||
_pdfioValueRead
|
||||
_pdfioValueWrite
|
||||
pdfioArrayAppendArray
|
||||
pdfioArrayAppendBinary
|
||||
pdfioArrayAppendBoolean
|
||||
@ -43,6 +101,7 @@ pdfioContentPathClose
|
||||
pdfioContentPathCurve
|
||||
pdfioContentPathCurve13
|
||||
pdfioContentPathCurve23
|
||||
pdfioContentPathEnd
|
||||
pdfioContentPathLineTo
|
||||
pdfioContentPathMoveTo
|
||||
pdfioContentPathRect
|
||||
@ -96,6 +155,7 @@ pdfioDictGetObj
|
||||
pdfioDictGetRect
|
||||
pdfioDictGetString
|
||||
pdfioDictGetType
|
||||
pdfioDictIterateKeys
|
||||
pdfioDictSetArray
|
||||
pdfioDictSetBinary
|
||||
pdfioDictSetBoolean
|
||||
@ -117,7 +177,9 @@ pdfioFileCreateICCObjFromFile
|
||||
pdfioFileCreateImageObjFromData
|
||||
pdfioFileCreateImageObjFromFile
|
||||
pdfioFileCreateObj
|
||||
pdfioFileCreateOutput
|
||||
pdfioFileCreatePage
|
||||
pdfioFileCreateTemporary
|
||||
pdfioFileFindObj
|
||||
pdfioFileGetAuthor
|
||||
pdfioFileGetCreationDate
|
||||
@ -129,6 +191,7 @@ pdfioFileGetNumObjs
|
||||
pdfioFileGetNumPages
|
||||
pdfioFileGetObj
|
||||
pdfioFileGetPage
|
||||
pdfioFileGetPermissions
|
||||
pdfioFileGetProducer
|
||||
pdfioFileGetSubject
|
||||
pdfioFileGetTitle
|
||||
@ -138,6 +201,7 @@ pdfioFileSetAuthor
|
||||
pdfioFileSetCreationDate
|
||||
pdfioFileSetCreator
|
||||
pdfioFileSetKeywords
|
||||
pdfioFileSetPermissions
|
||||
pdfioFileSetSubject
|
||||
pdfioFileSetTitle
|
||||
pdfioImageGetBytesPerLine
|
||||
@ -158,6 +222,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.1.0</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
@ -12,9 +12,13 @@
|
||||
<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-2023 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
<dependencies>
|
||||
<dependency id="pdfio_native.redist" version="1.1.0" />
|
||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="doc\pdfio-128.png" target="build\native" />
|
||||
@ -22,7 +26,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>
|
||||
|
25
pdfio_native.redist.nuspec
Normal file
25
pdfio_native.redist.nuspec
Normal file
@ -0,0 +1,25 @@
|
||||
<?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.1.0</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-2023 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
</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>
|
95
pdfiototext.c
Normal file
95
pdfiototext.c
Normal file
@ -0,0 +1,95 @@
|
||||
//
|
||||
// PDF to text program for PDFio.
|
||||
//
|
||||
// Copyright © 2022 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./pdfiototext FILENAME.pdf > FILENAME.txt
|
||||
//
|
||||
|
||||
#include "pdfio.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Main entry.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // I - Command-line arguments
|
||||
{
|
||||
pdfio_file_t *file; // PDF file
|
||||
size_t i, j, // Looping vars
|
||||
num_pages, // Number of pages
|
||||
num_streams; // Number of streams for page
|
||||
pdfio_obj_t *obj; // Current page object
|
||||
pdfio_stream_t *st; // Current page content stream
|
||||
char buffer[1024]; // String buffer
|
||||
bool first; // First string token?
|
||||
|
||||
|
||||
// Verify command-line arguments...
|
||||
if (argc != 2)
|
||||
{
|
||||
puts("Usage: pdfiototext FILENAME.pdf > FILENAME.txt");
|
||||
return (1);
|
||||
}
|
||||
|
||||
// Open the PDF file...
|
||||
if ((file = pdfioFileOpen(argv[1], NULL, NULL, NULL, NULL)) == NULL)
|
||||
return (1);
|
||||
|
||||
// printf("%s: %u pages\n", argv[1], (unsigned)pdfioFileGetNumPages(file));
|
||||
|
||||
// Try grabbing content from all of the pages...
|
||||
for (i = 0, num_pages = pdfioFileGetNumPages(file); i < num_pages; i ++)
|
||||
{
|
||||
if ((obj = pdfioFileGetPage(file, i)) == NULL)
|
||||
continue;
|
||||
|
||||
num_streams = pdfioPageGetNumStreams(obj);
|
||||
|
||||
// printf("%s: page%u=%p, num_streams=%u\n", argv[1], (unsigned)i, obj, (unsigned)num_streams);
|
||||
|
||||
for (j = 0; j < num_streams; j ++)
|
||||
{
|
||||
if ((st = pdfioPageOpenStream(obj, j, true)) == NULL)
|
||||
continue;
|
||||
|
||||
// printf("%s: page%u st%u=%p\n", argv[1], (unsigned)i, (unsigned)j, st);
|
||||
|
||||
first = true;
|
||||
while (pdfioStreamGetToken(st, buffer, sizeof(buffer)))
|
||||
{
|
||||
if (buffer[0] == '(')
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
putchar(' ');
|
||||
|
||||
fputs(buffer + 1, stdout);
|
||||
}
|
||||
else if (!strcmp(buffer, "Td") || !strcmp(buffer, "TD") || !strcmp(buffer, "T*") || !strcmp(buffer, "\'") || !strcmp(buffer, "\""))
|
||||
{
|
||||
putchar('\n');
|
||||
first = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!first)
|
||||
putchar('\n');
|
||||
|
||||
pdfioStreamClose(st);
|
||||
}
|
||||
}
|
||||
|
||||
pdfioFileClose(file);
|
||||
|
||||
return (0);
|
||||
}
|
1067
testpdfio.c
1067
testpdfio.c
File diff suppressed because it is too large
Load Diff
9
ttf.c
9
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;
|
||||
@ -513,7 +513,8 @@ ttfDelete(ttf_t *font) // I - Font
|
||||
return;
|
||||
|
||||
// Close the font file...
|
||||
close(font->fd);
|
||||
if (font->fd >= 0)
|
||||
close(font->fd);
|
||||
|
||||
// Free all memory used...
|
||||
free(font->copyright);
|
||||
|
Reference in New Issue
Block a user