From a37455c00959be7520cb316d98550d7b48efdf57 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Sun, 18 Jan 2026 19:51:56 -0500 Subject: [PATCH] Add _pdfioStringPrintf function and support for using a string buffer to collect an object's value (Issue #101) --- pdfio-private.h | 7 ++++-- pdfio-string.c | 58 +++++++++++++++++++++++++++++++++++++++++++------ pdfio-value.c | 10 ++++----- 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/pdfio-private.h b/pdfio-private.h index a1841eb..9029154 100644 --- a/pdfio-private.h +++ b/pdfio-private.h @@ -277,9 +277,11 @@ typedef struct _pdfio_objmap_s // PDF object map typedef struct _pdfio_strbuf_s // PDF string buffer { struct _pdfio_strbuf_s *next; // Next string buffer + pdfio_file_t *pdf; // PDF file bool bufused; // Is this string buffer being used? - char buffer[PDFIO_MAX_STRING + 32]; + char buffer[PDFIO_MAX_STRING + 32], // String buffer + *bufptr; // Pointer into buffer } _pdfio_strbuf_t; struct _pdfio_file_s // PDF file structure @@ -468,9 +470,10 @@ extern bool _pdfioObjWriteHeader(pdfio_obj_t *obj) _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 char *_pdfioStringAllocBuffer(pdfio_file_t *pdf); +extern char *_pdfioStringAllocBuffer(pdfio_file_t *pdf, _pdfio_strbuf_t **bptr); extern void _pdfioStringFreeBuffer(pdfio_file_t *pdf, char *buffer); extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL; +extern bool _pdfioStringPrintf(_pdfio_strbuf_t *bptr, const char *format, ...) _PDFIO_INTERNAL; extern void _pdfioTokenClear(_pdfio_token_t *tb) _PDFIO_INTERNAL; extern void _pdfioTokenFlush(_pdfio_token_t *tb) _PDFIO_INTERNAL; diff --git a/pdfio-string.c b/pdfio-string.c index 8790bc4..3fa762b 100644 --- a/pdfio-string.c +++ b/pdfio-string.c @@ -674,7 +674,8 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file char * // O - Buffer or `NULL` on error _pdfioStringAllocBuffer( - pdfio_file_t *pdf) // I - PDF file + pdfio_file_t *pdf, // I - PDF file + _pdfio_strbuf_t **bptr) // O - String buffer pointer { _pdfio_strbuf_t *current; // Current string buffer @@ -683,21 +684,34 @@ _pdfioStringAllocBuffer( for (current = pdf->strbuffers; current; current = current->next) { if (!current->bufused) - { - current->bufused = true; - return (current->buffer); - } + goto done; } // Didn't find one, allocate a new one... if ((current = calloc(1, sizeof(_pdfio_strbuf_t))) == NULL) + { + if (bptr) + *bptr = NULL; + return (NULL); + } // Add to the linked list of string buffers... - current->next = pdf->strbuffers; + current->pdf = pdf; + current->next = pdf->strbuffers; + pdf->strbuffers = current; + + // Claim and return the free string buffer... + done: + current->bufused = true; - pdf->strbuffers = current; + if (bptr) + { + *bptr = current; + current->buffer[0] = '\0'; + current->bufptr = current->buffer; + } return (current->buffer); } @@ -857,6 +871,36 @@ _pdfioStringIsAllocated( } +// +// '_pdfioStringPrintf()' - Append a formatted string to a string buffer. +// + +bool // O - `true` on success, `false` on failure +_pdfioStringPrintf( + _pdfio_strbuf_t *bptr, // I - String buffer + const char *format, // I - Format string + ...) // I - Additional arguments as needed +{ + va_list ap; // Pointer to additional arguments + size_t remaining; // Remaining bytes + ssize_t bytes; // Formatted bytes + + + // Format the string in the buffer... + va_start(ap, format); + + remaining = sizeof(bptr->buffer) - (size_t)(bptr->bufptr - bptr->buffer); + bytes = _pdfio_vsnprintf(bptr->pdf, bptr->bufptr, remaining, format, ap); + + va_end(ap); + + // Advance the current position in the buffer and return. + bptr->bufptr += strlen(bptr->bufptr); + + return (bytes < (ssize_t)remaining && bytes >= 0); +} + + // // 'find_string()' - Find an element in the array. // diff --git a/pdfio-value.c b/pdfio-value.c index 7d0eb13..96d9352 100644 --- a/pdfio-value.c +++ b/pdfio-value.c @@ -160,7 +160,7 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file _pdfioFileError(pdf, "Unable to read encrypted binary string - too long."); return (false); } - else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL) + else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf, /*bptr*/NULL)) == NULL) { _pdfioFileError(pdf, "Unable to read encrypted binary string - out of memory."); return (false); @@ -191,7 +191,7 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file _pdfioFileError(pdf, "Unable to read encrypted string - too long."); return (false); } - else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL) + else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf, /*bptr*/NULL)) == NULL) { _pdfioFileError(pdf, "Unable to read encrypted binary string - out of memory."); return (false); @@ -341,7 +341,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file size_t depth) // I - Depth of value { _pdfio_value_t *ret = NULL; // Return value - char *token = _pdfioStringAllocBuffer(pdf); + char *token = _pdfioStringAllocBuffer(pdf, /*bptr*/NULL); // Token buffer time_t timeval; // Date/time value #ifdef DEBUG @@ -638,7 +638,7 @@ _pdfioValueWrite( _pdfioFileError(obj->pdf, "Unable to write encrypted binary string - too long."); return (false); } - else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(obj->pdf)) == NULL) + else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(obj->pdf, /*bptr*/NULL)) == NULL) { _pdfioFileError(obj->pdf, "Unable to write encrypted binary string - out of memory."); return (false); @@ -764,7 +764,7 @@ _pdfioValueWrite( _pdfioFileError(obj->pdf, "Unable to write encrypted string - too long."); return (false); } - else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(obj->pdf)) == NULL) + else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(obj->pdf, /*bptr*/NULL)) == NULL) { _pdfioFileError(obj->pdf, "Unable to write encrypted string - out of memory."); return (false);