diff --git a/pdfio-file.c b/pdfio-file.c index 6d85706..2422c67 100644 --- a/pdfio-file.c +++ b/pdfio-file.c @@ -110,6 +110,8 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file { bool ret = true; // Return value size_t i; // Looping var + _pdfio_strbuf_t *current, // Current string buffer + *next; // Next string buffer // Range check input @@ -152,6 +154,12 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file free(pdf->strings[i]); free(pdf->strings); + for (current = pdf->strbuffers; current; current = next) + { + next = current->next; + free(current); + } + free(pdf); return (ret); diff --git a/pdfio-private.h b/pdfio-private.h index ff3717c..9a82fe3 100644 --- a/pdfio-private.h +++ b/pdfio-private.h @@ -225,6 +225,14 @@ typedef struct _pdfio_objmap_s // PDF object map size_t src_number; // Source object number } _pdfio_objmap_t; +typedef struct _pdfio_strbuf_s // PDF string buffer +{ + struct _pdfio_strbuf_s *next; // Next string buffer + bool bufused; // Is this string buffer being used? + char buffer[PDFIO_MAX_STRING + 32]; + // String buffer +} _pdfio_strbuf_t; + struct _pdfio_file_s // PDF file structure { char *filename; // Filename @@ -284,6 +292,7 @@ struct _pdfio_file_s // PDF file structure size_t num_strings, // Number of strings alloc_strings; // Allocated strings char **strings; // Nul-terminated strings + _pdfio_strbuf_t *strbuffers; // String buffers }; struct _pdfio_obj_s // Object @@ -391,6 +400,8 @@ 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 void _pdfioStringFreeBuffer(pdfio_file_t *pdf, char *buffer); extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL; extern void _pdfioTokenClear(_pdfio_token_t *tb) _PDFIO_INTERNAL; diff --git a/pdfio-string.c b/pdfio-string.c index 09f36d3..507e1a8 100644 --- a/pdfio-string.c +++ b/pdfio-string.c @@ -532,6 +532,41 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file } +// +// '_pdfioStringAllocBuffer()' - Allocate a string buffer. +// + +char * // O - Buffer or `NULL` on error +_pdfioStringAllocBuffer( + pdfio_file_t *pdf) // I - PDF file +{ + _pdfio_strbuf_t *current; // Current string buffer + + + // See if we have an available string buffer... + for (current = pdf->strbuffers; current; current = current->next) + { + if (!current->bufused) + { + current->bufused = true; + return (current->buffer); + } + } + + // Didn't find one, allocate a new one... + if ((current = calloc(1, sizeof(_pdfio_strbuf_t))) == NULL) + return (NULL); + + // Add to the linked list of string buffers... + current->next = pdf->strbuffers; + current->bufused = true; + + pdf->strbuffers = current; + + return (current->buffer); +} + + // // 'pdfioStringCreate()' - Create a durable literal string. // @@ -642,6 +677,29 @@ pdfioStringCreatef( } +// +// '_pdfioStringFreeBuffer()' - Free a string buffer. +// + +void +_pdfioStringFreeBuffer( + pdfio_file_t *pdf, // I - PDF file + char *buffer) // I - String buffer +{ + _pdfio_strbuf_t *current; // Current string buffer + + + for (current = pdf->strbuffers; current; current = current->next) + { + if (current->buffer == buffer) + { + current->bufused = false; + break; + } + } +} + + // // '_pdfioStringIsAllocated()' - Check whether a string has been allocated. // diff --git a/pdfio-value.c b/pdfio-value.c index 6203b4d..a4822d9 100644 --- a/pdfio-value.c +++ b/pdfio-value.c @@ -125,8 +125,7 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file _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[PDFIO_MAX_STRING + 32]; - // Temporary buffer for decryption + uint8_t *temp = NULL; // Temporary buffer for decryption size_t templen; // Number of actual data bytes time_t timeval; // Date/time value @@ -153,11 +152,16 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file case PDFIO_VALTYPE_BINARY : // Decrypt the binary string... - if (v->value.binary.datalen > (sizeof(temp) - 32)) + if (v->value.binary.datalen > PDFIO_MAX_STRING) { _pdfioFileError(pdf, "Unable to read encrypted binary string - too long."); return (false); } + else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL) + { + _pdfioFileError(pdf, "Unable to read encrypted binary string - out of memory."); + return (false); + } ivlen = v->value.binary.datalen; if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL) @@ -172,6 +176,8 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file v->value.binary.datalen = templen - temp[templen - 1]; else v->value.binary.datalen = templen; + + _pdfioStringFreeBuffer(pdf, (char *)temp); break; case PDFIO_VALTYPE_STRING : @@ -301,7 +307,9 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file _pdfio_value_t *v, // I - Value size_t depth) // I - Depth of value { - char token[PDFIO_MAX_STRING];// Token buffer + _pdfio_value_t *ret = NULL; // Return value + char *token = _pdfioStringAllocBuffer(pdf); + // Token buffer time_t timeval; // Date/time value #ifdef DEBUG static const char * const valtypes[] = @@ -323,8 +331,11 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file PDFIO_DEBUG("_pdfioValueRead(pdf=%p, obj=%p, v=%p)\n", pdf, obj, v); - if (!_pdfioTokenGet(tb, token, sizeof(token))) - return (NULL); + if (!token) + goto done; + + if (!_pdfioTokenGet(tb, token, PDFIO_MAX_STRING)) + goto done; if (!strcmp(token, "[")) { @@ -332,12 +343,14 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file if (depth >= PDFIO_MAX_DEPTH) { _pdfioFileError(pdf, "Too many nested arrays."); - return (NULL); + goto done; } v->type = PDFIO_VALTYPE_ARRAY; if ((v->value.array = _pdfioArrayRead(pdf, obj, tb, depth + 1)) == NULL) - return (NULL); + goto done; + + ret = v; } else if (!strcmp(token, "<<")) { @@ -345,29 +358,34 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file if (depth >= PDFIO_MAX_DEPTH) { _pdfioFileError(pdf, "Too many nested dictionaries."); - return (NULL); + goto done; } v->type = PDFIO_VALTYPE_DICT; if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL) - return (NULL); + goto done; + + ret = v; } else if ((timeval = get_date_time(token + 1)) != 0) { v->type = PDFIO_VALTYPE_DATE; v->value.date = timeval; + ret = v; } else if (token[0] == '(') { // String v->type = PDFIO_VALTYPE_STRING; v->value.string = pdfioStringCreate(pdf, token + 1); + ret = v; } else if (token[0] == '/') { // Name v->type = PDFIO_VALTYPE_NAME; v->value.name = pdfioStringCreate(pdf, token + 1); + ret = v; } else if (token[0] == '<') { @@ -380,7 +398,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file if ((v->value.binary.data = (unsigned char *)malloc(v->value.binary.datalen)) == NULL) { _pdfioFileError(pdf, "Out of memory for hex string."); - return (NULL); + goto done; } // Convert hex to binary... @@ -407,6 +425,8 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file *dataptr++ = (unsigned char)d; } + + ret = v; } else if (strchr("0123456789-+.", token[0]) != NULL) { @@ -494,7 +514,8 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file PDFIO_DEBUG("_pdfioValueRead: Returning indirect value %lu %u R.\n", (unsigned long)v->value.indirect.number, v->value.indirect.generation); - return (v); + ret = v; + goto done; } } } @@ -502,27 +523,41 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file // If we get here, we have a number... v->type = PDFIO_VALTYPE_NUMBER; v->value.number = _pdfio_strtod(pdf, token); + ret = v; } else if (!strcmp(token, "true") || !strcmp(token, "false")) { // Boolean value v->type = PDFIO_VALTYPE_BOOLEAN; v->value.boolean = !strcmp(token, "true"); + ret = v; } else if (!strcmp(token, "null")) { // null value v->type = PDFIO_VALTYPE_NULL; + ret = v; } else { _pdfioFileError(pdf, "Unexpected '%s' token seen.", token); - return (NULL); } - PDFIO_DEBUG("_pdfioValueRead: Returning %s value.\n", valtypes[v->type]); + done: - return (v); + if (token) + _pdfioStringFreeBuffer(pdf, token); + + if (ret) + { + PDFIO_DEBUG("_pdfioValueRead: Returning %s value.\n", valtypes[ret->type]); + return (ret); + } + else + { + PDFIO_DEBUG("_pdfioValueRead: Returning NULL.\n"); + return (NULL); + } } @@ -547,9 +582,10 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file case PDFIO_VALTYPE_BINARY : { size_t databytes; // Bytes to write - uint8_t temp[PDFIO_MAX_STRING + 32], - // Temporary buffer for encryption + uint8_t *temp = NULL, // Temporary buffer for encryption *dataptr; // Pointer into data + bool ret = false; // Return value + if (obj && pdf->encryption) { @@ -558,11 +594,16 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file _pdfio_crypto_cb_t cb; // Encryption callback size_t ivlen; // Number of initialization vector bytes - if (v->value.binary.datalen > (sizeof(temp) - 32)) + if (v->value.binary.datalen > PDFIO_MAX_STRING) { _pdfioFileError(pdf, "Unable to write encrypted binary string - too long."); return (false); } + else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL) + { + _pdfioFileError(pdf, "Unable to write encrypted binary string - out of memory."); + return (false); + } cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen); databytes = (cb)(&ctx, temp + ivlen, v->value.binary.data, v->value.binary.datalen) + ivlen; @@ -575,18 +616,25 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file } if (!_pdfioFilePuts(pdf, "<")) - return (false); + goto bindone; for (; databytes > 1; databytes -= 2, dataptr += 2) { if (!_pdfioFilePrintf(pdf, "%02X%02X", dataptr[0], dataptr[1])) - return (false); + goto bindone; } - if (databytes > 0) - return (_pdfioFilePrintf(pdf, "%02X>", dataptr[0])); - else - return (_pdfioFilePuts(pdf, ">")); + if (databytes > 0 && !_pdfioFilePrintf(pdf, "%02X", dataptr[0])) + goto bindone; + + ret = _pdfioFilePuts(pdf, ">"); + + bindone: + + if (temp) + _pdfioStringFreeBuffer(pdf, (char *)temp); + + return (ret); } case PDFIO_VALTYPE_BOOLEAN : @@ -611,8 +659,7 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file if (obj && pdf->encryption) { // Write encrypted string... - uint8_t temp[PDFIO_MAX_STRING + 32], - // Encrypted bytes + uint8_t temp[64], // Encrypted bytes *tempptr; // Pointer into encrypted bytes _pdfio_crypto_ctx_t ctx; // Encryption context _pdfio_crypto_cb_t cb; // Encryption callback @@ -663,8 +710,7 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file if (obj && pdf->encryption) { // Write encrypted string... - uint8_t temp[PDFIO_MAX_STRING + 32], - // Encrypted bytes + uint8_t *temp = NULL, // Encrypted bytes *tempptr; // Pointer into encrypted bytes _pdfio_crypto_ctx_t ctx; // Encryption context _pdfio_crypto_cb_t cb; // Encryption callback @@ -672,29 +718,41 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file // Length of value ivlen, // Number of initialization vector bytes tempbytes; // Number of output bytes + bool ret = false; // Return value - if (len > (sizeof(temp) - 32)) + if (len > PDFIO_MAX_STRING) { _pdfioFileError(pdf, "Unable to write encrypted string - too long."); return (false); } + else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL) + { + _pdfioFileError(pdf, "Unable to write encrypted string - out of memory."); + return (false); + } cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen); tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)v->value.string, len) + ivlen; if (!_pdfioFilePuts(pdf, "<")) - return (false); + goto strdone; for (tempptr = temp; tempbytes > 1; tempbytes -= 2, tempptr += 2) { if (!_pdfioFilePrintf(pdf, "%02X%02X", tempptr[0], tempptr[1])) - return (false); + goto strdone; } - if (tempbytes > 0) - return (_pdfioFilePrintf(pdf, "%02X>", *tempptr)); - else - return (_pdfioFilePuts(pdf, ">")); + if (tempbytes > 0 && !_pdfioFilePrintf(pdf, "%02X", *tempptr)) + goto strdone; + + ret = _pdfioFilePuts(pdf, ">"); + + strdone : + + _pdfioStringFreeBuffer(pdf, (char *)temp); + + return (ret); } else {