mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-07-13 14:34:28 +02:00
Compare commits
40 Commits
Author | SHA1 | Date | |
---|---|---|---|
cd80c3037d | |||
97934ab995 | |||
088646e1cf | |||
3f0aad7564 | |||
d36df63b57 | |||
a5dfac7495 | |||
0258384d53 | |||
9fec2195d0 | |||
8ccbdaed94 | |||
4804db38a5 | |||
ddd984215a | |||
efe7c01015 | |||
600fa4ce59 | |||
688810f143 | |||
858cc101b6 | |||
43114f43bf | |||
c4abceef79 | |||
2e91e05d7b | |||
7e3db6b639 | |||
acb6b66bdb | |||
b0a66eef78 | |||
ed88322496 | |||
59959bf0e5 | |||
19c45871fa | |||
b0e4646f9d | |||
12ef2fe2c3 | |||
4630060ee7 | |||
74a6fb1860 | |||
a3ea0a99ff | |||
fdfa700442 | |||
d759baf11e | |||
7f6ffcda22 | |||
87ca4db73f | |||
a83f7f50ff | |||
6a4ce57d09 | |||
d4c594cec4 | |||
35c674b633 | |||
97d4955666 | |||
e138232a93 | |||
8d8225f4a1 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -8,7 +8,10 @@
|
|||||||
/doc/pdfio.epub
|
/doc/pdfio.epub
|
||||||
/packages
|
/packages
|
||||||
/pdfio.xcodeproj/xcshareddata
|
/pdfio.xcodeproj/xcshareddata
|
||||||
|
/pdfio-*.tar.gz*
|
||||||
|
/pdfio-*.zip*
|
||||||
/pdfiototext
|
/pdfiototext
|
||||||
/testpdfio
|
/testpdfio
|
||||||
/testpdfio-*.pdf
|
/testpdfio-*.pdf
|
||||||
|
/testttf
|
||||||
/x64
|
/x64
|
||||||
|
41
CHANGES.md
41
CHANGES.md
@ -2,7 +2,46 @@ Changes in PDFio
|
|||||||
================
|
================
|
||||||
|
|
||||||
|
|
||||||
v1.1.0 (February 3, 2023)
|
v1.1.4 (December 3, 2023)
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
- Fixed detection of encrypted strings that are too short (Issue #52)
|
||||||
|
- Fixed a TrueType CMAP decoding bug.
|
||||||
|
- Fixed a text rendering issue for Asian text.
|
||||||
|
- Added a ToUnicode map for Unicode text to support text copying.
|
||||||
|
|
||||||
|
|
||||||
|
v1.1.3 (November 15, 2023)
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Fixed Unicode font support (Issue #16)
|
||||||
|
- Fixed missing initializer for 40-bit RC4 encryption (Issue #51)
|
||||||
|
|
||||||
|
|
||||||
|
v1.1.2 (October 10, 2023)
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
- Updated `pdfioContentSetDashPattern` to support setting a solid (0 length)
|
||||||
|
dash pattern (Issue #41)
|
||||||
|
- Fixed an issue with broken PDF files containing extra CR and/or LF separators
|
||||||
|
after the object stream token (Issue #40)
|
||||||
|
- Fixed an issue with PDF files produced by Crystal Reports (Issue #45)
|
||||||
|
- Fixed an issue with PDF files produced by Microsoft Reporting Services
|
||||||
|
(Issue #46)
|
||||||
|
- Fixed support for compound filters where the filter array consists of a
|
||||||
|
single named filter (Issue #47)
|
||||||
|
- Fixed builds on Windows - needed windows.h header for temporary files
|
||||||
|
(Issue #48)
|
||||||
|
|
||||||
|
|
||||||
|
v1.1.1 (March 20, 2023)
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
- CVE-2023-28428: Fixed a potential denial-of-service with corrupt PDF files.
|
||||||
|
- Fixed a few build issues.
|
||||||
|
|
||||||
|
|
||||||
|
v1.1.0 (February 6, 2023)
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
- CVE-2023-24808: Fixed a potential denial-of-service with corrupt PDF files.
|
- CVE-2023-24808: Fixed a potential denial-of-service with corrupt PDF files.
|
||||||
|
@ -118,7 +118,7 @@ the source file and the copyright and licensing notice:
|
|||||||
//
|
//
|
||||||
// Description of file contents.
|
// Description of file contents.
|
||||||
//
|
//
|
||||||
// Copyright YYYY by AUTHOR.
|
// Copyright © YYYY by AUTHOR.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
@ -330,7 +330,7 @@ typedef, for example:
|
|||||||
|
|
||||||
All constant names are uppercase with underscores between words, e.g.,
|
All constant names are uppercase with underscores between words, e.g.,
|
||||||
`PDFIO_THIS_CONSTANT`, `PDFIO_THAT_CONSTANT`, etc. Constants begin with the
|
`PDFIO_THIS_CONSTANT`, `PDFIO_THAT_CONSTANT`, etc. Constants begin with the
|
||||||
"PDFio\_" prefix to avoid conflicts with system constants. Private constants
|
"PDFIO\_" prefix to avoid conflicts with system constants. Private constants
|
||||||
start with an underscore, e.g., `_PDFIO_THIS_CONSTANT`,
|
start with an underscore, e.g., `_PDFIO_THIS_CONSTANT`,
|
||||||
`_PDFIO_THAT_CONSTANT`, etc.
|
`_PDFIO_THAT_CONSTANT`, etc.
|
||||||
|
|
||||||
@ -369,11 +369,12 @@ extensions MUST NOT be used.
|
|||||||
The following variables are defined in the makefile:
|
The following variables are defined in the makefile:
|
||||||
|
|
||||||
- `AR`; the static library archiver command,
|
- `AR`; the static library archiver command,
|
||||||
- `ARFLAGS`; options for the static library archiver command,
|
- `ARFLAGS`; options for the static library archiver,
|
||||||
- `CC`; the C compiler command,
|
- `CC`; the C compiler command,
|
||||||
- `CFLAGS`; options for the C compiler command,
|
- `CFLAGS`; options for the C compiler,
|
||||||
- `CODESIGN_IDENTITY`: the code signing identity,
|
- `CODESIGN_IDENTITY`: the code signing identity,
|
||||||
- `COMMONFLAGS`; common compiler optimization options,
|
- `COMMONFLAGS`; common compiler optimization options,
|
||||||
|
- `CPPFLAGS`; options for the C preprocessor,
|
||||||
- `DESTDIR`/`DSTROOT`: the destination root directory when installing.
|
- `DESTDIR`/`DSTROOT`: the destination root directory when installing.
|
||||||
- `DSO`; the shared library building command,
|
- `DSO`; the shared library building command,
|
||||||
- `DSOFLAGS`; options for the shared library building command,
|
- `DSOFLAGS`; options for the shared library building command,
|
||||||
@ -395,4 +396,5 @@ The following standard targets are defined in the makefile:
|
|||||||
with debug printfs and the clang address sanitizer enabled.
|
with debug printfs and the clang address sanitizer enabled.
|
||||||
- `install`; installs all distribution files in their corresponding locations.
|
- `install`; installs all distribution files in their corresponding locations.
|
||||||
- `install-shared`; same as `install` but also installs the shared library.
|
- `install-shared`; same as `install` but also installs the shared library.
|
||||||
|
- `macos`; same as `all` but creates a Universal Binary (X64 + ARM64).
|
||||||
- `test`; runs the unit test program, building it as needed.
|
- `test`; runs the unit test program, building it as needed.
|
||||||
|
23
Makefile
23
Makefile
@ -21,7 +21,7 @@ CFLAGS =
|
|||||||
CODESIGN_IDENTITY = Developer ID
|
CODESIGN_IDENTITY = Developer ID
|
||||||
COMMONFLAGS = -Os -g
|
COMMONFLAGS = -Os -g
|
||||||
#COMMONFLAGS = -O0 -g -fsanitize=address
|
#COMMONFLAGS = -O0 -g -fsanitize=address
|
||||||
CPPFLAGS = '-DPDFIO_VERSION="$(VERSION)"'
|
CPPFLAGS =
|
||||||
DESTDIR = $(DSTROOT)
|
DESTDIR = $(DSTROOT)
|
||||||
DSO = cc
|
DSO = cc
|
||||||
DSOFLAGS =
|
DSOFLAGS =
|
||||||
@ -29,7 +29,7 @@ DSONAME =
|
|||||||
LDFLAGS =
|
LDFLAGS =
|
||||||
LIBS = -lm -lz
|
LIBS = -lm -lz
|
||||||
RANLIB = ranlib
|
RANLIB = ranlib
|
||||||
VERSION = 1.1.0
|
VERSION = 1.1.4
|
||||||
prefix = /usr/local
|
prefix = /usr/local
|
||||||
|
|
||||||
|
|
||||||
@ -67,12 +67,14 @@ LIBOBJS = \
|
|||||||
OBJS = \
|
OBJS = \
|
||||||
$(LIBOBJS) \
|
$(LIBOBJS) \
|
||||||
pdfiototext.o \
|
pdfiototext.o \
|
||||||
testpdfio.o
|
testpdfio.o \
|
||||||
|
testttf.o
|
||||||
TARGETS = \
|
TARGETS = \
|
||||||
$(DSONAME) \
|
$(DSONAME) \
|
||||||
libpdfio.a \
|
libpdfio.a \
|
||||||
pdfiototext \
|
pdfiototext \
|
||||||
testpdfio
|
testpdfio \
|
||||||
|
testttf
|
||||||
|
|
||||||
|
|
||||||
# Make everything
|
# Make everything
|
||||||
@ -89,7 +91,7 @@ debug:
|
|||||||
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-g -fsanitize=address -DDEBUG=1" clean all
|
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-g -fsanitize=address -DDEBUG=1" clean all
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-Os -mmacosx-version-min=10.14 -arch x86_64 -arch arm64" clean all
|
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-Os -mmacosx-version-min=11 -arch x86_64 -arch arm64" clean all
|
||||||
|
|
||||||
|
|
||||||
# Clean everything
|
# Clean everything
|
||||||
@ -136,7 +138,8 @@ install-shared:
|
|||||||
|
|
||||||
# Test everything
|
# Test everything
|
||||||
test: testpdfio
|
test: testpdfio
|
||||||
./testpdfio
|
./testttf 2>test.log
|
||||||
|
./testpdfio 2>test.log
|
||||||
|
|
||||||
valgrind: testpdfio
|
valgrind: testpdfio
|
||||||
valgrind --leak-check=full ./testpdfio
|
valgrind --leak-check=full ./testpdfio
|
||||||
@ -182,16 +185,22 @@ testpdfio: testpdfio.o libpdfio.a
|
|||||||
echo Linking $@...
|
echo Linking $@...
|
||||||
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
|
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
|
||||||
|
|
||||||
|
# TTF test program
|
||||||
|
testttf: ttf.o testttf.o
|
||||||
|
echo Linking $@...
|
||||||
|
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o testttf ttf.o testttf.o $(LIBS)
|
||||||
|
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
$(OBJS): pdfio.h pdfio-private.h Makefile
|
$(OBJS): pdfio.h pdfio-private.h Makefile
|
||||||
pdfio-content.o: pdfio-content.h ttf.h
|
pdfio-content.o: pdfio-content.h ttf.h
|
||||||
|
testttf.o: ttf.h
|
||||||
ttf.o: ttf.h
|
ttf.o: ttf.h
|
||||||
|
|
||||||
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
||||||
DOCFLAGS = \
|
DOCFLAGS = \
|
||||||
--author "Michael R Sweet" \
|
--author "Michael R Sweet" \
|
||||||
--copyright "Copyright (c) 2021-2022 by Michael R Sweet" \
|
--copyright "Copyright (c) 2021-2023 by Michael R Sweet" \
|
||||||
--docversion $(VERSION)
|
--docversion $(VERSION)
|
||||||
|
|
||||||
.PHONY: doc
|
.PHONY: doc
|
||||||
|
@ -5,8 +5,6 @@ pdfio - PDF Read/Write Library
|
|||||||

|

|
||||||
[](https://github.com/michaelrsweet/pdfio/actions/workflows/build.yml)
|
[](https://github.com/michaelrsweet/pdfio/actions/workflows/build.yml)
|
||||||
[](https://scan.coverity.com/projects/michaelrsweet-pdfio)
|
[](https://scan.coverity.com/projects/michaelrsweet-pdfio)
|
||||||
[](https://lgtm.com/projects/g/michaelrsweet/pdfio/context:cpp)
|
|
||||||
[](https://lgtm.com/projects/g/michaelrsweet/pdfio/)
|
|
||||||
|
|
||||||
PDFio is a simple C library for reading and writing PDF files. The primary
|
PDFio is a simple C library for reading and writing PDF files. The primary
|
||||||
goals of PDFio are:
|
goals of PDFio are:
|
||||||
@ -121,7 +119,7 @@ You can reproduce this with the makefile using:
|
|||||||
Legal Stuff
|
Legal Stuff
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
PDFio is Copyright © 2021-2022 by Michael R Sweet.
|
PDFio is Copyright © 2021-2023 by Michael R Sweet.
|
||||||
|
|
||||||
This software is licensed under the Apache License Version 2.0 with an
|
This software is licensed under the Apache License Version 2.0 with an
|
||||||
(optional) exception to allow linking against GPL2/LGPL2 software. See the
|
(optional) exception to allow linking against GPL2/LGPL2 software. See the
|
||||||
|
27
SECURITY.md
27
SECURITY.md
@ -5,6 +5,25 @@ This file describes how security issues are reported and handled, and what the
|
|||||||
expectations are for security issues reported to this project.
|
expectations are for security issues reported to this project.
|
||||||
|
|
||||||
|
|
||||||
|
Reporting a Security Bug
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
For the purposes of this project, a security bug is a software defect that
|
||||||
|
allows a *local or remote user* to gain unauthorized access or privileges on the
|
||||||
|
host computer or to cause the software to crash. Such defects should be
|
||||||
|
reported to the project security advisory page at
|
||||||
|
<https://github.com/michaelrsweet/pdfio/security/advisories>.
|
||||||
|
|
||||||
|
Alternately, security bugs can be reported to "security AT msweet.org" using the
|
||||||
|
PGP public key below. Expect a response within 5 business days. Any proposed
|
||||||
|
embargo date should be at least 30 days and no more than 90 days in the future.
|
||||||
|
|
||||||
|
> *Note:* If you've found a software defect that allows a *program* to gain
|
||||||
|
> unauthorized access or privileges on the host computer or causes the program
|
||||||
|
> to crash, that defect should be reported as an ordinary project issue at
|
||||||
|
> <https://github.com/michaelrsweet/pdfio/issues>.
|
||||||
|
|
||||||
|
|
||||||
Responsible Disclosure
|
Responsible Disclosure
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
@ -50,14 +69,6 @@ example:
|
|||||||
1.0rc1
|
1.0rc1
|
||||||
|
|
||||||
|
|
||||||
Reporting a Vulnerability
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
Report all security issues to "security AT msweet.org". Expect a response
|
|
||||||
within 5 business days. Any proposed embargo date should be at least 30 days
|
|
||||||
and no more than 90 days in the future.
|
|
||||||
|
|
||||||
|
|
||||||
PGP Public Key
|
PGP Public Key
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
24
doc/pdfio.3
24
doc/pdfio.3
@ -1,4 +1,4 @@
|
|||||||
.TH pdfio 3 "pdf read/write library" "2022-07-03" "pdf read/write library"
|
.TH pdfio 3 "pdf read/write library" "2023-11-15" "pdf read/write library"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
pdfio \- pdf read/write library
|
pdfio \- pdf read/write library
|
||||||
.SH Introduction
|
.SH Introduction
|
||||||
@ -34,7 +34,7 @@ PDFio is
|
|||||||
.I not
|
.I not
|
||||||
concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.
|
concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.
|
||||||
.PP
|
.PP
|
||||||
PDFio is Copyright \[co] 2021\-2022 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
PDFio is Copyright \[co] 2021\-2023 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
||||||
.SS Requirements
|
.SS Requirements
|
||||||
.PP
|
.PP
|
||||||
PDFio requires the following to build the software:
|
PDFio requires the following to build the software:
|
||||||
@ -1357,7 +1357,7 @@ bool pdfioContentFillAndStroke (
|
|||||||
.fi
|
.fi
|
||||||
.SS pdfioContentMatrixConcat
|
.SS pdfioContentMatrixConcat
|
||||||
Concatenate a matrix to the current graphics
|
Concatenate a matrix to the current graphics
|
||||||
state.
|
state.
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
bool pdfioContentMatrixConcat (
|
bool pdfioContentMatrixConcat (
|
||||||
@ -1507,6 +1507,9 @@ bool pdfioContentSetDashPattern (
|
|||||||
double off
|
double off
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
|
.PP
|
||||||
|
This function sets the stroke pattern when drawing lines. If "on" and "off"
|
||||||
|
are 0, a solid line is drawn.
|
||||||
.SS pdfioContentSetFillColorDeviceCMYK
|
.SS pdfioContentSetFillColorDeviceCMYK
|
||||||
Set device CMYK fill color.
|
Set device CMYK fill color.
|
||||||
.PP
|
.PP
|
||||||
@ -1981,6 +1984,7 @@ function "cb":
|
|||||||
}
|
}
|
||||||
|
|
||||||
.fi
|
.fi
|
||||||
|
|
||||||
The iteration continues as long as the callback returns \fBtrue\fR or all keys
|
The iteration continues as long as the callback returns \fBtrue\fR or all keys
|
||||||
have been iterated.
|
have been iterated.
|
||||||
.SS pdfioDictSetArray
|
.SS pdfioDictSetArray
|
||||||
@ -2305,10 +2309,11 @@ written:
|
|||||||
ssize_t
|
ssize_t
|
||||||
output_cb(void *output_ctx, const void *buffer, size_t bytes)
|
output_cb(void *output_ctx, const void *buffer, size_t bytes)
|
||||||
{
|
{
|
||||||
// Write buffer to output and return the number of bytes written
|
// Write buffer to output and return the number of bytes written
|
||||||
}
|
}
|
||||||
|
|
||||||
.fi
|
.fi
|
||||||
|
|
||||||
The "version" argument specifies the PDF version number for the file or
|
The "version" argument specifies the PDF version number for the file or
|
||||||
\fBNULL\fR for the default ("2.0").
|
\fBNULL\fR for the default ("2.0").
|
||||||
.PP
|
.PP
|
||||||
@ -2616,7 +2621,7 @@ double pdfioImageGetWidth (
|
|||||||
.fi
|
.fi
|
||||||
.SS pdfioObjClose
|
.SS pdfioObjClose
|
||||||
Close an object, writing any data as needed to the PDF
|
Close an object, writing any data as needed to the PDF
|
||||||
file.
|
file.
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
bool pdfioObjClose (
|
bool pdfioObjClose (
|
||||||
@ -2802,6 +2807,13 @@ bool pdfioStreamGetToken (
|
|||||||
size_t bufsize
|
size_t bufsize
|
||||||
);
|
);
|
||||||
.fi
|
.fi
|
||||||
|
.PP
|
||||||
|
This function reads a single PDF token from a stream. Operator tokens,
|
||||||
|
boolean values, and numbers are returned as-is in the provided string buffer.
|
||||||
|
String values start with the opening parenthesis ('(') but have all escaping
|
||||||
|
resolved and the terminating parenthesis removed. Hexadecimal string values
|
||||||
|
start with the opening angle bracket ('<') and have all whitespace and the
|
||||||
|
terminating angle bracket removed.
|
||||||
.SS pdfioStreamPeek
|
.SS pdfioStreamPeek
|
||||||
Peek at data in a stream.
|
Peek at data in a stream.
|
||||||
.PP
|
.PP
|
||||||
@ -3035,4 +3047,4 @@ typedef uint8_t state_t[4][4];
|
|||||||
Michael R Sweet
|
Michael R Sweet
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
.PP
|
.PP
|
||||||
Copyright (c) 2021-2022 by Michael R Sweet
|
Copyright (c) 2021-2023 by Michael R Sweet
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en-US">
|
<html lang="en-US">
|
||||||
<head>
|
<head>
|
||||||
<title>PDFio Programming Manual v1.1</title>
|
<title>PDFio Programming Manual v1.1.3</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
<meta name="generator" content="codedoc v3.7">
|
<meta name="generator" content="codedoc v3.7">
|
||||||
<meta name="author" content="Michael R Sweet">
|
<meta name="author" content="Michael R Sweet">
|
||||||
<meta name="language" content="en-US">
|
<meta name="language" content="en-US">
|
||||||
<meta name="copyright" content="Copyright © 2021-2022 by Michael R Sweet">
|
<meta name="copyright" content="Copyright © 2021-2023 by Michael R Sweet">
|
||||||
<meta name="version" content="1.1">
|
<meta name="version" content="1.1.3">
|
||||||
<style type="text/css"><!--
|
<style type="text/css"><!--
|
||||||
body {
|
body {
|
||||||
background: white;
|
background: white;
|
||||||
@ -245,9 +245,9 @@ span.string {
|
|||||||
<body>
|
<body>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<p><img class="title" src="pdfio-512.png"></p>
|
<p><img class="title" src="pdfio-512.png"></p>
|
||||||
<h1 class="title">PDFio Programming Manual v1.1</h1>
|
<h1 class="title">PDFio Programming Manual v1.1.3</h1>
|
||||||
<p>Michael R Sweet</p>
|
<p>Michael R Sweet</p>
|
||||||
<p>Copyright © 2021-2022 by Michael R Sweet</p>
|
<p>Copyright © 2021-2023 by Michael R Sweet</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="contents">
|
<div class="contents">
|
||||||
<h2 class="title">Contents</h2>
|
<h2 class="title">Contents</h2>
|
||||||
@ -497,7 +497,7 @@ span.string {
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>PDFio is <em>not</em> concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.</p>
|
<p>PDFio is <em>not</em> concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.</p>
|
||||||
<p>PDFio is Copyright © 2021-2022 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.</p>
|
<p>PDFio is Copyright © 2021-2023 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.</p>
|
||||||
<h3 class="title" id="requirements">Requirements</h3>
|
<h3 class="title" id="requirements">Requirements</h3>
|
||||||
<p>PDFio requires the following to build the software:</p>
|
<p>PDFio requires the following to build the software:</p>
|
||||||
<ul>
|
<ul>
|
||||||
@ -1388,7 +1388,7 @@ bool pdfioContentFillAndStroke(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st,
|
|||||||
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
||||||
<h3 class="function"><a id="pdfioContentMatrixConcat">pdfioContentMatrixConcat</a></h3>
|
<h3 class="function"><a id="pdfioContentMatrixConcat">pdfioContentMatrixConcat</a></h3>
|
||||||
<p class="description">Concatenate a matrix to the current graphics
|
<p class="description">Concatenate a matrix to the current graphics
|
||||||
state.</p>
|
state.</p>
|
||||||
<p class="code">
|
<p class="code">
|
||||||
bool pdfioContentMatrixConcat(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, pdfio_matrix_t m);</p>
|
bool pdfioContentMatrixConcat(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, pdfio_matrix_t m);</p>
|
||||||
<h4 class="parameters">Parameters</h4>
|
<h4 class="parameters">Parameters</h4>
|
||||||
@ -1614,6 +1614,9 @@ bool pdfioContentSetDashPattern(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st
|
|||||||
</tbody></table>
|
</tbody></table>
|
||||||
<h4 class="returnvalue">Return Value</h4>
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function sets the stroke pattern when drawing lines. If "on" and "off"
|
||||||
|
are 0, a solid line is drawn.</p>
|
||||||
<h3 class="function"><a id="pdfioContentSetFillColorDeviceCMYK">pdfioContentSetFillColorDeviceCMYK</a></h3>
|
<h3 class="function"><a id="pdfioContentSetFillColorDeviceCMYK">pdfioContentSetFillColorDeviceCMYK</a></h3>
|
||||||
<p class="description">Set device CMYK fill color.</p>
|
<p class="description">Set device CMYK fill color.</p>
|
||||||
<p class="code">
|
<p class="code">
|
||||||
@ -2301,6 +2304,7 @@ my_dict_cb(pdfio_dict_t *dict, const char *key, void *cb_data)
|
|||||||
... return true to continue or false to stop ...
|
... return true to continue or false to stop ...
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
The iteration continues as long as the callback returns <code>true</code> or all keys
|
The iteration continues as long as the callback returns <code>true</code> or all keys
|
||||||
have been iterated.</p>
|
have been iterated.</p>
|
||||||
<h3 class="function"><a id="pdfioDictSetArray">pdfioDictSetArray</a></h3>
|
<h3 class="function"><a id="pdfioDictSetArray">pdfioDictSetArray</a></h3>
|
||||||
@ -2741,9 +2745,10 @@ written:
|
|||||||
ssize_t
|
ssize_t
|
||||||
output_cb(void *output_ctx, const void *buffer, size_t bytes)
|
output_cb(void *output_ctx, const void *buffer, size_t bytes)
|
||||||
{
|
{
|
||||||
// Write buffer to output and return the number of bytes written
|
// Write buffer to output and return the number of bytes written
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
The "version" argument specifies the PDF version number for the file or
|
The "version" argument specifies the PDF version number for the file or
|
||||||
<code>NULL</code> for the default ("2.0").<br>
|
<code>NULL</code> for the default ("2.0").<br>
|
||||||
<br>
|
<br>
|
||||||
@ -3152,7 +3157,7 @@ double pdfioImageGetWidth(<a href="#pdfio_obj_t">pdfio_obj_t</a> *obj);</p>
|
|||||||
<p class="description">Width in columns</p>
|
<p class="description">Width in columns</p>
|
||||||
<h3 class="function"><a id="pdfioObjClose">pdfioObjClose</a></h3>
|
<h3 class="function"><a id="pdfioObjClose">pdfioObjClose</a></h3>
|
||||||
<p class="description">Close an object, writing any data as needed to the PDF
|
<p class="description">Close an object, writing any data as needed to the PDF
|
||||||
file.</p>
|
file.</p>
|
||||||
<p class="code">
|
<p class="code">
|
||||||
bool pdfioObjClose(<a href="#pdfio_obj_t">pdfio_obj_t</a> *obj);</p>
|
bool pdfioObjClose(<a href="#pdfio_obj_t">pdfio_obj_t</a> *obj);</p>
|
||||||
<h4 class="parameters">Parameters</h4>
|
<h4 class="parameters">Parameters</h4>
|
||||||
@ -3413,6 +3418,13 @@ bool pdfioStreamGetToken(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, char
|
|||||||
</tbody></table>
|
</tbody></table>
|
||||||
<h4 class="returnvalue">Return Value</h4>
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
<p class="description"><code>true</code> on success, <code>false</code> on EOF</p>
|
<p class="description"><code>true</code> on success, <code>false</code> on EOF</p>
|
||||||
|
<h4 class="discussion">Discussion</h4>
|
||||||
|
<p class="discussion">This function reads a single PDF token from a stream. Operator tokens,
|
||||||
|
boolean values, and numbers are returned as-is in the provided string buffer.
|
||||||
|
String values start with the opening parenthesis ('(') but have all escaping
|
||||||
|
resolved and the terminating parenthesis removed. Hexadecimal string values
|
||||||
|
start with the opening angle bracket ('<') and have all whitespace and the
|
||||||
|
terminating angle bracket removed.</p>
|
||||||
<h3 class="function"><a id="pdfioStreamPeek">pdfioStreamPeek</a></h3>
|
<h3 class="function"><a id="pdfioStreamPeek">pdfioStreamPeek</a></h3>
|
||||||
<p class="description">Peek at data in a stream.</p>
|
<p class="description">Peek at data in a stream.</p>
|
||||||
<p class="code">
|
<p class="code">
|
||||||
|
@ -15,7 +15,7 @@ goals of pdfio are:
|
|||||||
PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF
|
PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF
|
||||||
RIP or viewer could be written using it.
|
RIP or viewer could be written using it.
|
||||||
|
|
||||||
PDFio is Copyright © 2021-2022 by Michael R Sweet and is licensed under the
|
PDFio is Copyright © 2021-2023 by Michael R Sweet and is licensed under the
|
||||||
Apache License Version 2.0 with an (optional) exception to allow linking against
|
Apache License Version 2.0 with an (optional) exception to allow linking against
|
||||||
GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
||||||
|
|
||||||
|
@ -375,9 +375,9 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
|||||||
if (whence != SEEK_END && offset >= pdf->bufpos && offset < (pdf->bufpos + pdf->bufend - pdf->buffer))
|
if (whence != SEEK_END && offset >= pdf->bufpos && offset < (pdf->bufpos + pdf->bufend - pdf->buffer))
|
||||||
{
|
{
|
||||||
// Yes, seek within existing buffer...
|
// Yes, seek within existing buffer...
|
||||||
pdf->bufptr = pdf->buffer + offset - pdf->bufpos;
|
pdf->bufptr = pdf->buffer + (offset - pdf->bufpos);
|
||||||
PDFIO_DEBUG("_pdfioFileSeek: Seek within buffer, bufpos=%ld.\n", (long)pdf->bufpos);
|
PDFIO_DEBUG("_pdfioFileSeek: Seek within buffer, bufpos=%ld.\n", (long)pdf->bufpos);
|
||||||
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p, bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufend);
|
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p(<%02X%02X...>), bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufptr[0] & 255, pdf->bufptr[1] & 255, pdf->bufend);
|
||||||
return (offset);
|
return (offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
257
pdfio-content.c
257
pdfio-content.c
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Content helper functions for PDFio.
|
// Content helper functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021 by Michael R Sweet.
|
// Copyright © 2021-2023 by Michael R Sweet.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
@ -670,6 +670,9 @@ pdfioContentSave(pdfio_stream_t *st) // I - Stream
|
|||||||
//
|
//
|
||||||
// 'pdfioContentSetDashPattern()' - Set the stroke pattern.
|
// 'pdfioContentSetDashPattern()' - Set the stroke pattern.
|
||||||
//
|
//
|
||||||
|
// This function sets the stroke pattern when drawing lines. If "on" and "off"
|
||||||
|
// are 0, a solid line is drawn.
|
||||||
|
//
|
||||||
|
|
||||||
bool // O - `true` on success, `false` on failure
|
bool // O - `true` on success, `false` on failure
|
||||||
pdfioContentSetDashPattern(
|
pdfioContentSetDashPattern(
|
||||||
@ -678,7 +681,12 @@ pdfioContentSetDashPattern(
|
|||||||
double on, // I - On length
|
double on, // I - On length
|
||||||
double off) // I - Off length
|
double off) // I - Off length
|
||||||
{
|
{
|
||||||
return (pdfioStreamPrintf(st, "[%g %g] %g d\n", on, off, phase));
|
if (on <= 0.0 && off <= 0.0)
|
||||||
|
return (pdfioStreamPrintf(st, "[] %g d\n", phase));
|
||||||
|
else if (fabs(on - off) < 0.001)
|
||||||
|
return (pdfioStreamPrintf(st, "[%g] %g d\n", on, phase));
|
||||||
|
else
|
||||||
|
return (pdfioStreamPrintf(st, "[%g %g] %g d\n", on, off, phase));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1281,13 +1289,13 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
pdfio_dict_t *dict, // Font dictionary
|
pdfio_dict_t *dict, // Font dictionary
|
||||||
*desc, // Font descriptor
|
*desc, // Font descriptor
|
||||||
*file; // Font file dictionary
|
*file; // Font file dictionary
|
||||||
pdfio_obj_t *obj, // Font object
|
pdfio_obj_t *obj = NULL, // Font object
|
||||||
*desc_obj, // Font descriptor object
|
*desc_obj, // Font descriptor object
|
||||||
*file_obj; // Font file object
|
*file_obj; // Font file object
|
||||||
const char *basefont; // Base font name
|
const char *basefont; // Base font name
|
||||||
pdfio_array_t *bbox; // Font bounding box array
|
pdfio_array_t *bbox; // Font bounding box array
|
||||||
pdfio_stream_t *st; // Font stream
|
pdfio_stream_t *st; // Font stream
|
||||||
int fd; // File
|
int fd = -1; // File
|
||||||
unsigned char buffer[16384]; // Read buffer
|
unsigned char buffer[16384]; // Read buffer
|
||||||
ssize_t bytes; // Bytes read
|
ssize_t bytes; // Bytes read
|
||||||
|
|
||||||
@ -1316,48 +1324,32 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
|
|
||||||
// Create the font file dictionary and object...
|
// Create the font file dictionary and object...
|
||||||
if ((file = pdfioDictCreate(pdf)) == NULL)
|
if ((file = pdfioDictCreate(pdf)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
close(fd);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioDictSetName(file, "Filter", "FlateDecode");
|
pdfioDictSetName(file, "Filter", "FlateDecode");
|
||||||
|
|
||||||
if ((file_obj = pdfioFileCreateObj(pdf, file)) == NULL)
|
if ((file_obj = pdfioFileCreateObj(pdf, file)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
close(fd);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((st = pdfioObjCreateStream(file_obj, PDFIO_FILTER_FLATE)) == NULL)
|
if ((st = pdfioObjCreateStream(file_obj, PDFIO_FILTER_FLATE)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
close(fd);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
|
while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
|
||||||
{
|
{
|
||||||
if (!pdfioStreamWrite(st, buffer, (size_t)bytes))
|
if (!pdfioStreamWrite(st, buffer, (size_t)bytes))
|
||||||
{
|
{
|
||||||
ttfDelete(font);
|
|
||||||
close(fd);
|
|
||||||
pdfioStreamClose(st);
|
pdfioStreamClose(st);
|
||||||
return (NULL);
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
pdfioStreamClose(st);
|
pdfioStreamClose(st);
|
||||||
|
|
||||||
// Create the font descriptor dictionary and object...
|
// Create the font descriptor dictionary and object...
|
||||||
if ((bbox = pdfioArrayCreate(pdf)) == NULL)
|
if ((bbox = pdfioArrayCreate(pdf)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
ttfGetBounds(font, &bounds);
|
ttfGetBounds(font, &bounds);
|
||||||
|
|
||||||
@ -1367,10 +1359,7 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
pdfioArrayAppendNumber(bbox, bounds.top);
|
pdfioArrayAppendNumber(bbox, bounds.top);
|
||||||
|
|
||||||
if ((desc = pdfioDictCreate(pdf)) == NULL)
|
if ((desc = pdfioDictCreate(pdf)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
basefont = pdfioStringCreate(pdf, ttfGetPostScriptName(font));
|
basefont = pdfioStringCreate(pdf, ttfGetPostScriptName(font));
|
||||||
|
|
||||||
@ -1389,59 +1378,71 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
pdfioDictSetNumber(desc, "StemV", ttfGetWeight(font) / 4 + 25);
|
pdfioDictSetNumber(desc, "StemV", ttfGetWeight(font) / 4 + 25);
|
||||||
|
|
||||||
if ((desc_obj = pdfioFileCreateObj(pdf, desc)) == NULL)
|
if ((desc_obj = pdfioFileCreateObj(pdf, desc)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioObjClose(desc_obj);
|
pdfioObjClose(desc_obj);
|
||||||
|
|
||||||
if (unicode)
|
if (unicode)
|
||||||
{
|
{
|
||||||
// Unicode (CID) font...
|
// Unicode (CID) font...
|
||||||
pdfio_dict_t *cid2gid; // CIDToGIDMap dictionary
|
pdfio_dict_t *cid2gid, // CIDToGIDMap dictionary
|
||||||
pdfio_obj_t *cid2gid_obj; // CIDToGIDMap object
|
*to_unicode; // ToUnicode dictionary
|
||||||
|
pdfio_obj_t *cid2gid_obj, // CIDToGIDMap object
|
||||||
|
*to_unicode_obj;// ToUnicode object
|
||||||
size_t i, // Looping var
|
size_t i, // Looping var
|
||||||
|
start, // Start character
|
||||||
num_cmap; // Number of CMap entries
|
num_cmap; // Number of CMap entries
|
||||||
const int *cmap; // CMap entries
|
const int *cmap; // CMap entries
|
||||||
|
int glyph, // Current glyph
|
||||||
|
min_glyph, // First glyph
|
||||||
|
max_glyph; // Last glyph
|
||||||
|
unsigned short glyphs[65536]; // Glyph to Unicode mapping
|
||||||
unsigned char *bufptr, // Pointer into buffer
|
unsigned char *bufptr, // Pointer into buffer
|
||||||
*bufend; // End of buffer
|
*bufend; // End of buffer
|
||||||
pdfio_dict_t *type2; // CIDFontType2 font dictionary
|
pdfio_dict_t *type2; // CIDFontType2 font dictionary
|
||||||
pdfio_obj_t *type2_obj; // CIDFontType2 font object
|
pdfio_obj_t *type2_obj; // CIDFontType2 font object
|
||||||
pdfio_array_t *descendants; // Decendant font list
|
pdfio_array_t *descendants; // Decendant font list
|
||||||
pdfio_dict_t *sidict; // CIDSystemInfo dictionary
|
pdfio_dict_t *sidict; // CIDSystemInfo dictionary
|
||||||
|
pdfio_array_t *w_array, // Width array
|
||||||
|
*temp_array; // Temporary width sub-array
|
||||||
|
int w0, w1; // Widths
|
||||||
|
|
||||||
|
// Create a CIDSystemInfo mapping to Adobe UCS2 v0 (Unicode)
|
||||||
|
if ((sidict = pdfioDictCreate(pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioDictSetString(sidict, "Registry", "Adobe");
|
||||||
|
pdfioDictSetString(sidict, "Ordering", "Identity");
|
||||||
|
pdfioDictSetNumber(sidict, "Supplement", 0);
|
||||||
|
|
||||||
// Create a CIDToGIDMap object for the Unicode font...
|
// Create a CIDToGIDMap object for the Unicode font...
|
||||||
if ((cid2gid = pdfioDictCreate(pdf)) == NULL)
|
if ((cid2gid = pdfioDictCreate(pdf)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
pdfioDictSetName(cid2gid, "Filter", "FlateDecode");
|
pdfioDictSetName(cid2gid, "Filter", "FlateDecode");
|
||||||
#endif // !DEBUG
|
#endif // !DEBUG
|
||||||
|
|
||||||
if ((cid2gid_obj = pdfioFileCreateObj(pdf, cid2gid)) == NULL)
|
if ((cid2gid_obj = pdfioFileCreateObj(pdf, cid2gid)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_NONE)) == NULL)
|
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_NONE)) == NULL)
|
||||||
#else
|
#else
|
||||||
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_FLATE)) == NULL)
|
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_FLATE)) == NULL)
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
cmap = ttfGetCMap(font, &num_cmap);
|
cmap = ttfGetCMap(font, &num_cmap);
|
||||||
|
min_glyph = 65536;
|
||||||
|
max_glyph = 0;
|
||||||
|
memset(glyphs, 0, sizeof(glyphs));
|
||||||
|
|
||||||
|
PDFIO_DEBUG("pdfioFileCreateFontObjFromFile: num_cmap=%u\n", (unsigned)num_cmap);
|
||||||
|
|
||||||
for (i = 0, bufptr = buffer, bufend = buffer + sizeof(buffer); i < num_cmap; i ++)
|
for (i = 0, bufptr = buffer, bufend = buffer + sizeof(buffer); i < num_cmap; i ++)
|
||||||
{
|
{
|
||||||
|
PDFIO_DEBUG("pdfioFileCreateFontObjFromFile: cmap[%u]=%d\n", (unsigned)i, cmap[i]);
|
||||||
if (cmap[i] < 0)
|
if (cmap[i] < 0)
|
||||||
{
|
{
|
||||||
// Map undefined glyph to .notdef...
|
// Map undefined glyph to .notdef...
|
||||||
@ -1453,6 +1454,12 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
// Map to specified glyph...
|
// Map to specified glyph...
|
||||||
*bufptr++ = (unsigned char)(cmap[i] >> 8);
|
*bufptr++ = (unsigned char)(cmap[i] >> 8);
|
||||||
*bufptr++ = (unsigned char)(cmap[i] & 255);
|
*bufptr++ = (unsigned char)(cmap[i] & 255);
|
||||||
|
|
||||||
|
glyphs[cmap[i]] = i;
|
||||||
|
if (cmap[i] < min_glyph)
|
||||||
|
min_glyph = cmap[i];
|
||||||
|
if (cmap[i] > max_glyph)
|
||||||
|
max_glyph = cmap[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufptr >= bufend)
|
if (bufptr >= bufend)
|
||||||
@ -1461,8 +1468,7 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
|
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
|
||||||
{
|
{
|
||||||
pdfioStreamClose(st);
|
pdfioStreamClose(st);
|
||||||
ttfDelete(font);
|
goto done;
|
||||||
return (NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bufptr = buffer;
|
bufptr = buffer;
|
||||||
@ -1475,30 +1481,102 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
|
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
|
||||||
{
|
{
|
||||||
pdfioStreamClose(st);
|
pdfioStreamClose(st);
|
||||||
ttfDelete(font);
|
goto done;
|
||||||
return (NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pdfioStreamClose(st);
|
pdfioStreamClose(st);
|
||||||
|
|
||||||
|
// ToUnicode mapping object
|
||||||
|
to_unicode = pdfioDictCreate(pdf);
|
||||||
|
pdfioDictSetName(to_unicode, "Type", "CMap");
|
||||||
|
pdfioDictSetName(to_unicode, "CMapName", "Adobe-Identity-UCS2");
|
||||||
|
pdfioDictSetDict(to_unicode, "CIDSystemInfo", sidict);
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
|
pdfioDictSetName(to_unicode, "Filter", "FlateDecode");
|
||||||
|
#endif // !DEBUG
|
||||||
|
|
||||||
|
if ((to_unicode_obj = pdfioFileCreateObj(pdf, to_unicode)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
if ((st = pdfioObjCreateStream(to_unicode_obj, PDFIO_FILTER_NONE)) == NULL)
|
||||||
|
#else
|
||||||
|
if ((st = pdfioObjCreateStream(to_unicode_obj, PDFIO_FILTER_FLATE)) == NULL)
|
||||||
|
#endif // DEBUG
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioStreamPuts(st,
|
||||||
|
"stream\n"
|
||||||
|
"/CIDInit /ProcSet findresource begin\n"
|
||||||
|
"12 dict begin\n"
|
||||||
|
"begincmap\n"
|
||||||
|
"/CIDSystemInfo<<\n"
|
||||||
|
"/Registry (Adobe)\n"
|
||||||
|
"/Ordering (UCS2)\n"
|
||||||
|
"/Supplement 0\n"
|
||||||
|
">> def\n"
|
||||||
|
"/CMapName /Adobe-Identity-UCS2 def\n"
|
||||||
|
"/CMapType 2 def\n"
|
||||||
|
"1 begincodespacerange\n"
|
||||||
|
"<0000> <FFFF>\n"
|
||||||
|
"endcodespacerange\n"
|
||||||
|
"1 beginbfrange\n"
|
||||||
|
"<0000> <FFFF> <0000>\n"
|
||||||
|
"endbfrange\n"
|
||||||
|
"endcmap\n"
|
||||||
|
"CMapName currentdict /CMap defineresource pop\n"
|
||||||
|
"end\n"
|
||||||
|
"end\n");
|
||||||
|
|
||||||
|
pdfioStreamClose(st);
|
||||||
|
|
||||||
// Create a CIDFontType2 dictionary for the Unicode font...
|
// Create a CIDFontType2 dictionary for the Unicode font...
|
||||||
if ((type2 = pdfioDictCreate(pdf)) == NULL)
|
if ((type2 = pdfioDictCreate(pdf)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((sidict = pdfioDictCreate(pdf)) == NULL)
|
// Width array
|
||||||
{
|
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
|
||||||
ttfDelete(font);
|
goto done;
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// CIDSystemInfo mapping to Adobe UCS2 v0 (Unicode)
|
for (start = 0, w0 = ttfGetWidth(font, 0), i = 1; i < 65536; start = i, w0 = w1, i ++)
|
||||||
pdfioDictSetString(sidict, "Registry", "Adobe");
|
{
|
||||||
pdfioDictSetString(sidict, "Ordering", "Identity");
|
while (i < 65536 && (w1 = ttfGetWidth(font, i)) == w0)
|
||||||
pdfioDictSetNumber(sidict, "Supplement", 0);
|
i ++;
|
||||||
|
|
||||||
|
if ((i - start) > 1)
|
||||||
|
{
|
||||||
|
// Encode a repeating sequence...
|
||||||
|
pdfioArrayAppendNumber(w_array, start);
|
||||||
|
pdfioArrayAppendNumber(w_array, i - 1);
|
||||||
|
pdfioArrayAppendNumber(w_array, w0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Encode a non-repeating sequence...
|
||||||
|
pdfioArrayAppendNumber(w_array, start);
|
||||||
|
|
||||||
|
if ((temp_array = pdfioArrayCreate(pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioArrayAppendNumber(temp_array, w0);
|
||||||
|
for (w0 = w1, i ++; i < 65536; w0 = w1, i ++)
|
||||||
|
{
|
||||||
|
if ((w1 = ttfGetWidth(font, i)) == w0 && i < 65535)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pdfioArrayAppendNumber(temp_array, w0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 65536)
|
||||||
|
pdfioArrayAppendNumber(temp_array, w0);
|
||||||
|
else
|
||||||
|
i --;
|
||||||
|
|
||||||
|
pdfioArrayAppendArray(w_array, temp_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Then the dictionary for the CID base font...
|
// Then the dictionary for the CID base font...
|
||||||
pdfioDictSetName(type2, "Type", "Font");
|
pdfioDictSetName(type2, "Type", "Font");
|
||||||
@ -1507,56 +1585,41 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
pdfioDictSetDict(type2, "CIDSystemInfo", sidict);
|
pdfioDictSetDict(type2, "CIDSystemInfo", sidict);
|
||||||
pdfioDictSetObj(type2, "CIDToGIDMap", cid2gid_obj);
|
pdfioDictSetObj(type2, "CIDToGIDMap", cid2gid_obj);
|
||||||
pdfioDictSetObj(type2, "FontDescriptor", desc_obj);
|
pdfioDictSetObj(type2, "FontDescriptor", desc_obj);
|
||||||
|
pdfioDictSetArray(type2, "W", w_array);
|
||||||
|
|
||||||
if ((type2_obj = pdfioFileCreateObj(pdf, type2)) == NULL)
|
if ((type2_obj = pdfioFileCreateObj(pdf, type2)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioObjClose(type2_obj);
|
pdfioObjClose(type2_obj);
|
||||||
|
|
||||||
// Create a Type 0 font object...
|
// Create a Type 0 font object...
|
||||||
if ((descendants = pdfioArrayCreate(pdf)) == NULL)
|
if ((descendants = pdfioArrayCreate(pdf)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioArrayAppendObj(descendants, type2_obj);
|
pdfioArrayAppendObj(descendants, type2_obj);
|
||||||
|
|
||||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioDictSetName(dict, "Type", "Font");
|
pdfioDictSetName(dict, "Type", "Font");
|
||||||
pdfioDictSetName(dict, "Subtype", "Type0");
|
pdfioDictSetName(dict, "Subtype", "Type0");
|
||||||
pdfioDictSetName(dict, "BaseFont", basefont);
|
pdfioDictSetName(dict, "BaseFont", basefont);
|
||||||
pdfioDictSetArray(dict, "DescendantFonts", descendants);
|
pdfioDictSetArray(dict, "DescendantFonts", descendants);
|
||||||
pdfioDictSetName(dict, "Encoding", "Identity-H");
|
pdfioDictSetName(dict, "Encoding", "Identity-H");
|
||||||
|
pdfioDictSetObj(dict, "ToUnicode", to_unicode_obj);
|
||||||
|
|
||||||
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
|
if ((obj = pdfioFileCreateObj(pdf, dict)) != NULL)
|
||||||
return (NULL);
|
pdfioObjClose(obj);
|
||||||
|
|
||||||
pdfioObjClose(obj);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Simple (CP1282 or custom encoding) 8-bit font...
|
// Simple (CP1282 or custom encoding) 8-bit font...
|
||||||
if (ttfGetMaxChar(font) >= 255 && !pdf->cp1252_obj && !create_cp1252(pdf))
|
if (ttfGetMaxChar(font) >= 255 && !pdf->cp1252_obj && !create_cp1252(pdf))
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a TrueType font object...
|
// Create a TrueType font object...
|
||||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||||
{
|
goto done;
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioDictSetName(dict, "Type", "Font");
|
pdfioDictSetName(dict, "Type", "Font");
|
||||||
pdfioDictSetName(dict, "Subtype", "TrueType");
|
pdfioDictSetName(dict, "Subtype", "TrueType");
|
||||||
@ -1566,15 +1629,15 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
|
|
||||||
pdfioDictSetObj(dict, "FontDescriptor", desc_obj);
|
pdfioDictSetObj(dict, "FontDescriptor", desc_obj);
|
||||||
|
|
||||||
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
|
if ((obj = pdfioFileCreateObj(pdf, dict)) != NULL)
|
||||||
{
|
pdfioObjClose(obj);
|
||||||
ttfDelete(font);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioObjClose(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
if (fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
|
||||||
ttfDelete(font);
|
ttfDelete(font);
|
||||||
|
|
||||||
return (obj);
|
return (obj);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Public content header file for PDFio.
|
// Public content header file for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021 by Michael R Sweet.
|
// Copyright © 2021-2023 by Michael R Sweet.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
@ -9,18 +9,7 @@
|
|||||||
|
|
||||||
#ifndef PDFIO_CONTENT_H
|
#ifndef PDFIO_CONTENT_H
|
||||||
# define PDFIO_CONTENT_H
|
# define PDFIO_CONTENT_H
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
# include "pdfio.h"
|
# include "pdfio.h"
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// C++ magic...
|
|
||||||
//
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
# endif // __cplusplus
|
# endif // __cplusplus
|
||||||
@ -151,10 +140,6 @@ extern bool pdfioPageDictAddFont(pdfio_dict_t *dict, const char *name, pdfio_ob
|
|||||||
extern bool pdfioPageDictAddImage(pdfio_dict_t *dict, const char *name, pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
extern bool pdfioPageDictAddImage(pdfio_dict_t *dict, const char *name, pdfio_obj_t *obj) _PDFIO_PUBLIC;
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// C++ magic...
|
|
||||||
//
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
}
|
}
|
||||||
# endif // __cplusplus
|
# endif // __cplusplus
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Cryptographic support functions for PDFio.
|
// Cryptographic support functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021 by Michael R Sweet.
|
// Copyright © 2021-2023 by Michael R Sweet.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
@ -446,10 +446,18 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
|
|
||||||
// Initialize the RC4 context using 40 bits of the digest...
|
// Initialize the RC4 context using 40 bits of the digest...
|
||||||
_pdfioCryptoRC4Init(&ctx->rc4, digest, 5);
|
_pdfioCryptoRC4Init(&ctx->rc4, digest, 5);
|
||||||
|
*ivlen = 0;
|
||||||
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
|
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
|
||||||
|
|
||||||
case PDFIO_ENCRYPTION_RC4_128 :
|
|
||||||
case PDFIO_ENCRYPTION_AES_128 :
|
case PDFIO_ENCRYPTION_AES_128 :
|
||||||
|
if (*ivlen < 16)
|
||||||
|
{
|
||||||
|
*ivlen = 0;
|
||||||
|
_pdfioFileError(pdf, "Value too short for AES encryption.");
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
case PDFIO_ENCRYPTION_RC4_128 :
|
||||||
// Copy the key data for the MD5 hash.
|
// Copy the key data for the MD5 hash.
|
||||||
memcpy(data, pdf->file_key, sizeof(pdf->file_key));
|
memcpy(data, pdf->file_key, sizeof(pdf->file_key));
|
||||||
data[16] = (uint8_t)obj->number;
|
data[16] = (uint8_t)obj->number;
|
||||||
|
44
pdfio-file.c
44
pdfio-file.c
@ -1514,6 +1514,7 @@ load_obj_stream(pdfio_obj_t *obj) // I - Object to load
|
|||||||
|
|
||||||
// Skip offset
|
// Skip offset
|
||||||
_pdfioTokenGet(&tb, buffer, sizeof(buffer));
|
_pdfioTokenGet(&tb, buffer, sizeof(buffer));
|
||||||
|
PDFIO_DEBUG("load_obj_stream: %ld at offset %s\n", (long)number, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!buffer[0])
|
if (!buffer[0])
|
||||||
@ -1737,6 +1738,10 @@ load_xref(
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("load_xref: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[0]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
|
||||||
|
if (tb.bufptr && tb.bufptr < tb.bufend && (tb.bufptr[0] == 0x0d || tb.bufptr[0] == 0x0a))
|
||||||
|
tb.bufptr ++; // Skip trailing CR or LF after token
|
||||||
|
|
||||||
_pdfioTokenFlush(&tb);
|
_pdfioTokenFlush(&tb);
|
||||||
|
|
||||||
obj->stream_offset = _pdfioFileTell(pdf);
|
obj->stream_offset = _pdfioFileTell(pdf);
|
||||||
@ -1759,9 +1764,9 @@ load_xref(
|
|||||||
w_2 = w[0];
|
w_2 = w[0];
|
||||||
w_3 = w[0] + w[1];
|
w_3 = w[0] + w[1];
|
||||||
|
|
||||||
if (w[1] == 0 || w[2] > 2 || w[0] > sizeof(buffer) || w[1] > sizeof(buffer) || w[2] > sizeof(buffer) || w_total > sizeof(buffer))
|
if (w[1] == 0 || w[2] > 4 || w[0] > sizeof(buffer) || w[1] > sizeof(buffer) || w[2] > sizeof(buffer) || w_total > sizeof(buffer))
|
||||||
{
|
{
|
||||||
_pdfioFileError(pdf, "Cross-reference stream has invalid W key.");
|
_pdfioFileError(pdf, "Cross-reference stream has invalid W key [%u %u %u].", (unsigned)w[0], (unsigned)w[1], (unsigned)w[2]);
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1801,9 +1806,11 @@ load_xref(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Offset
|
||||||
for (i = 1, offset = buffer[w_2]; i < w[1]; i ++)
|
for (i = 1, offset = buffer[w_2]; i < w[1]; i ++)
|
||||||
offset = (offset << 8) | buffer[w_2 + i];
|
offset = (offset << 8) | buffer[w_2 + i];
|
||||||
|
|
||||||
|
// Generation number
|
||||||
switch (w[2])
|
switch (w[2])
|
||||||
{
|
{
|
||||||
default :
|
default :
|
||||||
@ -1815,6 +1822,19 @@ load_xref(
|
|||||||
case 2 :
|
case 2 :
|
||||||
generation = (buffer[w_3] << 8) | buffer[w_3 + 1];
|
generation = (buffer[w_3] << 8) | buffer[w_3 + 1];
|
||||||
break;
|
break;
|
||||||
|
case 3 :
|
||||||
|
// Issue #46: Stupid Microsoft PDF generator using 3 bytes to
|
||||||
|
// encode 16-bit generation numbers == 0 (probably a lazy coder
|
||||||
|
// stuffing things into an array of 64-bit unsigned integers)
|
||||||
|
generation = (buffer[w_3] << 16) | (buffer[w_3 + 1] << 8) | buffer[w_3 + 2];
|
||||||
|
if (generation > 65535)
|
||||||
|
generation = 65535;
|
||||||
|
break;
|
||||||
|
case 4 : // Even stupider :)
|
||||||
|
generation = (buffer[w_3] << 24) | (buffer[w_3 + 1] << 16) | (buffer[w_3 + 2] << 8) | buffer[w_3 + 3];
|
||||||
|
if (generation > 65535)
|
||||||
|
generation = 65535;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a placeholder for the object in memory...
|
// Create a placeholder for the object in memory...
|
||||||
@ -1846,8 +1866,18 @@ load_xref(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i >= num_sobjs && num_sobjs < (sizeof(sobjs) / sizeof(sobjs[0])))
|
if (i >= num_sobjs)
|
||||||
sobjs[num_sobjs ++] = (size_t)offset;
|
{
|
||||||
|
if (num_sobjs < (sizeof(sobjs) / sizeof(sobjs[0])))
|
||||||
|
{
|
||||||
|
sobjs[num_sobjs ++] = (size_t)offset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Too many object streams.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!current)
|
else if (!current)
|
||||||
{
|
{
|
||||||
@ -1895,12 +1925,12 @@ load_xref(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!strcmp(line, "xref"))
|
else if (!strncmp(line, "xref", 4) && !line[4] || isspace(line[4] & 255))
|
||||||
{
|
{
|
||||||
// Read the xref tables
|
// Read the xref tables
|
||||||
while (_pdfioFileGets(pdf, line, sizeof(line)))
|
while (_pdfioFileGets(pdf, line, sizeof(line)))
|
||||||
{
|
{
|
||||||
if (!strcmp(line, "trailer"))
|
if (!strncmp(line, "trailer", 7) && !line[7] || isspace(line[7] & 255))
|
||||||
break;
|
break;
|
||||||
else if (!line[0])
|
else if (!line[0])
|
||||||
continue;
|
continue;
|
||||||
@ -1965,7 +1995,7 @@ load_xref(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(line, "trailer"))
|
if (strncmp(line, "trailer", 7))
|
||||||
{
|
{
|
||||||
_pdfioFileError(pdf, "Missing trailer.");
|
_pdfioFileError(pdf, "Missing trailer.");
|
||||||
return (false);
|
return (false);
|
||||||
|
@ -420,6 +420,9 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
|||||||
}
|
}
|
||||||
|
|
||||||
ptr += 3;
|
ptr += 3;
|
||||||
|
while (*ptr && isspace(*ptr & 255))
|
||||||
|
ptr ++;
|
||||||
|
|
||||||
_pdfioFileConsume(obj->pdf, (size_t)(ptr - line));
|
_pdfioFileConsume(obj->pdf, (size_t)(ptr - line));
|
||||||
|
|
||||||
// Then grab the object value...
|
// Then grab the object value...
|
||||||
@ -438,11 +441,15 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[0]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
|
||||||
|
if (tb.bufptr && tb.bufptr < tb.bufend && (tb.bufptr[0] == 0x0d || tb.bufptr[0] == 0x0a))
|
||||||
|
tb.bufptr ++; // Skip trailing CR or LF after token
|
||||||
|
|
||||||
_pdfioTokenFlush(&tb);
|
_pdfioTokenFlush(&tb);
|
||||||
|
|
||||||
if (!strcmp(line, "stream"))
|
if (!strcmp(line, "stream"))
|
||||||
{
|
{
|
||||||
// Yes, save its location...
|
// Yes, this is an embedded stream so save its location...
|
||||||
obj->stream_offset = _pdfioFileTell(obj->pdf);
|
obj->stream_offset = _pdfioFileTell(obj->pdf);
|
||||||
PDFIO_DEBUG("_pdfioObjLoad: stream_offset=%lu.\n", (unsigned long)obj->stream_offset);
|
PDFIO_DEBUG("_pdfioObjLoad: stream_offset=%lu.\n", (unsigned long)obj->stream_offset);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Private header file for PDFio.
|
// Private header file for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2022 by Michael R Sweet.
|
// Copyright © 2021-2023 by Michael R Sweet.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
@ -9,41 +9,22 @@
|
|||||||
|
|
||||||
#ifndef PDFIO_PRIVATE_H
|
#ifndef PDFIO_PRIVATE_H
|
||||||
# define PDFIO_PRIVATE_H
|
# define PDFIO_PRIVATE_H
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
# ifdef _WIN32
|
# ifdef _WIN32
|
||||||
/*
|
# define _CRT_SECURE_NO_WARNINGS // Disable bogus VS warnings/errors...
|
||||||
* Disable bogus VS warnings/errors...
|
|
||||||
*/
|
|
||||||
|
|
||||||
# define _CRT_SECURE_NO_WARNINGS
|
|
||||||
# endif // _WIN32
|
# endif // _WIN32
|
||||||
|
|
||||||
# include "pdfio.h"
|
# include "pdfio.h"
|
||||||
# include <stdarg.h>
|
# include <stdarg.h>
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
# include <string.h>
|
# include <string.h>
|
||||||
|
# include <ctype.h>
|
||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
# include <inttypes.h>
|
# include <inttypes.h>
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
# ifdef _WIN32
|
# ifdef _WIN32
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
# include <direct.h>
|
# include <direct.h>
|
||||||
|
# include <windows.h> // GetTempPathA
|
||||||
/*
|
# define access _access // Map standard POSIX/C99 names
|
||||||
* Microsoft renames the POSIX functions to _name, and introduces
|
|
||||||
* a broken compatibility layer using the original names. As a result,
|
|
||||||
* random crashes can occur when, for example, strdup() allocates memory
|
|
||||||
* from a different heap than used by malloc() and free().
|
|
||||||
*
|
|
||||||
* To avoid moronic problems like this, we #define the POSIX function
|
|
||||||
* names to the corresponding non-standard Microsoft names.
|
|
||||||
*/
|
|
||||||
|
|
||||||
# define access _access
|
|
||||||
# define close _close
|
# define close _close
|
||||||
# define fileno _fileno
|
# define fileno _fileno
|
||||||
# define lseek _lseek
|
# define lseek _lseek
|
||||||
@ -56,25 +37,18 @@
|
|||||||
# define unlink _unlink
|
# define unlink _unlink
|
||||||
# define vsnprintf _vsnprintf
|
# define vsnprintf _vsnprintf
|
||||||
# define write _write
|
# define write _write
|
||||||
|
# define F_OK 00 // POSIX parameters/flags
|
||||||
/*
|
|
||||||
* Map various parameters for POSIX...
|
|
||||||
*/
|
|
||||||
|
|
||||||
# define F_OK 00
|
|
||||||
# define W_OK 02
|
# define W_OK 02
|
||||||
# define R_OK 04
|
# define R_OK 04
|
||||||
# define O_RDONLY _O_RDONLY
|
# define O_RDONLY _O_RDONLY // Map standard POSIX open flags
|
||||||
# define O_WRONLY _O_WRONLY
|
# define O_WRONLY _O_WRONLY
|
||||||
# define O_CREAT _O_CREAT
|
# define O_CREAT _O_CREAT
|
||||||
# define O_TRUNC _O_TRUNC
|
# define O_TRUNC _O_TRUNC
|
||||||
# define O_BINARY _O_BINARY
|
# define O_BINARY _O_BINARY
|
||||||
# else // !_WIN32
|
# else // !_WIN32
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
# define O_BINARY 0
|
# define O_BINARY 0 // Map Windows-specific open flag
|
||||||
# endif // _WIN32
|
# endif // _WIN32
|
||||||
# include <string.h>
|
|
||||||
# include <ctype.h>
|
|
||||||
# include <zlib.h>
|
# include <zlib.h>
|
||||||
|
|
||||||
|
|
||||||
@ -411,4 +385,5 @@ extern void _pdfioValueDelete(_pdfio_value_t *v) _PDFIO_INTERNAL;
|
|||||||
extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
|
extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
|
||||||
extern bool _pdfioValueWrite(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_value_t *v, off_t *length) _PDFIO_INTERNAL;
|
extern bool _pdfioValueWrite(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_value_t *v, off_t *length) _PDFIO_INTERNAL;
|
||||||
|
|
||||||
|
|
||||||
#endif // !PDFIO_PRIVATE_H
|
#endif // !PDFIO_PRIVATE_H
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// SHA-256 functions for PDFio.
|
// SHA-256 functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021 by Michael R Sweet.
|
// Copyright © 2021-2023 by Michael R Sweet.
|
||||||
// Copyright © 2011 IETF Trust and the persons identified as authors of the
|
// Copyright © 2011 IETF Trust and the persons identified as authors of the
|
||||||
// code. All rights reserved.
|
// code. All rights reserved.
|
||||||
//
|
//
|
||||||
@ -217,7 +217,7 @@ _pdfioCryptoSHA256Append(_pdfio_sha256_t *context, const uint8_t *message_array,
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
_pdfioCryptoSHA256Finish(_pdfio_sha256_t *context,
|
_pdfioCryptoSHA256Finish(_pdfio_sha256_t *context,
|
||||||
uint8_t Message_Digest[SHA256HashSize])
|
uint8_t *Message_Digest)
|
||||||
{
|
{
|
||||||
SHA224_256ResultN(context, Message_Digest, SHA256HashSize);
|
SHA224_256ResultN(context, Message_Digest, SHA256HashSize);
|
||||||
}
|
}
|
||||||
|
@ -452,6 +452,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfioStreamOpen: ivlen=%d\n", (int)ivlen);
|
||||||
if (ivlen > 0)
|
if (ivlen > 0)
|
||||||
_pdfioFileConsume(st->pdf, ivlen);
|
_pdfioFileConsume(st->pdf, ivlen);
|
||||||
|
|
||||||
@ -464,11 +465,19 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
// Try to decode/decompress the contents of this object...
|
// Try to decode/decompress the contents of this object...
|
||||||
const char *filter = pdfioDictGetName(dict, "Filter");
|
const char *filter = pdfioDictGetName(dict, "Filter");
|
||||||
// Filter value
|
// Filter value
|
||||||
|
pdfio_array_t *fa = pdfioDictGetArray(dict, "Filter");
|
||||||
|
// Filter array
|
||||||
|
|
||||||
|
if (!filter && fa && pdfioArrayGetSize(fa) == 1)
|
||||||
|
{
|
||||||
|
// Support single-valued arrays...
|
||||||
|
filter = pdfioArrayGetName(fa, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (!filter)
|
if (!filter)
|
||||||
{
|
{
|
||||||
// No single filter name, do we have a compound filter?
|
// No single filter name, do we have a compound filter?
|
||||||
if (pdfioDictGetArray(dict, "Filter"))
|
if (fa)
|
||||||
{
|
{
|
||||||
// TODO: Implement compound filters...
|
// TODO: Implement compound filters...
|
||||||
_pdfioFileError(st->pdf, "Unsupported compound stream filter.");
|
_pdfioFileError(st->pdf, "Unsupported compound stream filter.");
|
||||||
@ -559,6 +568,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
else
|
else
|
||||||
st->predictor = _PDFIO_PREDICTOR_NONE;
|
st->predictor = _PDFIO_PREDICTOR_NONE;
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfioStreamOpen: pos=%ld\n", (long)_pdfioFileTell(st->pdf));
|
||||||
if (sizeof(st->cbuffer) > st->remaining)
|
if (sizeof(st->cbuffer) > st->remaining)
|
||||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
||||||
else
|
else
|
||||||
@ -579,12 +589,6 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
st->flate.next_in = (Bytef *)st->cbuffer;
|
||||||
st->flate.avail_in = (uInt)rbytes;
|
st->flate.avail_in = (uInt)rbytes;
|
||||||
|
|
||||||
if (st->cbuffer[0] == 0x0a)
|
|
||||||
{
|
|
||||||
st->flate.next_in ++; // Skip newline
|
|
||||||
st->flate.avail_in --;
|
|
||||||
}
|
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioStreamOpen: avail_in=%u, cbuffer=<%02X%02X%02X%02X%02X%02X%02X%02X...>\n", st->flate.avail_in, st->cbuffer[0], st->cbuffer[1], st->cbuffer[2], st->cbuffer[3], st->cbuffer[4], st->cbuffer[5], st->cbuffer[6], st->cbuffer[7]);
|
PDFIO_DEBUG("_pdfioStreamOpen: avail_in=%u, cbuffer=<%02X%02X%02X%02X%02X%02X%02X%02X...>\n", st->flate.avail_in, st->cbuffer[0], st->cbuffer[1], st->cbuffer[2], st->cbuffer[3], st->cbuffer[4], st->cbuffer[5], st->cbuffer[6], st->cbuffer[7]);
|
||||||
|
|
||||||
if ((status = inflateInit(&(st->flate))) != Z_OK)
|
if ((status = inflateInit(&(st->flate))) != Z_OK)
|
||||||
@ -1008,6 +1012,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
size_t bytes) // I - Number of bytes to read
|
size_t bytes) // I - Number of bytes to read
|
||||||
{
|
{
|
||||||
ssize_t rbytes; // Bytes read
|
ssize_t rbytes; // Bytes read
|
||||||
|
uInt avail_in, avail_out; // Previous flate values
|
||||||
|
|
||||||
|
|
||||||
if (st->filter == PDFIO_FILTER_NONE)
|
if (st->filter == PDFIO_FILTER_NONE)
|
||||||
@ -1060,11 +1065,19 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
st->flate.next_out = (Bytef *)buffer;
|
st->flate.next_out = (Bytef *)buffer;
|
||||||
st->flate.avail_out = (uInt)bytes;
|
st->flate.avail_out = (uInt)bytes;
|
||||||
|
|
||||||
|
avail_in = st->flate.avail_in;
|
||||||
|
avail_out = st->flate.avail_out;
|
||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
else if (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out)
|
||||||
|
{
|
||||||
|
_pdfioFileError(st->pdf, "Corrupt stream data.");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
return (st->flate.next_out - (Bytef *)buffer);
|
return (st->flate.next_out - (Bytef *)buffer);
|
||||||
}
|
}
|
||||||
@ -1113,12 +1126,15 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
st->flate.avail_in = (uInt)rbytes;
|
st->flate.avail_in = (uInt)rbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avail_in = st->flate.avail_in;
|
||||||
|
avail_out = st->flate.avail_out;
|
||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
else if (status == Z_STREAM_END)
|
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1180,12 +1196,15 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
st->flate.avail_in = (uInt)rbytes;
|
st->flate.avail_in = (uInt)rbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avail_in = st->flate.avail_in;
|
||||||
|
avail_out = st->flate.avail_out;
|
||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
else if (status == Z_STREAM_END)
|
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,6 +495,13 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
*bufptr++ = (char)ch;
|
*bufptr++ = (char)ch;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (ch == '>')
|
||||||
|
{
|
||||||
|
// Issue #46: Empty hex string from Microsoft PDF generator; treat as
|
||||||
|
// empty literal string...
|
||||||
|
*buffer = '(';
|
||||||
|
break;
|
||||||
|
}
|
||||||
else if (!isspace(ch & 255) && !isxdigit(ch & 255))
|
else if (!isspace(ch & 255) && !isxdigit(ch & 255))
|
||||||
{
|
{
|
||||||
_pdfioFileError(tb->pdf, "Syntax error: '<%c'", ch);
|
_pdfioFileError(tb->pdf, "Syntax error: '<%c'", ch);
|
||||||
|
@ -383,7 +383,10 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen);
|
ivlen = v->value.binary.datalen;
|
||||||
|
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL)
|
||||||
|
return (false);
|
||||||
|
|
||||||
templen = (cb)(&ctx, temp, v->value.binary.data + ivlen, v->value.binary.datalen - ivlen);
|
templen = (cb)(&ctx, temp, v->value.binary.data + ivlen, v->value.binary.datalen - ivlen);
|
||||||
|
|
||||||
// Copy the decrypted string back to the value and adjust the length...
|
// Copy the decrypted string back to the value and adjust the length...
|
||||||
|
24
pdfio.h
24
pdfio.h
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Public header file for PDFio.
|
// Public header file for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021-2022 by Michael R Sweet.
|
// Copyright © 2021-2023 by Michael R Sweet.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
@ -9,27 +9,23 @@
|
|||||||
|
|
||||||
#ifndef PDFIO_H
|
#ifndef PDFIO_H
|
||||||
# define PDFIO_H
|
# define PDFIO_H
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
# include <stdbool.h>
|
# include <stdbool.h>
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <time.h>
|
# include <time.h>
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// C++ magic...
|
|
||||||
//
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
# endif // __cplusplus
|
# endif // __cplusplus
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Version number...
|
||||||
|
//
|
||||||
|
|
||||||
|
# define PDFIO_VERSION "1.1.4"
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Visibility and other annotations...
|
// Visibility and other annotations...
|
||||||
//
|
//
|
||||||
@ -244,10 +240,6 @@ extern char *pdfioStringCreate(pdfio_file_t *pdf, const char *s) _PDFIO_PUBLIC
|
|||||||
extern char *pdfioStringCreatef(pdfio_file_t *pdf, const char *format, ...) _PDFIO_FORMAT(2,3) _PDFIO_PUBLIC;
|
extern char *pdfioStringCreatef(pdfio_file_t *pdf, const char *format, ...) _PDFIO_FORMAT(2,3) _PDFIO_PUBLIC;
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// C++ magic...
|
|
||||||
//
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
}
|
}
|
||||||
# endif // __cplusplus
|
# endif // __cplusplus
|
||||||
|
@ -87,7 +87,7 @@
|
|||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@ -101,7 +101,7 @@
|
|||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@ -115,7 +115,7 @@
|
|||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@ -130,7 +130,7 @@
|
|||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
@ -372,7 +372,7 @@
|
|||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 1.1;
|
CURRENT_PROJECT_VERSION = 1.1.2;
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
@ -381,7 +381,6 @@
|
|||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"'PDFIO_VERSION=\"$(CURRENT_PROJECT_VERSION)\"'",
|
|
||||||
);
|
);
|
||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
@ -397,7 +396,7 @@
|
|||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
@ -450,7 +449,7 @@
|
|||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 1.1;
|
CURRENT_PROJECT_VERSION = 1.1.2;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
@ -459,7 +458,6 @@
|
|||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"'PDFIO_VERSION=\"$(CURRENT_PROJECT_VERSION)\"'",
|
|
||||||
);
|
);
|
||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
@ -475,7 +473,7 @@
|
|||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||||
@ -515,7 +513,7 @@
|
|||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio;
|
PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
@ -529,7 +527,7 @@
|
|||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio;
|
PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<metadata>
|
<metadata>
|
||||||
<id>pdfio_native</id>
|
<id>pdfio_native</id>
|
||||||
<title>PDFio Library for VS2019+</title>
|
<title>PDFio Library for VS2019+</title>
|
||||||
<version>1.1.0</version>
|
<version>1.1.4</version>
|
||||||
<authors>Michael R Sweet</authors>
|
<authors>Michael R Sweet</authors>
|
||||||
<owners>michaelrsweet</owners>
|
<owners>michaelrsweet</owners>
|
||||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
||||||
<tags>pdf file native</tags>
|
<tags>pdf file native</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="pdfio_native.redist" version="1.1.0" />
|
<dependency id="pdfio_native.redist" version="1.1.4" />
|
||||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<metadata>
|
<metadata>
|
||||||
<id>pdfio_native.redist</id>
|
<id>pdfio_native.redist</id>
|
||||||
<title>PDFio Library for VS2019+</title>
|
<title>PDFio Library for VS2019+</title>
|
||||||
<version>1.1.0</version>
|
<version>1.1.4</version>
|
||||||
<authors>Michael R Sweet</authors>
|
<authors>Michael R Sweet</authors>
|
||||||
<owners>michaelrsweet</owners>
|
<owners>michaelrsweet</owners>
|
||||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||||
@ -15,6 +15,9 @@
|
|||||||
<summary>PDFio is a simple C library for reading and writing PDF files. This package provides the redistributable content for the PDFio library. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
<summary>PDFio is a simple C library for reading and writing PDF files. This package provides the redistributable content for the PDFio library. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
||||||
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
||||||
<tags>pdf file native</tags>
|
<tags>pdf file native</tags>
|
||||||
|
<dependencies>
|
||||||
|
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||||
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
<file src="doc\pdfio-128.png" target="build\native" />
|
<file src="doc\pdfio-128.png" target="build\native" />
|
||||||
|
72
testpdfio.c
72
testpdfio.c
@ -44,7 +44,7 @@ static int verify_image(pdfio_file_t *pdf, size_t number);
|
|||||||
static int write_alpha_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
static int write_alpha_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
||||||
static int write_color_patch(pdfio_stream_t *st, bool device);
|
static int write_color_patch(pdfio_stream_t *st, bool device);
|
||||||
static int write_color_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
static int write_color_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
||||||
static int write_font_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font, bool unicode);
|
static int write_font_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font, const char *textfontfile, bool unicode);
|
||||||
static int write_header_footer(pdfio_stream_t *st, const char *title, int number);
|
static int write_header_footer(pdfio_stream_t *st, const char *title, int number);
|
||||||
static pdfio_obj_t *write_image_object(pdfio_file_t *pdf, _pdfio_predictor_t predictor);
|
static pdfio_obj_t *write_image_object(pdfio_file_t *pdf, _pdfio_predictor_t predictor);
|
||||||
static int write_images_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
static int write_images_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
||||||
@ -406,7 +406,7 @@ do_test_file(const char *filename, // I - PDF filename
|
|||||||
|
|
||||||
filter = pdfioDictGetName(dict, "Filter");
|
filter = pdfioDictGetName(dict, "Filter");
|
||||||
|
|
||||||
if ((st = pdfioObjOpenStream(obj, (filter && !strcmp(filter, "FlateDecode")) ? PDFIO_FILTER_FLATE : PDFIO_FILTER_NONE)) == NULL)
|
if ((st = pdfioObjOpenStream(obj, filter && !strcmp(filter, "FlateDecode"))) == NULL)
|
||||||
{
|
{
|
||||||
_pdfioValueDebug(&obj->value, stdout);
|
_pdfioValueDebug(&obj->value, stdout);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
@ -455,7 +455,7 @@ do_test_file(const char *filename, // I - PDF filename
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" Page #%d is %gx%g.\n", (int)n + 1, media_box.x2, media_box.y2);
|
printf(" Page #%d (obj %d) is %gx%g.\n", (int)n + 1, (int)pdfioObjGetNumber(obj), media_box.x2, media_box.y2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2229,14 +2229,19 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
|
|||||||
//
|
//
|
||||||
|
|
||||||
static int // O - 1 on failure, 0 on success
|
static int // O - 1 on failure, 0 on success
|
||||||
write_font_test(pdfio_file_t *pdf, // I - PDF file
|
write_font_test(
|
||||||
int number, // I - Page number
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
pdfio_obj_t *font, // I - Page number font
|
int number, // I - Page number
|
||||||
bool unicode) // I - Use Unicode font?
|
pdfio_obj_t *font, // I - Page number font
|
||||||
|
const char *textfontfile, // I - Text font file
|
||||||
|
bool unicode) // I - Use Unicode font?
|
||||||
{
|
{
|
||||||
pdfio_dict_t *dict; // Page dictionary
|
pdfio_dict_t *dict; // Page dictionary
|
||||||
pdfio_stream_t *st; // Page contents stream
|
pdfio_stream_t *st; // Page contents stream
|
||||||
pdfio_obj_t *opensans; // OpenSans-Regular font
|
pdfio_obj_t *textfont; // Text font
|
||||||
|
char title[256], // Page title
|
||||||
|
textname[256], // Name of text font
|
||||||
|
*ptr; // Pointer into name
|
||||||
int i; // Looping var
|
int i; // Looping var
|
||||||
static const char * const welcomes[] =// "Welcome" in many languages
|
static const char * const welcomes[] =// "Welcome" in many languages
|
||||||
{
|
{
|
||||||
@ -2387,28 +2392,16 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
|
|||||||
"Märr-ŋamathirri",
|
"Märr-ŋamathirri",
|
||||||
"Ẹ ku abọ",
|
"Ẹ ku abọ",
|
||||||
"Kíimak 'oolal",
|
"Kíimak 'oolal",
|
||||||
"Ngiyakwemukela"
|
"Ngiyakwemukela",
|
||||||
|
"いらっしゃいませ"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
printf("pdfioFileCreateFontObjFromFile(%s): ", textfontfile);
|
||||||
if (unicode)
|
if ((textfont = pdfioFileCreateFontObjFromFile(pdf, textfontfile, unicode)) != NULL)
|
||||||
{
|
puts("PASS");
|
||||||
fputs("pdfioFileCreateFontObjFromFile(NotoSansJP-Regular.otf): ", stdout);
|
|
||||||
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/NotoSansJP-Regular.otf", true)) != NULL)
|
|
||||||
puts("PASS");
|
|
||||||
else
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
#endif // 0
|
return (1);
|
||||||
{
|
|
||||||
fputs("pdfioFileCreateFontObjFromFile(OpenSans-Regular.ttf): ", stdout);
|
|
||||||
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/OpenSans-Regular.ttf", unicode)) != NULL)
|
|
||||||
puts("PASS");
|
|
||||||
else
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("pdfioDictCreate: ", stdout);
|
fputs("pdfioDictCreate: ", stdout);
|
||||||
if ((dict = pdfioDictCreate(pdf)) != NULL)
|
if ((dict = pdfioDictCreate(pdf)) != NULL)
|
||||||
@ -2423,7 +2416,7 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
|
|||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
fputs("pdfioPageDictAddFont(F2): ", stdout);
|
fputs("pdfioPageDictAddFont(F2): ", stdout);
|
||||||
if (pdfioPageDictAddFont(dict, "F2", opensans))
|
if (pdfioPageDictAddFont(dict, "F2", textfont))
|
||||||
puts("PASS");
|
puts("PASS");
|
||||||
else
|
else
|
||||||
return (1);
|
return (1);
|
||||||
@ -2435,7 +2428,21 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
|
|||||||
else
|
else
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (write_header_footer(st, unicode ? "Unicode TrueType Font Test" : "CP1252 TrueType Font Test", number))
|
if ((ptr = strrchr(textfontfile, '/')) != NULL)
|
||||||
|
strncpy(textname, ptr + 1, sizeof(textname) - 1);
|
||||||
|
else
|
||||||
|
strncpy(textname, textfontfile, sizeof(textname) - 1);
|
||||||
|
|
||||||
|
textname[sizeof(textname) - 1] = '\0';
|
||||||
|
if ((ptr = strrchr(textname, '.')) != NULL)
|
||||||
|
*ptr = '\0';
|
||||||
|
|
||||||
|
if (unicode)
|
||||||
|
snprintf(title, sizeof(title), "Unicode %s Font Test", textname);
|
||||||
|
else
|
||||||
|
snprintf(title, sizeof(title), "CP1252 %s Font Test", textname);
|
||||||
|
|
||||||
|
if (write_header_footer(st, title, number))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
fputs("pdfioContentTextBegin(): ", stdout);
|
fputs("pdfioContentTextBegin(): ", stdout);
|
||||||
@ -3390,14 +3397,17 @@ write_unit_file(
|
|||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
// Test TrueType fonts...
|
// Test TrueType fonts...
|
||||||
if (write_font_test(outpdf, 9, helvetica, false))
|
if (write_font_test(outpdf, 9, helvetica, "testfiles/OpenSans-Regular.ttf", false))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (write_font_test(outpdf, 10, helvetica, true))
|
if (write_font_test(outpdf, 10, helvetica, "testfiles/OpenSans-Regular.ttf", true))
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
if (write_font_test(outpdf, 11, helvetica, "testfiles/NotoSansJP-Regular.otf", true))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
// Print this text file...
|
// Print this text file...
|
||||||
if (write_text_test(outpdf, 11, helvetica, "README.md"))
|
if (write_text_test(outpdf, 12, helvetica, "README.md"))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
fputs("pdfioFileGetNumPages: ", stdout);
|
fputs("pdfioFileGetNumPages: ", stdout);
|
||||||
|
304
testttf.c
Normal file
304
testttf.c
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
//
|
||||||
|
// Unit test program for TTF library
|
||||||
|
//
|
||||||
|
// https://github.com/michaelrsweet/ttf
|
||||||
|
//
|
||||||
|
// Copyright © 2018-2023 by Michael R Sweet.
|
||||||
|
//
|
||||||
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
|
// information.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// ./testttf [FILENAME]
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "ttf.h"
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Local functions...
|
||||||
|
//
|
||||||
|
|
||||||
|
static void error_cb(void *data, const char *message);
|
||||||
|
static int test_font(const char *filename);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'main()' - Main entry for unit tests.
|
||||||
|
//
|
||||||
|
|
||||||
|
int // O - Exit status
|
||||||
|
main(int argc, // I - Number of command-line arguments
|
||||||
|
char *argv[]) // I - Command-line arguments
|
||||||
|
{
|
||||||
|
int i; // Looping var
|
||||||
|
int errors = 0; // Number of errors
|
||||||
|
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
{
|
||||||
|
for (i = 1; i < argc; i ++)
|
||||||
|
errors += test_font(argv[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Test with the bundled TrueType files...
|
||||||
|
errors += test_font("testfiles/OpenSans-Bold.ttf");
|
||||||
|
errors += test_font("testfiles/OpenSans-Regular.ttf");
|
||||||
|
errors += test_font("testfiles/NotoSansJP-Regular.otf");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errors)
|
||||||
|
puts("\nALL TESTS PASSED");
|
||||||
|
else
|
||||||
|
printf("\n%d TEST(S) FAILED\n", errors);
|
||||||
|
|
||||||
|
return (errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'error_cb()' - Error callback.
|
||||||
|
//
|
||||||
|
|
||||||
|
static void
|
||||||
|
error_cb(void *data, // I - User data (not used)
|
||||||
|
const char *message) // I - Message string
|
||||||
|
{
|
||||||
|
fprintf(stderr, "FAIL (%s)\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'test_font()' - Test a font file.
|
||||||
|
//
|
||||||
|
|
||||||
|
static int // O - Number of errors
|
||||||
|
test_font(const char *filename) // I - Font filename
|
||||||
|
{
|
||||||
|
int i, // Looping var
|
||||||
|
errors = 0; // Number of errors
|
||||||
|
ttf_t *font; // Font
|
||||||
|
const char *value; // Font (string) value
|
||||||
|
int intvalue; // Font (integer) value
|
||||||
|
float realvalue; // Font (real) value
|
||||||
|
ttf_rect_t bounds; // Bounds
|
||||||
|
ttf_rect_t extents; // Extents
|
||||||
|
size_t num_fonts; // Number of fonts
|
||||||
|
ttf_style_t style; // Font style
|
||||||
|
ttf_weight_t weight; // Font weight
|
||||||
|
static const char * const stretches[] =
|
||||||
|
{ // Font stretch strings
|
||||||
|
"TTF_STRETCH_NORMAL", // normal
|
||||||
|
"TTF_STRETCH_ULTRA_CONDENSED", // ultra-condensed
|
||||||
|
"TTF_STRETCH_EXTRA_CONDENSED", // extra-condensed
|
||||||
|
"TTF_STRETCH_CONDENSED", // condensed
|
||||||
|
"TTF_STRETCH_SEMI_CONDENSED", // semi-condensed
|
||||||
|
"TTF_STRETCH_SEMI_EXPANDED", // semi-expanded
|
||||||
|
"TTF_STRETCH_EXPANDED", // expanded
|
||||||
|
"TTF_STRETCH_EXTRA_EXPANDED", // extra-expanded
|
||||||
|
"TTF_STRETCH_ULTRA_EXPANDED" // ultra-expanded
|
||||||
|
};
|
||||||
|
static const char * const strings[] = // Test strings
|
||||||
|
{
|
||||||
|
"Hello, World!", // English
|
||||||
|
"مرحبا بالعالم!", // Arabic
|
||||||
|
"Bonjour le monde!", // French
|
||||||
|
"Γειά σου Κόσμε!", // Greek
|
||||||
|
"שלום עולם!", // Hebrew
|
||||||
|
"Привет мир!", // Russian
|
||||||
|
"こんにちは世界!" // Japanese
|
||||||
|
};
|
||||||
|
static const char * const styles[] = // Font style names
|
||||||
|
{
|
||||||
|
"TTF_STYLE_NORMAL",
|
||||||
|
"TTF_STYLE_ITALIC",
|
||||||
|
"TTF_STYLE_OBLIQUE"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
printf("ttfCreate(\"%s\"): ", filename);
|
||||||
|
if ((font = ttfCreate(filename, 0, error_cb, NULL)) != NULL)
|
||||||
|
puts("PASS");
|
||||||
|
else
|
||||||
|
errors ++;
|
||||||
|
|
||||||
|
fputs("ttfGetAscent: ", stdout);
|
||||||
|
if ((intvalue = ttfGetAscent(font)) > 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%d)\n", intvalue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%d)\n", intvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetBounds: ", stdout);
|
||||||
|
if (ttfGetBounds(font, &bounds))
|
||||||
|
{
|
||||||
|
printf("PASS (%g %g %g %g)\n", bounds.left, bounds.bottom, bounds.right, bounds.top);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetCapHeight: ", stdout);
|
||||||
|
if ((intvalue = ttfGetCapHeight(font)) > 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%d)\n", intvalue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%d)\n", intvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetCopyright: ", stdout);
|
||||||
|
if ((value = ttfGetCopyright(font)) != NULL)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("WARNING (no copyright found)");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (int)(sizeof(strings) / sizeof(strings[0])); i ++)
|
||||||
|
{
|
||||||
|
printf("ttfGetExtents(\"%s\"): ", strings[i]);
|
||||||
|
if (ttfGetExtents(font, 12.0f, strings[i], &extents))
|
||||||
|
{
|
||||||
|
printf("PASS (%.1f %.1f %.1f %.1f)\n", extents.left, extents.bottom, extents.right, extents.top);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetFamily: ", stdout);
|
||||||
|
if ((value = ttfGetFamily(font)) != NULL)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetItalicAngle: ", stdout);
|
||||||
|
if ((realvalue = ttfGetItalicAngle(font)) >= -180.0 && realvalue <= 180.0)
|
||||||
|
{
|
||||||
|
printf("PASS (%g)\n", realvalue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%g)\n", realvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetNumFonts: ", stdout);
|
||||||
|
if ((num_fonts = ttfGetNumFonts(font)) > 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%u)\n", (unsigned)num_fonts);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetPostScriptName: ", stdout);
|
||||||
|
if ((value = ttfGetPostScriptName(font)) != NULL)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetStretch: ", stdout);
|
||||||
|
if ((intvalue = (int)ttfGetStretch(font)) >= TTF_STRETCH_NORMAL && intvalue <= TTF_STRETCH_ULTRA_EXPANDED)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", stretches[intvalue]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%d)\n", intvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetStyle: ", stdout);
|
||||||
|
if ((style = ttfGetStyle(font)) >= TTF_STYLE_NORMAL && style <= TTF_STYLE_ITALIC)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", styles[style]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetVersion: ", stdout);
|
||||||
|
if ((value = ttfGetVersion(font)) != NULL)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetWeight: ", stdout);
|
||||||
|
if ((weight = ttfGetWeight(font)) >= 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%u)\n", (unsigned)weight);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetWidth(' '): ", stdout);
|
||||||
|
if ((intvalue = ttfGetWidth(font, ' ')) > 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%d)\n", intvalue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%d)\n", intvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetXHeight: ", stdout);
|
||||||
|
if ((intvalue = ttfGetXHeight(font)) > 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%d)\n", intvalue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%d)\n", intvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfIsFixedPitch: ", stdout);
|
||||||
|
if (ttfIsFixedPitch(font))
|
||||||
|
puts("PASS (true)");
|
||||||
|
else
|
||||||
|
puts("PASS (false)");
|
||||||
|
|
||||||
|
ttfDelete(font);
|
||||||
|
|
||||||
|
return (errors);
|
||||||
|
}
|
55
ttf.c
55
ttf.c
@ -3,16 +3,12 @@
|
|||||||
//
|
//
|
||||||
// https://github.com/michaelrsweet/ttf
|
// https://github.com/michaelrsweet/ttf
|
||||||
//
|
//
|
||||||
// Copyright © 2018-2021 by Michael R Sweet.
|
// Copyright © 2018-2023 by Michael R Sweet.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define _CRT_SECURE_NO_WARNINGS
|
# define _CRT_SECURE_NO_WARNINGS
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
@ -75,7 +71,7 @@ typedef __int64 ssize_t; // POSIX type not present on Windows...
|
|||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// DEBUG is typically defined for debug builds. TTF_DEBUG maps to printf when
|
// DEBUG is typically defined for debug builds. TTF_DEBUG maps to fprintf when
|
||||||
// DEBUG is defined and is a no-op otherwise...
|
// DEBUG is defined and is a no-op otherwise...
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -452,7 +448,7 @@ ttfCreate(const char *filename, // I - Filename
|
|||||||
font->cap_height = font->ascent;
|
font->cap_height = font->ascent;
|
||||||
|
|
||||||
if (font->x_height == 0)
|
if (font->x_height == 0)
|
||||||
font->x_height = 3 * font->ascent / 5;
|
font->x_height = 3 * font->ascent / 5;
|
||||||
|
|
||||||
// Build a sparse glyph widths table...
|
// Build a sparse glyph widths table...
|
||||||
font->min_char = -1;
|
font->min_char = -1;
|
||||||
@ -481,6 +477,11 @@ ttfCreate(const char *filename, // I - Filename
|
|||||||
else
|
else
|
||||||
font->widths[bin][i & 255] = widths[glyph];
|
font->widths[bin][i & 255] = widths[glyph];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (i >= ' ' && i < 127 && font->widths[0])
|
||||||
|
TTF_DEBUG("ttfCreate: width['%c']=%d(%d)\n", (char)i, font->widths[0][i].width, font->widths[0][i].left_bearing);
|
||||||
|
#endif // DEBUG
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup and return the font...
|
// Cleanup and return the font...
|
||||||
@ -737,17 +738,6 @@ ttfGetFamily(ttf_t *font) // I - Font
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// 'ttfIsFixedPitch()' - Determine whether a font is fixedpitch.
|
|
||||||
//
|
|
||||||
|
|
||||||
bool // O - `true` if fixed pitch, `false` otherwise
|
|
||||||
ttfIsFixedPitch(ttf_t *font) // I - Font
|
|
||||||
{
|
|
||||||
return (font ? font->is_fixed : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'ttfGetItalicAngle()' - Get the italic angle.
|
// 'ttfGetItalicAngle()' - Get the italic angle.
|
||||||
//
|
//
|
||||||
@ -856,13 +846,14 @@ int // O - Width in 1000ths
|
|||||||
ttfGetWidth(ttf_t *font, // I - Font
|
ttfGetWidth(ttf_t *font, // I - Font
|
||||||
int ch) // I - Unicode character
|
int ch) // I - Unicode character
|
||||||
{
|
{
|
||||||
int bin = ch >> 8; // Bin in widths array
|
int bin = ch >> 8; // Bin in widths array
|
||||||
|
|
||||||
|
|
||||||
// Range check input...
|
// Range check input...
|
||||||
if (!font || ch < ' ' || ch == 0x7f)
|
if (!font || ch < ' ' || ch == 0x7f)
|
||||||
return (0);
|
return (0);
|
||||||
else if (font->widths[bin])
|
|
||||||
|
if (font->widths[bin])
|
||||||
return ((int)(1000.0f * font->widths[bin][ch & 255].width / font->units));
|
return ((int)(1000.0f * font->widths[bin][ch & 255].width / font->units));
|
||||||
else if (font->widths[0]) // .notdef
|
else if (font->widths[0]) // .notdef
|
||||||
return ((int)(1000.0f * font->widths[0][0].width / font->units));
|
return ((int)(1000.0f * font->widths[0][0].width / font->units));
|
||||||
@ -882,6 +873,17 @@ ttfGetXHeight(ttf_t *font) // I - Font
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'ttfIsFixedPitch()' - Determine whether a font is fixedpitch.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` if fixed pitch, `false` otherwise
|
||||||
|
ttfIsFixedPitch(ttf_t *font) // I - Font
|
||||||
|
{
|
||||||
|
return (font ? font->is_fixed : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'copy_name()' - Copy a name string from a font.
|
// 'copy_name()' - Copy a name string from a font.
|
||||||
//
|
//
|
||||||
@ -1280,7 +1282,7 @@ read_cmap(ttf_t *font) // I - Font
|
|||||||
|
|
||||||
// Based on the end code of the segent table, allocate space for the
|
// Based on the end code of the segent table, allocate space for the
|
||||||
// uncompressed cmap table...
|
// uncompressed cmap table...
|
||||||
segCount --; // Last segment is not used (sigh)
|
// segCount --; // Last segment is not used (sigh)
|
||||||
|
|
||||||
font->num_cmap = segments[segCount - 1].endCode + 1;
|
font->num_cmap = segments[segCount - 1].endCode + 1;
|
||||||
font->cmap = cmapptr = (int *)malloc(font->num_cmap * sizeof(int));
|
font->cmap = cmapptr = (int *)malloc(font->num_cmap * sizeof(int));
|
||||||
@ -1305,17 +1307,18 @@ read_cmap(ttf_t *font) // I - Font
|
|||||||
{
|
{
|
||||||
// Use an "obscure indexing trick" (words from the spec, not
|
// Use an "obscure indexing trick" (words from the spec, not
|
||||||
// mine) to look up the glyph index...
|
// mine) to look up the glyph index...
|
||||||
temp = segment->idRangeOffset / 2 + ch - segment->startCode + seg - segCount - 1;
|
temp = segment->idRangeOffset / 2 - segCount + (ch - segment->startCode) + (segment - segments);
|
||||||
|
|
||||||
if (temp < 0 || temp >= numGlyphIdArray || !glyphIdArray[temp])
|
TTF_DEBUG("read_cmap: ch=%d, temp=%d\n", ch, temp);
|
||||||
|
if (temp < 0 || temp >= numGlyphIdArray)
|
||||||
glyph = -1;
|
glyph = -1;
|
||||||
else
|
else
|
||||||
glyph = ((glyphIdArray[temp] + segment->idDelta) & 65535) - 1;
|
glyph = (glyphIdArray[temp] + segment->idDelta) & 65535;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Just use idDelta to compute a glyph index...
|
// Just use idDelta to compute a glyph index...
|
||||||
glyph = ((ch + segment->idDelta) & 65535) - 1;
|
glyph = (ch + segment->idDelta) & 65535;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmapptr[ch] = glyph;
|
cmapptr[ch] = glyph;
|
||||||
@ -1582,6 +1585,8 @@ read_hmtx(ttf_t *font, // I - Font
|
|||||||
{
|
{
|
||||||
widths[i].width = (short)read_ushort(font);
|
widths[i].width = (short)read_ushort(font);
|
||||||
widths[i].left_bearing = (short)read_short(font);
|
widths[i].left_bearing = (short)read_short(font);
|
||||||
|
|
||||||
|
TTF_DEBUG("read_hmtx: widths[%d].width=%d, .left_bearing=%d\n", i, widths[i].width, widths[i].left_bearing);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (widths);
|
return (widths);
|
||||||
|
13
ttf.h
13
ttf.h
@ -3,7 +3,7 @@
|
|||||||
//
|
//
|
||||||
// https://github.com/michaelrsweet/ttf
|
// https://github.com/michaelrsweet/ttf
|
||||||
//
|
//
|
||||||
// Copyright © 2018-2021 by Michael R Sweet.
|
// Copyright © 2018-2023 by Michael R Sweet.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
@ -11,17 +11,11 @@
|
|||||||
|
|
||||||
#ifndef TTF_H
|
#ifndef TTF_H
|
||||||
# define TTF_H
|
# define TTF_H
|
||||||
|
|
||||||
//
|
|
||||||
// Include necessary headers...
|
|
||||||
//
|
|
||||||
|
|
||||||
# include <stdbool.h>
|
# include <stdbool.h>
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
|
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
# endif //
|
# endif // __cplusplus
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -89,8 +83,8 @@ extern ttf_t *ttfCreate(const char *filename, size_t idx, ttf_err_cb_t err_cb,
|
|||||||
extern void ttfDelete(ttf_t *font);
|
extern void ttfDelete(ttf_t *font);
|
||||||
extern int ttfGetAscent(ttf_t *font);
|
extern int ttfGetAscent(ttf_t *font);
|
||||||
extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds);
|
extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds);
|
||||||
extern int ttfGetCapHeight(ttf_t *font);
|
|
||||||
extern const int *ttfGetCMap(ttf_t *font, size_t *num_cmap);
|
extern const int *ttfGetCMap(ttf_t *font, size_t *num_cmap);
|
||||||
|
extern int ttfGetCapHeight(ttf_t *font);
|
||||||
extern const char *ttfGetCopyright(ttf_t *font);
|
extern const char *ttfGetCopyright(ttf_t *font);
|
||||||
extern int ttfGetDescent(ttf_t *font);
|
extern int ttfGetDescent(ttf_t *font);
|
||||||
extern ttf_rect_t *ttfGetExtents(ttf_t *font, float size, const char *s, ttf_rect_t *extents);
|
extern ttf_rect_t *ttfGetExtents(ttf_t *font, float size, const char *s, ttf_rect_t *extents);
|
||||||
@ -112,5 +106,4 @@ extern bool ttfIsFixedPitch(ttf_t *font);
|
|||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
}
|
}
|
||||||
# endif // __cplusplus
|
# endif // __cplusplus
|
||||||
|
|
||||||
#endif // !TTF_H
|
#endif // !TTF_H
|
||||||
|
Reference in New Issue
Block a user