Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/pdf/pdf_repair.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2020-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
/* Routines to attempt repair of PDF files in the event of an error */
17
18
#include "pdf_int.h"
19
#include "pdf_stack.h"
20
#include "strmio.h"
21
#include "stream.h"
22
#include "pdf_deref.h"
23
#include "pdf_dict.h"
24
#include "pdf_file.h"
25
#include "pdf_misc.h"
26
#include "pdf_repair.h"
27
28
static int pdfi_repair_add_object(pdf_context *ctx, int64_t obj, int64_t gen, gs_offset_t offset)
29
3.06M
{
30
    /* Although we can handle object numbers larger than this, on some systems (32-bit Windows)
31
     * memset is limited to a (signed!) integer for the size of memory to clear. We could deal
32
     * with this by clearing the memory in blocks, but really, this is almost certainly a
33
     * corrupted file or something.
34
     */
35
3.06M
    if (obj >= 0x7ffffff / sizeof(xref_entry) || obj < 1 || gen < 0 || offset < 0)
36
7.31k
        return_error(gs_error_rangecheck);
37
38
3.05M
    if (ctx->xref_table == NULL) {
39
69.3k
        ctx->xref_table = (xref_table_t *)gs_alloc_bytes(ctx->memory, sizeof(xref_table_t), "repair xref table");
40
69.3k
        if (ctx->xref_table == NULL) {
41
0
            return_error(gs_error_VMerror);
42
0
        }
43
69.3k
        memset(ctx->xref_table, 0x00, sizeof(xref_table_t));
44
69.3k
        ctx->xref_table->xref = (xref_entry *)gs_alloc_bytes(ctx->memory, (obj + 1) * sizeof(xref_entry), "repair xref table");
45
69.3k
        if (ctx->xref_table->xref == NULL){
46
0
            gs_free_object(ctx->memory, ctx->xref_table, "failed to allocate xref table entries for repair");
47
0
            ctx->xref_table = NULL;
48
0
            return_error(gs_error_VMerror);
49
0
        }
50
69.3k
        memset(ctx->xref_table->xref, 0x00, (obj + 1) * sizeof(xref_entry));
51
69.3k
        ctx->xref_table->ctx = ctx;
52
69.3k
        ctx->xref_table->type = PDF_XREF_TABLE;
53
69.3k
        ctx->xref_table->xref_size = obj + 1;
54
#if REFCNT_DEBUG
55
        ctx->xref_table->UID = ctx->ref_UID++;
56
        outprintf(ctx->memory, "Allocated xref table with UID %"PRIi64"\n", ctx->xref_table->UID);
57
#endif
58
69.3k
        pdfi_countup(ctx->xref_table);
59
2.98M
    } else {
60
2.98M
        if (ctx->xref_table->xref_size < (obj + 1)) {
61
1.48M
            xref_entry *new_xrefs;
62
63
1.48M
            new_xrefs = (xref_entry *)gs_alloc_bytes(ctx->memory, (obj + 1) * sizeof(xref_entry), "read_xref_stream allocate xref table entries");
64
1.48M
            if (new_xrefs == NULL){
65
0
                pdfi_countdown(ctx->xref_table);
66
0
                ctx->xref_table = NULL;
67
0
                return_error(gs_error_VMerror);
68
0
            }
69
1.48M
            memset(new_xrefs, 0x00, (obj + 1) * sizeof(xref_entry));
70
1.48M
            memcpy(new_xrefs, ctx->xref_table->xref, ctx->xref_table->xref_size * sizeof(xref_entry));
71
1.48M
            gs_free_object(ctx->memory, ctx->xref_table->xref, "reallocated xref entries");
72
1.48M
            ctx->xref_table->xref = new_xrefs;
73
1.48M
            ctx->xref_table->xref_size = obj + 1;
74
1.48M
        }
75
2.98M
    }
76
3.05M
    ctx->xref_table->xref[obj].compressed = false;
77
3.05M
    ctx->xref_table->xref[obj].free = false;
78
3.05M
    ctx->xref_table->xref[obj].object_num = obj;
79
3.05M
    ctx->xref_table->xref[obj].u.uncompressed.generation_num = gen;
80
3.05M
    ctx->xref_table->xref[obj].u.uncompressed.offset = offset;
81
3.05M
    return 0;
82
3.05M
}
83
84
int pdfi_repair_file(pdf_context *ctx)
85
846k
{
86
846k
    int code = 0;
87
846k
    gs_offset_t offset, saved_offset;
88
846k
    int64_t object_num = 0, generation_num = 0;
89
846k
    int i;
90
846k
    gs_offset_t outer_saved_offset[3];
91
92
846k
    if (ctx->repaired) {
93
759k
        pdfi_set_error(ctx, 0, NULL, E_PDF_UNREPAIRABLE, "pdfi_repair_file", (char *)"%% Trying to repair file for second time -- unrepairable");
94
759k
        return_error(gs_error_undefined);
95
759k
    }
96
97
86.8k
    saved_offset = pdfi_unread_tell(ctx);
98
99
86.8k
    ctx->repaired = true;
100
86.8k
    if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_ioerror), NULL, E_PDF_REPAIRED, "pdfi_repair_file", NULL)) < 0)
