Compare commits

...

5 Commits

Author SHA1 Message Date
Michael R Sweet
f09105dd3f
Add support for writing the PCLm subset of PDF (Issue #99) 2025-02-20 18:18:53 -05:00
Michael R Sweet
5be5552b2b
Turn write_obj_header into private API. 2025-02-20 17:37:31 -05:00
Michael R Sweet
492a4f51b2
Allocate stream compression buffer. 2025-02-16 13:20:51 -05:00
Michael R Sweet
44827bac1a
Cleanup. 2025-02-16 12:40:39 -05:00
Michael R Sweet
3fad0d6f15
Support xref streams with encrypted output. 2025-02-16 12:35:45 -05:00
7 changed files with 149 additions and 54 deletions

View File

@ -10,6 +10,7 @@ v1.5.0 - YYYY-MM-DD
(Issue #10) (Issue #10)
- Added `pdfioFileGetModDate()` API (Issue #88) - Added `pdfioFileGetModDate()` API (Issue #88)
- Added support for using libpng to embed PNG images in PDF output (Issue #90) - Added support for using libpng to embed PNG images in PDF output (Issue #90)
- Added support for writing the PCLm subset of PDF (Issue #99)
- Now support opening damaged PDF files (Issue #45) - Now support opening damaged PDF files (Issue #45)
- Updated the pdf2txt example to support font encodings. - Updated the pdf2txt example to support font encodings.

View File

@ -1,4 +1,4 @@
.TH pdfio 3 "pdf read/write library" "2025-02-13" "pdf read/write library" .TH pdfio 3 "pdf read/write library" "2025-02-20" "pdf read/write library"
.SH NAME .SH NAME
pdfio \- pdf read/write library pdfio \- pdf read/write library
.SH Introduction .SH Introduction
@ -3561,7 +3561,8 @@ This function creates a new PDF file. The "filename" argument specifies the
name of the PDF file to create. name of the PDF file to create.
.PP .PP
The "version" argument specifies the PDF version number for the file or The "version" argument specifies the PDF version number for the file or
\fBNULL\fR for the default ("2.0"). \fBNULL\fR for the default ("2.0"). The value "PCLm-1.0" can be specified to
produce the PCLm subset of PDF.
.PP .PP
The "media_box" and "crop_box" arguments specify the default MediaBox and The "media_box" and "crop_box" arguments specify the default MediaBox and
CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size
@ -3643,8 +3644,19 @@ This function embeds a TrueType/OpenType font into a PDF file. The
characters (potentially full Unicode, but more typically a subset) characters (potentially full Unicode, but more typically a subset)
or to only support the Windows CP1252 (ISO-8859-1 with additional or to only support the Windows CP1252 (ISO-8859-1 with additional
characters such as the Euro symbol) subset of Unicode. characters such as the Euro symbol) subset of Unicode.
.SS pdfioFileCreateICCObjFromData
Add ICC profile data to a PDF file.
.PP
.nf
pdfio_obj_t * pdfioFileCreateICCObjFromData (
pdfio_file_t *pdf,
const unsigned char *data,
size_t datalen,
size_t num_colors
);
.fi
.SS pdfioFileCreateICCObjFromFile .SS pdfioFileCreateICCObjFromFile
Add an ICC profile object to a PDF file. Add an ICC profile file to a PDF file.
.PP .PP
.nf .nf
pdfio_obj_t * pdfioFileCreateICCObjFromFile ( pdfio_obj_t * pdfioFileCreateICCObjFromFile (
@ -3767,7 +3779,9 @@ written:
.fi .fi
The "version" argument specifies the PDF version number for the file or The "version" argument specifies the PDF version number for the file or
\fBNULL\fR for the default ("2.0"). \fBNULL\fR for the default ("2.0"). Unlike \fIpdfioFileCreate\fR and
\fIpdfioFileCreateTemporary\fR, it is generally not safe to pass the
"PCLm-1.0" version string.
.PP .PP
The "media_box" and "crop_box" arguments specify the default MediaBox and The "media_box" and "crop_box" arguments specify the default MediaBox and
CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size

View File

@ -400,6 +400,7 @@ span.string {
<li><a href="#pdfioFileCreateArrayObj">pdfioFileCreateArrayObj</a></li> <li><a href="#pdfioFileCreateArrayObj">pdfioFileCreateArrayObj</a></li>
<li><a href="#pdfioFileCreateFontObjFromBase">pdfioFileCreateFontObjFromBase</a></li> <li><a href="#pdfioFileCreateFontObjFromBase">pdfioFileCreateFontObjFromBase</a></li>
<li><a href="#pdfioFileCreateFontObjFromFile">pdfioFileCreateFontObjFromFile</a></li> <li><a href="#pdfioFileCreateFontObjFromFile">pdfioFileCreateFontObjFromFile</a></li>
<li><a href="#pdfioFileCreateICCObjFromData">pdfioFileCreateICCObjFromData</a></li>
<li><a href="#pdfioFileCreateICCObjFromFile">pdfioFileCreateICCObjFromFile</a></li> <li><a href="#pdfioFileCreateICCObjFromFile">pdfioFileCreateICCObjFromFile</a></li>
<li><a href="#pdfioFileCreateImageObjFromData">pdfioFileCreateImageObjFromData</a></li> <li><a href="#pdfioFileCreateImageObjFromData">pdfioFileCreateImageObjFromData</a></li>
<li><a href="#pdfioFileCreateImageObjFromFile">pdfioFileCreateImageObjFromFile</a></li> <li><a href="#pdfioFileCreateImageObjFromFile">pdfioFileCreateImageObjFromFile</a></li>
@ -3814,7 +3815,8 @@ have been iterated.</p>
name of the PDF file to create.<br> name of the PDF file to create.<br>
<br> <br>
The &quot;version&quot; argument specifies the PDF version number for the file or The &quot;version&quot; argument specifies the PDF version number for the file or
<code>NULL</code> for the default (&quot;2.0&quot;).<br> <code>NULL</code> for the default (&quot;2.0&quot;). The value &quot;PCLm-1.0&quot; can be specified to
produce the PCLm subset of PDF.<br>
<br> <br>
The &quot;media_box&quot; and &quot;crop_box&quot; arguments specify the default MediaBox and The &quot;media_box&quot; and &quot;crop_box&quot; arguments specify the default MediaBox and
CropBox for pages in the PDF file - if <code>NULL</code> then a default &quot;Universal&quot; size CropBox for pages in the PDF file - if <code>NULL</code> then a default &quot;Universal&quot; size
@ -3909,8 +3911,25 @@ Unicode.</p>
characters (potentially full Unicode, but more typically a subset) characters (potentially full Unicode, but more typically a subset)
or to only support the Windows CP1252 (ISO-8859-1 with additional or to only support the Windows CP1252 (ISO-8859-1 with additional
characters such as the Euro symbol) subset of Unicode.</p> characters such as the Euro symbol) subset of Unicode.</p>
<h3 class="function"><a id="pdfioFileCreateICCObjFromData">pdfioFileCreateICCObjFromData</a></h3>
<p class="description">Add ICC profile data to a PDF file.</p>
<p class="code">
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateICCObjFromData(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">unsigned</span> <span class="reserved">char</span> *data, size_t datalen, size_t num_colors);</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">ICC profile buffer</td></tr>
<tr><th>datalen</th>
<td class="description">Length of ICC profile</td></tr>
<tr><th>num_colors</th>
<td class="description">Number of color components (1, 3, or 4)</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">Object</p>
<h3 class="function"><a id="pdfioFileCreateICCObjFromFile">pdfioFileCreateICCObjFromFile</a></h3> <h3 class="function"><a id="pdfioFileCreateICCObjFromFile">pdfioFileCreateICCObjFromFile</a></h3>
<p class="description">Add an ICC profile object to a PDF file.</p> <p class="description">Add an ICC profile file to a PDF file.</p>
<p class="code"> <p class="code">
<a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateICCObjFromFile(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *filename, size_t num_colors);</p> <a href="#pdfio_obj_t">pdfio_obj_t</a> *pdfioFileCreateICCObjFromFile(<a href="#pdfio_file_t">pdfio_file_t</a> *pdf, <span class="reserved">const</span> <span class="reserved">char</span> *filename, size_t num_colors);</p>
<h4 class="parameters">Parameters</h4> <h4 class="parameters">Parameters</h4>
@ -4071,7 +4090,9 @@ output_cb(void *output_cbdata, const void *buffer, size_t bytes)
</pre> </pre>
The &quot;version&quot; argument specifies the PDF version number for the file or The &quot;version&quot; argument specifies the PDF version number for the file or
<code>NULL</code> for the default (&quot;2.0&quot;).<br> <code>NULL</code> for the default (&quot;2.0&quot;). Unlike <a href="#pdfioFileCreate"><code>pdfioFileCreate</code></a> and
<a href="#pdfioFileCreateTemporary"><code>pdfioFileCreateTemporary</code></a>, it is generally not safe to pass the
&quot;PCLm-1.0&quot; version string.<br>
<br> <br>
The &quot;media_box&quot; and &quot;crop_box&quot; arguments specify the default MediaBox and The &quot;media_box&quot; and &quot;crop_box&quot; arguments specify the default MediaBox and
CropBox for pages in the PDF file - if <code>NULL</code> then a default &quot;Universal&quot; size CropBox for pages in the PDF file - if <code>NULL</code> then a default &quot;Universal&quot; size
@ -4139,8 +4160,19 @@ You must call <a href="#pdfioObjClose"><code>pdfioObjClose</code></a> to write t
<p class="description">Create a temporary PDF file.</p> <p class="description">Create a temporary PDF file.</p>
<p class="discussion">This function creates a PDF file with a unique filename in the current <p class="discussion">This function creates a PDF file with a unique filename in the current
temporary directory. The temporary file is stored in the string &quot;buffer&quot; an temporary directory. The temporary file is stored in the string &quot;buffer&quot; an
will have a &quot;.pdf&quot; extension. Otherwise, this function works the same as will have a &quot;.pdf&quot; extension.<br>
the <a href="#pdfioFileCreate"><code>pdfioFileCreate</code></a> function. <br>
The &quot;version&quot; argument specifies the PDF version number for the file or
<code>NULL</code> for the default (&quot;2.0&quot;). The value &quot;PCLm-1.0&quot; can be specified to
produce the PCLm subset of PDF.<br>
<br>
The &quot;media_box&quot; and &quot;crop_box&quot; arguments specify the default MediaBox and
CropBox for pages in the PDF file - if <code>NULL</code> then a default &quot;Universal&quot; size
of 8.27x11in (the intersection of US Letter and ISO A4) is used.<br>
<br>
The &quot;error_cb&quot; and &quot;error_cbdata&quot; 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> </p>
<h3 class="function"><a id="pdfioFileFindObj">pdfioFileFindObj</a></h3> <h3 class="function"><a id="pdfioFileFindObj">pdfioFileFindObj</a></h3>

View File

@ -165,7 +165,8 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file
// name of the PDF file to create. // name of the PDF file to create.
// //
// The "version" argument specifies the PDF version number for the file or // The "version" argument specifies the PDF version number for the file or
// `NULL` for the default ("2.0"). // `NULL` for the default ("2.0"). The value "PCLm-1.0" can be specified to
// produce the PCLm subset of PDF.
// //
// The "media_box" and "crop_box" arguments specify the default MediaBox and // The "media_box" and "crop_box" arguments specify the default MediaBox and
// CropBox for pages in the PDF file - if `NULL` then a default "Universal" size // CropBox for pages in the PDF file - if `NULL` then a default "Universal" size
@ -397,7 +398,9 @@ _pdfioFileCreateObj(
// ``` // ```
// //
// The "version" argument specifies the PDF version number for the file or // The "version" argument specifies the PDF version number for the file or
// `NULL` for the default ("2.0"). // `NULL` for the default ("2.0"). Unlike @link pdfioFileCreate@ and
// @link pdfioFileCreateTemporary@, it is generally not safe to pass the
// "PCLm-1.0" version string.
// //
// The "media_box" and "crop_box" arguments specify the default MediaBox and // The "media_box" and "crop_box" arguments specify the default MediaBox and
// CropBox for pages in the PDF file - if `NULL` then a default "Universal" size // CropBox for pages in the PDF file - if `NULL` then a default "Universal" size
@ -532,8 +535,19 @@ pdfioFileCreateStringObj(
// //
// This function creates a PDF file with a unique filename in the current // This function creates a PDF file with a unique filename in the current
// temporary directory. The temporary file is stored in the string "buffer" an // temporary directory. The temporary file is stored in the string "buffer" an
// will have a ".pdf" extension. Otherwise, this function works the same as // will have a ".pdf" extension.
// the @link pdfioFileCreate@ function. //
// The "version" argument specifies the PDF version number for the file or
// `NULL` for the default ("2.0"). The value "PCLm-1.0" can be specified to
// produce the PCLm subset of PDF.
//
// The "media_box" and "crop_box" arguments specify the default MediaBox and
// CropBox for pages in the PDF file - if `NULL` then a default "Universal" size
// 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`.
// //
// @since PDFio v1.1@ // @since PDFio v1.1@
// //
@ -1396,7 +1410,7 @@ create_common(
pdf->output_cb = output_cb; pdf->output_cb = output_cb;
pdf->output_ctx = output_cbdata; pdf->output_ctx = output_cbdata;
pdf->filename = strdup(filename); pdf->filename = strdup(filename);
pdf->version = strdup(version); pdf->version = strdup(!strncmp(version, "PCLm-", 5) ? "1.4" : version);
pdf->mode = _PDFIO_MODE_WRITE; pdf->mode = _PDFIO_MODE_WRITE;
pdf->error_cb = error_cb; pdf->error_cb = error_cb;
pdf->error_data = error_cbdata; pdf->error_data = error_cbdata;
@ -1427,8 +1441,15 @@ create_common(
} }
// Write a standard PDF header... // Write a standard PDF header...
if (!_pdfioFilePrintf(pdf, "%%PDF-%s\n%%\342\343\317\323\n", version)) if (!strncmp(version, "PCLm-", 5))
{
if (!_pdfioFilePrintf(pdf, "%%PDF-1.4\n%%%s\n", version))
goto error;
}
else if (!_pdfioFilePrintf(pdf, "%%PDF-%s\n%%\342\343\317\323\n", version))
{
goto error; goto error;
}
// Create the pages object... // Create the pages object...
if ((dict = pdfioDictCreate(pdf)) == NULL) if ((dict = pdfioDictCreate(pdf)) == NULL)
@ -2364,8 +2385,7 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
// Write the xref table... // Write the xref table...
xref_offset = _pdfioFileTell(pdf); xref_offset = _pdfioFileTell(pdf);
// TODO: Figure out how to do xref streams with encrypted output if (strcmp(pdf->version, "1.5") >= 0 && !pdf->output_cb)
if (strcmp(pdf->version, "1.5") >= 0 && !pdf->output_cb && !pdf->encrypt_obj)
{ {
// Write a cross-reference stream... // Write a cross-reference stream...
pdfio_dict_t *xref_dict; // Object dictionary pdfio_dict_t *xref_dict; // Object dictionary
@ -2374,6 +2394,11 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
pdfio_stream_t *xref_st; // Stream pdfio_stream_t *xref_st; // Stream
int offsize; // Size of object offsets int offsize; // Size of object offsets
unsigned char buffer[10]; // Buffer entry unsigned char buffer[10]; // Buffer entry
pdfio_encryption_t encryption; // PDF encryption mode
// Disable encryption while we write the xref stream...
encryption = pdf->encryption;
pdf->encryption = PDFIO_ENCRYPTION_NONE;
// Figure out how many bytes are needed for the object numbers // Figure out how many bytes are needed for the object numbers
if (xref_offset < 0xff) if (xref_offset < 0xff)
@ -2416,13 +2441,14 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
pdfioDictSetNumber(xref_dict, "Size", pdf->num_objs + 2); pdfioDictSetNumber(xref_dict, "Size", pdf->num_objs + 2);
pdfioDictSetArray(xref_dict, "W", w_array); pdfioDictSetArray(xref_dict, "W", w_array);
pdfioDictSetName(xref_dict, "Filter", "FlateDecode"); pdfioDictSetName(xref_dict, "Filter", "FlateDecode");
pdfioDictSetObj(xref_dict, "Info", pdf->info_obj);
pdfioDictSetObj(xref_dict, "Root", pdf->root_obj);
if (pdf->encrypt_obj) if (pdf->encrypt_obj)
pdfioDictSetObj(xref_dict, "Encrypt", pdf->encrypt_obj); pdfioDictSetObj(xref_dict, "Encrypt", pdf->encrypt_obj);
if (pdf->id_array) if (pdf->id_array)
pdfioDictSetArray(xref_dict, "ID", pdf->id_array); pdfioDictSetArray(xref_dict, "ID", pdf->id_array);
pdfioDictSetObj(xref_dict, "Info", pdf->info_obj);
pdfioDictSetObj(xref_dict, "Root", pdf->root_obj);
if ((xref_obj = pdfioFileCreateObj(pdf, xref_dict)) == NULL) if ((xref_obj = pdfioFileCreateObj(pdf, xref_dict)) == NULL)
{ {
@ -2514,6 +2540,8 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
} }
pdfioStreamClose(xref_st); pdfioStreamClose(xref_st);
pdf->encryption = encryption;
} }
else else
{ {

View File

@ -1,7 +1,7 @@
// //
// PDF object functions for PDFio. // PDF object functions for PDFio.
// //
// Copyright © 2021-2024 by Michael R Sweet. // Copyright © 2021-2025 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -10,13 +10,6 @@
#include "pdfio-private.h" #include "pdfio-private.h"
//
// Local functions...
//
static bool write_obj_header(pdfio_obj_t *obj);
// //
// 'pdfioObjClose()' - Close an object, writing any data as needed to the PDF // 'pdfioObjClose()' - Close an object, writing any data as needed to the PDF
// file. // file.
@ -42,7 +35,7 @@ pdfioObjClose(pdfio_obj_t *obj) // I - Object
if (!obj->offset) if (!obj->offset)
{ {
// Write the object value // Write the object value
if (!write_obj_header(obj)) if (!_pdfioObjWriteHeader(obj))
return (false); return (false);
// Write the "endobj" line... // Write the "endobj" line...
@ -195,7 +188,7 @@ pdfioObjCreateStream(
} }
} }
if (!write_obj_header(obj)) if (!_pdfioObjWriteHeader(obj))
return (NULL); return (NULL);
if (!_pdfioFilePuts(obj->pdf, "stream\n")) if (!_pdfioFilePuts(obj->pdf, "stream\n"))
@ -205,7 +198,7 @@ pdfioObjCreateStream(
obj->pdf->current_obj = obj; obj->pdf->current_obj = obj;
// Return the new stream... // Return the new stream...
return (_pdfioStreamCreate(obj, length_obj, filter)); return (_pdfioStreamCreate(obj, length_obj, 0, filter));
} }
@ -582,11 +575,11 @@ _pdfioObjSetExtension(
// //
// 'write_obj_header()' - Write the object header... // '_pdfioObjWriteHeader()' - Write the object header...
// //
static bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
write_obj_header(pdfio_obj_t *obj) // I - Object _pdfioObjWriteHeader(pdfio_obj_t *obj) // I - Object
{ {
obj->offset = _pdfioFileTell(obj->pdf); obj->offset = _pdfioFileTell(obj->pdf);

View File

@ -1,7 +1,7 @@
// //
// Private header file for PDFio. // Private header file for PDFio.
// //
// Copyright © 2021-2024 by Michael R Sweet. // Copyright © 2021-2025 by Michael R Sweet.
// //
// Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -107,7 +107,7 @@ typedef enum _pdfio_mode_e // Read/write mode
typedef enum _pdfio_predictor_e // PNG predictor constants typedef enum _pdfio_predictor_e // PNG predictor constants
{ {
_PDFIO_PREDICTOR_NONE = 1, // No predictor (default) _PDFIO_PREDICTOR_NONE = 1, // No predictor (default)
_PDFIO_PREDICTOR_TIFF2 = 2, // TIFF2 predictor (???) _PDFIO_PREDICTOR_TIFF2 = 2, // TIFF predictor 2 (difference from left neighbor)
_PDFIO_PREDICTOR_PNG_NONE = 10, // PNG None predictor (same as `_PDFIO_PREDICTOR_NONE`) _PDFIO_PREDICTOR_PNG_NONE = 10, // PNG None predictor (same as `_PDFIO_PREDICTOR_NONE`)
_PDFIO_PREDICTOR_PNG_SUB = 11, // PNG Sub predictor _PDFIO_PREDICTOR_PNG_SUB = 11, // PNG Sub predictor
_PDFIO_PREDICTOR_PNG_UP = 12, // PNG Up predictor _PDFIO_PREDICTOR_PNG_UP = 12, // PNG Up predictor
@ -313,8 +313,9 @@ struct _pdfio_stream_s // Stream
z_stream flate; // Flate filter state z_stream flate; // Flate filter state
_pdfio_predictor_t predictor; // Predictor function, if any _pdfio_predictor_t predictor; // Predictor function, if any
size_t pbpixel, // Size of a pixel in bytes size_t pbpixel, // Size of a pixel in bytes
pbsize; // Predictor buffer size, if any pbsize, // Predictor buffer size, if any
unsigned char cbuffer[4096], // Compressed data buffer cbsize; // Compressed data buffer size
unsigned char *cbuffer, // Compressed data buffer
*prbuffer, // Raw buffer (previous line), as needed *prbuffer, // Raw buffer (previous line), as needed
*psbuffer; // PNG filter buffer, as needed *psbuffer; // PNG filter buffer, as needed
_pdfio_crypto_cb_t crypto_cb; // Encryption/descryption callback, if any _pdfio_crypto_cb_t crypto_cb; // Encryption/descryption callback, if any
@ -383,8 +384,9 @@ extern void _pdfioObjDelete(pdfio_obj_t *obj) _PDFIO_INTERNAL;
extern void *_pdfioObjGetExtension(pdfio_obj_t *obj) _PDFIO_INTERNAL; extern void *_pdfioObjGetExtension(pdfio_obj_t *obj) _PDFIO_INTERNAL;
extern bool _pdfioObjLoad(pdfio_obj_t *obj) _PDFIO_INTERNAL; extern bool _pdfioObjLoad(pdfio_obj_t *obj) _PDFIO_INTERNAL;
extern void _pdfioObjSetExtension(pdfio_obj_t *obj, void *data, _pdfio_extfree_t datafree) _PDFIO_INTERNAL; extern void _pdfioObjSetExtension(pdfio_obj_t *obj, void *data, _pdfio_extfree_t datafree) _PDFIO_INTERNAL;
extern bool _pdfioObjWriteHeader(pdfio_obj_t *obj) _PDFIO_INTERNAL;
extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, pdfio_filter_t compression) _PDFIO_INTERNAL; extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, size_t cbsize, pdfio_filter_t compression) _PDFIO_INTERNAL;
extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL; extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL;
extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL; extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;

View File

@ -50,7 +50,7 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
while ((status = deflate(&st->flate, Z_FINISH)) != Z_STREAM_END) while ((status = deflate(&st->flate, Z_FINISH)) != Z_STREAM_END)
{ {
size_t bytes = sizeof(st->cbuffer) - st->flate.avail_out, size_t bytes = st->cbsize - st->flate.avail_out,
// Bytes to write // Bytes to write
outbytes; // Actual bytes written outbytes; // Actual bytes written
@ -89,13 +89,13 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
} }
st->flate.next_out = (Bytef *)st->cbuffer + bytes; st->flate.next_out = (Bytef *)st->cbuffer + bytes;
st->flate.avail_out = (uInt)(sizeof(st->cbuffer) - bytes); st->flate.avail_out = (uInt)(st->cbsize - bytes);
} }
if (st->flate.avail_out < (uInt)sizeof(st->cbuffer)) if (st->flate.avail_out < (uInt)st->cbsize)
{ {
// Write any residuals... // Write any residuals...
size_t bytes = sizeof(st->cbuffer) - st->flate.avail_out; size_t bytes = st->cbsize - st->flate.avail_out;
// Bytes to write // Bytes to write
if (st->crypto_cb) if (st->crypto_cb)
@ -172,6 +172,7 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
st->pdf->current_obj = NULL; st->pdf->current_obj = NULL;
free(st->cbuffer);
free(st->prbuffer); free(st->prbuffer);
free(st->psbuffer); free(st->psbuffer);
free(st); free(st);
@ -190,6 +191,7 @@ pdfio_stream_t * // O - Stream or `NULL` on error
_pdfioStreamCreate( _pdfioStreamCreate(
pdfio_obj_t *obj, // I - Object pdfio_obj_t *obj, // I - Object
pdfio_obj_t *length_obj, // I - Length object, if any pdfio_obj_t *length_obj, // I - Length object, if any
size_t cbsize, // I - Size of compression buffer
pdfio_filter_t compression) // I - Compression to apply pdfio_filter_t compression) // I - Compression to apply
{ {
pdfio_stream_t *st; // Stream pdfio_stream_t *st; // Stream
@ -302,8 +304,21 @@ _pdfioStreamCreate(
else else
st->predictor = _PDFIO_PREDICTOR_NONE; st->predictor = _PDFIO_PREDICTOR_NONE;
if (cbsize == 0)
cbsize = 4096;
st->cbsize = cbsize;
if ((st->cbuffer = malloc(cbsize)) == NULL)
{
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Flate output buffer: %s", (unsigned long)cbsize, strerror(errno));
free(st->prbuffer);
free(st->psbuffer);
free(st);
return (NULL);
}
st->flate.next_out = (Bytef *)st->cbuffer; st->flate.next_out = (Bytef *)st->cbuffer;
st->flate.avail_out = (uInt)sizeof(st->cbuffer); st->flate.avail_out = (uInt)cbsize;
if ((status = deflateInit(&(st->flate), 9)) != Z_OK) if ((status = deflateInit(&(st->flate), 9)) != Z_OK)
{ {
@ -567,11 +582,21 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
else else
st->predictor = _PDFIO_PREDICTOR_NONE; st->predictor = _PDFIO_PREDICTOR_NONE;
st->cbsize = 4096;
if ((st->cbuffer = malloc(st->cbsize)) == NULL)
{
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Flate compression buffer.", (unsigned long)st->cbsize);
free(st->prbuffer);
free(st->psbuffer);
free(st);
return (NULL);
}
PDFIO_DEBUG("_pdfioStreamOpen: pos=%ld\n", (long)_pdfioFileTell(st->pdf)); PDFIO_DEBUG("_pdfioStreamOpen: pos=%ld\n", (long)_pdfioFileTell(st->pdf));
if (sizeof(st->cbuffer) > st->remaining) if (st->cbsize > st->remaining)
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining); rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
else else
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer)); rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
if (rbytes <= 0) if (rbytes <= 0)
{ {
@ -1045,10 +1070,10 @@ stream_read(pdfio_stream_t *st, // I - Stream
if (st->flate.avail_in == 0) if (st->flate.avail_in == 0)
{ {
// Read more from the file... // Read more from the file...
if (sizeof(st->cbuffer) > st->remaining) if (st->cbsize > st->remaining)
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining); rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
else else
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer)); rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
if (rbytes <= 0) if (rbytes <= 0)
return (-1); // End of file... return (-1); // End of file...
@ -1101,10 +1126,10 @@ stream_read(pdfio_stream_t *st, // I - Stream
if (st->flate.avail_in == 0) if (st->flate.avail_in == 0)
{ {
// Read more from the file... // Read more from the file...
if (sizeof(st->cbuffer) > st->remaining) if (st->cbsize > st->remaining)
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining); rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
else else
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer)); rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
if (rbytes <= 0) if (rbytes <= 0)
return (-1); // End of file... return (-1); // End of file...
@ -1171,10 +1196,10 @@ stream_read(pdfio_stream_t *st, // I - Stream
if (st->flate.avail_in == 0) if (st->flate.avail_in == 0)
{ {
// Read more from the file... // Read more from the file...
if (sizeof(st->cbuffer) > st->remaining) if (st->cbsize > st->remaining)
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining); rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
else else
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, sizeof(st->cbuffer)); rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->cbsize);
if (rbytes <= 0) if (rbytes <= 0)
return (-1); // End of file... return (-1); // End of file...
@ -1278,10 +1303,10 @@ stream_write(pdfio_stream_t *st, // I - Stream
while (st->flate.avail_in > 0) while (st->flate.avail_in > 0)
{ {
if (st->flate.avail_out < (sizeof(st->cbuffer) / 8)) if (st->flate.avail_out < (st->cbsize / 8))
{ {
// Flush the compression buffer... // Flush the compression buffer...
size_t cbytes = sizeof(st->cbuffer) - st->flate.avail_out, size_t cbytes = st->cbsize - st->flate.avail_out,
outbytes; outbytes;
if (st->crypto_cb) if (st->crypto_cb)
@ -1310,7 +1335,7 @@ stream_write(pdfio_stream_t *st, // I - Stream
} }
st->flate.next_out = (Bytef *)st->cbuffer + cbytes; st->flate.next_out = (Bytef *)st->cbuffer + cbytes;
st->flate.avail_out = (uInt)(sizeof(st->cbuffer) - cbytes); st->flate.avail_out = (uInt)(st->cbsize - cbytes);
} }
// Deflate what we can this time... // Deflate what we can this time...