mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-04-24 17:36:48 +02:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
cad8f450ab | ||
|
278ddb7fa7 | ||
|
1e6bb710e3 | ||
|
4ca93bd34f | ||
|
404ca72882 | ||
|
67704ce493 | ||
|
e983ba98d8 | ||
|
c23c6dec9a | ||
|
5e9617a742 | ||
|
09ee7d16c1 | ||
|
078985fc20 | ||
|
13fedfc424 | ||
|
c07927dc2d | ||
|
1393cd6c04 | ||
|
b278e33aac | ||
|
1116e929f7 | ||
|
c75611e274 | ||
|
c507cabbda | ||
|
81aeef46d2 | ||
|
ba7371b2e1 | ||
|
ec64af8b20 | ||
|
acd68df592 | ||
|
3d9c22aa49 | ||
|
3ae95f1545 | ||
|
cfdd6f55d9 | ||
|
06f38edcc7 | ||
|
76c1cc694f | ||
|
4219b8fd77 | ||
|
064e7fa473 |
29
CHANGES.md
29
CHANGES.md
@ -2,7 +2,34 @@ Changes in PDFio
|
||||
================
|
||||
|
||||
|
||||
v1.5.2 - YYYY-MM-DD
|
||||
v1.6.0 - YYYY-MM-DD
|
||||
-------------------
|
||||
|
||||
- Added generation of XMP metadata when writing PDFs (Issue #103)
|
||||
- Added "standard" `PDFIO_CS_CGATS001` color space for non-device CMYK
|
||||
(Issue #104)
|
||||
- Added CMYK JPEG support with embedded ICC profiles or using the CGATS001
|
||||
profile (Issue #104)
|
||||
- Added `pdfioFileAddOutputIntent` function to adding output intent information
|
||||
to a PDF file (Issue #104)
|
||||
- Added `pdfioFileCreateFontObjFromData` function for embedding fonts in
|
||||
memory (Issue #120)
|
||||
- Added `pdfioFileGetLanguage` and `pdfioFileSetLanguage` functions for getting
|
||||
and setting the default/primary language of a PDF file (Issue #124)
|
||||
- Now add default grayscale, RGB, and CMYK profile resources to pages as needed
|
||||
(Issue #104)
|
||||
|
||||
|
||||
v1.5.3 - YYYY-MM-DD
|
||||
-------------------
|
||||
|
||||
- Fixed decryption of PDF files "protected" by 40-bit RC4 (Issue #42)
|
||||
- Fixed decryption of UTF-16 strings (Issue #42)
|
||||
- Fixed decryption of PDF files with large permission values.
|
||||
- Fixed support for EncryptMetadata key in the encryption dictionary.
|
||||
|
||||
|
||||
v1.5.2 - 2025-04-12
|
||||
-------------------
|
||||
|
||||
- Updated maximum allowed PDF string size to 64k (Issue #117)
|
||||
|
@ -241,6 +241,7 @@ testttf: ttf.o testttf.o
|
||||
# Dependencies
|
||||
$(OBJS): pdfio.h pdfio-private.h Makefile
|
||||
pdfio-content.o: pdfio-content.h ttf.h
|
||||
testpdfio.o: test.h
|
||||
testttf.o: ttf.h
|
||||
ttf.o: ttf.h
|
||||
|
||||
|
24
configure
vendored
24
configure
vendored
@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.71 for pdfio 1.5.2.
|
||||
# Generated by GNU Autoconf 2.71 for pdfio 1.6.0.
|
||||
#
|
||||
# Report bugs to <https://github.com/michaelrsweet/pdfio/issues>.
|
||||
#
|
||||
@ -610,8 +610,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='pdfio'
|
||||
PACKAGE_TARNAME='pdfio'
|
||||
PACKAGE_VERSION='1.5.2'
|
||||
PACKAGE_STRING='pdfio 1.5.2'
|
||||
PACKAGE_VERSION='1.6.0'
|
||||
PACKAGE_STRING='pdfio 1.6.0'
|
||||
PACKAGE_BUGREPORT='https://github.com/michaelrsweet/pdfio/issues'
|
||||
PACKAGE_URL='https://www.msweet.org/pdfio'
|
||||
|
||||
@ -1295,7 +1295,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures pdfio 1.5.2 to adapt to many kinds of systems.
|
||||
\`configure' configures pdfio 1.6.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@ -1361,7 +1361,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of pdfio 1.5.2:";;
|
||||
short | recursive ) echo "Configuration of pdfio 1.6.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@ -1460,7 +1460,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
pdfio configure 1.5.2
|
||||
pdfio configure 1.6.0
|
||||
generated by GNU Autoconf 2.71
|
||||
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
@ -1678,7 +1678,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by pdfio $as_me 1.5.2, which was
|
||||
It was created by pdfio $as_me 1.6.0, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
$ $0$ac_configure_args_raw
|
||||
@ -2434,9 +2434,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
|
||||
PDFIO_VERSION="1.5.2"
|
||||
PDFIO_VERSION_MAJOR="`echo 1.5.2 | awk -F. '{print $1}'`"
|
||||
PDFIO_VERSION_MINOR="`echo 1.5.2 | awk -F. '{printf("%d\n",$2);}'`"
|
||||
PDFIO_VERSION="1.6.0"
|
||||
PDFIO_VERSION_MAJOR="`echo 1.6.0 | awk -F. '{print $1}'`"
|
||||
PDFIO_VERSION_MINOR="`echo 1.6.0 | awk -F. '{printf("%d\n",$2);}'`"
|
||||
|
||||
|
||||
|
||||
@ -5099,7 +5099,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by pdfio $as_me 1.5.2, which was
|
||||
This file was extended by pdfio $as_me 1.6.0, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@ -5155,7 +5155,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config='$ac_cs_config_escaped'
|
||||
ac_cs_version="\\
|
||||
pdfio config.status 1.5.2
|
||||
pdfio config.status 1.6.0
|
||||
configured by $0, generated by GNU Autoconf 2.71,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
@ -21,7 +21,7 @@ AC_PREREQ([2.70])
|
||||
|
||||
|
||||
dnl Package name and version...
|
||||
AC_INIT([pdfio], [1.5.2], [https://github.com/michaelrsweet/pdfio/issues], [pdfio], [https://www.msweet.org/pdfio])
|
||||
AC_INIT([pdfio], [1.6.0], [https://github.com/michaelrsweet/pdfio/issues], [pdfio], [https://www.msweet.org/pdfio])
|
||||
|
||||
PDFIO_VERSION="AC_PACKAGE_VERSION"
|
||||
PDFIO_VERSION_MAJOR="`echo AC_PACKAGE_VERSION | awk -F. '{print $1}'`"
|
||||
|
164
doc/pdfio.3
164
doc/pdfio.3
@ -1,4 +1,4 @@
|
||||
.TH pdfio 3 "pdf read/write library" "2025-04-12" "pdf read/write library"
|
||||
.TH pdfio 3 "pdf read/write library" "2025-04-23" "pdf read/write library"
|
||||
.SH NAME
|
||||
pdfio \- pdf read/write library
|
||||
.SH Introduction
|
||||
@ -325,7 +325,7 @@ where the five arguments to the function are the filename ("myinputfile.pdf"), a
|
||||
}
|
||||
.fi
|
||||
.PP
|
||||
The error callback is called for both errors and warnings and accepts the pdfio_file_t pointer, a message string, and the callback pointer value, for example:
|
||||
The error callback is called for both errors and warnings and accepts the pdfio_file_t pointer, a message string, and the callback pointer value. It returns true to continue processing the file or false to stop, for example:
|
||||
.nf
|
||||
|
||||
bool
|
||||
@ -335,12 +335,15 @@ The error callback is called for both errors and warnings and accepts the pdfio_
|
||||
|
||||
fprintf(stderr, "%s: %s\\n", pdfioFileGetName(pdf), message);
|
||||
|
||||
// Return false to treat warnings as errors
|
||||
return (false);
|
||||
// Return true for warning messages (continue) and false for errors (stop)
|
||||
return (!strncmp(message, "WARNING:", 8));
|
||||
}
|
||||
.fi
|
||||
.PP
|
||||
The default error callback (NULL) does the equivalent of the above.
|
||||
.PP
|
||||
Note: Many errors are unrecoverable, so PDFio ignores the return value from the error callback and always stops processing the PDF file. Warning messages start with the prefix "WARNING:" while errors have no prefix.
|
||||
|
||||
.PP
|
||||
Each PDF file contains one or more pages. The pdfioFileGetNumPages function returns the number of pages in the file while the pdfioFileGetPage function gets the specified page in the PDF file:
|
||||
.nf
|
||||
@ -2449,6 +2452,10 @@ PDFIO_CS_ADOBE
|
||||
.br
|
||||
AdobeRGB 1998
|
||||
.TP 5
|
||||
PDFIO_CS_CGATS001
|
||||
.br
|
||||
CGATS001 (CMYK)
|
||||
.TP 5
|
||||
PDFIO_CS_P3_D65
|
||||
.br
|
||||
Display P3
|
||||
@ -2477,7 +2484,7 @@ PDFIO_ENCRYPTION_RC4_128
|
||||
.TP 5
|
||||
PDFIO_ENCRYPTION_RC4_40
|
||||
.br
|
||||
40-bit RC4 encryption (PDF 1.3)
|
||||
40-bit RC4 encryption (PDF 1.3, reading only)
|
||||
.SS pdfio_filter_e
|
||||
Compression/decompression filters for streams
|
||||
.TP 5
|
||||
@ -2838,7 +2845,8 @@ pdfio_array_t * pdfioArrayCreateColorFromStandard (
|
||||
.fi
|
||||
.PP
|
||||
This function creates a color array for a standard \fBPDFIO_CS_\fR enumerated color space.
|
||||
The "num_colors" argument must be \fB1\fR for grayscale and \fB3\fR for RGB color.
|
||||
The "num_colors" argument must be \fB1\fR for grayscale, \fB3\fR for RGB color, and
|
||||
\fB4\fR for CMYK color.
|
||||
.SS pdfioArrayGetArray
|
||||
Get an array value from an array.
|
||||
.PP
|
||||
@ -2947,6 +2955,8 @@ bool pdfioArrayRemove (
|
||||
size_t n
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SS pdfioContentClip
|
||||
Clip output to the current path.
|
||||
.PP
|
||||
@ -3083,6 +3093,8 @@ bool pdfioContentPathEnd (
|
||||
pdfio_stream_t *st
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SS pdfioContentPathLineTo
|
||||
Add a straight line to the current path.
|
||||
.PP
|
||||
@ -3423,6 +3435,8 @@ double pdfioContentTextMeasure (
|
||||
This function measures the given text string "s" and returns its width based
|
||||
on "size". The text string must always use the UTF-8 (Unicode) encoding but
|
||||
any control characters (such as newlines) are ignored.
|
||||
|
||||
|
||||
.SS pdfioContentTextMoveLine
|
||||
Move to the next line and offset.
|
||||
.PP
|
||||
@ -3451,6 +3465,8 @@ bool pdfioContentTextNewLine (
|
||||
pdfio_stream_t *st
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SS pdfioContentTextNewLineShow
|
||||
Move to the next line and show text.
|
||||
.PP
|
||||
@ -3468,6 +3484,8 @@ This function moves to the next line and then shows some text with optional
|
||||
word and character spacing in a PDF content stream. The "unicode" argument
|
||||
specifies that the current font maps to full Unicode. The "s" argument
|
||||
specifies a UTF-8 encoded string.
|
||||
|
||||
|
||||
.SS pdfioContentTextNewLineShowf
|
||||
Show formatted text.
|
||||
.PP
|
||||
@ -3486,6 +3504,8 @@ This function moves to the next line and shows some formatted text with
|
||||
optional word and character spacing in a PDF content stream. The "unicode"
|
||||
argument specifies that the current font maps to full Unicode. The "format"
|
||||
argument specifies a UTF-8 encoded \fBprintf\fR-style format string.
|
||||
|
||||
|
||||
.SS pdfioContentTextShow
|
||||
Show text.
|
||||
.PP
|
||||
@ -3536,6 +3556,8 @@ bool pdfioDictClear (
|
||||
const char *key
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SS pdfioDictCopy
|
||||
Copy a dictionary to a PDF file.
|
||||
.PP
|
||||
@ -3608,6 +3630,8 @@ const char * pdfioDictGetKey (
|
||||
size_t n
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SS pdfioDictGetName
|
||||
Get a key name value from a dictionary.
|
||||
.PP
|
||||
@ -3625,6 +3649,8 @@ size_t pdfioDictGetNumPairs (
|
||||
pdfio_dict_t *dict
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SS pdfioDictGetNumber
|
||||
Get a key number value from a dictionary.
|
||||
.PP
|
||||
@ -3697,6 +3723,8 @@ function "cb":
|
||||
|
||||
The iteration continues as long as the callback returns \fBtrue\fR or all keys
|
||||
have been iterated.
|
||||
|
||||
|
||||
.SS pdfioDictSetArray
|
||||
Set a key array in a dictionary.
|
||||
.PP
|
||||
@ -3818,6 +3846,39 @@ bool pdfioDictSetStringf (
|
||||
...
|
||||
);
|
||||
.fi
|
||||
.SS pdfioFileAddOutputIntent
|
||||
Add an OutputIntent to a file.
|
||||
.PP
|
||||
.nf
|
||||
void pdfioFileAddOutputIntent (
|
||||
pdfio_file_t *pdf,
|
||||
const char *subtype,
|
||||
const char *condition,
|
||||
const char *cond_id,
|
||||
const char *reg_name,
|
||||
const char *info,
|
||||
pdfio_obj_t *profile
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
This function adds an OutputIntent dictionary to the PDF file catalog.
|
||||
The "subtype" argument specifies the intent subtype and is typically
|
||||
"GTS_PDFX" for PDF/X, "GTS_PDFA1" for PDF/A, or "ISO_PDFE1" for PDF/E.
|
||||
Passing \fBNULL\fR defaults the subtype to "GTS_PDFA1".
|
||||
.PP
|
||||
The "condition" argument specifies a short name for the output intent, while
|
||||
the "info" argument specifies a longer description for the output intent.
|
||||
Both can be \fBNULL\fR to omit this information.
|
||||
.PP
|
||||
The "cond_id" argument specifies a unique identifier such as a registration
|
||||
("CGATS001") or color space name ("sRGB"). The "reg_name" argument provides
|
||||
a URL for the identifier.
|
||||
.PP
|
||||
The "profile" argument specifies an ICC profile object for the output
|
||||
condition. If \fBNULL\fR, the PDF consumer will attempt to look up the correct
|
||||
profile using the "cond_id" value.
|
||||
|
||||
|
||||
.SS pdfioFileClose
|
||||
Close a PDF file and free all memory used for it.
|
||||
.PP
|
||||
@ -3852,8 +3913,9 @@ CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" siz
|
||||
of 8.27x11in (the intersection of US Letter and ISO A4) is used.
|
||||
.PP
|
||||
The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||
and its data pointer - if \fBNULL\fR the default error handler is used that
|
||||
writes error messages to \fBstderr\fR.
|
||||
and its data pointer - if \fBNULL\fR then the default error handler is used that
|
||||
writes error messages to \fBstderr\fR. The error handler callback should return
|
||||
\fBtrue\fR to continue writing the PDF file or \fBfalse\fR to stop.
|
||||
.SS pdfioFileCreateArrayObj
|
||||
Create a new object in a PDF file containing an array.
|
||||
.PP
|
||||
@ -3911,8 +3973,27 @@ specifies the font nane:
|
||||
Aside from "Symbol" and "Zapf-Dingbats", Base fonts use the Windows CP1252
|
||||
(ISO-8859-1 with additional characters such as the Euro symbol) subset of
|
||||
Unicode.
|
||||
.SS pdfioFileCreateFontObjFromData
|
||||
Add a font in memory to a PDF file.
|
||||
.PP
|
||||
.nf
|
||||
pdfio_obj_t * pdfioFileCreateFontObjFromData (
|
||||
pdfio_file_t *pdf,
|
||||
const void *data,
|
||||
size_t datasize,
|
||||
bool unicode
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
This function embeds TrueType/OpenType font data into a PDF file. The
|
||||
"unicode" parameter controls whether the font is encoded for two-byte
|
||||
characters (potentially full Unicode, but more typically a subset)
|
||||
or to only support the Windows CP1252 (ISO-8859-1 with additional
|
||||
characters such as the Euro symbol) subset of Unicode.
|
||||
|
||||
|
||||
.SS pdfioFileCreateFontObjFromFile
|
||||
Add a font object to a PDF file.
|
||||
Add a font file to a PDF file.
|
||||
.PP
|
||||
.nf
|
||||
pdfio_obj_t * pdfioFileCreateFontObjFromFile (
|
||||
@ -3922,7 +4003,7 @@ pdfio_obj_t * pdfioFileCreateFontObjFromFile (
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
This function embeds a TrueType/OpenType font into a PDF file. The
|
||||
This function embeds a TrueType/OpenType font file into a PDF file. The
|
||||
"unicode" parameter controls whether the font is encoded for two-byte
|
||||
characters (potentially full Unicode, but more typically a subset)
|
||||
or to only support the Windows CP1252 (ISO-8859-1 with additional
|
||||
@ -4011,6 +4092,8 @@ pdfio_obj_t * pdfioFileCreateNameObj (
|
||||
.PP
|
||||
This function creates a new object with a name value in a PDF file.
|
||||
You must call \fIpdfioObjClose\fR to write the object to the file.
|
||||
|
||||
|
||||
.SS pdfioFileCreateNumberObj
|
||||
Create a new object in a PDF file containing a number.
|
||||
.PP
|
||||
@ -4023,6 +4106,8 @@ pdfio_obj_t * pdfioFileCreateNumberObj (
|
||||
.PP
|
||||
This function creates a new object with a number value in a PDF file.
|
||||
You must call \fIpdfioObjClose\fR to write the object to the file.
|
||||
|
||||
|
||||
.SS pdfioFileCreateObj
|
||||
Create a new object in a PDF file.
|
||||
.PP
|
||||
@ -4071,8 +4156,9 @@ CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" siz
|
||||
of 8.27x11in (the intersection of US Letter and ISO A4) is used.
|
||||
.PP
|
||||
The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||
and its data pointer - if \fBNULL\fR the default error handler is used that
|
||||
writes error messages to \fBstderr\fR.
|
||||
and its data pointer - if \fBNULL\fR then the default error handler is used that
|
||||
writes error messages to \fBstderr\fR. The error handler callback should return
|
||||
\fBtrue\fR to continue writing the PDF file or \fBfalse\fR to stop.
|
||||
.PP
|
||||
.IP 5
|
||||
\fINote\fR: Files created using this API are slightly larger than those
|
||||
@ -4101,6 +4187,8 @@ pdfio_obj_t * pdfioFileCreateStringObj (
|
||||
.PP
|
||||
This function creates a new object with a string value in a PDF file.
|
||||
You must call \fIpdfioObjClose\fR to write the object to the file.
|
||||
|
||||
|
||||
.SS pdfioFileCreateTemporary
|
||||
|
||||
.PP
|
||||
@ -4177,6 +4265,21 @@ const char * pdfioFileGetKeywords (
|
||||
pdfio_file_t *pdf
|
||||
);
|
||||
.fi
|
||||
.SS pdfioFileGetLanguage
|
||||
Get the language metadata for a PDF file.
|
||||
.PP
|
||||
.nf
|
||||
const char * pdfioFileGetLanguage (
|
||||
pdfio_file_t *pdf
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
This function gets the (primary/default) language metadata, if any, for a PDF
|
||||
file. The returned string is an IETF BCP 47 language tag of the form
|
||||
"lang-REGION". For example, the string "en-CA" specifies Canadian English
|
||||
and the string "fr-CA" specifies Canadian French.
|
||||
|
||||
|
||||
.SS pdfioFileGetModificationDate
|
||||
Get the most recent modification date for a PDF file.
|
||||
.PP
|
||||
@ -4294,8 +4397,18 @@ cancel the open. If \fBNULL\fR is specified for the callback function and the
|
||||
PDF file requires a password, the open will always fail.
|
||||
.PP
|
||||
The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||
and its data pointer - if \fBNULL\fR the default error handler is used that
|
||||
writes error messages to \fBstderr\fR.
|
||||
and its data pointer - if \fBNULL\fR then the default error handler is used that
|
||||
writes error messages to \fBstderr\fR. The error handler callback should return
|
||||
\fBtrue\fR to continue reading the PDF file or \fBfalse\fR to stop.
|
||||
.PP
|
||||
.IP 5
|
||||
Note: Error messages starting with "WARNING:" are actually warning
|
||||
.IP 5
|
||||
messages - the callback should normally return \fBtrue\fR to allow PDFio to
|
||||
.IP 5
|
||||
try to resolve the issue. In addition, some errors are unrecoverable and
|
||||
.IP 5
|
||||
ignore the return value of the error callback.
|
||||
.SS pdfioFileSetAuthor
|
||||
Set the author for a PDF file.
|
||||
.PP
|
||||
@ -4332,6 +4445,22 @@ void pdfioFileSetKeywords (
|
||||
const char *value
|
||||
);
|
||||
.fi
|
||||
.SS pdfioFileSetLanguage
|
||||
Set the language metadata for a PDF file.
|
||||
.PP
|
||||
.nf
|
||||
void pdfioFileSetLanguage (
|
||||
pdfio_file_t *pdf,
|
||||
const char *value
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
This function sets the (primary/default) language metadata for a PDF file.
|
||||
The "value" argument is an IETF BCP 47 language tag string of the form
|
||||
"lang-REGION". For example, the string "en-CA" specifies Canadian English
|
||||
and the string "fr-CA" specifies Canadian French.
|
||||
|
||||
|
||||
.SS pdfioFileSetModificationDate
|
||||
Set the modification date for a PDF file.
|
||||
.PP
|
||||
@ -4474,6 +4603,8 @@ const char * pdfioObjGetName (
|
||||
pdfio_obj_t *obj
|
||||
);
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SS pdfioObjGetNumber
|
||||
Get the object's number.
|
||||
.PP
|
||||
@ -4677,8 +4808,9 @@ bool pdfioStreamPrintf (
|
||||
.fi
|
||||
.PP
|
||||
This function writes a formatted string to a stream. In addition to the
|
||||
standard \fBprintf\fR format characters, you can use "%N" to format a PDF name
|
||||
value ("/Name") and "%S" to format a PDF string ("(String)") value.
|
||||
standard \fBprintf\fR format characters, you can use "%H" to format a HTML/XML
|
||||
string value, "%N" to format a PDF name value ("/Name"), and "%S" to format
|
||||
a PDF string ("(String)") value.
|
||||
.SS pdfioStreamPutChar
|
||||
Write a single character to a stream.
|
||||
.PP
|
||||
|
214
doc/pdfio.html
214
doc/pdfio.html
@ -1,13 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<title>PDFio Programming Manual v1.5.2</title>
|
||||
<title>PDFio Programming Manual v1.6.0</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
<meta name="generator" content="codedoc v3.8">
|
||||
<meta name="author" content="Michael R Sweet">
|
||||
<meta name="language" content="en-US">
|
||||
<meta name="copyright" content="Copyright © 2021-2025 by Michael R Sweet">
|
||||
<meta name="version" content="1.5.2">
|
||||
<meta name="version" content="1.6.0">
|
||||
<style type="text/css"><!--
|
||||
body {
|
||||
background: white;
|
||||
@ -251,7 +251,7 @@ span.string {
|
||||
<body>
|
||||
<div class="header">
|
||||
<p><img class="title" src="pdfio-512.png"></p>
|
||||
<h1 class="title">PDFio Programming Manual v1.5.2</h1>
|
||||
<h1 class="title">PDFio Programming Manual v1.6.0</h1>
|
||||
<p>Michael R Sweet</p>
|
||||
<p>Copyright © 2021-2025 by Michael R Sweet</p>
|
||||
</div>
|
||||
@ -395,10 +395,12 @@ span.string {
|
||||
<li><a href="#pdfioDictSetRect">pdfioDictSetRect</a></li>
|
||||
<li><a href="#pdfioDictSetString">pdfioDictSetString</a></li>
|
||||
<li><a href="#pdfioDictSetStringf">pdfioDictSetStringf</a></li>
|
||||
<li><a href="#pdfioFileAddOutputIntent">pdfioFileAddOutputIntent</a></li>
|
||||
<li><a href="#pdfioFileClose">pdfioFileClose</a></li>
|
||||
<li><a href="#pdfioFileCreate">pdfioFileCreate</a></li>
|
||||
<li><a href="#pdfioFileCreateArrayObj">pdfioFileCreateArrayObj</a></li>
|
||||
<li><a href="#pdfioFileCreateFontObjFromBase">pdfioFileCreateFontObjFromBase</a></li>
|
||||
<li><a href="#pdfioFileCreateFontObjFromData">pdfioFileCreateFontObjFromData</a></li>
|
||||
<li><a href="#pdfioFileCreateFontObjFromFile">pdfioFileCreateFontObjFromFile</a></li>
|
||||
<li><a href="#pdfioFileCreateICCObjFromData">pdfioFileCreateICCObjFromData</a></li>
|
||||
<li><a href="#pdfioFileCreateICCObjFromFile">pdfioFileCreateICCObjFromFile</a></li>
|
||||
@ -418,6 +420,7 @@ span.string {
|
||||
<li><a href="#pdfioFileGetCreator">pdfioFileGetCreator</a></li>
|
||||
<li><a href="#pdfioFileGetID">pdfioFileGetID</a></li>
|
||||
<li><a href="#pdfioFileGetKeywords">pdfioFileGetKeywords</a></li>
|
||||
<li><a href="#pdfioFileGetLanguage">pdfioFileGetLanguage</a></li>
|
||||
<li><a href="#pdfioFileGetModificationDate">pdfioFileGetModificationDate</a></li>
|
||||
<li><a href="#pdfioFileGetName">pdfioFileGetName</a></li>
|
||||
<li><a href="#pdfioFileGetNumObjs">pdfioFileGetNumObjs</a></li>
|
||||
@ -434,6 +437,7 @@ span.string {
|
||||
<li><a href="#pdfioFileSetCreationDate">pdfioFileSetCreationDate</a></li>
|
||||
<li><a href="#pdfioFileSetCreator">pdfioFileSetCreator</a></li>
|
||||
<li><a href="#pdfioFileSetKeywords">pdfioFileSetKeywords</a></li>
|
||||
<li><a href="#pdfioFileSetLanguage">pdfioFileSetLanguage</a></li>
|
||||
<li><a href="#pdfioFileSetModificationDate">pdfioFileSetModificationDate</a></li>
|
||||
<li><a href="#pdfioFileSetPermissions">pdfioFileSetPermissions</a></li>
|
||||
<li><a href="#pdfioFileSetSubject">pdfioFileSetSubject</a></li>
|
||||
@ -728,7 +732,7 @@ password_cb(<span class="reserved">void</span> *data, <span class="reserved">con
|
||||
<span class="reserved">return</span> (<span class="string">"Password42"</span>);
|
||||
}
|
||||
</code></pre>
|
||||
<p>The error callback is called for both errors and warnings and accepts the <code>pdfio_file_t</code> pointer, a message string, and the callback pointer value, for example:</p>
|
||||
<p>The error callback is called for both errors and warnings and accepts the <code>pdfio_file_t</code> pointer, a message string, and the callback pointer value. It returns <code>true</code> to continue processing the file or <code>false</code> to stop, for example:</p>
|
||||
<pre><code class="language-c"><span class="reserved">bool</span>
|
||||
error_cb(pdfio_file_t *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *message, <span class="reserved">void</span> *data)
|
||||
{
|
||||
@ -736,11 +740,14 @@ error_cb(pdfio_file_t *pdf, <span class="reserved">const</span> <span class="res
|
||||
|
||||
fprintf(stderr, <span class="string">"%s: %s\n"</span>, pdfioFileGetName(pdf), message);
|
||||
|
||||
<span class="comment">// Return false to treat warnings as errors</span>
|
||||
<span class="reserved">return</span> (<span class="reserved">false</span>);
|
||||
<span class="comment">// Return true for warning messages (continue) and false for errors (stop)</span>
|
||||
<span class="reserved">return</span> (!strncmp(message, <span class="string">"WARNING:"</span>, <span class="number">8</span>));
|
||||
}
|
||||
</code></pre>
|
||||
<p>The default error callback (<code>NULL</code>) does the equivalent of the above.</p>
|
||||
<blockquote>
|
||||
<p>Note: Many errors are unrecoverable, so PDFio ignores the return value from the error callback and always stops processing the PDF file. Warning messages start with the prefix "WARNING:" while errors have no prefix.</p>
|
||||
</blockquote>
|
||||
<p>Each PDF file contains one or more pages. The <a href="#pdfioFileGetNumPages"><code>pdfioFileGetNumPages</code></a> function returns the number of pages in the file while the <a href="#pdfioFileGetPage"><code>pdfioFileGetPage</code></a> function gets the specified page in the PDF file:</p>
|
||||
<pre><code class="language-c">pdfio_file_t *pdf; <span class="comment">// PDF file</span>
|
||||
size_t i; <span class="comment">// Looping var</span>
|
||||
@ -2594,7 +2601,7 @@ dd->y = row_y - row->height;
|
||||
<tr><th>pdf</th>
|
||||
<td class="description">PDF file</td></tr>
|
||||
<tr><th>num_colors</th>
|
||||
<td class="description">Number of colors (1 or 3)</td></tr>
|
||||
<td class="description">Number of colors (1, 3, or 4)</td></tr>
|
||||
<tr><th>cs</th>
|
||||
<td class="description">Color space enumeration</td></tr>
|
||||
</tbody></table>
|
||||
@ -2602,7 +2609,8 @@ dd->y = row_y - row->height;
|
||||
<p class="description">Color array</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function creates a color array for a standard <code>PDFIO_CS_</code> enumerated color space.
|
||||
The "num_colors" argument must be <code>1</code> for grayscale and <code>3</code> for RGB color.</p>
|
||||
The "num_colors" argument must be <code>1</code> for grayscale, <code>3</code> for RGB color, and
|
||||
<code>4</code> for CMYK color.</p>
|
||||
<h3 class="function"><a id="pdfioArrayGetArray">pdfioArrayGetArray</a></h3>
|
||||
<p class="description">Get an array value from an array.</p>
|
||||
<p class="code">
|
||||
@ -2746,7 +2754,7 @@ size_t pdfioArrayGetSize(<a href="#pdfio_array_t">pdfio_array_t</a> *a);</p>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Value type</p>
|
||||
<h3 class="function"><a id="pdfioArrayRemove">pdfioArrayRemove</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.4 </span><a id="pdfioArrayRemove">pdfioArrayRemove</a></h3>
|
||||
<p class="description">Remove an array entry.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">bool</span> pdfioArrayRemove(<a href="#pdfio_array_t">pdfio_array_t</a> *a, size_t n);</p>
|
||||
@ -2951,7 +2959,7 @@ using the <a href="#pdfioPageDictAddImage"><code>pdfioPageDictAddImage</code></a
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
||||
<h3 class="function"><a id="pdfioContentPathEnd">pdfioContentPathEnd</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.1 </span><a id="pdfioContentPathEnd">pdfioContentPathEnd</a></h3>
|
||||
<p class="description">Clear the current path.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">bool</span> pdfioContentPathEnd(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);</p>
|
||||
@ -3441,7 +3449,7 @@ are 0, a solid line is drawn.</p>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
||||
<h3 class="function"><a id="pdfioContentTextMeasure">pdfioContentTextMeasure</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.2 </span><a id="pdfioContentTextMeasure">pdfioContentTextMeasure</a></h3>
|
||||
<p class="description">Measure a text string and return its width.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">double</span> pdfioContentTextMeasure(<a href="#pdfio_obj_t">pdfio_obj_t</a> *font, <span class="reserved">const</span> <span class="reserved">char</span> *s, <span class="reserved">double</span> size);</p>
|
||||
@ -3459,7 +3467,9 @@ are 0, a solid line is drawn.</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function measures the given text string "s" and returns its width based
|
||||
on "size". The text string must always use the UTF-8 (Unicode) encoding but
|
||||
any control characters (such as newlines) are ignored.</p>
|
||||
any control characters (such as newlines) are ignored.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><a id="pdfioContentTextMoveLine">pdfioContentTextMoveLine</a></h3>
|
||||
<p class="description">Move to the next line and offset.</p>
|
||||
<p class="code">
|
||||
@ -3490,7 +3500,7 @@ any control characters (such as newlines) are ignored.</p>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
||||
<h3 class="function"><a id="pdfioContentTextNewLine">pdfioContentTextNewLine</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.2 </span><a id="pdfioContentTextNewLine">pdfioContentTextNewLine</a></h3>
|
||||
<p class="description">Move to the next line.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">bool</span> pdfioContentTextNewLine(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st);</p>
|
||||
@ -3501,7 +3511,7 @@ any control characters (such as newlines) are ignored.</p>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
||||
<h3 class="function"><a id="pdfioContentTextNewLineShow">pdfioContentTextNewLineShow</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.2 </span><a id="pdfioContentTextNewLineShow">pdfioContentTextNewLineShow</a></h3>
|
||||
<p class="description">Move to the next line and show text.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">bool</span> pdfioContentTextNewLineShow(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, <span class="reserved">double</span> ws, <span class="reserved">double</span> cs, <span class="reserved">bool</span> unicode, <span class="reserved">const</span> <span class="reserved">char</span> *s);</p>
|
||||
@ -3524,8 +3534,10 @@ any control characters (such as newlines) are ignored.</p>
|
||||
<p class="discussion">This function moves to the next line and then shows some text with optional
|
||||
word and character spacing in a PDF content stream. The "unicode" argument
|
||||
specifies that the current font maps to full Unicode. The "s" argument
|
||||
specifies a UTF-8 encoded string.</p>
|
||||
<h3 class="function"><a id="pdfioContentTextNewLineShowf">pdfioContentTextNewLineShowf</a></h3>
|
||||
specifies a UTF-8 encoded string.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><span class="info"> PDFio v1.2 </span><a id="pdfioContentTextNewLineShowf">pdfioContentTextNewLineShowf</a></h3>
|
||||
<p class="description">Show formatted text.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">bool</span> pdfioContentTextNewLineShowf(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, <span class="reserved">double</span> ws, <span class="reserved">double</span> cs, <span class="reserved">bool</span> unicode, <span class="reserved">const</span> <span class="reserved">char</span> *format, ...);</p>
|
||||
@ -3550,7 +3562,9 @@ specifies a UTF-8 encoded string.</p>
|
||||
<p class="discussion">This function moves to the next line and shows some formatted text with
|
||||
optional word and character spacing in a PDF content stream. The "unicode"
|
||||
argument specifies that the current font maps to full Unicode. The "format"
|
||||
argument specifies a UTF-8 encoded <code>printf</code>-style format string.</p>
|
||||
argument specifies a UTF-8 encoded <code>printf</code>-style format string.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><a id="pdfioContentTextShow">pdfioContentTextShow</a></h3>
|
||||
<p class="description">Show text.</p>
|
||||
<p class="code">
|
||||
@ -3613,7 +3627,7 @@ argument specifies an array of UTF-8 encoded strings.</p>
|
||||
<p class="discussion">This function shows some formatted text in a PDF content stream. The
|
||||
"unicode" argument specifies that the current font maps to full Unicode.
|
||||
The "format" argument specifies a UTF-8 encoded <code>printf</code>-style format string.</p>
|
||||
<h3 class="function"><a id="pdfioDictClear">pdfioDictClear</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.4 </span><a id="pdfioDictClear">pdfioDictClear</a></h3>
|
||||
<p class="description">Remove a key/value pair from a dictionary.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">bool</span> pdfioDictClear(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, <span class="reserved">const</span> <span class="reserved">char</span> *key);</p>
|
||||
@ -3717,7 +3731,7 @@ time_t pdfioDictGetDate(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, <span cl
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Value</p>
|
||||
<h3 class="function"><a id="pdfioDictGetKey">pdfioDictGetKey</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.4 </span><a id="pdfioDictGetKey">pdfioDictGetKey</a></h3>
|
||||
<p class="description">Get the key for the specified pair.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">const</span> <span class="reserved">char</span> *pdfioDictGetKey(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, size_t n);</p>
|
||||
@ -3743,7 +3757,7 @@ time_t pdfioDictGetDate(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, <span cl
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Value</p>
|
||||
<h3 class="function"><a id="pdfioDictGetNumPairs">pdfioDictGetNumPairs</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.4 </span><a id="pdfioDictGetNumPairs">pdfioDictGetNumPairs</a></h3>
|
||||
<p class="description">Get the number of key/value pairs in a dictionary.</p>
|
||||
<p class="code">
|
||||
size_t pdfioDictGetNumPairs(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict);</p>
|
||||
@ -3821,7 +3835,7 @@ size_t pdfioDictGetNumPairs(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict);</p>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Value type</p>
|
||||
<h3 class="function"><a id="pdfioDictIterateKeys">pdfioDictIterateKeys</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.1 </span><a id="pdfioDictIterateKeys">pdfioDictIterateKeys</a></h3>
|
||||
<p class="description">Iterate the keys in a dictionary.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">void</span> pdfioDictIterateKeys(<a href="#pdfio_dict_t">pdfio_dict_t</a> *dict, <a href="#pdfio_dict_cb_t">pdfio_dict_cb_t</a> cb, <span class="reserved">void</span> *cb_data);</p>
|
||||
@ -3848,7 +3862,9 @@ my_dict_cb(pdfio_dict_t *dict, const char *key, void *cb_data)
|
||||
</pre>
|
||||
|
||||
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>
|
||||
<p class="description">Set a key array in a dictionary.</p>
|
||||
<p class="code">
|
||||
@ -4031,6 +4047,46 @@ have been iterated.</p>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
||||
<h3 class="function"><span class="info"> PDFio 1.6 </span><a id="pdfioFileAddOutputIntent">pdfioFileAddOutputIntent</a></h3>
|
||||
<p class="description">Add an OutputIntent to a file.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">void</span> pdfioFileAddOutputIntent(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *subtype, <span class="reserved">const</span> <span class="reserved">char</span> *condition, <span class="reserved">const</span> <span class="reserved">char</span> *cond_id, <span class="reserved">const</span> <span class="reserved">char</span> *reg_name, <span class="reserved">const</span> <span class="reserved">char</span> *info, <a href="#pdfio_obj_t">pdfio_obj_t</a> *profile);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>pdf</th>
|
||||
<td class="description">PDF file</td></tr>
|
||||
<tr><th>subtype</th>
|
||||
<td class="description">Intent subtype (standard)</td></tr>
|
||||
<tr><th>condition</th>
|
||||
<td class="description">Condition name or <code>NULL</code> for none</td></tr>
|
||||
<tr><th>cond_id</th>
|
||||
<td class="description">Identifier such as registration name or <code>NULL</code> for none</td></tr>
|
||||
<tr><th>reg_name</th>
|
||||
<td class="description">Registry URL or <code>NULL</code> for none</td></tr>
|
||||
<tr><th>info</th>
|
||||
<td class="description">Description or <code>NULL</code> for none</td></tr>
|
||||
<tr><th>profile</th>
|
||||
<td class="description">ICC profile object or <code>NULL</code> for none</td></tr>
|
||||
</tbody></table>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function adds an OutputIntent dictionary to the PDF file catalog.
|
||||
The "subtype" argument specifies the intent subtype and is typically
|
||||
"GTS_PDFX" for PDF/X, "GTS_PDFA1" for PDF/A, or "ISO_PDFE1" for PDF/E.
|
||||
Passing <code>NULL</code> defaults the subtype to "GTS_PDFA1".<br>
|
||||
<br>
|
||||
The "condition" argument specifies a short name for the output intent, while
|
||||
the "info" argument specifies a longer description for the output intent.
|
||||
Both can be <code>NULL</code> to omit this information.<br>
|
||||
<br>
|
||||
The "cond_id" argument specifies a unique identifier such as a registration
|
||||
("CGATS001") or color space name ("sRGB"). The "reg_name" argument provides
|
||||
a URL for the identifier.<br>
|
||||
<br>
|
||||
The "profile" argument specifies an ICC profile object for the output
|
||||
condition. If <code>NULL</code>, the PDF consumer will attempt to look up the correct
|
||||
profile using the "cond_id" value.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><a id="pdfioFileClose">pdfioFileClose</a></h3>
|
||||
<p class="description">Close a PDF file and free all memory used for it.</p>
|
||||
<p class="code">
|
||||
@ -4076,8 +4132,9 @@ CropBox for pages in the PDF file - if <code>NULL</code> then a default "Un
|
||||
of 8.27x11in (the intersection of US Letter and ISO A4) is used.<br>
|
||||
<br>
|
||||
The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||
and its data pointer - if <code>NULL</code> the default error handler is used that
|
||||
writes error messages to <code>stderr</code>.</p>
|
||||
and its data pointer - if <code>NULL</code> then the default error handler is used that
|
||||
writes error messages to <code>stderr</code>. The error handler callback should return
|
||||
<code>true</code> to continue writing the PDF file or <code>false</code> to stop.</p>
|
||||
<h3 class="function"><a id="pdfioFileCreateArrayObj">pdfioFileCreateArrayObj</a></h3>
|
||||
<p class="description">Create a new object in a PDF file containing an array.</p>
|
||||
<p class="code">
|
||||
@ -4143,8 +4200,33 @@ specifies the font nane:
|
||||
<p class="discussion">Aside from "Symbol" and "Zapf-Dingbats", Base fonts use the Windows CP1252
|
||||
(ISO-8859-1 with additional characters such as the Euro symbol) subset of
|
||||
Unicode.</p>
|
||||
<h3 class="function"><span class="info"> PDFio v1.6 </span><a id="pdfioFileCreateFontObjFromData">pdfioFileCreateFontObjFromData</a></h3>
|
||||
<p class="description">Add a font in memory to a PDF file.</p>
|
||||
<p class="code">
|
||||
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateFontObjFromData(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">void</span> *data, size_t datasize, <span class="reserved">bool</span> unicode);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>pdf</th>
|
||||
<td class="description">PDF file</td></tr>
|
||||
<tr><th>data</th>
|
||||
<td class="description">Font data in memory</td></tr>
|
||||
<tr><th>datasize</th>
|
||||
<td class="description">Size of font in memory</td></tr>
|
||||
<tr><th>unicode</th>
|
||||
<td class="description">Force Unicode</td></tr>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Font object</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function embeds TrueType/OpenType font data into a PDF file. The
|
||||
"unicode" parameter controls whether the font is encoded for two-byte
|
||||
characters (potentially full Unicode, but more typically a subset)
|
||||
or to only support the Windows CP1252 (ISO-8859-1 with additional
|
||||
characters such as the Euro symbol) subset of Unicode.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><a id="pdfioFileCreateFontObjFromFile">pdfioFileCreateFontObjFromFile</a></h3>
|
||||
<p class="description">Add a font object to a PDF file.</p>
|
||||
<p class="description">Add a font file to a PDF file.</p>
|
||||
<p class="code">
|
||||
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateFontObjFromFile(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *filename, <span class="reserved">bool</span> unicode);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
@ -4159,7 +4241,7 @@ Unicode.</p>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Font object</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function embeds a TrueType/OpenType font into a PDF file. The
|
||||
<p class="discussion">This function embeds a TrueType/OpenType font file into a PDF file. The
|
||||
"unicode" parameter controls whether the font is encoded for two-byte
|
||||
characters (potentially full Unicode, but more typically a subset)
|
||||
or to only support the Windows CP1252 (ISO-8859-1 with additional
|
||||
@ -4260,7 +4342,7 @@ image on the page.<br>
|
||||
Note: Currently PNG support is limited to grayscale, RGB, or indexed files
|
||||
without interlacing or alpha. Transparency (masking) based on color/index
|
||||
is supported.</blockquote>
|
||||
<h3 class="function"><a id="pdfioFileCreateNameObj">pdfioFileCreateNameObj</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.4 </span><a id="pdfioFileCreateNameObj">pdfioFileCreateNameObj</a></h3>
|
||||
<p class="description">Create a new object in a PDF file containing a name.</p>
|
||||
<p class="code">
|
||||
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateNameObj(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *name);</p>
|
||||
@ -4275,8 +4357,10 @@ is supported.</blockquote>
|
||||
<p class="description">New object</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function creates a new object with a name value in a PDF file.
|
||||
You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file.</p>
|
||||
<h3 class="function"><a id="pdfioFileCreateNumberObj">pdfioFileCreateNumberObj</a></h3>
|
||||
You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><span class="info"> PDFio v1.2 </span><a id="pdfioFileCreateNumberObj">pdfioFileCreateNumberObj</a></h3>
|
||||
<p class="description">Create a new object in a PDF file containing a number.</p>
|
||||
<p class="code">
|
||||
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateNumberObj(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">double</span> number);</p>
|
||||
@ -4291,7 +4375,9 @@ You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write t
|
||||
<p class="description">New object</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function creates a new object with a number value in a PDF file.
|
||||
You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file.</p>
|
||||
You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><a id="pdfioFileCreateObj">pdfioFileCreateObj</a></h3>
|
||||
<p class="description">Create a new object in a PDF file.</p>
|
||||
<p class="code">
|
||||
@ -4352,8 +4438,9 @@ CropBox for pages in the PDF file - if <code>NULL</code> then a default "Un
|
||||
of 8.27x11in (the intersection of US Letter and ISO A4) is used.<br>
|
||||
<br>
|
||||
The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||
and its data pointer - if <code>NULL</code> the default error handler is used that
|
||||
writes error messages to <code>stderr</code>.<br>
|
||||
and its data pointer - if <code>NULL</code> then the default error handler is used that
|
||||
writes error messages to <code>stderr</code>. The error handler callback should return
|
||||
<code>true</code> to continue writing the PDF file or <code>false</code> to stop.<br>
|
||||
<br>
|
||||
</p><blockquote>
|
||||
<em>Note</em>: Files created using this API are slightly larger than those
|
||||
@ -4372,7 +4459,7 @@ stored as indirect object references.</blockquote>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Contents stream</p>
|
||||
<h3 class="function"><a id="pdfioFileCreateStringObj">pdfioFileCreateStringObj</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.2 </span><a id="pdfioFileCreateStringObj">pdfioFileCreateStringObj</a></h3>
|
||||
<p class="description">Create a new object in a PDF file containing a string.</p>
|
||||
<p class="code">
|
||||
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateStringObj(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *string);</p>
|
||||
@ -4387,7 +4474,9 @@ stored as indirect object references.</blockquote>
|
||||
<p class="description">New object</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function creates a new object with a string value in a PDF file.
|
||||
You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file.</p>
|
||||
You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write the object to the file.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><a id="pdfioFileCreateTemporary">pdfioFileCreateTemporary</a></h3>
|
||||
<p class="description"></p>
|
||||
<p class="code">
|
||||
@ -4510,6 +4599,24 @@ time_t pdfioFileGetCreationDate(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf);<
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Keywords string or <code>NULL</code> for none</p>
|
||||
<h3 class="function"><span class="info"> PDFio 1.6 </span><a id="pdfioFileGetLanguage">pdfioFileGetLanguage</a></h3>
|
||||
<p class="description">Get the language metadata for a PDF file.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">const</span> <span class="reserved">char</span> *pdfioFileGetLanguage(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>pdf</th>
|
||||
<td class="description">PDF file</td></tr>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Language or <code>NULL</code> for none</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function gets the (primary/default) language metadata, if any, for a PDF
|
||||
file. The returned string is an IETF BCP 47 language tag of the form
|
||||
"lang-REGION". For example, the string "en-CA" specifies Canadian English
|
||||
and the string "fr-CA" specifies Canadian French.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><a id="pdfioFileGetModificationDate">pdfioFileGetModificationDate</a></h3>
|
||||
<p class="description">Get the most recent modification date for a PDF file.</p>
|
||||
<p class="code">
|
||||
@ -4670,8 +4777,15 @@ cancel the open. If <code>NULL</code> is specified for the callback function an
|
||||
PDF file requires a password, the open will always fail.<br>
|
||||
<br>
|
||||
The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||
and its data pointer - if <code>NULL</code> the default error handler is used that
|
||||
writes error messages to <code>stderr</code>.</p>
|
||||
and its data pointer - if <code>NULL</code> then the default error handler is used that
|
||||
writes error messages to <code>stderr</code>. The error handler callback should return
|
||||
<code>true</code> to continue reading the PDF file or <code>false</code> to stop.<br>
|
||||
<br>
|
||||
</p><blockquote>
|
||||
Note: Error messages starting with "WARNING:" are actually warning
|
||||
messages - the callback should normally return <code>true</code> to allow PDFio to
|
||||
try to resolve the issue. In addition, some errors are unrecoverable and
|
||||
ignore the return value of the error callback.</blockquote>
|
||||
<h3 class="function"><a id="pdfioFileSetAuthor">pdfioFileSetAuthor</a></h3>
|
||||
<p class="description">Set the author for a PDF file.</p>
|
||||
<p class="code">
|
||||
@ -4716,6 +4830,24 @@ writes error messages to <code>stderr</code>.</p>
|
||||
<tr><th>value</th>
|
||||
<td class="description">Value</td></tr>
|
||||
</tbody></table>
|
||||
<h3 class="function"><span class="info"> PDFio 1.6 </span><a id="pdfioFileSetLanguage">pdfioFileSetLanguage</a></h3>
|
||||
<p class="description">Set the language metadata for a PDF file.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">void</span> pdfioFileSetLanguage(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *value);</p>
|
||||
<h4 class="parameters">Parameters</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>pdf</th>
|
||||
<td class="description">PDF file</td></tr>
|
||||
<tr><th>value</th>
|
||||
<td class="description">Value</td></tr>
|
||||
</tbody></table>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function sets the (primary/default) language metadata for a PDF file.
|
||||
The "value" argument is an IETF BCP 47 language tag string of the form
|
||||
"lang-REGION". For example, the string "en-CA" specifies Canadian English
|
||||
and the string "fr-CA" specifies Canadian French.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><a id="pdfioFileSetModificationDate">pdfioFileSetModificationDate</a></h3>
|
||||
<p class="description">Set the modification date for a PDF file.</p>
|
||||
<p class="code">
|
||||
@ -4892,7 +5024,7 @@ size_t pdfioObjGetLength(<a href="#pdfio_obj_t">pdfio_obj_t</a> *obj);</p>
|
||||
</tbody></table>
|
||||
<h4 class="returnvalue">Return Value</h4>
|
||||
<p class="description">Length in bytes or <code>0</code> for none</p>
|
||||
<h3 class="function"><a id="pdfioObjGetName">pdfioObjGetName</a></h3>
|
||||
<h3 class="function"><span class="info"> PDFio v1.4 </span><a id="pdfioObjGetName">pdfioObjGetName</a></h3>
|
||||
<p class="description">Get the name value associated with an object.</p>
|
||||
<p class="code">
|
||||
<span class="reserved">const</span> <span class="reserved">char</span> *pdfioObjGetName(<a href="#pdfio_obj_t">pdfio_obj_t</a> *obj);</p>
|
||||
@ -5168,8 +5300,9 @@ ssize_t pdfioStreamPeek(<a href="#pdfio_stream_t">pdfio_stream_t</a> *st, <span
|
||||
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
|
||||
<h4 class="discussion">Discussion</h4>
|
||||
<p class="discussion">This function writes a formatted string to a stream. In addition to the
|
||||
standard <code>printf</code> format characters, you can use "%N" to format a PDF name
|
||||
value ("/Name") and "%S" to format a PDF string ("(String)") value.</p>
|
||||
standard <code>printf</code> format characters, you can use "%H" to format a HTML/XML
|
||||
string value, "%N" to format a PDF name value ("/Name"), and "%S" to format
|
||||
a PDF string ("(String)") value.</p>
|
||||
<h3 class="function"><a id="pdfioStreamPutChar">pdfioStreamPutChar</a></h3>
|
||||
<p class="description">Write a single character to a stream.</p>
|
||||
<p class="code">
|
||||
@ -5393,6 +5526,7 @@ typedef enum <a href="#pdfio_valtype_e">pdfio_valtype_e</a> pdfio_valtype_t;
|
||||
<h4 class="constants">Constants</h4>
|
||||
<table class="list"><tbody>
|
||||
<tr><th>PDFIO_CS_ADOBE </th><td class="description">AdobeRGB 1998</td></tr>
|
||||
<tr><th>PDFIO_CS_CGATS001 </th><td class="description">CGATS001 (CMYK)</td></tr>
|
||||
<tr><th>PDFIO_CS_P3_D65 </th><td class="description">Display P3</td></tr>
|
||||
<tr><th>PDFIO_CS_SRGB </th><td class="description">sRGB</td></tr>
|
||||
</tbody></table>
|
||||
@ -5403,7 +5537,7 @@ typedef enum <a href="#pdfio_valtype_e">pdfio_valtype_e</a> pdfio_valtype_t;
|
||||
<tr><th>PDFIO_ENCRYPTION_AES_128 </th><td class="description">128-bit AES encryption (PDF 1.6)</td></tr>
|
||||
<tr><th>PDFIO_ENCRYPTION_NONE </th><td class="description">No encryption</td></tr>
|
||||
<tr><th>PDFIO_ENCRYPTION_RC4_128 </th><td class="description">128-bit RC4 encryption (PDF 1.4)</td></tr>
|
||||
<tr><th>PDFIO_ENCRYPTION_RC4_40 </th><td class="description">40-bit RC4 encryption (PDF 1.3)</td></tr>
|
||||
<tr><th>PDFIO_ENCRYPTION_RC4_40 </th><td class="description">40-bit RC4 encryption (PDF 1.3, reading only)</td></tr>
|
||||
</tbody></table>
|
||||
<h3 class="enumeration"><a id="pdfio_filter_e">pdfio_filter_e</a></h3>
|
||||
<p class="description">Compression/decompression filters for streams</p>
|
||||
|
12
doc/pdfio.md
12
doc/pdfio.md
@ -343,8 +343,8 @@ password_cb(void *data, const char *filename)
|
||||
```
|
||||
|
||||
The error callback is called for both errors and warnings and accepts the
|
||||
`pdfio_file_t` pointer, a message string, and the callback pointer value, for
|
||||
example:
|
||||
`pdfio_file_t` pointer, a message string, and the callback pointer value. It
|
||||
returns `true` to continue processing the file or `false` to stop, for example:
|
||||
|
||||
```c
|
||||
bool
|
||||
@ -354,13 +354,17 @@ error_cb(pdfio_file_t *pdf, const char *message, void *data)
|
||||
|
||||
fprintf(stderr, "%s: %s\n", pdfioFileGetName(pdf), message);
|
||||
|
||||
// Return false to treat warnings as errors
|
||||
return (false);
|
||||
// Return true for warning messages (continue) and false for errors (stop)
|
||||
return (!strncmp(message, "WARNING:", 8));
|
||||
}
|
||||
```
|
||||
|
||||
The default error callback (`NULL`) does the equivalent of the above.
|
||||
|
||||
> Note: Many errors are unrecoverable, so PDFio ignores the return value from
|
||||
> the error callback and always stops processing the PDF file. Warning messages
|
||||
> start with the prefix "WARNING:" while errors have no prefix.
|
||||
|
||||
Each PDF file contains one or more pages. The [`pdfioFileGetNumPages`](@@)
|
||||
function returns the number of pages in the file while the
|
||||
[`pdfioFileGetPage`](@@) function gets the specified page in the PDF file:
|
||||
|
@ -32,11 +32,11 @@ if test $(grep AC_INIT configure.ac | awk '{print $2}') != "[$version],"; then
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $(head -4 CHANGES.md | tail -1 | awk '{print $1}') != "v$version"; then
|
||||
if test $(head -5 CHANGES.md | tail -1 | awk '{print $1}') != "v$version"; then
|
||||
echo "Still need to update CHANGES.md version number."
|
||||
status=1
|
||||
fi
|
||||
if test $(head -4 CHANGES.md | tail -1 | awk '{print $3}') = "YYYY-MM-DD"; then
|
||||
if test $(head -5 CHANGES.md | tail -1 | awk '{print $3}') = "YYYY-MM-DD"; then
|
||||
echo "Still need to update CHANGES.md release date."
|
||||
status=1
|
||||
fi
|
||||
|
@ -640,6 +640,8 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
|
||||
//
|
||||
// 'pdfioArrayRemove()' - Remove an array entry.
|
||||
//
|
||||
// @since PDFio v1.4@
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` otherwise
|
||||
pdfioArrayRemove(pdfio_array_t *a, // I - Array
|
||||
|
532
pdfio-cgats001-compat.h
Normal file
532
pdfio-cgats001-compat.h
Normal file
@ -0,0 +1,532 @@
|
||||
/* CGATS001Compat-v2-micro.icc */
|
||||
static unsigned char CGATS001Compat_v2_micro_icc[] = {
|
||||
0,0,33,16,65,68,66,69,2,16,0,0,115,99,110,114,
|
||||
67,77,89,75,76,97,98,32,7,230,0,12,0,7,0,22,
|
||||
0,16,0,42,97,99,115,112,77,83,70,84,0,0,0,0,
|
||||
115,97,119,115,99,116,114,108,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,246,214,0,1,0,0,0,0,211,45,
|
||||
104,97,110,100,195,103,209,209,26,217,105,182,62,57,156,48,
|
||||
22,179,165,88,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,4,100,101,115,99,0,0,0,180,0,0,0,95,
|
||||
99,112,114,116,0,0,0,208,0,0,0,12,119,116,112,116,
|
||||
0,0,0,220,0,0,0,20,65,50,66,48,0,0,0,240,
|
||||
0,0,32,32,100,101,115,99,0,0,0,0,0,0,0,5,
|
||||
117,67,77,89,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
116,101,120,116,0,0,0,0,67,67,48,0,88,89,90,32,
|
||||
0,0,0,0,0,0,246,214,0,1,0,0,0,0,211,45,
|
||||
109,102,116,50,0,0,0,0,4,3,6,0,0,1,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
|
||||
0,48,0,2,0,0,10,35,16,0,22,155,28,150,35,8,
|
||||
41,37,47,68,53,83,59,90,65,90,71,78,77,74,83,48,
|
||||
89,25,94,245,100,188,106,133,112,43,117,193,123,79,128,187,
|
||||
134,23,139,107,144,166,149,206,154,244,160,21,165,30,170,40,
|
||||
175,51,180,64,185,71,190,81,195,91,200,103,205,100,210,85,
|
||||
215,65,220,33,224,252,229,190,234,87,238,218,243,138,248,23,
|
||||
252,104,255,255,0,0,8,214,13,206,19,98,24,129,30,6,
|
||||
35,77,40,160,46,0,51,86,56,193,62,41,67,165,73,37,
|
||||
78,162,84,51,89,175,95,46,100,173,106,10,111,107,116,191,
|
||||
121,244,127,36,132,82,137,98,142,111,147,127,152,147,157,151,
|
||||
162,172,167,211,173,14,178,88,183,186,189,52,194,199,200,90,
|
||||
205,244,211,154,217,72,223,1,228,146,234,19,239,215,245,132,
|
||||
251,7,255,255,0,0,9,30,14,44,19,200,24,222,30,99,
|
||||
35,150,40,200,45,246,51,35,56,84,61,138,66,209,72,33,
|
||||
77,126,82,234,88,89,93,211,99,74,104,190,110,47,115,148,
|
||||
120,237,126,59,131,126,136,180,141,231,147,29,152,90,157,169,
|
||||
163,18,168,158,174,79,180,41,186,39,192,69,198,114,204,164,
|
||||
210,199,216,201,222,161,228,73,233,160,238,170,243,244,248,186,
|
||||
252,225,255,255,0,0,8,135,13,57,18,115,23,60,28,123,
|
||||
33,106,38,94,43,92,48,99,53,110,58,133,63,163,68,202,
|
||||
73,244,79,35,84,77,89,109,94,139,99,158,104,170,109,176,
|
||||
114,172,119,156,124,135,129,112,134,74,139,35,143,254,148,223,
|
||||
153,201,158,194,163,209,168,251,174,67,179,163,185,36,190,202,
|
||||
196,145,202,125,208,133,214,166,220,240,227,93,234,118,241,193,
|
||||
249,40,255,255,255,0,128,0,128,0,214,110,127,181,126,251,
|
||||
173,86,127,150,126,88,131,53,127,186,126,83,86,78,128,50,
|
||||
126,192,31,100,129,254,128,28,251,120,125,171,146,104,211,247,
|
||||
125,155,142,161,171,46,125,194,139,106,129,32,126,37,136,221,
|
||||
84,57,126,196,134,230,28,170,128,62,134,99,248,103,123,237,
|
||||
165,11,209,76,123,249,158,148,168,209,124,68,152,192,127,22,
|
||||
124,213,147,218,82,110,125,139,143,116,26,73,126,145,140,106,
|
||||
245,211,122,201,183,251,206,211,122,205,174,205,166,160,123,35,
|
||||
166,133,125,42,123,200,159,52,80,217,124,141,151,243,24,82,
|
||||
125,10,144,4,243,199,122,9,203,97,204,207,121,247,191,95,
|
||||
164,205,122,74,180,169,123,179,123,1,171,70,79,144,123,201,
|
||||
163,159,22,200,123,191,143,103,242,42,121,140,223,132,203,50,
|
||||
121,98,208,125,163,73,121,169,195,108,122,115,122,107,184,86,
|
||||
78,150,123,56,174,96,21,158,122,200,142,157,227,233,142,168,
|
||||
125,57,191,208,140,54,124,173,154,204,138,30,124,141,116,50,
|
||||
136,124,124,247,74,84,135,121,125,199,20,34,137,177,127,236,
|
||||
224,239,140,172,141,230,189,193,138,73,138,227,152,241,136,91,
|
||||
136,116,114,87,134,238,134,171,72,129,134,18,133,143,18,45,
|
||||
135,202,133,165,222,108,139,13,159,8,187,88,136,200,153,179,
|
||||
150,192,134,245,148,251,112,129,133,173,145,24,70,249,132,229,
|
||||
142,34,16,97,134,27,137,235,220,58,137,245,176,93,185,57,
|
||||
135,184,168,203,148,204,133,239,161,238,110,212,132,170,155,243,
|
||||
69,169,131,235,151,169,15,9,132,165,138,43,218,113,137,45,
|
||||
194,46,183,137,134,242,184,87,147,63,133,43,175,95,109,144,
|
||||
131,243,167,166,68,161,131,41,161,166,14,7,131,135,137,124,
|
||||
217,12,136,152,212,229,182,53,134,99,200,164,145,250,132,152,
|
||||
189,153,108,133,131,103,180,155,67,209,130,165,170,33,13,68,
|
||||
130,183,136,248,201,213,157,235,123,46,169,121,153,123,122,234,
|
||||
136,53,149,117,123,19,101,12,146,14,123,193,62,13,143,191,
|
||||
124,214,9,84,144,204,127,187,199,84,156,73,138,107,167,205,
|
||||
151,198,136,7,134,185,147,217,134,42,99,150,144,153,132,246,
|
||||
60,167,142,98,132,135,8,113,142,126,132,36,197,113,154,202,
|
||||
153,237,165,235,150,98,149,123,132,247,146,119,145,165,98,4,
|
||||
143,82,142,167,59,93,141,42,140,19,7,182,140,158,133,55,
|
||||
195,166,153,193,169,229,164,50,149,94,163,134,131,66,145,135,
|
||||
157,217,96,149,142,92,153,26,58,81,140,51,150,79,7,25,
|
||||
139,41,132,204,194,42,153,10,186,48,162,214,148,166,177,236,
|
||||
129,253,144,210,170,123,95,138,141,175,164,116,57,139,139,110,
|
||||
159,13,6,174,138,21,132,132,192,255,152,123,203,106,161,198,
|
||||
148,25,193,44,128,245,144,72,184,9,94,179,141,45,177,103,
|
||||
56,235,138,244,165,100,6,89,137,77,132,75,177,37,173,245,
|
||||
122,2,147,243,167,169,121,209,117,242,161,206,122,23,85,235,
|
||||
156,180,122,225,49,88,150,201,124,2,0,239,149,92,127,195,
|
||||
175,57,172,141,135,237,146,202,166,25,133,179,116,224,160,67,
|
||||
132,66,84,210,155,60,131,120,48,93,152,11,131,193,0,226,
|
||||
147,96,128,133,173,202,171,58,150,19,145,79,164,217,146,68,
|
||||
115,118,159,2,143,29,83,154,154,5,140,217,47,124,150,201,
|
||||
140,54,0,206,145,182,128,139,172,145,170,52,164,133,144,19,
|
||||
163,219,159,13,114,58,158,5,154,89,82,143,152,241,150,198,
|
||||
46,202,149,168,148,235,0,217,144,85,128,147,171,106,169,130,
|
||||
179,137,143,32,163,20,172,85,113,80,157,63,162,160,81,202,
|
||||
152,62,161,248,46,73,148,212,155,139,0,219,143,72,128,148,
|
||||
170,119,169,1,195,84,142,87,162,131,186,91,112,151,156,179,
|
||||
178,242,81,58,151,186,174,21,45,236,148,82,159,13,0,222,
|
||||
142,134,128,150,154,49,190,221,121,79,127,198,182,195,121,6,
|
||||
100,136,175,54,121,74,71,42,168,146,122,23,36,45,165,99,
|
||||
123,14,0,0,143,153,128,0,152,249,189,121,134,22,127,13,
|
||||
181,72,132,75,99,211,173,165,130,235,70,115,166,244,130,111,
|
||||
35,202,163,124,130,239,0,0,142,213,128,0,152,46,188,21,
|
||||
146,252,126,42,179,238,143,148,98,240,172,64,140,239,69,182,
|
||||
165,143,139,90,35,118,161,226,138,239,0,0,142,33,128,0,
|
||||
151,95,187,20,156,183,125,105,178,222,152,248,98,53,171,44,
|
||||
148,44,69,34,164,102,145,119,35,60,160,141,143,228,0,0,
|
||||
141,150,128,0,150,186,186,65,173,194,124,235,177,250,167,108,
|
||||
97,205,170,70,162,133,68,210,163,131,159,209,35,33,159,106,
|
||||
150,67,0,0,141,57,128,0,150,10,185,176,188,68,124,138,
|
||||
177,69,180,40,97,126,169,128,174,82,68,159,162,198,170,52,
|
||||
35,38,158,179,151,196,0,0,140,230,128,0,132,180,208,159,
|
||||
120,243,108,190,198,205,120,107,83,203,189,201,120,144,56,144,
|
||||
181,241,121,63,22,242,178,158,122,81,0,0,137,249,128,0,
|
||||
132,84,206,246,132,213,108,102,197,80,130,218,83,105,188,24,
|
||||
129,168,56,75,180,0,129,93,23,73,176,8,130,10,0,0,
|
||||
138,37,128,0,132,67,205,78,144,147,108,56,195,164,141,107,
|
||||
83,48,186,79,139,41,56,52,178,35,138,58,23,180,173,196,
|
||||
137,41,0,0,138,73,128,0,132,35,203,251,156,155,108,55,
|
||||
194,41,152,56,83,60,184,196,149,21,56,85,176,133,148,4,
|
||||
24,42,171,234,144,154,0,0,138,101,128,0,131,240,202,242,
|
||||
168,242,108,66,193,0,163,54,83,110,183,140,159,100,56,150,
|
||||
175,80,157,234,24,158,170,120,144,165,0,0,138,121,128,0,
|
||||
131,190,202,18,181,197,108,88,192,13,174,136,83,181,182,138,
|
||||
170,24,56,250,174,76,165,33,25,38,169,99,145,1,0,0,
|
||||
138,136,128,0,235,21,120,95,117,172,198,143,121,103,118,146,
|
||||
160,155,122,106,119,154,120,244,123,117,120,218,78,61,124,157,
|
||||
122,46,24,103,126,52,123,43,231,220,117,150,135,222,195,241,
|
||||
118,230,133,232,158,88,120,46,132,101,118,244,121,124,131,68,
|
||||
76,100,122,195,129,102,22,11,123,166,130,96,228,245,115,130,
|
||||
154,56,193,46,116,236,149,151,155,232,118,93,145,116,116,232,
|
||||
119,221,141,248,74,174,121,54,138,229,19,252,121,133,135,196,
|
||||
226,139,114,5,172,159,190,208,115,112,165,140,153,177,116,238,
|
||||
158,247,114,251,118,134,153,19,73,38,119,231,148,52,18,94,
|
||||
119,220,139,241,224,194,113,11,191,52,189,12,114,105,181,200,
|
||||
151,244,115,224,172,209,113,127,117,135,164,211,71,234,118,225,
|
||||
158,108,17,36,118,168,139,151,223,129,112,120,210,33,187,195,
|
||||
113,192,198,94,150,146,115,32,187,38,112,68,116,200,177,102,
|
||||
70,235,118,28,168,223,16,59,117,202,138,249,209,115,134,135,
|
||||
115,123,177,87,133,101,116,211,143,52,132,136,118,40,106,212,
|
||||
131,237,119,166,66,203,131,210,121,44,13,68,133,161,122,166,
|
||||
207,74,132,21,132,44,175,136,131,38,130,252,141,102,130,108,
|
||||
130,15,105,23,129,246,129,111,65,44,129,242,129,3,11,242,
|
||||
131,47,128,187,204,230,130,32,148,250,173,11,129,68,145,118,
|
||||
139,42,128,171,142,60,103,60,128,104,139,143,63,171,128,112,
|
||||
137,123,10,160,129,38,133,169,202,204,128,181,165,229,170,253,
|
||||
127,222,160,68,137,59,127,80,154,224,101,154,127,25,150,30,
|
||||
62,106,127,39,146,206,9,181,127,147,134,144,201,66,127,194,
|
||||
183,38,169,111,126,232,175,109,135,176,126,82,167,231,100,77,
|
||||
126,40,161,100,61,104,126,40,156,138,9,4,126,105,134,24,
|
||||
200,52,127,42,201,23,168,66,126,72,191,65,134,106,125,151,
|
||||
181,160,99,54,125,111,173,200,60,152,125,113,164,221,8,120,
|
||||
125,143,133,186,184,173,149,106,113,228,156,34,146,61,115,98,
|
||||
125,114,143,136,116,221,92,54,141,74,118,127,54,161,140,45,
|
||||
120,8,3,238,139,88,123,49,182,255,147,72,129,49,154,137,
|
||||
144,64,128,123,123,227,141,162,127,240,90,199,139,126,127,190,
|
||||
53,89,138,93,127,196,3,128,136,228,128,74,181,64,145,117,
|
||||
144,98,152,169,142,132,141,169,122,46,139,240,139,55,89,77,
|
||||
137,236,137,71,52,47,136,204,136,38,3,22,134,234,130,22,
|
||||
179,141,144,32,160,3,151,4,141,51,155,112,120,129,138,173,
|
||||
151,29,87,228,136,172,147,114,51,37,135,135,145,82,2,193,
|
||||
133,95,129,221,178,73,143,62,175,217,149,185,140,83,169,123,
|
||||
119,61,137,196,163,94,86,209,135,201,158,101,50,96,134,132,
|
||||
153,234,2,137,132,59,129,182,177,102,142,167,192,110,148,187,
|
||||
139,188,184,74,118,48,137,28,176,117,85,236,135,30,170,208,
|
||||
49,180,133,217,160,46,2,88,131,104,129,150,161,39,165,31,
|
||||
112,232,135,104,160,39,114,94,107,178,155,186,115,225,77,78,
|
||||
151,243,117,130,41,135,150,141,118,177,0,66,137,171,126,52,
|
||||
160,0,163,78,126,58,134,90,158,94,125,202,106,159,153,235,
|
||||
126,68,76,76,150,41,126,114,40,187,148,150,126,116,0,60,
|
||||
135,218,127,249,158,179,161,163,140,195,132,230,156,194,138,139,
|
||||
105,69,152,84,136,161,75,40,148,163,135,100,39,242,146,245,
|
||||
134,224,0,50,134,74,128,34,157,132,160,84,154,226,131,173,
|
||||
155,126,151,25,104,13,151,13,147,166,74,49,147,72,145,0,
|
||||
39,88,145,123,143,118,0,46,133,35,128,31,156,138,159,124,
|
||||
169,118,130,195,154,160,164,33,103,23,150,32,159,51,73,88,
|
||||
146,97,155,208,38,210,144,100,150,43,0,40,132,62,128,27,
|
||||
155,211,158,242,184,169,130,0,154,13,177,217,102,77,149,124,
|
||||
171,165,72,175,145,184,167,171,38,95,143,176,153,237,0,36,
|
||||
131,152,128,24,139,20,181,218,112,19,115,151,175,83,113,97,
|
||||
90,95,169,85,114,209,62,89,164,67,116,78,27,220,162,240,
|
||||
117,20,0,0,132,76,128,0,138,120,180,61,125,106,115,25,
|
||||
173,150,124,255,89,217,167,107,124,81,61,228,162,62,124,151,
|
||||
27,203,160,109,125,6,0,0,131,187,128,0,137,192,178,136,
|
||||
137,145,114,53,171,233,135,226,88,255,165,185,134,144,61,56,
|
||||
160,141,133,174,27,150,158,104,133,23,0,0,131,37,128,0,
|
||||
136,247,177,65,150,121,113,106,170,160,145,137,88,50,164,101,
|
||||
144,140,60,162,159,30,142,229,27,110,156,173,140,81,0,0,
|
||||
130,194,128,0,136,101,176,88,163,151,112,222,169,174,159,42,
|
||||
87,167,163,100,155,105,60,52,158,16,153,106,27,92,155,60,
|
||||
144,208,0,0,130,140,128,0,135,225,175,208,177,149,112,130,
|
||||
169,4,171,225,87,60,162,144,167,47,59,221,157,49,163,199,
|
||||
27,68,154,81,146,112,0,0,130,90,128,0,118,47,199,165,
|
||||
111,81,96,137,191,214,112,85,73,93,184,132,113,146,47,37,
|
||||
178,156,114,188,14,114,176,12,115,215,0,0,129,66,128,0,
|
||||
118,37,198,9,123,103,96,145,189,252,122,224,73,95,182,83,
|
||||
122,140,47,79,176,27,122,242,15,16,173,6,123,149,0,0,
|
||||
129,65,128,0,118,26,196,25,134,225,96,81,188,12,133,19,
|
||||
73,32,180,78,131,219,47,67,173,249,131,127,15,152,170,90,
|
||||
131,15,0,0,129,64,128,0,117,232,194,153,146,128,96,44,
|
||||
186,112,143,187,72,249,178,157,141,124,47,72,172,34,141,8,
|
||||
16,17,168,31,136,88,0,0,129,63,128,0,117,180,193,153,
|
||||
158,127,96,36,185,65,154,198,72,250,177,80,152,1,47,90,
|
||||
170,197,151,16,16,120,166,98,139,34,0,0,129,63,128,0,
|
||||
117,138,192,236,171,6,96,44,184,93,166,88,73,12,176,73,
|
||||
163,22,47,127,169,175,158,184,16,201,165,41,139,89,0,0,
|
||||
129,62,128,0,215,58,112,125,107,98,182,48,114,183,110,9,
|
||||
147,81,116,191,112,146,110,79,118,168,115,18,69,242,120,110,
|
||||
117,99,17,41,122,4,118,21,212,37,109,25,125,61,179,174,
|
||||
111,175,125,19,145,41,114,6,125,27,108,110,116,58,125,82,
|
||||
68,67,118,17,125,118,15,115,119,100,124,211,209,76,106,99,
|
||||
143,18,176,232,109,33,140,81,142,189,111,175,137,216,106,111,
|
||||
114,31,135,215,66,173,115,252,133,236,14,12,117,65,131,106,
|
||||
206,240,104,112,160,225,174,148,107,62,155,216,140,130,109,225,
|
||||
150,255,104,143,112,110,146,160,65,64,114,73,142,92,12,238,
|
||||
115,154,136,44,205,74,103,27,178,184,172,233,105,229,171,138,
|
||||
138,211,108,132,164,100,103,24,111,33,157,249,64,30,112,232,
|
||||
153,0,12,32,114,96,136,51,204,67,102,85,196,179,171,201,
|
||||
105,11,187,103,137,134,107,139,178,19,101,232,110,39,169,242,
|
||||
63,37,113,29,163,2,11,134,113,150,135,202,191,51,125,253,
|
||||
105,204,162,88,126,40,108,203,130,244,126,117,111,124,96,224,
|
||||
126,227,114,20,58,181,127,161,116,87,6,250,129,135,117,232,
|
||||
189,59,122,243,122,101,160,121,123,114,122,237,129,38,123,241,
|
||||
123,66,95,70,124,136,123,210,57,87,125,61,124,104,6,56,
|
||||
126,240,124,161,186,231,120,104,138,147,158,7,121,10,136,216,
|
||||
126,247,121,180,135,50,93,119,122,128,133,202,55,236,123,44,
|
||||
132,147,5,122,125,75,129,223,184,229,118,148,155,6,156,7,
|
||||
119,69,151,69,125,15,119,255,147,122,91,227,120,220,144,16,
|
||||
54,189,121,122,141,190,4,240,123,230,131,75,183,122,117,78,
|
||||
171,160,154,140,117,255,165,231,123,150,118,180,160,18,90,158,
|
||||
119,159,154,248,53,206,120,29,151,54,4,139,123,11,131,18,
|
||||
182,151,116,140,188,154,153,124,117,45,180,249,122,105,117,198,
|
||||
173,42,89,148,118,175,166,195,52,247,119,27,159,91,4,58,
|
||||
122,75,130,219,168,10,140,102,104,152,142,157,138,129,107,167,
|
||||
114,84,137,23,110,98,83,5,136,13,112,248,46,178,136,50,
|
||||
114,232,0,0,134,1,119,195,166,152,137,165,119,142,140,252,
|
||||
136,21,120,113,112,187,134,199,121,68,81,165,133,209,122,43,
|
||||
45,147,133,199,122,111,0,0,131,203,125,115,164,228,135,58,
|
||||
134,91,139,30,133,208,133,102,111,24,132,156,132,87,80,93,
|
||||
131,190,131,134,44,163,131,149,130,248,0,0,129,242,128,0,
|
||||
163,51,133,129,149,157,137,135,132,33,146,220,109,118,130,247,
|
||||
143,243,78,252,130,37,141,109,43,168,129,222,139,252,0,0,
|
||||
128,80,128,0,162,3,132,83,164,223,136,69,130,249,160,109,
|
||||
108,52,129,194,155,194,77,229,128,243,151,242,42,242,128,117,
|
||||
148,112,0,0,128,0,128,0,161,66,131,152,180,173,135,81,
|
||||
130,59,174,155,107,41,128,225,168,60,77,1,128,10,163,180,
|
||||
42,74,127,120,154,175,0,0,128,0,128,0,145,188,155,172,
|
||||
103,193,122,194,152,25,106,174,97,34,149,28,109,90,68,88,
|
||||
146,185,111,205,33,58,147,6,113,3,0,0,128,158,125,23,
|
||||
144,178,153,85,117,117,121,161,149,241,118,113,96,7,146,235,
|
||||
119,201,67,104,144,128,120,192,32,163,144,90,120,208,0,0,
|
||||
128,83,127,160,143,100,151,24,131,16,120,32,147,209,130,146,
|
||||
94,175,144,218,130,3,66,85,142,130,129,188,32,1,142,10,
|
||||
128,235,0,0,128,0,128,0,142,45,149,108,144,194,118,226,
|
||||
146,54,142,170,93,120,143,61,140,135,65,117,140,210,138,222,
|
||||
31,136,140,18,137,181,0,0,128,0,128,0,141,62,148,80,
|
||||
158,204,117,254,145,26,155,76,92,129,142,10,151,180,64,146,
|
||||
139,158,149,70,31,15,138,141,145,227,0,0,128,0,128,0,
|
||||
140,159,147,161,173,59,117,64,144,98,168,119,91,182,141,51,
|
||||
163,160,63,227,138,184,160,184,30,155,137,127,148,146,0,0,
|
||||
128,0,128,0,124,171,172,10,102,190,103,126,167,39,105,111,
|
||||
80,11,162,201,107,245,53,57,159,120,110,24,19,165,158,208,
|
||||
111,20,0,0,128,0,128,0,123,249,170,24,116,224,102,230,
|
||||
165,24,117,140,79,132,160,128,117,94,52,226,156,255,118,88,
|
||||
19,187,155,193,119,9,0,0,128,0,128,0,123,42,167,228,
|
||||
127,253,101,234,162,244,127,85,78,167,158,94,127,12,52,67,
|
||||
154,215,126,238,19,159,153,39,127,38,0,0,128,0,128,0,
|
||||
122,87,166,68,140,182,101,22,161,89,139,59,77,209,156,183,
|
||||
137,52,51,180,153,17,136,91,19,135,150,246,134,122,0,0,
|
||||
128,0,128,0,121,194,165,30,152,238,100,130,160,44,150,73,
|
||||
77,54,155,119,147,192,51,58,151,189,146,136,19,131,149,48,
|
||||
139,58,0,0,128,0,128,0,121,80,164,119,166,54,100,51,
|
||||
159,99,162,165,76,201,154,118,159,46,50,220,150,162,156,195,
|
||||
19,98,147,245,141,27,0,0,128,0,128,0,104,127,189,181,
|
||||
101,120,84,142,183,253,103,201,62,206,178,149,106,4,37,57,
|
||||
175,32,107,133,7,201,168,185,110,103,0,0,128,0,128,0,
|
||||
104,19,188,17,113,56,84,117,181,220,113,249,62,221,175,253,
|
||||
114,239,37,150,172,20,115,158,8,71,165,174,118,13,0,0,
|
||||
128,0,128,0,103,206,185,191,124,128,84,14,179,133,124,35,
|
||||
62,146,173,145,124,7,37,152,169,115,124,23,8,149,163,10,
|
||||
125,3,0,0,128,0,128,0,103,132,183,243,135,237,83,215,
|
||||
177,160,134,186,62,83,171,151,133,157,37,151,167,69,133,155,
|
||||
8,210,160,225,134,24,0,0,128,0,128,0,103,71,182,193,
|
||||
147,197,83,203,176,53,145,186,62,65,170,12,143,228,37,150,
|
||||
165,157,143,124,9,4,159,47,134,25,0,0,128,0,128,0,
|
||||
103,34,182,5,159,118,83,218,175,42,156,247,62,66,168,216,
|
||||
154,228,37,162,164,81,151,207,9,28,157,237,134,41,0,0,
|
||||
128,0,128,0,195,134,104,39,97,50,165,143,107,98,101,100,
|
||||
133,177,110,87,105,86,99,107,113,26,109,23,61,117,115,78,
|
||||
112,105,10,197,118,146,113,155,192,120,99,196,114,159,163,37,
|
||||
103,127,116,32,131,159,106,221,117,164,97,161,109,247,119,42,
|
||||
59,237,112,35,120,108,9,208,115,227,120,197,189,150,96,56,
|
||||
131,182,160,101,100,60,130,212,129,66,103,227,130,4,95,178,
|
||||
107,69,129,80,58,117,109,94,128,220,8,252,114,54,127,181,
|
||||
187,44,93,116,149,0,158,28,97,167,145,220,127,29,101,119,
|
||||
142,191,93,247,105,0,139,222,57,48,106,248,136,228,8,98,
|
||||
114,207,133,15,185,130,91,150,166,49,156,129,95,216,160,239,
|
||||
125,137,99,178,155,159,92,152,103,80,150,226,56,49,105,27,
|
||||
147,108,7,231,114,249,133,88,184,132,90,105,183,86,155,115,
|
||||
94,161,175,238,124,98,98,101,168,131,91,140,105,1,162,44,
|
||||
55,84,103,155,156,250,7,143,115,57,133,29,173,93,116,242,
|
||||
96,48,147,55,118,74,100,152,118,92,119,176,104,140,86,142,
|
||||
121,30,108,57,50,50,122,128,111,45,2,87,126,109,114,86,
|
||||
171,85,112,240,112,28,145,91,114,194,114,35,116,164,116,109,
|
||||
115,251,85,28,118,12,117,186,49,17,119,53,119,0,2,43,
|
||||
125,195,121,110,168,240,109,150,128,2,142,230,111,169,127,232,
|
||||
114,129,113,144,127,187,83,92,115,109,127,135,47,194,116,98,
|
||||
127,74,1,226,125,94,127,32,166,228,106,254,143,238,140,233,
|
||||
109,54,141,221,112,164,111,63,139,156,81,229,113,51,137,125,
|
||||
46,184,113,233,136,69,1,188,125,70,129,22,165,119,105,58,
|
||||
159,231,139,118,107,126,155,238,111,59,109,141,151,183,80,175,
|
||||
111,144,148,16,45,231,112,10,145,123,1,153,125,77,129,20,
|
||||
164,153,104,24,176,2,138,114,106,82,170,42,110,35,111,42,
|
||||
164,16,79,186,110,75,159,42,45,29,110,151,153,133,1,123,
|
||||
125,127,129,0,151,185,130,155,95,107,128,155,130,26,99,200,
|
||||
102,131,129,250,103,171,73,25,130,36,107,48,37,224,131,72,
|
||||
109,106,0,0,128,15,119,32,150,37,126,232,109,252,126,233,
|
||||
126,222,112,71,100,238,126,239,114,85,71,211,127,49,116,50,
|
||||
36,254,127,224,117,40,0,0,128,0,125,1,148,89,123,191,
|
||||
124,214,124,252,123,247,125,43,99,88,124,49,125,116,70,157,
|
||||
124,147,125,171,36,61,124,241,125,162,0,0,128,0,128,0,
|
||||
146,160,121,84,139,48,123,96,121,170,138,25,97,182,121,248,
|
||||
136,132,69,80,122,100,134,203,35,88,122,135,134,48,0,0,
|
||||
128,0,128,0,145,107,119,175,153,210,122,36,120,16,150,250,
|
||||
96,132,120,91,147,207,68,71,120,200,145,64,34,188,120,174,
|
||||
142,195,0,0,128,0,128,0,144,162,120,93,168,186,121,57,
|
||||
120,129,164,90,95,144,120,148,159,155,67,117,120,204,156,88,
|
||||
34,21,119,83,148,183,0,0,128,0,128,0,130,198,145,99,
|
||||
94,162,109,209,143,77,98,193,86,12,141,196,102,123,58,184,
|
||||
140,221,105,176,24,115,141,200,107,28,0,0,128,0,124,73,
|
||||
129,132,142,31,107,235,108,146,140,92,110,64,84,240,138,218,
|
||||
113,211,57,230,137,229,115,138,24,36,138,59,114,239,0,0,
|
||||
128,0,127,132,128,22,139,40,121,37,107,6,137,153,122,194,
|
||||
83,165,136,48,123,82,56,243,135,70,123,12,23,189,135,58,
|
||||
123,75,0,0,128,0,128,0,126,190,136,215,135,50,105,197,
|
||||
135,98,134,150,82,127,133,248,133,151,56,76,132,242,133,17,
|
||||
23,130,132,161,132,185,0,0,128,0,128,0,125,190,135,83,
|
||||
147,232,104,226,133,228,145,251,81,131,132,98,143,208,55,90,
|
||||
131,82,142,43,23,27,130,174,140,195,0,0,128,0,128,0,
|
||||
125,14,134,79,161,162,104,29,132,220,158,145,80,187,131,56,
|
||||
154,254,54,173,130,12,153,42,22,191,129,62,143,48,0,0,
|
||||
128,0,128,0,110,138,161,103,93,113,91,64,158,36,97,61,
|
||||
69,98,155,115,100,180,43,134,154,24,103,87,11,238,152,5,
|
||||
105,90,0,0,128,0,127,174,109,133,158,164,105,164,90,112,
|
||||
155,103,107,227,68,195,152,129,109,252,43,62,150,221,111,137,
|
||||
12,25,148,105,113,67,0,0,128,0,128,0,108,132,155,200,
|
||||
117,179,89,77,152,172,118,164,67,211,149,207,119,119,42,162,
|
||||
148,24,120,5,12,19,145,67,121,90,0,0,128,0,128,0,
|
||||
107,134,153,143,129,221,88,92,150,130,129,173,66,235,147,154,
|
||||
129,73,42,24,145,180,129,15,12,0,142,157,128,215,0,0,
|
||||
128,0,128,0,106,209,152,11,143,26,87,176,149,0,141,197,
|
||||
66,62,146,3,140,0,41,140,143,253,139,52,12,1,140,140,
|
||||
133,216,0,0,128,0,128,0,106,74,151,18,154,199,87,83,
|
||||
147,243,152,208,65,214,144,186,150,118,41,61,142,132,149,10,
|
||||
11,233,139,8,136,14,0,0,128,0,128,0,90,217,179,10,
|
||||
91,159,72,146,175,35,94,239,52,17,171,191,97,242,26,122,
|
||||
171,135,99,103,2,147,158,4,105,195,0,0,128,0,128,0,
|
||||
89,242,176,188,102,234,72,22,172,122,104,233,51,223,168,163,
|
||||
106,202,26,208,167,186,107,134,3,13,154,120,113,121,0,0,
|
||||
128,0,128,0,89,104,173,222,113,237,71,119,169,158,114,221,
|
||||
51,113,165,180,115,185,26,205,164,114,115,225,3,91,151,84,
|
||||
119,101,0,0,128,0,128,0,88,225,171,136,125,19,71,16,
|
||||
167,63,125,46,51,16,163,58,125,29,26,204,161,154,125,2,
|
||||
3,150,148,166,126,188,0,0,128,0,128,0,88,127,169,250,
|
||||
136,100,70,230,165,137,135,210,50,233,161,96,135,19,26,190,
|
||||
159,136,135,59,3,199,146,155,130,61,0,0,128,0,128,0,
|
||||
88,66,168,239,147,235,70,221,164,67,146,236,50,224,159,237,
|
||||
145,204,26,206,157,221,143,133,3,222,145,7,130,157,0,0,
|
||||
128,0,128,0,176,156,94,195,87,72,149,115,98,233,92,217,
|
||||
120,99,102,205,98,34,88,182,106,104,103,28,53,1,108,159,
|
||||
107,102,5,152,118,139,109,251,173,120,88,199,104,44,147,0,
|
||||
93,173,107,60,118,78,98,35,110,48,86,244,102,42,113,1,
|
||||
51,155,104,36,115,88,5,62,119,36,117,123,170,129,83,218,
|
||||
120,230,144,69,89,66,121,155,116,3,94,37,122,79,85,27,
|
||||
98,129,123,12,50,72,100,77,123,164,4,235,119,176,124,186,
|
||||
167,244,79,239,137,125,142,8,85,186,136,49,114,1,90,231,
|
||||
134,220,83,144,95,120,133,94,49,50,97,23,132,122,4,171,
|
||||
120,27,130,105,166,29,76,244,153,245,140,119,83,4,150,99,
|
||||
112,161,88,98,146,223,82,98,93,18,143,209,48,103,94,148,
|
||||
141,222,4,128,120,101,131,11,165,1,75,27,170,73,139,111,
|
||||
81,61,164,132,111,168,86,158,159,0,81,141,91,86,154,125,
|
||||
47,181,92,180,151,6,4,90,120,165,130,241,156,106,106,192,
|
||||
86,220,132,107,109,76,92,113,105,223,111,205,97,148,76,63,
|
||||
114,46,102,77,41,113,115,222,105,208,0,133,127,32,112,194,
|
||||
154,6,101,52,102,67,130,120,104,112,105,168,104,51,107,92,
|
||||
108,201,74,235,109,253,111,166,40,136,111,123,113,155,0,121,
|
||||
127,52,119,248,151,123,96,136,117,195,127,250,100,52,119,22,
|
||||
102,27,103,124,120,55,73,62,106,97,121,62,39,94,107,182,
|
||||
121,207,0,101,127,85,125,231,149,85,92,216,133,116,125,254,
|
||||
96,208,133,45,100,78,100,86,131,234,71,229,103,88,131,7,
|
||||
38,123,104,160,130,168,0,90,127,104,128,21,147,206,90,13,
|
||||
148,102,124,145,94,51,145,245,98,253,97,219,143,75,70,199,
|
||||
100,234,141,18,37,213,102,40,139,156,0,82,127,118,128,55,
|
||||
146,221,88,74,163,183,123,146,92,123,159,112,97,255,96,28,
|
||||
154,247,69,241,99,40,151,144,37,38,100,94,147,151,0,74,
|
||||
127,132,128,50,136,83,119,164,86,119,114,249,120,152,91,224,
|
||||
90,200,121,197,96,207,63,24,123,14,101,47,28,228,124,239,
|
||||
103,177,0,0,128,0,118,153,134,86,114,117,100,134,113,39,
|
||||
116,9,104,12,89,55,117,132,107,62,61,232,118,232,110,10,
|
||||
28,63,120,131,111,111,0,0,128,0,124,173,132,83,110,13,
|
||||
114,153,111,34,112,8,116,89,87,166,113,196,117,216,60,195,
|
||||
115,69,119,23,27,177,116,190,119,163,0,0,128,0,128,0,
|
||||
130,119,106,149,129,11,109,119,108,205,130,35,86,4,110,179,
|
||||
128,158,59,134,112,55,128,143,26,244,113,202,129,140,0,0,
|
||||
128,0,128,0,129,36,103,242,142,177,108,51,106,79,140,179,
|
||||
84,214,108,70,139,126,58,135,109,187,138,52,26,128,111,130,
|
||||
137,83,0,0,128,0,128,0,128,71,102,62,157,11,107,73,
|
||||
104,167,154,28,83,238,106,146,150,196,57,196,107,241,148,173,
|
||||
25,237,109,244,142,180,0,0,128,0,128,0,116,102,133,188,
|
||||
85,206,97,9,133,77,90,232,74,225,133,71,95,143,48,197,
|
||||
133,211,99,100,15,223,135,31,101,112,0,0,128,0,123,165,
|
||||
114,183,129,2,98,152,95,147,129,17,102,24,73,174,129,44,
|
||||
105,65,47,247,129,153,107,201,15,177,130,194,109,55,0,0,
|
||||
128,0,127,79,113,14,124,224,111,119,93,220,125,64,113,115,
|
||||
72,73,125,135,115,40,46,243,125,235,116,107,15,86,127,106,
|
||||
117,126,0,0,128,0,128,0,111,138,121,149,124,88,92,114,
|
||||
122,42,124,241,71,9,122,128,125,56,46,66,122,185,125,99,
|
||||
15,42,124,159,125,207,0,0,128,0,128,0,110,95,119,23,
|
||||
138,202,91,117,119,207,138,10,70,19,120,28,137,0,45,94,
|
||||
120,38,135,245,14,222,122,140,135,102,0,0,128,0,128,0,
|
||||
109,149,121,89,150,108,90,170,121,119,148,158,69,84,118,115,
|
||||
146,87,44,190,118,78,145,129,14,137,120,225,137,87,0,0,
|
||||
128,0,128,0,96,221,149,113,84,82,79,24,147,218,89,8,
|
||||
58,133,146,240,93,68,32,234,148,5,96,5,5,223,142,72,
|
||||
100,242,0,0,128,0,127,76,95,109,145,55,96,1,77,234,
|
||||
143,234,99,97,57,154,142,232,102,93,32,131,143,118,104,29,
|
||||
6,7,138,144,108,199,0,0,128,0,128,0,94,36,141,70,
|
||||
107,194,76,143,140,50,109,216,56,136,139,63,111,156,31,218,
|
||||
139,127,112,111,5,254,135,60,116,52,0,0,128,0,128,0,
|
||||
92,237,138,30,122,85,75,113,137,51,120,146,55,133,136,57,
|
||||
121,39,31,91,136,14,123,110,5,246,132,117,123,118,0,0,
|
||||
128,0,128,0,91,246,135,172,131,111,74,141,134,231,131,84,
|
||||
54,186,133,222,130,234,30,202,133,72,130,209,6,11,130,149,
|
||||
129,136,0,0,128,0,128,0,91,71,134,25,143,189,74,30,
|
||||
133,105,142,218,54,108,132,29,141,96,30,192,131,24,140,170,
|
||||
6,8,129,66,132,20,0,0,128,0,128,0,77,84,167,52,
|
||||
81,238,60,225,164,229,86,29,41,102,163,178,89,171,15,187,
|
||||
165,245,91,30,0,0,143,192,102,232,0,0,128,0,128,0,
|
||||
76,0,163,132,92,179,59,195,161,83,95,199,40,139,159,206,
|
||||
98,84,15,179,160,234,99,35,0,0,141,58,110,94,0,0,
|
||||
128,0,128,0,75,38,159,158,103,107,58,198,157,140,105,113,
|
||||
39,202,155,249,107,4,15,139,156,80,107,83,0,0,138,237,
|
||||
113,76,0,0,128,0,128,0,74,77,156,103,114,86,58,10,
|
||||
154,119,115,117,39,52,152,188,116,26,15,133,152,85,116,52,
|
||||
0,33,136,220,120,138,0,0,128,0,128,0,73,149,153,242,
|
||||
125,109,57,132,152,31,125,200,38,211,150,60,125,178,15,95,
|
||||
149,64,125,240,0,63,135,71,127,146,0,0,128,0,128,0,
|
||||
73,42,152,77,136,216,57,58,150,125,136,168,38,173,148,107,
|
||||
136,30,15,114,147,1,134,175,0,80,134,33,128,54,0,0,
|
||||
128,0,128,0,158,251,83,213,77,213,134,82,88,228,84,162,
|
||||
107,209,93,194,91,44,78,135,98,47,97,81,44,208,100,17,
|
||||
102,124,1,123,125,128,107,25,155,163,75,156,94,40,131,186,
|
||||
81,193,98,171,105,163,87,113,102,252,76,186,92,94,107,9,
|
||||
43,127,94,109,110,93,1,148,125,85,114,218,152,136,68,110,
|
||||
110,104,128,251,75,123,112,169,103,104,81,210,114,214,74,252,
|
||||
87,33,116,232,42,89,89,132,118,188,1,168,125,50,122,87,
|
||||
149,187,62,95,127,39,126,199,70,68,127,37,101,151,77,45,
|
||||
126,223,73,179,82,194,126,247,41,128,85,129,127,2,1,184,
|
||||
125,23,128,57,147,155,57,144,141,195,125,55,66,42,139,246,
|
||||
100,109,73,147,138,142,72,188,79,81,137,33,40,239,82,91,
|
||||
136,147,1,196,125,4,129,50,146,51,54,15,157,180,124,41,
|
||||
63,34,153,134,99,178,70,225,149,233,72,51,76,186,147,48,
|
||||
40,130,79,242,145,93,1,205,124,245,129,56,140,172,95,13,
|
||||
78,0,118,82,98,194,84,136,93,217,102,97,90,197,66,68,
|
||||
105,148,96,126,32,220,108,22,100,131,0,0,128,0,112,38,
|
||||
137,166,87,69,92,206,116,43,92,3,97,107,92,39,96,73,
|
||||
101,193,64,246,99,194,105,173,32,26,102,123,108,69,0,0,
|
||||
128,0,119,103,134,217,80,99,107,214,113,151,85,234,110,117,
|
||||
90,18,90,193,112,228,63,85,94,121,115,18,31,23,97,180,
|
||||
116,108,0,0,128,0,125,112,132,131,74,171,122,184,111,150,
|
||||
80,207,123,118,88,87,86,26,124,13,62,35,89,237,124,145,
|
||||
30,107,94,103,125,47,0,0,128,0,127,202,130,209,70,47,
|
||||
137,129,110,40,76,204,136,111,87,33,82,108,135,54,61,36,
|
||||
86,56,134,85,29,248,92,10,133,252,0,0,128,0,128,0,
|
||||
129,180,66,231,151,227,109,43,73,215,149,17,86,72,79,164,
|
||||
146,42,60,121,83,93,144,56,29,122,90,173,141,217,0,0,
|
||||
128,0,128,0,122,59,107,13,78,9,101,239,109,128,84,51,
|
||||
79,94,111,248,90,17,53,66,114,34,95,58,20,89,117,114,
|
||||
98,63,0,0,128,0,118,48,119,113,99,183,91,125,99,224,
|
||||
103,9,96,10,77,191,105,251,100,71,52,13,108,44,103,232,
|
||||
19,212,112,104,105,245,0,0,128,0,124,88,117,9,93,44,
|
||||
105,29,97,175,97,41,107,247,76,39,100,134,110,150,50,241,
|
||||
102,174,112,192,19,113,108,243,114,23,0,0,128,0,128,0,
|
||||
114,243,87,180,118,223,95,234,92,47,120,23,74,129,95,218,
|
||||
121,16,49,195,97,217,121,223,18,225,106,136,122,228,0,0,
|
||||
128,0,128,0,113,120,83,101,132,147,94,155,88,59,132,58,
|
||||
73,87,92,22,131,141,48,207,93,197,131,35,18,148,104,170,
|
||||
130,227,0,0,128,0,128,0,112,124,80,47,145,214,93,175,
|
||||
85,72,144,47,72,123,89,48,142,34,48,28,90,139,141,35,
|
||||
18,32,103,124,136,248,0,0,128,0,128,0,103,70,120,84,
|
||||
77,117,84,232,121,161,83,63,64,11,123,28,88,172,38,210,
|
||||
124,209,92,243,8,233,127,70,96,200,0,0,128,0,123,34,
|
||||
100,213,113,135,89,167,83,25,115,126,94,24,62,167,117,48,
|
||||
98,36,37,231,118,126,101,44,8,193,123,161,104,123,0,0,
|
||||
128,0,127,24,98,194,107,80,102,30,81,34,109,203,105,23,
|
||||
61,29,111,188,107,190,36,205,112,158,109,148,8,119,120,180,
|
||||
112,173,0,0,128,0,128,0,96,242,102,12,114,156,79,130,
|
||||
104,236,116,47,59,191,107,0,117,116,36,18,107,82,118,75,
|
||||
8,91,118,101,120,166,0,0,128,0,128,0,95,146,97,206,
|
||||
130,67,78,97,101,12,129,141,58,188,103,46,129,182,35,42,
|
||||
103,31,127,144,8,40,116,175,127,220,0,0,128,0,128,0,
|
||||
94,161,94,147,139,177,77,129,98,16,138,232,57,241,100,48,
|
||||
137,174,34,137,99,241,137,147,7,229,115,133,132,115,0,0,
|
||||
128,0,128,0,84,37,135,119,75,195,67,155,135,178,81,48,
|
||||
48,13,136,148,86,4,22,132,139,57,88,202,1,153,133,28,
|
||||
97,193,0,0,128,0,126,220,82,13,129,47,86,229,65,224,
|
||||
129,244,91,44,46,166,130,201,94,217,21,210,132,77,96,184,
|
||||
1,163,129,218,105,124,0,0,128,0,128,0,80,85,123,60,
|
||||
98,71,64,40,124,97,101,75,45,71,125,64,103,204,20,248,
|
||||
126,25,104,210,1,154,127,79,110,152,0,0,128,0,128,0,
|
||||
78,197,118,17,114,119,62,180,119,146,116,238,44,4,120,106,
|
||||
118,37,20,83,121,5,113,106,1,147,125,213,117,185,0,0,
|
||||
128,0,128,0,77,131,113,206,121,100,61,140,115,179,122,30,
|
||||
43,13,116,126,122,121,19,183,117,62,122,187,1,164,125,57,
|
||||
126,172,0,0,128,0,128,0,76,158,110,125,133,67,60,216,
|
||||
112,196,133,20,42,153,113,118,132,123,19,130,114,86,132,73,
|
||||
1,142,125,96,129,13,0,0,128,0,128,0,64,153,153,69,
|
||||
72,171,49,169,152,158,77,168,30,160,153,228,81,115,6,90,
|
||||
154,60,83,247,0,0,130,209,102,37,0,0,128,0,128,0,
|
||||
62,163,147,140,82,227,47,151,147,139,86,215,28,182,148,160,
|
||||
89,168,5,183,147,71,91,203,0,0,128,103,109,199,0,0,
|
||||
128,0,128,0,61,68,141,206,93,80,46,3,142,29,96,44,
|
||||
27,97,143,2,98,7,5,78,141,29,99,223,0,0,128,0,
|
||||
117,60,0,0,128,0,128,0,59,244,136,146,104,3,44,191,
|
||||
137,80,105,212,26,96,137,238,106,205,5,45,136,30,108,152,
|
||||
0,0,128,0,123,80,0,0,128,0,128,0,58,216,132,48,
|
||||
114,233,43,191,133,110,115,203,25,174,133,218,116,14,4,250,
|
||||
132,101,118,30,0,0,128,0,127,34,0,0,128,0,128,0,
|
||||
58,13,128,170,126,39,42,253,130,99,126,61,25,57,130,182,
|
||||
126,10,4,241,129,178,126,213,0,0,128,0,128,0,0,0,
|
||||
128,0,128,0,0,0,255,255,0,0,255,255,0,0,255,255
|
||||
};
|
@ -47,7 +47,7 @@ _pdfioFileConsume(pdfio_file_t *pdf, // I - PDF file
|
||||
// `false` to halt.
|
||||
//
|
||||
|
||||
bool // O - `false` to stop
|
||||
bool // O - `false` to stop, `true` to continue
|
||||
_pdfioFileDefaultError(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
const char *message, // I - Error message
|
||||
@ -57,7 +57,7 @@ _pdfioFileDefaultError(
|
||||
|
||||
fprintf(stderr, "%s: %s\n", pdf->filename, message);
|
||||
|
||||
return (false);
|
||||
return (!strncmp(message, "WARNING:", 8));
|
||||
}
|
||||
|
||||
|
||||
@ -134,19 +134,20 @@ _pdfioFileGetChar(pdfio_file_t *pdf) // I - PDF file
|
||||
bool // O - `true` on success, `false` on error
|
||||
_pdfioFileGets(pdfio_file_t *pdf, // I - PDF file
|
||||
char *buffer, // I - Line buffer
|
||||
size_t bufsize) // I - Size of line buffer
|
||||
size_t bufsize, // I - Size of line buffer
|
||||
bool discard) // I - OK to discard excess line chars?
|
||||
{
|
||||
bool eol = false; // End of line?
|
||||
char *bufptr = buffer, // Pointer into buffer
|
||||
*bufend = buffer + bufsize - 1; // Pointer to end of buffer
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioFileGets(pdf=%p, buffer=%p, bufsize=%lu) bufpos=%ld, buffer=%p, bufptr=%p, bufend=%p, offset=%lu\n", pdf, buffer, (unsigned long)bufsize, (long)pdf->bufpos, pdf->buffer, pdf->bufptr, pdf->bufend, (unsigned long)(pdf->bufpos + (pdf->bufptr - pdf->buffer)));
|
||||
PDFIO_DEBUG("_pdfioFileGets(pdf=%p, buffer=%p, bufsize=%lu, discard=%s) bufpos=%ld, buffer=%p, bufptr=%p, bufend=%p, offset=%lu\n", pdf, buffer, (unsigned long)bufsize, discard ? "true" : "false", (long)pdf->bufpos, pdf->buffer, pdf->bufptr, pdf->bufend, (unsigned long)(pdf->bufpos + (pdf->bufptr - pdf->buffer)));
|
||||
|
||||
while (!eol)
|
||||
{
|
||||
// If there are characters ready in the buffer, use them...
|
||||
while (!eol && pdf->bufptr < pdf->bufend && bufptr < bufend)
|
||||
while (!eol && pdf->bufptr < pdf->bufend)
|
||||
{
|
||||
char ch = *(pdf->bufptr++); // Next character in buffer
|
||||
|
||||
@ -168,8 +169,10 @@ _pdfioFileGets(pdfio_file_t *pdf, // I - PDF file
|
||||
pdf->bufptr ++;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (bufptr < bufend)
|
||||
*bufptr++ = ch;
|
||||
else if (!discard)
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill the read buffer as needed...
|
||||
@ -424,7 +427,7 @@ off_t // O - Offset from beginning of file
|
||||
_pdfioFileTell(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
if (pdf->bufptr)
|
||||
return (pdf->bufpos + (pdf->bufptr - pdf->buffer));
|
||||
return (pdf->bufpos + (off_t)(pdf->bufptr - pdf->buffer));
|
||||
else
|
||||
return (pdf->bufpos);
|
||||
}
|
||||
@ -452,7 +455,7 @@ _pdfioFileWrite(pdfio_file_t *pdf, // I - PDF file
|
||||
if (!write_buffer(pdf, buffer, bytes))
|
||||
return (false);
|
||||
|
||||
pdf->bufpos += bytes;
|
||||
pdf->bufpos += (off_t)bytes;
|
||||
|
||||
return (true);
|
||||
}
|
||||
@ -478,7 +481,7 @@ fill_buffer(pdfio_file_t *pdf) // I - PDF file
|
||||
|
||||
// Advance current position in file as needed...
|
||||
if (pdf->bufend)
|
||||
pdf->bufpos += pdf->bufend - pdf->buffer;
|
||||
pdf->bufpos += (off_t)(pdf->bufend - pdf->buffer);
|
||||
|
||||
// Try reading from the file...
|
||||
if ((bytes = read_buffer(pdf, pdf->buffer, sizeof(pdf->buffer))) <= 0)
|
||||
|
925
pdfio-content.c
925
pdfio-content.c
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Public content header file for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -23,7 +23,8 @@ typedef enum pdfio_cs_e // Standard color spaces
|
||||
{
|
||||
PDFIO_CS_ADOBE, // AdobeRGB 1998
|
||||
PDFIO_CS_P3_D65, // Display P3
|
||||
PDFIO_CS_SRGB // sRGB
|
||||
PDFIO_CS_SRGB, // sRGB
|
||||
PDFIO_CS_CGATS001 // CGATS001 (CMYK)
|
||||
} pdfio_cs_t;
|
||||
|
||||
typedef enum pdfio_linecap_e // Line capping modes
|
||||
@ -127,7 +128,9 @@ extern bool pdfioContentTextShowf(pdfio_stream_t *st, bool unicode, const char
|
||||
extern bool pdfioContentTextShowJustified(pdfio_stream_t *st, bool unicode, size_t num_fragments, const double *offsets, const char * const *fragments) _PDFIO_PUBLIC;
|
||||
|
||||
// Resource helpers...
|
||||
extern void pdfioFileAddOutputIntent(pdfio_file_t *pdf, const char *subtype, const char *condition, const char *cond_id, const char *reg_name, const char *info, pdfio_obj_t *profile) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromBase(pdfio_file_t *pdf, const char *name) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromData(pdfio_file_t *pdf, const void *data, size_t datasize, bool unicode) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromFile(pdfio_file_t *pdf, const char *filename, bool unicode) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateICCObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t datalen, size_t num_colors) _PDFIO_PUBLIC;
|
||||
extern pdfio_obj_t *pdfioFileCreateICCObjFromFile(pdfio_file_t *pdf, const char *filename, size_t num_colors) _PDFIO_PUBLIC;
|
||||
|
125
pdfio-crypto.c
125
pdfio-crypto.c
@ -98,7 +98,7 @@ static uint8_t pdf_passpad[32] = // Padding for passwords
|
||||
|
||||
static void decrypt_user_key(pdfio_encryption_t encryption, const uint8_t *file_key, uint8_t user_key[32]);
|
||||
static void encrypt_user_key(pdfio_encryption_t encryption, const uint8_t *file_key, uint8_t user_key[32]);
|
||||
static void make_file_key(pdfio_encryption_t encryption, pdfio_permission_t permissions, const unsigned char *file_id, size_t file_idlen, const uint8_t *user_pad, const uint8_t *owner_key, uint8_t file_key[16]);
|
||||
static void make_file_key(pdfio_encryption_t encryption, pdfio_permission_t permissions, const unsigned char *file_id, size_t file_idlen, const uint8_t *user_pad, const uint8_t *owner_key, bool encrypt_metadata, uint8_t file_key[16]);
|
||||
static void make_owner_key(pdfio_encryption_t encryption, const uint8_t *owner_pad, const uint8_t *user_pad, uint8_t owner_key[32]);
|
||||
static void make_user_key(const unsigned char *file_id, size_t file_idlen, uint8_t user_key[32]);
|
||||
static void pad_password(const char *password, uint8_t pad[32]);
|
||||
@ -158,7 +158,7 @@ _pdfioCryptoLock(
|
||||
// Generate the encryption key
|
||||
file_id = pdfioArrayGetBinary(pdf->id_array, 0, &file_idlen);
|
||||
|
||||
make_file_key(encryption, permissions, file_id, file_idlen, user_pad, pdf->owner_key, pdf->file_key);
|
||||
make_file_key(encryption, permissions, file_id, file_idlen, user_pad, pdf->owner_key, pdf->encrypt_metadata, pdf->file_key);
|
||||
pdf->file_keylen = 16;
|
||||
|
||||
// Generate the user key...
|
||||
@ -409,13 +409,6 @@ _pdfioCryptoMakeReader(
|
||||
uint8_t data[21]; // Key data
|
||||
_pdfio_md5_t md5; // MD5 state
|
||||
uint8_t digest[16]; // MD5 digest value
|
||||
#if PDFIO_OBJ_CRYPT
|
||||
pdfio_array_t *id_array; // Object ID array
|
||||
unsigned char *id_value; // Object ID value
|
||||
size_t id_len; // Length of object ID
|
||||
uint8_t temp_key[16]; // File key for object
|
||||
#endif // PDFIO_OBJ_CRYPT
|
||||
uint8_t *file_key; // Computed file key to use
|
||||
|
||||
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeReader(pdf=%p, obj=%p(%d), ctx=%p, iv=%p, ivlen=%p(%d))\n", pdf, obj, (int)obj->number, ctx, iv, ivlen, (int)*ivlen);
|
||||
@ -427,60 +420,6 @@ _pdfioCryptoMakeReader(
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#if PDFIO_OBJ_CRYPT
|
||||
if ((id_array = pdfioDictGetArray(pdfioObjGetDict(obj), "ID")) != NULL)
|
||||
{
|
||||
// Object has its own ID that will get used for encryption...
|
||||
_pdfio_md5_t md5; // MD5 context
|
||||
uint8_t file_digest[16]; // MD5 digest of file ID and pad
|
||||
uint8_t user_pad[32], // Padded user password
|
||||
own_user_key[32], // Calculated user key
|
||||
pdf_user_key[32]; // Decrypted user key
|
||||
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeReader: Per-object file ID.\n");
|
||||
|
||||
if ((id_value = pdfioArrayGetBinary(id_array, 0, &id_len)) == NULL)
|
||||
{
|
||||
*ivlen = 0;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
_pdfioCryptoMD5Init(&md5);
|
||||
_pdfioCryptoMD5Append(&md5, pdf_passpad, 32);
|
||||
_pdfioCryptoMD5Append(&md5, id_value, id_len);
|
||||
_pdfioCryptoMD5Finish(&md5, file_digest);
|
||||
|
||||
make_owner_key(pdf->encryption, pdf->password, pdf->owner_key, user_pad);
|
||||
make_file_key(pdf->encryption, pdf->permissions, id_value, id_len, user_pad, pdf->owner_key, temp_key);
|
||||
make_user_key(id_value, id_len, own_user_key);
|
||||
|
||||
if (memcmp(own_user_key, pdf->user_key, sizeof(own_user_key)))
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioCryptoMakeReader: Not user password, trying owner password.\n");
|
||||
|
||||
make_file_key(pdf->encryption, pdf->permissions, id_value, id_len, pdf->password, pdf->owner_key, temp_key);
|
||||
make_user_key(id_value, id_len, own_user_key);
|
||||
|
||||
memcpy(pdf_user_key, pdf->user_key, sizeof(pdf_user_key));
|
||||
decrypt_user_key(pdf->encryption, temp_key, pdf_user_key);
|
||||
|
||||
if (memcmp(pdf->password, pdf_user_key, 32) && memcmp(own_user_key, pdf_user_key, 16))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to unlock file.");
|
||||
*ivlen = 0;
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
file_key = temp_key;
|
||||
}
|
||||
else
|
||||
#endif // PDFIO_OBJ_CRYPT
|
||||
{
|
||||
// Use the default file key...
|
||||
file_key = pdf->file_key;
|
||||
}
|
||||
|
||||
switch (pdf->encryption)
|
||||
{
|
||||
default :
|
||||
@ -490,20 +429,20 @@ _pdfioCryptoMakeReader(
|
||||
|
||||
case PDFIO_ENCRYPTION_RC4_40 :
|
||||
// Copy the key data for the MD5 hash.
|
||||
memcpy(data, file_key, 16);
|
||||
data[16] = (uint8_t)obj->number;
|
||||
data[17] = (uint8_t)(obj->number >> 8);
|
||||
data[18] = (uint8_t)(obj->number >> 16);
|
||||
data[19] = (uint8_t)obj->generation;
|
||||
data[20] = (uint8_t)(obj->generation >> 8);
|
||||
memcpy(data, pdf->file_key, 5);
|
||||
data[5] = (uint8_t)obj->number;
|
||||
data[6] = (uint8_t)(obj->number >> 8);
|
||||
data[7] = (uint8_t)(obj->number >> 16);
|
||||
data[8] = (uint8_t)obj->generation;
|
||||
data[9] = (uint8_t)(obj->generation >> 8);
|
||||
|
||||
// Hash it...
|
||||
_pdfioCryptoMD5Init(&md5);
|
||||
_pdfioCryptoMD5Append(&md5, data, sizeof(data));
|
||||
_pdfioCryptoMD5Append(&md5, data, 10);
|
||||
_pdfioCryptoMD5Finish(&md5, digest);
|
||||
|
||||
// Initialize the RC4 context using 40 bits of the digest...
|
||||
_pdfioCryptoRC4Init(&ctx->rc4, digest, 5);
|
||||
// Initialize the RC4 context using 80 bits of the digest...
|
||||
_pdfioCryptoRC4Init(&ctx->rc4, digest, 10);
|
||||
*ivlen = 0;
|
||||
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
|
||||
|
||||
@ -517,7 +456,7 @@ _pdfioCryptoMakeReader(
|
||||
|
||||
case PDFIO_ENCRYPTION_RC4_128 :
|
||||
// Copy the key data for the MD5 hash.
|
||||
memcpy(data, file_key, 16);
|
||||
memcpy(data, pdf->file_key, 16);
|
||||
data[16] = (uint8_t)obj->number;
|
||||
data[17] = (uint8_t)(obj->number >> 8);
|
||||
data[18] = (uint8_t)(obj->number >> 16);
|
||||
@ -643,6 +582,8 @@ _pdfioCryptoUnlock(
|
||||
file_idlen; // Length of file ID
|
||||
_pdfio_md5_t md5; // MD5 context
|
||||
uint8_t file_digest[16]; // MD5 digest of file ID and pad
|
||||
double p; // Permissions value as a double
|
||||
_pdfio_value_t *value; // Encrypt dictionary value, if any
|
||||
|
||||
|
||||
// See if we support the type of encryption specified by the Encrypt object
|
||||
@ -658,7 +599,12 @@ _pdfioCryptoUnlock(
|
||||
revision = (int)pdfioDictGetNumber(encrypt_dict, "R");
|
||||
length = (int)pdfioDictGetNumber(encrypt_dict, "Length");
|
||||
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: handler=%p(%s), version=%d, revision=%d, length=%d\n", (void *)handler, handler ? handler : "(null)", version, revision, length);
|
||||
if ((value = _pdfioDictGetValue(encrypt_dict, "EncryptMetadata")) != NULL && value->type == PDFIO_VALTYPE_BOOLEAN)
|
||||
pdf->encrypt_metadata = value->value.boolean;
|
||||
else
|
||||
pdf->encrypt_metadata = true;
|
||||
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: handler=%p(%s), version=%d, revision=%d, length=%d, encrypt_metadata=%s\n", (void *)handler, handler ? handler : "(null)", version, revision, length, pdf->encrypt_metadata ? "true" : "false");
|
||||
|
||||
if (!handler || strcmp(handler, "Standard"))
|
||||
{
|
||||
@ -750,8 +696,13 @@ _pdfioCryptoUnlock(
|
||||
|
||||
// Grab the remaining values we need to unlock the PDF...
|
||||
pdf->file_keylen = (size_t)(length / 8);
|
||||
pdf->permissions = (pdfio_permission_t)pdfioDictGetNumber(encrypt_dict, "P");
|
||||
|
||||
p = pdfioDictGetNumber(encrypt_dict, "P");
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: P=%.0f\n", p);
|
||||
if (p < 0x7fffffff) // Handle integers > 2^31-1
|
||||
pdf->permissions = (pdfio_permission_t)p;
|
||||
else
|
||||
pdf->permissions = (pdfio_permission_t)(p - 4294967296.0);
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: permissions=%d\n", pdf->permissions);
|
||||
|
||||
owner_key = pdfioDictGetBinary(encrypt_dict, "O", &owner_keylen);
|
||||
@ -823,7 +774,7 @@ _pdfioCryptoUnlock(
|
||||
make_owner_key(pdf->encryption, pad, pdf->owner_key, user_pad);
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Upad=%02X%02X%02X%02X...%02X%02X%02X%02X\n", user_pad[0], user_pad[1], user_pad[2], user_pad[3], user_pad[28], user_pad[29], user_pad[30], user_pad[31]);
|
||||
|
||||
make_file_key(pdf->encryption, pdf->permissions, file_id, file_idlen, user_pad, pdf->owner_key, file_key);
|
||||
make_file_key(pdf->encryption, pdf->permissions, file_id, file_idlen, user_pad, pdf->owner_key, pdf->encrypt_metadata, file_key);
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Fown=%02X%02X%02X%02X...%02X%02X%02X%02X\n", file_key[0], file_key[1], file_key[2], file_key[3], file_key[12], file_key[13], file_key[14], file_key[15]);
|
||||
|
||||
make_user_key(file_id, file_idlen, own_user_key);
|
||||
@ -841,7 +792,7 @@ _pdfioCryptoUnlock(
|
||||
}
|
||||
|
||||
// Not the owner password, try the user password...
|
||||
make_file_key(pdf->encryption, pdf->permissions, file_id, file_idlen, pad, pdf->owner_key, file_key);
|
||||
make_file_key(pdf->encryption, pdf->permissions, file_id, file_idlen, pad, pdf->owner_key, pdf->encrypt_metadata, file_key);
|
||||
PDFIO_DEBUG("_pdfioCryptoUnlock: Fuse=%02X%02X%02X%02X...%02X%02X%02X%02X\n", file_key[0], file_key[1], file_key[2], file_key[3], file_key[12], file_key[13], file_key[14], file_key[15]);
|
||||
|
||||
make_user_key(file_id, file_idlen, own_user_key);
|
||||
@ -973,6 +924,8 @@ make_file_key(
|
||||
size_t file_idlen, // I - Length of file ID
|
||||
const uint8_t *user_pad, // I - Padded user password
|
||||
const uint8_t *owner_key, // I - Owner key
|
||||
bool encrypt_metadata,
|
||||
// I - Encrypt metadata?
|
||||
uint8_t file_key[16]) // O - Encryption key
|
||||
{
|
||||
size_t i; // Looping var
|
||||
@ -986,13 +939,25 @@ make_file_key(
|
||||
perm_bytes[2] = (uint8_t)(permissions >> 16);
|
||||
perm_bytes[3] = (uint8_t)(permissions >> 24);
|
||||
|
||||
PDFIO_DEBUG("make_file_key: user_pad[32]=<%02X%02X%02X%02X...%02X%02X%02X%02X>\n", user_pad[0], user_pad[1], user_pad[2], user_pad[3], user_pad[28], user_pad[29], user_pad[30], user_pad[31]);
|
||||
PDFIO_DEBUG("make_file_key: owner_key[32]=<%02X%02X%02X%02X...%02X%02X%02X%02X>\n", owner_key[0], owner_key[1], owner_key[2], owner_key[3], owner_key[28], owner_key[29], owner_key[30], owner_key[31]);
|
||||
PDFIO_DEBUG("make_file_key: permissions(%d)=<%02X%02X%02X%02X>\n", permissions, perm_bytes[0], perm_bytes[1], perm_bytes[2], perm_bytes[3]);
|
||||
|
||||
_pdfioCryptoMD5Init(&md5);
|
||||
_pdfioCryptoMD5Append(&md5, user_pad, 32);
|
||||
_pdfioCryptoMD5Append(&md5, owner_key, 32);
|
||||
_pdfioCryptoMD5Append(&md5, perm_bytes, 4);
|
||||
_pdfioCryptoMD5Append(&md5, file_id, file_idlen);
|
||||
if (!encrypt_metadata)
|
||||
{
|
||||
uint8_t meta_bytes[4] = { 0xff, 0xff, 0xff, 0xff };
|
||||
// Metadata bytes
|
||||
_pdfioCryptoMD5Append(&md5, meta_bytes, 4);
|
||||
}
|
||||
_pdfioCryptoMD5Finish(&md5, digest);
|
||||
|
||||
PDFIO_DEBUG("make_file_key: first md5=<%02X%02X%02X%02X...%02X%02X%02X%02X>\n", digest[0], digest[1], digest[2], digest[3], digest[12], digest[13], digest[14], digest[15]);
|
||||
|
||||
if (encryption != PDFIO_ENCRYPTION_RC4_40)
|
||||
{
|
||||
// MD5 the result 50 times..
|
||||
@ -1004,6 +969,8 @@ make_file_key(
|
||||
}
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("make_file_key: file_key[16]=<%02X%02X%02X%02X...%02X%02X%02X%02X>\n", digest[0], digest[1], digest[2], digest[3], digest[12], digest[13], digest[14], digest[15]);
|
||||
|
||||
memcpy(file_key, digest, 16);
|
||||
}
|
||||
|
||||
@ -1054,9 +1021,11 @@ make_owner_key(
|
||||
// Encrypt 20 times...
|
||||
uint8_t encrypt_key[16]; // RC4 encryption key
|
||||
|
||||
for (i = 0; i < 20; i ++)
|
||||
for (i = 20; i > 0;)
|
||||
{
|
||||
// XOR each byte in the digest with the loop counter to make a key...
|
||||
i --;
|
||||
|
||||
for (j = 0; j < sizeof(encrypt_key); j ++)
|
||||
encrypt_key[j] = (uint8_t)(digest[j] ^ i);
|
||||
|
||||
|
137
pdfio-dict.c
137
pdfio-dict.c
@ -20,6 +20,8 @@ static int compare_pairs(_pdfio_pair_t *a, _pdfio_pair_t *b);
|
||||
//
|
||||
// 'pdfioDictClear()' - Remove a key/value pair from a dictionary.
|
||||
//
|
||||
// @since PDFio v1.4@
|
||||
//
|
||||
|
||||
bool // O - `true` if cleared, `false` otherwise
|
||||
pdfioDictClear(pdfio_dict_t *dict, // I - Dictionary
|
||||
@ -345,6 +347,8 @@ pdfioDictGetDict(pdfio_dict_t *dict, // I - Dictionary
|
||||
//
|
||||
// 'pdfioDictGetKey()' - Get the key for the specified pair.
|
||||
//
|
||||
// @since PDFio v1.4@
|
||||
//
|
||||
|
||||
const char * // O - Key for specified pair
|
||||
pdfioDictGetKey(pdfio_dict_t *dict, // I - Dictionary
|
||||
@ -375,6 +379,8 @@ pdfioDictGetName(pdfio_dict_t *dict, // I - Dictionary
|
||||
//
|
||||
// 'pdfioDictGetNumPairs()' - Get the number of key/value pairs in a dictionary.
|
||||
//
|
||||
// @since PDFio v1.4@
|
||||
//
|
||||
|
||||
size_t // O - Number of pairs
|
||||
pdfioDictGetNumPairs(pdfio_dict_t *dict)// I - Dictionary
|
||||
@ -465,127 +471,12 @@ pdfioDictGetString(pdfio_dict_t *dict, // I - Dictionary
|
||||
else if (value && value->type == PDFIO_VALTYPE_BINARY && value->value.binary.datalen < 4096)
|
||||
{
|
||||
// Convert binary string to regular string...
|
||||
char temp[4096], // Temporary string
|
||||
*tempptr; // Pointer into temporary string
|
||||
unsigned char *dataptr; // Pointer into the data string
|
||||
char temp[4096]; // Temporary UTF-8 string
|
||||
|
||||
if (!(value->value.binary.datalen & 1) && !memcmp(value->value.binary.data, "\376\377", 2))
|
||||
if (!(value->value.binary.datalen & 1) && (!memcmp(value->value.binary.data, "\376\377", 2) || !memcmp(value->value.binary.data, "\377\376", 2)))
|
||||
{
|
||||
// Copy UTF-16 BE
|
||||
int ch; // Unicode character
|
||||
size_t remaining; // Remaining bytes
|
||||
|
||||
for (dataptr = value->value.binary.data + 2, remaining = value->value.binary.datalen - 2, tempptr = temp; remaining > 1 && tempptr < (temp + sizeof(temp) - 5); dataptr += 2, remaining -= 2)
|
||||
{
|
||||
ch = (dataptr[0] << 8) | dataptr[1];
|
||||
|
||||
if (ch >= 0xd800 && ch <= 0xdbff && remaining > 3)
|
||||
{
|
||||
// Multi-word UTF-16 char...
|
||||
int lch; // Lower bits
|
||||
|
||||
lch = (dataptr[2] << 8) | dataptr[3];
|
||||
|
||||
if (lch < 0xdc00 || lch >= 0xdfff)
|
||||
break;
|
||||
|
||||
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
|
||||
dataptr += 2;
|
||||
remaining -= 2;
|
||||
}
|
||||
else if (ch >= 0xfffe)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*tempptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 4096)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*tempptr++ = (char)(0xc0 | (ch >> 6));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else if (ch < 65536)
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 12));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 18));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
*tempptr = '\0';
|
||||
}
|
||||
else if (!(value->value.binary.datalen & 1) && !memcmp(value->value.binary.data, "\377\376", 2))
|
||||
{
|
||||
// Copy UTF-16 LE
|
||||
int ch; // Unicode character
|
||||
size_t remaining; // Remaining bytes
|
||||
|
||||
for (dataptr = value->value.binary.data + 2, remaining = value->value.binary.datalen - 2, tempptr = temp; remaining > 1 && tempptr < (temp + sizeof(temp) - 5); dataptr += 2, remaining -= 2)
|
||||
{
|
||||
ch = (dataptr[1] << 8) | dataptr[0];
|
||||
|
||||
if (ch >= 0xd800 && ch <= 0xdbff && remaining > 3)
|
||||
{
|
||||
// Multi-word UTF-16 char...
|
||||
int lch; // Lower bits
|
||||
|
||||
lch = (dataptr[3] << 8) | dataptr[2];
|
||||
|
||||
if (lch < 0xdc00 || lch >= 0xdfff)
|
||||
break;
|
||||
|
||||
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
|
||||
dataptr += 2;
|
||||
remaining -= 2;
|
||||
}
|
||||
else if (ch >= 0xfffe)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*tempptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 4096)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*tempptr++ = (char)(0xc0 | (ch >> 6));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else if (ch < 65536)
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 12));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | (ch >> 18));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
*tempptr = '\0';
|
||||
// Copy UTF-16...
|
||||
_pdfio_utf16cpy(temp, value->value.binary.data, value->value.binary.datalen, sizeof(temp));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -677,6 +568,8 @@ _pdfioDictGetValue(pdfio_dict_t *dict, // I - Dictionary
|
||||
// The iteration continues as long as the callback returns `true` or all keys
|
||||
// have been iterated.
|
||||
//
|
||||
// @since PDFio v1.1@
|
||||
//
|
||||
|
||||
void
|
||||
pdfioDictIterateKeys(
|
||||
@ -750,9 +643,11 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
||||
{
|
||||
// Issue 118: Discard duplicate key/value pairs, in the future this will
|
||||
// be a warning message...
|
||||
_pdfioFileError(pdf, "WARNING: Discarding value for duplicate dictionary key '%s'.", key + 1);
|
||||
_pdfioValueDelete(&value);
|
||||
continue;
|
||||
if (_pdfioFileError(pdf, "WARNING: Discarding value for duplicate dictionary key '%s'.", key + 1))
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if (!_pdfioDictSetValue(dict, pdfioStringCreate(pdf, key + 1), &value))
|
||||
break;
|
||||
|
485
pdfio-file.c
485
pdfio-file.c
@ -8,6 +8,7 @@
|
||||
//
|
||||
|
||||
#include "pdfio-private.h"
|
||||
#include "pdfio-content.h"
|
||||
#ifndef O_BINARY
|
||||
# define O_BINARY 0
|
||||
#endif // !O_BINARY
|
||||
@ -21,11 +22,13 @@ static pdfio_obj_t *add_obj(pdfio_file_t *pdf, size_t number, unsigned short gen
|
||||
static int compare_objmaps(_pdfio_objmap_t *a, _pdfio_objmap_t *b);
|
||||
static pdfio_file_t *create_common(const char *filename, int fd, pdfio_output_cb_t output_cb, void *output_cbdata, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_cbdata);
|
||||
static const char *get_info_string(pdfio_file_t *pdf, const char *key);
|
||||
static char *get_iso_date(time_t t, char *buffer, size_t bufsize);
|
||||
static struct lconv *get_lconv(void);
|
||||
static bool load_obj_stream(pdfio_obj_t *obj);
|
||||
static bool load_pages(pdfio_file_t *pdf, pdfio_obj_t *obj, size_t depth);
|
||||
static bool load_xref(pdfio_file_t *pdf, off_t xref_offset, pdfio_password_cb_t password_cb, void *password_data);
|
||||
static bool repair_xref(pdfio_file_t *pdf, pdfio_password_cb_t password_cb, void *password_data);
|
||||
static bool write_metadata(pdfio_file_t *pdf);
|
||||
static bool write_pages(pdfio_file_t *pdf);
|
||||
static bool write_trailer(pdfio_file_t *pdf);
|
||||
|
||||
@ -123,7 +126,11 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
ret = false;
|
||||
|
||||
if (pdfioObjClose(pdf->info_obj) && write_pages(pdf) && pdfioObjClose(pdf->root_obj) && write_trailer(pdf))
|
||||
// Add default OutputIntent for PDF/A CMYK printing...
|
||||
pdfioFileAddOutputIntent(pdf, /*subtype*/"GTS_PDFA1", /*condition*/"CMYK", /*cond_id*/"CGATS001", /*reg_name*/NULL, /*info*/"CMYK Printing", /*profile*/NULL);
|
||||
|
||||
// Close and write out the last bits...
|
||||
if (write_metadata(pdf) && pdfioObjClose(pdf->info_obj) && write_pages(pdf) && pdfioObjClose(pdf->root_obj) && write_trailer(pdf))
|
||||
ret = _pdfioFileFlush(pdf);
|
||||
}
|
||||
|
||||
@ -181,8 +188,9 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file
|
||||
// of 8.27x11in (the intersection of US Letter and ISO A4) is used.
|
||||
//
|
||||
// The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||
// and its data pointer - if `NULL` the default error handler is used that
|
||||
// writes error messages to `stderr`.
|
||||
// and its data pointer - if `NULL` then the default error handler is used that
|
||||
// writes error messages to `stderr`. The error handler callback should return
|
||||
// `true` to continue writing the PDF file or `false` to stop.
|
||||
//
|
||||
|
||||
pdfio_file_t * // O - PDF file or `NULL` on error
|
||||
@ -260,6 +268,8 @@ pdfioFileCreateArrayObj(
|
||||
// This function creates a new object with a name value in a PDF file.
|
||||
// You must call @link pdfioObjClose@ to write the object to the file.
|
||||
//
|
||||
// @since PDFio v1.4@
|
||||
//
|
||||
|
||||
pdfio_obj_t * // O - New object
|
||||
pdfioFileCreateNameObj(
|
||||
@ -289,6 +299,8 @@ pdfioFileCreateNameObj(
|
||||
// This function creates a new object with a number value in a PDF file.
|
||||
// You must call @link pdfioObjClose@ to write the object to the file.
|
||||
//
|
||||
// @since PDFio v1.2@
|
||||
//
|
||||
|
||||
pdfio_obj_t * // O - New object
|
||||
pdfioFileCreateNumberObj(
|
||||
@ -415,8 +427,9 @@ _pdfioFileCreateObj(
|
||||
// of 8.27x11in (the intersection of US Letter and ISO A4) is used.
|
||||
//
|
||||
// The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||
// and its data pointer - if `NULL` the default error handler is used that
|
||||
// writes error messages to `stderr`.
|
||||
// and its data pointer - if `NULL` then the default error handler is used that
|
||||
// writes error messages to `stderr`. The error handler callback should return
|
||||
// `true` to continue writing the PDF file or `false` to stop.
|
||||
//
|
||||
// > *Note*: Files created using this API are slightly larger than those
|
||||
// > created using the @link pdfioFileCreate@ function since stream lengths are
|
||||
@ -474,8 +487,9 @@ pdfioFileCreatePage(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
pdfioDictSetObj(dict, "Parent", pdf->pages_obj);
|
||||
|
||||
if (!_pdfioDictGetValue(dict, "Resources"))
|
||||
pdfioDictSetDict(dict, "Resources", pdfioDictCreate(pdf));
|
||||
pdfioPageDictAddColorSpace(dict, "DefaultGray", pdfioArrayCreateColorFromStandard(pdf, 1, PDFIO_CS_SRGB));
|
||||
pdfioPageDictAddColorSpace(dict, "DefaultRGB", pdfioArrayCreateColorFromStandard(pdf, 3, PDFIO_CS_SRGB));
|
||||
pdfioPageDictAddColorSpace(dict, "DefaultCMYK", pdfioArrayCreateColorFromStandard(pdf, 4, PDFIO_CS_CGATS001));
|
||||
|
||||
if (!_pdfioDictGetValue(dict, "Type"))
|
||||
pdfioDictSetName(dict, "Type", "Page");
|
||||
@ -518,6 +532,8 @@ pdfioFileCreatePage(pdfio_file_t *pdf, // I - PDF file
|
||||
// This function creates a new object with a string value in a PDF file.
|
||||
// You must call @link pdfioObjClose@ to write the object to the file.
|
||||
//
|
||||
// @since PDFio v1.2@
|
||||
//
|
||||
|
||||
pdfio_obj_t * // O - New object
|
||||
pdfioFileCreateStringObj(
|
||||
@ -824,6 +840,24 @@ pdfioFileGetKeywords(pdfio_file_t *pdf) // I - PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioFileGetLanguage()' - Get the language metadata for a PDF file.
|
||||
//
|
||||
// This function gets the (primary/default) language metadata, if any, for a PDF
|
||||
// file. The returned string is an IETF BCP 47 language tag of the form
|
||||
// "lang-REGION". For example, the string "en-CA" specifies Canadian English
|
||||
// and the string "fr-CA" specifies Canadian French.
|
||||
//
|
||||
// @since PDFio 1.6@
|
||||
//
|
||||
|
||||
const char * // O - Language or `NULL` for none
|
||||
pdfioFileGetLanguage(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
return (pdfioDictGetString(pdfioFileGetCatalog(pdf), "Lang"));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioFileGetModificationDate()' - Get the most recent modification date for a PDF file.
|
||||
//
|
||||
@ -987,8 +1021,14 @@ pdfioFileGetVersion(
|
||||
// PDF file requires a password, the open will always fail.
|
||||
//
|
||||
// The "error_cb" and "error_cbdata" arguments specify an error handler callback
|
||||
// and its data pointer - if `NULL` the default error handler is used that
|
||||
// writes error messages to `stderr`.
|
||||
// and its data pointer - if `NULL` then the default error handler is used that
|
||||
// writes error messages to `stderr`. The error handler callback should return
|
||||
// `true` to continue reading the PDF file or `false` to stop.
|
||||
//
|
||||
// > Note: Error messages starting with "WARNING:" are actually warning
|
||||
// > messages - the callback should normally return `true` to allow PDFio to
|
||||
// > try to resolve the issue. In addition, some errors are unrecoverable and
|
||||
// > ignore the return value of the error callback.
|
||||
//
|
||||
|
||||
pdfio_file_t * // O - PDF file
|
||||
@ -1049,7 +1089,7 @@ pdfioFileOpen(
|
||||
}
|
||||
|
||||
// Read the header from the first line...
|
||||
if (!_pdfioFileGets(pdf, line, sizeof(line)))
|
||||
if (!_pdfioFileGets(pdf, line, sizeof(line), true))
|
||||
goto error;
|
||||
|
||||
if ((strncmp(line, "%PDF-1.", 7) && strncmp(line, "%PDF-2.", 7)) || !isdigit(line[7] & 255))
|
||||
@ -1063,7 +1103,7 @@ pdfioFileOpen(
|
||||
pdf->version = strdup(line + 5);
|
||||
|
||||
// Grab the last 1k of the file to find the start of the xref table...
|
||||
if (_pdfioFileSeek(pdf, -1024, SEEK_END) < 0)
|
||||
if (_pdfioFileSeek(pdf, 1 - sizeof(line), SEEK_END) < 0)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read startxref data.");
|
||||
goto error;
|
||||
@ -1075,28 +1115,36 @@ pdfioFileOpen(
|
||||
goto error;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("pdfioOpen: Read %d bytes at end of file.\n", (int)bytes);
|
||||
|
||||
line[bytes] = '\0';
|
||||
end = line + bytes - 9;
|
||||
|
||||
for (ptr = line; ptr < end; ptr ++)
|
||||
{
|
||||
if (!memcmp(ptr, "startxref", 9))
|
||||
if (!strncmp(ptr, "startxref", 9) && !strstr(ptr + 9, "startxref") && strtol(ptr + 9, NULL, 10) > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ptr >= end)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to find start of xref table.");
|
||||
goto error;
|
||||
}
|
||||
if (!_pdfioFileError(pdf, "WARNING: Unable to find start of cross-reference table, will attempt to rebuild."))
|
||||
goto error;
|
||||
|
||||
xref_offset = (off_t)strtol(ptr + 9, NULL, 10);
|
||||
|
||||
if (!load_xref(pdf, xref_offset, password_cb, password_cbdata))
|
||||
{
|
||||
if (!repair_xref(pdf, password_cb, password_cbdata))
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
PDFIO_DEBUG("pdfioFileOpen: line=%p,ptr=%p(\"%s\")\n", line, ptr, ptr);
|
||||
|
||||
xref_offset = (off_t)strtol(ptr + 9, NULL, 10);
|
||||
|
||||
PDFIO_DEBUG("pdfioFileOpen: xref_offset=%lu\n", (unsigned long)xref_offset);
|
||||
|
||||
if (!load_xref(pdf, xref_offset, password_cb, password_cbdata))
|
||||
goto error;
|
||||
}
|
||||
|
||||
return (pdf);
|
||||
|
||||
@ -1164,6 +1212,26 @@ pdfioFileSetKeywords(
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioFileSetLanguage()' - Set the language metadata for a PDF file.
|
||||
//
|
||||
// This function sets the (primary/default) language metadata for a PDF file.
|
||||
// The "value" argument is an IETF BCP 47 language tag string of the form
|
||||
// "lang-REGION". For example, the string "en-CA" specifies Canadian English
|
||||
// and the string "fr-CA" specifies Canadian French.
|
||||
//
|
||||
// @since PDFio 1.6@
|
||||
//
|
||||
|
||||
void
|
||||
pdfioFileSetLanguage(
|
||||
pdfio_file_t *pdf, // I - PDF file
|
||||
const char *value) // I - Value
|
||||
{
|
||||
pdfioDictSetString(pdfioFileGetCatalog(pdf), "Lang", value);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'pdfioFileSetModificationDate()' - Set the modification date for a PDF file.
|
||||
//
|
||||
@ -1210,6 +1278,8 @@ pdfioFileSetPermissions(
|
||||
if (encryption == PDFIO_ENCRYPTION_NONE)
|
||||
return (true);
|
||||
|
||||
pdf->encrypt_metadata = true;
|
||||
|
||||
return (_pdfioCryptoLock(pdf, permissions, encryption, owner_password, user_password));
|
||||
}
|
||||
|
||||
@ -1530,6 +1600,32 @@ get_info_string(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'get_iso_date()' - Convert a time_t value to an ISO 8601 date/time value.
|
||||
//
|
||||
|
||||
static char * // O - Date string
|
||||
get_iso_date(time_t t, // I - Time value in seconds
|
||||
char *buffer, // I - Date buffer
|
||||
size_t bufsize) // I - Size of date buffer
|
||||
{
|
||||
struct tm d; // Date values
|
||||
|
||||
|
||||
// Convert time to UTC date
|
||||
#if _WIN32
|
||||
gmtime_s(&d, &t);
|
||||
#else
|
||||
gmtime_r(&t, &d);
|
||||
#endif // _WIN32
|
||||
|
||||
// Format the string and return...
|
||||
snprintf(buffer, bufsize, "%04d-%02d-%02dT%02d:%02d:%02dZ", d.tm_year + 1900, d.tm_mon + 1, d.tm_mday, d.tm_hour, d.tm_min, d.tm_sec);
|
||||
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'get_lconv()' - Get any locale-specific numeric information.
|
||||
//
|
||||
@ -1675,7 +1771,10 @@ load_pages(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
if ((type = pdfioDictGetName(dict, "Type")) == NULL || (strcmp(type, "Pages") && strcmp(type, "Page")))
|
||||
return (false);
|
||||
{
|
||||
if (!_pdfioFileError(pdf, "WARNING: No Type value for pages object."))
|
||||
return (false);
|
||||
}
|
||||
|
||||
// If there is a Kids array, then this is a parent node and we have to look
|
||||
// at the child objects...
|
||||
@ -1742,31 +1841,32 @@ load_xref(
|
||||
int generation; // Generation number
|
||||
_pdfio_token_t tb; // Token buffer/stack
|
||||
off_t line_offset; // Offset to start of line
|
||||
pdfio_obj_t *pages_obj; // Pages object
|
||||
|
||||
|
||||
while (!done)
|
||||
{
|
||||
if (_pdfioFileSeek(pdf, xref_offset, SEEK_SET) != xref_offset)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to seek to start of xref table.");
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Unable to seek to %lu.\n", (unsigned long)xref_offset);
|
||||
goto repair;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
line_offset = _pdfioFileTell(pdf);
|
||||
|
||||
if (!_pdfioFileGets(pdf, line, sizeof(line)))
|
||||
if (!_pdfioFileGets(pdf, line, sizeof(line), true))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read start of xref table.");
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Unable to read line at offset %lu.\n", (unsigned long)line_offset);
|
||||
goto repair;
|
||||
}
|
||||
}
|
||||
while (!line[0]);
|
||||
|
||||
PDFIO_DEBUG("load_xref: line_offset=%lu, line='%s'\n", (unsigned long)line_offset, line);
|
||||
|
||||
if (isdigit(line[0] & 255) && strlen(line) > 4 && (!strcmp(line + strlen(line) - 4, " obj") || ((ptr = strstr(line, " obj")) != NULL && ptr[4] == '<')))
|
||||
if (isdigit(line[0] & 255) && strlen(line) > 4 && (!strcmp(line + strlen(line) - 4, " obj") || ((ptr = strstr(line, " obj")) != NULL && (ptr[4] == '<' || isspace(ptr[4])))))
|
||||
{
|
||||
// Cross-reference stream
|
||||
pdfio_obj_t *obj; // Object
|
||||
@ -1788,14 +1888,14 @@ load_xref(
|
||||
|
||||
if ((number = strtoimax(line, &ptr, 10)) < 1)
|
||||
{
|
||||
_pdfioFileError(pdf, "Bad xref table header '%s'.", line);
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Unable to scan object number.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
if ((generation = (int)strtol(ptr, &ptr, 10)) < 0 || (generation > 65535 && number != 0))
|
||||
{
|
||||
_pdfioFileError(pdf, "Bad xref table header '%s'.", line);
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Unable to scan generation number (%u).\n", (unsigned)generation);
|
||||
goto repair;
|
||||
}
|
||||
|
||||
while (isspace(*ptr & 255))
|
||||
@ -1803,14 +1903,14 @@ load_xref(
|
||||
|
||||
if (strncmp(ptr, "obj", 3))
|
||||
{
|
||||
_pdfioFileError(pdf, "Bad xref table header '%s'.", line);
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: No 'obj' after object number and generation (saw '%s').\n", ptr);
|
||||
goto repair;
|
||||
}
|
||||
|
||||
if (_pdfioFileSeek(pdf, line_offset + (off_t)(ptr + 3 - line), SEEK_SET) < 0)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to seek to xref object %lu %u.", (unsigned long)number, (unsigned)generation);
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Unable to seek to start of cross-reference object dictionary.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("load_xref: Loading object %lu %u.\n", (unsigned long)number, (unsigned)generation);
|
||||
@ -1825,21 +1925,21 @@ load_xref(
|
||||
|
||||
if (!_pdfioValueRead(pdf, obj, &tb, &trailer, 0))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read cross-reference stream dictionary.");
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Unable to read cross-reference object dictionary.\n");
|
||||
goto repair;
|
||||
}
|
||||
else if (trailer.type != PDFIO_VALTYPE_DICT)
|
||||
{
|
||||
_pdfioFileError(pdf, "Cross-reference stream does not have a dictionary.");
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Expected dictionary for cross-reference object (type=%d).", trailer.type);
|
||||
goto repair;
|
||||
}
|
||||
|
||||
obj->value = trailer;
|
||||
|
||||
if (!_pdfioTokenGet(&tb, line, sizeof(line)) || strcmp(line, "stream"))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to get stream after xref dictionary.");
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: No stream token after dictionary (got '%s').\n", line);
|
||||
goto repair;
|
||||
}
|
||||
|
||||
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]);
|
||||
@ -1857,8 +1957,8 @@ load_xref(
|
||||
|
||||
if ((w_array = pdfioDictGetArray(trailer.value.dict, "W")) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Cross-reference stream does not have required W key.");
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Missing W array in cross-reference objection dictionary.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
w[0] = (size_t)pdfioArrayGetNumber(w_array, 0);
|
||||
@ -1868,16 +1968,18 @@ load_xref(
|
||||
w_2 = w[0];
|
||||
w_3 = w[0] + w[1];
|
||||
|
||||
if (w[1] == 0 || w[2] > 4 || w[0] > sizeof(buffer) || w[1] > sizeof(buffer) || w[2] > sizeof(buffer) || w_total > sizeof(buffer))
|
||||
PDFIO_DEBUG("W=[%u %u %u], w_total=%u\n", (unsigned)w[0], (unsigned)w[1], (unsigned)w[2], (unsigned)w_total);
|
||||
|
||||
if (pdfioArrayGetSize(w_array) > 3 || 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 [%u %u %u].", (unsigned)w[0], (unsigned)w[1], (unsigned)w[2]);
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Bad W array in cross-reference objection dictionary.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
if ((st = pdfioObjOpenStream(obj, true)) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to open cross-reference stream.");
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Unable to open cross-reference stream.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
for (index_n = 0; index_n < index_count; index_n += 2)
|
||||
@ -1897,7 +1999,20 @@ load_xref(
|
||||
{
|
||||
count --;
|
||||
|
||||
PDFIO_DEBUG("load_xref: number=%u %02X%02X%02X%02X%02X\n", (unsigned)number, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
|
||||
#ifdef DEBUG
|
||||
if (w_total > 5)
|
||||
PDFIO_DEBUG("load_xref: number=%u %02X%02X%02X%02X%02X...\n", (unsigned)number, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
|
||||
else if (w_total == 5)
|
||||
PDFIO_DEBUG("load_xref: number=%u %02X%02X%02X%02X%02X\n", (unsigned)number, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
|
||||
else if (w_total == 4)
|
||||
PDFIO_DEBUG("load_xref: number=%u %02X%02X%02X%02X\n", (unsigned)number, buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
else if (w_total == 3)
|
||||
PDFIO_DEBUG("load_xref: number=%u %02X%02X%02X\n", (unsigned)number, buffer[0], buffer[1], buffer[2]);
|
||||
else if (w_total == 2)
|
||||
PDFIO_DEBUG("load_xref: number=%u %02X%02X\n", (unsigned)number, buffer[0], buffer[1]);
|
||||
else
|
||||
PDFIO_DEBUG("load_xref: number=%u %02X\n", (unsigned)number, buffer[0]);
|
||||
#endif // DEBUG
|
||||
|
||||
// Check whether this is an object definition...
|
||||
if (w[0] > 0)
|
||||
@ -1979,6 +2094,7 @@ load_xref(
|
||||
else
|
||||
{
|
||||
_pdfioFileError(pdf, "Too many object streams.");
|
||||
pdfioStreamClose(st);
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
@ -1987,7 +2103,10 @@ load_xref(
|
||||
{
|
||||
// Add this object...
|
||||
if (!add_obj(pdf, (size_t)number, (unsigned short)generation, (off_t)offset))
|
||||
{
|
||||
pdfioStreamClose(st);
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
number ++;
|
||||
@ -2035,7 +2154,7 @@ load_xref(
|
||||
// Offset of current line
|
||||
|
||||
PDFIO_DEBUG("load_xref: Reading xref table starting at offset %lu\n", (unsigned long)trailer_offset);
|
||||
while (_pdfioFileGets(pdf, line, sizeof(line)))
|
||||
while (_pdfioFileGets(pdf, line, sizeof(line), false))
|
||||
{
|
||||
PDFIO_DEBUG("load_xref: '%s' at offset %lu\n", line, (unsigned long)trailer_offset);
|
||||
|
||||
@ -2060,8 +2179,8 @@ load_xref(
|
||||
|
||||
if (sscanf(line, "%jd%jd", &number, &num_objects) != 2)
|
||||
{
|
||||
_pdfioFileError(pdf, "Malformed xref table section '%s'.", line);
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Unable to scan START COUNT from line.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
// Read this group of objects...
|
||||
@ -2069,41 +2188,45 @@ load_xref(
|
||||
{
|
||||
// Read a line from the file and validate it...
|
||||
if (_pdfioFileRead(pdf, line, 20) != 20)
|
||||
return (false);
|
||||
{
|
||||
PDFIO_DEBUG("load_xref: Unable to read 20 byte xref record.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
line[20] = '\0';
|
||||
|
||||
if (strcmp(line + 18, "\r\n") && strcmp(line + 18, " \n") && strcmp(line + 18, " \r"))
|
||||
if (strcmp(line + 18, "\r\n") && strcmp(line + 18, "\r\r") && strcmp(line + 18, " \n") && strcmp(line + 18, " \r"))
|
||||
{
|
||||
_pdfioFileError(pdf, "Malformed xref table entry '%s'.", line);
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Bad end-of-line <%02X%02X>\n", line[18], line[19]);
|
||||
goto repair;
|
||||
}
|
||||
|
||||
line[18] = '\0';
|
||||
|
||||
// Parse the line
|
||||
if ((offset = strtoimax(line, &ptr, 10)) < 0)
|
||||
{
|
||||
_pdfioFileError(pdf, "Malformed xref table entry '%s'.", line);
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Unable to scan offset.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
if ((generation = (int)strtol(ptr, &ptr, 10)) < 0 || (generation > 65535 && offset != 0))
|
||||
{
|
||||
_pdfioFileError(pdf, "Malformed xref table entry '%s'.", line);
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Unable to scan generation (%u).\n", (unsigned)generation);
|
||||
goto repair;
|
||||
}
|
||||
|
||||
if (*ptr != ' ')
|
||||
{
|
||||
_pdfioFileError(pdf, "Malformed xref table entry '%s'.", line);
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Missing space before type.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
ptr ++;
|
||||
if (*ptr != 'f' && *ptr != 'n')
|
||||
{
|
||||
_pdfioFileError(pdf, "Malformed xref table entry '%s'.", line);
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Bad type '%c'.\n", *ptr);
|
||||
goto repair;
|
||||
}
|
||||
|
||||
if (*ptr == 'f')
|
||||
@ -2122,21 +2245,21 @@ load_xref(
|
||||
|
||||
if (strncmp(line, "trailer", 7))
|
||||
{
|
||||
_pdfioFileError(pdf, "Missing trailer.");
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: No trailer after xref table.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
_pdfioTokenInit(&tb, pdf, (_pdfio_tconsume_cb_t)_pdfioFileConsume, (_pdfio_tpeek_cb_t)_pdfioFilePeek, pdf);
|
||||
|
||||
if (!_pdfioValueRead(pdf, NULL, &tb, &trailer, 0))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read trailer dictionary.");
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Unable to read trailer dictionary.\n");
|
||||
goto repair;
|
||||
}
|
||||
else if (trailer.type != PDFIO_VALTYPE_DICT)
|
||||
{
|
||||
_pdfioFileError(pdf, "Trailer is not a dictionary.");
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Trailer not a dictionary (type=%d).\n", trailer.type);
|
||||
goto repair;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("load_xref: Got trailer dict.\n");
|
||||
@ -2158,8 +2281,7 @@ load_xref(
|
||||
}
|
||||
else
|
||||
{
|
||||
_pdfioFileError(pdf, "Bad xref table header '%s'.", line);
|
||||
return (false);
|
||||
goto repair;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("load_xref: Contents of trailer dictionary:\n");
|
||||
@ -2188,13 +2310,31 @@ load_xref(
|
||||
|
||||
if ((pdf->root_obj = pdfioDictGetObj(pdf->trailer_dict, "Root")) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Missing Root object.");
|
||||
return (false);
|
||||
PDFIO_DEBUG("load_xref: Missing Root object.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("load_xref: Root=%p(%lu)\n", pdf->root_obj, (unsigned long)pdf->root_obj->number);
|
||||
|
||||
return (load_pages(pdf, pdfioDictGetObj(pdfioObjGetDict(pdf->root_obj), "Pages"), 0));
|
||||
if ((pages_obj = pdfioDictGetObj(pdfioObjGetDict(pdf->root_obj), "Pages")) == NULL)
|
||||
{
|
||||
PDFIO_DEBUG("load_xref: Missing Pages object.\n");
|
||||
goto repair;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("load_xref: Pages=%p(%lu)\n", pdf->root_obj, (unsigned long)pdf->root_obj->number);
|
||||
|
||||
return (load_pages(pdf, pages_obj, 0));
|
||||
|
||||
// If we get here the cross-reference table is busted - try repairing if the
|
||||
// error callback says to proceed...
|
||||
|
||||
repair:
|
||||
|
||||
if (_pdfioFileError(pdf, "WARNING: Cross-reference is damaged, will attempt to rebuild."))
|
||||
return (repair_xref(pdf, password_cb, password_data));
|
||||
else
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
@ -2208,7 +2348,7 @@ repair_xref(
|
||||
pdfio_password_cb_t password_cb, // I - Password callback or `NULL` for none
|
||||
void *password_data) // I - Password callback data, if any
|
||||
{
|
||||
char line[16384], // Line from file
|
||||
char line[1024], // Line from file
|
||||
*ptr; // Pointer into line
|
||||
off_t line_offset; // Offset in file
|
||||
intmax_t number; // Object number
|
||||
@ -2216,16 +2356,22 @@ repair_xref(
|
||||
size_t i; // Looping var
|
||||
size_t num_sobjs = 0; // Number of object streams
|
||||
pdfio_obj_t *sobjs[16384]; // Object streams to load
|
||||
pdfio_dict_t *backup_trailer = NULL; // Backup trailer dictionary
|
||||
pdfio_obj_t *pages_obj; // Pages object
|
||||
|
||||
|
||||
// Let caller know something is wrong...
|
||||
_pdfioFileError(pdf, "WARNING: Cross-reference table is damaged, attempting to rebuild.");
|
||||
// Clear trailer data...
|
||||
pdf->trailer_dict = NULL;
|
||||
pdf->root_obj = NULL;
|
||||
pdf->info_obj = NULL;
|
||||
pdf->pages_obj = NULL;
|
||||
pdf->encrypt_obj = NULL;
|
||||
|
||||
// Read from the beginning of the file, looking for
|
||||
// Read from the beginning of the file, looking for objects...
|
||||
if ((line_offset = _pdfioFileSeek(pdf, 0, SEEK_SET)) < 0)
|
||||
return (false);
|
||||
|
||||
while (_pdfioFileGets(pdf, line, sizeof(line)))
|
||||
while (_pdfioFileGets(pdf, line, sizeof(line), true))
|
||||
{
|
||||
// See if this is the start of an object...
|
||||
if (line[0] >= '1' && line[0] <= '9')
|
||||
@ -2242,43 +2388,75 @@ repair_xref(
|
||||
pdfio_obj_t *obj; // Object
|
||||
_pdfio_token_t tb; // Token buffer/stack
|
||||
|
||||
PDFIO_DEBUG("OBJECT %ld %d at offset %ld\n", (long)number, generation, (long)line_offset);
|
||||
PDFIO_DEBUG("repair_xref: OBJECT %ld %d at offset %ld\n", (long)number, generation, (long)line_offset);
|
||||
|
||||
if ((obj = add_obj(pdf, (size_t)number, (unsigned short)generation, line_offset)) == NULL)
|
||||
if ((obj = pdfioFileFindObj(pdf, (size_t)number)) != NULL)
|
||||
{
|
||||
obj->offset = line_offset;
|
||||
}
|
||||
else if ((obj = add_obj(pdf, (size_t)number, (unsigned short)generation, line_offset)) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to allocate memory for object.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (ptr[3])
|
||||
{
|
||||
// Probably the start of the object dictionary, rewind the file so
|
||||
// we can read it...
|
||||
_pdfioFileSeek(pdf, line_offset + (ptr - line + 3), SEEK_SET);
|
||||
}
|
||||
|
||||
_pdfioTokenInit(&tb, pdf, (_pdfio_tconsume_cb_t)_pdfioFileConsume, (_pdfio_tpeek_cb_t)_pdfioFilePeek, pdf);
|
||||
|
||||
if (!_pdfioValueRead(pdf, obj, &tb, &obj->value, 0))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read cross-reference stream dictionary.");
|
||||
return (false);
|
||||
if (!_pdfioFileError(pdf, "WARNING: Unable to read object dictionary/value."))
|
||||
return (false);
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_pdfioTokenGet(&tb, line, sizeof(line)) && strcmp(line, "stream"))
|
||||
if (_pdfioTokenGet(&tb, line, sizeof(line)))
|
||||
{
|
||||
const char *type = pdfioObjGetType(obj);
|
||||
// Object type
|
||||
|
||||
_pdfioTokenFlush(&tb);
|
||||
obj->stream_offset = _pdfioFileTell(pdf);
|
||||
|
||||
if (type && !strcmp(type, "ObjStm") && num_sobjs < (sizeof(sobjs) / sizeof(sobjs[0])))
|
||||
{
|
||||
sobjs[num_sobjs] = obj;
|
||||
num_sobjs ++;
|
||||
}
|
||||
|
||||
if (type && !strcmp(type, "XRef") && !pdf->trailer_dict)
|
||||
if (type && !strcmp(line, "stream"))
|
||||
{
|
||||
// Save the trailer dictionary...
|
||||
pdf->trailer_dict = pdfioObjGetDict(obj);
|
||||
pdf->encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt");
|
||||
pdf->id_array = pdfioDictGetArray(pdf->trailer_dict, "ID");
|
||||
}
|
||||
// Possible object or XRef stream...
|
||||
obj->stream_offset = _pdfioFileTell(pdf);
|
||||
|
||||
if (!strcmp(type, "ObjStm") && num_sobjs < (sizeof(sobjs) / sizeof(sobjs[0])))
|
||||
{
|
||||
PDFIO_DEBUG("repair_xref: Object stream...\n");
|
||||
sobjs[num_sobjs] = obj;
|
||||
num_sobjs ++;
|
||||
}
|
||||
|
||||
if (!strcmp(type, "XRef") && !pdf->trailer_dict)
|
||||
{
|
||||
// Save the trailer dictionary...
|
||||
PDFIO_DEBUG("repair_xref: XRef stream...\n");
|
||||
pdf->trailer_dict = pdfioObjGetDict(obj);
|
||||
pdf->encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt");
|
||||
pdf->id_array = pdfioDictGetArray(pdf->trailer_dict, "ID");
|
||||
}
|
||||
}
|
||||
else if (type && !strcmp(line, "endobj"))
|
||||
{
|
||||
// Possible catalog or pages object...
|
||||
if (!strcmp(type, "Catalog"))
|
||||
{
|
||||
PDFIO_DEBUG("repair_xref: Catalog (root) object...\n");
|
||||
if (!backup_trailer)
|
||||
backup_trailer = pdfioDictCreate(pdf);
|
||||
|
||||
pdfioDictSetObj(backup_trailer, "Root", obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2289,6 +2467,8 @@ repair_xref(
|
||||
_pdfio_token_t tb; // Token buffer/stack
|
||||
_pdfio_value_t trailer; // Trailer
|
||||
|
||||
PDFIO_DEBUG("repair_xref: line=\"%s\"\n", line);
|
||||
|
||||
if (line[7])
|
||||
{
|
||||
// Probably the start of the trailer dictionary, rewind the file so
|
||||
@ -2296,7 +2476,7 @@ repair_xref(
|
||||
_pdfioFileSeek(pdf, line_offset + 7, SEEK_SET);
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("TRAILER at offset %ld\n", (long)line_offset);
|
||||
PDFIO_DEBUG("repair_xref: TRAILER at offset %ld\n", (long)line_offset);
|
||||
|
||||
_pdfioTokenInit(&tb, pdf, (_pdfio_tconsume_cb_t)_pdfioFileConsume, (_pdfio_tpeek_cb_t)_pdfioFilePeek, pdf);
|
||||
if (!_pdfioValueRead(pdf, NULL, &tb, &trailer, 0))
|
||||
@ -2312,10 +2492,12 @@ repair_xref(
|
||||
|
||||
_pdfioTokenFlush(&tb);
|
||||
|
||||
if (!pdf->trailer_dict)
|
||||
if (_pdfioDictGetValue(trailer.value.dict, "Root"))
|
||||
{
|
||||
// Save the trailer dictionary and grab the root (catalog) and info
|
||||
// objects...
|
||||
PDFIO_DEBUG("repair_xref: Using this trailer dictionary.\n");
|
||||
|
||||
pdf->trailer_dict = trailer.value.dict;
|
||||
pdf->encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt");
|
||||
pdf->id_array = pdfioDictGetArray(pdf->trailer_dict, "ID");
|
||||
@ -2326,11 +2508,18 @@ repair_xref(
|
||||
line_offset = _pdfioFileTell(pdf);
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("repair_xref: Stopped at line_offset=%lu\n", (unsigned long)line_offset);
|
||||
|
||||
if (!pdf->trailer_dict && backup_trailer)
|
||||
pdf->trailer_dict = backup_trailer;
|
||||
|
||||
// If the trailer contains an Encrypt key, try unlocking the file...
|
||||
if (pdf->encrypt_obj && !_pdfioCryptoUnlock(pdf, password_cb, password_data))
|
||||
return (false);
|
||||
|
||||
// Load any stream objects...
|
||||
PDFIO_DEBUG("repair_xref: Found %lu stream objects.\n", (unsigned long)num_sobjs);
|
||||
|
||||
for (i = 0; i < num_sobjs; i ++)
|
||||
{
|
||||
if (!load_obj_stream(sobjs[i]))
|
||||
@ -2349,8 +2538,99 @@ repair_xref(
|
||||
|
||||
PDFIO_DEBUG("repair_xref: Root=%p(%lu)\n", pdf->root_obj, (unsigned long)pdf->root_obj->number);
|
||||
|
||||
if ((pages_obj = pdfioDictGetObj(pdfioObjGetDict(pdf->root_obj), "Pages")) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Missing Pages object.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("repair_xref: Pages=%p(%lu)\n", pages_obj, (unsigned long)pages_obj->number);
|
||||
|
||||
// Load pages...
|
||||
return (load_pages(pdf, pdfioDictGetObj(pdfioObjGetDict(pdf->root_obj), "Pages"), 0));
|
||||
return (load_pages(pdf, pages_obj, 0));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'write_metadata()' - Write an XMP metadata stream.
|
||||
//
|
||||
|
||||
static bool // O - `true` on success, `false` on failure
|
||||
write_metadata(pdfio_file_t *pdf) // I - PDF file
|
||||
{
|
||||
pdfio_dict_t *dict; // XMP object dictionary
|
||||
pdfio_obj_t *obj; // XMP object
|
||||
pdfio_stream_t *st; // XMP stream
|
||||
bool status = true; // Write status
|
||||
const char *value; // Value from info dictionary
|
||||
time_t t; // Date/time value in seconds
|
||||
char d[64]; // Date/time string (ISO 8601)
|
||||
|
||||
|
||||
// Create the Metadata object...
|
||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||
return (false);
|
||||
|
||||
pdfioDictSetName(dict, "Type", "Metadata");
|
||||
pdfioDictSetName(dict, "Subtype", "XML");
|
||||
|
||||
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
|
||||
return (false);
|
||||
|
||||
// Write the XMP stream...
|
||||
if ((st = pdfioObjCreateStream(obj, PDFIO_FILTER_NONE)) == NULL)
|
||||
return (false);
|
||||
|
||||
status &= pdfioStreamPuts(st, "<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n");
|
||||
status &= pdfioStreamPuts(st, "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n");
|
||||
status &= pdfioStreamPuts(st, " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n");
|
||||
|
||||
status &= pdfioStreamPuts(st, " <rdf:Description rdf:about=\"\" xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n");
|
||||
t = pdfioFileGetCreationDate(pdf);
|
||||
status &= pdfioStreamPrintf(st, " <xmp:CreateDate>%H</xmp:CreateDate>\n", get_iso_date(t, d, sizeof(d)));
|
||||
if ((value = pdfioFileGetCreator(pdf)) != NULL)
|
||||
status &= pdfioStreamPrintf(st, " <xmp:CreatorTool>%H</xmp:CreatorTool>\n", value);
|
||||
status &= pdfioStreamPrintf(st, " <xmp:MetadataDate>%H</xmp:MetadataDate>\n", d);
|
||||
if ((t = pdfioFileGetModificationDate(pdf)) > 0)
|
||||
status &= pdfioStreamPrintf(st, " <xmp:ModifyDate>%H</xmp:ModifyDate>\n", get_iso_date(t, d, sizeof(d)));
|
||||
status &= pdfioStreamPuts(st, " </rdf:Description>\n");
|
||||
|
||||
status &= pdfioStreamPuts(st, " <rdf:Description rdf:about=\"\" xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n");
|
||||
status &= pdfioStreamPrintf(st, " <pdf:Producer>%H</pdf:Producer>\n", pdfioFileGetProducer(pdf));
|
||||
if ((value = pdfioFileGetKeywords(pdf)) != NULL)
|
||||
status &= pdfioStreamPrintf(st, " <pdf:Keywords>%H</pdf:Keywords>\n", value);
|
||||
status &= pdfioStreamPuts(st, " </rdf:Description>\n");
|
||||
|
||||
status &= pdfioStreamPuts(st, " <rdf:Description rdf:about=\"\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n");
|
||||
status &= pdfioStreamPrintf(st, " <dc:format>application/pdf</dc:format>\n");
|
||||
if ((value = pdfioFileGetTitle(pdf)) != NULL)
|
||||
status &= pdfioStreamPrintf(st, " <dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">%H</rdf:li></rdf:Alt></dc:title>\n", value);
|
||||
if ((value = pdfioFileGetAuthor(pdf)) != NULL)
|
||||
status &= pdfioStreamPrintf(st, " <dc:creator><rdf:Seq><rdf:li>%H</rdf:li></rdf:Seq></dc:creator>\n", value);
|
||||
if ((value = pdfioFileGetSubject(pdf)) != NULL)
|
||||
status &= pdfioStreamPrintf(st, " <dc:description><rdf:Alt><rdf:li xml:lang=\"x-default\">%H</rdf:li></rdf:Alt></dc:description>\n", value);
|
||||
status &= pdfioStreamPuts(st, " </rdf:Description>\n");
|
||||
|
||||
// TODO: Need a better way to choose the output profile - something that lets
|
||||
// us choose the base PDF version and PDF/A, PDF/E, PDF/X, etc.
|
||||
#if 0
|
||||
status &= pdfioStreamPuts(st, " <rdf:Description rdf:about=\"\" xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n");
|
||||
status &= pdfioStreamPuts(st, " <pdfaid:conformance>A</pdfaid:conformance>\n");
|
||||
status &= pdfioStreamPuts(st, " <pdfaid:part>1</pdfaid:part>\n");
|
||||
status &= pdfioStreamPuts(st, " </rdf:Description>\n");
|
||||
#endif // 0
|
||||
|
||||
status &= pdfioStreamPuts(st, " </rdf:RDF>\n");
|
||||
status &= pdfioStreamPuts(st, "</x:xmpmeta>\n");
|
||||
status &= pdfioStreamPuts(st, "<?xpacket end=\"r\"?>\n");
|
||||
|
||||
status &= pdfioStreamClose(st);
|
||||
|
||||
if (!status)
|
||||
return (false);
|
||||
|
||||
// If we get this far, add the Metadata key/value to the catalog/root object.
|
||||
return (pdfioDictSetObj(pdfioFileGetCatalog(pdf), "Metadata", obj));
|
||||
}
|
||||
|
||||
|
||||
@ -2500,12 +2780,16 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
|
||||
buffer[2] = (obj->offset >> 8) & 255;
|
||||
buffer[3] = obj->offset & 255;
|
||||
break;
|
||||
#ifdef _WIN32
|
||||
default :
|
||||
#endif // _WIN32
|
||||
case 4 :
|
||||
buffer[1] = (obj->offset >> 24) & 255;
|
||||
buffer[2] = (obj->offset >> 16) & 255;
|
||||
buffer[3] = (obj->offset >> 8) & 255;
|
||||
buffer[4] = obj->offset & 255;
|
||||
break;
|
||||
#ifndef _WIN32 // Windows off_t is 32-bits?!?
|
||||
case 5 :
|
||||
buffer[1] = (obj->offset >> 32) & 255;
|
||||
buffer[2] = (obj->offset >> 24) & 255;
|
||||
@ -2540,6 +2824,7 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
|
||||
buffer[7] = (obj->offset >> 8) & 255;
|
||||
buffer[8] = obj->offset & 255;
|
||||
break;
|
||||
#endif // !_WIN32
|
||||
}
|
||||
|
||||
if (!pdfioStreamWrite(xref_st, buffer, offsize + 2))
|
||||
|
@ -141,6 +141,7 @@ pdfioObjCreateStream(
|
||||
pdfio_obj_t *obj, // I - Object
|
||||
pdfio_filter_t filter) // I - Type of compression to apply
|
||||
{
|
||||
pdfio_stream_t *st; // Stream
|
||||
pdfio_obj_t *length_obj = NULL; // Length object, if any
|
||||
|
||||
|
||||
@ -194,11 +195,13 @@ pdfioObjCreateStream(
|
||||
if (!_pdfioFilePuts(obj->pdf, "stream\n"))
|
||||
return (NULL);
|
||||
|
||||
obj->stream_offset = _pdfioFileTell(obj->pdf);
|
||||
obj->pdf->current_obj = obj;
|
||||
obj->stream_offset = _pdfioFileTell(obj->pdf);
|
||||
|
||||
// Return the new stream...
|
||||
return (_pdfioStreamCreate(obj, length_obj, 0, filter));
|
||||
if ((st = _pdfioStreamCreate(obj, length_obj, 0, filter)) != NULL)
|
||||
obj->pdf->current_obj = obj;
|
||||
|
||||
return (st);
|
||||
}
|
||||
|
||||
|
||||
@ -330,6 +333,8 @@ pdfioObjGetLength(pdfio_obj_t *obj) // I - Object
|
||||
//
|
||||
// 'pdfioObjGetName()' - Get the name value associated with an object.
|
||||
//
|
||||
// @since PDFio v1.4@
|
||||
//
|
||||
|
||||
const char * // O - Dictionary or `NULL` on error
|
||||
pdfioObjGetName(pdfio_obj_t *obj) // I - Object
|
||||
@ -505,7 +510,7 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
||||
}
|
||||
|
||||
// Decrypt as needed...
|
||||
if (obj->pdf->encryption)
|
||||
if (obj->pdf->encryption && obj->pdf->encrypt_metadata)
|
||||
{
|
||||
PDFIO_DEBUG("_pdfioObjLoad: Decrypting value...\n");
|
||||
|
||||
@ -532,6 +537,9 @@ pdfio_stream_t * // O - Stream or `NULL` on error
|
||||
pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object
|
||||
bool decode) // I - Decode/decompress data?
|
||||
{
|
||||
pdfio_stream_t *st; // Stream
|
||||
|
||||
|
||||
// Range check input...
|
||||
if (!obj)
|
||||
return (NULL);
|
||||
@ -554,9 +562,10 @@ pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object
|
||||
return (NULL);
|
||||
|
||||
// Open the stream...
|
||||
obj->pdf->current_obj = obj;
|
||||
if ((st = _pdfioStreamOpen(obj, decode)) != NULL)
|
||||
obj->pdf->current_obj = obj;
|
||||
|
||||
return (_pdfioStreamOpen(obj, decode));
|
||||
return (st);
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
#ifndef PDFIO_PRIVATE_H
|
||||
# define PDFIO_PRIVATE_H
|
||||
# ifdef _WIN32
|
||||
# define _CRT_SECURE_NO_WARNINGS // Disable bogus VS warnings/errors...
|
||||
# define _CRT_SECURE_NO_WARNINGS 1 // Disable bogus VS warnings/errors...
|
||||
# endif // _WIN32
|
||||
# include "pdfio.h"
|
||||
# include <stdarg.h>
|
||||
@ -28,16 +28,16 @@
|
||||
# define access _access // Map standard POSIX/C99 names
|
||||
# define close _close
|
||||
# define fileno _fileno
|
||||
# define lseek _lseek
|
||||
# define lseek(f,o,w) (off_t)_lseek((f),(long)(o),(w))
|
||||
# define mkdir(d,p) _mkdir(d)
|
||||
# define open _open
|
||||
# define read _read
|
||||
# define read(f,b,s) _read((f),(b),(unsigned)(s))
|
||||
# define rmdir _rmdir
|
||||
# define snprintf _snprintf
|
||||
# define strdup _strdup
|
||||
# define unlink _unlink
|
||||
# define vsnprintf _vsnprintf
|
||||
# define write _write
|
||||
# define write(f,b,s) _write((f),(b),(unsigned)(s))
|
||||
# ifndef F_OK
|
||||
# define F_OK 00 // POSIX parameters/flags
|
||||
# define W_OK 02
|
||||
@ -267,9 +267,11 @@ struct _pdfio_file_s // PDF file structure
|
||||
pdfio_obj_t *info_obj; // Information object
|
||||
pdfio_obj_t *pages_obj; // Root pages object
|
||||
pdfio_obj_t *encrypt_obj; // De/Encryption object/dictionary
|
||||
pdfio_obj_t *cp1252_obj, // CP1252 font encoding object
|
||||
pdfio_obj_t *cgats001_obj, // CGATS001 ICC profile object
|
||||
*cp1252_obj, // CP1252 font encoding object
|
||||
*unicode_obj; // Unicode font encoding object
|
||||
pdfio_array_t *id_array; // ID array
|
||||
bool encrypt_metadata; // Encrypt metadata?
|
||||
|
||||
// Allocated data elements
|
||||
size_t num_arrays, // Number of arrays
|
||||
@ -339,6 +341,7 @@ struct _pdfio_stream_s // Stream
|
||||
|
||||
extern size_t _pdfio_strlcpy(char *dst, const char *src, size_t dstsize) _PDFIO_INTERNAL;
|
||||
extern double _pdfio_strtod(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
|
||||
extern void _pdfio_utf16cpy(char *dst, const unsigned char *src, size_t srclen, size_t dstsize) _PDFIO_INTERNAL;
|
||||
extern ssize_t _pdfio_vsnprintf(pdfio_file_t *pdf, char *buffer, size_t bufsize, const char *format, va_list ap) _PDFIO_INTERNAL;
|
||||
|
||||
extern bool _pdfioArrayDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_array_t *a, size_t depth) _PDFIO_INTERNAL;
|
||||
@ -382,7 +385,7 @@ extern bool _pdfioFileError(pdfio_file_t *pdf, const char *format, ...) _PDFIO_
|
||||
extern pdfio_obj_t *_pdfioFileFindMappedObj(pdfio_file_t *pdf, pdfio_file_t *src_pdf, size_t src_number) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileFlush(pdfio_file_t *pdf) _PDFIO_INTERNAL;
|
||||
extern int _pdfioFileGetChar(pdfio_file_t *pdf) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileGets(pdfio_file_t *pdf, char *buffer, size_t bufsize) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFileGets(pdfio_file_t *pdf, char *buffer, size_t bufsize, bool discard) _PDFIO_INTERNAL;
|
||||
extern ssize_t _pdfioFilePeek(pdfio_file_t *pdf, void *buffer, size_t bytes) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFilePrintf(pdfio_file_t *pdf, const char *format, ...) _PDFIO_INTERNAL;
|
||||
extern bool _pdfioFilePuts(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
|
||||
|
@ -259,7 +259,7 @@ _pdfioStreamCreate(
|
||||
{
|
||||
colors = 1;
|
||||
}
|
||||
else if (colors < 0 || colors > 4)
|
||||
else if (colors < 0 || colors > 32)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Colors value %d.", colors);
|
||||
free(st);
|
||||
@ -532,7 +532,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
{
|
||||
colors = 1;
|
||||
}
|
||||
else if (colors < 0 || colors > 4)
|
||||
else if (colors < 0 || colors > 32)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unsupported Colors value %d.", colors);
|
||||
goto error;
|
||||
@ -562,6 +562,13 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
||||
if (predictor >= 10)
|
||||
st->pbsize ++; // Add PNG predictor byte
|
||||
|
||||
if (st->pbsize < 2)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Bad Predictor buffer size %lu.", (unsigned long)st->pbsize);
|
||||
goto error;
|
||||
}
|
||||
|
||||
PDFIO_DEBUG("_pdfioStreamOpen: st->predictor=%d, st->pbpixel=%u, st->pbsize=%lu\n", st->predictor, (unsigned)st->pbpixel, (unsigned long)st->pbsize);
|
||||
if ((st->prbuffer = calloc(1, st->pbsize - 1)) == NULL || (st->psbuffer = calloc(1, st->pbsize)) == NULL)
|
||||
{
|
||||
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Predictor buffers.", (unsigned long)st->pbsize);
|
||||
@ -690,8 +697,9 @@ pdfioStreamPeek(pdfio_stream_t *st, // I - Stream
|
||||
// 'pdfioStreamPrintf()' - Write a formatted string to a stream.
|
||||
//
|
||||
// This function writes a formatted string to a stream. In addition to the
|
||||
// standard `printf` format characters, you can use "%N" to format a PDF name
|
||||
// value ("/Name") and "%S" to format a PDF string ("(String)") value.
|
||||
// standard `printf` format characters, you can use "%H" to format a HTML/XML
|
||||
// string value, "%N" to format a PDF name value ("/Name"), and "%S" to format
|
||||
// a PDF string ("(String)") value.
|
||||
//
|
||||
|
||||
bool // O - `true` on success, `false` on failure
|
||||
@ -1227,7 +1235,18 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
||||
}
|
||||
|
||||
// Apply predictor for this line
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X %02X %02X %02X.\n", sptr[-1], sptr[0], sptr[0], sptr[2], sptr[3]);
|
||||
#ifdef DEBUG
|
||||
if (remaining > 4)
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X %02X %02X %02X ...\n", sptr[-1], sptr[0], sptr[1], sptr[2], sptr[3]);
|
||||
else if (remaining > 3)
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X %02X %02X %02X.\n", sptr[-1], sptr[0], sptr[1], sptr[2], sptr[3]);
|
||||
else if (remaining > 2)
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X %02X %02X.\n", sptr[-1], sptr[0], sptr[1], sptr[2]);
|
||||
else if (remaining > 1)
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X %02X.\n", sptr[-1], sptr[0], sptr[1]);
|
||||
else
|
||||
PDFIO_DEBUG("stream_read: Line %02X %02X.\n", sptr[-1], sptr[0]);
|
||||
#endif // DEBUG
|
||||
|
||||
switch (sptr[-1])
|
||||
{
|
||||
|
136
pdfio-string.c
136
pdfio-string.c
@ -158,6 +158,89 @@ _pdfio_strtod(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_utf16cpy()' - Convert UTF-16 to UTF-8.
|
||||
//
|
||||
|
||||
void
|
||||
_pdfio_utf16cpy(
|
||||
char *dst, // I - Destination buffer for UTF-8
|
||||
const unsigned char *src, // I - Source UTF-16
|
||||
size_t srclen, // I - Length of UTF-16
|
||||
size_t dstsize) // I - Destination buffer size
|
||||
{
|
||||
char *dstptr = dst, // Pointer into buffer
|
||||
*dstend = dst + dstsize - 5; // End of buffer
|
||||
int ch; // Unicode character
|
||||
bool is_be = !memcmp(src, "\376\377", 2);
|
||||
// Big-endian strings?
|
||||
|
||||
|
||||
// Loop through the UTF-16 string, converting to Unicode then UTF-8...
|
||||
for (src += 2, srclen -= 2; srclen > 1 && dstptr < dstend; src += 2, srclen -= 2)
|
||||
{
|
||||
// Initial character...
|
||||
if (is_be)
|
||||
ch = (src[0] << 8) | src[1];
|
||||
else
|
||||
ch = (src[1] << 8) | src[0];
|
||||
|
||||
if (ch >= 0xd800 && ch <= 0xdbff && srclen > 3)
|
||||
{
|
||||
// Multi-word UTF-16 char...
|
||||
int lch; // Lower bits
|
||||
|
||||
if (is_be)
|
||||
lch = (src[2] << 8) | src[3];
|
||||
else
|
||||
lch = (src[3] << 8) | src[2];
|
||||
|
||||
if (lch < 0xdc00 || lch >= 0xdfff)
|
||||
break;
|
||||
|
||||
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
|
||||
src += 2;
|
||||
srclen -= 2;
|
||||
}
|
||||
else if (ch >= 0xfffe)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert Unicode to UTF-8...
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*dstptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 4096)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*dstptr++ = (char)(0xc0 | (ch >> 6));
|
||||
*dstptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else if (ch < 65536)
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*dstptr++ = (char)(0xe0 | (ch >> 12));
|
||||
*dstptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*dstptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4-byte UTF-8
|
||||
*dstptr++ = (char)(0xe0 | (ch >> 18));
|
||||
*dstptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
|
||||
*dstptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*dstptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
// Nul-terminate the UTF-8 string...
|
||||
*dstptr = '\0';
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// '_pdfio_vsnprintf()' - Format a string.
|
||||
//
|
||||
@ -403,6 +486,59 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
|
||||
}
|
||||
break;
|
||||
|
||||
case 'H' : // XML/HTML string
|
||||
if ((s = va_arg(ap, char *)) == NULL)
|
||||
s = "(null)";
|
||||
|
||||
// Loop through the literal string...
|
||||
while (*s)
|
||||
{
|
||||
// Escape special characters
|
||||
if (*s == '&')
|
||||
{
|
||||
// &
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, "&", (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
|
||||
bytes += 5;
|
||||
}
|
||||
else if (*s == '<')
|
||||
{
|
||||
// <
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, "<", (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
|
||||
bytes += 4;
|
||||
}
|
||||
else if (*s == '>')
|
||||
{
|
||||
// >
|
||||
if (bufptr < bufend)
|
||||
{
|
||||
_pdfio_strlcpy(bufptr, ">", (size_t)(bufend - bufptr + 1));
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
|
||||
bytes += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal character...
|
||||
if (bufptr < bufend)
|
||||
*bufptr++ = *s;
|
||||
bytes ++;
|
||||
}
|
||||
|
||||
s ++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S' : // PDF string
|
||||
if ((s = va_arg(ap, char *)) == NULL)
|
||||
s = "(null)";
|
||||
|
@ -172,7 +172,7 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||
// Copy the decrypted string back to the value and adjust the length...
|
||||
memcpy(v->value.binary.data, temp, templen);
|
||||
|
||||
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128)
|
||||
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128 && temp[templen - 1] <= templen)
|
||||
v->value.binary.datalen = templen - temp[templen - 1];
|
||||
else
|
||||
v->value.binary.datalen = templen;
|
||||
@ -183,20 +183,48 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||
case PDFIO_VALTYPE_STRING :
|
||||
// Decrypt regular string...
|
||||
templen = strlen(v->value.string);
|
||||
if (templen > (sizeof(temp) - 33))
|
||||
if (templen > (PDFIO_MAX_STRING - 1))
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted string - too long.");
|
||||
return (false);
|
||||
}
|
||||
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL)
|
||||
{
|
||||
_pdfioFileError(pdf, "Unable to read encrypted binary string - out of memory.");
|
||||
return (false);
|
||||
}
|
||||
|
||||
ivlen = templen;
|
||||
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, (uint8_t *)v->value.string, &ivlen)) == NULL)
|
||||
return (false);
|
||||
|
||||
templen = (cb)(&ctx, temp, (uint8_t *)v->value.string + ivlen, templen - ivlen);
|
||||
|
||||
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128 && temp[templen - 1] <= templen)
|
||||
templen -= temp[templen - 1];
|
||||
|
||||
temp[templen] = '\0';
|
||||
|
||||
if ((timeval = get_date_time((char *)temp)) != 0)
|
||||
if ((templen & 1) == 0 && (!memcmp(temp, "\376\377", 2) || !memcmp(temp, "\377\376", 2)))
|
||||
{
|
||||
// Convert UTF-16 to UTF-8...
|
||||
char utf8[4096]; // Temporary string
|
||||
|
||||
_pdfio_utf16cpy(utf8, temp, templen, sizeof(utf8));
|
||||
|
||||
if ((timeval = get_date_time((char *)utf8)) != 0)
|
||||
{
|
||||
// Change the type to date...
|
||||
v->type = PDFIO_VALTYPE_DATE;
|
||||
v->value.date = timeval;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the decrypted string back to the value...
|
||||
v->value.string = pdfioStringCreate(pdf, utf8);
|
||||
}
|
||||
}
|
||||
else if ((timeval = get_date_time((char *)temp)) != 0)
|
||||
{
|
||||
// Change the type to date...
|
||||
v->type = PDFIO_VALTYPE_DATE;
|
||||
@ -207,6 +235,8 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||
// Copy the decrypted string back to the value...
|
||||
v->value.string = pdfioStringCreate(pdf, (char *)temp);
|
||||
}
|
||||
|
||||
_pdfioStringFreeBuffer(pdf, (char *)temp);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -367,18 +397,22 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
||||
|
||||
ret = v;
|
||||
}
|
||||
else if ((timeval = get_date_time(token + 1)) != 0)
|
||||
{
|
||||
v->type = PDFIO_VALTYPE_DATE;
|
||||
v->value.date = timeval;
|
||||
ret = v;
|
||||
}
|
||||
else if (token[0] == '(')
|
||||
{
|
||||
// String
|
||||
v->type = PDFIO_VALTYPE_STRING;
|
||||
v->value.string = pdfioStringCreate(pdf, token + 1);
|
||||
ret = v;
|
||||
if ((timeval = get_date_time(token + 1)) != 0)
|
||||
{
|
||||
// Date
|
||||
v->type = PDFIO_VALTYPE_DATE;
|
||||
v->value.date = timeval;
|
||||
ret = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
// String
|
||||
v->type = PDFIO_VALTYPE_STRING;
|
||||
v->value.string = pdfioStringCreate(pdf, token + 1);
|
||||
ret = v;
|
||||
}
|
||||
}
|
||||
else if (token[0] == '/')
|
||||
{
|
||||
|
10
pdfio.h
10
pdfio.h
@ -23,9 +23,9 @@ extern "C" {
|
||||
// Version numbers...
|
||||
//
|
||||
|
||||
# define PDFIO_VERSION "1.5.2"
|
||||
# define PDFIO_VERSION "1.6.0"
|
||||
# define PDFIO_VERSION_MAJOR 1
|
||||
# define PDFIO_VERSION_MINOR 5
|
||||
# define PDFIO_VERSION_MINOR 6
|
||||
|
||||
|
||||
//
|
||||
@ -46,7 +46,7 @@ extern "C" {
|
||||
//
|
||||
|
||||
# if _WIN32
|
||||
typedef __int64 ssize_t; // POSIX type not present on Windows... @private@
|
||||
typedef __int64 ssize_t; // POSIX type not present on Windows @private@
|
||||
# endif // _WIN32
|
||||
|
||||
typedef struct _pdfio_array_s pdfio_array_t;
|
||||
@ -62,7 +62,7 @@ typedef bool (*pdfio_error_cb_t)(pdfio_file_t *pdf, const char *message, void *d
|
||||
typedef enum pdfio_encryption_e // PDF encryption modes
|
||||
{
|
||||
PDFIO_ENCRYPTION_NONE = 0, // No encryption
|
||||
PDFIO_ENCRYPTION_RC4_40, // 40-bit RC4 encryption (PDF 1.3)
|
||||
PDFIO_ENCRYPTION_RC4_40, // 40-bit RC4 encryption (PDF 1.3, reading only)
|
||||
PDFIO_ENCRYPTION_RC4_128, // 128-bit RC4 encryption (PDF 1.4)
|
||||
PDFIO_ENCRYPTION_AES_128, // 128-bit AES encryption (PDF 1.6)
|
||||
PDFIO_ENCRYPTION_AES_256 // 256-bit AES encryption (PDF 2.0) @exclude all@
|
||||
@ -201,6 +201,7 @@ extern time_t pdfioFileGetCreationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetCreator(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern pdfio_array_t *pdfioFileGetID(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetKeywords(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetLanguage(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern time_t pdfioFileGetModificationDate(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern const char *pdfioFileGetName(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
extern size_t pdfioFileGetNumObjs(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||
@ -217,6 +218,7 @@ extern void pdfioFileSetAuthor(pdfio_file_t *pdf, const char *value) _PDFIO_PUB
|
||||
extern void pdfioFileSetCreationDate(pdfio_file_t *pdf, time_t value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetCreator(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetKeywords(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetLanguage(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetModificationDate(pdfio_file_t *pdf, time_t value) _PDFIO_PUBLIC;
|
||||
extern bool pdfioFileSetPermissions(pdfio_file_t *pdf, pdfio_permission_t permissions, pdfio_encryption_t encryption, const char *owner_password, const char *user_password) _PDFIO_PUBLIC;
|
||||
extern void pdfioFileSetSubject(pdfio_file_t *pdf, const char *value) _PDFIO_PUBLIC;
|
||||
|
64
pdfio1.def
64
pdfio1.def
@ -1,20 +1,78 @@
|
||||
LIBRARY pdfio1
|
||||
VERSION 1.5
|
||||
VERSION 1.6
|
||||
EXPORTS
|
||||
_pdfioArrayDebug
|
||||
_pdfioArrayDecrypt
|
||||
_pdfioArrayDelete
|
||||
_pdfioArrayGetValue
|
||||
_pdfioArrayRead
|
||||
_pdfioArrayWrite
|
||||
_pdfioCryptoAESDecrypt
|
||||
_pdfioCryptoAESEncrypt
|
||||
_pdfioCryptoAESInit
|
||||
_pdfioCryptoLock
|
||||
_pdfioCryptoMD5Append
|
||||
_pdfioCryptoMD5Finish
|
||||
_pdfioCryptoMD5Init
|
||||
_pdfioCryptoMakeRandom
|
||||
_pdfioCryptoMakeReader
|
||||
_pdfioCryptoMakeWriter
|
||||
_pdfioCryptoRC4Crypt
|
||||
_pdfioCryptoRC4Init
|
||||
_pdfioCryptoSHA256Append
|
||||
_pdfioCryptoSHA256Finish
|
||||
_pdfioCryptoSHA256Init
|
||||
_pdfioCryptoUnlock
|
||||
_pdfioDictDebug
|
||||
_pdfioDictDecrypt
|
||||
_pdfioDictDelete
|
||||
_pdfioDictGetValue
|
||||
_pdfioDictRead
|
||||
_pdfioDictSetValue
|
||||
_pdfioDictWrite
|
||||
_pdfioFileAddMappedObj
|
||||
_pdfioFileAddPage
|
||||
_pdfioFileConsume
|
||||
_pdfioFileCreateObj
|
||||
_pdfioFileDefaultError
|
||||
_pdfioFileError
|
||||
_pdfioFileFindMappedObj
|
||||
_pdfioFileFlush
|
||||
_pdfioFileGetChar
|
||||
_pdfioFileGets
|
||||
_pdfioFilePeek
|
||||
_pdfioFilePrintf
|
||||
_pdfioFilePuts
|
||||
_pdfioFileRead
|
||||
_pdfioFileSeek
|
||||
_pdfioFileTell
|
||||
_pdfioFileWrite
|
||||
_pdfioObjDelete
|
||||
_pdfioObjGetExtension
|
||||
_pdfioObjLoad
|
||||
_pdfioObjSetExtension
|
||||
_pdfioObjWriteHeader
|
||||
_pdfioStreamCreate
|
||||
_pdfioStreamOpen
|
||||
_pdfioStringAllocBuffer
|
||||
_pdfioStringFreeBuffer
|
||||
_pdfioStringIsAllocated
|
||||
_pdfioTokenClear
|
||||
_pdfioTokenFlush
|
||||
_pdfioTokenGet
|
||||
_pdfioTokenInit
|
||||
_pdfioTokenPush
|
||||
_pdfioTokenRead
|
||||
_pdfioValueCopy
|
||||
_pdfioValueDebug
|
||||
_pdfioValueDecrypt
|
||||
_pdfioValueDelete
|
||||
_pdfioValueRead
|
||||
_pdfioValueWrite
|
||||
_pdfio_strlcpy
|
||||
_pdfio_strtod
|
||||
_pdfio_utf16cpy
|
||||
_pdfio_vsnprintf
|
||||
pdfioArrayAppendArray
|
||||
pdfioArrayAppendBinary
|
||||
pdfioArrayAppendBoolean
|
||||
@ -129,10 +187,12 @@ pdfioDictSetObj
|
||||
pdfioDictSetRect
|
||||
pdfioDictSetString
|
||||
pdfioDictSetStringf
|
||||
pdfioFileAddOutputIntent
|
||||
pdfioFileClose
|
||||
pdfioFileCreate
|
||||
pdfioFileCreateArrayObj
|
||||
pdfioFileCreateFontObjFromBase
|
||||
pdfioFileCreateFontObjFromData
|
||||
pdfioFileCreateFontObjFromFile
|
||||
pdfioFileCreateICCObjFromData
|
||||
pdfioFileCreateICCObjFromFile
|
||||
@ -152,6 +212,7 @@ pdfioFileGetCreationDate
|
||||
pdfioFileGetCreator
|
||||
pdfioFileGetID
|
||||
pdfioFileGetKeywords
|
||||
pdfioFileGetLanguage
|
||||
pdfioFileGetModificationDate
|
||||
pdfioFileGetName
|
||||
pdfioFileGetNumObjs
|
||||
@ -168,6 +229,7 @@ pdfioFileSetAuthor
|
||||
pdfioFileSetCreationDate
|
||||
pdfioFileSetCreator
|
||||
pdfioFileSetKeywords
|
||||
pdfioFileSetLanguage
|
||||
pdfioFileSetModificationDate
|
||||
pdfioFileSetPermissions
|
||||
pdfioFileSetSubject
|
||||
|
@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.5.2</version>
|
||||
<version>1.6.0</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
@ -16,7 +16,7 @@
|
||||
<copyright>Copyright © 2019-2025 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
<dependencies>
|
||||
<dependency id="pdfio_native.redist" version="1.5.2" />
|
||||
<dependency id="pdfio_native.redist" version="1.6.0" />
|
||||
<dependency id="libpng_native.redist" version="1.6.30" />
|
||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||
</dependencies>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native.redist</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.5.2</version>
|
||||
<version>1.6.0</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
|
39
test-corpus.sh
Executable file
39
test-corpus.sh
Executable file
@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Script to test PDFio against a directory of PDF files.
|
||||
#
|
||||
# Copyright © 2025 by Michael R Sweet.
|
||||
#
|
||||
# Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
# information.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ./test-corpus.sh DIRECTORY
|
||||
#
|
||||
|
||||
if test $# = 0; then
|
||||
echo "Usage: ./test-corpus.sh DIRECTORY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for file in $(find "$@" -name \*.pdf -print); do
|
||||
# Don't worry about test files containing MIME garbage...
|
||||
(head -4 $file | grep -q Content-Type) && continue;
|
||||
|
||||
# Or test files containing MacBinary garbage...
|
||||
(file $file | grep -q MacBinary) && continue;
|
||||
|
||||
# Don't worry about test files that Xpdf can't handle...
|
||||
pdfinfo $file >/dev/null 2>&1 || continue;
|
||||
|
||||
# Run testpdfio to test loading the file...
|
||||
./testpdfio $file >$file.log 2>&1
|
||||
if test $? = 0; then
|
||||
# Passed
|
||||
rm -f $file.log
|
||||
else
|
||||
# Failed, preserve log and write filename to stdout...
|
||||
echo $file
|
||||
fi
|
||||
done
|
282
test.h
Normal file
282
test.h
Normal file
@ -0,0 +1,282 @@
|
||||
//
|
||||
// Unit test header for C/C++ programs.
|
||||
//
|
||||
// Copyright © 2021-2025 by Michael R Sweet.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef TEST_H
|
||||
# define TEST_H
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdarg.h>
|
||||
# include <stdbool.h>
|
||||
# include <string.h>
|
||||
# if _WIN32
|
||||
# include <io.h>
|
||||
# define isatty(f) _isatty(f)
|
||||
# else
|
||||
# include <unistd.h>
|
||||
# endif // !_WIN32
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif // __cplusplus
|
||||
|
||||
|
||||
//
|
||||
// This header implements a simple unit test framework for C/C++ programs.
|
||||
// Inline functions are provided to write a test summary to stdout and the
|
||||
// details to stderr. This allows unit test programs to output a summary to
|
||||
// stdout with details sent to stderr, e.g.:
|
||||
//
|
||||
// mytestprogram 2>test.log
|
||||
//
|
||||
// Documentation:
|
||||
//
|
||||
// void testBegin(const char *title, ...)
|
||||
//
|
||||
// Start a test with a printf-style title message. "Title:" (the formatted
|
||||
// title followed by a colon) is output.
|
||||
//
|
||||
// void testEnd(bool pass)
|
||||
//
|
||||
// End a test without an additional message. "pass" should be `true` if the
|
||||
// test passed and `false` otherwise. "PASS" or "FAIL" is output.
|
||||
//
|
||||
// void testEndMessage(bool pass, const char *message, ...)
|
||||
//
|
||||
// End a test with an additional printf-style message. "pass" should be
|
||||
// `true` if the test passed and `false` otherwise. "PASS (message)" or
|
||||
// "FAIL (message)" is output.
|
||||
//
|
||||
// testError(const char *error, ...)
|
||||
//
|
||||
// Sends a formatted error string to stderr.
|
||||
//
|
||||
// testHexDump(const unsigned char *buffer, size_t bytes)
|
||||
//
|
||||
// Sends a hex dump of the specified buffer to stderr.
|
||||
//
|
||||
// testMessage(const char *error, ...)
|
||||
//
|
||||
// Outputs a formatted message string.
|
||||
//
|
||||
// testProgress(void)
|
||||
//
|
||||
// Shows a progress spinner for long-running tests.
|
||||
//
|
||||
// bool testsPassed
|
||||
//
|
||||
// This global variable specifies whether all tests have passed (`true`)
|
||||
// or one or more have failed (`false`).
|
||||
//
|
||||
|
||||
static bool testsPassed = true; // All tests passed?
|
||||
static int test_progress; // Current progress
|
||||
static char test_title[1024] = ""; // Current test title
|
||||
|
||||
|
||||
// Start a test
|
||||
static inline void
|
||||
testBegin(const char *title, ...) // I - printf-style title string
|
||||
{
|
||||
va_list ap; // Pointer to additional arguments
|
||||
|
||||
|
||||
// Format the title string
|
||||
va_start(ap, title);
|
||||
vsnprintf(test_title, sizeof(test_title), title, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Send the title to stdout and stderr...
|
||||
test_progress = 0;
|
||||
|
||||
printf("%s: ", test_title);
|
||||
fflush(stdout);
|
||||
|
||||
if (!isatty(2))
|
||||
fprintf(stderr, "%s: ", test_title);
|
||||
}
|
||||
|
||||
|
||||
// End a test with no additional information
|
||||
static inline void
|
||||
testEnd(bool pass) // I - `true` if the test passed, `false` otherwise
|
||||
{
|
||||
// Send the test result to stdout and stderr
|
||||
if (test_progress)
|
||||
putchar('\b');
|
||||
|
||||
if (!pass)
|
||||
testsPassed = false;
|
||||
|
||||
puts(pass ? "PASS" : "FAIL");
|
||||
if (!isatty(2))
|
||||
fputs(pass ? "PASS\n" : "FAIL\n", stderr);
|
||||
|
||||
test_title[0] = '\0';
|
||||
}
|
||||
|
||||
|
||||
// End a test with no additional information
|
||||
static inline void
|
||||
testEndMessage(bool pass, // I - `true` if the test passed, `false` otherwise
|
||||
const char *message, ...)// I - printf-style message
|
||||
{
|
||||
char buffer[1024]; // Formatted title string
|
||||
va_list ap; // Pointer to additional arguments
|
||||
|
||||
|
||||
// Format the title string
|
||||
va_start(ap, message);
|
||||
vsnprintf(buffer, sizeof(buffer), message, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Send the test result to stdout and stderr
|
||||
if (test_progress)
|
||||
putchar('\b');
|
||||
|
||||
printf(pass ? "PASS (%s)\n" : "FAIL (%s)\n", buffer);
|
||||
if (!isatty(2))
|
||||
fprintf(stderr, pass ? "PASS (%s)\n" : "FAIL (%s)\n", buffer);
|
||||
|
||||
test_title[0] = '\0';
|
||||
}
|
||||
|
||||
|
||||
// Show/update a progress spinner
|
||||
static inline void
|
||||
testProgress(void)
|
||||
{
|
||||
if (test_progress)
|
||||
putchar('\b');
|
||||
putchar("-\\|/"[test_progress & 3]);
|
||||
fflush(stdout);
|
||||
|
||||
test_progress ++;
|
||||
}
|
||||
|
||||
|
||||
// Show an error to stderr...
|
||||
static inline void
|
||||
testError(const char *error, ...) // I - printf-style error string
|
||||
{
|
||||
char buffer[1024]; // Formatted title string
|
||||
va_list ap; // Pointer to additional arguments
|
||||
|
||||
|
||||
// Format the error string
|
||||
va_start(ap, error);
|
||||
vsnprintf(buffer, sizeof(buffer), error, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Send the error to stderr...
|
||||
fprintf(stderr, "%s\n", buffer);
|
||||
|
||||
if (test_title[0])
|
||||
fprintf(stderr, "%s: ", test_title);
|
||||
}
|
||||
|
||||
|
||||
// Show a message to stdout and stderr...
|
||||
static inline void
|
||||
testMessage(const char *error, ...) // I - printf-style error string
|
||||
{
|
||||
char buffer[1024]; // Formatted title string
|
||||
va_list ap; // Pointer to additional arguments
|
||||
|
||||
|
||||
// Format the error string
|
||||
va_start(ap, error);
|
||||
vsnprintf(buffer, sizeof(buffer), error, ap);
|
||||
va_end(ap);
|
||||
|
||||
// Send the message to stdout and stderr too if needed...
|
||||
printf("%s\n", buffer);
|
||||
if (test_title[0])
|
||||
{
|
||||
printf("%s: ", test_title);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if (!isatty(2))
|
||||
{
|
||||
fprintf(stderr, "%s\n", buffer);
|
||||
|
||||
if (test_title[0])
|
||||
fprintf(stderr, "%s: ", test_title);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Show a hex dump of a buffer to stderr...
|
||||
static inline void
|
||||
testHexDump(const unsigned char *buffer,// I - Buffer
|
||||
size_t bytes) // I - Number of bytes
|
||||
{
|
||||
size_t i, j; // Looping vars
|
||||
int ch; // Current ASCII char
|
||||
|
||||
|
||||
if (test_title[0])
|
||||
fputs("\n", stderr);
|
||||
|
||||
// Show lines of 16 bytes at a time...
|
||||
for (i = 0; i < bytes; i += 16)
|
||||
{
|
||||
// Show the offset...
|
||||
fprintf(stderr, "%04x ", (unsigned)i);
|
||||
|
||||
// Then up to 16 bytes in hex...
|
||||
for (j = 0; j < 16; j ++)
|
||||
{
|
||||
if ((i + j) < bytes)
|
||||
fprintf(stderr, " %02x", buffer[i + j]);
|
||||
else
|
||||
fputs(" ", stderr);
|
||||
}
|
||||
|
||||
// Then the ASCII representation of the bytes...
|
||||
fputs(" ", stderr);
|
||||
|
||||
for (j = 0; j < 16 && (i + j) < bytes; j ++)
|
||||
{
|
||||
ch = buffer[i + j] & 127;
|
||||
|
||||
if (ch < ' ' || ch == 127)
|
||||
fputc('.', stderr);
|
||||
else
|
||||
fputc(ch, stderr);
|
||||
}
|
||||
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
if (test_title[0])
|
||||
fprintf(stderr, "%s: ", test_title);
|
||||
}
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif // __cplusplus
|
||||
#endif // !TEST_H
|
BIN
testfiles/CGATS001Compat-v2-micro.icc
Normal file
BIN
testfiles/CGATS001Compat-v2-micro.icc
Normal file
Binary file not shown.
5
testfiles/CGATS001Compat-v2-micro.txt
Normal file
5
testfiles/CGATS001Compat-v2-micro.txt
Normal file
@ -0,0 +1,5 @@
|
||||
https://github.com/saucecontrol/Compact-ICC-Profiles
|
||||
|
||||
All profiles in this collection are released to the public domain under the
|
||||
Creative Commons CC0 license. They are free from restrictions on distribution
|
||||
and use to the extent allowed by law.
|
1581
testpdfio.c
1581
testpdfio.c
File diff suppressed because it is too large
Load Diff
93
testttf.c
93
testttf.c
@ -3,7 +3,7 @@
|
||||
//
|
||||
// https://github.com/michaelrsweet/ttf
|
||||
//
|
||||
// Copyright © 2018-2024 by Michael R Sweet.
|
||||
// Copyright © 2018-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -14,6 +14,10 @@
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include "ttf.h"
|
||||
|
||||
|
||||
@ -81,9 +85,13 @@ test_font(const char *filename) // I - Font filename
|
||||
int i, // Looping var
|
||||
errors = 0; // Number of errors
|
||||
ttf_t *font; // Font
|
||||
struct stat fileinfo; // Font file information
|
||||
FILE *fp = NULL; // File pointer
|
||||
void *data = NULL; // Memory buffer for font file
|
||||
const char *value; // Font (string) value
|
||||
int intvalue; // Font (integer) value
|
||||
float realvalue; // Font (real) value
|
||||
char psname[1024]; // Postscript font name
|
||||
ttf_rect_t bounds; // Bounds
|
||||
ttf_rect_t extents; // Extents
|
||||
size_t num_fonts; // Number of fonts
|
||||
@ -220,6 +228,9 @@ test_font(const char *filename) // I - Font filename
|
||||
if ((value = ttfGetPostScriptName(font)) != NULL)
|
||||
{
|
||||
printf("PASS (%s)\n", value);
|
||||
|
||||
strncpy(psname, value, sizeof(psname) - 1);
|
||||
psname[sizeof(psname) - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -300,6 +311,86 @@ test_font(const char *filename) // I - Font filename
|
||||
puts("PASS (false)");
|
||||
|
||||
ttfDelete(font);
|
||||
font = NULL;
|
||||
|
||||
// Now copy the font to memory and open it that way...
|
||||
printf("fopen(\"%s\", \"rb\"): ", filename);
|
||||
if ((fp = fopen(filename, "rb")) == NULL)
|
||||
{
|
||||
printf("FAIL (%s)\n", strerror(errno));
|
||||
errors ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("PASS (%d)\n", fileno(fp));
|
||||
printf("fstat(%d): ", fileno(fp));
|
||||
if (fstat(fileno(fp), &fileinfo))
|
||||
{
|
||||
printf("FAIL (%s)\n", strerror(errno));
|
||||
errors ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("PASS (%lu bytes)\n", (unsigned long)fileinfo.st_size);
|
||||
|
||||
fputs("malloc(): ", stdout);
|
||||
if ((data = malloc((size_t)fileinfo.st_size)) == NULL)
|
||||
{
|
||||
printf("FAIL (%s)\n", strerror(errno));
|
||||
errors ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("PASS");
|
||||
fputs("fread(): ", stdout);
|
||||
if (fread(data, (size_t)fileinfo.st_size, 1, fp) != 1)
|
||||
{
|
||||
printf("FAIL (%s)\n", strerror(errno));
|
||||
errors ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("PASS");
|
||||
fputs("ttfCreateData(): ", stdout);
|
||||
if ((font = ttfCreateData(data, (size_t)fileinfo.st_size, /*idx*/0, error_cb, /*err_data*/NULL)) == NULL)
|
||||
{
|
||||
puts("FAIL");
|
||||
errors ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("PASS");
|
||||
|
||||
fputs("ttfGetPostScriptName: ", stdout);
|
||||
if ((value = ttfGetPostScriptName(font)) != NULL)
|
||||
{
|
||||
if (!strcmp(value, psname))
|
||||
{
|
||||
printf("PASS (%s)\n", value);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("FAIL (got \"%s\", expected \"%s\")\n", value, psname);
|
||||
errors ++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("FAIL");
|
||||
errors ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
|
||||
free(data);
|
||||
|
||||
ttfDelete(font);
|
||||
}
|
||||
|
||||
return (errors);
|
||||
}
|
||||
|
576
ttf.c
576
ttf.c
@ -10,7 +10,7 @@
|
||||
//
|
||||
|
||||
#ifdef _WIN32
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_WARNINGS 1
|
||||
#endif // _WIN32
|
||||
|
||||
#include "ttf.h"
|
||||
@ -38,16 +38,16 @@
|
||||
# define access _access
|
||||
# define close _close
|
||||
# define fileno _fileno
|
||||
# define lseek _lseek
|
||||
# define lseek(f,o,w) (off_t)_lseek((f),(long)(o),(w))
|
||||
# define mkdir(d,p) _mkdir(d)
|
||||
# define open _open
|
||||
# define read _read
|
||||
# define read(f,b,s) _read((f),(b),(unsigned)(s))
|
||||
# define rmdir _rmdir
|
||||
# define snprintf _snprintf
|
||||
# define strdup _strdup
|
||||
# define unlink _unlink
|
||||
# define vsnprintf _vsnprintf
|
||||
# define write _write
|
||||
# define write(f,b,s) _write((f),(b),(unsigned)(s))
|
||||
|
||||
//
|
||||
// Map various parameters for POSIX...
|
||||
@ -177,9 +177,19 @@ typedef struct _ttf_off_names_s // OFF/TTF naming table
|
||||
unsigned storage_size; // Size of storage area
|
||||
} _ttf_off_names_t;
|
||||
|
||||
typedef size_t (*_ttf_read_cb_t)(ttf_t *font, void *buffer, size_t bytes);
|
||||
// Font read callback, returns number of bytes read
|
||||
typedef bool (*_ttf_seek_cb_t)(ttf_t *font, size_t offset);
|
||||
// Font seek callback, returns `true` on success
|
||||
|
||||
struct _ttf_s
|
||||
{
|
||||
int fd; // File descriptor
|
||||
_ttf_read_cb_t read_cb; // Read callback
|
||||
_ttf_seek_cb_t seek_cb; // Seek callback
|
||||
int file_fd; // File descriptor for ttfCreate
|
||||
const char *data; // Font data for ttfCreateData
|
||||
size_t data_size; // Size of font data for ttfCreateData
|
||||
size_t data_offset; // Offset within input
|
||||
size_t idx; // Font number in file
|
||||
ttf_err_cb_t err_cb; // Error callback, if any
|
||||
void *err_data; // Error callback data
|
||||
@ -245,10 +255,10 @@ typedef struct _ttf_off_head_s // Font header
|
||||
} _ttf_off_head_t;
|
||||
|
||||
#define TTF_OFF_macStyle_Bold 0x01
|
||||
#define TTF_OFF_macStyle_Italic 0x02
|
||||
#define TTF_OFF_macStyle_Italic 0x02
|
||||
#define TTF_OFF_macStyle_Underline 0x04
|
||||
#define TTF_OFF_macStyle_Outline 0x08
|
||||
#define TTF_OFF_macStyle_Shadow 0x10
|
||||
#define TTF_OFF_macStyle_Shadow 0x10
|
||||
#define TTF_OFF_macStyle_Condensed 0x20
|
||||
#define TTF_OFF_macStyle_Extended 0x40
|
||||
|
||||
@ -282,7 +292,12 @@ typedef struct _ttf_off_post_s // PostScript information
|
||||
//
|
||||
|
||||
static char *copy_name(ttf_t *font, unsigned name_id);
|
||||
static ttf_t *create_font(const char *filename, const void *data, size_t datasize, size_t idx, ttf_err_cb_t err_cb, void *err_data);
|
||||
static void errorf(ttf_t *font, const char *message, ...) TTF_FORMAT_ARGS(2,3);
|
||||
static size_t fd_read_cb(ttf_t *font, void *buffer, size_t bytes);
|
||||
static bool fd_seek_cb(ttf_t *font, size_t offset);
|
||||
static size_t mem_read_cb(ttf_t *font, void *buffer, size_t bytes);
|
||||
static bool mem_seek_cb(ttf_t *font, size_t offset);
|
||||
static bool read_cmap(ttf_t *font);
|
||||
static bool read_head(ttf_t *font, _ttf_off_head_t *head);
|
||||
static bool read_hhea(ttf_t *font, _ttf_off_hhea_t *hhea);
|
||||
@ -329,15 +344,6 @@ ttfCreate(const char *filename, // I - Filename
|
||||
ttf_err_cb_t err_cb, // I - Error callback or `NULL` to log to stderr
|
||||
void *err_data) // I - Error callback data
|
||||
{
|
||||
ttf_t *font = NULL; // New font object
|
||||
size_t i; // Looping var
|
||||
_ttf_metric_t *widths = NULL; // Glyph metrics
|
||||
_ttf_off_head_t head; // head table
|
||||
_ttf_off_hhea_t hhea; // hhea table
|
||||
_ttf_off_os_2_t os_2; // OS/2 table
|
||||
_ttf_off_post_t post; // PostScript table
|
||||
|
||||
|
||||
TTF_DEBUG("ttfCreate(filename=\"%s\", idx=%u, err_cb=%p, err_data=%p)\n", filename, (unsigned)idx, err_cb, err_data);
|
||||
|
||||
// Range check input..
|
||||
@ -347,178 +353,57 @@ ttfCreate(const char *filename, // I - Filename
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
// Allocate memory...
|
||||
if ((font = (ttf_t *)calloc(1, sizeof(ttf_t))) == NULL)
|
||||
// Open and return the font...
|
||||
return (create_font(filename, /*data*/NULL, /*datasize*/0, idx, err_cb, err_data));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'ttfCreateData()' - Create a new font object from a memory buffer.
|
||||
//
|
||||
// This function creates a new font object from a memory buffer. The "data"
|
||||
// argument specifies a pointer to the first byte of data and the "datasize"
|
||||
// argument specifies the length of the memory buffer in bytes.
|
||||
//
|
||||
// > Note: The caller is responsible for ensuring that the memory buffer is
|
||||
// > available until the font object is deleted with @link ttfDelete@.
|
||||
//
|
||||
// The "idx" argument specifies the font to load from a collection - the first
|
||||
// font is number `0`. Once created, you can call the @link ttfGetNumFonts@
|
||||
// function to determine whether the loaded font file is a collection with more
|
||||
// than one font.
|
||||
//
|
||||
// The "err_cb" and "err_data" arguments specify a callback function and data
|
||||
// pointer for receiving error messages. If `NULL`, errors are sent to the
|
||||
// `stderr` file. The callback function receives the data pointer and a text
|
||||
// message string, for example:
|
||||
//
|
||||
// ```
|
||||
// void my_err_cb(void *err_data, const char *message)
|
||||
// {
|
||||
// fprintf(stderr, "ERROR: %s\n", message);
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
|
||||
ttf_t * // O - New font object
|
||||
ttfCreateData(const void *data, // I - Buffer
|
||||
size_t datasize, // I - Size of buffer in bytes
|
||||
size_t idx, // I - Font number to create in collection (0-based)
|
||||
ttf_err_cb_t err_cb, // I - Error callback or `NULL` to log to stderr
|
||||
void *err_data) // I - Error callback data
|
||||
{
|
||||
TTF_DEBUG("ttfCreateData(data=%p, datasize=%lu, idx=%u, err_cb=%p, err_data=%p)\n", data, (unsigned long)datasize, (unsigned)idx, err_cb, err_data);
|
||||
|
||||
// Range check input..
|
||||
if (!data || datasize == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
|
||||
font->idx = idx;
|
||||
font->err_cb = err_cb;
|
||||
font->err_data = err_data;
|
||||
|
||||
// Open the font file...
|
||||
if ((font->fd = open(filename, O_RDONLY | O_BINARY)) < 0)
|
||||
{
|
||||
errorf(font, "Unable to open '%s': %s", filename, strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
TTF_DEBUG("ttfCreate: fd=%d\n", font->fd);
|
||||
|
||||
// Read the table of contents and the identifying names...
|
||||
if (!read_table(font))
|
||||
goto error;
|
||||
|
||||
TTF_DEBUG("ttfCreate: num_entries=%d\n", font->table.num_entries);
|
||||
|
||||
if (!read_names(font))
|
||||
goto error;
|
||||
|
||||
TTF_DEBUG("ttfCreate: num_names=%d\n", font->names.num_names);
|
||||
|
||||
// Copy key font meta data strings...
|
||||
font->copyright = copy_name(font, TTF_OFF_Copyright);
|
||||
font->family = copy_name(font, TTF_OFF_FontFamily);
|
||||
font->postscript_name = copy_name(font, TTF_OFF_PostScriptName);
|
||||
font->version = copy_name(font, TTF_OFF_FontVersion);
|
||||
|
||||
if (read_post(font, &post))
|
||||
{
|
||||
font->italic_angle = post.italicAngle;
|
||||
font->is_fixed = post.isFixedPitch != 0;
|
||||
}
|
||||
|
||||
TTF_DEBUG("ttfCreate: copyright=\"%s\"\n", font->copyright);
|
||||
TTF_DEBUG("ttfCreate: family=\"%s\"\n", font->family);
|
||||
TTF_DEBUG("ttfCreate: postscript_name=\"%s\"\n", font->postscript_name);
|
||||
TTF_DEBUG("ttfCreate: version=\"%s\"\n", font->version);
|
||||
TTF_DEBUG("ttfCreate: italic_angle=%g\n", font->italic_angle);
|
||||
TTF_DEBUG("ttfCreate: is_fixed=%s\n", font->is_fixed ? "true" : "false");
|
||||
|
||||
if (!read_cmap(font))
|
||||
goto error;
|
||||
|
||||
if (!read_head(font, &head))
|
||||
goto error;
|
||||
|
||||
font->units = (float)head.unitsPerEm;
|
||||
font->x_max = head.xMax;
|
||||
font->x_min = head.xMin;
|
||||
font->y_max = head.yMax;
|
||||
font->y_min = head.yMin;
|
||||
|
||||
if (head.macStyle & TTF_OFF_macStyle_Italic)
|
||||
{
|
||||
if (font->postscript_name && strstr(font->postscript_name, "Oblique"))
|
||||
font->style = TTF_STYLE_OBLIQUE;
|
||||
else
|
||||
font->style = TTF_STYLE_ITALIC;
|
||||
}
|
||||
else
|
||||
font->style = TTF_STYLE_NORMAL;
|
||||
|
||||
if (!read_hhea(font, &hhea))
|
||||
goto error;
|
||||
|
||||
font->ascent = hhea.ascender;
|
||||
font->descent = hhea.descender;
|
||||
|
||||
if (read_maxp(font) < 0)
|
||||
goto error;
|
||||
|
||||
if (hhea.numberOfHMetrics > 0)
|
||||
{
|
||||
if ((widths = read_hmtx(font, &hhea)) == NULL)
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorf(font, "Number of horizontal metrics is 0.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (read_os_2(font, &os_2))
|
||||
{
|
||||
// Copy key values from OS/2 table...
|
||||
static const ttf_stretch_t stretches[] =
|
||||
{
|
||||
TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed
|
||||
TTF_STRETCH_EXTRA_CONDENSED, // extra-condensed
|
||||
TTF_STRETCH_CONDENSED, // condensed
|
||||
TTF_STRETCH_SEMI_CONDENSED, // semi-condensed
|
||||
TTF_STRETCH_NORMAL, // normal
|
||||
TTF_STRETCH_SEMI_EXPANDED, // semi-expanded
|
||||
TTF_STRETCH_EXPANDED, // expanded
|
||||
TTF_STRETCH_EXTRA_EXPANDED, // extra-expanded
|
||||
TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded
|
||||
};
|
||||
|
||||
if (os_2.usWidthClass >= 1 && os_2.usWidthClass <= (int)(sizeof(stretches) / sizeof(stretches[0])))
|
||||
font->stretch = stretches[os_2.usWidthClass - 1];
|
||||
|
||||
font->weight = (short)os_2.usWeightClass;
|
||||
font->cap_height = os_2.sCapHeight;
|
||||
font->x_height = os_2.sxHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default key values since there isn't an OS/2 table...
|
||||
TTF_DEBUG("ttfCreate: Unable to read OS/2 table.\n");
|
||||
|
||||
font->weight = 400;
|
||||
}
|
||||
|
||||
if (font->cap_height == 0)
|
||||
font->cap_height = font->ascent;
|
||||
|
||||
if (font->x_height == 0)
|
||||
font->x_height = 3 * font->ascent / 5;
|
||||
|
||||
// Build a sparse glyph widths table...
|
||||
font->min_char = -1;
|
||||
|
||||
for (i = 0; i < font->num_cmap; i ++)
|
||||
{
|
||||
if (font->cmap[i] >= 0)
|
||||
{
|
||||
int bin = (int)i / 256, // Sub-array bin
|
||||
glyph = font->cmap[i]; // Glyph index
|
||||
|
||||
// Update min/max...
|
||||
if (font->min_char < 0)
|
||||
font->min_char = (int)i;
|
||||
|
||||
font->max_char = (int)i;
|
||||
|
||||
// Allocate a sub-array as needed...
|
||||
if (!font->widths[bin])
|
||||
font->widths[bin] = (_ttf_metric_t *)calloc(256, sizeof(_ttf_metric_t));
|
||||
|
||||
// Copy the width of the specified glyph or the last one if we are past
|
||||
// the end of the table...
|
||||
if (glyph >= hhea.numberOfHMetrics)
|
||||
font->widths[bin][i & 255] = widths[hhea.numberOfHMetrics - 1];
|
||||
else
|
||||
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...
|
||||
free(widths);
|
||||
|
||||
return (font);
|
||||
|
||||
// If we get here something bad happened...
|
||||
error:
|
||||
|
||||
free(widths);
|
||||
ttfDelete(font);
|
||||
|
||||
return (NULL);
|
||||
// Open and return the font...
|
||||
return (create_font(/*filename*/NULL, data, datasize, idx, err_cb, err_data));
|
||||
}
|
||||
|
||||
|
||||
@ -537,8 +422,8 @@ ttfDelete(ttf_t *font) // I - Font
|
||||
return;
|
||||
|
||||
// Close the font file...
|
||||
if (font->fd >= 0)
|
||||
close(font->fd);
|
||||
if (font->file_fd >= 0)
|
||||
close(font->file_fd);
|
||||
|
||||
// Free all memory used...
|
||||
free(font->copyright);
|
||||
@ -1043,6 +928,219 @@ copy_name(ttf_t *font, // I - Font
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'create_font()' - Create a font object from the file or data.
|
||||
//
|
||||
|
||||
static ttf_t *
|
||||
create_font(const char *filename, // I - Filename of `NULL`
|
||||
const void *data, // I - Data pointer or `NULL`
|
||||
size_t datasize, // I - Size of data or 0
|
||||
size_t idx, // I - Font index
|
||||
ttf_err_cb_t err_cb, // I - Error callback function
|
||||
void *err_data) // I - Error callback data
|
||||
{
|
||||
ttf_t *font = NULL; // New font object
|
||||
size_t i; // Looping var
|
||||
_ttf_metric_t *widths = NULL; // Glyph metrics
|
||||
_ttf_off_head_t head; // head table
|
||||
_ttf_off_hhea_t hhea; // hhea table
|
||||
_ttf_off_os_2_t os_2; // OS/2 table
|
||||
_ttf_off_post_t post; // PostScript table
|
||||
|
||||
|
||||
TTF_DEBUG("create_font(filename=\"%s\", data=%p, datasize=%lu, idx=%u, err_cb=%p, err_data=%p)\n", filename, data, (unsigned long)datasize, (unsigned)idx, err_cb, err_data);
|
||||
|
||||
// Allocate memory...
|
||||
if ((font = (ttf_t *)calloc(1, sizeof(ttf_t))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
font->idx = idx;
|
||||
font->err_cb = err_cb;
|
||||
font->err_data = err_data;
|
||||
|
||||
if (filename)
|
||||
{
|
||||
// Open the font file...
|
||||
if ((font->file_fd = open(filename, O_RDONLY | O_BINARY)) < 0)
|
||||
{
|
||||
errorf(font, "Unable to open '%s': %s", filename, strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
TTF_DEBUG("create_font: file_fd=%d\n", font->file_fd);
|
||||
|
||||
font->read_cb = fd_read_cb;
|
||||
font->seek_cb = fd_seek_cb;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read from memory...
|
||||
font->file_fd = -1;
|
||||
font->data = (const char *)data;
|
||||
font->data_size = datasize;
|
||||
font->read_cb = mem_read_cb;
|
||||
font->seek_cb = mem_seek_cb;
|
||||
}
|
||||
|
||||
// Read the table of contents and the identifying names...
|
||||
if (!read_table(font))
|
||||
goto error;
|
||||
|
||||
TTF_DEBUG("create_font: num_entries=%d\n", font->table.num_entries);
|
||||
|
||||
if (!read_names(font))
|
||||
goto error;
|
||||
|
||||
TTF_DEBUG("create_font: num_names=%d\n", font->names.num_names);
|
||||
|
||||
// Copy key font meta data strings...
|
||||
font->copyright = copy_name(font, TTF_OFF_Copyright);
|
||||
font->family = copy_name(font, TTF_OFF_FontFamily);
|
||||
font->postscript_name = copy_name(font, TTF_OFF_PostScriptName);
|
||||
font->version = copy_name(font, TTF_OFF_FontVersion);
|
||||
|
||||
if (read_post(font, &post))
|
||||
{
|
||||
font->italic_angle = post.italicAngle;
|
||||
font->is_fixed = post.isFixedPitch != 0;
|
||||
}
|
||||
|
||||
TTF_DEBUG("create_font: copyright=\"%s\"\n", font->copyright);
|
||||
TTF_DEBUG("create_font: family=\"%s\"\n", font->family);
|
||||
TTF_DEBUG("create_font: postscript_name=\"%s\"\n", font->postscript_name);
|
||||
TTF_DEBUG("create_font: version=\"%s\"\n", font->version);
|
||||
TTF_DEBUG("create_font: italic_angle=%g\n", font->italic_angle);
|
||||
TTF_DEBUG("create_font: is_fixed=%s\n", font->is_fixed ? "true" : "false");
|
||||
|
||||
if (!read_cmap(font))
|
||||
goto error;
|
||||
|
||||
if (!read_head(font, &head))
|
||||
goto error;
|
||||
|
||||
font->units = (float)head.unitsPerEm;
|
||||
font->x_max = head.xMax;
|
||||
font->x_min = head.xMin;
|
||||
font->y_max = head.yMax;
|
||||
font->y_min = head.yMin;
|
||||
|
||||
if (head.macStyle & TTF_OFF_macStyle_Italic)
|
||||
{
|
||||
if (font->postscript_name && strstr(font->postscript_name, "Oblique"))
|
||||
font->style = TTF_STYLE_OBLIQUE;
|
||||
else
|
||||
font->style = TTF_STYLE_ITALIC;
|
||||
}
|
||||
else
|
||||
font->style = TTF_STYLE_NORMAL;
|
||||
|
||||
if (!read_hhea(font, &hhea))
|
||||
goto error;
|
||||
|
||||
font->ascent = hhea.ascender;
|
||||
font->descent = hhea.descender;
|
||||
|
||||
if (read_maxp(font) < 0)
|
||||
goto error;
|
||||
|
||||
if (hhea.numberOfHMetrics > 0)
|
||||
{
|
||||
if ((widths = read_hmtx(font, &hhea)) == NULL)
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorf(font, "Number of horizontal metrics is 0.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (read_os_2(font, &os_2))
|
||||
{
|
||||
// Copy key values from OS/2 table...
|
||||
static const ttf_stretch_t stretches[] =
|
||||
{
|
||||
TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed
|
||||
TTF_STRETCH_EXTRA_CONDENSED, // extra-condensed
|
||||
TTF_STRETCH_CONDENSED, // condensed
|
||||
TTF_STRETCH_SEMI_CONDENSED, // semi-condensed
|
||||
TTF_STRETCH_NORMAL, // normal
|
||||
TTF_STRETCH_SEMI_EXPANDED, // semi-expanded
|
||||
TTF_STRETCH_EXPANDED, // expanded
|
||||
TTF_STRETCH_EXTRA_EXPANDED, // extra-expanded
|
||||
TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded
|
||||
};
|
||||
|
||||
if (os_2.usWidthClass >= 1 && os_2.usWidthClass <= (int)(sizeof(stretches) / sizeof(stretches[0])))
|
||||
font->stretch = stretches[os_2.usWidthClass - 1];
|
||||
|
||||
font->weight = (short)os_2.usWeightClass;
|
||||
font->cap_height = os_2.sCapHeight;
|
||||
font->x_height = os_2.sxHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default key values since there isn't an OS/2 table...
|
||||
TTF_DEBUG("create_font: Unable to read OS/2 table.\n");
|
||||
|
||||
font->weight = 400;
|
||||
}
|
||||
|
||||
if (font->cap_height == 0)
|
||||
font->cap_height = font->ascent;
|
||||
|
||||
if (font->x_height == 0)
|
||||
font->x_height = 3 * font->ascent / 5;
|
||||
|
||||
// Build a sparse glyph widths table...
|
||||
font->min_char = -1;
|
||||
|
||||
for (i = 0; i < font->num_cmap; i ++)
|
||||
{
|
||||
if (font->cmap[i] >= 0)
|
||||
{
|
||||
int bin = (int)i / 256, // Sub-array bin
|
||||
glyph = font->cmap[i]; // Glyph index
|
||||
|
||||
// Update min/max...
|
||||
if (font->min_char < 0)
|
||||
font->min_char = (int)i;
|
||||
|
||||
font->max_char = (int)i;
|
||||
|
||||
// Allocate a sub-array as needed...
|
||||
if (!font->widths[bin])
|
||||
font->widths[bin] = (_ttf_metric_t *)calloc(256, sizeof(_ttf_metric_t));
|
||||
|
||||
// Copy the width of the specified glyph or the last one if we are past
|
||||
// the end of the table...
|
||||
if (glyph >= hhea.numberOfHMetrics)
|
||||
font->widths[bin][i & 255] = widths[hhea.numberOfHMetrics - 1];
|
||||
else
|
||||
font->widths[bin][i & 255] = widths[glyph];
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (i >= ' ' && i < 127 && font->widths[0])
|
||||
TTF_DEBUG("create_font: 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...
|
||||
free(widths);
|
||||
|
||||
return (font);
|
||||
|
||||
// If we get here something bad happened...
|
||||
error:
|
||||
|
||||
free(widths);
|
||||
ttfDelete(font);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'errorf()' - Show an error message.
|
||||
//
|
||||
@ -1070,9 +1168,85 @@ errorf(ttf_t *font, // I - Font
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 'read_cmap()' - Read the cmap table, getting the Unicode mapping table.
|
||||
*/
|
||||
//
|
||||
// 'fd_read_cb()' - Read from a file.
|
||||
//
|
||||
|
||||
static size_t // O - Number of bytes read
|
||||
fd_read_cb(ttf_t *font, // I - Font
|
||||
void *buffer, // I - Read buffer
|
||||
size_t bytes) // I - Number of bytes to read
|
||||
{
|
||||
ssize_t rbytes; // Bytes read
|
||||
|
||||
|
||||
if ((rbytes = read(font->file_fd, buffer, bytes)) < 0)
|
||||
return (0);
|
||||
|
||||
return ((size_t)rbytes);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'fd_seek_cb()' - Seek in a file.
|
||||
//
|
||||
|
||||
static bool // O - `true` on success, `false` on failure
|
||||
fd_seek_cb(ttf_t *font, // I - Font
|
||||
size_t offset) // I - Offset in data
|
||||
{
|
||||
return (lseek(font->file_fd, offset, SEEK_SET) == offset);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'mem_read_cb()' - Read from a memory buffer.
|
||||
//
|
||||
|
||||
static size_t // O - Number of bytes read
|
||||
mem_read_cb(ttf_t *font, // I - Font
|
||||
void *buffer, // I - Read buffer
|
||||
size_t bytes) // I - Number of bytes to read
|
||||
{
|
||||
size_t rbytes; // Bytes to copy
|
||||
|
||||
|
||||
if (font->data_offset >= font->data_size)
|
||||
return (0);
|
||||
|
||||
if ((rbytes = font->data_size - font->data_offset) > bytes)
|
||||
rbytes = bytes;
|
||||
|
||||
memcpy(buffer, font->data + font->data_offset, rbytes);
|
||||
font->data_offset += rbytes;
|
||||
|
||||
return (rbytes);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'mem_seek_cb()' - Seek in a memory buffer.
|
||||
//
|
||||
|
||||
static bool // O - `true` on success, `false` on error
|
||||
mem_seek_cb(ttf_t *font, // I - Font
|
||||
size_t offset) // I - Offset in data
|
||||
{
|
||||
if (offset >= font->data_size)
|
||||
{
|
||||
errno = ENXIO;
|
||||
return (false);
|
||||
}
|
||||
|
||||
font->data_offset = offset;
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'read_cmap()' - Read the cmap table, getting the Unicode mapping table.
|
||||
//
|
||||
|
||||
static bool // O - `true` on success, `false` on error
|
||||
read_cmap(ttf_t *font) // I - Font
|
||||
@ -1219,7 +1393,7 @@ read_cmap(ttf_t *font) // I - Font
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (read(font->fd, bmap, font->num_cmap) != (ssize_t)font->num_cmap)
|
||||
if ((font->read_cb)(font, bmap, font->num_cmap) != font->num_cmap)
|
||||
{
|
||||
errorf(font, "Unable to read cmap table length at offset %u.", coffset);
|
||||
return (false);
|
||||
@ -1646,9 +1820,9 @@ read_hhea(ttf_t *font, // I - Font
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 'read_hmtx()' - Read the horizontal metrics from the font.
|
||||
*/
|
||||
//
|
||||
// 'read_hmtx()' - Read the horizontal metrics from the font.
|
||||
//
|
||||
|
||||
static _ttf_metric_t * // O - Array of glyph metrics
|
||||
read_hmtx(ttf_t *font, // I - Font
|
||||
@ -1774,7 +1948,7 @@ read_names(ttf_t *font) // I - Font
|
||||
|
||||
length -= (unsigned)offset;
|
||||
|
||||
if (read(font->fd, font->names.storage, length) < 0)
|
||||
if ((font->read_cb)(font, font->names.storage, length) == 0)
|
||||
{
|
||||
errorf(font, "Unable to read name table: %s", strerror(errno));
|
||||
return (false);
|
||||
@ -1823,7 +1997,7 @@ read_os_2(ttf_t *font, // I - Font
|
||||
/* yStrikeoutOffset */ read_short(font);
|
||||
/* sFamilyClass */ read_short(font);
|
||||
/* panose[10] */
|
||||
if (read(font->fd, panose, sizeof(panose)) != (ssize_t)sizeof(panose))
|
||||
if ((font->read_cb)(font, panose, sizeof(panose)) != sizeof(panose))
|
||||
return (false);
|
||||
/* ulUnicodeRange1 */ read_ulong(font);
|
||||
/* ulUnicodeRange2 */ read_ulong(font);
|
||||
@ -1885,7 +2059,7 @@ read_short(ttf_t *font) // I - Font
|
||||
unsigned char buffer[2]; // Read buffer
|
||||
|
||||
|
||||
if (read(font->fd, buffer, sizeof(buffer)) != sizeof(buffer))
|
||||
if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer))
|
||||
return (EOF);
|
||||
else if (buffer[0] & 0x80)
|
||||
return (((buffer[0] << 8) | buffer[1]) - 65536);
|
||||
@ -1958,7 +2132,7 @@ read_table(ttf_t *font) // I - Font
|
||||
|
||||
TTF_DEBUG("read_table: Offset for font %u is %u.\n", (unsigned)font->idx, temp);
|
||||
|
||||
if (lseek(font->fd, temp + 4, SEEK_SET) < 0)
|
||||
if (!(font->seek_cb)(font, temp + 4))
|
||||
{
|
||||
errorf(font, "Unable to seek to font %u: %s", (unsigned)font->idx, strerror(errno));
|
||||
return (false);
|
||||
@ -2034,7 +2208,7 @@ read_ulong(ttf_t *font) // I - Font
|
||||
unsigned char buffer[4]; // Read buffer
|
||||
|
||||
|
||||
if (read(font->fd, buffer, sizeof(buffer)) != sizeof(buffer))
|
||||
if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer))
|
||||
return ((unsigned)EOF);
|
||||
else
|
||||
return ((unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]));
|
||||
@ -2051,7 +2225,7 @@ read_ushort(ttf_t *font) // I - Font
|
||||
unsigned char buffer[2]; // Read buffer
|
||||
|
||||
|
||||
if (read(font->fd, buffer, sizeof(buffer)) != sizeof(buffer))
|
||||
if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer))
|
||||
return (EOF);
|
||||
else
|
||||
return ((buffer[0] << 8) | buffer[1]);
|
||||
@ -2078,7 +2252,7 @@ seek_table(ttf_t *font, // I - Font
|
||||
if (current->tag == tag)
|
||||
{
|
||||
// Found it, seek and return...
|
||||
if (lseek(font->fd, current->offset + offset, SEEK_SET) == (current->offset + offset))
|
||||
if ((font->seek_cb)(font, current->offset + offset))
|
||||
{
|
||||
// Successful seek...
|
||||
return (current->length - offset);
|
||||
|
3
ttf.h
3
ttf.h
@ -3,7 +3,7 @@
|
||||
//
|
||||
// https://github.com/michaelrsweet/ttf
|
||||
//
|
||||
// Copyright © 2018-2024 by Michael R Sweet.
|
||||
// Copyright © 2018-2025 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -81,6 +81,7 @@ typedef struct ttf_rect_s // Bounding rectangle
|
||||
//
|
||||
|
||||
extern ttf_t *ttfCreate(const char *filename, size_t idx, ttf_err_cb_t err_cb, void *err_data);
|
||||
extern ttf_t *ttfCreateData(const void *data, size_t data_size, size_t idx, ttf_err_cb_t err_cb, void *err_data);
|
||||
extern void ttfDelete(ttf_t *font);
|
||||
extern int ttfGetAscent(ttf_t *font);
|
||||
extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds);
|
||||
|
Loading…
x
Reference in New Issue
Block a user