101
0
        return code;
102
103
86.8k
    ctx->repairing = true;
104
105
86.8k
    pdfi_clearstack(ctx);
106
107
86.8k
    if(ctx->args.pdfdebug)
108
0
        outprintf(ctx->memory, "%% Error encountered in opening PDF file, attempting repair\n");
109
110
    /* First try to locate a %PDF header. If we can't find one, abort this, the file is too broken
111
     * and may not even be a PDF file.
112
     */
113
86.8k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
114
86.8k
    {
115
86.8k
        static const char test[] = "%PDF";
116
86.8k
        int index = 0;
117
118
347k
        do {
119
347k
            int c = pdfi_read_byte(ctx, ctx->main_stream);
120
347k
            if (c < 0)
121
0
                goto exit;
122
123
347k
            if (c == test[index])
124
347k
                index++;
125
0
            else
126
0
                index = 0;
127
347k
        } while (index < 4);
128
86.8k
        if (index != 4) {
129
0
            code = gs_note_error(gs_error_undefined);
130
0
            goto exit;
131
0
        }
132
86.8k
        pdfi_unread(ctx, ctx->main_stream, (byte *)test, 4);
133
86.8k
        pdfi_skip_comment(ctx, ctx->main_stream);
134
86.8k
    }
135
86.8k
    if (ctx->main_stream->eof == true) {
136
810
        code = gs_note_error(gs_error_ioerror);
137
810
        goto exit;
138
810
    }
139
140
    /* First pass, identify all the objects of the form x y obj */
