mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-07-20 07:49:53 +02:00
Compare commits
10 Commits
2b92044504
...
v1.2.0
Author | SHA1 | Date | |
---|---|---|---|
cd1406e158 | |||
59deee020a | |||
476013706e | |||
a43a9d9e32 | |||
abc69b3361 | |||
83bfb135c6 | |||
2dfb560f8b | |||
7330cc35ba | |||
5d760e7315 | |||
2a85baaf81 |
10
CHANGES.md
10
CHANGES.md
@ -2,19 +2,23 @@ Changes in PDFio
|
|||||||
================
|
================
|
||||||
|
|
||||||
|
|
||||||
v1.2.0 (Month DD, YYYY)
|
v1.2.0 (January 24, 2024)
|
||||||
-----------------------
|
-------------------------
|
||||||
|
|
||||||
|
- Now use autoconf to configure the PDFio sources (Issue #54)
|
||||||
- Added `pdfioFileCreateNumberObj` and `pdfioFileCreateStringObj` functions
|
- Added `pdfioFileCreateNumberObj` and `pdfioFileCreateStringObj` functions
|
||||||
(Issue #14)
|
(Issue #14)
|
||||||
- Added `pdfioContentTextMeasure` function (Issue #17)
|
- Added `pdfioContentTextMeasure` function (Issue #17)
|
||||||
- Added `pdfioContentTextNewLineShow` and `pdfioContentTextNewLineShowf`
|
- Added `pdfioContentTextNewLineShow` and `pdfioContentTextNewLineShowf`
|
||||||
functions (Issue #24)
|
functions (Issue #24)
|
||||||
- Renamed `pdfioContentTextNextLine` to `pdfioContentTextNewLine`.
|
- Renamed `pdfioContentTextNextLine` to `pdfioContentTextNewLine`.
|
||||||
- Now use autoconf to configure the PDFio sources (Issue #54)
|
- Updated the maximum number of object streams in a single file from 4096 to
|
||||||
|
8192 (Issue #58)
|
||||||
- Updated the token reading code to protect against some obvious abuses of the
|
- Updated the token reading code to protect against some obvious abuses of the
|
||||||
PDF format.
|
PDF format.
|
||||||
- Updated the xref reading code to protect against loops.
|
- Updated the xref reading code to protect against loops.
|
||||||
|
- Updated the object handling code to use a binary insertion algorithm -
|
||||||
|
provides a significant (~800x) improvement in open times.
|
||||||
- Fixed handling of encrypted PDFs with per-object file IDs (Issue #42)
|
- Fixed handling of encrypted PDFs with per-object file IDs (Issue #42)
|
||||||
- Fixed handling of of trailer dictionaries that started immediately after the
|
- Fixed handling of of trailer dictionaries that started immediately after the
|
||||||
"trailer" keyword (Issue #58)
|
"trailer" keyword (Issue #58)
|
||||||
|
@ -172,6 +172,7 @@ valgrind: testpdfio
|
|||||||
# pdfio library
|
# pdfio library
|
||||||
libpdfio.a: $(LIBOBJS)
|
libpdfio.a: $(LIBOBJS)
|
||||||
echo Archiving $@...
|
echo Archiving $@...
|
||||||
|
$(RM) $@
|
||||||
$(AR) $(ARFLAGS) $@ $(LIBOBJS)
|
$(AR) $(ARFLAGS) $@ $(LIBOBJS)
|
||||||
$(RANLIB) $@
|
$(RANLIB) $@
|
||||||
|
|
||||||
@ -226,7 +227,7 @@ ttf.o: ttf.h
|
|||||||
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
||||||
DOCFLAGS = \
|
DOCFLAGS = \
|
||||||
--author "Michael R Sweet" \
|
--author "Michael R Sweet" \
|
||||||
--copyright "Copyright (c) 2021-2023 by Michael R Sweet" \
|
--copyright "Copyright (c) 2021-2024 by Michael R Sweet" \
|
||||||
--docversion $(PDFIO_VERSION)
|
--docversion $(PDFIO_VERSION)
|
||||||
|
|
||||||
.PHONY: doc
|
.PHONY: doc
|
||||||
|
2
NOTICE
2
NOTICE
@ -1,6 +1,6 @@
|
|||||||
PDFio - PDF Read/Write Library
|
PDFio - PDF Read/Write Library
|
||||||
|
|
||||||
Copyright © 2021-2023 by Michael R Sweet.
|
Copyright © 2021-2024 by Michael R Sweet.
|
||||||
|
|
||||||
(Optional) Exceptions to the Apache 2.0 License:
|
(Optional) Exceptions to the Apache 2.0 License:
|
||||||
================================================
|
================================================
|
||||||
|
@ -89,7 +89,7 @@ generates a static library that will be installed under "/usr/local" with:
|
|||||||
Legal Stuff
|
Legal Stuff
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
PDFio is Copyright © 2021-2023 by Michael R Sweet.
|
PDFio is Copyright © 2021-2024 by Michael R Sweet.
|
||||||
|
|
||||||
This software is licensed under the Apache License Version 2.0 with an
|
This software is licensed under the Apache License Version 2.0 with an
|
||||||
(optional) exception to allow linking against GPL2/LGPL2 software. See the
|
(optional) exception to allow linking against GPL2/LGPL2 software. See the
|
||||||
|
@ -54,7 +54,7 @@ starting at 0. A feature release has a "PATCH" value of 0, for example:
|
|||||||
1.1.0
|
1.1.0
|
||||||
2.0.0
|
2.0.0
|
||||||
|
|
||||||
Beta releases and release candidates are *not* prodution releases and use
|
Beta releases and release candidates are *not* production releases and use
|
||||||
semantic version numbers of the form:
|
semantic version numbers of the form:
|
||||||
|
|
||||||
MAJOR.MINORbNUMBER
|
MAJOR.MINORbNUMBER
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
dnl
|
dnl
|
||||||
dnl Configuration script for PDFio
|
dnl Configuration script for PDFio
|
||||||
dnl
|
dnl
|
||||||
dnl Copyright © 2023 by Michael R Sweet
|
dnl Copyright © 2023-2024 by Michael R Sweet
|
||||||
dnl
|
dnl
|
||||||
dnl Licensed under Apache License v2.0. See the file "LICENSE" for more
|
dnl Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
dnl information.
|
dnl information.
|
||||||
@ -105,8 +105,8 @@ dnl ZLIB
|
|||||||
AC_MSG_CHECKING([for zlib via pkg-config])
|
AC_MSG_CHECKING([for zlib via pkg-config])
|
||||||
AS_IF([$PKGCONFIG --exists zlib], [
|
AS_IF([$PKGCONFIG --exists zlib], [
|
||||||
AC_MSG_RESULT([yes])
|
AC_MSG_RESULT([yes])
|
||||||
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
|
||||||
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
|
||||||
|
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
|
||||||
],[
|
],[
|
||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
AC_CHECK_HEADER([zlib.h])
|
AC_CHECK_HEADER([zlib.h])
|
||||||
@ -116,6 +116,7 @@ AS_IF([$PKGCONFIG --exists zlib], [
|
|||||||
AC_MSG_ERROR([Sorry, this software requires zlib 1.1 or higher.])
|
AC_MSG_ERROR([Sorry, this software requires zlib 1.1 or higher.])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
PKGCONFIG_REQUIRES=""
|
||||||
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
|
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.TH pdfio 3 "pdf read/write library" "2023-12-05" "pdf read/write library"
|
.TH pdfio 3 "pdf read/write library" "2024-01-24" "pdf read/write library"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
pdfio \- pdf read/write library
|
pdfio \- pdf read/write library
|
||||||
.SH Introduction
|
.SH Introduction
|
||||||
@ -34,7 +34,7 @@ PDFio is
|
|||||||
.I not
|
.I not
|
||||||
concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.
|
concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.
|
||||||
.PP
|
.PP
|
||||||
PDFio is Copyright \[co] 2021\-2023 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
PDFio is Copyright \[co] 2021\-2024 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
||||||
.SS Requirements
|
.SS Requirements
|
||||||
.PP
|
.PP
|
||||||
PDFio requires the following to build the software:
|
PDFio requires the following to build the software:
|
||||||
@ -3087,4 +3087,4 @@ typedef enum pdfio_valtype_e pdfio_valtype_t;
|
|||||||
Michael R Sweet
|
Michael R Sweet
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
.PP
|
.PP
|
||||||
Copyright (c) 2021-2023 by Michael R Sweet
|
Copyright (c) 2021-2024 by Michael R Sweet
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<meta name="generator" content="codedoc v3.7">
|
<meta name="generator" content="codedoc v3.7">
|
||||||
<meta name="author" content="Michael R Sweet">
|
<meta name="author" content="Michael R Sweet">
|
||||||
<meta name="language" content="en-US">
|
<meta name="language" content="en-US">
|
||||||
<meta name="copyright" content="Copyright © 2021-2023 by Michael R Sweet">
|
<meta name="copyright" content="Copyright © 2021-2024 by Michael R Sweet">
|
||||||
<meta name="version" content="1.2.0">
|
<meta name="version" content="1.2.0">
|
||||||
<style type="text/css"><!--
|
<style type="text/css"><!--
|
||||||
body {
|
body {
|
||||||
@ -247,7 +247,7 @@ span.string {
|
|||||||
<p><img class="title" src="pdfio-512.png"></p>
|
<p><img class="title" src="pdfio-512.png"></p>
|
||||||
<h1 class="title">PDFio Programming Manual v1.2.0</h1>
|
<h1 class="title">PDFio Programming Manual v1.2.0</h1>
|
||||||
<p>Michael R Sweet</p>
|
<p>Michael R Sweet</p>
|
||||||
<p>Copyright © 2021-2023 by Michael R Sweet</p>
|
<p>Copyright © 2021-2024 by Michael R Sweet</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="contents">
|
<div class="contents">
|
||||||
<h2 class="title">Contents</h2>
|
<h2 class="title">Contents</h2>
|
||||||
@ -501,7 +501,7 @@ span.string {
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>PDFio is <em>not</em> concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.</p>
|
<p>PDFio is <em>not</em> concerned with rendering or viewing a PDF file, although a PDF RIP or viewer could be written using it.</p>
|
||||||
<p>PDFio is Copyright © 2021-2023 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.</p>
|
<p>PDFio is Copyright © 2021-2024 by Michael R Sweet and is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.</p>
|
||||||
<h3 class="title" id="requirements">Requirements</h3>
|
<h3 class="title" id="requirements">Requirements</h3>
|
||||||
<p>PDFio requires the following to build the software:</p>
|
<p>PDFio requires the following to build the software:</p>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -15,7 +15,7 @@ goals of pdfio are:
|
|||||||
PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF
|
PDFio is *not* concerned with rendering or viewing a PDF file, although a PDF
|
||||||
RIP or viewer could be written using it.
|
RIP or viewer could be written using it.
|
||||||
|
|
||||||
PDFio is Copyright © 2021-2023 by Michael R Sweet and is licensed under the
|
PDFio is Copyright © 2021-2024 by Michael R Sweet and is licensed under the
|
||||||
Apache License Version 2.0 with an (optional) exception to allow linking against
|
Apache License Version 2.0 with an (optional) exception to allow linking against
|
||||||
GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
GPL2/LGPL2 software. See the files "LICENSE" and "NOTICE" for more information.
|
||||||
|
|
||||||
|
@ -327,6 +327,30 @@ pdfioArrayCreate(pdfio_file_t *pdf) // I - PDF file
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfioArrayDecrypt()' - Decrypt values in an array.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` on error
|
||||||
|
_pdfioArrayDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||||
|
pdfio_obj_t *obj, // I - Object
|
||||||
|
pdfio_array_t *a, // I - Array
|
||||||
|
size_t depth) // I - Depth
|
||||||
|
{
|
||||||
|
size_t i; // Looping var
|
||||||
|
_pdfio_value_t *v; // Current value
|
||||||
|
|
||||||
|
|
||||||
|
for (i = a->num_values, v = a->values; i > 0; i --, v ++)
|
||||||
|
{
|
||||||
|
if (!_pdfioValueDecrypt(pdf, obj, v, depth))
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// '_pdfioArrayDebug()' - Print the contents of an array.
|
// '_pdfioArrayDebug()' - Print the contents of an array.
|
||||||
//
|
//
|
||||||
|
@ -1131,20 +1131,20 @@ pdfioContentTextMeasure(
|
|||||||
if (ch < 128)
|
if (ch < 128)
|
||||||
{
|
{
|
||||||
// ASCII
|
// ASCII
|
||||||
*tempptr++ = ch;
|
*tempptr++ = (char)ch;
|
||||||
}
|
}
|
||||||
else if (ch < 2048)
|
else if (ch < 2048)
|
||||||
{
|
{
|
||||||
// 2-byte UTF-8
|
// 2-byte UTF-8
|
||||||
*tempptr++ = 0xc0 | ((ch >> 6) & 0x1f);
|
*tempptr++ = (char)(0xc0 | ((ch >> 6) & 0x1f));
|
||||||
*tempptr++ = 0x80 | (ch & 0x3f);
|
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 3-byte UTF-8
|
// 3-byte UTF-8
|
||||||
*tempptr++ = 0xe0 | ((ch >> 12) & 0x0f);
|
*tempptr++ = (char)(0xe0 | ((ch >> 12) & 0x0f));
|
||||||
*tempptr++ = 0x80 | ((ch >> 6) & 0x3f);
|
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||||
*tempptr++ = 0x80 | (ch & 0x3f);
|
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1152,7 +1152,7 @@ pdfioContentTextMeasure(
|
|||||||
s = temp;
|
s = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
ttfGetExtents(ttf, size, s, &extents);
|
ttfGetExtents(ttf, (float)size, s, &extents);
|
||||||
|
|
||||||
return (extents.right - extents.left);
|
return (extents.right - extents.left);
|
||||||
}
|
}
|
||||||
@ -1642,7 +1642,7 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
*bufptr++ = (unsigned char)(cmap[i] >> 8);
|
*bufptr++ = (unsigned char)(cmap[i] >> 8);
|
||||||
*bufptr++ = (unsigned char)(cmap[i] & 255);
|
*bufptr++ = (unsigned char)(cmap[i] & 255);
|
||||||
|
|
||||||
glyphs[cmap[i]] = i;
|
glyphs[cmap[i]] = (unsigned short)i;
|
||||||
if (cmap[i] < min_glyph)
|
if (cmap[i] < min_glyph)
|
||||||
min_glyph = cmap[i];
|
min_glyph = cmap[i];
|
||||||
if (cmap[i] > max_glyph)
|
if (cmap[i] > max_glyph)
|
||||||
@ -1727,9 +1727,9 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
|
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
for (start = 0, w0 = ttfGetWidth(font, 0), i = 1; i < 65536; start = i, w0 = w1, i ++)
|
for (start = 0, w0 = ttfGetWidth(font, 0), w1 = 0, i = 1; i < 65536; start = i, w0 = w1, i ++)
|
||||||
{
|
{
|
||||||
while (i < 65536 && (w1 = ttfGetWidth(font, i)) == w0)
|
while (i < 65536 && (w1 = ttfGetWidth(font, (int)i)) == w0)
|
||||||
i ++;
|
i ++;
|
||||||
|
|
||||||
if ((i - start) > 1)
|
if ((i - start) > 1)
|
||||||
@ -1750,7 +1750,7 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
pdfioArrayAppendNumber(temp_array, w0);
|
pdfioArrayAppendNumber(temp_array, w0);
|
||||||
for (w0 = w1, i ++; i < 65536; w0 = w1, i ++)
|
for (w0 = w1, i ++; i < 65536; w0 = w1, i ++)
|
||||||
{
|
{
|
||||||
if ((w1 = ttfGetWidth(font, i)) == w0 && i < 65535)
|
if ((w1 = ttfGetWidth(font, (int)i)) == w0 && i < 65535)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
pdfioArrayAppendNumber(temp_array, w0);
|
pdfioArrayAppendNumber(temp_array, w0);
|
||||||
|
@ -399,7 +399,7 @@ _pdfioCryptoMakeRandom(uint8_t *buffer, // I - Buffer
|
|||||||
//
|
//
|
||||||
|
|
||||||
_pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
_pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
||||||
_pdfioCryptoMakeReader(
|
_pdfioCryptoMakeReader(
|
||||||
pdfio_file_t *pdf, // I - PDF file
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
pdfio_obj_t *obj, // I - PDF object
|
pdfio_obj_t *obj, // I - PDF object
|
||||||
_pdfio_crypto_ctx_t *ctx, // I - Pointer to crypto context
|
_pdfio_crypto_ctx_t *ctx, // I - Pointer to crypto context
|
||||||
@ -409,11 +409,13 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
uint8_t data[21]; // Key data
|
uint8_t data[21]; // Key data
|
||||||
_pdfio_md5_t md5; // MD5 state
|
_pdfio_md5_t md5; // MD5 state
|
||||||
uint8_t digest[16]; // MD5 digest value
|
uint8_t digest[16]; // MD5 digest value
|
||||||
|
#if PDFIO_OBJ_CRYPT
|
||||||
pdfio_array_t *id_array; // Object ID array
|
pdfio_array_t *id_array; // Object ID array
|
||||||
unsigned char *id_value; // Object ID value
|
unsigned char *id_value; // Object ID value
|
||||||
size_t id_len; // Length of object ID
|
size_t id_len; // Length of object ID
|
||||||
uint8_t *file_key, // Computed file key to use
|
uint8_t temp_key[16]; // File key for object
|
||||||
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);
|
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);
|
||||||
@ -425,6 +427,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PDFIO_OBJ_CRYPT
|
||||||
if ((id_array = pdfioDictGetArray(pdfioObjGetDict(obj), "ID")) != NULL)
|
if ((id_array = pdfioDictGetArray(pdfioObjGetDict(obj), "ID")) != NULL)
|
||||||
{
|
{
|
||||||
// Object has its own ID that will get used for encryption...
|
// Object has its own ID that will get used for encryption...
|
||||||
@ -434,6 +437,8 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
own_user_key[32], // Calculated user key
|
own_user_key[32], // Calculated user key
|
||||||
pdf_user_key[32]; // Decrypted 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)
|
if ((id_value = pdfioArrayGetBinary(id_array, 0, &id_len)) == NULL)
|
||||||
{
|
{
|
||||||
*ivlen = 0;
|
*ivlen = 0;
|
||||||
@ -451,6 +456,8 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
|
|
||||||
if (memcmp(own_user_key, pdf->user_key, sizeof(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_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);
|
make_user_key(id_value, id_len, own_user_key);
|
||||||
|
|
||||||
@ -467,6 +474,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
file_key = temp_key;
|
file_key = temp_key;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif // PDFIO_OBJ_CRYPT
|
||||||
{
|
{
|
||||||
// Use the default file key...
|
// Use the default file key...
|
||||||
file_key = pdf->file_key;
|
file_key = pdf->file_key;
|
||||||
@ -543,7 +551,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
//
|
//
|
||||||
|
|
||||||
_pdfio_crypto_cb_t // O - Encryption callback or `NULL` for none
|
_pdfio_crypto_cb_t // O - Encryption callback or `NULL` for none
|
||||||
_pdfioCryptoMakeWriter(
|
_pdfioCryptoMakeWriter(
|
||||||
pdfio_file_t *pdf, // I - PDF file
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
pdfio_obj_t *obj, // I - PDF object
|
pdfio_obj_t *obj, // I - PDF object
|
||||||
_pdfio_crypto_ctx_t *ctx, // I - Pointer to crypto context
|
_pdfio_crypto_ctx_t *ctx, // I - Pointer to crypto context
|
||||||
@ -648,6 +656,8 @@ _pdfioCryptoUnlock(
|
|||||||
revision = (int)pdfioDictGetNumber(encrypt_dict, "R");
|
revision = (int)pdfioDictGetNumber(encrypt_dict, "R");
|
||||||
length = (int)pdfioDictGetNumber(encrypt_dict, "Length");
|
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 (!handler || strcmp(handler, "Standard"))
|
if (!handler || strcmp(handler, "Standard"))
|
||||||
{
|
{
|
||||||
_pdfioFileError(pdf, "Unsupported security handler '%s'.", handler ? handler : "(null)");
|
_pdfioFileError(pdf, "Unsupported security handler '%s'.", handler ? handler : "(null)");
|
||||||
@ -696,6 +706,8 @@ _pdfioCryptoUnlock(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioCryptoUnlock: CFM=\"%s\"\n", cfm);
|
||||||
|
|
||||||
if (length < 40 || length > 128)
|
if (length < 40 || length > 128)
|
||||||
length = 128; // Default to 128 bits
|
length = 128; // Default to 128 bits
|
||||||
|
|
||||||
|
31
pdfio-dict.c
31
pdfio-dict.c
@ -158,6 +158,30 @@ pdfioDictCreate(pdfio_file_t *pdf) // I - PDF file
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfioDictDecrypt()' - Decrypt the values in a dictionary.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` on error
|
||||||
|
_pdfioDictDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||||
|
pdfio_obj_t *obj, // I - Object
|
||||||
|
pdfio_dict_t *dict, // I - Dictionary
|
||||||
|
size_t depth) // I - Depth
|
||||||
|
{
|
||||||
|
size_t i; // Looping var
|
||||||
|
_pdfio_pair_t *pair; // Current pair
|
||||||
|
|
||||||
|
|
||||||
|
for (i = dict->num_pairs, pair = dict->pairs; i > 0; i --, pair ++)
|
||||||
|
{
|
||||||
|
if (strcmp(pair->key, "ID") && !_pdfioValueDecrypt(pdf, obj, &pair->value, depth + 1))
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// '_pdfioDictDebug()' - Dump a dictionary to stderr.
|
// '_pdfioDictDebug()' - Dump a dictionary to stderr.
|
||||||
//
|
//
|
||||||
@ -518,7 +542,7 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
_pdfio_value_t value; // Dictionary value
|
_pdfio_value_t value; // Dictionary value
|
||||||
|
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioDictRead(pdf=%p)\n", pdf);
|
PDFIO_DEBUG("_pdfioDictRead(pdf=%p, obj=%p, tb=%p, depth=%lu)\n", pdf, obj, tb, (unsigned long)depth);
|
||||||
|
|
||||||
// Create a dictionary and start reading...
|
// Create a dictionary and start reading...
|
||||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||||
@ -530,6 +554,7 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
if (!strcmp(key, ">>"))
|
if (!strcmp(key, ">>"))
|
||||||
{
|
{
|
||||||
// End of dictionary...
|
// End of dictionary...
|
||||||
|
PDFIO_DEBUG("_pdfioDictRead: Returning dictionary value...\n");
|
||||||
return (dict);
|
return (dict);
|
||||||
}
|
}
|
||||||
else if (key[0] != '/')
|
else if (key[0] != '/')
|
||||||
@ -548,14 +573,14 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
if (!_pdfioValueRead(pdf, obj, tb, &value, depth))
|
if (!_pdfioValueRead(pdf, obj, tb, &value, depth))
|
||||||
{
|
{
|
||||||
_pdfioFileError(pdf, "Missing value for dictionary key.");
|
_pdfioFileError(pdf, "Missing value for dictionary key '%s'.", key + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_pdfioDictSetValue(dict, pdfioStringCreate(pdf, key + 1), &value))
|
if (!_pdfioDictSetValue(dict, pdfioStringCreate(pdf, key + 1), &value))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// PDFIO_DEBUG("_pdfioDictRead: Set %s.\n", key);
|
PDFIO_DEBUG("_pdfioDictRead: Set %s.\n", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dictionary is invalid - pdfioFileClose will free the memory, return NULL
|
// Dictionary is invalid - pdfioFileClose will free the memory, return NULL
|
||||||
|
134
pdfio-file.c
134
pdfio-file.c
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
static pdfio_obj_t *add_obj(pdfio_file_t *pdf, size_t number, unsigned short generation, off_t offset);
|
static pdfio_obj_t *add_obj(pdfio_file_t *pdf, size_t number, unsigned short generation, off_t offset);
|
||||||
static int compare_objmaps(_pdfio_objmap_t *a, _pdfio_objmap_t *b);
|
static int compare_objmaps(_pdfio_objmap_t *a, _pdfio_objmap_t *b);
|
||||||
static int compare_objs(pdfio_obj_t **a, pdfio_obj_t **b);
|
|
||||||
static const char *get_info_string(pdfio_file_t *pdf, const char *key);
|
static const char *get_info_string(pdfio_file_t *pdf, const char *key);
|
||||||
static bool load_obj_stream(pdfio_obj_t *obj);
|
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_pages(pdfio_file_t *pdf, pdfio_obj_t *obj, size_t depth);
|
||||||
@ -916,21 +915,57 @@ pdfioFileFindObj(
|
|||||||
pdfio_file_t *pdf, // I - PDF file
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
size_t number) // I - Object number (1 to N)
|
size_t number) // I - Object number (1 to N)
|
||||||
{
|
{
|
||||||
pdfio_obj_t key, // Search key
|
size_t left, // Left object
|
||||||
*keyptr, // Pointer to key
|
right, // Right object
|
||||||
**match; // Pointer to match
|
current; // Current object
|
||||||
|
|
||||||
|
|
||||||
if (pdf->num_objs > 0)
|
PDFIO_DEBUG("pdfioFileFindObj(pdf=%p, number=%lu) alloc_objs=%lu, num_objs=%lu, objs=%p\n", (void *)pdf, (unsigned long)number, (unsigned long)(pdf ? pdf->alloc_objs : 0), (unsigned long)(pdf ? pdf->num_objs : 0), (void *)(pdf ? pdf->objs : NULL));
|
||||||
|
|
||||||
|
// Range check input...
|
||||||
|
if (!pdf || pdf->num_objs == 0 || number < 1)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
// Do a binary search for the object...
|
||||||
|
if ((current = number - 1) >= pdf->num_objs)
|
||||||
|
current = pdf->num_objs / 2;
|
||||||
|
|
||||||
|
PDFIO_DEBUG("pdfioFileFindObj: objs[current=%lu]=%p\n", (unsigned long)current, (void *)pdf->objs[current]);
|
||||||
|
|
||||||
|
if (number == pdf->objs[current]->number)
|
||||||
{
|
{
|
||||||
key.number = number;
|
// Fast match...
|
||||||
keyptr = &key;
|
return (pdf->objs[current]);
|
||||||
match = (pdfio_obj_t **)bsearch(&keyptr, pdf->objs, pdf->num_objs, sizeof(pdfio_obj_t *), (int (*)(const void *, const void *))compare_objs);
|
}
|
||||||
|
else if (number < pdf->objs[current]->number)
|
||||||
return (match ? *match : NULL);
|
{
|
||||||
|
left = 0;
|
||||||
|
right = current;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
left = current;
|
||||||
|
right = pdf->num_objs - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (NULL);
|
while ((right - left) > 1)
|
||||||
|
{
|
||||||
|
current = (left + right) / 2;
|
||||||
|
|
||||||
|
if (number == pdf->objs[current]->number)
|
||||||
|
return (pdf->objs[current]);
|
||||||
|
else if (number < pdf->objs[current]->number)
|
||||||
|
right = current;
|
||||||
|
else
|
||||||
|
left = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number == pdf->objs[left]->number)
|
||||||
|
return (pdf->objs[left]);
|
||||||
|
else if (number == pdf->objs[right]->number)
|
||||||
|
return (pdf->objs[right]);
|
||||||
|
else
|
||||||
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1385,6 +1420,9 @@ add_obj(pdfio_file_t *pdf, // I - PDF file
|
|||||||
off_t offset) // I - Offset in file
|
off_t offset) // I - Offset in file
|
||||||
{
|
{
|
||||||
pdfio_obj_t *obj; // Object
|
pdfio_obj_t *obj; // Object
|
||||||
|
size_t left, // Left object
|
||||||
|
right, // Right object
|
||||||
|
current; // Current object (center)
|
||||||
|
|
||||||
|
|
||||||
// Allocate memory for the object...
|
// Allocate memory for the object...
|
||||||
@ -1410,8 +1448,6 @@ add_obj(pdfio_file_t *pdf, // I - PDF file
|
|||||||
pdf->alloc_objs += 32;
|
pdf->alloc_objs += 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdf->objs[pdf->num_objs ++] = obj;
|
|
||||||
|
|
||||||
obj->pdf = pdf;
|
obj->pdf = pdf;
|
||||||
obj->number = number;
|
obj->number = number;
|
||||||
obj->generation = generation;
|
obj->generation = generation;
|
||||||
@ -1419,9 +1455,56 @@ add_obj(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
PDFIO_DEBUG("add_obj: obj=%p, ->pdf=%p, ->number=%lu, ->offset=%lu\n", obj, pdf, (unsigned long)obj->number, (unsigned long)offset);
|
PDFIO_DEBUG("add_obj: obj=%p, ->pdf=%p, ->number=%lu, ->offset=%lu\n", obj, pdf, (unsigned long)obj->number, (unsigned long)offset);
|
||||||
|
|
||||||
// Re-sort object array as needed...
|
// Insert object into array as needed...
|
||||||
if (pdf->num_objs > 1 && pdf->objs[pdf->num_objs - 2]->number > number)
|
if (pdf->num_objs == 0 || obj->number > pdf->objs[pdf->num_objs - 1]->number)
|
||||||
qsort(pdf->objs, pdf->num_objs, sizeof(pdfio_obj_t *), (int (*)(const void *, const void *))compare_objs);
|
{
|
||||||
|
// Append object...
|
||||||
|
PDFIO_DEBUG("add_obj: Appending at %lu\n", (unsigned long)pdf->num_objs);
|
||||||
|
|
||||||
|
pdf->objs[pdf->num_objs] = obj;
|
||||||
|
pdf->last_obj = pdf->num_objs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Insert object...
|
||||||
|
if (obj->number < pdf->objs[pdf->last_obj]->number)
|
||||||
|
{
|
||||||
|
left = 0;
|
||||||
|
right = pdf->last_obj;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
left = pdf->last_obj;
|
||||||
|
right = pdf->num_objs - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((right - left) > 1)
|
||||||
|
{
|
||||||
|
current = (left + right) / 2;
|
||||||
|
|
||||||
|
if (obj->number < pdf->objs[current]->number)
|
||||||
|
right = current;
|
||||||
|
else
|
||||||
|
left = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->number < pdf->objs[left]->number)
|
||||||
|
current = left;
|
||||||
|
else if (obj->number < pdf->objs[right]->number)
|
||||||
|
current = right;
|
||||||
|
else
|
||||||
|
current = right;
|
||||||
|
|
||||||
|
PDFIO_DEBUG("add_obj: Inserting at %lu\n", (unsigned long)current);
|
||||||
|
|
||||||
|
if (current < pdf->num_objs)
|
||||||
|
memmove(pdf->objs + current + 1, pdf->objs + current, (pdf->num_objs - current) * sizeof(pdfio_obj_t *));
|
||||||
|
|
||||||
|
pdf->objs[current] = obj;
|
||||||
|
pdf->last_obj = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdf->num_objs ++;
|
||||||
|
|
||||||
return (obj);
|
return (obj);
|
||||||
}
|
}
|
||||||
@ -1448,23 +1531,6 @@ compare_objmaps(_pdfio_objmap_t *a, // I - First object map
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// 'compare_objs()' - Compare the object numbers of two objects.
|
|
||||||
//
|
|
||||||
|
|
||||||
static int // O - Result of comparison
|
|
||||||
compare_objs(pdfio_obj_t **a, // I - First object
|
|
||||||
pdfio_obj_t **b) // I - Second object
|
|
||||||
{
|
|
||||||
if ((*a)->number < (*b)->number)
|
|
||||||
return (-1);
|
|
||||||
else if ((*a)->number == (*b)->number)
|
|
||||||
return (0);
|
|
||||||
else
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'get_info_string()' - Get a string value from the Info dictionary.
|
// 'get_info_string()' - Get a string value from the Info dictionary.
|
||||||
//
|
//
|
||||||
@ -1737,7 +1803,7 @@ load_xref(
|
|||||||
pdfio_stream_t *st; // Stream
|
pdfio_stream_t *st; // Stream
|
||||||
unsigned char buffer[32]; // Read buffer
|
unsigned char buffer[32]; // Read buffer
|
||||||
size_t num_sobjs = 0, // Number of object streams
|
size_t num_sobjs = 0, // Number of object streams
|
||||||
sobjs[4096]; // Object streams to load
|
sobjs[8192]; // Object streams to load
|
||||||
pdfio_obj_t *current; // Current object
|
pdfio_obj_t *current; // Current object
|
||||||
|
|
||||||
if ((number = strtoimax(line, &ptr, 10)) < 1)
|
if ((number = strtoimax(line, &ptr, 10)) < 1)
|
||||||
|
@ -453,9 +453,7 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[0]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
|
PDFIO_DEBUG("_pdfioObjLoad: tb.bufptr=%p, tb.bufend=%p, tb.bufptr[0]=0x%02x, tb.bufptr[1]=0x%02x\n", tb.bufptr, tb.bufend, tb.bufptr[0], tb.bufptr[1]);
|
||||||
if (tb.bufptr && tb.bufptr < tb.bufend && (tb.bufptr[0] == 0x0d || tb.bufptr[0] == 0x0a))
|
|
||||||
tb.bufptr ++; // Skip trailing CR or LF after token
|
|
||||||
|
|
||||||
_pdfioTokenFlush(&tb);
|
_pdfioTokenFlush(&tb);
|
||||||
|
|
||||||
@ -466,6 +464,18 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
|
|||||||
PDFIO_DEBUG("_pdfioObjLoad: stream_offset=%lu.\n", (unsigned long)obj->stream_offset);
|
PDFIO_DEBUG("_pdfioObjLoad: stream_offset=%lu.\n", (unsigned long)obj->stream_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decrypt as needed...
|
||||||
|
if (obj->pdf->encryption)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioObjLoad: Decrypting value...\n");
|
||||||
|
|
||||||
|
if (!_pdfioValueDecrypt(obj->pdf, obj, &obj->value, 0))
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("_pdfioObjLoad: Failed to decrypt.\n");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PDFIO_DEBUG("_pdfioObjLoad: ");
|
PDFIO_DEBUG("_pdfioObjLoad: ");
|
||||||
PDFIO_DEBUG_VALUE(&obj->value);
|
PDFIO_DEBUG_VALUE(&obj->value);
|
||||||
PDFIO_DEBUG("\n");
|
PDFIO_DEBUG("\n");
|
||||||
|
@ -266,7 +266,8 @@ struct _pdfio_file_s // PDF file structure
|
|||||||
alloc_dicts; // Allocated dictionaries
|
alloc_dicts; // Allocated dictionaries
|
||||||
pdfio_dict_t **dicts; // Dictionaries
|
pdfio_dict_t **dicts; // Dictionaries
|
||||||
size_t num_objs, // Number of objects
|
size_t num_objs, // Number of objects
|
||||||
alloc_objs; // Allocated objects
|
alloc_objs, // Allocated objects
|
||||||
|
last_obj; // Last object added
|
||||||
pdfio_obj_t **objs, // Objects
|
pdfio_obj_t **objs, // Objects
|
||||||
*current_obj; // Current object being written/read
|
*current_obj; // Current object being written/read
|
||||||
size_t num_objmaps, // Number of object maps
|
size_t num_objmaps, // Number of object maps
|
||||||
@ -321,6 +322,7 @@ struct _pdfio_stream_s // Stream
|
|||||||
// Functions...
|
// Functions...
|
||||||
//
|
//
|
||||||
|
|
||||||
|
extern bool _pdfioArrayDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_array_t *a, size_t depth) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioArrayDebug(pdfio_array_t *a, FILE *fp) _PDFIO_INTERNAL;
|
extern void _pdfioArrayDebug(pdfio_array_t *a, FILE *fp) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioArrayDelete(pdfio_array_t *a) _PDFIO_INTERNAL;
|
extern void _pdfioArrayDelete(pdfio_array_t *a) _PDFIO_INTERNAL;
|
||||||
extern _pdfio_value_t *_pdfioArrayGetValue(pdfio_array_t *a, size_t n) _PDFIO_INTERNAL;
|
extern _pdfio_value_t *_pdfioArrayGetValue(pdfio_array_t *a, size_t n) _PDFIO_INTERNAL;
|
||||||
@ -345,6 +347,7 @@ extern void _pdfioCryptoSHA256Finish(_pdfio_sha256_t *ctx, uint8_t *Message_Dig
|
|||||||
extern bool _pdfioCryptoUnlock(pdfio_file_t *pdf, pdfio_password_cb_t password_cb, void *password_data) _PDFIO_INTERNAL;
|
extern bool _pdfioCryptoUnlock(pdfio_file_t *pdf, pdfio_password_cb_t password_cb, void *password_data) _PDFIO_INTERNAL;
|
||||||
|
|
||||||
extern void _pdfioDictClear(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
extern void _pdfioDictClear(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
||||||
|
extern bool _pdfioDictDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, pdfio_dict_t *dict, size_t depth) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioDictDebug(pdfio_dict_t *dict, FILE *fp) _PDFIO_INTERNAL;
|
extern void _pdfioDictDebug(pdfio_dict_t *dict, FILE *fp) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioDictDelete(pdfio_dict_t *dict) _PDFIO_INTERNAL;
|
extern void _pdfioDictDelete(pdfio_dict_t *dict) _PDFIO_INTERNAL;
|
||||||
extern _pdfio_value_t *_pdfioDictGetValue(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
extern _pdfio_value_t *_pdfioDictGetValue(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
|
||||||
@ -388,6 +391,7 @@ extern void _pdfioTokenPush(_pdfio_token_t *tb, const char *token) _PDFIO_INTER
|
|||||||
extern bool _pdfioTokenRead(_pdfio_token_t *tb, char *buffer, size_t bufsize);
|
extern bool _pdfioTokenRead(_pdfio_token_t *tb, char *buffer, size_t bufsize);
|
||||||
|
|
||||||
extern _pdfio_value_t *_pdfioValueCopy(pdfio_file_t *pdfdst, _pdfio_value_t *vdst, pdfio_file_t *pdfsrc, _pdfio_value_t *vsrc) _PDFIO_INTERNAL;
|
extern _pdfio_value_t *_pdfioValueCopy(pdfio_file_t *pdfdst, _pdfio_value_t *vdst, pdfio_file_t *pdfsrc, _pdfio_value_t *vsrc) _PDFIO_INTERNAL;
|
||||||
|
extern bool _pdfioValueDecrypt(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioValueDebug(_pdfio_value_t *v, FILE *fp) _PDFIO_INTERNAL;
|
extern void _pdfioValueDebug(_pdfio_value_t *v, FILE *fp) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioValueDelete(_pdfio_value_t *v) _PDFIO_INTERNAL;
|
extern void _pdfioValueDelete(_pdfio_value_t *v) _PDFIO_INTERNAL;
|
||||||
extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
|
extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, _pdfio_value_t *v, size_t depth) _PDFIO_INTERNAL;
|
||||||
|
@ -1066,7 +1066,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
else if (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out)
|
else if (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out)
|
||||||
@ -1127,7 +1127,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
||||||
@ -1197,7 +1197,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
|
|
||||||
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
|
||||||
{
|
{
|
||||||
_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
|
_pdfioFileError(st->pdf, "Unable to decompress stream data for object %ld: %s", (long)st->obj->number, zstrerror(status));
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
|
||||||
|
@ -447,6 +447,13 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ch == '\r')
|
||||||
|
{
|
||||||
|
// Look for a trailing LF
|
||||||
|
if ((ch = get_char(tb)) != EOF && ch != '\n')
|
||||||
|
tb->bufptr --;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'N' : // number
|
case 'N' : // number
|
||||||
|
275
pdfio-value.c
275
pdfio-value.c
@ -10,6 +10,13 @@
|
|||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Local functions...
|
||||||
|
//
|
||||||
|
|
||||||
|
static time_t get_date_time(const char *s);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// '_pdfioValueCopy()' - Copy a value to a PDF file.
|
// '_pdfioValueCopy()' - Copy a value to a PDF file.
|
||||||
//
|
//
|
||||||
@ -105,6 +112,101 @@ _pdfioValueCopy(pdfio_file_t *pdfdst, // I - Destination PDF file
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfioValueDecrypt()' - Decrypt a value.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` on error
|
||||||
|
_pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
|
||||||
|
pdfio_obj_t *obj, // I - Object
|
||||||
|
_pdfio_value_t *v, // I - Value
|
||||||
|
size_t depth)// I - Depth
|
||||||
|
{
|
||||||
|
_pdfio_crypto_ctx_t ctx; // Decryption context
|
||||||
|
_pdfio_crypto_cb_t cb; // Decryption callback
|
||||||
|
size_t ivlen; // Number of initialization vector bytes
|
||||||
|
uint8_t temp[32768]; // Temporary buffer for decryption
|
||||||
|
size_t templen; // Number of actual data bytes
|
||||||
|
time_t timeval; // Date/time value
|
||||||
|
|
||||||
|
|
||||||
|
if (depth > PDFIO_MAX_DEPTH)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Value too deep.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (v->type)
|
||||||
|
{
|
||||||
|
default :
|
||||||
|
// Do nothing
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFIO_VALTYPE_ARRAY :
|
||||||
|
return (_pdfioArrayDecrypt(pdf, obj, v->value.array, depth + 1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFIO_VALTYPE_DICT :
|
||||||
|
return (_pdfioDictDecrypt(pdf, obj, v->value.dict, depth + 1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFIO_VALTYPE_BINARY :
|
||||||
|
// Decrypt the binary string...
|
||||||
|
if (v->value.binary.datalen > (sizeof(temp) - 32))
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to read encrypted binary string - too long.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ivlen = v->value.binary.datalen;
|
||||||
|
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL)
|
||||||
|
return (false);
|
||||||
|
|
||||||
|
templen = (cb)(&ctx, temp, v->value.binary.data + ivlen, v->value.binary.datalen - ivlen);
|
||||||
|
|
||||||
|
// Copy the decrypted string back to the value and adjust the length...
|
||||||
|
memcpy(v->value.binary.data, temp, templen);
|
||||||
|
|
||||||
|
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128)
|
||||||
|
v->value.binary.datalen = templen - temp[templen - 1];
|
||||||
|
else
|
||||||
|
v->value.binary.datalen = templen;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFIO_VALTYPE_STRING :
|
||||||
|
// Decrypt regular string...
|
||||||
|
templen = strlen(v->value.string);
|
||||||
|
if (templen > (sizeof(temp) - 33))
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to read encrypted string - too long.");
|
||||||
|
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);
|
||||||
|
temp[templen] = '\0';
|
||||||
|
|
||||||
|
if ((timeval = get_date_time((char *)temp)) != 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, (char *)temp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// '_pdfioValueDebug()' - Print the contents of a value.
|
// '_pdfioValueDebug()' - Print the contents of a value.
|
||||||
//
|
//
|
||||||
@ -196,6 +298,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
size_t depth) // I - Depth of value
|
size_t depth) // I - Depth of value
|
||||||
{
|
{
|
||||||
char token[32768]; // Token buffer
|
char token[32768]; // Token buffer
|
||||||
|
time_t timeval; // Date/time value
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static const char * const valtypes[] =
|
static const char * const valtypes[] =
|
||||||
{
|
{
|
||||||
@ -245,73 +348,10 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL)
|
if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
else if (!strncmp(token, "(D:", 3))
|
else if (!strncmp(token, "(D:", 3) && (timeval = get_date_time(token + 1)) != 0)
|
||||||
{
|
{
|
||||||
// Possible date value of the form:
|
v->type = PDFIO_VALTYPE_DATE;
|
||||||
//
|
v->value.date = timeval;
|
||||||
// (D:YYYYMMDDhhmmssZ)
|
|
||||||
// (D:YYYYMMDDhhmmss+HH'mm)
|
|
||||||
// (D:YYYYMMDDhhmmss-HH'mm)
|
|
||||||
//
|
|
||||||
int i; // Looping var
|
|
||||||
struct tm dateval; // Date value
|
|
||||||
int offset; // Date offset
|
|
||||||
|
|
||||||
for (i = 3; i < 17; i ++)
|
|
||||||
{
|
|
||||||
if (!isdigit(token[i] & 255))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= 17)
|
|
||||||
{
|
|
||||||
if (token[i] == 'Z')
|
|
||||||
{
|
|
||||||
i ++;
|
|
||||||
}
|
|
||||||
else if (token[i] == '-' || token[i] == '+')
|
|
||||||
{
|
|
||||||
if (isdigit(token[i + 1] & 255) && isdigit(token[i + 2] & 255) && token[i + 3] == '\'' && isdigit(token[i + 4] & 255) && isdigit(token[i + 5] & 255))
|
|
||||||
{
|
|
||||||
i += 6;
|
|
||||||
if (token[i] == '\'')
|
|
||||||
i ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token[i])
|
|
||||||
{
|
|
||||||
// Just a string...
|
|
||||||
v->type = PDFIO_VALTYPE_STRING;
|
|
||||||
v->value.string = pdfioStringCreate(pdf, token + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Date value...
|
|
||||||
memset(&dateval, 0, sizeof(dateval));
|
|
||||||
|
|
||||||
dateval.tm_year = (token[3] - '0') * 1000 + (token[4] - '0') * 100 + (token[5] - '0') * 10 + token[6] - '0' - 1900;
|
|
||||||
dateval.tm_mon = (token[7] - '0') * 10 + token[8] - '0' - 1;
|
|
||||||
dateval.tm_mday = (token[9] - '0') * 10 + token[10] - '0';
|
|
||||||
dateval.tm_hour = (token[11] - '0') * 10 + token[12] - '0';
|
|
||||||
dateval.tm_min = (token[13] - '0') * 10 + token[14] - '0';
|
|
||||||
dateval.tm_sec = (token[15] - '0') * 10 + token[16] - '0';
|
|
||||||
|
|
||||||
if (token[17] == 'Z')
|
|
||||||
{
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
offset = (token[18] - '0') * 600 + (token[19] - '0') * 60 + (token[20] - '0') * 10 + token[21] - '0';
|
|
||||||
if (token[17] == '-')
|
|
||||||
offset = -offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
v->type = PDFIO_VALTYPE_DATE;
|
|
||||||
v->value.date = mktime(&dateval) + offset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (token[0] == '(')
|
else if (token[0] == '(')
|
||||||
{
|
{
|
||||||
@ -363,36 +403,6 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
*dataptr++ = (unsigned char)d;
|
*dataptr++ = (unsigned char)d;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj && pdf->encryption)
|
|
||||||
{
|
|
||||||
// Decrypt the string...
|
|
||||||
_pdfio_crypto_ctx_t ctx; // Decryption context
|
|
||||||
_pdfio_crypto_cb_t cb; // Decryption callback
|
|
||||||
size_t ivlen; // Number of initialization vector bytes
|
|
||||||
uint8_t temp[32768]; // Temporary buffer for decryption
|
|
||||||
size_t templen; // Number of actual data bytes
|
|
||||||
|
|
||||||
if (v->value.binary.datalen > (sizeof(temp) - 32))
|
|
||||||
{
|
|
||||||
_pdfioFileError(pdf, "Unable to read encrypted binary string - too long.");
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ivlen = v->value.binary.datalen;
|
|
||||||
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL)
|
|
||||||
return (false);
|
|
||||||
|
|
||||||
templen = (cb)(&ctx, temp, v->value.binary.data + ivlen, v->value.binary.datalen - ivlen);
|
|
||||||
|
|
||||||
// Copy the decrypted string back to the value and adjust the length...
|
|
||||||
memcpy(v->value.binary.data, temp, templen);
|
|
||||||
|
|
||||||
if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128)
|
|
||||||
v->value.binary.datalen = templen - temp[templen - 1];
|
|
||||||
else
|
|
||||||
v->value.binary.datalen = templen;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (strchr("0123456789-+.", token[0]) != NULL)
|
else if (strchr("0123456789-+.", token[0]) != NULL)
|
||||||
{
|
{
|
||||||
@ -728,3 +738,76 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'get_date_time()' - Convert PDF date/time value to time_t.
|
||||||
|
//
|
||||||
|
|
||||||
|
static time_t // O - Time in seconds
|
||||||
|
get_date_time(const char *s) // I - PDF date/time value
|
||||||
|
{
|
||||||
|
int i; // Looping var
|
||||||
|
struct tm dateval; // Date value
|
||||||
|
int offset; // Date offset
|
||||||
|
|
||||||
|
|
||||||
|
// Possible date value of the form:
|
||||||
|
//
|
||||||
|
// (D:YYYYMMDDhhmmssZ)
|
||||||
|
// (D:YYYYMMDDhhmmss+HH'mm)
|
||||||
|
// (D:YYYYMMDDhhmmss-HH'mm)
|
||||||
|
//
|
||||||
|
|
||||||
|
for (i = 2; i < 16; i ++)
|
||||||
|
{
|
||||||
|
if (!isdigit(s[i] & 255) || !s[i])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= 16)
|
||||||
|
{
|
||||||
|
if (s[i] == 'Z')
|
||||||
|
{
|
||||||
|
i ++;
|
||||||
|
}
|
||||||
|
else if (s[i] == '-' || s[i] == '+')
|
||||||
|
{
|
||||||
|
if (isdigit(s[i + 1] & 255) && isdigit(s[i + 2] & 255) && s[i + 3] == '\'' && isdigit(s[i + 4] & 255) && isdigit(s[i + 5] & 255))
|
||||||
|
{
|
||||||
|
i += 6;
|
||||||
|
if (s[i] == '\'')
|
||||||
|
i ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s[i])
|
||||||
|
{
|
||||||
|
// Just a string...
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Date value...
|
||||||
|
memset(&dateval, 0, sizeof(dateval));
|
||||||
|
|
||||||
|
dateval.tm_year = (s[2] - '0') * 1000 + (s[3] - '0') * 100 + (s[4] - '0') * 10 + s[5] - '0' - 1900;
|
||||||
|
dateval.tm_mon = (s[6] - '0') * 10 + s[7] - '0' - 1;
|
||||||
|
dateval.tm_mday = (s[8] - '0') * 10 + s[9] - '0';
|
||||||
|
dateval.tm_hour = (s[10] - '0') * 10 + s[11] - '0';
|
||||||
|
dateval.tm_min = (s[12] - '0') * 10 + s[13] - '0';
|
||||||
|
dateval.tm_sec = (s[14] - '0') * 10 + s[15] - '0';
|
||||||
|
|
||||||
|
if (s[16] == 'Z')
|
||||||
|
{
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset = (s[17] - '0') * 600 + (s[18] - '0') * 60 + (s[19] - '0') * 10 + s[20] - '0';
|
||||||
|
if (s[16] == '-')
|
||||||
|
offset = -offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (mktime(&dateval) + offset);
|
||||||
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<description>PDFio Library for VS2019+</description>
|
<description>PDFio Library for VS2019+</description>
|
||||||
<summary>PDFio is a simple C library for reading and writing PDF files. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
<summary>PDFio is a simple C library for reading and writing PDF files. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
||||||
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
<copyright>Copyright © 2019-2024 by Michael R Sweet</copyright>
|
||||||
<tags>pdf file native</tags>
|
<tags>pdf file native</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="pdfio_native.redist" version="1.2.0" />
|
<dependency id="pdfio_native.redist" version="1.2.0" />
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<description>PDFio Library for VS2019+</description>
|
<description>PDFio Library for VS2019+</description>
|
||||||
<summary>PDFio is a simple C library for reading and writing PDF files. This package provides the redistributable content for the PDFio library. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
<summary>PDFio is a simple C library for reading and writing PDF files. This package provides the redistributable content for the PDFio library. PDFio is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GNU GPL2-only software.</summary>
|
||||||
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
<copyright>Copyright © 2019-2024 by Michael R Sweet</copyright>
|
||||||
<tags>pdf file native</tags>
|
<tags>pdf file native</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||||
|
2
ttf.c
2
ttf.c
@ -1307,7 +1307,7 @@ read_cmap(ttf_t *font) // I - Font
|
|||||||
{
|
{
|
||||||
// Use an "obscure indexing trick" (words from the spec, not
|
// Use an "obscure indexing trick" (words from the spec, not
|
||||||
// mine) to look up the glyph index...
|
// mine) to look up the glyph index...
|
||||||
temp = segment->idRangeOffset / 2 - segCount + (ch - segment->startCode) + (segment - segments);
|
temp = (int)(segment->idRangeOffset / 2 - segCount + (ch - segment->startCode) + (segment - segments));
|
||||||
|
|
||||||
TTF_DEBUG("read_cmap: ch=%d, temp=%d\n", ch, temp);
|
TTF_DEBUG("read_cmap: ch=%d, temp=%d\n", ch, temp);
|
||||||
if (temp < 0 || temp >= numGlyphIdArray)
|
if (temp < 0 || temp >= numGlyphIdArray)
|
||||||
|
Reference in New Issue
Block a user