Coverage Report

Created: 2025-06-10 07:27

/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
6.95k
        return_error(gs_error_rangecheck);
37
38
3.05M
    if (ctx->xref_table == NULL) {
39
67.3k
        ctx->xref_table = (xref_table_t *)gs_alloc_bytes(ctx->memory, sizeof(xref_table_t), "repair xref table");
40
67.3k
        if (ctx->xref_table == NULL) {
41
0
            return_error(gs_error_VMerror);
42
0
        }
43
67.3k
        memset(ctx->xref_table, 0x00, sizeof(xref_table_t));
44
67.3k
        ctx->xref_table->xref = (xref_entry *)gs_alloc_bytes(ctx->memory, (obj + 1) * sizeof(xref_entry), "repair xref table");
45
67.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
67.3k
        memset(ctx->xref_table->xref, 0x00, (obj + 1) * sizeof(xref_entry));
51
67.3k
        ctx->xref_table->ctx = ctx;
52
67.3k
        ctx->xref_table->type = PDF_XREF_TABLE;
53
67.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
67.3k
        pdfi_countup(ctx->xref_table);
59
2.98M
    } else {
60
2.98M
        if (ctx->xref_table->xref_size < (obj + 1)) {
61
1.47M
            xref_entry *new_xrefs;
62
63
1.47M
            new_xrefs = (xref_entry *)gs_alloc_bytes(ctx->memory, (obj + 1) * sizeof(xref_entry), "read_xref_stream allocate xref table entries");
64
1.47M
            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.47M
            memset(new_xrefs, 0x00, (obj + 1) * sizeof(xref_entry));
70
1.47M
            memcpy(new_xrefs, ctx->xref_table->xref, ctx->xref_table->xref_size * sizeof(xref_entry));
71
1.47M
            gs_free_object(ctx->memory, ctx->xref_table->xref, "reallocated xref entries");
72
1.47M
            ctx->xref_table->xref = new_xrefs;
73
1.47M
            ctx->xref_table->xref_size = obj + 1;
74
1.47M
        }
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
841k
{
86
841k
    int code = 0;
87
841k
    gs_offset_t offset, saved_offset;
88
841k
    int64_t object_num = 0, generation_num = 0;
89
841k
    int i;
90
841k
    gs_offset_t outer_saved_offset[3];
91
92
841k
    if (ctx->repaired) {
93
757k
        pdfi_set_error(ctx, 0, NULL, E_PDF_UNREPAIRABLE, "pdfi_repair_file", (char *)"%% Trying to repair file for second time -- unrepairable");
94
757k
        return_error(gs_error_undefined);
95
757k
    }
96
97
84.4k
    saved_offset = pdfi_unread_tell(ctx);
98
99
84.4k
    ctx->repaired = true;
100
84.4k
    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
84.4k
    ctx->repairing = true;
104
105
84.4k
    pdfi_clearstack(ctx);
106
107
84.4k
    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
84.4k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
114
84.4k
    {
115
84.4k
        static const char test[] = "%PDF";
116
84.4k
        int index = 0;
117
118
337k
        do {
119
337k
            int c = pdfi_read_byte(ctx, ctx->main_stream);
120
337k
            if (c < 0)
121
0
                goto exit;
122
123
337k
            if (c == test[index])
124
337k
                index++;
125
0
            else
126
0
                index = 0;
127
337k
        } while (index < 4);
128
84.4k
        if (index != 4) {
129
0
            code = gs_note_error(gs_error_undefined);
130
0
            goto exit;
131
0
        }
132
84.4k
        pdfi_unread(ctx, ctx->main_stream, (byte *)test, 4);
133
84.4k
        pdfi_skip_comment(ctx, ctx->main_stream);
134
84.4k
    }
135
84.4k
    if (ctx->main_stream->eof == true) {
136
735
        code = gs_note_error(gs_error_ioerror);
137
735
        goto exit;
138
735
    }
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
24.1M
        do {
154
24.1M
            outer_saved_offset[0] = outer_saved_offset[1];
155
24.1M
            outer_saved_offset[1] = outer_saved_offset[2];
156
24.1M
            outer_saved_offset[2] = pdfi_unread_tell(ctx);
157
158
24.1M
            object_num = 0;
159
160
24.1M
            code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
161
24.1M
            if (code < 0) {
162
878k
                if (code != gs_error_VMerror && code != gs_error_ioerror) {
163
878k
                    pdfi_clearstack(ctx);
164
878k
                    continue;
165
878k
                } else
166
215
                    goto exit;
167
878k
            }
168
23.2M
            if (pdfi_count_stack(ctx) > 0) {
169
22.1M
                if (pdfi_type_of(ctx->stack_top[-1]) == PDF_FAST_KEYWORD) {
170
6.08M
                    pdf_obj *k = ctx->stack_top[-1];
171
6.08M
                    pdf_num *n;
172
173
6.08M
                    if (k == PDF_TOKEN_AS_OBJ(TOKEN_OBJ)) {
174
2.98M
                        gs_offset_t saved_offset[3];
175
176
2.98M
                        offset = outer_saved_offset[0];
177
178
2.98M
                        saved_offset[0] = saved_offset[1] = saved_offset[2] = 0;
179
180
2.98M
                        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
13.6k
                            pdfi_clearstack(ctx);
182
13.6k
                            continue;
183
13.6k
                        }
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
88.1M
                        do {
191
                            /* move all the saved offsets up by one */
192
88.1M
                            saved_offset[0] = saved_offset[1];
193
88.1M
                            saved_offset[1] = saved_offset[2];
194
88.1M
                            saved_offset[2] = pdfi_unread_tell(ctx);
195
196
88.1M
                            code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
197
88.1M
                            if (code < 0) {
198
646k
                                if (code != gs_error_VMerror && code != gs_error_ioerror)
199
646k
                                    continue;
200
107
                                goto exit;
201
646k
                            }
202
87.5M
                            if (code == 0 && ctx->main_stream->eof)
203
19.0k
                                break;
204
205
87.4M
                            if (pdfi_type_of(ctx->stack_top[-1]) == PDF_FAST_KEYWORD) {
206
3.26M
                                pdf_obj *k = ctx->stack_top[-1];
207
208
3.26M
                                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
58.6k
                                    code = pdfi_repair_add_object(ctx, object_num, generation_num, offset);
213
58.6k
                                    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
7.93k
                                        pdfi_clearstack(ctx);
215
7.93k
                                        break;
216
7.93k
                                    }
217
50.7k
                                    n = (pdf_num *)ctx->stack_top[-3];
218
50.7k
                                    object_num = n->value.i;
219
50.7k
                                    n = (pdf_num *)ctx->stack_top[-2];
220
50.7k
                                    generation_num = n->value.i;
221
50.7k
                                    pdfi_clearstack(ctx);
222
50.7k
                                    offset = saved_offset[0];
223
50.7k
                                    continue;
224
58.6k
                                }
225
226
3.21M
                                if (k == PDF_TOKEN_AS_OBJ(TOKEN_ENDOBJ)) {
227
1.84M
                                    code = pdfi_repair_add_object(ctx, object_num, generation_num, offset);
228
1.84M
                                    if (code < 0)
229
121
                                        goto exit;
230
1.84M
                                    pdfi_clearstack(ctx);
231
1.84M
                                    break;
232
1.84M
                                } else {
233
1.36M
                                    if (k == PDF_TOKEN_AS_OBJ(TOKEN_STREAM)) {
234
1.10M
                                        static const char test[] = "endstream";
235
1.10M
                                        int index = 0;
236
237
3.81G
                                        do {
238
3.81G
                                            int c = pdfi_read_byte(ctx, ctx->main_stream);
239
3.81G
                                            if (c == EOFC)
240
24.9k
                                                break;
241
3.81G
                                            if (c < 0)
242
0
                                                goto exit;
243
3.81G
                                            if (c == test[index])
244
30.9M
                                                index++;
245
3.78G
                                            else if (c == test[0]) /* Pesky 'e' appears twice */
246
294k
                                                index = 1;
247
3.78G
                                            else
248
3.78G
                                                index = 0;
249
3.81G
                                        } while (index < 9);
250
1.10M
                                        do {
251
1.10M
                                            code = pdfi_read_bare_keyword(ctx, ctx->main_stream);
252
1.10M
                                            if (code == gs_error_VMerror || code == gs_error_ioerror)
253
0
                                                goto exit;
254
1.10M
                                            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.10M
                                            } else {
258
1.10M
                                                if (code == TOKEN_ENDOBJ || code == TOKEN_INVALID_KEY) {
259
1.10M
                                                    code = pdfi_repair_add_object(ctx, object_num, generation_num, offset);
260
1.10M
                                                    if (code == gs_error_VMerror || code == gs_error_ioerror)
261
0
                                                        goto exit;
262
1.10M
                                                    break;
263
1.10M
                                                }
264
1.10M
                                            }
265
1.10M
                                        } while(ctx->main_stream->eof == false);
266
1.10M
                                        pdfi_clearstack(ctx);
267
1.10M
                                        break;
268
1.10M
                                    } else {
269
264k
                                        pdfi_clearstack(ctx);
270
264k
                                    }
271
1.36M
                                }
272
3.21M
                            }
273
87.4M
                        } while(1);
274
2.97M
                        break;
275
3.09M
                    } else {
276
3.09M
                        if (k == PDF_TOKEN_AS_OBJ(TOKEN_ENDOBJ)) {
277
43.6k
                            pdfi_clearstack(ctx);
278
43.6k
                        } else
279
3.05M
                            if (k == PDF_TOKEN_AS_OBJ(TOKEN_STARTXREF)) {
280
17.7k
                                code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
281
17.7k
                                if (code < 0 && code != gs_error_VMerror && code != gs_error_ioerror)
282
15
                                    continue;
283
17.7k
                                if (code < 0)
284
0
                                    goto exit;
285
17.7k
                                pdfi_clearstack(ctx);
286
3.03M
                            } else {
287
3.03M
                                if (k == PDF_TOKEN_AS_OBJ(TOKEN_TRAILER)) {
288
58.9k
                                    code = pdfi_read_bare_object(ctx, ctx->main_stream, 0, 0, 0);
289
58.9k
                                    if (code == 0 && pdfi_count_stack(ctx) > 0 && pdfi_type_of(ctx->stack_top[-1]) == PDF_DICT) {
290
31.3k
                                        if (ctx->Trailer) {
291
10.4k
                                            pdf_dict *d = (pdf_dict *)ctx->stack_top[-1];
292
10.4k
                                            bool known = false;
293
294
10.4k
                                            code = pdfi_dict_known(ctx, d, "Root", &known);
295
10.4k
                                            if (code == 0 && known) {
296
7.28k
                                                pdfi_countdown(ctx->Trailer);
297
7.28k
                                                ctx->Trailer = (pdf_dict *)ctx->stack_top[-1];
298
7.28k
                                                pdfi_countup(ctx->Trailer);
299
7.28k
                                            }
300
20.8k
                                        } else {
301
20.8k
                                            ctx->Trailer = (pdf_dict *)ctx->stack_top[-1];
302
20.8k
                                            pdfi_countup(ctx->Trailer);
303
20.8k
                                        }
304
31.3k
                                    }
305
58.9k
                                }
306
3.03M
                                pdfi_clearstack(ctx);
307
3.03M
                            }
308
3.09M
                    }
309
3.09M
                    code = pdfi_skip_white(ctx, ctx->main_stream);
310
3.09M
                    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.09M
                }