141
142
3.01M
    do {
143
3.01M
        code = pdfi_skip_white(ctx, ctx->main_stream);
144
3.01M
        if (code < 0) {
145
0
            if (code != gs_error_VMerror && code != gs_error_ioerror) {
146
0
                pdfi_clearstack(ctx);
147
0
                continue;
148
0
            } else
149
0
                goto exit;
150
0
        }
151
3.01M
        offset = pdfi_unread_tell(ctx);
152
3.01M
        outer_saved_offset[0] = outer_saved_offset[1] = outer_saved_offset[2] = 0;
153
23.9M
        do {
154
23.9M
            outer_saved_offset[0] = outer_saved_offset[1];
155
23.9M
            outer_saved_offset[1] = outer_saved_offset[2];
156
23.9M
            outer_saved_offset[2] = pdfi_unread_tell(ctx);
157
158
23.9M
            object_num = 0;
159
160
23.9M
            code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
161
23.9M
            if (code < 0) {
162
870k
                if (code != gs_error_VMerror && code != gs_error_ioerror) {
163
870k
                    pdfi_clearstack(ctx);
164
870k
                    continue;
165
870k
                } else
166
204
                    goto exit;
167
870k
            }
168
23.1M
            if (pdfi_count_stack(ctx) > 0) {
169
22.1M
                if (pdfi_type_of(ctx->stack_top[-1]) == PDF_FAST_KEYWORD) {
170
6.05M
                    pdf_obj *k = ctx->stack_top[-1];
171
6.05M
                    pdf_num *n;
172
173
6.05M
                    if (k == PDF_TOKEN_AS_OBJ(TOKEN_OBJ)) {
174
2.99M
                        gs_offset_t saved_offset[3];
175
176
2.99M
                        offset = outer_saved_offset[0];
177
178
2.99M
                        saved_offset[0] = saved_offset[1] = saved_offset[2] = 0;
179
180
2.99M
                        if (pdfi_count_stack(ctx) < 3 || pdfi_type_of(ctx->stack_top[-3]) != PDF_INT || pdfi_type_of(ctx->stack_top[-2]) != PDF_INT) {
181
14.7k
                            pdfi_clearstack(ctx);
182
14.7k
                            continue;
183
14.7k
                        }
184
2.97M
                        n = (pdf_num *)ctx->stack_top[-3];
185
2.97M
                        object_num = n->value.i;
186
2.97M
                        n = (pdf_num *)ctx->stack_top[-2];
187
2.97M
                        generation_num = n->value.i;
188
2.97M
                        pdfi_clearstack(ctx);
189
190
87.9M
                        do {
191
                            /* move all the saved offsets up by one */
192
87.9M
                            saved_offset[0] = saved_offset[1];
193
87.9M
                            saved_offset[1] = saved_offset[2];
194
87.9M
                            saved_offset[2] = pdfi_unread_tell(ctx);
195
196
87.9M
                            code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
197
87.9M
                            if (code < 0) {
198
695k
                                if (code != gs_error_VMerror && code != gs_error_ioerror)
199
695k
                                    continue;
200
106
                                goto exit;
201
695k
                            }
202
87.2M
                            if (code == 0 && ctx->main_stream->eof)
203
19.5k
                                break;
204
205
87.2M
                            if (pdfi_type_of(ctx->stack_top[-1]) == PDF_FAST_KEYWORD) {
206
3.27M
                                pdf_obj *k = ctx->stack_top[-1];
207
208
3.27M
                                if (k == PDF_TOKEN_AS_OBJ(TOKEN_OBJ)) {
209
                                    /* Found obj while looking for endobj, store the existing 'obj'
210
                                     * and start afresh.
211
                                     */
212
60.2k
                                    code = pdfi_repair_add_object(ctx, object_num, generation_num, offset);
213
60.2k
                                    if (pdfi_count_stack(ctx) < 3 || pdfi_type_of(ctx->stack_top[-3]) != PDF_INT || pdfi_type_of(ctx->stack_top[-2]) != PDF_INT) {
214
8.15k
                                        pdfi_clearstack(ctx);
215
8.15k
                                        break;
216
8.15k
                                    }
217
52.1k
                                    n = (pdf_num *)ctx->stack_top[-3];
218
52.1k
                                    object_num = n->value.i;
219
52.1k
                                    n = (pdf_num *)ctx->stack_top[-2];
220
52.1k
                                    generation_num = n->value.i;
221
52.1k
                                    pdfi_clearstack(ctx);
222
52.1k
                                    offset = saved_offset[0];
223
52.1k
                                    continue;
224
60.2k
                                }
225
226
3.21M
                                if (k == PDF_TOKEN_AS_OBJ(TOKEN_ENDOBJ)) {
227
1.85M
                                    code = pdfi_repair_add_object(ctx, object_num, generation_num, offset);
228
1.85M
                                    if (code < 0)
229
128
                                        goto exit;
230
1.85M
                                    pdfi_clearstack(ctx);
231
1.85M
                                    break;
232
1.85M
                                } else {
233
1.36M
                                    if (k == PDF_TOKEN_AS_OBJ(TOKEN_STREAM)) {
234
1.09M
                                        static const char test[] = "endstream";
235
1.09M
                                        int index = 0;
236
237
3.84G
                                        do {
238
3.84G
                                            int c = pdfi_read_byte(ctx, ctx->main_stream);
239
3.84G
                                            if (c == EOFC)
240
25.9k
                                                break;
241
3.84G
                                            if (c < 0)
242
0
                                                goto exit;
243
3.84G
                                            if (c == test[index])
244
30.8M
                                                index++;
245
3.81G
                                            else if (c == test[0]) /* Pesky 'e' appears twice */
246
294k
                                                index = 1;
247
3.81G
                                            else
248
3.81G
                                                index = 0;
249
3.84G
                                        } while (index < 9);
250
1.09M
                                        do {
251
1.09M
                                            code = pdfi_read_bare_keyword(ctx, ctx->main_stream);
252
1.09M
                                            if (code == gs_error_VMerror || code == gs_error_ioerror)
253
0
                                                goto exit;
254
1.09M
                                            if (code < 0) {
255
                                                /* Something went wrong and we couldn't read a token, consume one byte and retry */
256
0
                                                (void)pdfi_read_byte(ctx, ctx->main_stream);
257
1.09M
                                            } else {
258
1.09M
                                                if (code == TOKEN_ENDOBJ || code == TOKEN_INVALID_KEY) {
259
1.09M
                                                    code = pdfi_repair_add_object(ctx, object_num, generation_num, offset);
260
1.09M
                                                    if (code == gs_error_VMerror || code == gs_error_ioerror)
261
0
                                                        goto exit;
262
1.09M
                                                    break;
263
1.09M
                                                }
264
1.09M
                                            }
265
1.09M
                                        } while(ctx->main_stream->eof == false);
266
1.09M
                                        pdfi_clearstack(ctx);
267
1.09M
                                        break;
268
1.09M
                                    } else {
269
268k
                                        pdfi_clearstack(ctx);
270
268k
                                    }
271
1.36M
                                }
272
3.21M
                            }
273
87.2M
                        } while(1);
274
2.97M
                        break;
275
3.06M
                    } else {
276
3.06M
                        if (k == PDF_TOKEN_AS_OBJ(TOKEN_ENDOBJ)) {
277
44.4k
                            pdfi_clearstack(ctx);
278
44.4k
                        } else
279
3.01M
                            if (k == PDF_TOKEN_AS_OBJ(TOKEN_STARTXREF)) {
280
17.6k
                                code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
281
17.6k
                                if (code < 0 && code != gs_error_VMerror && code != gs_error_ioerror)
282
16
                                    continue;
283
17.6k
                                if (code < 0)
284
0
                                    goto exit;
285
17.6k
                                pdfi_clearstack(ctx);
286
3.00M
                            } else {
287
3.00M
                                if (k == PDF_TOKEN_AS_OBJ(TOKEN_TRAILER)) {
288
60.7k
                                    code = pdfi_read_bare_object(ctx, ctx->main_stream, 0, 0, 0);
289
60.7k
                                    if (code == 0 && pdfi_count_stack(ctx) > 0 && pdfi_type_of(ctx->stack_top[-1]) == PDF_DICT) {
290
31.6k
                                        if (ctx->Trailer) {
291
10.5k
                                            pdf_dict *d = (pdf_dict *)ctx->stack_top[-1];
292
10.5k
                                            bool known = false;
293
294
10.5k
                                            code = pdfi_dict_known(ctx, d, "Root", &known);
295
10.5k
                                            if (code == 0 && known) {
296
7.45k
                                                pdfi_countdown(ctx->Trailer);
297
7.45k
                                                ctx->Trailer = (pdf_dict *)ctx->stack_top[-1];
298
7.45k
                                                pdfi_countup(ctx->Trailer);
299
7.45k
                                            }
300
21.0k
                                        } else {
301
21.0k
                                            ctx->Trailer = (pdf_dict *)ctx->stack_top[-1];
302
21.0k
                                            pdfi_countup(ctx->Trailer);
303
21.0k
                                        }
304
31.6k
                                    }
305
60.7k
                                }
306
3.00M
                                pdfi_clearstack(ctx);
307
3.00M
                            }
308
3.06M
                    }
309
3.06M
                    code = pdfi_skip_white(ctx, ctx->main_stream);
310
3.06M
                    if (code < 0) {
311
0
                        if (code != gs_error_VMerror && code != gs_error_ioerror) {
312
0
                            pdfi_clearstack(ctx);
313
0
                            continue;
314
0
                        } else
315
0
                            goto exit;
316
0
                    }
317
3.06M
                }
318
19.1M
                if (pdfi_count_stack(ctx) > 0 && pdfi_type_of(ctx->stack_top[-1]) != PDF_INT)
319
3.55M
                    pdfi_clearstack(ctx);
320
19.1M
            }
321
23.1M
        } while (ctx->main_stream->eof == false);
322
3.01M
    } while(ctx->main_stream->eof == false);
