33 Commits

Author SHA1 Message Date
9fec2195d0 Update changelog. 2023-11-15 10:14:02 -05:00
8ccbdaed94 Update documentation. 2023-11-15 09:28:57 -05:00
4804db38a5 Fix missing ivlen initializer for 40-bit RC4 (Issue #51) 2023-11-15 08:43:07 -05:00
ddd984215a Save work (debug printfs, etc.) 2023-11-15 08:38:47 -05:00
efe7c01015 Fix typo and 'make debug'. 2023-11-14 18:38:26 -05:00
600fa4ce59 Fix Unicode font handling (Issue #16) 2023-11-14 18:19:34 -05:00
688810f143 Save work. 2023-11-13 16:18:02 -05:00
858cc101b6 Save work. 2023-11-13 13:39:06 -05:00
43114f43bf Bump version. 2023-10-10 10:22:27 -04:00
c4abceef79 Make Visual Studio compiler happy. 2023-10-10 07:24:27 -04:00
2e91e05d7b Allow "compound" filters that consist of a single named filter (Issue #47) 2023-10-10 07:14:12 -04:00
7e3db6b639 Merge pull request #48 from crystalidea/master
added windows.h header for GetTempPathA
2023-10-10 07:07:46 -04:00
acb6b66bdb added windows.h header for GetTempPathA 2023-10-10 09:12:03 +02:00
b0a66eef78 Fix reading of PDF files from Crystal Reports (Issue #45) 2023-10-09 10:04:20 -04:00
ed88322496 Debug logging, work in progress for Unicode text support. 2023-10-07 12:05:18 -04:00
59959bf0e5 Merge TTF changes to fix off-by-one error. 2023-10-06 16:44:20 -04:00
19c45871fa Update pdfioContentSetDashPattern to support setting solid line styles (Issue #41) 2023-10-06 15:47:27 -04:00
b0e4646f9d Rework CR/LF skip code to be more consistent. 2023-10-06 14:41:55 -04:00
12ef2fe2c3 Remove LGTM badges. 2023-10-06 14:40:40 -04:00
4630060ee7 Update security reporting and contribution text. 2023-10-06 14:40:28 -04:00
74a6fb1860 Get rid of superfluous comments. 2023-10-06 14:40:08 -04:00
a3ea0a99ff Cleanup spacing and comments. 2023-10-06 14:39:42 -04:00
fdfa700442 Update ignored files. 2023-10-06 14:39:10 -04:00
d759baf11e Bump version and put PDFIO_VERSION definition in the pdfio.h header. 2023-10-06 14:38:38 -04:00
7f6ffcda22 Fix a couple issues with parsing PDF files produced by Microsoft Reporting
Services (Issue #46)

- Odd cross-reference stream containing 3-byte generation number field for this
  16-bit value
- Odd empty hex strings
2023-10-06 10:46:30 -04:00
87ca4db73f Clean up private header. 2023-10-02 05:27:40 -04:00
a83f7f50ff Allow extra whitespace/newlines after stream tokens (Issue #40) 2023-10-02 05:06:33 -04:00
6a4ce57d09 Bump versions for Mac/Windows project files. 2023-03-20 10:40:25 -04:00
d4c594cec4 Bump copyright in readme. 2023-03-20 10:22:19 -04:00
35c674b633 Fix another build issue. 2023-03-20 10:11:05 -04:00
97d4955666 Fix potential denial-of-service in flate stream code. 2023-03-20 09:27:19 -04:00
e138232a93 Fix build error due to mismatched function declarations. 2023-03-20 08:19:31 -04:00
8d8225f4a1 Fix release date. 2023-02-07 17:10:48 -05:00
28 changed files with 645 additions and 198 deletions

3
.gitignore vendored
View File

@ -8,7 +8,10 @@
/doc/pdfio.epub
/packages
/pdfio.xcodeproj/xcshareddata
/pdfio-*.tar.gz*
/pdfio-*.zip*
/pdfiototext
/testpdfio
/testpdfio-*.pdf
/testttf
/x64

View File

@ -2,7 +2,37 @@ Changes in PDFio
================
v1.1.0 (February 3, 2023)
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.

View File

@ -118,7 +118,7 @@ the source file and the copyright and licensing notice:
//
// Description of file contents.
//
// Copyright YYYY by AUTHOR.
// Copyright © YYYY by AUTHOR.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
@ -330,7 +330,7 @@ typedef, for example:
All constant names are uppercase with underscores between words, e.g.,
`PDFIO_THIS_CONSTANT`, `PDFIO_THAT_CONSTANT`, etc. Constants begin with the
"PDFio\_" prefix to avoid conflicts with system constants. Private constants
"PDFIO\_" prefix to avoid conflicts with system constants. Private constants
start with an underscore, e.g., `_PDFIO_THIS_CONSTANT`,
`_PDFIO_THAT_CONSTANT`, etc.
@ -369,11 +369,12 @@ extensions MUST NOT be used.
The following variables are defined in the makefile:
- `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,
- `CFLAGS`; options for the C compiler command,
- `CFLAGS`; options for the C compiler,
- `CODESIGN_IDENTITY`: the code signing identity,
- `COMMONFLAGS`; common compiler optimization options,
- `CPPFLAGS`; options for the C preprocessor,
- `DESTDIR`/`DSTROOT`: the destination root directory when installing.
- `DSO`; the shared library building command,
- `DSOFLAGS`; options for the shared library building command,
@ -395,4 +396,5 @@ The following standard targets are defined in the makefile:
with debug printfs and the clang address sanitizer enabled.
- `install`; installs all distribution files in their corresponding locations.
- `install-shared`; same as `install` but also installs the shared library.
- `macos`; same as `all` but creates a Universal Binary (X64 + ARM64).
- `test`; runs the unit test program, building it as needed.

View File

@ -21,7 +21,7 @@ CFLAGS =
CODESIGN_IDENTITY = Developer ID
COMMONFLAGS = -Os -g
#COMMONFLAGS = -O0 -g -fsanitize=address
CPPFLAGS = '-DPDFIO_VERSION="$(VERSION)"'
CPPFLAGS =
DESTDIR = $(DSTROOT)
DSO = cc
DSOFLAGS =
@ -29,7 +29,7 @@ DSONAME =
LDFLAGS =
LIBS = -lm -lz
RANLIB = ranlib
VERSION = 1.1.0
VERSION = 1.1.3
prefix = /usr/local
@ -67,12 +67,14 @@ LIBOBJS = \
OBJS = \
$(LIBOBJS) \
pdfiototext.o \
testpdfio.o
testpdfio.o \
testttf.o
TARGETS = \
$(DSONAME) \
libpdfio.a \
pdfiototext \
testpdfio
testpdfio \
testttf
# Make everything
@ -89,7 +91,7 @@ debug:
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-g -fsanitize=address -DDEBUG=1" clean all
macos:
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-Os -mmacosx-version-min=10.14 -arch x86_64 -arch arm64" clean all
$(MAKE) -$(MAKEFLAGS) COMMONFLAGS="-Os -mmacosx-version-min=11 -arch x86_64 -arch arm64" clean all
# Clean everything
@ -136,7 +138,8 @@ install-shared:
# Test everything
test: testpdfio
./testpdfio
./testttf 2>test.log
./testpdfio 2>test.log
valgrind: testpdfio
valgrind --leak-check=full ./testpdfio
@ -182,16 +185,22 @@ testpdfio: testpdfio.o libpdfio.a
echo Linking $@...
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
# TTF test program
testttf: ttf.o testttf.o
echo Linking $@...
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o testttf ttf.o testttf.o $(LIBS)
# Dependencies
$(OBJS): pdfio.h pdfio-private.h Makefile
pdfio-content.o: pdfio-content.h ttf.h
testttf.o: ttf.h
ttf.o: ttf.h
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
DOCFLAGS = \
--author "Michael R Sweet" \
--copyright "Copyright (c) 2021-2022 by Michael R Sweet" \
--copyright "Copyright (c) 2021-2023 by Michael R Sweet" \
--docversion $(VERSION)
.PHONY: doc

View File

@ -5,8 +5,6 @@ pdfio - PDF Read/Write Library
![Apache 2.0](https://img.shields.io/github/license/michaelrsweet/pdfio)
[![Build Status](https://img.shields.io/github/workflow/status/michaelrsweet/pdfio/Build)](https://github.com/michaelrsweet/pdfio/actions/workflows/build.yml)
[![Coverity Scan Status](https://img.shields.io/coverity/scan/22385.svg)](https://scan.coverity.com/projects/michaelrsweet-pdfio)
[![LGTM Grade](https://img.shields.io/lgtm/grade/cpp/github/michaelrsweet/pdfio)](https://lgtm.com/projects/g/michaelrsweet/pdfio/context:cpp)
[![LGTM Alerts](https://img.shields.io/lgtm/alerts/github/michaelrsweet/pdfio)](https://lgtm.com/projects/g/michaelrsweet/pdfio/)
PDFio is a simple C library for reading and writing PDF files. The primary
goals of PDFio are:
@ -121,7 +119,7 @@ You can reproduce this with the makefile using:
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
(optional) exception to allow linking against GPL2/LGPL2 software. See the

View File

@ -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.
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
----------------------
@ -50,14 +69,6 @@ example:
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
--------------

View File

@ -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
pdfio \- pdf read/write library
.SH Introduction
@ -34,7 +34,7 @@ PDFio is
.I not
concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.
.PP
PDFio is Copyright \[co] 2021\-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
.PP
PDFio requires the following to build the software:
@ -1357,7 +1357,7 @@ bool pdfioContentFillAndStroke (
.fi
.SS pdfioContentMatrixConcat
Concatenate a matrix to the current graphics
state.
state.
.PP
.nf
bool pdfioContentMatrixConcat (
@ -1507,6 +1507,9 @@ bool pdfioContentSetDashPattern (
double off
);
.fi
.PP
This function sets the stroke pattern when drawing lines. If "on" and "off"
are 0, a solid line is drawn.
.SS pdfioContentSetFillColorDeviceCMYK
Set device CMYK fill color.
.PP
@ -1981,6 +1984,7 @@ function "cb":
}
.fi
The iteration continues as long as the callback returns \fBtrue\fR or all keys
have been iterated.
.SS pdfioDictSetArray
@ -2305,10 +2309,11 @@ written:
ssize_t
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
The "version" argument specifies the PDF version number for the file or
\fBNULL\fR for the default ("2.0").
.PP
@ -2616,7 +2621,7 @@ double pdfioImageGetWidth (
.fi
.SS pdfioObjClose
Close an object, writing any data as needed to the PDF
file.
file.
.PP
.nf
bool pdfioObjClose (
@ -2802,6 +2807,13 @@ bool pdfioStreamGetToken (
size_t bufsize
);
.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
Peek at data in a stream.
.PP
@ -3035,4 +3047,4 @@ typedef uint8_t state_t[4][4];
Michael R Sweet
.SH COPYRIGHT
.PP
Copyright (c) 2021-2022 by Michael R Sweet
Copyright (c) 2021-2023 by Michael R Sweet

View File

@ -1,13 +1,13 @@
<!DOCTYPE html>
<html lang="en-US">
<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 name="generator" content="codedoc v3.7">
<meta name="author" content="Michael R Sweet">
<meta name="language" content="en-US">
<meta name="copyright" content="Copyright © 2021-2022 by Michael R Sweet">
<meta name="version" content="1.1">
<meta name="copyright" content="Copyright © 2021-2023 by Michael R Sweet">
<meta name="version" content="1.1.3">
<style type="text/css"><!--
body {
background: white;
@ -245,9 +245,9 @@ span.string {
<body>
<div class="header">
<p><img class="title" src="pdfio-512.png"></p>
<h1 class="title">PDFio Programming Manual v1.1</h1>
<h1 class="title">PDFio Programming Manual v1.1.3</h1>
<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 class="contents">
<h2 class="title">Contents</h2>
@ -497,7 +497,7 @@ span.string {
</li>
</ul>
<p>PDFio is <em>not</em> concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.</p>
<p>PDFio is Copyright © 2021-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 &quot;LICENSE&quot; and &quot;NOTICE&quot; 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 &quot;LICENSE&quot; and &quot;NOTICE&quot; for more information.</p>
<h3 class="title" id="requirements">Requirements</h3>
<p>PDFio requires the following to build the software:</p>
<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>
<h3 class="function"><a id="pdfioContentMatrixConcat">pdfioContentMatrixConcat</a></h3>
<p class="description">Concatenate a matrix to the current graphics
state.</p>
state.</p>
<p class="code">
bool pdfioContentMatrixConcat(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, pdfio_matrix_t m);</p>
<h4 class="parameters">Parameters</h4>
@ -1614,6 +1614,9 @@ bool pdfioContentSetDashPattern(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<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 &quot;on&quot; and &quot;off&quot;
are 0, a solid line is drawn.</p>
<h3 class="function"><a id="pdfioContentSetFillColorDeviceCMYK">pdfioContentSetFillColorDeviceCMYK</a></h3>
<p class="description">Set device CMYK fill color.</p>
<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 ...
}
</pre>
The iteration continues as long as the callback returns <code>true</code> or all keys
have been iterated.</p>
<h3 class="function"><a id="pdfioDictSetArray">pdfioDictSetArray</a></h3>
@ -2741,9 +2745,10 @@ written:
ssize_t
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>
The &quot;version&quot; argument specifies the PDF version number for the file or
<code>NULL</code> for the default (&quot;2.0&quot;).<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>
<h3 class="function"><a id="pdfioObjClose">pdfioObjClose</a></h3>
<p class="description">Close an object, writing any data as needed to the PDF
file.</p>
file.</p>
<p class="code">
bool pdfioObjClose(<a href="#pdfio_obj_t">pdfio_obj_t</a> *obj);</p>
<h4 class="parameters">Parameters</h4>
@ -3413,6 +3418,13 @@ bool pdfioStreamGetToken(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, char
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<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 ('&lt;') and have all whitespace and the
terminating angle bracket removed.</p>
<h3 class="function"><a id="pdfioStreamPeek">pdfioStreamPeek</a></h3>
<p class="description">Peek at data in a stream.</p>
<p class="code">

View File

@ -15,7 +15,7 @@ goals of pdfio are:
PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF
RIP or viewer could be written using it.
PDFio is Copyright © 2021-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
GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.

View File

@ -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))
{
// Yes, seek within existing buffer...
pdf->bufptr = pdf->buffer + offset - pdf->bufpos;
pdf->bufptr = pdf->buffer + (offset - pdf->bufpos);
PDFIO_DEBUG("_pdfioFileSeek: Seek within buffer, bufpos=%ld.\n", (long)pdf->bufpos);
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p, bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufend);
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p(<%02X%02X...>), bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufptr[0] & 255, pdf->bufptr[1] & 255, pdf->bufend);
return (offset);
}

View File

@ -1,7 +1,7 @@
//
// 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
// information.
@ -670,6 +670,9 @@ pdfioContentSave(pdfio_stream_t *st) // I - Stream
//
// '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
pdfioContentSetDashPattern(
@ -678,7 +681,12 @@ pdfioContentSetDashPattern(
double on, // I - On 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));
}
@ -1402,6 +1410,7 @@ pdfioFileCreateFontObjFromFile(
pdfio_dict_t *cid2gid; // CIDToGIDMap dictionary
pdfio_obj_t *cid2gid_obj; // CIDToGIDMap object
size_t i, // Looping var
start, // Start character
num_cmap; // Number of CMap entries
const int *cmap; // CMap entries
unsigned char *bufptr, // Pointer into buffer
@ -1410,6 +1419,9 @@ pdfioFileCreateFontObjFromFile(
pdfio_obj_t *type2_obj; // CIDFontType2 font object
pdfio_array_t *descendants; // Decendant font list
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 CIDToGIDMap object for the Unicode font...
if ((cid2gid = pdfioDictCreate(pdf)) == NULL)
@ -1440,8 +1452,11 @@ pdfioFileCreateFontObjFromFile(
cmap = ttfGetCMap(font, &num_cmap);
PDFIO_DEBUG("pdfioFileCreateFontObjFromFile: num_cmap=%u\n", (unsigned)num_cmap);
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)
{
// Map undefined glyph to .notdef...
@ -1495,6 +1510,54 @@ pdfioFileCreateFontObjFromFile(
return (NULL);
}
// Width array
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
{
ttfDelete(font);
return (NULL);
}
for (start = 0, w0 = ttfGetWidth(font, 0), i = 1; i < 65536; start = i, w0 = w1, i ++)
{
while (i < 65536 && (w1 = ttfGetWidth(font, i)) == w0)
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)
{
ttfDelete(font);
return (NULL);
}
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);
}
}
// CIDSystemInfo mapping to Adobe UCS2 v0 (Unicode)
pdfioDictSetString(sidict, "Registry", "Adobe");
pdfioDictSetString(sidict, "Ordering", "Identity");
@ -1507,6 +1570,7 @@ pdfioFileCreateFontObjFromFile(
pdfioDictSetDict(type2, "CIDSystemInfo", sidict);
pdfioDictSetObj(type2, "CIDToGIDMap", cid2gid_obj);
pdfioDictSetObj(type2, "FontDescriptor", desc_obj);
pdfioDictSetArray(type2, "W", w_array);
if ((type2_obj = pdfioFileCreateObj(pdf, type2)) == NULL)
{
@ -2989,7 +3053,7 @@ write_string(pdfio_stream_t *st, // I - Stream
// Start the string...
if (!pdfioStreamPuts(st, unicode ? "<" : "("))
if (!pdfioStreamPuts(st, unicode ? "<FEFF" : "("))
return (false);
// Loop through the string, handling UTF-8 as needed...

View File

@ -1,7 +1,7 @@
//
// Public content header file for PDFio.
//
// Copyright © 2021 by Michael R Sweet.
// Copyright © 2021-2023 by Michael R Sweet.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
@ -9,18 +9,7 @@
#ifndef PDFIO_CONTENT_H
# define PDFIO_CONTENT_H
//
// Include necessary headers...
//
# include "pdfio.h"
//
// C++ magic...
//
# ifdef __cplusplus
extern "C" {
# endif // __cplusplus
@ -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;
//
// C++ magic...
//
# ifdef __cplusplus
}
# endif // __cplusplus

View File

@ -1,7 +1,7 @@
//
// 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
// information.
@ -446,6 +446,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
// Initialize the RC4 context using 40 bits of the digest...
_pdfioCryptoRC4Init(&ctx->rc4, digest, 5);
*ivlen = 0;
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
case PDFIO_ENCRYPTION_RC4_128 :

View File

@ -1514,6 +1514,7 @@ load_obj_stream(pdfio_obj_t *obj) // I - Object to load
// Skip offset
_pdfioTokenGet(&tb, buffer, sizeof(buffer));
PDFIO_DEBUG("load_obj_stream: %ld at offset %s\n", (long)number, buffer);
}
if (!buffer[0])
@ -1737,6 +1738,10 @@ load_xref(
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);
obj->stream_offset = _pdfioFileTell(pdf);
@ -1759,9 +1764,9 @@ load_xref(
w_2 = w[0];
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);
}
@ -1801,9 +1806,11 @@ load_xref(
}
}
// Offset
for (i = 1, offset = buffer[w_2]; i < w[1]; i ++)
offset = (offset << 8) | buffer[w_2 + i];
// Generation number
switch (w[2])
{
default :
@ -1815,6 +1822,19 @@ load_xref(
case 2 :
generation = (buffer[w_3] << 8) | buffer[w_3 + 1];
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...
@ -1846,8 +1866,18 @@ load_xref(
break;
}
if (i >= num_sobjs && num_sobjs < (sizeof(sobjs) / sizeof(sobjs[0])))
sobjs[num_sobjs ++] = (size_t)offset;
if (i >= num_sobjs)
{
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)
{
@ -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
while (_pdfioFileGets(pdf, line, sizeof(line)))
{
if (!strcmp(line, "trailer"))
if (!strncmp(line, "trailer", 7) && !line[7] || isspace(line[7] & 255))
break;
else if (!line[0])
continue;
@ -1965,7 +1995,7 @@ load_xref(
}
}
if (strcmp(line, "trailer"))
if (strncmp(line, "trailer", 7))
{
_pdfioFileError(pdf, "Missing trailer.");
return (false);

View File

@ -420,6 +420,9 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
}
ptr += 3;
while (*ptr && isspace(*ptr & 255))
ptr ++;
_pdfioFileConsume(obj->pdf, (size_t)(ptr - line));
// Then grab the object value...
@ -438,11 +441,15 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
return (false);
}
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[0]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
if (tb.bufptr && tb.bufptr < tb.bufend && (tb.bufptr[0] == 0x0d || tb.bufptr[0] == 0x0a))
tb.bufptr ++; // Skip trailing CR or LF after token
_pdfioTokenFlush(&tb);
if (!strcmp(line, "stream"))
{
// Yes, save its location...
// Yes, this is an embedded stream so save its location...
obj->stream_offset = _pdfioFileTell(obj->pdf);
PDFIO_DEBUG("_pdfioObjLoad: stream_offset=%lu.\n", (unsigned long)obj->stream_offset);
}

View File

@ -1,7 +1,7 @@
//
// 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
// information.
@ -9,41 +9,22 @@
#ifndef PDFIO_PRIVATE_H
# define PDFIO_PRIVATE_H
//
// Include necessary headers...
//
# ifdef _WIN32
/*
* Disable bogus VS warnings/errors...
*/
# define _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS // Disable bogus VS warnings/errors...
# endif // _WIN32
# include "pdfio.h"
# include <stdarg.h>
# include <stdint.h>
# include <string.h>
# include <ctype.h>
# include <errno.h>
# include <inttypes.h>
# include <fcntl.h>
# ifdef _WIN32
# include <io.h>
# include <direct.h>
/*
* Microsoft renames the POSIX functions to _name, and introduces
* a broken compatibility layer using the original names. As a result,
* random crashes can occur when, for example, strdup() allocates memory
* from a different heap than used by malloc() and free().
*
* To avoid moronic problems like this, we #define the POSIX function
* names to the corresponding non-standard Microsoft names.
*/
# define access _access
# include <windows.h> // GetTempPathA
# define access _access // Map standard POSIX/C99 names
# define close _close
# define fileno _fileno
# define lseek _lseek
@ -56,25 +37,18 @@
# define unlink _unlink
# define vsnprintf _vsnprintf
# define write _write
/*
* Map various parameters for POSIX...
*/
# define F_OK 00
# define F_OK 00 // POSIX parameters/flags
# define W_OK 02
# 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_CREAT _O_CREAT
# define O_TRUNC _O_TRUNC
# define O_BINARY _O_BINARY
# else // !_WIN32
# include <unistd.h>
# define O_BINARY 0
# define O_BINARY 0 // Map Windows-specific open flag
# endif // _WIN32
# include <string.h>
# include <ctype.h>
# include <zlib.h>
@ -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 bool _pdfioValueWrite(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_value_t *v, off_t *length) _PDFIO_INTERNAL;
#endif // !PDFIO_PRIVATE_H

View File

@ -1,7 +1,7 @@
//
// 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
// code. All rights reserved.
//
@ -217,7 +217,7 @@ _pdfioCryptoSHA256Append(_pdfio_sha256_t *context, const uint8_t *message_array,
*/
void
_pdfioCryptoSHA256Finish(_pdfio_sha256_t *context,
uint8_t Message_Digest[SHA256HashSize])
uint8_t *Message_Digest)
{
SHA224_256ResultN(context, Message_Digest, SHA256HashSize);
}

View File

@ -452,6 +452,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
return (NULL);
}
PDFIO_DEBUG("_pdfioStreamOpen: ivlen=%d\n", (int)ivlen);
if (ivlen > 0)
_pdfioFileConsume(st->pdf, ivlen);
@ -464,11 +465,19 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
// Try to decode/decompress the contents of this object...
const char *filter = pdfioDictGetName(dict, "Filter");
// Filter value
pdfio_array_t *fa = pdfioDictGetArray(dict, "Filter");
// Filter array
if (!filter && fa && pdfioArrayGetSize(fa) == 1)
{
// Support single-valued arrays...
filter = pdfioArrayGetName(fa, 0);
}
if (!filter)
{
// No single filter name, do we have a compound filter?
if (pdfioDictGetArray(dict, "Filter"))
if (fa)
{
// TODO: Implement compound filters...
_pdfioFileError(st->pdf, "Unsupported compound stream filter.");
@ -559,6 +568,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
else
st->predictor = _PDFIO_PREDICTOR_NONE;
PDFIO_DEBUG("_pdfioStreamOpen: pos=%ld\n", (long)_pdfioFileTell(st->pdf));
if (sizeof(st->cbuffer) > st->remaining)
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
else
@ -579,12 +589,6 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
st->flate.next_in = (Bytef *)st->cbuffer;
st->flate.avail_in = (uInt)rbytes;
if (st->cbuffer[0] == 0x0a)
{
st->flate.next_in ++; // Skip newline
st->flate.avail_in --;
}
PDFIO_DEBUG("_pdfioStreamOpen: avail_in=%u, cbuffer=<%02X%02X%02X%02X%02X%02X%02X%02X...>\n", st->flate.avail_in, st->cbuffer[0], st->cbuffer[1], st->cbuffer[2], st->cbuffer[3], st->cbuffer[4], st->cbuffer[5], st->cbuffer[6], st->cbuffer[7]);
if ((status = inflateInit(&(st->flate))) != Z_OK)
@ -1008,6 +1012,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
size_t bytes) // I - Number of bytes to read
{
ssize_t rbytes; // Bytes read
uInt avail_in, avail_out; // Previous flate values
if (st->filter == PDFIO_FILTER_NONE)
@ -1060,11 +1065,19 @@ stream_read(pdfio_stream_t *st, // I - Stream
st->flate.next_out = (Bytef *)buffer;
st->flate.avail_out = (uInt)bytes;
avail_in = st->flate.avail_in;
avail_out = st->flate.avail_out;
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
{
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
return (-1);
}
else if (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out)
{
_pdfioFileError(st->pdf, "Corrupt stream data.");
return (-1);
}
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;
}
avail_in = st->flate.avail_in;
avail_out = st->flate.avail_out;
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
{
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
return (-1);
}
else if (status == Z_STREAM_END)
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
break;
}
@ -1180,12 +1196,15 @@ stream_read(pdfio_stream_t *st, // I - Stream
st->flate.avail_in = (uInt)rbytes;
}
avail_in = st->flate.avail_in;
avail_out = st->flate.avail_out;
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
{
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
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;
}

View File

@ -495,6 +495,13 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
*bufptr++ = (char)ch;
break;
}
else if (ch == '>')
{
// Issue #46: Empty hex string from Microsoft PDF generator; treat as
// empty literal string...
*buffer = '(';
break;
}
else if (!isspace(ch & 255) && !isxdigit(ch & 255))
{
_pdfioFileError(tb->pdf, "Syntax error: '<%c'", ch);

24
pdfio.h
View File

@ -1,7 +1,7 @@
//
// 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
// information.
@ -9,27 +9,23 @@
#ifndef PDFIO_H
# define PDFIO_H
//
// Include necessary headers...
//
# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>
# include <sys/types.h>
# include <time.h>
//
// C++ magic...
//
# ifdef __cplusplus
extern "C" {
# endif // __cplusplus
//
// Version number...
//
# define PDFIO_VERSION "1.1.3"
//
// 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;
//
// C++ magic...
//
# ifdef __cplusplus
}
# endif // __cplusplus

View File

@ -87,7 +87,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
@ -101,7 +101,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
@ -115,7 +115,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
@ -130,7 +130,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>PDFIO_VERSION="1.1.0";NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>

View File

@ -372,7 +372,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Apple Development";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1.1;
CURRENT_PROJECT_VERSION = 1.1.2;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@ -381,7 +381,6 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"DEBUG=1",
"'PDFIO_VERSION=\"$(CURRENT_PROJECT_VERSION)\"'",
);
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -397,7 +396,7 @@
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@ -450,7 +449,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Apple Development";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1.1;
CURRENT_PROJECT_VERSION = 1.1.2;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_NS_ASSERTIONS = NO;
@ -459,7 +458,6 @@
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"'PDFIO_VERSION=\"$(CURRENT_PROJECT_VERSION)\"'",
);
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -475,7 +473,7 @@
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
RUN_CLANG_STATIC_ANALYZER = YES;
@ -515,7 +513,7 @@
ENABLE_HARDENED_RUNTIME = YES;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 11.0;
PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -529,7 +527,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 11.0;
PRODUCT_BUNDLE_IDENTIFIER = org.msweet.testpdfio;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

View File

@ -3,7 +3,7 @@
<metadata>
<id>pdfio_native</id>
<title>PDFio Library for VS2019+</title>
<version>1.1.0</version>
<version>1.1.3</version>
<authors>Michael R Sweet</authors>
<owners>michaelrsweet</owners>
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
@ -16,7 +16,7 @@
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
<tags>pdf file native</tags>
<dependencies>
<dependency id="pdfio_native.redist" version="1.1.0" />
<dependency id="pdfio_native.redist" version="1.1.3" />
<dependency id="zlib_native.redist" version="1.2.11" />
</dependencies>
</metadata>

View File

@ -3,7 +3,7 @@
<metadata>
<id>pdfio_native.redist</id>
<title>PDFio Library for VS2019+</title>
<version>1.1.0</version>
<version>1.1.3</version>
<authors>Michael R Sweet</authors>
<owners>michaelrsweet</owners>
<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>
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
<tags>pdf file native</tags>
<dependencies>
<dependency id="zlib_native.redist" version="1.2.11" />
</dependencies>
</metadata>
<files>
<file src="doc\pdfio-128.png" target="build\native" />

View File

@ -406,7 +406,7 @@ do_test_file(const char *filename, // I - PDF filename
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);
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);
}
}
@ -2391,24 +2391,11 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
};
#if 0
if (unicode)
{
fputs("pdfioFileCreateFontObjFromFile(NotoSansJP-Regular.otf): ", stdout);
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/NotoSansJP-Regular.otf", true)) != NULL)
puts("PASS");
else
return (1);
}
fputs("pdfioFileCreateFontObjFromFile(OpenSans-Regular.ttf): ", stdout);
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/OpenSans-Regular.ttf", unicode)) != NULL)
puts("PASS");
else
#endif // 0
{
fputs("pdfioFileCreateFontObjFromFile(OpenSans-Regular.ttf): ", stdout);
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/OpenSans-Regular.ttf", unicode)) != NULL)
puts("PASS");
else
return (1);
}
return (1);
fputs("pdfioDictCreate: ", stdout);
if ((dict = pdfioDictCreate(pdf)) != NULL)

305
testttf.c Normal file
View File

@ -0,0 +1,305 @@
//
// 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("FAIL");
errors ++;
}
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)) >= 0.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);
}

52
ttf.c
View File

@ -3,16 +3,12 @@
//
// 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
// information.
//
//
// Include necessary headers...
//
#ifdef _WIN32
# define _CRT_SECURE_NO_WARNINGS
#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...
//
@ -452,7 +448,7 @@ ttfCreate(const char *filename, // I - Filename
font->cap_height = font->ascent;
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...
font->min_char = -1;
@ -481,6 +477,11 @@ ttfCreate(const char *filename, // I - Filename
else
font->widths[bin][i & 255] = widths[glyph];
}
#ifdef DEBUG
if (i >= ' ' && i < 127)
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...
@ -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.
//
@ -856,13 +846,14 @@ int // O - Width in 1000ths
ttfGetWidth(ttf_t *font, // I - Font
int ch) // I - Unicode character
{
int bin = ch >> 8; // Bin in widths array
int bin = ch >> 8; // Bin in widths array
// Range check input...
if (!font || ch < ' ' || ch == 0x7f)
return (0);
else if (font->widths[bin])
if (font->widths[bin])
return ((int)(1000.0f * font->widths[bin][ch & 255].width / font->units));
else if (font->widths[0]) // .notdef
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.
//
@ -1305,17 +1307,17 @@ read_cmap(ttf_t *font) // I - Font
{
// Use an "obscure indexing trick" (words from the spec, not
// mine) to look up the glyph index...
temp = segment->idRangeOffset / 2 + ch - segment->startCode + seg - segCount - 1;
temp = segment->idRangeOffset / 2 + ch - segment->startCode + seg - segCount;
if (temp < 0 || temp >= numGlyphIdArray || !glyphIdArray[temp])
if (temp < 0 || temp >= numGlyphIdArray)
glyph = -1;
else
glyph = ((glyphIdArray[temp] + segment->idDelta) & 65535) - 1;
glyph = (glyphIdArray[temp] + segment->idDelta) & 65535;
}
else
{
// Just use idDelta to compute a glyph index...
glyph = ((ch + segment->idDelta) & 65535) - 1;
glyph = (ch + segment->idDelta) & 65535;
}
cmapptr[ch] = glyph;
@ -1582,6 +1584,8 @@ read_hmtx(ttf_t *font, // I - Font
{
widths[i].width = (short)read_ushort(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);

13
ttf.h
View File

@ -3,7 +3,7 @@
//
// 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
// information.
@ -11,17 +11,11 @@
#ifndef TTF_H
# define TTF_H
//
// Include necessary headers...
//
# include <stdbool.h>
# include <sys/types.h>
# ifdef __cplusplus
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 int ttfGetAscent(ttf_t *font);
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 int ttfGetCapHeight(ttf_t *font);
extern const char *ttfGetCopyright(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);
@ -112,5 +106,4 @@ extern bool ttfIsFixedPitch(ttf_t *font);
# ifdef __cplusplus
}
# endif // __cplusplus
#endif // !TTF_H