From e2e2192ea988f6a33715095b4297c382643b68f8 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Tue, 27 Apr 2021 21:22:34 -0400 Subject: [PATCH] Save work. --- TODO.md | 6 + pdfio-array.c | 56 ++++++--- pdfio-common.c | 69 ++++++++++-- pdfio-dict.c | 76 +++++++++---- pdfio-file.c | 293 ++++++++++++++++++++++++++++++++++++++++++++---- pdfio-object.c | 37 ++++-- pdfio-page.c | 11 +- pdfio-private.h | 88 +++++++++++---- pdfio-value.c | 119 +++++++++++++++++++- pdfio.h | 30 ++--- 10 files changed, 672 insertions(+), 113 deletions(-) create mode 100644 TODO.md diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..16134ff --- /dev/null +++ b/TODO.md @@ -0,0 +1,6 @@ +To-Do List +========== + +- Binary data/strings: needed for certain values, particular for the File ID + and user/owner passwords +- Copy methods for array, dict, object, page, value diff --git a/pdfio-array.c b/pdfio-array.c index 62c5fb2..55d0801 100644 --- a/pdfio-array.c +++ b/pdfio-array.c @@ -14,19 +14,6 @@ #include "pdfio-private.h" -// -// Array structure -// - -struct _pdfio_array_s -{ - pdfio_file_t *pdf; // PDF file - size_t num_values, // Number of values in use - alloc_values; // Number of allocated values - _pdfio_value_t *values; // Array of values -}; - - // // Local functions... // @@ -167,6 +154,21 @@ pdfioArrayAppendString( } +// +// 'pdfioArrayCopy()' - Copy an array. +// + +pdfio_array_t * // O - New array or `NULL` on error +pdfioArrayCopy(pdfio_file_t *pdf, // I - PDF file + pdfio_array_t *a) // I - Original array +{ + // TODO: Implement me + (void)pdf; + (void)a; + return (NULL); +} + + // // 'pdfioArrayCreate()' - Create an empty array. // @@ -365,6 +367,34 @@ _pdfioArrayGetValue(pdfio_array_t *a, // I - Array } +// +// '_pdfioArrayWrite()' - Write an array to a PDF file. +// + +bool // O - `true` on success, `false` otherwise +_pdfioArrayWrite(pdfio_array_t *a) // I - Array +{ + pdfio_file_t *pdf = a->pdf; // PDF file + size_t i; // Looping var + _pdfio_value_t *v; // Current value + + + // Arrays are surrounded by square brackets ([ ... ]) + if (!_pdfioFilePuts(pdf, "[")) + return (false); + + // Write each value... + for (i = a->num_values, v = a->values; i > 0; i --, v ++) + { + if (!_pdfioValueWrite(pdf, v)) + return (false); + } + + // Closing bracket... + return (_pdfioFilePuts(pdf, "]")); +} + + // // 'append_value()' - Append a value. // diff --git a/pdfio-common.c b/pdfio-common.c index 513ff9a..f74d919 100644 --- a/pdfio-common.c +++ b/pdfio-common.c @@ -65,6 +65,26 @@ _pdfioFileError(pdfio_file_t *pdf, // I - PDF file } +// +// '_pdfioFileFlush()' - Flush any pending write data. +// + +bool // O - `true` on success, `false` on failure +_pdfioFileFlush(pdfio_file_t *pdf) // I - PDF file +{ + if (pdf->bufptr > pdf->buffer) + { + if (!write_buffer(pdf, pdf->buffer, (size_t)(pdf->bufptr - pdf->buffer))) + return (false); + + pdf->bufpos += pdf->bufptr - pdf->buffer; + pdf->bufptr = pdf->buffer; + } + + return (true); +} + + // // '_pdfioFileGetChar()' - Get a character from a PDF file. // @@ -85,6 +105,42 @@ _pdfioFileGetChar(pdfio_file_t *pdf) // I - PDF file } +// +// '_pdfioFilePrintf()' - Write a formatted string to a PDF file. +// + +bool // O - `true` on success, `false` on failure +_pdfioFilePrintf(pdfio_file_t *pdf, // I - PDF file + const char *format, // I - `printf`-style format string + ...) // I - Additional arguments as needed +{ + char buffer[8102]; // String buffer + va_list ap; // Argument list + + + // Format the string... + va_start(ap, format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + // Write it... + return (_pdfioFileWrite(pdf, buffer, strlen(buffer))); +} + + +// +// '_pdfioFilePuts()' - Write a literal string to a PDF file. +// + +bool // O - `true` on success, `false` on failure +_pdfioFilePuts(pdfio_file_t *pdf, // I - PDF file + const char *s) // I - Literal string +{ + // Write it... + return (_pdfioFileWrite(pdf, s, strlen(s))); +} + + // // '_pdfioFileRead()' - Read from a PDF file. // @@ -152,7 +208,7 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file whence = SEEK_SET; } - if (pdf->mode == PDFIO_MODE_READ) + if (pdf->mode == _PDFIO_MODE_READ) { // Reading, see if we already have the data we need... if (whence != SEEK_END && offset >= pdf->bufpos && offset < (pdf->bufpos + pdf->bufend - pdf->buffer)) @@ -217,15 +273,8 @@ _pdfioFileWrite(pdfio_file_t *pdf, // I - PDF file if (bytes > (size_t)(pdf->bufend - pdf->bufptr)) { // No room, flush any current data... - if (pdf->bufptr > pdf->buffer) - { - if (!write_buffer(pdf, pdf->buffer, (size_t)(pdf->bufptr - pdf->buffer))) - return (false); - - pdf->bufpos += pdf->bufptr - pdf->buffer; - } - - pdf->bufptr = pdf->buffer; + if (!_pdfioFileFlush(pdf)) + return (false); if (bytes >= sizeof(pdf->buffer)) { diff --git a/pdfio-dict.c b/pdfio-dict.c index 04edbe4..2fa4fac 100644 --- a/pdfio-dict.c +++ b/pdfio-dict.c @@ -14,25 +14,6 @@ #include "pdfio-private.h" -// -// Dictionary structures -// - -typedef struct _pdfio_pair_s // Key/value pair -{ - const char *key; // Key string - _pdfio_value_t value; // Value -} _pdfio_pair_t; - -struct _pdfio_dict_s -{ - pdfio_file_t *pdf; // PDF file - size_t num_pairs, // Number of pairs in use - alloc_pairs; // Number of allocated pairs - _pdfio_pair_t *pairs; // Array of pairs -}; - - // // Local functions... // @@ -40,6 +21,21 @@ struct _pdfio_dict_s static int compare_pairs(_pdfio_pair_t *a, _pdfio_pair_t *b); +// +// 'pdfioDictCopy()' - Copy a dictionary to a PDF file. +// + +pdfio_dict_t * // O - New dictionary +pdfioDictCopy(pdfio_file_t *pdf, // I - PDF file + pdfio_dict_t *dict) // I - Original dictionary +{ + // TODO: Implement me + (void)pdf; + (void)dict; + return (NULL); +} + + // // 'pdfioDictCreate()' - Create a dictionary to hold key/value pairs. // @@ -531,6 +527,48 @@ _pdfioDictSetValue( } +// +// '_pdfioDictWrite()' - Write a dictionary to a PDF file. +// + +bool // O - `true` on success, `false` on failure +_pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary + off_t *length) // I - Offset to length value +{ + pdfio_file_t *pdf = dict->pdf; // PDF file + size_t i; // Looping var + _pdfio_pair_t *pair; // Current key/value pair + + + if (length) + *length = 0; + + // Dictionaries are bounded by "<<" and ">>"... + if (!_pdfioFilePuts(pdf, "<<")) + return (false); + + // Write all of the key/value pairs... + for (i = dict->num_pairs, pair = dict->pairs; i > 0; i --, pair ++) + { + if (!_pdfioFilePrintf(pdf, "/%s", pair->key)) + return (false); + + if (length && !strcmp(pair->key, "Length")) + { + // Writing an object dictionary with an undefined length + *length = _pdfioFileTell(pdf); + if (!_pdfioFilePuts(pdf, " 999999999")) + return (false); + } + else if (!_pdfioValueWrite(pdf, &pair->value)) + return (false); + } + + // Close it up... + return (_pdfioFilePuts(pdf, ">>")); +} + + // // 'compare_pairs()' - Compare the keys for two pairs. // diff --git a/pdfio-file.c b/pdfio-file.c index b5634b1..7924140 100644 --- a/pdfio-file.c +++ b/pdfio-file.c @@ -12,95 +12,348 @@ // #include "pdfio-private.h" +#ifndef O_BINARY +# define O_BINARY 0 +#endif // !O_BINARY // -// '()' - . +// Local functions... // -bool pdfioFileClose(pdfio_file_t *pdf) +static bool write_trailer(pdfio_file_t *pdf); + + +// +// 'pdfioFileClose()' - Close a PDF file and free all memory used for it. +// + +bool // O - `true` on success and `false` on failure +pdfioFileClose(pdfio_file_t *pdf) // I - PDF file { + bool ret = true; // Return value + size_t i; // Looping var + + + // Range check input + if (!pdf) + return (false); + + // Close the file itself... + if (pdf->mode == _PDFIO_MODE_WRITE) + ret = write_trailer(pdf); + + if (close(pdf->fd) < 0) + ret = false; + + // Free all data... + free(pdf->filename); + free(pdf->version); + + for (i = 0; i < pdf->num_arrays; i ++) + _pdfioArrayDelete(pdf->arrays[i]); + free(pdf->arrays); + + for (i = 0; i < pdf->num_dicts; i ++) + _pdfioDictDelete(pdf->dicts[i]); + free(pdf->dicts); + + for (i = 0; i < pdf->num_objs; i ++) + _pdfioObjDelete(pdf->objs[i]); + free(pdf->objs); + + free(pdf->pages); + + for (i = 0; i < pdf->num_strings; i ++) + free(pdf->strings[i]); + free(pdf->strings); + + free(pdf); + + return (ret); } // -// '()' - . +// 'pdfioFileCreate()' - Create a PDF file. // -pdfio_obj_t *pdfioFileCreateObject(pdfio_file_t *file, pdfio_dict_t *dict) +pdfio_file_t * // O - PDF file or `NULL` on error +pdfioFileCreate( + const char *filename, // I - Filename + const char *version, // I - PDF version number or `NULL` for default (2.0) + pdfio_error_cb_t error_cb, // I - Error callback or `NULL` for default + void *error_data) // I - Error callback data, if any { + pdfio_file_t *pdf; // PDF file + + + // Range check input... + if (!filename) + return (NULL); + + if (!version) + version = "2.0"; + + if (!error_cb) + { + error_cb = _pdfioFileDefaultError; + error_data = NULL; + } + + // Allocate a PDF file structure... + if ((pdf = (pdfio_file_t *)calloc(1, sizeof(pdfio_file_t))) == NULL) + { + pdfio_file_t temp; // Dummy file + char message[8192]; // Message string + + temp.filename = (char *)filename; + snprintf(message, sizeof(message), "Unable to allocate memory for PDF file - %s", strerror(errno)); + (error_cb)(&temp, message, error_data); + return (NULL); + } + + pdf->filename = strdup(filename); + pdf->version = strdup(version); + pdf->mode = _PDFIO_MODE_WRITE; + pdf->error_cb = error_cb; + pdf->error_data = error_data; + + // Create the file... + if ((pdf->fd = open(filename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0666)) < 0) + { + _pdfioFileError(pdf, "Unable to create file - %s", strerror(errno)); + free(pdf->filename); + free(pdf->version); + free(pdf); + return (NULL); + } + + // Write a standard PDF header... + if (!_pdfioFilePrintf(pdf, "%%PDF-%s\n%%\342\343\317\323\n", version)) + { + pdfioFileClose(pdf); + unlink(filename); + return (NULL); + } + + return (pdf); } // -// '()' - . +// 'pdfioFileCreateObject()' - Create a new object in a PDF file. // -pdfio_obj_t *pdfioFileCreatePage(pdfio_t *pdf, pdfio_dict_t *dict) +pdfio_obj_t * // O - New object +pdfioFileCreateObject( + pdfio_file_t *pdf, // I - PDF file + pdfio_dict_t *dict) // I - Object dictionary { + pdfio_obj_t *obj; // New object + + + // Range check input... + if (!pdf || !dict) + { + if (pdf) + _pdfioFileError(pdf, "Missing object dictionary."); + + return (NULL); + } + + if (dict->pdf != pdf) + dict = pdfioDictCopy(pdf, dict); // Copy dictionary to new PDF + + // Allocate memory for the object... + if ((obj = (pdfio_obj_t *)calloc(1, sizeof(pdfio_obj_t))) == NULL) + { + _pdfioFileError(pdf, "Unable to allocate memory for object - %s", strerror(errno)); + return (NULL); + } + + // Expand the objects array as needed + if (pdf->num_objs >= pdf->alloc_objs) + { + pdfio_obj_t **temp = (pdfio_obj_t **)realloc(pdf->objs, (pdf->alloc_objs + 32) * sizeof(pdfio_obj_t *)); + + if (!temp) + { + _pdfioFileError(pdf, "Unable to allocate memory for object - %s", strerror(errno)); + return (NULL); + } + + pdf->objs = temp; + pdf->alloc_objs += 32; + } + + pdf->objs[pdf->num_objs ++] = obj; + + // Initialize the object... + obj->pdf = pdf; + obj->number = pdf->num_objs; + obj->dict = dict; + obj->offset = _pdfioFileTell(pdf); + + // Don't write anything just yet... + return (obj); } // -// '()' - . +// 'pdfioFileCreatePage()' - Create a page in a PDF file. // -void _pdfioFileDelete(pdfio_file_t *file) +pdfio_obj_t * // O - New object +pdfioFileCreatePage(pdfio_file_t *pdf, // I - PDF file + pdfio_dict_t *dict) // I - Page dictionary { + // TODO: Implement me + (void)pdf; + (void)dict; + return (NULL); } // -// '()' - . +// 'pdfioFileGetName()' - Get a PDF's filename. // -const char *pdfioFileGetName(pdfio_file_t *pdf) +const char * // O - Filename +pdfioFileGetName(pdfio_file_t *pdf) // I - PDF file { + return (pdf ? pdf->filename : NULL); } // -// '()' - . +// 'pdfioFileGetNumObjects()' - Get the number of objects in a PDF file. // -int pdfioFileGetNumObjects(pdfio_file_t *pdf) +size_t // O - Number of objects +pdfioFileGetNumObjects( + pdfio_file_t *pdf) // I - PDF file { + return (pdf ? pdf->num_objs : 0); } // -// '()' - . +// 'pdfioFileGetNumPages()' - Get the number of pages in a PDF file. // -int pdfioFileGetNumPages(pdfio_file_t *pdf) +size_t // O - Number of pages +pdfioFileGetNumPages(pdfio_file_t *pdf) // I - PDF file { + return (pdf ? pdf->num_pages : 0); } // -// '()' - . +// 'pdfioFileGetObject()' - Get an object from a PDF file. // -pdfio_obj_t *pdfioFileGetObject(pdfio_file_t *pdf, int number) +pdfio_obj_t * // O - Object +pdfioFileGetObject(pdfio_file_t *pdf, // I - PDF file + size_t number) // I - Object number (starting at 1) { + if (!pdf || number < 1 || number > pdf->num_objs) + return (NULL); + else + return (pdf->objs[number - 1]); } // -// '()' - . +// 'pdfioFileGetPage()' - Get a page object from a PDF file. // -pdfio_obj_t *pdfioFileGetPage(pdfio_file_t *pdf, int number) +pdfio_obj_t * // O - Object +pdfioFileGetPage(pdfio_file_t *pdf, // I - PDF file + size_t number) // I - Page number (starting at 1) { + if (!pdf || number < 1 || number > pdf->num_pages) + return (NULL); + else + return (pdf->pages[number - 1]); } // -// '()' - . +// '()' - Get the PDF version number for a PDF file. // -pdfio_file_t *pdfioFileOpen(const char *filename, const char *mode, pdfio_error_cb_t error_cb, void *error_data) +const char * // O - Version number or `NULL` +pdfioFileGetVersion( + pdfio_file_t *pdf) // I - PDF file { + return (pdf ? pdf->version : NULL); } +// +// 'pdfioFileOpen()' - Open a PDF file for reading. +// + +pdfio_file_t * // O - PDF file +pdfioFileOpen( + const char *filename, // I - Filename + pdfio_error_cb_t error_cb, // I - Error callback or `NULL` for default + void *error_data) // I - Error callback data, if any +{ + pdfio_file_t *pdf; // PDF file + + + // Range check input... + if (!filename) + return (NULL); + + if (!error_cb) + { + error_cb = _pdfioFileDefaultError; + error_data = NULL; + } + + // Allocate a PDF file structure... + if ((pdf = (pdfio_file_t *)calloc(1, sizeof(pdfio_file_t))) == NULL) + { + pdfio_file_t temp; // Dummy file + char message[8192]; // Message string + + temp.filename = (char *)filename; + snprintf(message, sizeof(message), "Unable to allocate memory for PDF file - %s", strerror(errno)); + (error_cb)(&temp, message, error_data); + return (NULL); + } + + pdf->filename = strdup(filename); + pdf->mode = _PDFIO_MODE_READ; + pdf->error_cb = error_cb; + pdf->error_data = error_data; + + // Open the file... + if ((pdf->fd = open(filename, O_RDONLY | O_BINARY)) < 0) + { + _pdfioFileError(pdf, "Unable to open file - %s", strerror(errno)); + free(pdf->filename); + free(pdf); + return (NULL); + } + + // TODO: read header, trailer, and xref table... + return (pdf); +} + + +// +// 'write_trailer()' - Write the PDF catalog object, xref table, and trailer. +// + +static bool // O - `true` on success, `false` on failure +write_trailer(pdfio_file_t *pdf) // I - PDF file +{ + // TODO: Write trailer + (void)pdf; + + return (false); +} diff --git a/pdfio-object.c b/pdfio-object.c index 8559ca6..f85ed39 100644 --- a/pdfio-object.c +++ b/pdfio-object.c @@ -14,8 +14,6 @@ #include "pdfio-private.h" - - // // 'pdfioObjClose()' - Close an object, writing any data as needed to the PDF // file. @@ -24,6 +22,9 @@ bool // O - `true` on success, `false` on failure pdfioObjClose(pdfio_obj_t *obj) // I - Object { + // TODO: Implement me + (void)obj; + return (false); } @@ -37,6 +38,11 @@ pdfioObjCreateStream( pdfio_obj_t *obj, // I - Object pdfio_filter_t filter) // I - Type of compression to apply { + // TODO: Implement me + (void)obj; + (void)filter; + + return (NULL); } @@ -45,7 +51,7 @@ pdfioObjCreateStream( // void -_pdfioObjDelete(pdfio_object_t *obj) // I - Object +_pdfioObjDelete(pdfio_obj_t *obj) // I - Object { if (obj) pdfioStreamClose(obj->stream); @@ -69,29 +75,38 @@ pdfioObjGetDict(pdfio_obj_t *obj) // I - Object // -// '()' - . +// 'pdfioObjGetGeneration()' - Get the object's generation number. // -int pdfioObjGetGeneration(pdfio_obj_t *obj) +size_t // O - Generation number (0 to 65535) +pdfioObjGetGeneration(pdfio_obj_t *obj) // I - Object { + return (obj ? obj->generation : 0); } // -// '()' - . +// 'pdfioObjGetNumber()' - Get the object's number. // -int pdfioObjGetNumber(pdfio_obj_t *obj) +size_t // O - Object number (1 to 9999999999) +pdfioObjGetNumber(pdfio_obj_t *obj) // I - Object { + return (obj ? obj->number : 0); } // -// '()' - . +// 'pdfioObjGetType()' - Get an object's type. // -const char *pdfioObjGetType(pdfio_obj_t *obj) +const char * // O - Object type +pdfioObjGetType(pdfio_obj_t *obj) // I - Object { + // TODO: Implement me + (void)obj; + + return (NULL); } @@ -102,4 +117,8 @@ const char *pdfioObjGetType(pdfio_obj_t *obj) pdfio_stream_t * // O - Stream or `NULL` on error pdfioObjOpenStream(pdfio_obj_t *obj) // I - Object { + // TODO: Implement me + (void)obj; + + return (NULL); } diff --git a/pdfio-page.c b/pdfio-page.c index c9b0b99..5e2ed05 100644 --- a/pdfio-page.c +++ b/pdfio-page.c @@ -15,9 +15,16 @@ // -// '()' - . +// 'pdfioPageCopy()' - Copy a page to a PDF file. // -pdfio_obj_t *pdfioPageCopy(pdfio_t *pdf, pdfio_obj_t *src) +pdfio_obj_t * // O - Destination page +pdfioPageCopy(pdfio_file_t *pdf, // I - PDF file + pdfio_obj_t *src) // I - Source page { + // TODO: Implement me + (void)pdf; + (void)src; + + return (NULL); } diff --git a/pdfio-private.h b/pdfio-private.h index befec65..3cb0797 100644 --- a/pdfio-private.h +++ b/pdfio-private.h @@ -56,10 +56,60 @@ // Types and constants... // +typedef enum _pdfio_mode_e // Read/write mode +{ + _PDFIO_MODE_READ, // Read a PDF file + _PDFIO_MODE_WRITE // Write a PDF file +} _pdfio_mode_t; + +typedef struct _pdfio_value_s // Value structure +{ + pdfio_valtype_t type; // Type of value + union + { + pdfio_array_t *array; // Array value + struct + { + unsigned char *data; // Data + size_t datalen; // Length + } binary; // Binary ("Hex String") data + bool boolean; // Boolean value + time_t date; // Date/time value + pdfio_dict_t *dict; // Dictionary value + pdfio_obj_t *obj; // Indirect object (N G obj) value + const char *name; // Name value + float number; // Number value + const char *string; // String value + } value; // Value union +} _pdfio_value_t; + +struct _pdfio_array_s +{ + pdfio_file_t *pdf; // PDF file + size_t num_values, // Number of values in use + alloc_values; // Number of allocated values + _pdfio_value_t *values; // Array of values +}; + +typedef struct _pdfio_pair_s // Key/value pair +{ + const char *key; // Key string + _pdfio_value_t value; // Value +} _pdfio_pair_t; + +struct _pdfio_dict_s +{ + pdfio_file_t *pdf; // PDF file + size_t num_pairs, // Number of pairs in use + alloc_pairs; // Number of allocated pairs + _pdfio_pair_t *pairs; // Array of pairs +}; + struct _pdfio_file_s // PDF file structure { - const char *filename; // Filename - pdfio_mode_t mode; // Read/write mode + char *filename; // Filename + char *version; // Version number + _pdfio_mode_t mode; // Read/write mode pdfio_error_cb_t error_cb; // Error callback void *error_data; // Data for error callback @@ -80,6 +130,9 @@ struct _pdfio_file_s // PDF file structure size_t num_objs, // Number of objects alloc_objs; // Allocated objects pdfio_obj_t **objs; // Objects + size_t num_pages, // Number of pages + alloc_pages; // Allocated pages + pdfio_obj_t **pages; // Pages size_t num_strings, // Number of strings alloc_strings; // Allocated strings char **strings; // Nul-terminated strings @@ -88,10 +141,10 @@ struct _pdfio_file_s // PDF file structure struct _pdfio_obj_s // Object { pdfio_file_t *pdf; // PDF file - int number, // Number + size_t number, // Number generation; // Generation - off_t dict_offset, // Offset to dict in file - length_offset, // Offset to /Length in dict + off_t offset, // Offset to object in file + length_offset, // Offset to /Length in object dict stream_offset; // Offset to start of stream in file size_t stream_length; // Length of stream, if any pdfio_dict_t *dict; // Dictionary @@ -108,22 +161,6 @@ struct _pdfio_stream_s // Stream z_stream flate; // Flate filter state }; -typedef struct _pdfio_value_s // Value structure -{ - pdfio_valtype_t type; // Type of value - union - { - pdfio_array_t *array; // Array value - bool boolean; // Boolean value - time_t date; // Date/time value - pdfio_dict_t *dict; // Dictionary value - pdfio_obj_t *obj; // Indirect object (N G obj) value - const char *name; // Name value - float number; // Number value - const char *string; // String value - } value; // Value union -} _pdfio_value_t; - // // Functions... @@ -131,15 +168,19 @@ typedef struct _pdfio_value_s // Value structure extern void _pdfioArrayDelete(pdfio_array_t *a) PDFIO_INTERNAL; extern _pdfio_value_t *_pdfioArrayGetValue(pdfio_array_t *a, size_t n) PDFIO_INTERNAL; +extern bool _pdfioArrayWrite(pdfio_array_t *a) 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 bool _pdfioDictSetValue(pdfio_dict_t *dict, const char *key, _pdfio_value_t *value) PDFIO_INTERNAL; +extern bool _pdfioDictWrite(pdfio_dict_t *dict, off_t *length) PDFIO_INTERNAL; extern bool _pdfioFileDefaultError(pdfio_file_t *pdf, const char *message, void *data) PDFIO_INTERNAL; -extern void _pdfioFileDelete(pdfio_file_t *pdf) PDFIO_INTERNAL; extern bool _pdfioFileError(pdfio_file_t *pdf, const char *format, ...) PDFIO_FORMAT(2,3) PDFIO_INTERNAL; +extern bool _pdfioFileFlush(pdfio_file_t *pdf) PDFIO_INTERNAL; extern int _pdfioFileGetChar(pdfio_file_t *pdf) PDFIO_INTERNAL; +extern bool _pdfioFilePrintf(pdfio_file_t *pdf, const char *format, ...) PDFIO_FORMAT(2,3) PDFIO_INTERNAL; +extern bool _pdfioFilePuts(pdfio_file_t *pdf, const char *s) PDFIO_INTERNAL; extern ssize_t _pdfioFileRead(pdfio_file_t *pdf, char *buffer, size_t bytes) PDFIO_INTERNAL; extern off_t _pdfioFileSeek(pdfio_file_t *pdf, off_t offset, int whence) PDFIO_INTERNAL; extern off_t _pdfioFileTell(pdfio_file_t *pdf) PDFIO_INTERNAL; @@ -151,7 +192,8 @@ extern void _pdfioStreamDelete(pdfio_stream_t *obj) PDFIO_INTERNAL; extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) 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 void _pdfioValueDelete(_pdfio_value_t *v) PDFIO_INTERNAL; - +extern bool _pdfioValueWrite(pdfio_file_t *pdf, _pdfio_value_t *v) PDFIO_INTERNAL; #endif // !PDFIO_PRIVATE_H diff --git a/pdfio-value.c b/pdfio-value.c index dae24b7..115b13a 100644 --- a/pdfio-value.c +++ b/pdfio-value.c @@ -15,11 +15,126 @@ // -// '()' - . +// '_pdfioValueCopy()' - Copy a value to a PDF file. // -void _pdfioValueDelete(pdfio_value_t *v) +_pdfio_value_t * +_pdfioValueCopy(pdfio_file_t *pdfdst, // I - Destination PDF file + _pdfio_value_t *vdst, // I - Destination value + pdfio_file_t *pdfsrc, // I - Source PDF file + _pdfio_value_t *vsrc) // I - Source value { + // TODO: Implement me + (void)pdfdst; + (void)vdst; + (void)pdfsrc; + (void)vsrc; + + return (NULL); } +// +// '_pdfioValueDelete()' - Free the memory used by a value. +// + +void +_pdfioValueDelete(_pdfio_value_t *v) // I - Value +{ + // TODO: Implement me + (void)v; +} + + +// +// '_pdfioValueWrite()' - Write a value to a PDF file. +// + +bool // O - `true` on success, `false` on failure +_pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file + _pdfio_value_t *v) // I - Value +{ + switch (v->type) + { + default : + return (false); + + case PDFIO_VALTYPE_ARRAY : + return (_pdfioArrayWrite(v->value.array)); + + case PDFIO_VALTYPE_BINARY : + // TODO: Implement binary value support + return (false); + case PDFIO_VALTYPE_BOOLEAN : + if (v->value.boolean) + return (_pdfioFilePuts(pdf, " true")); + else + return (_pdfioFilePuts(pdf, " false")); + + case PDFIO_VALTYPE_DATE : + // TODO: Implement date value support + break; + + case PDFIO_VALTYPE_DICT : + return (_pdfioDictWrite(v->value.dict, NULL)); + + case PDFIO_VALTYPE_INDIRECT : + return (_pdfioFilePrintf(pdf, " %lu %lu obj", (unsigned long)v->value.obj->number, (unsigned long)v->value.obj->generation)); + + case PDFIO_VALTYPE_NAME : + return (_pdfioFilePrintf(pdf, "/%s", v->value.name)); + + case PDFIO_VALTYPE_NULL : + return (_pdfioFilePuts(pdf, " null")); + + case PDFIO_VALTYPE_NUMBER : + return (_pdfioFilePrintf(pdf, " %g", v->value.number)); + + case PDFIO_VALTYPE_STRING : + { + const char *start, // Start of fragment + *end; // End of fragment + + if (!_pdfioFilePuts(pdf, "(")) + return (false); + + // Write a quoted string value... + for (start = v->value.string; *start; start = end) + { + // Find the next character that needs to be quoted... + for (end = start; *end; end ++) + { + if (*end == '\\' || *end == ')' || (*end & 255) < ' ') + break; + } + + if (end > start) + { + // Write unquoted (safe) characters... + if (!_pdfioFileWrite(pdf, start, (size_t)(end - start))) + return (false); + } + + if (*end) + { + // Quote this character... + bool success; // Did the write work? + + if (*end == '\\' || *end == ')') + success = _pdfioFilePrintf(pdf, "\\%c", *end); + else + success = _pdfioFilePrintf(pdf, "\\%03o", *end); + + if (!success) + return (false); + + end ++; + } + } + + return (_pdfioFilePuts(pdf, ")")); + } + } + + return (false); +} diff --git a/pdfio.h b/pdfio.h index 5041d4f..eaeeed0 100644 --- a/pdfio.h +++ b/pdfio.h @@ -60,11 +60,6 @@ typedef enum pdfio_filter_e // Compression/decompression filters for streams PDFIO_FILTER_NONE, // No filter PDFIO_FILTER_FLATE // Flate filter } pdfio_filter_t; -typedef enum pdfio_mode_e // Read/write mode -{ - PDFIO_MODE_READ, // Read a PDF file - PDFIO_MODE_WRITE // Write a PDF file -} pdfio_mode_t; typedef struct _pdfio_obj_s pdfio_obj_t;// Numbered object in PDF file typedef struct pdfio_rect_s // PDF rectangle { @@ -79,6 +74,7 @@ typedef enum pdfio_valtype_e // PDF value types { PDFIO_VALTYPE_NONE, // No value, not set PDFIO_VALTYPE_ARRAY, // Array + PDFIO_VALTYPE_BINARY, // Binary data PDFIO_VALTYPE_BOOLEAN, // Boolean PDFIO_VALTYPE_DATE, // Date/time PDFIO_VALTYPE_DICT, // Dictionary @@ -103,7 +99,8 @@ extern bool pdfioArrayAppendName(pdfio_array_t *a, const char *value) PDFIO_PUB extern bool pdfioArrayAppendNumber(pdfio_array_t *a, float value) PDFIO_PUBLIC; extern bool pdfioArrayAppendObject(pdfio_array_t *a, pdfio_obj_t *value) PDFIO_PUBLIC; extern bool pdfioArrayAppendString(pdfio_array_t *a, const char *value) PDFIO_PUBLIC; -extern pdfio_array_t *pdfioArrayCreate(pdfio_file_t *file) PDFIO_PUBLIC; +extern pdfio_array_t *pdfioArrayCopy(pdfio_file_t *pdf, pdfio_array_t *a) PDFIO_PUBLIC; +extern pdfio_array_t *pdfioArrayCreate(pdfio_file_t *pdf) PDFIO_PUBLIC; extern pdfio_array_t *pdfioArrayGetArray(pdfio_array_t *a, size_t n) PDFIO_PUBLIC; extern bool pdfioArrayGetBoolean(pdfio_array_t *a, size_t n) PDFIO_PUBLIC; extern pdfio_dict_t *pdfioArrayGetDict(pdfio_array_t *a, size_t n) PDFIO_PUBLIC; @@ -114,7 +111,8 @@ extern size_t pdfioArrayGetSize(pdfio_array_t *a) PDFIO_PUBLIC; extern const char *pdfioArrayGetString(pdfio_array_t *a, size_t n) PDFIO_PUBLIC; extern pdfio_valtype_t pdfioArrayGetType(pdfio_array_t *a, size_t n) PDFIO_PUBLIC; -extern pdfio_dict_t *pdfioDictCreate(pdfio_file_t *file) PDFIO_PUBLIC; +extern pdfio_dict_t *pdfioDictCopy(pdfio_file_t *pdf, pdfio_dict_t *dict) PDFIO_PUBLIC; +extern pdfio_dict_t *pdfioDictCreate(pdfio_file_t *pdf) PDFIO_PUBLIC; extern pdfio_array_t *pdfioDictGetArray(pdfio_dict_t *dict, const char *name) PDFIO_PUBLIC; extern bool pdfioDictGetBoolean(pdfio_dict_t *dict, const char *name) PDFIO_PUBLIC; extern pdfio_dict_t *pdfioDictGetDict(pdfio_dict_t *dict, const char *name) PDFIO_PUBLIC; @@ -136,20 +134,22 @@ extern bool pdfioDictSetString(pdfio_dict_t *dict, const char *name, const char extern bool pdfioDictSetStringf(pdfio_dict_t *dict, const char *name, const char *format, ...) PDFIO_PUBLIC PDFIO_FORMAT(3,4); extern bool pdfioFileClose(pdfio_file_t *pdf) PDFIO_PUBLIC; -extern pdfio_obj_t *pdfioFileCreateObject(pdfio_file_t *file, pdfio_dict_t *dict) PDFIO_PUBLIC; +extern pdfio_file_t *pdfioFileCreate(const char *filename, const char *version, pdfio_error_cb_t error_cb, void *error_data) PDFIO_PUBLIC; +extern pdfio_obj_t *pdfioFileCreateObject(pdfio_file_t *pdf, pdfio_dict_t *dict) PDFIO_PUBLIC; extern pdfio_obj_t *pdfioFileCreatePage(pdfio_file_t *pdf, pdfio_dict_t *dict) PDFIO_PUBLIC; extern const char *pdfioFileGetName(pdfio_file_t *pdf) PDFIO_PUBLIC; -extern unsigned pdfioFileGetNumObjects(pdfio_file_t *pdf) PDFIO_PUBLIC; -extern unsigned pdfioFileGetNumPages(pdfio_file_t *pdf) PDFIO_PUBLIC; -extern pdfio_obj_t *pdfioFileGetObject(pdfio_file_t *pdf, unsigned number) PDFIO_PUBLIC; -extern pdfio_obj_t *pdfioFileGetPage(pdfio_file_t *pdf, unsigned number) PDFIO_PUBLIC; -extern pdfio_file_t *pdfioFileOpen(const char *filename, pdfio_mode_t mode, pdfio_error_cb_t error_cb, void *error_data) PDFIO_PUBLIC; +extern size_t pdfioFileGetNumObjects(pdfio_file_t *pdf) PDFIO_PUBLIC; +extern size_t pdfioFileGetNumPages(pdfio_file_t *pdf) PDFIO_PUBLIC; +extern pdfio_obj_t *pdfioFileGetObject(pdfio_file_t *pdf, size_t number) PDFIO_PUBLIC; +extern pdfio_obj_t *pdfioFileGetPage(pdfio_file_t *pdf, size_t number) PDFIO_PUBLIC; +extern const char *pdfioFileGetVersion(pdfio_file_t *pdf) PDFIO_PUBLIC; +extern pdfio_file_t *pdfioFileOpen(const char *filename, pdfio_error_cb_t error_cb, void *error_data) PDFIO_PUBLIC; extern bool pdfioObjClose(pdfio_obj_t *obj) PDFIO_PUBLIC; extern pdfio_stream_t *pdfioObjCreateStream(pdfio_obj_t *obj, pdfio_filter_t compression) PDFIO_PUBLIC; extern pdfio_dict_t *pdfioObjGetDict(pdfio_obj_t *obj) PDFIO_PUBLIC; -extern unsigned pdfioObjGetGeneration(pdfio_obj_t *obj) PDFIO_PUBLIC; -extern unsigned pdfioObjGetNumber(pdfio_obj_t *obj) PDFIO_PUBLIC; +extern size_t pdfioObjGetGeneration(pdfio_obj_t *obj) PDFIO_PUBLIC; +extern size_t pdfioObjGetNumber(pdfio_obj_t *obj) PDFIO_PUBLIC; extern const char *pdfioObjGetType(pdfio_obj_t *obj) PDFIO_PUBLIC; extern pdfio_stream_t *pdfioObjOpenStream(pdfio_obj_t *obj) PDFIO_PUBLIC;