323
324
85.5k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
325
85.5k
    ctx->main_stream->eof = false;
326
327
    /* Second pass, examine every object we have located to see if its an ObjStm */
328
85.5k
    if (ctx->xref_table == NULL || ctx->xref_table->xref_size < 1) {
329
7.25k
        code = gs_note_error(gs_error_syntaxerror);
330
7.25k
        goto exit;
331
7.25k
    }
332
333
211M
    for (i=1;i < ctx->xref_table->xref_size;i++) {
334
211M
        if (ctx->xref_table->xref[i].object_num != 0) {
335
            /* At this stage, all the objects we've found must be uncompressed */
336
4.12M
            if (ctx->xref_table->xref[i].u.uncompressed.offset > ctx->main_stream_length) {
337
                /* This can only happen if we had read an xref table before we tried to repair
338
                 * the file, and the table has entries we didn't find in the file. So
339
                 * mark the entry as free, and offset of 0, and just carry on.
340
                 */
341
9.06k
                ctx->xref_table->xref[i].free = 1;
342
9.06k
                ctx->xref_table->xref[i].u.uncompressed.offset = 0;
343
9.06k
                continue;
344
9.06k
            }
345
346
4.11M
            pdfi_seek(ctx, ctx->main_stream, ctx->xref_table->xref[i].u.uncompressed.offset, SEEK_SET);
347
132M
            do {
348
132M
                code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
349
132M
                if (ctx->main_stream->eof == true || (code < 0 && code != gs_error_ioerror && code != gs_error_VMerror)) {
350
                    /* object offset is beyond EOF or object is broken (possibly due to multiple xref
351
                     * errors) ignore the error and carry on, if the object gets used then we will
352
                     * error out at that point.
353
                     */
354
201k
                    code = 0;
355
201k
                    break;
356
201k
                }
357
132M
                if (code < 0)
358
0
                    goto exit;
359
132M
                if (pdfi_type_of(ctx->stack_top[-1]) == PDF_FAST_KEYWORD) {
360
11.0M
                    pdf_obj *k = ctx->stack_top[-1];
361
362
11.0M
                    if (k == PDF_TOKEN_AS_OBJ(TOKEN_OBJ)) {
363
3.73M
                        continue;
364
3.73M
                    }
365
7.31M
                    if (k == PDF_TOKEN_AS_OBJ(TOKEN_ENDOBJ)) {
366
2.84M
                        if (pdfi_count_stack(ctx) > 1) {
367
2.82M
                            if (pdfi_type_of(ctx->stack_top[-2]) == PDF_DICT) {
368
1.81M
                                pdf_dict *d = (pdf_dict *)ctx->stack_top[-2];
369
1.81M
                                pdf_obj *o = NULL;
370
371
1.81M
                                code = pdfi_dict_knownget_type(ctx, d, "Type", PDF_NAME, &o);
372
1.81M
                                if (code < 0) {
373
226
                                    pdfi_clearstack(ctx);
374
226
                                    continue;
375
226
                                }
376
1.81M
                                if (code > 0) {
377
939k
                                    pdf_name *n = (pdf_name *)o;
378
379
939k
                                    if (pdfi_name_is(n, "Catalog")) {
380
109k
                                        pdfi_countdown(ctx->Root); /* In case it was already set */
381
109k
                                        ctx->Root = (pdf_dict *)ctx->stack_top[-2];
382
109k
                                        pdfi_countup(ctx->Root);
383
109k
                                    }
384
939k
                                }
385
1.81M
                                pdfi_countdown(o);
386
1.81M
                            }
387
2.82M
                        }
388
2.84M
                        pdfi_clearstack(ctx);
389
2.84M
                        break;
390
2.84M
                    }
391
4.46M
                    if (k == PDF_TOKEN_AS_OBJ(TOKEN_STREAM)) {
392
1.06M
                        pdf_dict *d;
393
1.06M
                        pdf_name *n = NULL;
394
395
1.06M
                        if (pdfi_count_stack(ctx) <= 1) {
396
1.42k
                            pdfi_clearstack(ctx);
397
1.42k
                            break;;
398
0
                        }
399
1.06M
                        d = (pdf_dict *)ctx->stack_top[-2];
400
1.06M
                        if (pdfi_type_of(d) != PDF_DICT) {
401
21.1k
                            pdfi_clearstack(ctx);
402
21.1k
                            break;;
403
0
                        }
404
1.04M
                        code = pdfi_dict_knownget_type(ctx, d, "Type", PDF_NAME, (pdf_obj **)&n);
405
1.04M
                        if (code < 0) {
406
55
                            if ((code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_UNREPAIRABLE, "pdfi_repair_file", NULL)) < 0) {
407
0
                                pdfi_clearstack(ctx);
408
0
                                goto exit;
409
0
                            }
410
55
                        }
411
1.04M
                        if (code > 0) {
412
465k
                            if (pdfi_name_is(n, "ObjStm")) {
413
48.4k
                                int64_t N;
414
48.4k
                                int obj_num, offset;
415
48.4k
                                int j;
416
48.4k
                                pdf_c_stream *compressed_stream;
417
48.4k
                                pdf_stream *stream;
418
419
48.4k
                                offset = pdfi_unread_tell(ctx);
420
48.4k
                                pdfi_seek(ctx, ctx->main_stream, offset, SEEK_SET);
421
422
48.4k
                                code = pdfi_obj_dict_to_stream(ctx, d, &stream, true);
423
48.4k
                                if (code == 0)
424
48.4k
                                    code = pdfi_filter(ctx, stream, ctx->main_stream, &compressed_stream, false);
425
426
48.4k
                                pdfi_countdown(stream);
427
428
48.4k
                                if (code == 0) {
429
48.0k
                                    code = pdfi_dict_get_int(ctx, d, "N", &N);
430
48.0k
                                    if (code == 0) {
431
1.53M
                                        for (j=0;j < N; j++) {
432
1.49M
                                            code = pdfi_read_bare_int(ctx, compressed_stream, &obj_num);
433
1.49M
                                            if (code <= 0)
434
5.87k
                                                break;
435
1.49M
                                            else {
436
1.49M
                                                code = pdfi_read_bare_int(ctx, compressed_stream, &offset);
437
1.49M
                                                if (code > 0) {
438
1.48M
                                                    if (obj_num < 1) {
439
53
                                                        pdfi_close_file(ctx, compressed_stream);
440
53
                                                        pdfi_countdown(n);
441
53
                                                        pdfi_clearstack(ctx);
442
53
                                                        code = gs_note_error(gs_error_rangecheck);
443
53
                                                        goto exit;
444
53
                                                    }
445
1.48M
                                                    if (obj_num >= ctx->xref_table->xref_size)
446
56.0k
                                                        code = pdfi_repair_add_object(ctx, obj_num, 0, 0);
447
448
1.48M
                                                    if (code >= 0) {
449
1.48M
                                                        ctx->xref_table->xref[obj_num].compressed = true;
450
1.48M
                                                        ctx->xref_table->xref[obj_num].free = false;
451
1.48M
                                                        ctx->xref_table->xref[obj_num].object_num = obj_num;
452
1.48M
                                                        ctx->xref_table->xref[obj_num].u.compressed.compressed_stream_num = i;
453
1.48M
                                                        ctx->xref_table->xref[obj_num].u.compressed.object_index = j;
454
1.48M
                                                    }
455
1.48M
                                                }
456
1.49M
                                            }
457
1.49M
                                        }
458
47.9k
                                    }
459
47.9k
                                    pdfi_close_file(ctx, compressed_stream);
460
47.9k
                                }
461
48.3k
                                if (code < 0) {
462
4.06k
                                    if ((code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_UNREPAIRABLE, "pdfi_repair_file", NULL)) < 0) {
463
0
                                        pdfi_countdown(n);
464
0
                                        pdfi_clearstack(ctx);
465
0
                                        goto exit;
466
0
                                    }
467
4.06k
                                }
468
48.3k
                            }
469
465k
                        }
470
1.04M
                        pdfi_countdown(n);
471
1.04M
                        pdfi_clearstack(ctx);
472
1.04M
                        break;
473
1.04M
                    }
474
4.46M
                }
475
132M
            } while (1);
476
4.11M
        }
477
211M
    }
478
479
86.8k
exit:
480
86.8k
    if (code > 0)
481
24.5k
        code = 0;
482
86.8k
    pdfi_seek(ctx, ctx->main_stream, saved_offset, SEEK_SET);
483
86.8k
    ctx->main_stream->eof = false;
484
86.8k
    ctx->repairing = false;
485
86.8k
    return code;
486
78.3k
}