318
19.2M
                if (pdfi_count_stack(ctx) > 0 && pdfi_type_of(ctx->stack_top[-1]) != PDF_INT)
319
3.55M
                    pdfi_clearstack(ctx);
320
19.2M
            }
321
23.2M
        } while (ctx->main_stream->eof == false);
322
3.01M
    } while(ctx->main_stream->eof == false);
323
324
83.3k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
325
83.3k
    ctx->main_stream->eof = false;
326
327
    /* Second pass, examine every object we have located to see if its an ObjStm */
328
83.3k
    if (ctx->xref_table == NULL || ctx->xref_table->xref_size < 1) {
329
7.12k
        code = gs_note_error(gs_error_syntaxerror);
330
7.12k
        goto exit;
331
7.12k
    }
332
333
198M
    for (i=1;i < ctx->xref_table->xref_size;i++) {
334
198M
        if (ctx->xref_table->xref[i].object_num != 0) {
335
            /* At this stage, all the objects we've found must be uncompressed */
336
4.15M
            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.36k
                ctx->xref_table->xref[i].free = 1;
342
9.36k
                ctx->xref_table->xref[i].u.uncompressed.offset = 0;
343
9.36k
                continue;
344
9.36k
            }
345
346
4.14M
            pdfi_seek(ctx, ctx->main_stream, ctx->xref_table->xref[i].u.uncompressed.offset, SEEK_SET);
347
133M
            do {
348
133M
                code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
349
133M
                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
204k
                    code = 0;
355
204k
                    break;
356
204k
                }
357
133M
                if (code < 0)
358
0
                    goto exit;
359
133M
                if (pdfi_type_of(ctx->stack_top[-1]) == PDF_FAST_KEYWORD) {
360
11.1M
                    pdf_obj *k = ctx->stack_top[-1];
361
362
11.1M
                    if (k == PDF_TOKEN_AS_OBJ(TOKEN_OBJ)) {
363
3.66M
                        continue;
364
3.66M
                    }
365
7.50M
                    if (k == PDF_TOKEN_AS_OBJ(TOKEN_ENDOBJ)) {
366
2.86M
                        if (pdfi_count_stack(ctx) > 1) {
367
2.83M
                            if (pdfi_type_of(ctx->stack_top[-2]) == PDF_DICT) {
368
1.82M
                                pdf_dict *d = (pdf_dict *)ctx->stack_top[-2];
369
1.82M
                                pdf_obj *o = NULL;
370
371
1.82M
                                code = pdfi_dict_knownget_type(ctx, d, "Type", PDF_NAME, &o);
372
1.82M
                                if (code < 0) {
373
233
                                    pdfi_clearstack(ctx);
374
233
                                    continue;
375
233
                                }
376
1.82M
                                if (code > 0) {
377
934k
                                    pdf_name *n = (pdf_name *)o;
378
379
934k
                                    if (pdfi_name_is(n, "Catalog")) {
380
104k
                                        pdfi_countdown(ctx->Root); /* In case it was already set */
381
104k
                                        ctx->Root = (pdf_dict *)ctx->stack_top[-2];
382
104k
                                        pdfi_countup(ctx->Root);
383
104k
                                    }
384
934k
                                }
385
1.82M
                                pdfi_countdown(o);
386
1.82M
                            }
387
2.83M
                        }
388
2.86M
                        pdfi_clearstack(ctx);
389
2.86M
                        break;
390
2.86M
                    }
391
4.63M
                    if (k == PDF_TOKEN_AS_OBJ(TOKEN_STREAM)) {
392
1.07M
                        pdf_dict *d;
393
1.07M
                        pdf_name *n = NULL;
394
395
1.07M
                        if (pdfi_count_stack(ctx) <= 1) {
396
1.52k
                            pdfi_clearstack(ctx);
397
1.52k
                            break;;
398
0
                        }
399
1.07M
                        d = (pdf_dict *)ctx->stack_top[-2];
400
1.07M
                        if (pdfi_type_of(d) != PDF_DICT) {
401
23.3k
                            pdfi_clearstack(ctx);
402
23.3k
                            break;;
403
0
                        }
404
1.05M
                        code = pdfi_dict_knownget_type(ctx, d, "Type", PDF_NAME, (pdf_obj **)&n);
405
1.05M
                        if (code < 0) {
406
48
                            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
48
                        }
411
1.05M
                        if (code > 0) {
412
468k
                            if (pdfi_name_is(n, "ObjStm")) {
413
47.1k
                                int64_t N;
414
47.1k
                                int obj_num, offset;
415
47.1k
                                int j;
416
47.1k
                                pdf_c_stream *compressed_stream;
417
47.1k
                                pdf_stream *stream;
418
419
47.1k
                                offset = pdfi_unread_tell(ctx);
420
47.1k
                                pdfi_seek(ctx, ctx->main_stream, offset, SEEK_SET);
421
422
47.1k
                                code = pdfi_obj_dict_to_stream(ctx, d, &stream, true);
423
47.1k
                                if (code == 0)
424
47.1k
                                    code = pdfi_filter(ctx, stream, ctx->main_stream, &compressed_stream, false);
425
426
47.1k
                                pdfi_countdown(stream);
427
428
47.1k
                                if (code == 0) {
429
46.8k
                                    code = pdfi_dict_get_int(ctx, d, "N", &N);
430
46.8k
                                    if (code == 0) {
431
1.55M
                                        for (j=0;j < N; j++) {
432
1.51M
                                            code = pdfi_read_bare_int(ctx, compressed_stream, &obj_num);
433
1.51M
                                            if (code <= 0)
434
5.43k
                                                break;
435
1.51M
                                            else {
436
1.51M
                                                code = pdfi_read_bare_int(ctx, compressed_stream, &offset);
437
1.51M
                                                if (code > 0) {
438
1.50M
                                                    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.50M
                                                    if (obj_num >= ctx->xref_table->xref_size)
446
55.5k
                                                        code = pdfi_repair_add_object(ctx, obj_num, 0, 0);
447
448
1.50M
                                                    if (code >= 0) {
449
1.50M
                                                        ctx->xref_table->xref[obj_num].compressed = true;
450
1.50M
                                                        ctx->xref_table->xref[obj_num].free = false;
451
1.50M
                                                        ctx->xref_table->xref[obj_num].object_num = obj_num;
452
1.50M
                                                        ctx->xref_table->xref[obj_num].u.compressed.compressed_stream_num = i;
453
1.50M
                                                        ctx->xref_table->xref[obj_num].u.compressed.object_index = j;
454
1.50M
                                                    }
455
1.50M
                                                }
456
1.51M
                                            }
457
1.51M
                                        }
458
46.7k
                                    }
459
46.8k
                                    pdfi_close_file(ctx, compressed_stream);
460
46.8k
                                }
461
47.1k
                                if (code < 0) {
462
3.68k
                                    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
3.68k
                                }
468
47.1k
                            }
469
468k
                        }
470
1.05M
                        pdfi_countdown(n);
471
1.05M
                        pdfi_clearstack(ctx);
472
1.05M
                        break;
473
1.05M
                    }
474
4.63M
                }
475
133M
            } while (1);
476
4.14M
        }
477
198M
    }
478
479
84.4k
exit:
480
84.4k
    if (code > 0)
481
23.9k
        code = 0;
482
84.4k
    pdfi_seek(ctx, ctx->main_stream, saved_offset, SEEK_SET);
483
84.4k
    ctx->main_stream->eof = false;
484
84.4k
    ctx->repairing = false;
485
84.4k
    return code;
486
76.1k
}