diff options
Diffstat (limited to 'pdf/pdf_loop_detect.c')
-rw-r--r-- | pdf/pdf_loop_detect.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/pdf/pdf_loop_detect.c b/pdf/pdf_loop_detect.c new file mode 100644 index 00000000..7d08b182 --- /dev/null +++ b/pdf/pdf_loop_detect.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2018-2021 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, + CA 94945, U.S.A., +1(415)492-9861, for further information. +*/ + +/* code for handling circular references */ + +#include "pdf_int.h" +#include "pdf_loop_detect.h" + +static int pdfi_init_loop_detector(pdf_context *ctx) +{ + if (ctx->loop_detection) { + dbgmprintf(ctx->memory, "Attempt to initialise loop detector while one is in operation\n"); + return_error(gs_error_unknownerror); + } + + ctx->loop_detection = (uint64_t *)gs_alloc_bytes(ctx->memory, INITIAL_LOOP_TRACKER_SIZE * sizeof (uint64_t), "allocate loop tracking array"); + if (ctx->loop_detection == NULL) + return_error(gs_error_VMerror); + + ctx->loop_detection_entries = 0; + ctx->loop_detection_size = INITIAL_LOOP_TRACKER_SIZE; + return 0; +} + +static int pdfi_free_loop_detector(pdf_context *ctx) +{ + if (ctx->loop_detection == NULL) { + dbgmprintf(ctx->memory, "Attempt to free loop detector without initialising it\n"); + return 0; + } + if (ctx->loop_detection != NULL) + gs_free_object(ctx->memory, ctx->loop_detection, "Free array for loop tracking"); + ctx->loop_detection_entries = 0; + ctx->loop_detection_size = 0; + ctx->loop_detection = NULL; + + return 0; +} + +int pdfi_loop_detector_add_object(pdf_context *ctx, uint64_t object) +{ + if (ctx->loop_detection == NULL) { + dbgmprintf(ctx->memory, "Attempt to use loop detector without initialising it\n"); + return 0; + } + + if (ctx->loop_detection_entries == ctx->loop_detection_size) { + uint64_t *New; + + New = (uint64_t *)gs_alloc_bytes(ctx->memory, (ctx->loop_detection_size + INITIAL_LOOP_TRACKER_SIZE) * sizeof (uint64_t), "re-allocate loop tracking array"); + if (New == NULL) { + return_error(gs_error_VMerror); + } + memcpy(New, ctx->loop_detection, ctx->loop_detection_entries * sizeof(uint64_t)); + gs_free_object(ctx->memory, ctx->loop_detection, "Free array for loop tracking"); + ctx->loop_detection_size += INITIAL_LOOP_TRACKER_SIZE; + ctx->loop_detection = New; + } + ctx->loop_detection[ctx->loop_detection_entries++] = object; + return 0; +} + +bool pdfi_loop_detector_check_object(pdf_context *ctx, uint64_t object) +{ + int i = 0; + + if (ctx->loop_detection == NULL) { + dbgmprintf(ctx->memory, "Attempt to use loop detector without initialising it\n"); + return 0; + } + + for (i=0;i < ctx->loop_detection_entries;i++) { + if (ctx->loop_detection[i] == object) { + char info_string[256]; + gs_sprintf(info_string, "Error! circular reference to object %"PRIu64" detected.\n", object); + pdfi_set_error(ctx, 0, NULL, E_PDF_CIRCULARREF, "pdfi_loop_detector_check_object", info_string); + return true; + } + } + return false; +} + +int pdfi_loop_detector_mark(pdf_context *ctx) +{ + int code = 0; + + if (ctx->loop_detection == NULL) { + code = pdfi_init_loop_detector(ctx); + if (code < 0) + return code; + } + + return pdfi_loop_detector_add_object(ctx, 0); +} + +int pdfi_loop_detector_cleartomark(pdf_context *ctx) +{ + if (ctx->loop_detection == NULL) { + dbgmprintf(ctx->memory, "Attempt to use loop detector without initialising it\n"); + return 0; + } + + while (ctx->loop_detection[--ctx->loop_detection_entries] != 0) { + ctx->loop_detection[ctx->loop_detection_entries] = 0; + } + /* FIXME - potential optimisation + * Instead of freeing the loop detection array every tiome we are done with it + * and then reallocating a new one next time we need one, we could just keep + * the existing (empty) array. I suspect this would provide a small performance + * improvement. + */ + if (ctx->loop_detection_entries == 0) + pdfi_free_loop_detector(ctx); + return 0; +} |