mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-02-26 13:52:49 +01:00
Add xref stream support (Issue #10)
This commit is contained in:
parent
8d72f22efe
commit
aeee24b856
@ -6,6 +6,8 @@ v1.5.0 - YYYY-MM-DD
|
|||||||
|
|
||||||
- Added support for embedded color profiles in JPEG images (Issue #7)
|
- Added support for embedded color profiles in JPEG images (Issue #7)
|
||||||
- Added `pdfioFileCreateICCObjFromData` API.
|
- Added `pdfioFileCreateICCObjFromData` API.
|
||||||
|
- Added support for writing cross-reference streams for PDF 1.5 and newer files
|
||||||
|
(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)
|
||||||
- Now support opening damaged PDF files (Issue #45)
|
- Now support opening damaged PDF files (Issue #45)
|
||||||
|
225
pdfio-file.c
225
pdfio-file.c
@ -2358,59 +2358,214 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
|
|||||||
bool ret = true; // Return value
|
bool ret = true; // Return value
|
||||||
off_t xref_offset; // Offset to xref table
|
off_t xref_offset; // Offset to xref table
|
||||||
size_t i; // Looping var
|
size_t i; // Looping var
|
||||||
|
pdfio_obj_t *obj; // Current object
|
||||||
|
|
||||||
|
|
||||||
// Write the xref table...
|
// Write the xref table...
|
||||||
// TODO: Look at adding support for xref streams...
|
|
||||||
xref_offset = _pdfioFileTell(pdf);
|
xref_offset = _pdfioFileTell(pdf);
|
||||||
|
|
||||||
if (!_pdfioFilePrintf(pdf, "xref\n0 %lu \n0000000000 65535 f \n", (unsigned long)pdf->num_objs + 1))
|
// TODO: Figure out how to do xref streams with encrypted output
|
||||||
|
if (strcmp(pdf->version, "1.5") >= 0 && !pdf->output_cb && !pdf->encrypt_obj)
|
||||||
{
|
{
|
||||||
_pdfioFileError(pdf, "Unable to write cross-reference table.");
|
// Write a cross-reference stream...
|
||||||
ret = false;
|
pdfio_dict_t *xref_dict; // Object dictionary
|
||||||
goto done;
|
pdfio_array_t *w_array; // W array
|
||||||
}
|
pdfio_obj_t *xref_obj; // Object
|
||||||
|
pdfio_stream_t *xref_st; // Stream
|
||||||
|
int offsize; // Size of object offsets
|
||||||
|
unsigned char buffer[10]; // Buffer entry
|
||||||
|
|
||||||
for (i = 0; i < pdf->num_objs; i ++)
|
// Figure out how many bytes are needed for the object numbers
|
||||||
{
|
if (xref_offset < 0xff)
|
||||||
pdfio_obj_t *obj = pdf->objs[i]; // Current object
|
offsize = 1;
|
||||||
|
else if (xref_offset < 0xffff)
|
||||||
|
offsize = 2;
|
||||||
|
else if (xref_offset < 0xffffff)
|
||||||
|
offsize = 3;
|
||||||
|
else if (xref_offset < 0xffffffff)
|
||||||
|
offsize = 4;
|
||||||
|
else if (xref_offset < 0xffffffffff)
|
||||||
|
offsize = 5;
|
||||||
|
else if (xref_offset < 0xffffffffffff)
|
||||||
|
offsize = 6;
|
||||||
|
else if (xref_offset < 0xffffffffffffff)
|
||||||
|
offsize = 7;
|
||||||
|
else
|
||||||
|
offsize = 8;
|
||||||
|
|
||||||
if (!_pdfioFilePrintf(pdf, "%010lu %05u n \n", (unsigned long)obj->offset, obj->generation))
|
// Create the object...
|
||||||
|
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
|
||||||
{
|
{
|
||||||
_pdfioFileError(pdf, "Unable to write cross-reference table.");
|
_pdfioFileError(pdf, "Unable to write cross-reference table.");
|
||||||
ret = false;
|
ret = false;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pdfioArrayAppendNumber(w_array, 1);
|
||||||
|
pdfioArrayAppendNumber(w_array, offsize);
|
||||||
|
pdfioArrayAppendNumber(w_array, 1);
|
||||||
|
|
||||||
|
if ((xref_dict = pdfioDictCreate(pdf)) == NULL)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to write cross-reference table.");
|
||||||
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioDictSetName(xref_dict, "Type", "XRef");
|
||||||
|
pdfioDictSetNumber(xref_dict, "Size", pdf->num_objs + 2);
|
||||||
|
pdfioDictSetArray(xref_dict, "W", w_array);
|
||||||
|
pdfioDictSetName(xref_dict, "Filter", "FlateDecode");
|
||||||
|
|
||||||
|
if (pdf->encrypt_obj)
|
||||||
|
pdfioDictSetObj(xref_dict, "Encrypt", pdf->encrypt_obj);
|
||||||
|
if (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)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to write cross-reference table.");
|
||||||
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((xref_st = pdfioObjCreateStream(xref_obj, PDFIO_FILTER_FLATE)) == NULL)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to write cross-reference table.");
|
||||||
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the "free" 0 object...
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
pdfioStreamWrite(xref_st, buffer, offsize + 2);
|
||||||
|
|
||||||
|
// Then write the "allocated" objects...
|
||||||
|
buffer[0] = 1;
|
||||||
|
|
||||||
|
for (i = 0; i < pdf->num_objs; i ++)
|
||||||
|
{
|
||||||
|
obj = pdf->objs[i]; // Current object
|
||||||
|
|
||||||
|
switch (offsize)
|
||||||
|
{
|
||||||
|
case 1 :
|
||||||
|
buffer[1] = obj->offset & 255;
|
||||||
|
break;
|
||||||
|
case 2 :
|
||||||
|
buffer[1] = (obj->offset >> 8) & 255;
|
||||||
|
buffer[2] = obj->offset & 255;
|
||||||
|
break;
|
||||||
|
case 3 :
|
||||||
|
buffer[1] = (obj->offset >> 16) & 255;
|
||||||
|
buffer[2] = (obj->offset >> 8) & 255;
|
||||||
|
buffer[3] = obj->offset & 255;
|
||||||
|
break;
|
||||||
|
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;
|
||||||
|
case 5 :
|
||||||
|
buffer[1] = (obj->offset >> 32) & 255;
|
||||||
|
buffer[2] = (obj->offset >> 24) & 255;
|
||||||
|
buffer[3] = (obj->offset >> 16) & 255;
|
||||||
|
buffer[4] = (obj->offset >> 8) & 255;
|
||||||
|
buffer[5] = obj->offset & 255;
|
||||||
|
break;
|
||||||
|
case 6 :
|
||||||
|
buffer[1] = (obj->offset >> 40) & 255;
|
||||||
|
buffer[2] = (obj->offset >> 32) & 255;
|
||||||
|
buffer[3] = (obj->offset >> 24) & 255;
|
||||||
|
buffer[4] = (obj->offset >> 16) & 255;
|
||||||
|
buffer[5] = (obj->offset >> 8) & 255;
|
||||||
|
buffer[6] = obj->offset & 255;
|
||||||
|
break;
|
||||||
|
case 7 :
|
||||||
|
buffer[1] = (obj->offset >> 48) & 255;
|
||||||
|
buffer[2] = (obj->offset >> 40) & 255;
|
||||||
|
buffer[3] = (obj->offset >> 32) & 255;
|
||||||
|
buffer[4] = (obj->offset >> 24) & 255;
|
||||||
|
buffer[5] = (obj->offset >> 16) & 255;
|
||||||
|
buffer[6] = (obj->offset >> 8) & 255;
|
||||||
|
buffer[7] = obj->offset & 255;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
buffer[1] = (obj->offset >> 56) & 255;
|
||||||
|
buffer[2] = (obj->offset >> 48) & 255;
|
||||||
|
buffer[3] = (obj->offset >> 40) & 255;
|
||||||
|
buffer[4] = (obj->offset >> 32) & 255;
|
||||||
|
buffer[5] = (obj->offset >> 24) & 255;
|
||||||
|
buffer[6] = (obj->offset >> 16) & 255;
|
||||||
|
buffer[7] = (obj->offset >> 8) & 255;
|
||||||
|
buffer[8] = obj->offset & 255;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pdfioStreamWrite(xref_st, buffer, offsize + 2))
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to write cross-reference table.");
|
||||||
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioStreamClose(xref_st);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// Write the trailer...
|
|
||||||
if (!_pdfioFilePuts(pdf, "trailer\n"))
|
|
||||||
{
|
{
|
||||||
_pdfioFileError(pdf, "Unable to write trailer.");
|
// Write a cross-reference table...
|
||||||
ret = false;
|
if (!_pdfioFilePrintf(pdf, "xref\n0 %lu \n0000000000 65535 f \n", (unsigned long)pdf->num_objs + 1))
|
||||||
goto done;
|
{
|
||||||
}
|
_pdfioFileError(pdf, "Unable to write cross-reference table.");
|
||||||
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if ((pdf->trailer_dict = pdfioDictCreate(pdf)) == NULL)
|
for (i = 0; i < pdf->num_objs; i ++)
|
||||||
{
|
{
|
||||||
_pdfioFileError(pdf, "Unable to create trailer.");
|
obj = pdf->objs[i]; // Current object
|
||||||
ret = false;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pdf->encrypt_obj)
|
if (!_pdfioFilePrintf(pdf, "%010lu %05u n \n", (unsigned long)obj->offset, obj->generation))
|
||||||
pdfioDictSetObj(pdf->trailer_dict, "Encrypt", pdf->encrypt_obj);
|
{
|
||||||
if (pdf->id_array)
|
_pdfioFileError(pdf, "Unable to write cross-reference table.");
|
||||||
pdfioDictSetArray(pdf->trailer_dict, "ID", pdf->id_array);
|
ret = false;
|
||||||
pdfioDictSetObj(pdf->trailer_dict, "Info", pdf->info_obj);
|
goto done;
|
||||||
pdfioDictSetObj(pdf->trailer_dict, "Root", pdf->root_obj);
|
}
|
||||||
pdfioDictSetNumber(pdf->trailer_dict, "Size", pdf->num_objs + 1);
|
}
|
||||||
|
|
||||||
if (!_pdfioDictWrite(pdf->trailer_dict, NULL, NULL))
|
// Write the trailer...
|
||||||
{
|
if (!_pdfioFilePuts(pdf, "trailer\n"))
|
||||||
_pdfioFileError(pdf, "Unable to write trailer.");
|
{
|
||||||
ret = false;
|
_pdfioFileError(pdf, "Unable to write trailer.");
|
||||||
goto done;
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pdf->trailer_dict = pdfioDictCreate(pdf)) == NULL)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to create trailer.");
|
||||||
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdf->encrypt_obj)
|
||||||
|
pdfioDictSetObj(pdf->trailer_dict, "Encrypt", pdf->encrypt_obj);
|
||||||
|
if (pdf->id_array)
|
||||||
|
pdfioDictSetArray(pdf->trailer_dict, "ID", pdf->id_array);
|
||||||
|
pdfioDictSetObj(pdf->trailer_dict, "Info", pdf->info_obj);
|
||||||
|
pdfioDictSetObj(pdf->trailer_dict, "Root", pdf->root_obj);
|
||||||
|
pdfioDictSetNumber(pdf->trailer_dict, "Size", pdf->num_objs + 1);
|
||||||
|
|
||||||
|
if (!_pdfioDictWrite(pdf->trailer_dict, NULL, NULL))
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to write trailer.");
|
||||||
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_pdfioFilePrintf(pdf, "\nstartxref\n%lu\n%%EOF\n", (unsigned long)xref_offset))
|
if (!_pdfioFilePrintf(pdf, "\nstartxref\n%lu\n%%EOF\n", (unsigned long)xref_offset))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user