Coverage Report

Created: 2024-09-08 06:22

/src/mupdf/source/pdf/pdf-write.c
Line
Count
Source (jump to first uncovered line)
1
// Copyright (C) 2004-2024 Artifex Software, Inc.
2
//
3
// This file is part of MuPDF.
4
//
5
// MuPDF is free software: you can redistribute it and/or modify it under the
6
// terms of the GNU Affero General Public License as published by the Free
7
// Software Foundation, either version 3 of the License, or (at your option)
8
// any later version.
9
//
10
// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
// details.
14
//
15
// You should have received a copy of the GNU Affero General Public License
16
// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17
//
18
// Alternative licensing terms are available from the licensor.
19
// For commercial licensing, see <https://www.artifex.com/> or contact
20
// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21
// CA 94129, USA, for further information.
22
23
#include "mupdf/fitz.h"
24
#include "pdf-annot-imp.h"
25
26
#include <zlib.h>
27
28
#include <assert.h>
29
#include <limits.h>
30
#include <string.h>
31
32
#include <stdio.h> /* for debug printing */
33
/* #define DEBUG_LINEARIZATION */
34
/* #define DEBUG_HEAP_SORT */
35
/* #define DEBUG_WRITING */
36
/* #define DEBUG_MARK_AND_SWEEP */
37
38
0
#define SIG_EXTRAS_SIZE (1024)
39
40
0
#define SLASH_BYTE_RANGE ("/ByteRange")
41
0
#define SLASH_CONTENTS ("/Contents")
42
0
#define SLASH_FILTER ("/Filter")
43
44
45
/*
46
  As part of linearization, we need to keep a list of what objects are used
47
  by what page. We do this by recording the objects used in a given page
48
  in a page_objects structure. We have a list of these structures (one per
49
  page) in the page_objects_list structure.
50
51
  The page_objects structure maintains a heap in the object array, so
52
  insertion takes log n time, and we can heapsort and dedupe at the end for
53
  a total worse case n log n time.
54
55
  The magic heap invariant is that:
56
    entry[n] >= entry[(n+1)*2-1] & entry[n] >= entry[(n+1)*2]
57
  or equivalently:
58
    entry[(n-1)>>1] >= entry[n]
59
60
  For a discussion of the heap data structure (and heapsort) see Kingston,
61
  "Algorithms and Data Structures".
62
*/
63
64
typedef struct {
65
  int num_shared;
66
  int page_object_number;
67
  int num_objects;
68
  int min_ofs;
69
  int max_ofs;
70
  /* Extensible list of objects used on this page */
71
  int cap;
72
  int len;
73
  int object[1];
74
} page_objects;
75
76
typedef struct {
77
  int cap;
78
  int len;
79
  page_objects *page[1];
80
} page_objects_list;
81
82
typedef struct
83
{
84
  fz_output *out;
85
86
  int do_incremental;
87
  int do_tight;
88
  int do_ascii;
89
  int do_expand;
90
  int do_compress;
91
  int do_compress_images;
92
  int do_compress_fonts;
93
  int do_garbage;
94
  int do_linear;
95
  int do_clean;
96
  int do_encrypt;
97
  int dont_regenerate_id;
98
  int do_snapshot;
99
  int do_preserve_metadata;
100
  int do_use_objstms;
101
  int compression_effort;
102
103
  int list_len;
104
  int *use_list;
105
  int64_t *ofs_list;
106
  int *gen_list;
107
  int *renumber_map;
108
109
  /* The following extras are required for linearization */
110
  int *rev_renumber_map;
111
  int start;
112
  int64_t first_xref_offset;
113
  int64_t main_xref_offset;
114
  int64_t first_xref_entry_offset;
115
  int64_t file_len;
116
  int hints_shared_offset;
117
  int64_t hintstream_len;
118
  pdf_obj *linear_l;
119
  pdf_obj *linear_h0;
120
  pdf_obj *linear_h1;
121
  pdf_obj *linear_o;
122
  pdf_obj *linear_e;
123
  pdf_obj *linear_n;
124
  pdf_obj *linear_t;
125
  pdf_obj *hints_s;
126
  pdf_obj *hints_length;
127
  int hint_object_num;
128
  int page_count;
129
  page_objects_list *page_object_lists;
130
  int crypt_object_number;
131
  char opwd_utf8[128];
132
  char upwd_utf8[128];
133
  int permissions;
134
  pdf_crypt *crypt;
135
  pdf_obj *crypt_obj;
136
  pdf_obj *metadata;
137
} pdf_write_state;
138
139
/*
140
 * Constants for use with use_list.
141
 *
142
 * If use_list[num] = 0, then object num is unused.
143
 * If use_list[num] & PARAMS, then object num is the linearisation params obj.
144
 * If use_list[num] & CATALOGUE, then object num is used by the catalogue.
145
 * If use_list[num] & PAGE1, then object num is used by page 1.
146
 * If use_list[num] & SHARED, then object num is shared between pages.
147
 * If use_list[num] & PAGE_OBJECT then this must be the first object in a page.
148
 * If use_list[num] & OTHER_OBJECTS then this must should appear in section 9.
149
 * Otherwise object num is used by page (use_list[num]>>USE_PAGE_SHIFT).
150
 */
151
enum
152
{
153
  USE_CATALOGUE = 2,
154
  USE_PAGE1 = 4,
155
  USE_SHARED = 8,
156
  USE_PARAMS = 16,
157
  USE_HINTS = 32,
158
  USE_PAGE_OBJECT = 64,
159
  USE_OTHER_OBJECTS = 128,
160
  USE_PAGE_MASK = ~255,
161
  USE_PAGE_SHIFT = 8
162
};
163
164
static void
165
expand_lists(fz_context *ctx, pdf_write_state *opts, int num)
166
0
{
167
0
  int i;
168
169
  /* objects are numbered 0..num and maybe two additional objects for linearization */
170
0
  num += 3;
171
0
  if (num <= opts->list_len)
172
0
    return;
173
174
0
  opts->use_list = fz_realloc_array(ctx, opts->use_list, num, int);
175
0
  opts->ofs_list = fz_realloc_array(ctx, opts->ofs_list, num, int64_t);
176
0
  opts->gen_list = fz_realloc_array(ctx, opts->gen_list, num, int);
177
0
  opts->renumber_map = fz_realloc_array(ctx, opts->renumber_map, num, int);
178
0
  opts->rev_renumber_map = fz_realloc_array(ctx, opts->rev_renumber_map, num, int);
179
180
0
  for (i = opts->list_len; i < num; i++)
181
0
  {
182
0
    opts->use_list[i] = 0;
183
0
    opts->ofs_list[i] = 0;
184
0
    opts->gen_list[i] = 0;
185
0
    opts->renumber_map[i] = i;
186
0
    opts->rev_renumber_map[i] = i;
187
0
  }
188
0
  opts->list_len = num;
189
0
}
190
191
/*
192
 * page_objects and page_object_list handling functions
193
 */
194
static page_objects_list *
195
page_objects_list_create(fz_context *ctx)
196
0
{
197
0
  page_objects_list *pol = fz_calloc(ctx, 1, sizeof(*pol));
198
199
0
  pol->cap = 1;
200
0
  pol->len = 0;
201
0
  return pol;
202
0
}
203
204
static void
205
page_objects_list_destroy(fz_context *ctx, page_objects_list *pol)
206
0
{
207
0
  int i;
208
209
0
  if (!pol)
210
0
    return;
211
0
  for (i = 0; i < pol->len; i++)
212
0
  {
213
0
    fz_free(ctx, pol->page[i]);
214
0
  }
215
0
  fz_free(ctx, pol);
216
0
}
217
218
static void
219
page_objects_list_ensure(fz_context *ctx, page_objects_list **pol, int newcap)
220
0
{
221
0
  int oldcap = (*pol)->cap;
222
0
  if (newcap <= oldcap)
223
0
    return;
224
0
  *pol = fz_realloc(ctx, *pol, sizeof(page_objects_list) + (newcap-1)*sizeof(page_objects *));
225
0
  memset(&(*pol)->page[oldcap], 0, (newcap-oldcap)*sizeof(page_objects *));
226
0
  (*pol)->cap = newcap;
227
0
}
228
229
static page_objects *
230
page_objects_create(fz_context *ctx)
231
0
{
232
0
  int initial_cap = 8;
233
0
  page_objects *po = fz_calloc(ctx, 1, sizeof(*po) + (initial_cap-1) * sizeof(int));
234
235
0
  po->cap = initial_cap;
236
0
  po->len = 0;
237
0
  return po;
238
0
}
239
240
static void
241
page_objects_insert(fz_context *ctx, page_objects **ppo, int i)
242
0
{
243
0
  page_objects *po;
244
245
  /* Make a page_objects if we don't have one */
246
0
  if (*ppo == NULL)
247
0
    *ppo = page_objects_create(ctx);
248
249
0
  po = *ppo;
250
  /* page_objects insertion: extend the page_objects by 1, and put us on the end */
251
0
  if (po->len == po->cap)
252
0
  {
253
0
    po = fz_realloc(ctx, po, sizeof(page_objects) + (po->cap*2 - 1)*sizeof(int));
254
0
    po->cap *= 2;
255
0
    *ppo = po;
256
0
  }
257
0
  po->object[po->len++] = i;
258
0
}
259
260
static void
261
page_objects_list_insert(fz_context *ctx, pdf_write_state *opts, int page, int object)
262
0
{
263
0
  page_objects_list_ensure(ctx, &opts->page_object_lists, page+1);
264
0
  if (object >= opts->list_len)
265
0
    expand_lists(ctx, opts, object);
266
0
  if (opts->page_object_lists->len < page+1)
267
0
    opts->page_object_lists->len = page+1;
268
0
  page_objects_insert(ctx, &opts->page_object_lists->page[page], object);
269
0
}
270
271
static void
272
page_objects_list_set_page_object(fz_context *ctx, pdf_write_state *opts, int page, int object)
273
0
{
274
0
  page_objects_list_ensure(ctx, &opts->page_object_lists, page+1);
275
0
  if (object >= opts->list_len)
276
0
    expand_lists(ctx, opts, object);
277
0
  opts->page_object_lists->page[page]->page_object_number = object;
278
0
}
279
280
static void
281
page_objects_sort(fz_context *ctx, page_objects *po)
282
0
{
283
0
  int i, j;
284
0
  int n = po->len;
285
286
  /* Step 1: Make a heap */
287
  /* Invariant: Valid heap in [0..i), unsorted elements in [i..n) */
288
0
  for (i = 1; i < n; i++)
289
0
  {
290
    /* Now bubble backwards to maintain heap invariant */
291
0
    j = i;
292
0
    while (j != 0)
293
0
    {
294
0
      int tmp;
295
0
      int k = (j-1)>>1;
296
0
      if (po->object[k] >= po->object[j])
297
0
        break;
298
0
      tmp = po->object[k];
299
0
      po->object[k] = po->object[j];
300
0
      po->object[j] = tmp;
301
0
      j = k;
302
0
    }
303
0
  }
304
305
  /* Step 2: Heap sort */
306
  /* Invariant: valid heap in [0..i), sorted list in [i..n) */
307
  /* Initially: i = n */
308
0
  for (i = n-1; i > 0; i--)
309
0
  {
310
    /* Swap the maximum (0th) element from the page_objects into its place
311
     * in the sorted list (position i). */
312
0
    int tmp = po->object[0];
313
0
    po->object[0] = po->object[i];
314
0
    po->object[i] = tmp;
315
    /* Now, the page_objects is invalid because the 0th element is out
316
     * of place. Bubble it until the page_objects is valid. */
317
0
    j = 0;
318
0
    while (1)
319
0
    {
320
      /* Children are k and k+1 */
321
0
      int k = (j+1)*2-1;
322
      /* If both children out of the page_objects, we're done */
323
0
      if (k > i-1)
324
0
        break;
325
      /* If both are in the page_objects, pick the larger one */
326
0
      if (k < i-1 && po->object[k] < po->object[k+1])
327
0
        k++;
328
      /* If j is bigger than k (i.e. both of its children),
329
       * we're done */
330
0
      if (po->object[j] > po->object[k])
331
0
        break;
332
0
      tmp = po->object[k];
333
0
      po->object[k] = po->object[j];
334
0
      po->object[j] = tmp;
335
0
      j = k;
336
0
    }
337
0
  }
338
0
}
339
340
static int
341
order_ge(int ui, int uj)
342
0
{
343
  /*
344
  For linearization, we need to order the sections as follows:
345
346
    Remaining pages         (Part 7)
347
    Shared objects          (Part 8)
348
    Objects not associated with any page    (Part 9)
349
    Any "other" objects
350
              (Header)(Part 1)
351
    (Linearization params)        (Part 2)
352
          (1st page Xref/Trailer) (Part 3)
353
    Catalogue (and other document level objects)  (Part 4)
354
    First page          (Part 6)
355
    (Primary Hint stream)     (*) (Part 5)
356
    Any free objects
357
358
  Note, this is NOT the same order they appear in
359
  the final file!
360
361
  (*) The PDF reference gives us the option of putting the hint stream
362
  after the first page, and we take it, for simplicity.
363
  */
364
365
  /* If the 2 objects are in the same section, then page object comes first. */
366
0
  if (((ui ^ uj) & ~USE_PAGE_OBJECT) == 0)
367
0
    return ((ui & USE_PAGE_OBJECT) == 0);
368
  /* Put unused objects last */
369
0
  else if (ui == 0)
370
0
    return 1;
371
0
  else if (uj == 0)
372
0
    return 0;
373
  /* Put the hint stream before that... */
374
0
  else if (ui & USE_HINTS)
375
0
    return 1;
376
0
  else if (uj & USE_HINTS)
377
0
    return 0;
378
  /* Put page 1 before that... */
379
0
  else if (ui & USE_PAGE1)
380
0
    return 1;
381
0
  else if (uj & USE_PAGE1)
382
0
    return 0;
383
  /* Put the catalogue before that... */
384
0
  else if (ui & USE_CATALOGUE)
385
0
    return 1;
386
0
  else if (uj & USE_CATALOGUE)
387
0
    return 0;
388
  /* Put the linearization params before that... */
389
0
  else if (ui & USE_PARAMS)
390
0
    return 1;
391
0
  else if (uj & USE_PARAMS)
392
0
    return 0;
393
  /* Put other objects before that */
394
0
  else if (ui & USE_OTHER_OBJECTS)
395
0
    return 1;
396
0
  else if (uj & USE_OTHER_OBJECTS)
397
0
    return 0;
398
  /* Put shared objects before that... */
399
0
  else if (ui & USE_SHARED)
400
0
    return 1;
401
0
  else if (uj & USE_SHARED)
402
0
    return 0;
403
  /* And otherwise, order by the page number on which
404
   * they are used. */
405
0
  return (ui>>USE_PAGE_SHIFT) >= (uj>>USE_PAGE_SHIFT);
406
0
}
407
408
static void
409
heap_sort(int *list, int n, const int *val, int (*ge)(int, int))
410
0
{
411
0
  int i, j;
412
413
#ifdef DEBUG_HEAP_SORT
414
  fprintf(stderr, "Initially:\n");
415
  for (i=0; i < n; i++)
416
  {
417
    fprintf(stderr, "%d: %d %x\n", i, list[i], val[list[i]]);
418
  }
419
#endif
420
  /* Step 1: Make a heap */
421
  /* Invariant: Valid heap in [0..i), unsorted elements in [i..n) */
422
0
  for (i = 1; i < n; i++)
423
0
  {
424
    /* Now bubble backwards to maintain heap invariant */
425
0
    j = i;
426
0
    while (j != 0)
427
0
    {
428
0
      int tmp;
429
0
      int k = (j-1)>>1;
430
0
      if (ge(val[list[k]], val[list[j]]))
431
0
        break;
432
0
      tmp = list[k];
433
0
      list[k] = list[j];
434
0
      list[j] = tmp;
435
0
      j = k;
436
0
    }
437
0
  }
438
#ifdef DEBUG_HEAP_SORT
439
  fprintf(stderr, "Valid heap:\n");
440
  for (i=0; i < n; i++)
441
  {
442
    int k;
443
    fprintf(stderr, "%d: %d %x ", i, list[i], val[list[i]]);
444
    k = (i+1)*2-1;
445
    if (k < n)
446
    {
447
      if (ge(val[list[i]], val[list[k]]))
448
        fprintf(stderr, "OK ");
449
      else
450
        fprintf(stderr, "BAD ");
451
    }
452
    if (k+1 < n)
453
    {
454
      if (ge(val[list[i]], val[list[k+1]]))
455
        fprintf(stderr, "OK\n");
456
      else
457
        fprintf(stderr, "BAD\n");
458
    }
459
    else
460
        fprintf(stderr, "\n");
461
  }
462
#endif
463
464
  /* Step 2: Heap sort */
465
  /* Invariant: valid heap in [0..i), sorted list in [i..n) */
466
  /* Initially: i = n */
467
0
  for (i = n-1; i > 0; i--)
468
0
  {
469
    /* Swap the maximum (0th) element from the page_objects into its place
470
     * in the sorted list (position i). */
471
0
    int tmp = list[0];
472
0
    list[0] = list[i];
473
0
    list[i] = tmp;
474
    /* Now, the page_objects is invalid because the 0th element is out
475
     * of place. Bubble it until the page_objects is valid. */
476
0
    j = 0;
477
0
    while (1)
478
0
    {
479
      /* Children are k and k+1 */
480
0
      int k = (j+1)*2-1;
481
      /* If both children out of the page_objects, we're done */
482
0
      if (k > i-1)
483
0
        break;
484
      /* If both are in the page_objects, pick the larger one */
485
0
      if (k < i-1 && ge(val[list[k+1]], val[list[k]]))
486
0
        k++;
487
      /* If j is bigger than k (i.e. both of its children),
488
       * we're done */
489
0
      if (ge(val[list[j]], val[list[k]]))
490
0
        break;
491
0
      tmp = list[k];
492
0
      list[k] = list[j];
493
0
      list[j] = tmp;
494
0
      j = k;
495
0
    }
496
0
  }
497
#ifdef DEBUG_HEAP_SORT
498
  fprintf(stderr, "Sorted:\n");
499
  for (i=0; i < n; i++)
500
  {
501
    fprintf(stderr, "%d: %d %x ", i, list[i], val[list[i]]);
502
    if (i+1 < n)
503
    {
504
      if (ge(val[list[i+1]], val[list[i]]))
505
        fprintf(stderr, "OK");
506
      else
507
        fprintf(stderr, "BAD");
508
    }
509
    fprintf(stderr, "\n");
510
  }
511
#endif
512
0
}
513
514
static void
515
page_objects_dedupe(fz_context *ctx, page_objects *po)
516
0
{
517
0
  int i, j;
518
0
  int n = po->len-1;
519
520
0
  for (i = 0; i < n; i++)
521
0
  {
522
0
    if (po->object[i] == po->object[i+1])
523
0
      break;
524
0
  }
525
0
  j = i; /* j points to the last valid one */
526
0
  i++; /* i points to the first one we haven't looked at */
527
0
  for (; i < n; i++)
528
0
  {
529
0
    if (po->object[j] != po->object[i])
530
0
      po->object[++j] = po->object[i];
531
0
  }
532
0
  po->len = j+1;
533
0
}
534
535
static void
536
page_objects_list_sort_and_dedupe(fz_context *ctx, page_objects_list *pol)
537
0
{
538
0
  int i;
539
0
  int n = pol->len;
540
541
0
  for (i = 0; i < n; i++)
542
0
  {
543
0
    page_objects_sort(ctx, pol->page[i]);
544
0
    page_objects_dedupe(ctx, pol->page[i]);
545
0
  }
546
0
}
547
548
#ifdef DEBUG_LINEARIZATION
549
static void
550
page_objects_dump(pdf_write_state *opts)
551
{
552
  page_objects_list *pol = opts->page_object_lists;
553
  int i, j;
554
555
  for (i = 0; i < pol->len; i++)
556
  {
557
    page_objects *p = pol->page[i];
558
    fprintf(stderr, "Page %d\n", i+1);
559
    for (j = 0; j < p->len; j++)
560
    {
561
      int o = p->object[j];
562
      fprintf(stderr, "\tObject %d: use=%x\n", o, opts->use_list[o]);
563
    }
564
    fprintf(stderr, "Byte range=%d->%d\n", p->min_ofs, p->max_ofs);
565
    fprintf(stderr, "Number of objects=%d, Number of shared objects=%d\n", p->num_objects, p->num_shared);
566
    fprintf(stderr, "Page object number=%d\n", p->page_object_number);
567
  }
568
}
569
570
static void
571
objects_dump(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
572
{
573
  int i;
574
575
  for (i=0; i < pdf_xref_len(ctx, doc); i++)
576
  {
577
    fprintf(stderr, "Object %d use=%x offset=%d\n", i, opts->use_list[i], (int)opts->ofs_list[i]);
578
  }
579
}
580
#endif
581
582
/*
583
 * Garbage collect objects not reachable from the trailer.
584
 */
585
586
/* Mark a reference. If it's been marked already, return NULL (as no further
587
 * processing is required). If it's not, return the resolved object so
588
 * that we can continue our recursive marking. If it's a duff reference
589
 * return the fact so that we can remove the reference at source.
590
 */
591
static pdf_obj *markref(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, pdf_obj *obj, int *duff)
592
0
{
593
0
  int num = pdf_to_num(ctx, obj);
594
0
  int xref_len = pdf_xref_len(ctx, doc);
595
596
0
  if (num <= 0 || num >= xref_len)
597
0
  {
598
0
    *duff = 1;
599
0
    return NULL;
600
0
  }
601
0
  expand_lists(ctx, opts, xref_len);
602
0
  *duff = 0;
603
0
  if (opts->use_list[num])
604
0
    return NULL;
605
606
0
  opts->use_list[num] = 1;
607
608
  /* Bake in /Length in stream objects */
609
0
  fz_try(ctx)
610
0
  {
611
0
    if (pdf_obj_num_is_stream(ctx, doc, num))
612
0
    {
613
0
      pdf_obj *len = pdf_dict_get(ctx, obj, PDF_NAME(Length));
614
0
      if (pdf_is_indirect(ctx, len))
615
0
      {
616
0
        int num2 = pdf_to_num(ctx, len);
617
0
        expand_lists(ctx, opts, num2+1);
618
0
        opts->use_list[num2] = 0;
619
0
        len = pdf_resolve_indirect(ctx, len);
620
0
        pdf_dict_put(ctx, obj, PDF_NAME(Length), len);
621
0
      }
622
0
    }
623
0
  }
624
0
  fz_catch(ctx)
625
0
  {
626
    /* Leave broken */
627
0
  }
628
629
0
  obj = pdf_resolve_indirect(ctx, obj);
630
0
  if (obj == NULL || pdf_is_null(ctx, obj))
631
0
  {
632
0
    *duff = 1;
633
0
    opts->use_list[num] = 0;
634
0
  }
635
636
0
  return obj;
637
0
}
638
639
#ifdef DEBUG_MARK_AND_SWEEP
640
static int depth = 0;
641
642
static
643
void indent()
644
{
645
  while (depth > 0)
646
  {
647
    int d  = depth;
648
    if (d > 16)
649
      d = 16;
650
    printf("%s", &"                "[16-d]);
651
    depth -= d;
652
  }
653
}
654
#define DEBUGGING_MARKING(A) do { A; } while (0)
655
#else
656
0
#define DEBUGGING_MARKING(A) do { } while (0)
657
#endif
658
659
/* Recursively mark an object. If any references found are duff, then
660
 * replace them with nulls. */
661
static int markobj(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, pdf_obj *obj)
662
0
{
663
0
  int i;
664
665
0
  DEBUGGING_MARKING(depth++);
666
667
0
  while (pdf_is_indirect(ctx, obj))
668
0
  {
669
0
    int duff;
670
0
    DEBUGGING_MARKING(indent(); printf("Marking object %d\n", pdf_to_num(ctx, obj)));
671
0
    obj = markref(ctx, doc, opts, obj, &duff);
672
0
    if (duff)
673
0
    {
674
0
      DEBUGGING_MARKING(depth--);
675
0
      return 1;
676
0
    }
677
0
  }
678
679
0
  if (pdf_is_dict(ctx, obj))
680
0
  {
681
0
    int n = pdf_dict_len(ctx, obj);
682
0
    for (i = 0; i < n; i++)
683
0
    {
684
0
      DEBUGGING_MARKING(indent(); printf("DICT[%d/%d] = %s\n", i, n, pdf_to_name(ctx, pdf_dict_get_key(ctx, obj, i))));
685
0
      if (markobj(ctx, doc, opts, pdf_dict_get_val(ctx, obj, i)))
686
0
        pdf_dict_put_val_null(ctx, obj, i);
687
0
    }
688
0
  }
689
690
0
  else if (pdf_is_array(ctx, obj))
691
0
  {
692
0
    int n = pdf_array_len(ctx, obj);
693
0
    for (i = 0; i < n; i++)
694
0
    {
695
0
      DEBUGGING_MARKING(indent(); printf("ARRAY[%d/%d]\n", i, n));
696
0
      if (markobj(ctx, doc, opts, pdf_array_get(ctx, obj, i)))
697
0
        pdf_array_put(ctx, obj, i, PDF_NULL);
698
0
    }
699
0
  }
700
701
0
  DEBUGGING_MARKING(depth--);
702
703
0
  return 0;
704
0
}
705
706
/*
707
 * Scan for and remove duplicate objects (slow)
708
 */
709
710
static void removeduplicateobjs(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
711
0
{
712
0
  int num, other;
713
0
  int xref_len = pdf_xref_len(ctx, doc);
714
715
0
  expand_lists(ctx, opts, xref_len);
716
0
  for (num = 1; num < xref_len; num++)
717
0
  {
718
    /* Only compare an object to objects preceding it */
719
0
    for (other = 1; other < num; other++)
720
0
    {
721
0
      pdf_obj *a, *b;
722
0
      int newnum;
723
724
0
      if (num == other || num >= opts->list_len || !opts->use_list[num] || !opts->use_list[other])
725
0
        continue;
726
727
      /* TODO: resolve indirect references to see if we can omit them */
728
729
0
      a = pdf_get_xref_entry_no_null(ctx, doc, num)->obj;
730
0
      b = pdf_get_xref_entry_no_null(ctx, doc, other)->obj;
731
0
      if (opts->do_garbage >= 4)
732
0
      {
733
0
        if (pdf_objcmp_deep(ctx, a, b))
734
0
          continue;
735
0
      }
736
0
      else
737
0
      {
738
0
        if (pdf_objcmp(ctx, a, b))
739
0
          continue;
740
0
      }
741
742
      /* Keep the lowest numbered object */
743
0
      newnum = fz_mini(num, other);
744
0
      opts->renumber_map[num] = newnum;
745
0
      opts->renumber_map[other] = newnum;
746
0
      opts->rev_renumber_map[newnum] = num; /* Either will do */
747
0
      opts->use_list[fz_maxi(num, other)] = 0;
748
749
      /* One duplicate was found, do not look for another */
750
0
      break;
751
0
    }
752
0
  }
753
0
}
754
755
/*
756
 * Renumber objects sequentially so the xref is more compact
757
 *
758
 * This code assumes that any opts->renumber_map[n] <= n for all n.
759
 */
760
761
static void compactxref(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
762
0
{
763
0
  int num, newnum;
764
0
  int xref_len = pdf_xref_len(ctx, doc);
765
766
  /*
767
   * Update renumber_map in-place, clustering all used
768
   * objects together at low object ids. Objects that
769
   * already should be renumbered will have their new
770
   * object ids be updated to reflect the compaction.
771
   */
772
773
0
  if (xref_len > opts->list_len)
774
0
    expand_lists(ctx, opts, xref_len-1);
775
776
0
  newnum = 1;
777
0
  for (num = 1; num < xref_len; num++)
778
0
  {
779
    /* If it's not used, map it to zero */
780
0
    if (!opts->use_list[opts->renumber_map[num]])
781
0
    {
782
0
      opts->renumber_map[num] = 0;
783
0
    }
784
    /* If it's not moved, compact it. */
785
0
    else if (opts->renumber_map[num] == num)
786
0
    {
787
0
      opts->rev_renumber_map[newnum] = opts->rev_renumber_map[num];
788
0
      opts->renumber_map[num] = newnum++;
789
0
    }
790
    /* Otherwise it's used, and moved. We know that it must have
791
     * moved down, so the place it's moved to will be in the right
792
     * place already. */
793
0
    else
794
0
    {
795
0
      opts->renumber_map[num] = opts->renumber_map[opts->renumber_map[num]];
796
0
    }
797
0
  }
798
0
}
799
800
/*
801
 * Update indirect objects according to renumbering established when
802
 * removing duplicate objects and compacting the xref.
803
 */
804
805
static void renumberobj(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, pdf_obj *obj)
806
0
{
807
0
  int i;
808
0
  int xref_len = pdf_xref_len(ctx, doc);
809
810
0
  if (pdf_is_dict(ctx, obj))
811
0
  {
812
0
    int n = pdf_dict_len(ctx, obj);
813
0
    for (i = 0; i < n; i++)
814
0
    {
815
0
      pdf_obj *key = pdf_dict_get_key(ctx, obj, i);
816
0
      pdf_obj *val = pdf_dict_get_val(ctx, obj, i);
817
0
      if (pdf_is_indirect(ctx, val))
818
0
      {
819
0
        int o = pdf_to_num(ctx, val);
820
0
        if (o >= xref_len || o <= 0 || opts->renumber_map[o] == 0)
821
0
          val = PDF_NULL;
822
0
        else
823
0
          val = pdf_new_indirect(ctx, doc, opts->renumber_map[o], 0);
824
0
        pdf_dict_put_drop(ctx, obj, key, val);
825
0
      }
826
0
      else
827
0
      {
828
0
        renumberobj(ctx, doc, opts, val);
829
0
      }
830
0
    }
831
0
  }
832
833
0
  else if (pdf_is_array(ctx, obj))
834
0
  {
835
0
    int n = pdf_array_len(ctx, obj);
836
0
    for (i = 0; i < n; i++)
837
0
    {
838
0
      pdf_obj *val = pdf_array_get(ctx, obj, i);
839
0
      if (pdf_is_indirect(ctx, val))
840
0
      {
841
0
        int o = pdf_to_num(ctx, val);
842
0
        if (o >= xref_len || o <= 0 || opts->renumber_map[o] == 0)
843
0
          val = PDF_NULL;
844
0
        else
845
0
          val = pdf_new_indirect(ctx, doc, opts->renumber_map[o], 0);
846
0
        pdf_array_put_drop(ctx, obj, i, val);
847
0
      }
848
0
      else
849
0
      {
850
0
        renumberobj(ctx, doc, opts, val);
851
0
      }
852
0
    }
853
0
  }
854
0
}
855
856
static void renumberobjs(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
857
0
{
858
0
  pdf_xref_entry *newxref = NULL;
859
0
  int newlen;
860
0
  int num;
861
0
  int *new_use_list;
862
0
  int xref_len = pdf_xref_len(ctx, doc);
863
864
0
  new_use_list = fz_calloc(ctx, pdf_xref_len(ctx, doc)+3, sizeof(int));
865
866
0
  fz_var(newxref);
867
0
  fz_try(ctx)
868
0
  {
869
    /* Apply renumber map to indirect references in all objects in xref */
870
0
    renumberobj(ctx, doc, opts, pdf_trailer(ctx, doc));
871
0
    for (num = 0; num < xref_len; num++)
872
0
    {
873
0
      pdf_obj *obj;
874
0
      int to = opts->renumber_map[num];
875
876
      /* If object is going to be dropped, don't bother renumbering */
877
0
      if (to == 0)
878
0
        continue;
879
880
0
      obj = pdf_get_xref_entry_no_null(ctx, doc, num)->obj;
881
882
0
      if (pdf_is_indirect(ctx, obj))
883
0
      {
884
0
        obj = pdf_new_indirect(ctx, doc, to, 0);
885
0
        fz_try(ctx)
886
0
          pdf_update_object(ctx, doc, num, obj);
887
0
        fz_always(ctx)
888
0
          pdf_drop_obj(ctx, obj);
889
0
        fz_catch(ctx)
890
0
          fz_rethrow(ctx);
891
0
      }
892
0
      else
893
0
      {
894
0
        renumberobj(ctx, doc, opts, obj);
895
0
      }
896
0
    }
897
898
    /* Create new table for the reordered, compacted xref */
899
0
    newxref = Memento_label(fz_malloc_array(ctx, xref_len + 3, pdf_xref_entry), "pdf_xref_entries");
900
0
    newxref[0] = *pdf_get_xref_entry_no_null(ctx, doc, 0);
901
902
    /* Move used objects into the new compacted xref */
903
0
    newlen = 0;
904
0
    for (num = 1; num < xref_len; num++)
905
0
    {
906
0
      if (opts->use_list[num])
907
0
      {
908
0
        pdf_xref_entry *e;
909
0
        if (newlen < opts->renumber_map[num])
910
0
          newlen = opts->renumber_map[num];
911
0
        e = pdf_get_xref_entry_no_null(ctx, doc, num);
912
0
        newxref[opts->renumber_map[num]] = *e;
913
0
        if (e->obj)
914
0
          pdf_set_obj_parent(ctx, e->obj, opts->renumber_map[num]);
915
0
        e->obj = NULL;
916
0
        e->stm_buf = NULL;
917
0
        new_use_list[opts->renumber_map[num]] = opts->use_list[num];
918
0
      }
919
0
      else
920
0
      {
921
0
        pdf_xref_entry *e = pdf_get_xref_entry_no_null(ctx, doc, num);
922
0
        pdf_drop_obj(ctx, e->obj);
923
0
        e->obj = NULL;
924
0
        fz_drop_buffer(ctx, e->stm_buf);
925
0
        e->stm_buf = NULL;
926
0
      }
927
0
    }
928
929
0
    pdf_replace_xref(ctx, doc, newxref, newlen + 1);
930
0
    newxref = NULL;
931
0
  }
932
0
  fz_catch(ctx)
933
0
  {
934
0
    fz_free(ctx, newxref);
935
0
    fz_free(ctx, new_use_list);
936
0
    fz_rethrow(ctx);
937
0
  }
938
0
  fz_free(ctx, opts->use_list);
939
0
  opts->use_list = new_use_list;
940
941
0
  for (num = 1; num < xref_len; num++)
942
0
  {
943
0
    opts->renumber_map[num] = num;
944
0
  }
945
0
}
946
947
static void page_objects_list_renumber(pdf_write_state *opts)
948
0
{
949
0
  int i, j;
950
951
0
  for (i = 0; i < opts->page_object_lists->len; i++)
952
0
  {
953
0
    page_objects *po = opts->page_object_lists->page[i];
954
0
    for (j = 0; j < po->len; j++)
955
0
    {
956
0
      po->object[j] = opts->renumber_map[po->object[j]];
957
0
    }
958
0
    po->page_object_number = opts->renumber_map[po->page_object_number];
959
0
  }
960
0
}
961
962
static void
963
swap_indirect_obj(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, pdf_obj **obj)
964
0
{
965
0
  pdf_obj *o = pdf_new_indirect(ctx, doc, opts->renumber_map[pdf_to_num(ctx, *obj)], 0);
966
967
0
  pdf_drop_obj(ctx, *obj);
968
0
  *obj = o;
969
0
}
970
971
static void
972
renumber_pages(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
973
0
{
974
0
  fz_page *page;
975
976
0
  for (page = doc->super.open; page != NULL; page = page->next)
977
0
  {
978
0
    pdf_page *ppage = (pdf_page *)page;
979
0
    pdf_annot *annot;
980
0
    swap_indirect_obj(ctx, doc, opts, &ppage->obj);
981
982
0
    for (annot = ppage->annots; annot != NULL; annot = annot->next)
983
0
      swap_indirect_obj(ctx, doc, opts, &annot->obj);
984
0
    for (annot = ppage->widgets; annot != NULL; annot = annot->next)
985
0
      swap_indirect_obj(ctx, doc, opts, &annot->obj);
986
0
  }
987
0
}
988
989
static void
990
mark_all(fz_context *ctx, pdf_document *doc, pdf_mark_list *list, pdf_write_state *opts, pdf_obj *val, int flag, int page)
991
0
{
992
0
  if (pdf_mark_list_push(ctx, list, val))
993
0
    return;
994
995
0
  if (pdf_is_indirect(ctx, val))
996
0
  {
997
0
    int num = pdf_to_num(ctx, val);
998
0
    int bits = flag;
999
0
    if (num >= opts->list_len)
1000
0
      expand_lists(ctx, opts, num);
1001
0
    if (page >= 0)
1002
0
      page_objects_list_insert(ctx, opts, page, num);
1003
0
    if (opts->use_list[num] & USE_PAGE_MASK)
1004
      /* Already used */
1005
0
      bits = USE_SHARED;
1006
0
    if ((opts->use_list[num] | bits) == opts->use_list[num])
1007
0
    {
1008
      /* Been here already */
1009
0
      pdf_mark_list_pop(ctx, list);
1010
0
      return;
1011
0
    }
1012
0
    opts->use_list[num] |= bits;
1013
0
  }
1014
1015
0
  if (pdf_is_dict(ctx, val))
1016
0
  {
1017
0
    int i, n;
1018
0
    n = pdf_dict_len(ctx, val);
1019
1020
0
    for (i = 0; i < n; i++)
1021
0
    {
1022
0
      pdf_obj *v = pdf_dict_get_val(ctx, val, i);
1023
0
      pdf_obj *type = pdf_dict_get(ctx, v, PDF_NAME(Type));
1024
1025
      /* Don't walk through the Page tree, or direct to a page. */
1026
0
      if (pdf_name_eq(ctx, PDF_NAME(Pages), type) || pdf_name_eq(ctx, PDF_NAME(Page), type))
1027
0
        continue;
1028
1029
0
      mark_all(ctx, doc, list, opts, v, flag, page);
1030
0
    }
1031
0
  }
1032
0
  else if (pdf_is_array(ctx, val))
1033
0
  {
1034
0
    int i, n = pdf_array_len(ctx, val);
1035
1036
0
    for (i = 0; i < n; i++)
1037
0
    {
1038
0
      pdf_obj *v = pdf_array_get(ctx, val, i);
1039
0
      pdf_obj *type = pdf_dict_get(ctx, v, PDF_NAME(Type));
1040
1041
      /* Don't walk through the Page tree, or direct to a page. */
1042
0
      if (pdf_name_eq(ctx, PDF_NAME(Pages), type) || pdf_name_eq(ctx, PDF_NAME(Page), type))
1043
0
        continue;
1044
1045
0
      mark_all(ctx, doc, list, opts, v, flag, page);
1046
0
    }
1047
0
  }
1048
0
  pdf_mark_list_pop(ctx, list);
1049
0
}
1050
1051
static int
1052
mark_pages(fz_context *ctx, pdf_document *doc, pdf_mark_list *list, pdf_write_state *opts, pdf_obj *val, int pagenum)
1053
0
{
1054
0
  if (pdf_mark_list_push(ctx, list, val))
1055
0
    return pagenum;
1056
1057
0
  if (pdf_is_dict(ctx, val))
1058
0
  {
1059
0
    if (pdf_name_eq(ctx, PDF_NAME(Page), pdf_dict_get(ctx, val, PDF_NAME(Type))))
1060
0
    {
1061
0
      int num = pdf_to_num(ctx, val);
1062
0
      pdf_mark_list_pop(ctx, list);
1063
1064
0
      mark_all(ctx, doc, list, opts, val, pagenum == 0 ? USE_PAGE1 : (pagenum<<USE_PAGE_SHIFT), pagenum);
1065
0
      page_objects_list_set_page_object(ctx, opts, pagenum, num);
1066
0
      pagenum++;
1067
0
      opts->use_list[num] |= USE_PAGE_OBJECT;
1068
0
      return pagenum;
1069
0
    }
1070
0
    else
1071
0
    {
1072
0
      int i, n = pdf_dict_len(ctx, val);
1073
1074
0
      for (i = 0; i < n; i++)
1075
0
      {
1076
0
        pdf_obj *key = pdf_dict_get_key(ctx, val, i);
1077
0
        pdf_obj *obj = pdf_dict_get_val(ctx, val, i);
1078
1079
0
        if (pdf_name_eq(ctx, PDF_NAME(Kids), key))
1080
0
          pagenum = mark_pages(ctx, doc, list, opts, obj, pagenum);
1081
0
        else
1082
0
          mark_all(ctx, doc, list, opts, obj, USE_CATALOGUE, -1);
1083
0
      }
1084
1085
0
      if (pdf_is_indirect(ctx, val))
1086
0
      {
1087
0
        int num = pdf_to_num(ctx, val);
1088
0
        opts->use_list[num] |= USE_CATALOGUE;
1089
0
      }
1090
0
    }
1091
0
  }
1092
0
  else if (pdf_is_array(ctx, val))
1093
0
  {
1094
0
    int i, n = pdf_array_len(ctx, val);
1095
1096
0
    for (i = 0; i < n; i++)
1097
0
    {
1098
0
      pagenum = mark_pages(ctx, doc, list, opts, pdf_array_get(ctx, val, i), pagenum);
1099
0
    }
1100
0
    if (pdf_is_indirect(ctx, val))
1101
0
    {
1102
0
      int num = pdf_to_num(ctx, val);
1103
0
      opts->use_list[num] |= USE_CATALOGUE;
1104
0
    }
1105
0
  }
1106
0
  pdf_mark_list_pop(ctx, list);
1107
1108
0
  return pagenum;
1109
0
}
1110
1111
static void
1112
mark_root(fz_context *ctx, pdf_document *doc, pdf_mark_list *list, pdf_write_state *opts, pdf_obj *dict)
1113
0
{
1114
0
  int i, n = pdf_dict_len(ctx, dict);
1115
1116
0
  if (pdf_mark_list_push(ctx, list, dict))
1117
0
    return;
1118
1119
0
  if (pdf_is_indirect(ctx, dict))
1120
0
  {
1121
0
    int num = pdf_to_num(ctx, dict);
1122
0
    opts->use_list[num] |= USE_CATALOGUE;
1123
0
  }
1124
1125
0
  for (i = 0; i < n; i++)
1126
0
  {
1127
0
    pdf_obj *key = pdf_dict_get_key(ctx, dict, i);
1128
0
    pdf_obj *val = pdf_dict_get_val(ctx, dict, i);
1129
1130
0
    if (pdf_name_eq(ctx, PDF_NAME(Pages), key))
1131
0
      opts->page_count = mark_pages(ctx, doc, list, opts, val, 0);
1132
0
    else if (pdf_name_eq(ctx, PDF_NAME(Names), key))
1133
0
      mark_all(ctx, doc, list, opts, val, USE_OTHER_OBJECTS, -1);
1134
0
    else if (pdf_name_eq(ctx, PDF_NAME(Dests), key))
1135
0
      mark_all(ctx, doc, list, opts, val, USE_OTHER_OBJECTS, -1);
1136
0
    else if (pdf_name_eq(ctx, PDF_NAME(Outlines), key))
1137
0
    {
1138
0
      int section;
1139
      /* Look at PageMode to decide whether to
1140
       * USE_OTHER_OBJECTS or USE_PAGE1 here. */
1141
0
      if (pdf_name_eq(ctx, pdf_dict_get(ctx, dict, PDF_NAME(PageMode)), PDF_NAME(UseOutlines)))
1142
0
        section = USE_PAGE1;
1143
0
      else
1144
0
        section = USE_OTHER_OBJECTS;
1145
0
      mark_all(ctx, doc, list, opts, val, section, -1);
1146
0
    }
1147
0
    else
1148
0
      mark_all(ctx, doc, list, opts, val, USE_CATALOGUE, -1);
1149
0
  }
1150
0
  pdf_mark_list_pop(ctx, list);
1151
0
}
1152
1153
static void
1154
mark_trailer(fz_context *ctx, pdf_document *doc, pdf_mark_list *list, pdf_write_state *opts, pdf_obj *dict)
1155
0
{
1156
0
  int i, n = pdf_dict_len(ctx, dict);
1157
1158
0
  if (pdf_mark_list_push(ctx, list, dict))
1159
0
    return;
1160
1161
0
  for (i = 0; i < n; i++)
1162
0
  {
1163
0
    pdf_obj *key = pdf_dict_get_key(ctx, dict, i);
1164
0
    pdf_obj *val = pdf_dict_get_val(ctx, dict, i);
1165
1166
0
    if (pdf_name_eq(ctx, PDF_NAME(Root), key))
1167
0
      mark_root(ctx, doc, list, opts, val);
1168
0
    else
1169
0
      mark_all(ctx, doc, list, opts, val, USE_CATALOGUE, -1);
1170
0
  }
1171
0
  pdf_mark_list_pop(ctx, list);
1172
0
}
1173
1174
static void
1175
add_linearization_objs(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
1176
0
{
1177
0
  pdf_obj *params_obj = NULL;
1178
0
  pdf_obj *params_ref = NULL;
1179
0
  pdf_obj *hint_obj = NULL;
1180
0
  pdf_obj *hint_ref = NULL;
1181
0
  pdf_obj *o;
1182
0
  int params_num, hint_num;
1183
1184
0
  fz_var(params_obj);
1185
0
  fz_var(params_ref);
1186
0
  fz_var(hint_obj);
1187
0
  fz_var(hint_ref);
1188
1189
0
  fz_try(ctx)
1190
0
  {
1191
0
    pdf_xref_entry *xe;
1192
1193
    /* Linearization params */
1194
0
    params_obj = pdf_new_dict(ctx, doc, 10);
1195
0
    params_ref = pdf_add_object(ctx, doc, params_obj);
1196
0
    params_num = pdf_to_num(ctx, params_ref);
1197
1198
0
    opts->use_list[params_num] = USE_PARAMS;
1199
0
    opts->renumber_map[params_num] = params_num;
1200
0
    opts->rev_renumber_map[params_num] = params_num;
1201
0
    opts->gen_list[params_num] = 0;
1202
0
    pdf_dict_put_real(ctx, params_obj, PDF_NAME(Linearized), 1.0f);
1203
0
    opts->linear_l = pdf_new_int(ctx, INT_MIN);
1204
0
    pdf_dict_put(ctx, params_obj, PDF_NAME(L), opts->linear_l);
1205
0
    opts->linear_h0 = pdf_new_int(ctx, INT_MIN);
1206
0
    o = pdf_dict_put_array(ctx, params_obj, PDF_NAME(H), 2);
1207
0
    pdf_array_push(ctx, o, opts->linear_h0);
1208
0
    opts->linear_h1 = pdf_new_int(ctx, INT_MIN);
1209
0
    pdf_array_push(ctx, o, opts->linear_h1);
1210
0
    opts->linear_o = pdf_new_int(ctx, INT_MIN);
1211
0
    pdf_dict_put(ctx, params_obj, PDF_NAME(O), opts->linear_o);
1212
0
    opts->linear_e = pdf_new_int(ctx, INT_MIN);
1213
0
    pdf_dict_put(ctx, params_obj, PDF_NAME(E), opts->linear_e);
1214
0
    opts->linear_n = pdf_new_int(ctx, INT_MIN);
1215
0
    pdf_dict_put(ctx, params_obj, PDF_NAME(N), opts->linear_n);
1216
0
    opts->linear_t = pdf_new_int(ctx, INT_MIN);
1217
0
    pdf_dict_put(ctx, params_obj, PDF_NAME(T), opts->linear_t);
1218
0
    pdf_dict_put_int(ctx, params_obj, PDF_NAME(P), 0);
1219
1220
    /* Primary hint stream */
1221
0
    hint_obj = pdf_new_dict(ctx, doc, 10);
1222
0
    hint_ref = pdf_add_object(ctx, doc, hint_obj);
1223
0
    hint_num = pdf_to_num(ctx, hint_ref);
1224
1225
0
    opts->hint_object_num = hint_num;
1226
0
    opts->use_list[hint_num] = USE_HINTS;
1227
0
    opts->renumber_map[hint_num] = hint_num;
1228
0
    opts->rev_renumber_map[hint_num] = hint_num;
1229
0
    opts->gen_list[hint_num] = 0;
1230
0
    opts->hints_s = pdf_new_int(ctx, INT_MIN);
1231
0
    pdf_dict_put(ctx, hint_obj, PDF_NAME(S), opts->hints_s);
1232
    /* FIXME: Do we have thumbnails? Do a T entry */
1233
    /* FIXME: Do we have outlines? Do an O entry */
1234
    /* FIXME: Do we have article threads? Do an A entry */
1235
    /* FIXME: Do we have named destinations? Do a E entry */
1236
    /* FIXME: Do we have interactive forms? Do a V entry */
1237
    /* FIXME: Do we have document information? Do an I entry */
1238
    /* FIXME: Do we have logical structure hierarchy? Do a C entry */
1239
    /* FIXME: Do L, Page Label hint table */
1240
0
    pdf_dict_put(ctx, hint_obj, PDF_NAME(Filter), PDF_NAME(FlateDecode));
1241
0
    opts->hints_length = pdf_new_int(ctx, INT_MIN);
1242
0
    pdf_dict_put(ctx, hint_obj, PDF_NAME(Length), opts->hints_length);
1243
0
    xe = pdf_get_xref_entry_no_null(ctx, doc, hint_num);
1244
0
    xe->stm_ofs = 0;
1245
    /* Empty stream, required so that we write the object as
1246
     * a stream during the first pass. Without this, offsets
1247
     * for the xref will be wrong. */
1248
0
    xe->stm_buf = fz_new_buffer(ctx, 1);
1249
0
  }
1250
0
  fz_always(ctx)
1251
0
  {
1252
0
    pdf_drop_obj(ctx, params_obj);
1253
0
    pdf_drop_obj(ctx, params_ref);
1254
0
    pdf_drop_obj(ctx, hint_ref);
1255
0
    pdf_drop_obj(ctx, hint_obj);
1256
0
  }
1257
0
  fz_catch(ctx)
1258
0
  {
1259
0
    fz_rethrow(ctx);
1260
0
  }
1261
0
}
1262
1263
static void
1264
lpr_inherit_res_contents(fz_context *ctx, pdf_mark_list *list, int cycle, pdf_obj *res, pdf_obj *dict, pdf_obj *text)
1265
0
{
1266
0
  pdf_obj *o, *r;
1267
0
  int i, n;
1268
1269
  /* If the parent node doesn't have an entry of this type, give up. */
1270
0
  o = pdf_dict_get(ctx, dict, text);
1271
0
  if (!o)
1272
0
    return;
1273
1274
0
  if (!cycle)
1275
0
    cycle = pdf_mark_list_check(ctx, list, o);
1276
1277
  /* If the resources dict we are building doesn't have an entry of this
1278
   * type yet, then just copy it (ensuring it's not a reference) */
1279
0
  r = pdf_dict_get(ctx, res, text);
1280
0
  if (r == NULL)
1281
0
  {
1282
    /* Only copy the dict if to do so would not cause a cycle! */
1283
0
    if (!cycle)
1284
0
    {
1285
0
      if (pdf_is_dict(ctx, o))
1286
0
        o = pdf_copy_dict(ctx, o);
1287
0
      else if (pdf_is_array(ctx, o))
1288
0
        o = pdf_copy_array(ctx, o);
1289
0
      else
1290
0
        o = NULL;
1291
0
      if (o)
1292
0
        pdf_dict_put_drop(ctx, res, text, o);
1293
0
    }
1294
0
    else if (o)
1295
0
      pdf_dict_put(ctx, res, text, o);
1296
0
    return;
1297
0
  }
1298
1299
  /* Otherwise we need to merge o into r */
1300
0
  if (pdf_is_dict(ctx, o))
1301
0
  {
1302
0
    n = pdf_dict_len(ctx, o);
1303
0
    for (i = 0; i < n; i++)
1304
0
    {
1305
0
      pdf_obj *key = pdf_dict_get_key(ctx, o, i);
1306
0
      pdf_obj *val = pdf_dict_get_val(ctx, o, i);
1307
1308
0
      if (pdf_dict_get(ctx, r, key))
1309
0
        continue;
1310
0
      pdf_dict_put(ctx, r, key, val);
1311
0
    }
1312
0
  }
1313
0
}
1314
1315
static void
1316
lpr_inherit_res(fz_context *ctx, pdf_mark_list *list, pdf_obj *node, int depth, pdf_obj *dict)
1317
0
{
1318
0
  while (1)
1319
0
  {
1320
0
    pdf_obj *o;
1321
0
    int cycle;
1322
1323
0
    node = pdf_dict_get(ctx, node, PDF_NAME(Parent));
1324
0
    depth--;
1325
0
    if (!node || depth < 0)
1326
0
      break;
1327
1328
0
    cycle = pdf_mark_list_push(ctx, list, node);
1329
0
    o = pdf_dict_get(ctx, node, PDF_NAME(Resources));
1330
0
    if (o)
1331
0
    {
1332
0
      int cycle2 = cycle;
1333
0
      if (!cycle)
1334
0
        cycle2 = pdf_mark_list_push(ctx, list, o);
1335
0
      lpr_inherit_res_contents(ctx, list, cycle2, dict, o, PDF_NAME(ExtGState));
1336
0
      lpr_inherit_res_contents(ctx, list, cycle2, dict, o, PDF_NAME(ColorSpace));
1337
0
      lpr_inherit_res_contents(ctx, list, cycle2, dict, o, PDF_NAME(Pattern));
1338
0
      lpr_inherit_res_contents(ctx, list, cycle2, dict, o, PDF_NAME(Shading));
1339
0
      lpr_inherit_res_contents(ctx, list, cycle2, dict, o, PDF_NAME(XObject));
1340
0
      lpr_inherit_res_contents(ctx, list, cycle2, dict, o, PDF_NAME(Font));
1341
0
      lpr_inherit_res_contents(ctx, list, cycle2, dict, o, PDF_NAME(ProcSet));
1342
0
      lpr_inherit_res_contents(ctx, list, cycle2, dict, o, PDF_NAME(Properties));
1343
0
      if (!cycle2)
1344
0
        pdf_mark_list_pop(ctx, list);
1345
0
    }
1346
0
    if (!cycle)
1347
0
      pdf_mark_list_pop(ctx, list);
1348
0
  }
1349
0
}
1350
1351
static pdf_obj *
1352
lpr_inherit(fz_context *ctx, pdf_mark_list *list, pdf_obj *node, char *text, int depth)
1353
0
{
1354
0
  do
1355
0
  {
1356
0
    pdf_obj *o = pdf_dict_gets(ctx, node, text);
1357
1358
0
    if (o)
1359
0
    {
1360
      /* Watch for cycling here. If we do hit a cycle, then take
1361
       * care NOT to resolve the indirection to avoid creating direct
1362
       * object cycles. */
1363
0
      if (pdf_mark_list_push(ctx, list, o))
1364
0
        return o;
1365
1366
0
      pdf_mark_list_pop(ctx, list);
1367
0
      return pdf_resolve_indirect(ctx, o);
1368
0
    }
1369
0
    node = pdf_dict_get(ctx, node, PDF_NAME(Parent));
1370
0
    depth--;
1371
0
  }
1372
0
  while (depth >= 0 && node);
1373
1374
0
  return NULL;
1375
0
}
1376
1377
static int
1378
lpr(fz_context *ctx, pdf_document *doc, pdf_mark_list *list, pdf_obj *node, int depth, int page)
1379
0
{
1380
0
  pdf_obj *kids;
1381
0
  pdf_obj *o = NULL;
1382
0
  int i, n;
1383
1384
0
  if (pdf_mark_list_push(ctx, list, node))
1385
0
    return page;
1386
1387
0
  fz_var(o);
1388
1389
0
  fz_try(ctx)
1390
0
  {
1391
0
    if (pdf_name_eq(ctx, PDF_NAME(Page), pdf_dict_get(ctx, node, PDF_NAME(Type))))
1392
0
    {
1393
0
      pdf_obj *r; /* r is deliberately not cleaned up */
1394
1395
      /* Copy resources down to the child */
1396
0
      o = pdf_keep_obj(ctx, pdf_dict_get(ctx, node, PDF_NAME(Resources)));
1397
0
      if (!o)
1398
0
      {
1399
0
        o = pdf_keep_obj(ctx, pdf_new_dict(ctx, doc, 2));
1400
0
        pdf_dict_put(ctx, node, PDF_NAME(Resources), o);
1401
0
      }
1402
0
      lpr_inherit_res(ctx, list, node, depth, o);
1403
0
      r = lpr_inherit(ctx, list, node, "MediaBox", depth);
1404
0
      if (r)
1405
0
        pdf_dict_put(ctx, node, PDF_NAME(MediaBox), r);
1406
0
      r = lpr_inherit(ctx, list, node, "CropBox", depth);
1407
0
      if (r)
1408
0
        pdf_dict_put(ctx, node, PDF_NAME(CropBox), r);
1409
0
      r = lpr_inherit(ctx, list, node, "BleedBox", depth);
1410
0
      if (r)
1411
0
        pdf_dict_put(ctx, node, PDF_NAME(BleedBox), r);
1412
0
      r = lpr_inherit(ctx, list, node, "TrimBox", depth);
1413
0
      if (r)
1414
0
        pdf_dict_put(ctx, node, PDF_NAME(TrimBox), r);
1415
0
      r = lpr_inherit(ctx, list, node, "ArtBox", depth);
1416
0
      if (r)
1417
0
        pdf_dict_put(ctx, node, PDF_NAME(ArtBox), r);
1418
0
      r = lpr_inherit(ctx, list, node, "Rotate", depth);
1419
0
      if (r)
1420
0
        pdf_dict_put(ctx, node, PDF_NAME(Rotate), r);
1421
0
      page++;
1422
0
    }
1423
0
    else
1424
0
    {
1425
0
      kids = pdf_dict_get(ctx, node, PDF_NAME(Kids));
1426
0
      n = pdf_array_len(ctx, kids);
1427
0
      for(i = 0; i < n; i++)
1428
0
      {
1429
0
        page = lpr(ctx, doc, list, pdf_array_get(ctx, kids, i), depth+1, page);
1430
0
      }
1431
0
      pdf_dict_del(ctx, node, PDF_NAME(Resources));
1432
0
      pdf_dict_del(ctx, node, PDF_NAME(MediaBox));
1433
0
      pdf_dict_del(ctx, node, PDF_NAME(CropBox));
1434
0
      pdf_dict_del(ctx, node, PDF_NAME(BleedBox));
1435
0
      pdf_dict_del(ctx, node, PDF_NAME(TrimBox));
1436
0
      pdf_dict_del(ctx, node, PDF_NAME(ArtBox));
1437
0
      pdf_dict_del(ctx, node, PDF_NAME(Rotate));
1438
0
    }
1439
0
  }
1440
0
  fz_always(ctx)
1441
0
  {
1442
0
    pdf_mark_list_pop(ctx, list);
1443
0
    pdf_drop_obj(ctx, o);
1444
0
  }
1445
0
  fz_catch(ctx)
1446
0
    fz_rethrow(ctx);
1447
1448
0
  return page;
1449
0
}
1450
1451
static void
1452
pdf_localise_page_resources(fz_context *ctx, pdf_document *doc, pdf_mark_list *list)
1453
0
{
1454
0
  if (doc->resources_localised)
1455
0
    return;
1456
1457
0
  lpr(ctx, doc, list, pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root), PDF_NAME(Pages), NULL), 0, 0);
1458
1459
0
  doc->resources_localised = 1;
1460
0
}
1461
1462
static void
1463
linearize(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
1464
0
{
1465
0
  int i;
1466
0
  int n = pdf_xref_len(ctx, doc) + 2;
1467
0
  int *reorder;
1468
0
  int *rev_renumber_map;
1469
0
  pdf_mark_list list;
1470
1471
0
  pdf_mark_list_init(ctx, &list);
1472
0
  opts->page_object_lists = page_objects_list_create(ctx);
1473
1474
  /* Ensure that every page has local references of its resources */
1475
0
  fz_try(ctx)
1476
0
  {
1477
    /* FIXME: We could 'thin' the resources according to what is actually
1478
     * required for each page, but this would require us to run the page
1479
     * content streams. */
1480
0
    pdf_localise_page_resources(ctx, doc, &list);
1481
1482
    /* Walk the objects for each page, marking which ones are used, where */
1483
0
    memset(opts->use_list, 0, n * sizeof(int));
1484
0
    mark_trailer(ctx, doc, &list, opts, pdf_trailer(ctx, doc));
1485
0
  }
1486
0
  fz_always(ctx)
1487
0
    pdf_mark_list_free(ctx, &list);
1488
0
  fz_catch(ctx)
1489
0
    fz_rethrow(ctx);
1490
1491
  /* Add new objects required for linearization */
1492
0
  add_linearization_objs(ctx, doc, opts);
1493
1494
#ifdef DEBUG_WRITING
1495
  fprintf(stderr, "Usage calculated:\n");
1496
  for (i=0; i < pdf_xref_len(ctx, doc); i++)
1497
  {
1498
    fprintf(stderr, "%d: use=%d\n", i, opts->use_list[i]);
1499
  }
1500
#endif
1501
1502
  /* Allocate/init the structures used for renumbering the objects */
1503
0
  reorder = fz_calloc(ctx, n, sizeof(int));
1504
0
  rev_renumber_map = fz_calloc(ctx, n, sizeof(int));
1505
0
  for (i = 0; i < n; i++)
1506
0
  {
1507
0
    reorder[i] = i;
1508
0
  }
1509
1510
  /* Heap sort the reordering */
1511
0
  heap_sort(reorder+1, n-1, opts->use_list, &order_ge);
1512
1513
#ifdef DEBUG_WRITING
1514
  fprintf(stderr, "Reordered:\n");
1515
  for (i=1; i < pdf_xref_len(ctx, doc); i++)
1516
  {
1517
    fprintf(stderr, "%d: use=%d\n", i, opts->use_list[reorder[i]]);
1518
  }
1519
#endif
1520
1521
  /* Find the split point */
1522
0
  for (i = 1; (opts->use_list[reorder[i]] & USE_PARAMS) == 0; i++) {}
1523
0
  opts->start = i;
1524
1525
  /* Roll the reordering into the renumber_map */
1526
0
  for (i = 0; i < n; i++)
1527
0
  {
1528
0
    opts->renumber_map[reorder[i]] = i;
1529
0
    rev_renumber_map[i] = opts->rev_renumber_map[reorder[i]];
1530
0
  }
1531
0
  fz_free(ctx, opts->rev_renumber_map);
1532
0
  opts->rev_renumber_map = rev_renumber_map;
1533
0
  fz_free(ctx, reorder);
1534
1535
  /* Apply the renumber_map */
1536
0
  page_objects_list_renumber(opts);
1537
0
  renumberobjs(ctx, doc, opts);
1538
0
  renumber_pages(ctx, doc, opts);
1539
1540
0
  page_objects_list_sort_and_dedupe(ctx, opts->page_object_lists);
1541
0
}
1542
1543
static void
1544
update_linearization_params(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
1545
0
{
1546
0
  int64_t offset;
1547
0
  pdf_set_int(ctx, opts->linear_l, opts->file_len);
1548
  /* Primary hint stream offset (of object, not stream!) */
1549
0
  pdf_set_int(ctx, opts->linear_h0, opts->ofs_list[pdf_xref_len(ctx, doc)-1]);
1550
  /* Primary hint stream length (of object, not stream!) */
1551
0
  offset = (opts->start == 1 ? opts->main_xref_offset : opts->ofs_list[1] + opts->hintstream_len);
1552
0
  pdf_set_int(ctx, opts->linear_h1, offset - opts->ofs_list[pdf_xref_len(ctx, doc)-1]);
1553
  /* Object number of first pages page object (the first object of page 0) */
1554
0
  pdf_set_int(ctx, opts->linear_o, opts->page_object_lists->page[0]->object[0]);
1555
  /* Offset of end of first page (first page is followed by primary
1556
   * hint stream (object n-1) then remaining pages (object 1...). The
1557
   * primary hint stream counts as part of the first pages data, I think.
1558
   */
1559
0
  offset = (opts->start == 1 ? opts->main_xref_offset : opts->ofs_list[1] + opts->hintstream_len);
1560
0
  pdf_set_int(ctx, opts->linear_e, offset);
1561
  /* Number of pages in document */
1562
0
  pdf_set_int(ctx, opts->linear_n, opts->page_count);
1563
  /* Offset of first entry in main xref table */
1564
0
  pdf_set_int(ctx, opts->linear_t, opts->first_xref_entry_offset + opts->hintstream_len);
1565
  /* Offset of shared objects hint table in the primary hint stream */
1566
0
  pdf_set_int(ctx, opts->hints_s, opts->hints_shared_offset);
1567
  /* Primary hint stream length */
1568
0
  pdf_set_int(ctx, opts->hints_length, opts->hintstream_len);
1569
0
}
1570
1571
/*
1572
 * Make sure we have loaded objects from object streams.
1573
 */
1574
1575
static void preloadobjstms(fz_context *ctx, pdf_document *doc)
1576
0
{
1577
0
  pdf_obj *obj;
1578
0
  int num;
1579
0
  pdf_xref_entry *x = NULL;
1580
0
  int load = 1;
1581
1582
  /* If we have attempted a repair, then everything will have been
1583
   * loaded already. */
1584
0
  if (doc->repair_attempted)
1585
0
  {
1586
    /* Bug 707112: But we do need to mark all our 'o' objects as being something else. */
1587
0
    load = 0;
1588
0
  }
1589
1590
0
  fz_var(num);
1591
0
  fz_var(x);
1592
1593
  /* xref_len may change due to repair, so check it every iteration */
1594
0
  for (num = 0; num < pdf_xref_len(ctx, doc); num++)
1595
0
  {
1596
0
    fz_try(ctx)
1597
0
    {
1598
0
      for (; num < pdf_xref_len(ctx, doc); num++)
1599
0
      {
1600
0
        x = pdf_get_xref_entry_no_null(ctx, doc, num);
1601
0
        if (x->type == 'o')
1602
0
        {
1603
0
          if (load)
1604
0
          {
1605
0
            obj = pdf_load_object(ctx, doc, num);
1606
0
            pdf_drop_obj(ctx, obj);
1607
0
          }
1608
          /* The object is no longer an objstm one. It's a regular object
1609
           * held in memory. Previously we used gen to hold the index of
1610
           * the obj in the objstm, so reset this to 0. */
1611
0
          x->type = 'n';
1612
0
          x->gen = 0;
1613
0
        }
1614
0
        x = NULL;
1615
0
      }
1616
0
    }
1617
0
    fz_catch(ctx)
1618
0
    {
1619
      /* We need to clear the type even in the event of an error, lest we
1620
       * hit an assert later. Bug 707110. */
1621
0
      if (x && x->type == 'o')
1622
0
      {
1623
0
        x->type = 'f';
1624
0
        x->gen = 0;
1625
0
      }
1626
      /* Ignore the error, so we can carry on trying to load. */
1627
0
      fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
1628
0
      fz_report_error(ctx);
1629
0
    }
1630
0
  }
1631
0
}
1632
1633
/*
1634
 * Save streams and objects to the output
1635
 */
1636
1637
static int is_bitmap_stream(fz_context *ctx, pdf_obj *obj, size_t len, int *w, int *h)
1638
0
{
1639
0
  pdf_obj *bpc;
1640
0
  pdf_obj *cs;
1641
0
  int stride;
1642
0
  if (pdf_dict_get(ctx, obj, PDF_NAME(Subtype)) != PDF_NAME(Image))
1643
0
    return 0;
1644
0
  *w = pdf_dict_get_int(ctx, obj, PDF_NAME(Width));
1645
0
  *h = pdf_dict_get_int(ctx, obj, PDF_NAME(Height));
1646
0
  stride = (*w + 7) >> 3;
1647
0
  if ((size_t)stride * (*h) != len)
1648
0
    return 0;
1649
0
  if (pdf_dict_get_bool(ctx, obj, PDF_NAME(ImageMask)))
1650
0
  {
1651
0
    return 1;
1652
0
  }
1653
0
  else
1654
0
  {
1655
0
    bpc = pdf_dict_get(ctx, obj, PDF_NAME(BitsPerComponent));
1656
0
    if (!pdf_is_int(ctx, bpc))
1657
0
      return 0;
1658
0
    if (pdf_to_int(ctx, bpc) != 1)
1659
0
      return 0;
1660
0
    cs = pdf_dict_get(ctx, obj, PDF_NAME(ColorSpace));
1661
0
    if (!pdf_name_eq(ctx, cs, PDF_NAME(DeviceGray)))
1662
0
      return 0;
1663
0
    return 1;
1664
0
  }
1665
0
}
1666
1667
static inline int isbinary(int c)
1668
0
{
1669
0
  if (c == '\n' || c == '\r' || c == '\t')
1670
0
    return 0;
1671
0
  return c < 32 || c > 127;
1672
0
}
1673
1674
static int isbinarystream(fz_context *ctx, const unsigned char *data, size_t len)
1675
0
{
1676
0
  size_t i;
1677
0
  for (i = 0; i < len; i++)
1678
0
    if (isbinary(data[i]))
1679
0
      return 1;
1680
0
  return 0;
1681
0
}
1682
1683
static fz_buffer *hexbuf(fz_context *ctx, const unsigned char *p, size_t n)
1684
0
{
1685
0
  static const char hex[17] = "0123456789abcdef";
1686
0
  int x = 0;
1687
0
  size_t len = n * 2 + (n / 32) + 1;
1688
0
  unsigned char *data = Memento_label(fz_malloc(ctx, len), "hexbuf");
1689
0
  fz_buffer *buf = fz_new_buffer_from_data(ctx, data, len);
1690
1691
0
  while (n--)
1692
0
  {
1693
0
    *data++ = hex[*p >> 4];
1694
0
    *data++ = hex[*p & 15];
1695
0
    if (++x == 32)
1696
0
    {
1697
0
      *data++ = '\n';
1698
0
      x = 0;
1699
0
    }
1700
0
    p++;
1701
0
  }
1702
1703
0
  *data++ = '>';
1704
1705
0
  return buf;
1706
0
}
1707
1708
static void addhexfilter(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
1709
0
{
1710
0
  pdf_obj *f, *dp, *newf, *newdp;
1711
1712
0
  newf = newdp = NULL;
1713
0
  f = pdf_dict_get(ctx, dict, PDF_NAME(Filter));
1714
0
  dp = pdf_dict_get(ctx, dict, PDF_NAME(DecodeParms));
1715
1716
0
  fz_var(newf);
1717
0
  fz_var(newdp);
1718
1719
0
  fz_try(ctx)
1720
0
  {
1721
0
    if (pdf_is_name(ctx, f))
1722
0
    {
1723
0
      newf = pdf_new_array(ctx, doc, 2);
1724
0
      pdf_array_push(ctx, newf, PDF_NAME(ASCIIHexDecode));
1725
0
      pdf_array_push(ctx, newf, f);
1726
0
      f = newf;
1727
0
      if (pdf_is_dict(ctx, dp))
1728
0
      {
1729
0
        newdp = pdf_new_array(ctx, doc, 2);
1730
0
        pdf_array_push(ctx, newdp, PDF_NULL);
1731
0
        pdf_array_push(ctx, newdp, dp);
1732
0
        dp = newdp;
1733
0
      }
1734
0
    }
1735
0
    else if (pdf_is_array(ctx, f))
1736
0
    {
1737
0
      pdf_array_insert(ctx, f, PDF_NAME(ASCIIHexDecode), 0);
1738
0
      if (pdf_is_array(ctx, dp))
1739
0
        pdf_array_insert(ctx, dp, PDF_NULL, 0);
1740
0
    }
1741
0
    else
1742
0
      f = PDF_NAME(ASCIIHexDecode);
1743
1744
0
    pdf_dict_put(ctx, dict, PDF_NAME(Filter), f);
1745
0
    if (dp)
1746
0
      pdf_dict_put(ctx, dict, PDF_NAME(DecodeParms), dp);
1747
0
  }
1748
0
  fz_always(ctx)
1749
0
  {
1750
0
    pdf_drop_obj(ctx, newf);
1751
0
    pdf_drop_obj(ctx, newdp);
1752
0
  }
1753
0
  fz_catch(ctx)
1754
0
    fz_rethrow(ctx);
1755
0
}
1756
1757
static fz_buffer *deflatebuf(fz_context *ctx, const unsigned char *p, size_t n, int effort)
1758
0
{
1759
0
  fz_buffer *buf;
1760
0
  uLongf csize;
1761
0
  int t;
1762
0
  uLong longN = (uLong)n;
1763
0
  unsigned char *data;
1764
0
  size_t cap;
1765
0
  int mode;
1766
1767
0
  if (n != (size_t)longN)
1768
0
    fz_throw(ctx, FZ_ERROR_LIMIT, "Buffer too large to deflate");
1769
1770
0
  cap = compressBound(longN);
1771
0
  data = Memento_label(fz_malloc(ctx, cap), "pdf_write_deflate");
1772
0
  buf = fz_new_buffer_from_data(ctx, data, cap);
1773
0
  csize = (uLongf)cap;
1774
0
  if (effort == 0)
1775
0
    mode = Z_DEFAULT_COMPRESSION;
1776
0
  else
1777
0
    mode = effort * Z_BEST_COMPRESSION / 100;
1778
0
  t = compress2(data, &csize, p, longN, mode);
1779
0
  if (t != Z_OK)
1780
0
  {
1781
0
    fz_drop_buffer(ctx, buf);
1782
0
    fz_throw(ctx, FZ_ERROR_LIBRARY, "cannot deflate buffer");
1783
0
  }
1784
0
  fz_try(ctx)
1785
0
    fz_resize_buffer(ctx, buf, csize);
1786
0
  fz_catch(ctx)
1787
0
  {
1788
0
    fz_drop_buffer(ctx, buf);
1789
0
    fz_rethrow(ctx);
1790
0
  }
1791
0
  return buf;
1792
0
}
1793
1794
static int striphexfilter(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
1795
0
{
1796
0
  pdf_obj *f, *dp;
1797
0
  int is_hex = 0;
1798
1799
0
  f = pdf_dict_get(ctx, dict, PDF_NAME(Filter));
1800
0
  dp = pdf_dict_get(ctx, dict, PDF_NAME(DecodeParms));
1801
1802
0
  if (pdf_is_array(ctx, f))
1803
0
  {
1804
    /* Remove ASCIIHexDecode from head of filter list */
1805
0
    if (pdf_array_get(ctx, f, 0) == PDF_NAME(ASCIIHexDecode))
1806
0
    {
1807
0
      is_hex = 1;
1808
0
      pdf_array_delete(ctx, f, 0);
1809
0
      if (pdf_is_array(ctx, dp))
1810
0
        pdf_array_delete(ctx, dp, 0);
1811
0
    }
1812
    /* Unpack array if only one filter remains */
1813
0
    if (pdf_array_len(ctx, f) == 1)
1814
0
    {
1815
0
      f = pdf_array_get(ctx, f, 0);
1816
0
      pdf_dict_put(ctx, dict, PDF_NAME(Filter), f);
1817
0
      if (dp)
1818
0
      {
1819
0
        dp = pdf_array_get(ctx, dp, 0);
1820
0
        pdf_dict_put(ctx, dict, PDF_NAME(DecodeParms), dp);
1821
0
      }
1822
0
    }
1823
    /* Remove array if no filters remain */
1824
0
    else if (pdf_array_len(ctx, f) == 0)
1825
0
    {
1826
0
      pdf_dict_del(ctx, dict, PDF_NAME(Filter));
1827
0
      pdf_dict_del(ctx, dict, PDF_NAME(DecodeParms));
1828
0
    }
1829
0
  }
1830
0
  else if (f == PDF_NAME(ASCIIHexDecode))
1831
0
  {
1832
0
    is_hex = 1;
1833
0
    pdf_dict_del(ctx, dict, PDF_NAME(Filter));
1834
0
    pdf_dict_del(ctx, dict, PDF_NAME(DecodeParms));
1835
0
  }
1836
1837
0
  return is_hex;
1838
0
}
1839
1840
static fz_buffer *unhexbuf(fz_context *ctx, const unsigned char *p, size_t n)
1841
0
{
1842
0
  fz_stream *mstm = NULL;
1843
0
  fz_stream *xstm = NULL;
1844
0
  fz_buffer *out = NULL;
1845
0
  fz_var(mstm);
1846
0
  fz_var(xstm);
1847
0
  fz_try(ctx)
1848
0
  {
1849
0
    mstm = fz_open_memory(ctx, p, n);
1850
0
    xstm = fz_open_ahxd(ctx, mstm);
1851
0
    out = fz_read_all(ctx, xstm, n/2);
1852
0
  }
1853
0
  fz_always(ctx)
1854
0
  {
1855
0
    fz_drop_stream(ctx, xstm);
1856
0
    fz_drop_stream(ctx, mstm);
1857
0
  }
1858
0
  fz_catch(ctx)
1859
0
    fz_rethrow(ctx);
1860
0
  return out;
1861
0
}
1862
1863
static void write_data(fz_context *ctx, void *arg, const unsigned char *data, size_t len)
1864
0
{
1865
0
  fz_write_data(ctx, (fz_output *)arg, data, len);
1866
0
}
1867
1868
static void copystream(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, pdf_obj *obj_orig, int num, int gen, int do_deflate, int unenc)
1869
0
{
1870
0
  fz_buffer *tmp_unhex = NULL, *tmp_comp = NULL, *tmp_hex = NULL, *buf = NULL;
1871
0
  pdf_obj *obj = NULL;
1872
0
  pdf_obj *dp;
1873
0
  size_t len;
1874
0
  unsigned char *data;
1875
0
  int w, h;
1876
1877
0
  fz_var(buf);
1878
0
  fz_var(tmp_comp);
1879
0
  fz_var(tmp_hex);
1880
0
  fz_var(obj);
1881
1882
0
  fz_try(ctx)
1883
0
  {
1884
0
    buf = pdf_load_raw_stream_number(ctx, doc, num);
1885
0
    obj = pdf_copy_dict(ctx, obj_orig);
1886
1887
0
    len = fz_buffer_storage(ctx, buf, &data);
1888
1889
0
    if (do_deflate && striphexfilter(ctx, doc, obj))
1890
0
    {
1891
0
      tmp_unhex = unhexbuf(ctx, data, len);
1892
0
      len = fz_buffer_storage(ctx, tmp_unhex, &data);
1893
0
    }
1894
1895
0
    if (do_deflate && !pdf_dict_get(ctx, obj, PDF_NAME(Filter)))
1896
0
    {
1897
0
      if (is_bitmap_stream(ctx, obj, len, &w, &h))
1898
0
      {
1899
0
        tmp_comp = fz_compress_ccitt_fax_g4(ctx, data, w, h, (w+7)>>3);
1900
0
        pdf_dict_put(ctx, obj, PDF_NAME(Filter), PDF_NAME(CCITTFaxDecode));
1901
0
        dp = pdf_dict_put_dict(ctx, obj, PDF_NAME(DecodeParms), 1);
1902
0
        pdf_dict_put_int(ctx, dp, PDF_NAME(K), -1);
1903
0
        pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), w);
1904
0
      }
1905
0
      else
1906
0
      {
1907
0
        tmp_comp = deflatebuf(ctx, data, len, opts->compression_effort);
1908
0
        pdf_dict_put(ctx, obj, PDF_NAME(Filter), PDF_NAME(FlateDecode));
1909
0
      }
1910
0
      len = fz_buffer_storage(ctx, tmp_comp, &data);
1911
0
    }
1912
1913
0
    if (opts->do_ascii && isbinarystream(ctx, data, len))
1914
0
    {
1915
0
      tmp_hex = hexbuf(ctx, data, len);
1916
0
      len = fz_buffer_storage(ctx, tmp_hex, &data);
1917
0
      addhexfilter(ctx, doc, obj);
1918
0
    }
1919
1920
0
    fz_write_printf(ctx, opts->out, "%d %d obj\n", num, gen);
1921
1922
0
    if (unenc)
1923
0
    {
1924
0
      pdf_dict_put_int(ctx, obj, PDF_NAME(Length), len);
1925
0
      pdf_print_obj(ctx, opts->out, obj, opts->do_tight, opts->do_ascii);
1926
0
      fz_write_string(ctx, opts->out, "\nstream\n");
1927
0
      fz_write_data(ctx, opts->out, data, len);
1928
0
    }
1929
0
    else
1930
0
    {
1931
0
      pdf_dict_put_int(ctx, obj, PDF_NAME(Length), pdf_encrypted_len(ctx, opts->crypt, num, gen, len));
1932
0
      pdf_print_encrypted_obj(ctx, opts->out, obj, opts->do_tight, opts->do_ascii, opts->crypt, num, gen, NULL);
1933
0
      fz_write_string(ctx, opts->out, "\nstream\n");
1934
0
      pdf_encrypt_data(ctx, opts->crypt, num, gen, write_data, opts->out, data, len);
1935
0
    }
1936
1937
0
    fz_write_string(ctx, opts->out, "\nendstream\nendobj\n\n");
1938
0
  }
1939
0
  fz_always(ctx)
1940
0
  {
1941
0
    fz_drop_buffer(ctx, tmp_unhex);
1942
0
    fz_drop_buffer(ctx, tmp_hex);
1943
0
    fz_drop_buffer(ctx, tmp_comp);
1944
0
    fz_drop_buffer(ctx, buf);
1945
0
    pdf_drop_obj(ctx, obj);
1946
0
  }
1947
0
  fz_catch(ctx)
1948
0
  {
1949
0
    fz_rethrow(ctx);
1950
0
  }
1951
0
}
1952
1953
static void expandstream(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, pdf_obj *obj_orig, int num, int gen, int do_deflate, int unenc)
1954
0
{
1955
0
  fz_buffer *buf = NULL, *tmp_comp = NULL, *tmp_hex = NULL;
1956
0
  pdf_obj *obj = NULL;
1957
0
  pdf_obj *dp;
1958
0
  size_t len;
1959
0
  unsigned char *data;
1960
0
  int w, h;
1961
1962
0
  fz_var(buf);
1963
0
  fz_var(tmp_comp);
1964
0
  fz_var(tmp_hex);
1965
0
  fz_var(obj);
1966
1967
0
  fz_try(ctx)
1968
0
  {
1969
0
    buf = pdf_load_stream_number(ctx, doc, num);
1970
0
    obj = pdf_copy_dict(ctx, obj_orig);
1971
0
    pdf_dict_del(ctx, obj, PDF_NAME(Filter));
1972
0
    pdf_dict_del(ctx, obj, PDF_NAME(DecodeParms));
1973
1974
0
    len = fz_buffer_storage(ctx, buf, &data);
1975
0
    if (do_deflate)
1976
0
    {
1977
0
      if (is_bitmap_stream(ctx, obj, len, &w, &h))
1978
0
      {
1979
0
        tmp_comp = fz_compress_ccitt_fax_g4(ctx, data, w, h, (w+7)>>3);
1980
0
        pdf_dict_put(ctx, obj, PDF_NAME(Filter), PDF_NAME(CCITTFaxDecode));
1981
0
        dp = pdf_dict_put_dict(ctx, obj, PDF_NAME(DecodeParms), 1);
1982
0
        pdf_dict_put_int(ctx, dp, PDF_NAME(K), -1);
1983
0
        pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), w);
1984
0
      }
1985
0
      else
1986
0
      {
1987
0
        tmp_comp = deflatebuf(ctx, data, len, opts->compression_effort);
1988
0
        pdf_dict_put(ctx, obj, PDF_NAME(Filter), PDF_NAME(FlateDecode));
1989
0
      }
1990
0
      len = fz_buffer_storage(ctx, tmp_comp, &data);
1991
0
    }
1992
1993
0
    if (opts->do_ascii && isbinarystream(ctx, data, len))
1994
0
    {
1995
0
      tmp_hex = hexbuf(ctx, data, len);
1996
0
      len = fz_buffer_storage(ctx, tmp_hex, &data);
1997
0
      addhexfilter(ctx, doc, obj);
1998
0
    }
1999
2000
0
    fz_write_printf(ctx, opts->out, "%d %d obj\n", num, gen);
2001
2002
0
    if (unenc)
2003
0
    {
2004
0
      pdf_dict_put_int(ctx, obj, PDF_NAME(Length), len);
2005
0
      pdf_print_obj(ctx, opts->out, obj, opts->do_tight, opts->do_ascii);
2006
0
      fz_write_string(ctx, opts->out, "\nstream\n");
2007
0
      fz_write_data(ctx, opts->out, data, len);
2008
0
    }
2009
0
    else
2010
0
    {
2011
0
      pdf_dict_put_int(ctx, obj, PDF_NAME(Length), pdf_encrypted_len(ctx, opts->crypt, num, gen, (int)len));
2012
0
      pdf_print_encrypted_obj(ctx, opts->out, obj, opts->do_tight, opts->do_ascii, opts->crypt, num, gen, NULL);
2013
0
      fz_write_string(ctx, opts->out, "\nstream\n");
2014
0
      pdf_encrypt_data(ctx, opts->crypt, num, gen, write_data, opts->out, data, len);
2015
0
    }
2016
2017
0
    fz_write_string(ctx, opts->out, "\nendstream\nendobj\n\n");
2018
0
  }
2019
0
  fz_always(ctx)
2020
0
  {
2021
0
    fz_drop_buffer(ctx, tmp_hex);
2022
0
    fz_drop_buffer(ctx, tmp_comp);
2023
0
    fz_drop_buffer(ctx, buf);
2024
0
    pdf_drop_obj(ctx, obj);
2025
0
  }
2026
0
  fz_catch(ctx)
2027
0
  {
2028
0
    fz_rethrow(ctx);
2029
0
  }
2030
0
}
2031
2032
static int is_image_filter(pdf_obj *s)
2033
0
{
2034
0
  return
2035
0
    s == PDF_NAME(CCITTFaxDecode) || s == PDF_NAME(CCF) ||
2036
0
    s == PDF_NAME(DCTDecode) || s == PDF_NAME(DCT) ||
2037
0
    s == PDF_NAME(RunLengthDecode) || s == PDF_NAME(RL) ||
2038
0
    s == PDF_NAME(JBIG2Decode) ||
2039
0
    s == PDF_NAME(JPXDecode);
2040
0
}
2041
2042
static int filter_implies_image(fz_context *ctx, pdf_obj *o)
2043
0
{
2044
0
  if (pdf_is_name(ctx, o))
2045
0
    return is_image_filter(o);
2046
0
  if (pdf_is_array(ctx, o))
2047
0
  {
2048
0
    int i, len;
2049
0
    len = pdf_array_len(ctx, o);
2050
0
    for (i = 0; i < len; i++)
2051
0
      if (is_image_filter(pdf_array_get(ctx, o, i)))
2052
0
        return 1;
2053
0
  }
2054
0
  return 0;
2055
0
}
2056
2057
static int is_jpx_filter(fz_context *ctx, pdf_obj *o)
2058
0
{
2059
0
  if (o == PDF_NAME(JPXDecode))
2060
0
    return 1;
2061
0
  if (pdf_is_array(ctx, o))
2062
0
  {
2063
0
    int i, len;
2064
0
    len = pdf_array_len(ctx, o);
2065
0
    for (i = 0; i < len; i++)
2066
0
      if (pdf_array_get(ctx, o, i) == PDF_NAME(JPXDecode))
2067
0
        return 1;
2068
0
  }
2069
0
  return 0;
2070
0
}
2071
2072
static int is_image_stream(fz_context *ctx, pdf_obj *obj)
2073
0
{
2074
0
  pdf_obj *o;
2075
0
  if ((o = pdf_dict_get(ctx, obj, PDF_NAME(Type)), pdf_name_eq(ctx, o, PDF_NAME(XObject))))
2076
0
    if ((o = pdf_dict_get(ctx, obj, PDF_NAME(Subtype)), pdf_name_eq(ctx, o, PDF_NAME(Image))))
2077
0
      return 1;
2078
0
  if (o = pdf_dict_get(ctx, obj, PDF_NAME(Filter)), filter_implies_image(ctx, o))
2079
0
    return 1;
2080
0
  if (pdf_dict_get(ctx, obj, PDF_NAME(Width)) != NULL && pdf_dict_get(ctx, obj, PDF_NAME(Height)) != NULL)
2081
0
    return 1;
2082
0
  return 0;
2083
0
}
2084
2085
static int is_font_stream(fz_context *ctx, pdf_obj *obj)
2086
0
{
2087
0
  pdf_obj *o;
2088
0
  if (o = pdf_dict_get(ctx, obj, PDF_NAME(Type)), pdf_name_eq(ctx, o, PDF_NAME(Font)))
2089
0
    return 1;
2090
0
  if (o = pdf_dict_get(ctx, obj, PDF_NAME(Type)), pdf_name_eq(ctx, o, PDF_NAME(FontDescriptor)))
2091
0
    return 1;
2092
0
  if (pdf_dict_get(ctx, obj, PDF_NAME(Length1)) != NULL)
2093
0
    return 1;
2094
0
  if (pdf_dict_get(ctx, obj, PDF_NAME(Length2)) != NULL)
2095
0
    return 1;
2096
0
  if (pdf_dict_get(ctx, obj, PDF_NAME(Length3)) != NULL)
2097
0
    return 1;
2098
0
  if (o = pdf_dict_get(ctx, obj, PDF_NAME(Subtype)), pdf_name_eq(ctx, o, PDF_NAME(Type1C)))
2099
0
    return 1;
2100
0
  if (o = pdf_dict_get(ctx, obj, PDF_NAME(Subtype)), pdf_name_eq(ctx, o, PDF_NAME(CIDFontType0C)))
2101
0
    return 1;
2102
0
  return 0;
2103
0
}
2104
2105
static int is_jpx_stream(fz_context *ctx, pdf_obj *obj)
2106
0
{
2107
0
  pdf_obj *o;
2108
0
  if (o = pdf_dict_get(ctx, obj, PDF_NAME(Filter)), is_jpx_filter(ctx, o))
2109
0
    return 1;
2110
0
  return 0;
2111
0
}
2112
2113
2114
static int is_xml_metadata(fz_context *ctx, pdf_obj *obj)
2115
0
{
2116
0
  if (pdf_name_eq(ctx, pdf_dict_get(ctx, obj, PDF_NAME(Type)), PDF_NAME(Metadata)))
2117
0
    if (pdf_name_eq(ctx, pdf_dict_get(ctx, obj, PDF_NAME(Subtype)), PDF_NAME(XML)))
2118
0
      return 1;
2119
0
  return 0;
2120
0
}
2121
2122
static void writeobject(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, int num, int gen, int skip_xrefs, int unenc)
2123
0
{
2124
0
  pdf_obj *obj = NULL;
2125
0
  fz_buffer *buf = NULL;
2126
0
  int do_deflate = 0;
2127
0
  int do_expand = 0;
2128
0
  int skip = 0;
2129
2130
0
  fz_var(obj);
2131
0
  fz_var(buf);
2132
2133
0
  if (opts->do_encrypt == PDF_ENCRYPT_NONE)
2134
0
    unenc = 1;
2135
2136
0
  fz_try(ctx)
2137
0
  {
2138
0
    obj = pdf_load_object(ctx, doc, num);
2139
2140
    /* skip ObjStm and XRef objects */
2141
0
    if (pdf_is_dict(ctx, obj))
2142
0
    {
2143
0
      pdf_obj *type = pdf_dict_get(ctx, obj, PDF_NAME(Type));
2144
0
      if (type == PDF_NAME(ObjStm) && !opts->do_use_objstms)
2145
0
      {
2146
0
        if (opts->use_list)
2147
0
          opts->use_list[num] = 0;
2148
0
        skip = 1;
2149
0
      }
2150
0
      if (skip_xrefs && type == PDF_NAME(XRef))
2151
0
      {
2152
0
        if (opts->use_list)
2153
0
          opts->use_list[num] = 0;
2154
0
        skip = 1;
2155
0
      }
2156
0
    }
2157
2158
0
    if (!skip)
2159
0
    {
2160
0
      if (pdf_obj_num_is_stream(ctx, doc, num))
2161
0
      {
2162
0
        do_deflate = opts->do_compress;
2163
0
        do_expand = opts->do_expand;
2164
0
        if (opts->do_compress_images && is_image_stream(ctx, obj))
2165
0
          do_deflate = 1, do_expand = 0;
2166
0
        if (opts->do_compress_fonts && is_font_stream(ctx, obj))
2167
0
          do_deflate = 1, do_expand = 0;
2168
0
        if (is_xml_metadata(ctx, obj))
2169
0
          do_deflate = 0, do_expand = 0;
2170
0
        if (is_jpx_stream(ctx, obj))
2171
0
          do_deflate = 0, do_expand = 0;
2172
2173
0
        if (do_expand && num != opts->hint_object_num)
2174
0
          expandstream(ctx, doc, opts, obj, num, gen, do_deflate, unenc);
2175
0
        else
2176
0
          copystream(ctx, doc, opts, obj, num, gen, do_deflate, unenc);
2177
0
      }
2178
0
      else
2179
0
      {
2180
0
        fz_write_printf(ctx, opts->out, "%d %d obj\n", num, gen);
2181
0
        pdf_print_encrypted_obj(ctx, opts->out, obj, opts->do_tight, opts->do_ascii, unenc ? NULL : opts->crypt, num, gen, NULL);
2182
0
        fz_write_string(ctx, opts->out, "\nendobj\n\n");
2183
0
      }
2184
0
    }
2185
0
  }
2186
0
  fz_always(ctx)
2187
0
  {
2188
0
    fz_drop_buffer(ctx, buf);
2189
0
    pdf_drop_obj(ctx, obj);
2190
0
  }
2191
0
  fz_catch(ctx)
2192
0
  {
2193
0
    fz_rethrow(ctx);
2194
0
  }
2195
0
}
2196
2197
static void writexrefsubsect(fz_context *ctx, pdf_write_state *opts, int from, int to)
2198
0
{
2199
0
  int num;
2200
2201
0
  fz_write_printf(ctx, opts->out, "%d %d\n", from, to - from);
2202
0
  for (num = from; num < to; num++)
2203
0
  {
2204
0
    if (opts->use_list[num])
2205
0
      fz_write_printf(ctx, opts->out, "%010lu %05d n \n", opts->ofs_list[num], opts->gen_list[num]);
2206
0
    else
2207
0
      fz_write_printf(ctx, opts->out, "%010lu %05d f \n", opts->ofs_list[num], opts->gen_list[num]);
2208
0
  }
2209
0
}
2210
2211
static void writexref(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, int from, int to, int first, int64_t main_xref_offset, int64_t startxref)
2212
0
{
2213
0
  pdf_obj *trailer = NULL;
2214
0
  pdf_obj *obj;
2215
2216
0
  fz_write_string(ctx, opts->out, "xref\n");
2217
0
  opts->first_xref_entry_offset = fz_tell_output(ctx, opts->out);
2218
2219
0
  if (opts->do_incremental)
2220
0
  {
2221
0
    int subfrom = from;
2222
0
    int subto;
2223
2224
0
    while (subfrom < to)
2225
0
    {
2226
0
      while (subfrom < to && !pdf_xref_is_incremental(ctx, doc, subfrom))
2227
0
        subfrom++;
2228
2229
0
      subto = subfrom;
2230
0
      while (subto < to && pdf_xref_is_incremental(ctx, doc, subto))
2231
0
        subto++;
2232
2233
0
      if (subfrom < subto)
2234
0
        writexrefsubsect(ctx, opts, subfrom, subto);
2235
2236
0
      subfrom = subto;
2237
0
    }
2238
0
  }
2239
0
  else
2240
0
  {
2241
0
    writexrefsubsect(ctx, opts, from, to);
2242
0
  }
2243
2244
0
  fz_write_string(ctx, opts->out, "\n");
2245
2246
0
  fz_var(trailer);
2247
2248
0
  fz_try(ctx)
2249
0
  {
2250
0
    if (opts->do_incremental)
2251
0
    {
2252
0
      trailer = pdf_keep_obj(ctx, pdf_trailer(ctx, doc));
2253
0
      pdf_dict_put_int(ctx, trailer, PDF_NAME(Size), pdf_xref_len(ctx, doc));
2254
0
      pdf_dict_put_int(ctx, trailer, PDF_NAME(Prev), doc->startxref);
2255
0
      pdf_dict_del(ctx, trailer, PDF_NAME(XRefStm));
2256
0
      if (!opts->do_snapshot)
2257
0
        doc->startxref = startxref;
2258
0
    }
2259
0
    else
2260
0
    {
2261
0
      trailer = pdf_new_dict(ctx, doc, 5);
2262
2263
0
      pdf_dict_put_int(ctx, trailer, PDF_NAME(Size), to);
2264
2265
0
      if (first)
2266
0
      {
2267
0
        pdf_obj *otrailer = pdf_trailer(ctx, doc);
2268
0
        obj = pdf_dict_get(ctx, otrailer, PDF_NAME(Info));
2269
0
        if (obj)
2270
0
          pdf_dict_put(ctx, trailer, PDF_NAME(Info), obj);
2271
2272
0
        obj = pdf_dict_get(ctx, otrailer, PDF_NAME(Root));
2273
0
        if (obj)
2274
0
          pdf_dict_put(ctx, trailer, PDF_NAME(Root), obj);
2275
2276
2277
0
        obj = pdf_dict_get(ctx, otrailer, PDF_NAME(ID));
2278
0
        if (obj)
2279
0
          pdf_dict_put(ctx, trailer, PDF_NAME(ID), obj);
2280
2281
0
        if (opts->crypt_obj)
2282
0
        {
2283
0
          if (pdf_is_indirect(ctx, opts->crypt_obj))
2284
0
            pdf_dict_put_drop(ctx, trailer, PDF_NAME(Encrypt), pdf_new_indirect(ctx, doc, opts->crypt_object_number, 0));
2285
0
          else
2286
0
            pdf_dict_put(ctx, trailer, PDF_NAME(Encrypt), opts->crypt_obj);
2287
0
        }
2288
2289
0
        if (opts->metadata)
2290
0
          pdf_dict_putp(ctx, trailer, "Root/Metadata", opts->metadata);
2291
0
      }
2292
0
      if (main_xref_offset != 0)
2293
0
        pdf_dict_put_int(ctx, trailer, PDF_NAME(Prev), main_xref_offset);
2294
0
    }
2295
2296
0
    fz_write_string(ctx, opts->out, "trailer\n");
2297
    /* Trailer is NOT encrypted */
2298
0
    pdf_print_obj(ctx, opts->out, trailer, opts->do_tight, opts->do_ascii);
2299
0
    fz_write_string(ctx, opts->out, "\n");
2300
2301
0
    fz_write_printf(ctx, opts->out, "startxref\n%lu\n%%%%EOF\n", startxref);
2302
2303
0
    doc->last_xref_was_old_style = 1;
2304
0
  }
2305
0
  fz_always(ctx)
2306
0
  {
2307
0
    pdf_drop_obj(ctx, trailer);
2308
0
  }
2309
0
  fz_catch(ctx)
2310
0
  {
2311
0
    fz_rethrow(ctx);
2312
0
  }
2313
0
}
2314
2315
static void writexrefstreamsubsect(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, pdf_obj *index, fz_buffer *fzbuf, int from, int to)
2316
0
{
2317
0
  int num;
2318
2319
0
  pdf_array_push_int(ctx, index, from);
2320
0
  pdf_array_push_int(ctx, index, to - from);
2321
0
  for (num = from; num < to; num++)
2322
0
  {
2323
0
    int f1, f2, f3;
2324
0
    pdf_xref_entry *x = pdf_get_xref_entry_no_null(ctx, doc, num);
2325
0
    if (opts->use_list[num] == 0)
2326
0
    {
2327
0
      f1 = 0; /* Free */
2328
0
      f2 = opts->ofs_list[num];
2329
0
      f3 = opts->gen_list[num];
2330
0
    }
2331
0
    else if (x->type == 'o')
2332
0
    {
2333
0
      f1 = 2; /* Object Stream */
2334
0
      f2 = opts->ofs_list[num];
2335
0
      f3 = opts->gen_list[num];
2336
0
    }
2337
0
    else
2338
0
    {
2339
0
      f1 = 1; /* Object */
2340
0
      f2 = opts->ofs_list[num];
2341
0
      f3 = opts->gen_list[num];
2342
0
    }
2343
0
    fz_append_byte(ctx, fzbuf, f1);
2344
0
    fz_append_byte(ctx, fzbuf, f2>>24);
2345
0
    fz_append_byte(ctx, fzbuf, f2>>16);
2346
0
    fz_append_byte(ctx, fzbuf, f2>>8);
2347
0
    fz_append_byte(ctx, fzbuf, f2);
2348
0
    fz_append_byte(ctx, fzbuf, f3);
2349
0
  }
2350
0
}
2351
2352
static void writexrefstream(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, int from, int to, int first, int64_t main_xref_offset, int64_t startxref)
2353
0
{
2354
0
  int num;
2355
0
  pdf_obj *dict = NULL;
2356
0
  pdf_obj *obj;
2357
0
  pdf_obj *w = NULL;
2358
0
  pdf_obj *index;
2359
0
  fz_buffer *fzbuf = NULL;
2360
2361
0
  fz_var(dict);
2362
0
  fz_var(w);
2363
0
  fz_var(fzbuf);
2364
0
  fz_try(ctx)
2365
0
  {
2366
0
    num = pdf_create_object(ctx, doc);
2367
0
    expand_lists(ctx, opts, num);
2368
2369
0
    dict = pdf_new_dict(ctx, doc, 6);
2370
0
    pdf_update_object(ctx, doc, num, dict);
2371
2372
0
    opts->first_xref_entry_offset = fz_tell_output(ctx, opts->out);
2373
2374
0
    to++;
2375
2376
0
    if (first)
2377
0
    {
2378
0
      obj = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Info));
2379
0
      if (obj)
2380
0
        pdf_dict_put(ctx, dict, PDF_NAME(Info), obj);
2381
2382
0
      obj = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root));
2383
0
      if (obj)
2384
0
        pdf_dict_put(ctx, dict, PDF_NAME(Root), obj);
2385
2386
0
      obj = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(ID));
2387
0
      if (obj)
2388
0
        pdf_dict_put(ctx, dict, PDF_NAME(ID), obj);
2389
2390
0
      if (opts->do_incremental)
2391
0
      {
2392
0
        obj = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Encrypt));
2393
0
        if (obj)
2394
0
          pdf_dict_put(ctx, dict, PDF_NAME(Encrypt), obj);
2395
0
      }
2396
0
    }
2397
2398
0
    pdf_dict_put_int(ctx, dict, PDF_NAME(Size), to);
2399
2400
0
    if (opts->do_incremental)
2401
0
    {
2402
0
      pdf_dict_put_int(ctx, dict, PDF_NAME(Prev), doc->startxref);
2403
0
      if (!opts->do_snapshot)
2404
0
        doc->startxref = startxref;
2405
0
    }
2406
0
    else
2407
0
    {
2408
0
      if (main_xref_offset != 0)
2409
0
        pdf_dict_put_int(ctx, dict, PDF_NAME(Prev), main_xref_offset);
2410
0
    }
2411
2412
0
    pdf_dict_put(ctx, dict, PDF_NAME(Type), PDF_NAME(XRef));
2413
2414
0
    w = pdf_new_array(ctx, doc, 3);
2415
0
    pdf_dict_put(ctx, dict, PDF_NAME(W), w);
2416
0
    pdf_array_push_int(ctx, w, 1);
2417
0
    pdf_array_push_int(ctx, w, 4);
2418
0
    pdf_array_push_int(ctx, w, 1);
2419
2420
0
    index = pdf_new_array(ctx, doc, 2);
2421
0
    pdf_dict_put_drop(ctx, dict, PDF_NAME(Index), index);
2422
2423
    /* opts->gen_list[num] is already initialized by fz_calloc. */
2424
0
    opts->use_list[num] = 1;
2425
0
    opts->ofs_list[num] = opts->first_xref_entry_offset;
2426
2427
0
    fzbuf = fz_new_buffer(ctx, (1 + 4 + 1) * (to-from));
2428
2429
0
    if (opts->do_incremental)
2430
0
    {
2431
0
      int subfrom = from;
2432
0
      int subto;
2433
2434
0
      while (subfrom < to)
2435
0
      {
2436
0
        while (subfrom < to && !pdf_xref_is_incremental(ctx, doc, subfrom))
2437
0
          subfrom++;
2438
2439
0
        subto = subfrom;
2440
0
        while (subto < to && pdf_xref_is_incremental(ctx, doc, subto))
2441
0
          subto++;
2442
2443
0
        if (subfrom < subto)
2444
0
          writexrefstreamsubsect(ctx, doc, opts, index, fzbuf, subfrom, subto);
2445
2446
0
        subfrom = subto;
2447
0
      }
2448
0
    }
2449
0
    else
2450
0
    {
2451
0
      writexrefstreamsubsect(ctx, doc, opts, index, fzbuf, from, to);
2452
0
    }
2453
2454
0
    pdf_update_stream(ctx, doc, dict, fzbuf, 0);
2455
2456
0
    writeobject(ctx, doc, opts, num, 0, 0, 1);
2457
0
    fz_write_printf(ctx, opts->out, "startxref\n%lu\n%%%%EOF\n", startxref);
2458
2459
0
    if (opts->do_snapshot)
2460
0
      pdf_delete_object(ctx, doc, num);
2461
0
  }
2462
0
  fz_always(ctx)
2463
0
  {
2464
0
    pdf_drop_obj(ctx, dict);
2465
0
    pdf_drop_obj(ctx, w);
2466
0
    fz_drop_buffer(ctx, fzbuf);
2467
0
  }
2468
0
  fz_catch(ctx)
2469
0
  {
2470
0
    fz_rethrow(ctx);
2471
0
  }
2472
2473
0
  doc->last_xref_was_old_style = 0;
2474
0
}
2475
2476
static void
2477
padto(fz_context *ctx, fz_output *out, int64_t target)
2478
0
{
2479
0
  int64_t pos = fz_tell_output(ctx, out);
2480
2481
0
  assert(pos <= target);
2482
0
  while (pos < target)
2483
0
  {
2484
0
    fz_write_byte(ctx, out, '\n');
2485
0
    pos++;
2486
0
  }
2487
0
}
2488
2489
static void
2490
dowriteobject(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, int num, int pass)
2491
0
{
2492
0
  pdf_xref_entry *entry = pdf_get_xref_entry_no_null(ctx, doc, num);
2493
0
  int gen = opts->gen_list ? opts->gen_list[num] : 0;
2494
0
  if (entry->type == 'f')
2495
0
    gen = entry->gen;
2496
0
  if (entry->type == 'n')
2497
0
    gen = entry->gen;
2498
2499
  /* If we are renumbering, then make sure all generation numbers are
2500
   * zero (except object 0 which must be free, and have a gen number of
2501
   * 65535). Changing the generation numbers (and indeed object numbers)
2502
   * will break encryption - so only do this if we are renumbering
2503
   * anyway. */
2504
0
  if (opts->do_garbage >= 2)
2505
0
    gen = (num == 0 ? 65535 : 0);
2506
2507
  /* For objects in object streams, the gen number gives us the index of
2508
   * the object within the stream. */
2509
0
  if (entry->type == 'o')
2510
0
    gen = entry->gen;
2511
2512
0
  if (opts->gen_list)
2513
0
    opts->gen_list[num] = gen;
2514
2515
0
  if (opts->do_garbage && !opts->use_list[num])
2516
0
    return;
2517
2518
0
  if (entry->type == 'o' && (!opts->do_incremental || pdf_xref_is_incremental(ctx, doc, num)))
2519
0
  {
2520
0
    assert(opts->do_use_objstms);
2521
0
    opts->ofs_list[num] = entry->ofs;
2522
0
    return;
2523
0
  }
2524
2525
0
  if (entry->type == 'n')
2526
0
  {
2527
0
    if (pass > 0)
2528
0
      padto(ctx, opts->out, opts->ofs_list[num]);
2529
0
    if (!opts->do_incremental || pdf_xref_is_incremental(ctx, doc, num))
2530
0
    {
2531
0
      if (opts->ofs_list)
2532
0
        opts->ofs_list[num] = fz_tell_output(ctx, opts->out);
2533
0
      writeobject(ctx, doc, opts, num, gen, 1, num == opts->crypt_object_number);
2534
0
    }
2535
0
  }
2536
0
  else if (opts->use_list)
2537
0
    opts->use_list[num] = 0;
2538
0
}
2539
2540
static void
2541
writeobjects(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, int pass)
2542
0
{
2543
0
  int num;
2544
0
  int xref_len = pdf_xref_len(ctx, doc);
2545
2546
0
  if (!opts->do_incremental)
2547
0
  {
2548
0
    int version = pdf_version(ctx, doc);
2549
0
    fz_write_printf(ctx, opts->out, "%%PDF-%d.%d\n", version / 10, version % 10);
2550
0
    fz_write_string(ctx, opts->out, "%\xC2\xB5\xC2\xB6\n\n");
2551
0
  }
2552
2553
0
  dowriteobject(ctx, doc, opts, opts->start, pass);
2554
2555
0
  if (opts->do_linear)
2556
0
  {
2557
    /* Write first xref */
2558
0
    if (pass == 0)
2559
0
      opts->first_xref_offset = fz_tell_output(ctx, opts->out);
2560
0
    else
2561
0
      padto(ctx, opts->out, opts->first_xref_offset);
2562
0
    writexref(ctx, doc, opts, opts->start, pdf_xref_len(ctx, doc), 1, opts->main_xref_offset, 0);
2563
0
  }
2564
2565
0
  for (num = opts->start+1; num < xref_len; num++)
2566
0
    dowriteobject(ctx, doc, opts, num, pass);
2567
0
  if (opts->do_linear && pass == 1)
2568
0
  {
2569
0
    int64_t offset = (opts->start == 1 ? opts->main_xref_offset : opts->ofs_list[1] + opts->hintstream_len);
2570
0
    padto(ctx, opts->out, offset);
2571
0
  }
2572
0
  for (num = 1; num < opts->start; num++)
2573
0
  {
2574
0
    if (pass == 1)
2575
0
      opts->ofs_list[num] += opts->hintstream_len;
2576
0
    dowriteobject(ctx, doc, opts, num, pass);
2577
0
  }
2578
0
}
2579
2580
static int
2581
my_log2(int x)
2582
0
{
2583
0
  int i = 0;
2584
0
  const int sign_bit = sizeof(int)*8-1;
2585
2586
0
  if (x <= 0)
2587
0
    return 0;
2588
2589
0
  while ((1<<i) <= x && i < sign_bit)
2590
0
    i++;
2591
2592
0
  if (i >= sign_bit)
2593
0
    return 0;
2594
2595
0
  return i;
2596
0
}
2597
2598
static int64_t
2599
offset_of_first_used_obj_after(const pdf_write_state *opts, int i, int len)
2600
0
{
2601
  /* The objects in the file are laid out as:
2602
   *
2603
   * start
2604
   * ...
2605
   * len-1
2606
   * 1
2607
   * ...
2608
   * start-1
2609
   *
2610
   * But, some may not be present...
2611
   */
2612
0
  do
2613
0
  {
2614
0
    i++;
2615
0
    if (i == len)
2616
0
      i = 1;
2617
0
    if (i == opts->start)
2618
0
      return opts->main_xref_offset;
2619
0
  }
2620
0
  while (opts->use_list[i] == 0);
2621
2622
0
  return opts->ofs_list[i];
2623
0
}
2624
2625
static void
2626
make_page_offset_hints(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, fz_buffer *buf)
2627
0
{
2628
0
  int i, j;
2629
0
  int min_objs_per_page, max_objs_per_page;
2630
0
  int min_page_length, max_page_length;
2631
0
  int objs_per_page_bits;
2632
0
  int min_shared_object, max_shared_object;
2633
0
  int max_shared_object_refs = 0;
2634
0
  int min_shared_length, max_shared_length;
2635
0
  page_objects **pop = &opts->page_object_lists->page[0];
2636
0
  int page_len_bits, shared_object_bits, shared_object_id_bits;
2637
0
  int shared_length_bits;
2638
0
  int xref_len = pdf_xref_len(ctx, doc);
2639
2640
0
  min_shared_object = pdf_xref_len(ctx, doc);
2641
0
  max_shared_object = 1;
2642
0
  min_shared_length = opts->file_len;
2643
0
  max_shared_length = 0;
2644
0
  for (i=1; i < xref_len; i++)
2645
0
  {
2646
0
    int min, max, page;
2647
2648
0
    min = opts->ofs_list[i];
2649
0
    max = offset_of_first_used_obj_after(opts, i, xref_len);
2650
2651
0
    assert(max > min);
2652
2653
0
    if (opts->use_list[i] & USE_SHARED)
2654
0
    {
2655
0
      page = -1;
2656
0
      if (i < min_shared_object)
2657
0
        min_shared_object = i;
2658
0
      if (i > max_shared_object)
2659
0
        max_shared_object = i;
2660
0
      if (min_shared_length > max - min)
2661
0
        min_shared_length = max - min;
2662
0
      if (max_shared_length < max - min)
2663
0
        max_shared_length = max - min;
2664
0
    }
2665
0
    else if (opts->use_list[i] & (USE_CATALOGUE | USE_HINTS | USE_PARAMS))
2666
0
      page = -1;
2667
0
    else if (opts->use_list[i] & USE_PAGE1)
2668
0
    {
2669
0
      page = 0;
2670
0
      if (min_shared_length > max - min)
2671
0
        min_shared_length = max - min;
2672
0
      if (max_shared_length < max - min)
2673
0
        max_shared_length = max - min;
2674
0
    }
2675
0
    else if (opts->use_list[i] == 0)
2676
0
      page = -1;
2677
0
    else
2678
0
      page = opts->use_list[i]>>USE_PAGE_SHIFT;
2679
2680
0
    if (page >= 0)
2681
0
    {
2682
0
      pop[page]->num_objects++;
2683
0
      if (pop[page]->min_ofs > min)
2684
0
        pop[page]->min_ofs = min;
2685
0
      if (pop[page]->max_ofs < max)
2686
0
        pop[page]->max_ofs = max;
2687
0
    }
2688
0
  }
2689
2690
0
  min_objs_per_page = max_objs_per_page = pop[0]->num_objects;
2691
0
  min_page_length = max_page_length = pop[0]->max_ofs - pop[0]->min_ofs;
2692
0
  for (i=1; i < opts->page_count; i++)
2693
0
  {
2694
0
    int tmp;
2695
0
    if (min_objs_per_page > pop[i]->num_objects)
2696
0
      min_objs_per_page = pop[i]->num_objects;
2697
0
    if (max_objs_per_page < pop[i]->num_objects)
2698
0
      max_objs_per_page = pop[i]->num_objects;
2699
0
    tmp = pop[i]->max_ofs - pop[i]->min_ofs;
2700
0
    if (tmp < min_page_length)
2701
0
      min_page_length = tmp;
2702
0
    if (tmp > max_page_length)
2703
0
      max_page_length = tmp;
2704
0
  }
2705
2706
0
  for (i=0; i < opts->page_count; i++)
2707
0
  {
2708
0
    int count = 0;
2709
0
    page_objects *po = opts->page_object_lists->page[i];
2710
0
    for (j = 0; j < po->len; j++)
2711
0
    {
2712
0
      if (i == 0 && opts->use_list[po->object[j]] & USE_PAGE1)
2713
0
        count++;
2714
0
      else if (i != 0 && opts->use_list[po->object[j]] & USE_SHARED)
2715
0
        count++;
2716
0
    }
2717
0
    po->num_shared = count;
2718
0
    if (i == 0 || count > max_shared_object_refs)
2719
0
      max_shared_object_refs = count;
2720
0
  }
2721
0
  if (min_shared_object > max_shared_object)
2722
0
    min_shared_object = max_shared_object = 0;
2723
2724
  /* Table F.3 - Header */
2725
  /* Header Item 1: Least number of objects in a page */
2726
0
  fz_append_bits(ctx, buf, min_objs_per_page, 32);
2727
  /* Header Item 2: Location of first pages page object */
2728
0
  fz_append_bits(ctx, buf, opts->ofs_list[pop[0]->page_object_number], 32);
2729
  /* Header Item 3: Number of bits required to represent the difference
2730
   * between the greatest and least number of objects in a page. */
2731
0
  objs_per_page_bits = my_log2(max_objs_per_page - min_objs_per_page);
2732
0
  fz_append_bits(ctx, buf, objs_per_page_bits, 16);
2733
  /* Header Item 4: Least length of a page. */
2734
0
  fz_append_bits(ctx, buf, min_page_length, 32);
2735
  /* Header Item 5: Number of bits needed to represent the difference
2736
   * between the greatest and least length of a page. */
2737
0
  page_len_bits = my_log2(max_page_length - min_page_length);
2738
0
  fz_append_bits(ctx, buf, page_len_bits, 16);
2739
  /* Header Item 6: Least offset to start of content stream (Acrobat
2740
   * sets this to always be 0) */
2741
0
  fz_append_bits(ctx, buf, 0, 32);
2742
  /* Header Item 7: Number of bits needed to represent the difference
2743
   * between the greatest and least offset to content stream (Acrobat
2744
   * sets this to always be 0) */
2745
0
  fz_append_bits(ctx, buf, 0, 16);
2746
  /* Header Item 8: Least content stream length. (Acrobat
2747
   * sets this to always be 0) */
2748
0
  fz_append_bits(ctx, buf, 0, 32);
2749
  /* Header Item 9: Number of bits needed to represent the difference
2750
   * between the greatest and least content stream length (Acrobat
2751
   * sets this to always be the same as item 5) */
2752
0
  fz_append_bits(ctx, buf, page_len_bits, 16);
2753
  /* Header Item 10: Number of bits needed to represent the greatest
2754
   * number of shared object references. */
2755
0
  shared_object_bits = my_log2(max_shared_object_refs);
2756
0
  fz_append_bits(ctx, buf, shared_object_bits, 16);
2757
  /* Header Item 11: Number of bits needed to represent the greatest
2758
   * shared object identifier. */
2759
0
  shared_object_id_bits = my_log2(max_shared_object - min_shared_object + pop[0]->num_shared);
2760
0
  fz_append_bits(ctx, buf, shared_object_id_bits, 16);
2761
  /* Header Item 12: Number of bits needed to represent the numerator
2762
   * of the fractions. We always send 0. */
2763
0
  fz_append_bits(ctx, buf, 0, 16);
2764
  /* Header Item 13: Number of bits needed to represent the denominator
2765
   * of the fractions. We always send 0. */
2766
0
  fz_append_bits(ctx, buf, 0, 16);
2767
2768
  /* Table F.4 - Page offset hint table (per page) */
2769
  /* Item 1: A number that, when added to the least number of objects
2770
   * on a page, gives the number of objects in the page. */
2771
0
  for (i = 0; i < opts->page_count; i++)
2772
0
  {
2773
0
    fz_append_bits(ctx, buf, pop[i]->num_objects - min_objs_per_page, objs_per_page_bits);
2774
0
  }
2775
0
  fz_append_bits_pad(ctx, buf);
2776
  /* Item 2: A number that, when added to the least page length, gives
2777
   * the length of the page in bytes. */
2778
0
  for (i = 0; i < opts->page_count; i++)
2779
0
  {
2780
0
    fz_append_bits(ctx, buf, pop[i]->max_ofs - pop[i]->min_ofs - min_page_length, page_len_bits);
2781
0
  }
2782
0
  fz_append_bits_pad(ctx, buf);
2783
  /* Item 3: The number of shared objects referenced from the page. */
2784
0
  for (i = 0; i < opts->page_count; i++)
2785
0
  {
2786
0
    fz_append_bits(ctx, buf, pop[i]->num_shared, shared_object_bits);
2787
0
  }
2788
0
  fz_append_bits_pad(ctx, buf);
2789
  /* Item 4: Shared object id for each shared object ref in every page.
2790
   * Spec says "not for page 1", but acrobat does send page 1's - all
2791
   * as zeros. */
2792
0
  for (i = 0; i < opts->page_count; i++)
2793
0
  {
2794
0
    for (j = 0; j < pop[i]->len; j++)
2795
0
    {
2796
0
      int o = pop[i]->object[j];
2797
0
      if (i == 0 && opts->use_list[o] & USE_PAGE1)
2798
0
        fz_append_bits(ctx, buf, 0 /* o - pop[0]->page_object_number */, shared_object_id_bits);
2799
0
      if (i != 0 && opts->use_list[o] & USE_SHARED)
2800
0
        fz_append_bits(ctx, buf, o - min_shared_object + pop[0]->num_shared, shared_object_id_bits);
2801
0
    }
2802
0
  }
2803
0
  fz_append_bits_pad(ctx, buf);
2804
  /* Item 5: Numerator of fractional position for each shared object reference. */
2805
  /* We always send 0 in 0 bits */
2806
  /* Item 6: A number that, when added to the least offset to the start
2807
   * of the content stream (F.3 Item 6), gives the offset in bytes of
2808
   * start of the pages content stream object relative to the beginning
2809
   * of the page. Always 0 in 0 bits. */
2810
  /* Item 7: A number that, when added to the least content stream length
2811
   * (F.3 Item 8), gives the length of the pages content stream object.
2812
   * Always == Item 2 as least content stream length = least page stream
2813
   * length.
2814
   */
2815
0
  for (i = 0; i < opts->page_count; i++)
2816
0
  {
2817
0
    fz_append_bits(ctx, buf, pop[i]->max_ofs - pop[i]->min_ofs - min_page_length, page_len_bits);
2818
0
  }
2819
2820
  /* Pad, and then do shared object hint table */
2821
0
  fz_append_bits_pad(ctx, buf);
2822
0
  opts->hints_shared_offset = (int)fz_buffer_storage(ctx, buf, NULL);
2823
2824
  /* Table F.5: */
2825
  /* Header Item 1: Object number of the first object in the shared
2826
   * objects section. */
2827
0
  fz_append_bits(ctx, buf, min_shared_object, 32);
2828
  /* Header Item 2: Location of first object in the shared objects
2829
   * section. */
2830
0
  fz_append_bits(ctx, buf, opts->ofs_list[min_shared_object], 32);
2831
  /* Header Item 3: The number of shared object entries for the first
2832
   * page. */
2833
0
  fz_append_bits(ctx, buf, pop[0]->num_shared, 32);
2834
  /* Header Item 4: The number of shared object entries for the shared
2835
   * objects section + first page. */
2836
0
  fz_append_bits(ctx, buf, max_shared_object - min_shared_object + pop[0]->num_shared, 32);
2837
  /* Header Item 5: The number of bits needed to represent the greatest
2838
   * number of objects in a shared object group (Always 0). */
2839
0
  fz_append_bits(ctx, buf, 0, 16);
2840
  /* Header Item 6: The least length of a shared object group in bytes. */
2841
0
  fz_append_bits(ctx, buf, min_shared_length, 32);
2842
  /* Header Item 7: The number of bits required to represent the
2843
   * difference between the greatest and least length of a shared object
2844
   * group. */
2845
0
  shared_length_bits = my_log2(max_shared_length - min_shared_length);
2846
0
  fz_append_bits(ctx, buf, shared_length_bits, 16);
2847
2848
  /* Table F.6 */
2849
  /* Item 1: Shared object group length (page 1 objects) */
2850
0
  for (j = 0; j < pop[0]->len; j++)
2851
0
  {
2852
0
    int o = pop[0]->object[j];
2853
0
    int64_t min, max;
2854
0
    min = opts->ofs_list[o];
2855
0
    if (o == opts->start-1)
2856
0
      max = opts->main_xref_offset;
2857
0
    else if (o < xref_len-1)
2858
0
      max = opts->ofs_list[o+1];
2859
0
    else
2860
0
      max = opts->ofs_list[1];
2861
0
    if (opts->use_list[o] & USE_PAGE1)
2862
0
      fz_append_bits(ctx, buf, max - min - min_shared_length, shared_length_bits);
2863
0
  }
2864
  /* Item 1: Shared object group length (shared objects) */
2865
0
  for (i = min_shared_object; i <= max_shared_object; i++)
2866
0
  {
2867
0
    int min, max;
2868
0
    min = opts->ofs_list[i];
2869
0
    if (i == opts->start-1)
2870
0
      max = opts->main_xref_offset;
2871
0
    else if (i < xref_len-1)
2872
0
      max = opts->ofs_list[i+1];
2873
0
    else
2874
0
      max = opts->ofs_list[1];
2875
0
    fz_append_bits(ctx, buf, max - min - min_shared_length, shared_length_bits);
2876
0
  }
2877
0
  fz_append_bits_pad(ctx, buf);
2878
2879
  /* Item 2: MD5 presence flags */
2880
0
  for (i = max_shared_object - min_shared_object + pop[0]->num_shared; i > 0; i--)
2881
0
  {
2882
0
    fz_append_bits(ctx, buf, 0, 1);
2883
0
  }
2884
0
  fz_append_bits_pad(ctx, buf);
2885
  /* Item 3: MD5 sums (not present) */
2886
0
  fz_append_bits_pad(ctx, buf);
2887
  /* Item 4: Number of objects in the group (not present) */
2888
0
}
2889
2890
static void
2891
make_hint_stream(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
2892
0
{
2893
0
  fz_buffer *buf;
2894
0
  pdf_obj *obj = NULL;
2895
2896
0
  fz_var(obj);
2897
2898
0
  buf = fz_new_buffer(ctx, 100);
2899
0
  fz_try(ctx)
2900
0
  {
2901
0
    make_page_offset_hints(ctx, doc, opts, buf);
2902
0
    obj = pdf_load_object(ctx, doc, pdf_xref_len(ctx, doc)-1);
2903
0
    pdf_update_stream(ctx, doc, obj, buf, 0);
2904
0
    opts->hintstream_len = (int64_t)fz_buffer_storage(ctx, buf, NULL);
2905
0
  }
2906
0
  fz_always(ctx)
2907
0
  {
2908
0
    pdf_drop_obj(ctx, obj);
2909
0
    fz_drop_buffer(ctx, buf);
2910
0
  }
2911
0
  fz_catch(ctx)
2912
0
    fz_rethrow(ctx);
2913
0
}
2914
2915
#ifdef DEBUG_WRITING
2916
static void dump_object_details(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
2917
{
2918
  int i;
2919
2920
  for (i = 0; i < pdf_xref_len(ctx, doc); i++)
2921
  {
2922
    fprintf(stderr, "%d@%ld: use=%d\n", i, opts->ofs_list[i], opts->use_list[i]);
2923
  }
2924
}
2925
#endif
2926
2927
static void presize_unsaved_signature_byteranges(fz_context *ctx, pdf_document *doc)
2928
0
{
2929
0
  int s;
2930
2931
0
  for (s = 0; s < doc->num_incremental_sections; s++)
2932
0
  {
2933
0
    pdf_xref *xref = &doc->xref_sections[s];
2934
2935
0
    if (xref->unsaved_sigs)
2936
0
    {
2937
      /* The ByteRange objects of signatures are initially written out with
2938
      * dummy values, and then overwritten later. We need to make sure their
2939
      * initial form at least takes enough sufficient file space */
2940
0
      pdf_unsaved_sig *usig;
2941
0
      int n = 0;
2942
2943
0
      for (usig = xref->unsaved_sigs; usig; usig = usig->next)
2944
0
        n++;
2945
2946
0
      for (usig = xref->unsaved_sigs; usig; usig = usig->next)
2947
0
      {
2948
        /* There will be segments of bytes at the beginning, at
2949
        * the end and between each consecutive pair of signatures,
2950
        * hence n + 1 */
2951
0
        int i;
2952
0
        pdf_obj *byte_range = pdf_dict_getl(ctx, usig->field, PDF_NAME(V), PDF_NAME(ByteRange), NULL);
2953
2954
0
        for (i = 0; i < n+1; i++)
2955
0
        {
2956
0
          pdf_array_push_int(ctx, byte_range, INT_MAX);
2957
0
          pdf_array_push_int(ctx, byte_range, INT_MAX);
2958
0
        }
2959
0
      }
2960
0
    }
2961
0
  }
2962
0
}
2963
2964
static void complete_signatures(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
2965
0
{
2966
0
  pdf_obj *byte_range = NULL;
2967
0
  char *buf = NULL, *ptr;
2968
0
  int s;
2969
0
  fz_stream *stm = NULL;
2970
2971
0
  fz_var(byte_range);
2972
0
  fz_var(stm);
2973
0
  fz_var(buf);
2974
2975
0
  fz_try(ctx)
2976
0
  {
2977
0
    for (s = 0; s < doc->num_incremental_sections; s++)
2978
0
    {
2979
0
      pdf_xref *xref = &doc->xref_sections[doc->num_incremental_sections - s - 1];
2980
2981
0
      if (xref->unsaved_sigs)
2982
0
      {
2983
0
        pdf_unsaved_sig *usig;
2984
0
        size_t buf_size = 0;
2985
0
        size_t i;
2986
0
        size_t last_end;
2987
2988
0
        for (usig = xref->unsaved_sigs; usig; usig = usig->next)
2989
0
        {
2990
0
          size_t size = usig->signer->max_digest_size(ctx, usig->signer);
2991
0
          buf_size = fz_maxz(buf_size, size);
2992
0
        }
2993
2994
0
        buf_size = buf_size * 2 + SIG_EXTRAS_SIZE;
2995
2996
0
        buf = fz_calloc(ctx, buf_size, 1);
2997
2998
0
        stm = fz_stream_from_output(ctx, opts->out);
2999
        /* Locate the byte ranges and contents in the saved file */
3000
0
        for (usig = xref->unsaved_sigs; usig; usig = usig->next)
3001
0
        {
3002
0
          char *bstr, *cstr, *fstr;
3003
0
          size_t bytes_read;
3004
0
          int pnum = pdf_obj_parent_num(ctx, pdf_dict_getl(ctx, usig->field, PDF_NAME(V), PDF_NAME(ByteRange), NULL));
3005
0
          fz_seek(ctx, stm, opts->ofs_list[pnum], SEEK_SET);
3006
          /* SIG_EXTRAS_SIZE is an arbitrary value and its addition above to buf_size
3007
           * could cause an attempt to read off the end of the file. That's not an
3008
           * error, but we need to keep track of how many bytes are read and search
3009
           * for markers only in defined data */
3010
0
          bytes_read = fz_read(ctx, stm, (unsigned char *)buf, buf_size);
3011
0
          assert(bytes_read <= buf_size);
3012
3013
0
          bstr = fz_memmem(buf, bytes_read, SLASH_BYTE_RANGE, sizeof(SLASH_BYTE_RANGE)-1);
3014
0
          cstr = fz_memmem(buf, bytes_read, SLASH_CONTENTS, sizeof(SLASH_CONTENTS)-1);
3015
0
          fstr = fz_memmem(buf, bytes_read, SLASH_FILTER, sizeof(SLASH_FILTER)-1);
3016
3017
0
          if (!(bstr && cstr && fstr && bstr < cstr && cstr < fstr))
3018
0
            fz_throw(ctx, FZ_ERROR_FORMAT, "Failed to determine byte ranges while writing signature");
3019
3020
0
          usig->byte_range_start = bstr - buf + sizeof(SLASH_BYTE_RANGE)-1 + opts->ofs_list[pnum];
3021
0
          usig->byte_range_end = cstr - buf + opts->ofs_list[pnum];
3022
0
          usig->contents_start = cstr - buf + sizeof(SLASH_CONTENTS)-1 + opts->ofs_list[pnum];
3023
0
          usig->contents_end = fstr - buf + opts->ofs_list[pnum];
3024
0
        }
3025
3026
0
        fz_drop_stream(ctx, stm);
3027
0
        stm = NULL;
3028
3029
        /* Recreate ByteRange with correct values. */
3030
0
        byte_range = pdf_new_array(ctx, doc, 4);
3031
3032
0
        last_end = 0;
3033
0
        for (usig = xref->unsaved_sigs; usig; usig = usig->next)
3034
0
        {
3035
0
          pdf_array_push_int(ctx, byte_range, last_end);
3036
0
          pdf_array_push_int(ctx, byte_range, usig->contents_start - last_end);
3037
0
          last_end = usig->contents_end;
3038
0
        }
3039
0
        pdf_array_push_int(ctx, byte_range, last_end);
3040
0
        pdf_array_push_int(ctx, byte_range, xref->end_ofs - last_end);
3041
3042
        /* Copy the new ByteRange to the other unsaved signatures */
3043
0
        for (usig = xref->unsaved_sigs; usig; usig = usig->next)
3044
0
          pdf_dict_putl_drop(ctx, usig->field, pdf_copy_array(ctx, byte_range), PDF_NAME(V), PDF_NAME(ByteRange), NULL);
3045
3046
        /* Write the byte range into buf, padding with spaces*/
3047
0
        ptr = pdf_sprint_obj(ctx, buf, buf_size, &i, byte_range, 1, 0);
3048
0
        if (ptr != buf) /* should never happen, since data should fit in buf_size */
3049
0
          fz_free(ctx, ptr);
3050
0
        memset(buf+i, ' ', buf_size-i);
3051
3052
        /* Write the byte range to the file */
3053
0
        for (usig = xref->unsaved_sigs; usig; usig = usig->next)
3054
0
        {
3055
0
          fz_seek_output(ctx, opts->out, usig->byte_range_start, SEEK_SET);
3056
0
          fz_write_data(ctx, opts->out, buf, usig->byte_range_end - usig->byte_range_start);
3057
0
        }
3058
3059
        /* Write the digests into the file */
3060
0
        for (usig = xref->unsaved_sigs; usig; usig = usig->next)
3061
0
          pdf_write_digest(ctx, opts->out, byte_range, usig->field, usig->contents_start, usig->contents_end - usig->contents_start, usig->signer);
3062
3063
        /* delete the unsaved_sigs records */
3064
0
        while ((usig = xref->unsaved_sigs) != NULL)
3065
0
        {
3066
0
          xref->unsaved_sigs = usig->next;
3067
0
          pdf_drop_obj(ctx, usig->field);
3068
0
          pdf_drop_signer(ctx, usig->signer);
3069
0
          fz_free(ctx, usig);
3070
0
        }
3071
3072
0
        xref->unsaved_sigs_end = NULL;
3073
3074
0
        pdf_drop_obj(ctx, byte_range);
3075
0
        byte_range = NULL;
3076
3077
0
        fz_free(ctx, buf);
3078
0
        buf = NULL;
3079
0
      }
3080
0
    }
3081
0
  }
3082
0
  fz_always(ctx)
3083
0
  {
3084
0
    pdf_drop_obj(ctx, byte_range);
3085
0
  }
3086
0
  fz_catch(ctx)
3087
0
  {
3088
0
    fz_drop_stream(ctx, stm);
3089
0
    fz_free(ctx, buf);
3090
0
    fz_rethrow(ctx);
3091
0
  }
3092
0
}
3093
3094
static void clean_content_streams(fz_context *ctx, pdf_document *doc, int sanitize, int ascii, int newlines)
3095
0
{
3096
0
  int n = pdf_count_pages(ctx, doc);
3097
0
  int i;
3098
3099
0
  pdf_filter_options options = { 0 };
3100
0
  pdf_sanitize_filter_options sopts = { 0 };
3101
0
  pdf_filter_factory list[2] = { 0 };
3102
3103
0
  options.recurse = 1;
3104
0
  options.ascii = ascii;
3105
0
  options.newlines = newlines;
3106
0
  options.filters = sanitize ? list : NULL;
3107
0
  list[0].filter = pdf_new_sanitize_filter;
3108
0
  list[0].options = &sopts;
3109
3110
0
  for (i = 0; i < n; i++)
3111
0
  {
3112
0
    pdf_annot *annot;
3113
0
    pdf_page *page = pdf_load_page(ctx, doc, i);
3114
3115
0
    fz_try(ctx)
3116
0
    {
3117
0
      pdf_filter_page_contents(ctx, doc, page, &options);
3118
0
      for (annot = pdf_first_annot(ctx, page); annot != NULL; annot = pdf_next_annot(ctx, annot))
3119
0
      {
3120
0
        pdf_filter_annot_contents(ctx, doc, annot, &options);
3121
0
      }
3122
0
    }
3123
0
    fz_always(ctx)
3124
0
      fz_drop_page(ctx, &page->super);
3125
0
    fz_catch(ctx)
3126
0
      fz_rethrow(ctx);
3127
0
  }
3128
0
}
3129
3130
/* Initialise the pdf_write_state, used dynamically during the write, from the static
3131
 * pdf_write_options, passed into pdf_save_document */
3132
static void initialise_write_state(fz_context *ctx, pdf_document *doc, const pdf_write_options *in_opts, pdf_write_state *opts)
3133
0
{
3134
0
  int xref_len = pdf_xref_len(ctx, doc);
3135
3136
0
  opts->do_incremental = in_opts->do_incremental;
3137
0
  opts->do_ascii = in_opts->do_ascii;
3138
0
  opts->do_tight = !in_opts->do_pretty;
3139
0
  opts->do_expand = in_opts->do_decompress;
3140
0
  opts->do_compress = in_opts->do_compress;
3141
0
  opts->do_compress_images = in_opts->do_compress_images;
3142
0
  opts->do_compress_fonts = in_opts->do_compress_fonts;
3143
0
  opts->do_snapshot = in_opts->do_snapshot;
3144
0
  opts->compression_effort = in_opts->compression_effort;
3145
0
  if (opts->compression_effort < 0)
3146
0
    opts->compression_effort = 0;
3147
0
  else if (opts->compression_effort > 100)
3148
0
    opts->compression_effort = 100;
3149
3150
0
  opts->do_garbage = in_opts->do_garbage;
3151
0
  opts->do_linear = in_opts->do_linear;
3152
0
  opts->do_clean = in_opts->do_clean;
3153
0
  opts->do_encrypt = in_opts->do_encrypt;
3154
0
  opts->dont_regenerate_id = in_opts->dont_regenerate_id;
3155
0
  opts->do_preserve_metadata = in_opts->do_preserve_metadata;
3156
0
  opts->do_use_objstms = in_opts->do_use_objstms;
3157
0
  opts->start = 0;
3158
0
  opts->main_xref_offset = INT_MIN;
3159
3160
0
  opts->permissions = in_opts->permissions;
3161
0
  memcpy(opts->opwd_utf8, in_opts->opwd_utf8, nelem(opts->opwd_utf8));
3162
0
  memcpy(opts->upwd_utf8, in_opts->upwd_utf8, nelem(opts->upwd_utf8));
3163
3164
  /* We deliberately make these arrays long enough to cope with
3165
  * 1 to n access rather than 0..n-1, and add space for 2 new
3166
  * extra entries that may be required for linearization. */
3167
0
  opts->list_len = 0;
3168
0
  opts->use_list = NULL;
3169
0
  opts->ofs_list = NULL;
3170
0
  opts->gen_list = NULL;
3171
0
  opts->renumber_map = NULL;
3172
0
  opts->rev_renumber_map = NULL;
3173
3174
0
  expand_lists(ctx, opts, xref_len);
3175
0
}
3176
3177
/* Free the resources held by the dynamic write options */
3178
static void finalise_write_state(fz_context *ctx, pdf_write_state *opts)
3179
0
{
3180
0
  fz_free(ctx, opts->use_list);
3181
0
  fz_free(ctx, opts->ofs_list);
3182
0
  fz_free(ctx, opts->gen_list);
3183
0
  fz_free(ctx, opts->renumber_map);
3184
0
  fz_free(ctx, opts->rev_renumber_map);
3185
0
  pdf_drop_obj(ctx, opts->linear_l);
3186
0
  pdf_drop_obj(ctx, opts->linear_h0);
3187
0
  pdf_drop_obj(ctx, opts->linear_h1);
3188
0
  pdf_drop_obj(ctx, opts->linear_o);
3189
0
  pdf_drop_obj(ctx, opts->linear_e);
3190
0
  pdf_drop_obj(ctx, opts->linear_n);
3191
0
  pdf_drop_obj(ctx, opts->linear_t);
3192
0
  pdf_drop_obj(ctx, opts->hints_s);
3193
0
  pdf_drop_obj(ctx, opts->hints_length);
3194
0
  page_objects_list_destroy(ctx, opts->page_object_lists);
3195
0
}
3196
3197
const pdf_write_options pdf_default_write_options = {
3198
  0, /* do_incremental */
3199
  0, /* do_pretty */
3200
  0, /* do_ascii */
3201
  0, /* do_compress */
3202
  0, /* do_compress_images */
3203
  0, /* do_compress_fonts */
3204
  0, /* do_decompress */
3205
  0, /* do_garbage */
3206
  0, /* do_linear */
3207
  0, /* do_clean */
3208
  0, /* do_sanitize */
3209
  0, /* do_appearance */
3210
  0, /* do_encrypt */
3211
  0, /* dont_regenerate_id */
3212
  ~0, /* permissions */
3213
  "", /* opwd_utf8[128] */
3214
  "", /* upwd_utf8[128] */
3215
  0 /* do_snapshot */
3216
};
3217
3218
static const pdf_write_options pdf_snapshot_write_options = {
3219
  1, /* do_incremental */
3220
  0, /* do_pretty */
3221
  0, /* do_ascii */
3222
  0, /* do_compress */
3223
  0, /* do_compress_images */
3224
  0, /* do_compress_fonts */
3225
  0, /* do_decompress */
3226
  0, /* do_garbage */
3227
  0, /* do_linear */
3228
  0, /* do_clean */
3229
  0, /* do_sanitize */
3230
  0, /* do_appearance */
3231
  0, /* do_encrypt */
3232
  1, /* dont_regenerate_id */
3233
  ~0, /* permissions */
3234
  "", /* opwd_utf8[128] */
3235
  "", /* upwd_utf8[128] */
3236
  1 /* do_snapshot */
3237
};
3238
3239
const char *fz_pdf_write_options_usage =
3240
  "PDF output options:\n"
3241
  "\tdecompress: decompress all streams (except compress-fonts/images)\n"
3242
  "\tcompress: compress all streams\n"
3243
  "\tcompress-fonts: compress embedded fonts\n"
3244
  "\tcompress-images: compress images\n"
3245
  "\tascii: ASCII hex encode binary streams\n"
3246
  "\tpretty: pretty-print objects with indentation\n"
3247
  "\tlinearize: optimize for web browsers\n"
3248
  "\tclean: pretty-print graphics commands in content streams\n"
3249
  "\tsanitize: sanitize graphics commands in content streams\n"
3250
  "\tgarbage: garbage collect unused objects\n"
3251
  "\tincremental: write changes as incremental update\n"
3252
  "\tcontinue-on-error: continue saving the document even if there is an error\n"
3253
  "\tor garbage=compact: ... and compact cross reference table\n"
3254
  "\tor garbage=deduplicate: ... and remove duplicate objects\n"
3255
  "\tdecrypt: write unencrypted document\n"
3256
  "\tencrypt=rc4-40|rc4-128|aes-128|aes-256: write encrypted document\n"
3257
  "\tpermissions=NUMBER: document permissions to grant when encrypting\n"
3258
  "\tuser-password=PASSWORD: password required to read document\n"
3259
  "\towner-password=PASSWORD: password required to edit document\n"
3260
  "\tregenerate-id: (default yes) regenerate document id\n"
3261
  "\n";
3262
3263
pdf_write_options *
3264
pdf_parse_write_options(fz_context *ctx, pdf_write_options *opts, const char *args)
3265
0
{
3266
0
  const char *val;
3267
3268
0
  memset(opts, 0, sizeof *opts);
3269
3270
0
  if (fz_has_option(ctx, args, "decompress", &val))
3271
0
    opts->do_decompress = fz_option_eq(val, "yes");
3272
0
  if (fz_has_option(ctx, args, "compress", &val))
3273
0
    opts->do_compress = fz_option_eq(val, "yes");
3274
0
  if (fz_has_option(ctx, args, "compress-fonts", &val))
3275
0
    opts->do_compress_fonts = fz_option_eq(val, "yes");
3276
0
  if (fz_has_option(ctx, args, "compress-images", &val))
3277
0
    opts->do_compress_images = fz_option_eq(val, "yes");
3278
0
  if (fz_has_option(ctx, args, "compression-effort", &val))
3279
0
    opts->compression_effort = fz_atoi(val);
3280
0
  if (fz_has_option(ctx, args, "ascii", &val))
3281
0
    opts->do_ascii = fz_option_eq(val, "yes");
3282
0
  if (fz_has_option(ctx, args, "pretty", &val))
3283
0
    opts->do_pretty = fz_option_eq(val, "yes");
3284
0
  if (fz_has_option(ctx, args, "linearize", &val))
3285
0
    opts->do_linear = fz_option_eq(val, "yes");
3286
0
  if (fz_has_option(ctx, args, "clean", &val))
3287
0
    opts->do_clean = fz_option_eq(val, "yes");
3288
0
  if (fz_has_option(ctx, args, "sanitize", &val))
3289
0
    opts->do_sanitize = fz_option_eq(val, "yes");
3290
0
  if (fz_has_option(ctx, args, "incremental", &val))
3291
0
    opts->do_incremental = fz_option_eq(val, "yes");
3292
0
  if (fz_has_option(ctx, args, "objstms", &val))
3293
0
    opts->do_use_objstms = fz_option_eq(val, "yes");
3294
0
  if (fz_has_option(ctx, args, "regenerate-id", &val))
3295
0
    opts->dont_regenerate_id = fz_option_eq(val, "no");
3296
0
  if (fz_has_option(ctx, args, "decrypt", &val))
3297
0
    opts->do_encrypt = fz_option_eq(val, "yes") ? PDF_ENCRYPT_NONE : PDF_ENCRYPT_KEEP;
3298
0
  if (fz_has_option(ctx, args, "encrypt", &val))
3299
0
  {
3300
0
    opts->do_encrypt = PDF_ENCRYPT_UNKNOWN;
3301
0
    if (fz_option_eq(val, "none") || fz_option_eq(val, "no"))
3302
0
      opts->do_encrypt = PDF_ENCRYPT_NONE;
3303
0
    if (fz_option_eq(val, "keep"))
3304
0
      opts->do_encrypt = PDF_ENCRYPT_KEEP;
3305
0
    if (fz_option_eq(val, "rc4-40") || fz_option_eq(val, "yes"))
3306
0
      opts->do_encrypt = PDF_ENCRYPT_RC4_40;
3307
0
    if (fz_option_eq(val, "rc4-128"))
3308
0
      opts->do_encrypt = PDF_ENCRYPT_RC4_128;
3309
0
    if (fz_option_eq(val, "aes-128"))
3310
0
      opts->do_encrypt = PDF_ENCRYPT_AES_128;
3311
0
    if (fz_option_eq(val, "aes-256"))
3312
0
      opts->do_encrypt = PDF_ENCRYPT_AES_256;
3313
0
  }
3314
0
  if (fz_has_option(ctx, args, "owner-password", &val))
3315
0
    fz_copy_option(ctx, val, opts->opwd_utf8, nelem(opts->opwd_utf8));
3316
0
  if (fz_has_option(ctx, args, "user-password", &val))
3317
0
    fz_copy_option(ctx, val, opts->upwd_utf8, nelem(opts->upwd_utf8));
3318
0
  if (fz_has_option(ctx, args, "permissions", &val))
3319
0
    opts->permissions = fz_atoi(val);
3320
0
  else
3321
0
    opts->permissions = ~0;
3322
0
  if (fz_has_option(ctx, args, "garbage", &val))
3323
0
  {
3324
0
    if (fz_option_eq(val, "yes"))
3325
0
      opts->do_garbage = 1;
3326
0
    else if (fz_option_eq(val, "compact"))
3327
0
      opts->do_garbage = 2;
3328
0
    else if (fz_option_eq(val, "deduplicate"))
3329
0
      opts->do_garbage = 3;
3330
0
    else
3331
0
      opts->do_garbage = fz_atoi(val);
3332
0
  }
3333
0
  if (fz_has_option(ctx, args, "appearance", &val))
3334
0
  {
3335
0
    if (fz_option_eq(val, "yes"))
3336
0
      opts->do_appearance = 1;
3337
0
    else if (fz_option_eq(val, "all"))
3338
0
      opts->do_appearance = 2;
3339
0
  }
3340
3341
0
  return opts;
3342
0
}
3343
3344
int pdf_can_be_saved_incrementally(fz_context *ctx, pdf_document *doc)
3345
0
{
3346
0
  if (doc->repair_attempted)
3347
0
    return 0;
3348
0
  if (doc->redacted)
3349
0
    return 0;
3350
0
  return 1;
3351
0
}
3352
3353
static void
3354
prepare_for_save(fz_context *ctx, pdf_document *doc, const pdf_write_options *in_opts)
3355
0
{
3356
  /* Rewrite (and possibly sanitize) the operator streams */
3357
0
  if (in_opts->do_clean || in_opts->do_sanitize)
3358
0
  {
3359
0
    pdf_begin_operation(ctx, doc, "Clean content streams");
3360
0
    fz_try(ctx)
3361
0
    {
3362
0
      clean_content_streams(ctx, doc, in_opts->do_sanitize, in_opts->do_ascii, in_opts->do_pretty);
3363
0
      pdf_end_operation(ctx, doc);
3364
0
    }
3365
0
    fz_catch(ctx)
3366
0
    {
3367
0
      pdf_abandon_operation(ctx, doc);
3368
0
      fz_rethrow(ctx);
3369
0
    }
3370
0
  }
3371
3372
  /* When saving a PDF with signatures the file will
3373
  first be written once, then the file will have its
3374
  digests and byte ranges calculated and and then the
3375
  signature dictionary containing them will be updated
3376
  both in memory and in the saved file. By setting this
3377
  flag we avoid a new xref section from being created when
3378
  the signature dictionary is updated. */
3379
0
  doc->save_in_progress = 1;
3380
3381
0
  if (!in_opts->do_snapshot)
3382
0
    presize_unsaved_signature_byteranges(ctx, doc);
3383
0
}
3384
3385
static pdf_obj *
3386
new_identity(fz_context *ctx, pdf_document *doc)
3387
0
{
3388
0
  unsigned char rnd[32];
3389
0
  pdf_obj *id;
3390
3391
0
  fz_memrnd(ctx, rnd, nelem(rnd));
3392
3393
0
  id = pdf_dict_put_array(ctx, pdf_trailer(ctx, doc), PDF_NAME(ID), 2);
3394
0
  pdf_array_push_string(ctx, id, (char *) rnd + 0, nelem(rnd) / 2);
3395
0
  pdf_array_push_string(ctx, id, (char *) rnd + 16, nelem(rnd) / 2);
3396
3397
0
  return id;
3398
0
}
3399
3400
static void
3401
change_identity(fz_context *ctx, pdf_document *doc, pdf_obj *id)
3402
0
{
3403
0
  unsigned char rnd[16];
3404
0
  if (pdf_array_len(ctx, id) >= 2)
3405
0
  {
3406
    /* Update second half of ID array with new random data. */
3407
0
    fz_memrnd(ctx, rnd, 16);
3408
0
    pdf_array_put_string(ctx, id, 1, (char *)rnd, 16);
3409
0
  }
3410
0
}
3411
3412
static void
3413
create_encryption_dictionary(fz_context *ctx, pdf_document *doc, pdf_crypt *crypt)
3414
0
{
3415
0
  unsigned char *o, *u;
3416
0
  pdf_obj *encrypt;
3417
0
  int r;
3418
3419
0
  r = pdf_crypt_revision(ctx, crypt);
3420
3421
0
  encrypt = pdf_dict_put_dict(ctx, pdf_trailer(ctx, doc), PDF_NAME(Encrypt), 10);
3422
3423
0
  pdf_dict_put_name(ctx, encrypt, PDF_NAME(Filter), "Standard");
3424
0
  pdf_dict_put_int(ctx, encrypt, PDF_NAME(R), r);
3425
0
  pdf_dict_put_int(ctx, encrypt, PDF_NAME(V), pdf_crypt_version(ctx, crypt));
3426
0
  pdf_dict_put_int(ctx, encrypt, PDF_NAME(Length), pdf_crypt_length(ctx, crypt));
3427
0
  pdf_dict_put_int(ctx, encrypt, PDF_NAME(P), pdf_crypt_permissions(ctx, crypt));
3428
0
  pdf_dict_put_bool(ctx, encrypt, PDF_NAME(EncryptMetadata), pdf_crypt_encrypt_metadata(ctx, crypt));
3429
3430
0
  o = pdf_crypt_owner_password(ctx, crypt);
3431
0
  u = pdf_crypt_user_password(ctx, crypt);
3432
3433
0
  if (r < 4)
3434
0
  {
3435
0
    pdf_dict_put_string(ctx, encrypt, PDF_NAME(O), (char *) o, 32);
3436
0
    pdf_dict_put_string(ctx, encrypt, PDF_NAME(U), (char *) u, 32);
3437
0
  }
3438
0
  else if (r == 4)
3439
0
  {
3440
0
    pdf_obj *cf;
3441
3442
0
    pdf_dict_put_name(ctx, encrypt, PDF_NAME(StmF), "StdCF");
3443
0
    pdf_dict_put_name(ctx, encrypt, PDF_NAME(StrF), "StdCF");
3444
3445
0
    cf = pdf_dict_put_dict(ctx, encrypt, PDF_NAME(CF), 1);
3446
0
    cf = pdf_dict_put_dict(ctx, cf, PDF_NAME(StdCF), 3);
3447
0
    pdf_dict_put_name(ctx, cf, PDF_NAME(AuthEvent), "DocOpen");
3448
0
    pdf_dict_put_name(ctx, cf, PDF_NAME(CFM), "AESV2");
3449
0
    pdf_dict_put_int(ctx, cf, PDF_NAME(Length), 16);
3450
0
    pdf_dict_put_string(ctx, encrypt, PDF_NAME(O), (char *) o, 32);
3451
0
    pdf_dict_put_string(ctx, encrypt, PDF_NAME(U), (char *) u, 32);
3452
0
  }
3453
0
  else if (r == 6)
3454
0
  {
3455
0
    unsigned char *oe = pdf_crypt_owner_encryption(ctx, crypt);
3456
0
    unsigned char *ue = pdf_crypt_user_encryption(ctx, crypt);
3457
0
    pdf_obj *cf;
3458
3459
0
    pdf_dict_put_name(ctx, encrypt, PDF_NAME(StmF), "StdCF");
3460
0
    pdf_dict_put_name(ctx, encrypt, PDF_NAME(StrF), "StdCF");
3461
3462
0
    cf = pdf_dict_put_dict(ctx, encrypt, PDF_NAME(CF), 1);
3463
0
    cf = pdf_dict_put_dict(ctx, cf, PDF_NAME(StdCF), 3);
3464
0
    pdf_dict_put_name(ctx, cf, PDF_NAME(AuthEvent), "DocOpen");
3465
0
    pdf_dict_put_name(ctx, cf, PDF_NAME(CFM), "AESV3");
3466
0
    pdf_dict_put_int(ctx, cf, PDF_NAME(Length), 32);
3467
0
    pdf_dict_put_string(ctx, encrypt, PDF_NAME(O), (char *) o, 48);
3468
0
    pdf_dict_put_string(ctx, encrypt, PDF_NAME(U), (char *) u, 48);
3469
0
    pdf_dict_put_string(ctx, encrypt, PDF_NAME(OE), (char *) oe, 32);
3470
0
    pdf_dict_put_string(ctx, encrypt, PDF_NAME(UE), (char *) ue, 32);
3471
0
    pdf_dict_put_string(ctx, encrypt, PDF_NAME(Perms), (char *) pdf_crypt_permissions_encryption(ctx, crypt), 16);
3472
0
  }
3473
0
}
3474
3475
static void
3476
ensure_initial_incremental_contents(fz_context *ctx, fz_stream *in, fz_output *out, int64_t len)
3477
0
{
3478
0
  fz_stream *verify;
3479
0
  unsigned char buf0[4096];
3480
0
  unsigned char buf1[4096];
3481
0
  size_t n0, n1;
3482
0
  int64_t off = 0;
3483
0
  int same;
3484
3485
0
  if (!in)
3486
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "no input file for incremental write");
3487
3488
0
  verify = fz_stream_from_output(ctx, out);
3489
3490
0
  fz_try(ctx)
3491
0
  {
3492
    /* Compare current contents of output file (in case we append) */
3493
0
    if (verify)
3494
0
    {
3495
0
      do
3496
0
      {
3497
0
        int64_t read = sizeof(buf0);
3498
0
        if (off + read > len)
3499
0
          read = len - off;
3500
0
        fz_seek(ctx, in, off, SEEK_SET);
3501
0
        n0 = fz_read(ctx, in, buf0, read);
3502
0
        fz_seek(ctx, verify, off, SEEK_SET);
3503
0
        n1 = fz_read(ctx, verify, buf1, read);
3504
0
        same = (n0 == n1 && !memcmp(buf0, buf1, n0));
3505
0
        off += (int64_t)n0;
3506
0
      }
3507
0
      while (same && n0 > 0 && off < len);
3508
3509
0
      if (same)
3510
0
      {
3511
0
        fz_seek_output(ctx, out, len, SEEK_SET);
3512
0
        fz_truncate_output(ctx, out);
3513
0
        break; /* return from try */
3514
0
      }
3515
3516
0
      fz_seek_output(ctx, out, 0, SEEK_SET);
3517
0
    }
3518
3519
    /* Copy old contents into new file */
3520
0
    fz_seek(ctx, in, 0, SEEK_SET);
3521
0
    off = 0;
3522
0
    do
3523
0
    {
3524
0
      int64_t read = sizeof(buf0);
3525
0
      if (off + read > len)
3526
0
        read = len - off;
3527
0
      n0 = fz_read(ctx, in, buf0, read);
3528
0
      if (n0)
3529
0
        fz_write_data(ctx, out, buf0, n0);
3530
0
      off += n0;
3531
0
    }
3532
0
    while (n0 > 0 && off < len);
3533
3534
0
    if (verify)
3535
0
    {
3536
0
      fz_truncate_output(ctx, out);
3537
0
      fz_seek_output(ctx, out, 0, SEEK_END);
3538
0
    }
3539
0
  }
3540
0
  fz_always(ctx)
3541
0
    fz_drop_stream(ctx, verify);
3542
0
  fz_catch(ctx)
3543
0
    fz_rethrow(ctx);
3544
0
}
3545
3546
0
#define OBJSTM_MAXOBJS 256
3547
0
#define OBJSTM_MAXLEN 1<<24
3548
3549
typedef struct
3550
{
3551
  pdf_write_state *opts;
3552
  int n;
3553
  int objnum[OBJSTM_MAXOBJS];
3554
  size_t len[OBJSTM_MAXOBJS];
3555
  fz_buffer *content_buf;
3556
  fz_output *content_out;
3557
  int root_num;
3558
  int info_num;
3559
  int sep;
3560
} objstm_gather_data;
3561
3562
static void
3563
flush_gathered(fz_context *ctx, pdf_document *doc, objstm_gather_data *data)
3564
0
{
3565
0
  pdf_obj *obj;
3566
0
  pdf_obj *ref = NULL;
3567
0
  fz_buffer *newbuf = NULL;
3568
0
  fz_output *out = NULL;
3569
0
  int i;
3570
3571
0
  if (data->n == 0)
3572
0
    return;
3573
3574
0
  obj = pdf_new_dict(ctx, doc, 4);
3575
3576
0
  fz_var(ref);
3577
0
  fz_var(newbuf);
3578
0
  fz_var(out);
3579
3580
0
  fz_try(ctx)
3581
0
  {
3582
0
    size_t pos = 0, first;
3583
0
    int num;
3584
0
    newbuf = fz_new_buffer(ctx, 128);
3585
3586
0
    out = fz_new_output_with_buffer(ctx, newbuf);
3587
3588
0
    for (i = 0; i < data->n; i++)
3589
0
    {
3590
0
      fz_write_printf(ctx, out, "%d %d ", data->objnum[i], pos);
3591
0
      pos += data->len[i];
3592
0
    }
3593
3594
0
    fz_close_output(ctx, out);
3595
0
    first = fz_tell_output(ctx, out);
3596
0
    fz_drop_output(ctx, out);
3597
0
    out = NULL;
3598
3599
0
    pdf_dict_put_int(ctx, obj, PDF_NAME(First), first);
3600
0
    pdf_dict_put_int(ctx, obj, PDF_NAME(N), data->n);
3601
0
    pdf_dict_put(ctx, obj, PDF_NAME(Type), PDF_NAME(ObjStm));
3602
3603
0
    fz_close_output(ctx, data->content_out);
3604
0
    fz_append_buffer(ctx, newbuf, data->content_buf);
3605
3606
0
    doc->xref_base = 0; /* Might have been reset by our caller */
3607
0
    ref = pdf_add_object(ctx, doc, obj);
3608
0
    pdf_update_stream(ctx, doc, ref, newbuf, 0);
3609
3610
0
    num = pdf_to_num(ctx, ref);
3611
0
    expand_lists(ctx, data->opts, num);
3612
0
    data->opts->use_list[num] = 1;
3613
3614
    /* Update all the xref entries for the objects to point into this stream. */
3615
0
    for (i = 0; i < data->n; i++)
3616
0
    {
3617
0
      pdf_xref_entry *x = pdf_get_xref_entry_no_null(ctx, doc, data->objnum[i]);
3618
0
      x->ofs = num; /* ofs = which objstm is this in */
3619
0
      x->gen = i; /* gen = nth entry in the objstm */
3620
0
      data->opts->ofs_list[data->objnum[i]] = i;
3621
0
      data->opts->gen_list[data->objnum[i]] = i;
3622
0
    }
3623
3624
0
    data->n = 0;
3625
0
    data->sep = 0;
3626
0
  }
3627
0
  fz_always(ctx)
3628
0
  {
3629
0
    fz_drop_output(ctx, data->content_out);
3630
0
    data->content_out = NULL;
3631
0
    fz_drop_buffer(ctx, data->content_buf);
3632
0
    data->content_buf = NULL;
3633
0
    pdf_drop_obj(ctx, obj);
3634
0
    pdf_drop_obj(ctx, ref);
3635
0
    fz_drop_buffer(ctx, newbuf);
3636
0
    fz_drop_output(ctx, out);
3637
0
  }
3638
0
  fz_catch(ctx)
3639
0
    fz_rethrow(ctx);
3640
0
}
3641
3642
static void
3643
objstm_gather(fz_context *ctx, pdf_xref_entry *x, int i, pdf_document *doc, void *arg)
3644
0
{
3645
0
  size_t olen, len;
3646
0
  objstm_gather_data *data = (objstm_gather_data *)arg;
3647
3648
  /* If we are writing incrementally, then only the last one can be gathered. */
3649
0
  if (data->opts->do_incremental && doc->xref_base != 0)
3650
0
    return;
3651
3652
0
  if (i == data->root_num || i == data->info_num)
3653
0
    return;
3654
3655
  /* Ensure the object is loaded! */
3656
0
  if (i == 0)
3657
0
    return; /* pdf_cache_object does not like being called for i == 0 which should be free. */
3658
0
  pdf_cache_object(ctx, doc, i);
3659
3660
0
  if (x->type != 'n' || x->stm_buf != NULL || x->stm_ofs != 0 || x->gen != 0)
3661
0
    return; /* Ineligible for using an objstm */
3662
3663
  /* FIXME: Can we do a pass through to check for such objects more exactly? */
3664
0
  if (pdf_is_int(ctx, x->obj))
3665
0
    return; /* In case it's a Length value. */
3666
0
  if (pdf_is_indirect(ctx, x->obj))
3667
0
    return; /* Bare indirect references are not allowed. */
3668
0
  if (data->opts->do_linear && pdf_is_dict(ctx, x->obj))
3669
0
  {
3670
0
    pdf_obj *type = pdf_dict_get(ctx, x->obj, PDF_NAME(Type));
3671
0
    if (pdf_name_eq(ctx, type, PDF_NAME(Pages)) ||
3672
0
      pdf_name_eq(ctx, type, PDF_NAME(Page)))
3673
0
      return;
3674
0
  }
3675
3676
0
  if (data->content_buf == NULL)
3677
0
    data->content_buf = fz_new_buffer(ctx, 128);
3678
0
  if (data->content_out == NULL)
3679
0
    data->content_out = fz_new_output_with_buffer(ctx, data->content_buf);
3680
3681
0
  olen = data->content_buf->len;
3682
0
  pdf_print_encrypted_obj(ctx, data->content_out, x->obj, 1, 0, NULL, 0, 0, NULL);
3683
0
  data->objnum[data->n] = i;
3684
0
  len = data->content_buf->len;
3685
0
  data->len[data->n] = len - olen;
3686
0
  x->type = 'o';
3687
0
  x->gen = data->n;
3688
0
  data->n++;
3689
0
  if (data->n == OBJSTM_MAXOBJS || len > OBJSTM_MAXLEN)
3690
0
    flush_gathered(ctx, doc, data);
3691
0
}
3692
3693
static void
3694
gather_to_objstms(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, int xref_len)
3695
0
{
3696
0
  objstm_gather_data data = { 0 };
3697
3698
0
  data.opts = opts;
3699
0
  data.root_num = pdf_to_num(ctx, pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root)));
3700
0
  data.info_num = pdf_to_num(ctx, pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Info)));
3701
3702
0
  pdf_xref_entry_map(ctx, doc, objstm_gather, &data);
3703
0
  flush_gathered(ctx, doc, &data);
3704
0
}
3705
3706
static void
3707
do_pdf_save_document(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, const pdf_write_options *in_opts)
3708
0
{
3709
0
  int lastfree;
3710
0
  int num;
3711
0
  int xref_len;
3712
0
  pdf_obj *id1, *id = NULL;
3713
3714
0
  if (in_opts->do_incremental)
3715
0
  {
3716
0
    ensure_initial_incremental_contents(ctx, doc->file, opts->out, doc->file_size);
3717
3718
    /* If no changes, nothing more to write */
3719
0
    if (!pdf_has_unsaved_changes(ctx, doc))
3720
0
    {
3721
0
      doc->save_in_progress = 0;
3722
0
      return;
3723
0
    }
3724
3725
0
    fz_write_string(ctx, opts->out, "\n");
3726
0
  }
3727
3728
0
  xref_len = pdf_xref_len(ctx, doc);
3729
3730
0
  pdf_begin_operation(ctx, doc, "Save document");
3731
0
  fz_try(ctx)
3732
0
  {
3733
0
    initialise_write_state(ctx, doc, in_opts, opts);
3734
3735
0
    if (!opts->dont_regenerate_id)
3736
0
    {
3737
      /* Update second half of ID array if it exists. */
3738
0
      id = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(ID));
3739
0
      if (id)
3740
0
        change_identity(ctx, doc, id);
3741
0
    }
3742
3743
    /* Remove encryption dictionary if saving without encryption. */
3744
0
    if (opts->do_encrypt == PDF_ENCRYPT_NONE)
3745
0
    {
3746
0
      assert(!in_opts->do_snapshot);
3747
0
      pdf_dict_del(ctx, pdf_trailer(ctx, doc), PDF_NAME(Encrypt));
3748
0
    }
3749
3750
    /* Keep encryption dictionary if saving with old encryption. */
3751
0
    else if (opts->do_encrypt == PDF_ENCRYPT_KEEP)
3752
0
    {
3753
0
      opts->crypt = doc->crypt;
3754
0
    }
3755
3756
    /* Create encryption dictionary if saving with new encryption. */
3757
0
    else
3758
0
    {
3759
0
      assert(!opts->do_snapshot);
3760
0
      if (!id)
3761
0
        id = new_identity(ctx, doc);
3762
0
      id1 = pdf_array_get(ctx, id, 0);
3763
0
      opts->crypt = pdf_new_encrypt(ctx, opts->opwd_utf8, opts->upwd_utf8, id1, opts->permissions, opts->do_encrypt);
3764
0
      create_encryption_dictionary(ctx, doc, opts->crypt);
3765
0
    }
3766
3767
    /* Stash Encrypt entry in the writer state, in case a repair pass throws away the old trailer. */
3768
0
    opts->crypt_obj = pdf_keep_obj(ctx, pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Encrypt)));
3769
3770
    /* If we're writing a snapshot, we can't be doing garbage
3771
     * collection, or linearisation, and must be writing
3772
     * incrementally. */
3773
0
    assert(!opts->do_snapshot || (opts->do_garbage == 0 && !opts->do_linear));
3774
3775
    /* Make sure any objects hidden in compressed streams have been loaded */
3776
0
    if (!opts->do_incremental)
3777
0
    {
3778
0
      pdf_ensure_solid_xref(ctx, doc, xref_len);
3779
0
      preloadobjstms(ctx, doc);
3780
0
    }
3781
3782
    /* If we're using objstms, then the version must be at least 1.5 */
3783
0
    if (opts->do_use_objstms && pdf_version(ctx, doc) < 15)
3784
0
    {
3785
0
      pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root));
3786
0
      pdf_obj *version = pdf_dict_get(ctx, root, PDF_NAME(Version));
3787
0
      doc->version = 15;
3788
0
      if (opts->do_incremental || version != NULL)
3789
0
      {
3790
0
        pdf_dict_put(ctx, root, PDF_NAME(Version), PDF_NAME(1_5));
3791
0
      }
3792
0
    }
3793
3794
0
    if (opts->do_preserve_metadata)
3795
0
      opts->metadata = pdf_keep_obj(ctx, pdf_metadata(ctx, doc));
3796
3797
0
    xref_len = pdf_xref_len(ctx, doc); /* May have changed due to repair */
3798
0
    expand_lists(ctx, opts, xref_len);
3799
3800
    /* Sweep & mark objects from the trailer */
3801
0
    if (opts->do_garbage >= 1 || opts->do_linear)
3802
0
      (void)markobj(ctx, doc, opts, pdf_trailer(ctx, doc));
3803
0
    else
3804
0
      for (num = 0; num < xref_len; num++)
3805
0
        opts->use_list[num] = 1;
3806
3807
    /* Coalesce and renumber duplicate objects */
3808
0
    if (opts->do_garbage >= 3)
3809
0
      removeduplicateobjs(ctx, doc, opts);
3810
3811
    /* Compact xref by renumbering and removing unused objects */
3812
0
    if (opts->do_garbage >= 2 || opts->do_linear)
3813
0
      compactxref(ctx, doc, opts);
3814
3815
0
    opts->crypt_object_number = 0;
3816
0
    if (opts->crypt)
3817
0
    {
3818
0
      pdf_obj *crypt = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Encrypt));
3819
0
      int crypt_num = pdf_to_num(ctx, crypt);
3820
0
      opts->crypt_object_number = opts->renumber_map[crypt_num];
3821
0
    }
3822
3823
    /* Make renumbering affect all indirect references and update xref */
3824
0
    if (opts->do_garbage >= 2 || opts->do_linear)
3825
0
      renumberobjs(ctx, doc, opts);
3826
3827
0
    if (opts->do_use_objstms)
3828
0
      gather_to_objstms(ctx, doc, opts, xref_len);
3829
3830
0
    xref_len = pdf_xref_len(ctx, doc); /* May have changed due to repair */
3831
0
    expand_lists(ctx, opts, xref_len);
3832
3833
    /* Truncate the xref after compacting and renumbering */
3834
0
    if ((opts->do_garbage >= 2 || opts->do_linear) &&
3835
0
      !opts->do_incremental)
3836
0
    {
3837
0
      while (xref_len > 0 && !opts->use_list[xref_len-1])
3838
0
        xref_len--;
3839
0
    }
3840
3841
0
    if (opts->do_linear)
3842
0
      linearize(ctx, doc, opts);
3843
3844
0
    if (opts->do_incremental)
3845
0
    {
3846
0
      int i;
3847
3848
0
      doc->disallow_new_increments = 1;
3849
3850
0
      for (i = 0; i < doc->num_incremental_sections; i++)
3851
0
      {
3852
0
        doc->xref_base = doc->num_incremental_sections - i - 1;
3853
0
        xref_len = pdf_xref_len(ctx, doc);
3854
3855
0
        writeobjects(ctx, doc, opts, 0);
3856
3857
#ifdef DEBUG_WRITING
3858
        dump_object_details(ctx, doc, opts);
3859
#endif
3860
3861
0
        for (num = 0; num < xref_len; num++)
3862
0
        {
3863
0
          if (!opts->use_list[num] && pdf_xref_is_incremental(ctx, doc, num))
3864
0
          {
3865
            /* Make unreusable. FIXME: would be better to link to existing free list */
3866
0
            opts->gen_list[num] = 65535;
3867
0
            opts->ofs_list[num] = 0;
3868
0
          }
3869
0
        }
3870
3871
0
        opts->first_xref_offset = fz_tell_output(ctx, opts->out);
3872
0
        if (!doc->last_xref_was_old_style || opts->do_use_objstms)
3873
0
          writexrefstream(ctx, doc, opts, 0, xref_len, 1, 0, opts->first_xref_offset);
3874
0
        else
3875
0
          writexref(ctx, doc, opts, 0, xref_len, 1, 0, opts->first_xref_offset);
3876
3877
0
        doc->xref_sections[doc->xref_base].end_ofs = fz_tell_output(ctx, opts->out);
3878
0
      }
3879
3880
0
      doc->xref_base = 0;
3881
0
      doc->disallow_new_increments = 0;
3882
0
    }
3883
0
    else
3884
0
    {
3885
0
      writeobjects(ctx, doc, opts, 0);
3886
3887
#ifdef DEBUG_WRITING
3888
      dump_object_details(ctx, doc, opts);
3889
#endif
3890
3891
      /* Construct linked list of free object slots */
3892
0
      lastfree = 0;
3893
0
      for (num = 0; num < xref_len; num++)
3894
0
      {
3895
0
        if (!opts->use_list[num])
3896
0
        {
3897
0
          opts->gen_list[num]++;
3898
0
          opts->ofs_list[lastfree] = num;
3899
0
          lastfree = num;
3900
0
        }
3901
0
      }
3902
3903
0
      if (opts->do_linear && opts->page_count > 0)
3904
0
      {
3905
0
        opts->main_xref_offset = fz_tell_output(ctx, opts->out);
3906
0
        writexref(ctx, doc, opts, 0, opts->start, 0, 0, opts->first_xref_offset);
3907
0
        opts->file_len = fz_tell_output(ctx, opts->out);
3908
3909
0
        make_hint_stream(ctx, doc, opts);
3910
0
        if (opts->do_ascii)
3911
0
        {
3912
0
          opts->hintstream_len *= 2;
3913
0
          opts->hintstream_len += 1 + ((opts->hintstream_len+63)>>6);
3914
0
        }
3915
0
        opts->file_len += opts->hintstream_len;
3916
0
        opts->main_xref_offset += opts->hintstream_len;
3917
0
        update_linearization_params(ctx, doc, opts);
3918
0
        fz_seek_output(ctx, opts->out, 0, 0);
3919
0
        writeobjects(ctx, doc, opts, 1);
3920
3921
0
        padto(ctx, opts->out, opts->main_xref_offset);
3922
0
        if (opts->do_use_objstms)
3923
0
          writexrefstream(ctx, doc, opts, 0, xref_len, 1, 0, opts->first_xref_offset);
3924
0
        else
3925
0
          writexref(ctx, doc, opts, 0, opts->start, 0, 0, opts->first_xref_offset);
3926
0
      }
3927
0
      else
3928
0
      {
3929
0
        opts->first_xref_offset = fz_tell_output(ctx, opts->out);
3930
0
        if (opts->do_use_objstms)
3931
0
          writexrefstream(ctx, doc, opts, 0, xref_len, 1, 0, opts->first_xref_offset);
3932
0
        else
3933
0
          writexref(ctx, doc, opts, 0, xref_len, 1, 0, opts->first_xref_offset);
3934
0
      }
3935
3936
0
      doc->xref_sections[0].end_ofs = fz_tell_output(ctx, opts->out);
3937
0
    }
3938
3939
0
    if (!in_opts->do_snapshot)
3940
0
    {
3941
0
      complete_signatures(ctx, doc, opts);
3942
0
    }
3943
0
    pdf_end_operation(ctx, doc);
3944
0
  }
3945
0
  fz_always(ctx)
3946
0
  {
3947
#ifdef DEBUG_LINEARIZATION
3948
    page_objects_dump(opts);
3949
    objects_dump(ctx, doc, opts);
3950
#endif
3951
0
    finalise_write_state(ctx, opts);
3952
0
    if (opts->crypt != doc->crypt)
3953
0
      pdf_drop_crypt(ctx, opts->crypt);
3954
0
    pdf_drop_obj(ctx, opts->crypt_obj);
3955
0
    pdf_drop_obj(ctx, opts->metadata);
3956
0
    doc->save_in_progress = 0;
3957
0
  }
3958
0
  fz_catch(ctx)
3959
0
  {
3960
0
    pdf_abandon_operation(ctx, doc);
3961
0
    fz_rethrow(ctx);
3962
0
  }
3963
0
}
3964
3965
int pdf_has_unsaved_sigs(fz_context *ctx, pdf_document *doc)
3966
0
{
3967
0
  int s;
3968
0
  for (s = 0; s < doc->num_incremental_sections; s++)
3969
0
  {
3970
0
    pdf_xref *xref = &doc->xref_sections[doc->num_incremental_sections - s - 1];
3971
3972
0
    if (xref->unsaved_sigs)
3973
0
      return 1;
3974
0
  }
3975
0
  return 0;
3976
0
}
3977
3978
void pdf_write_document(fz_context *ctx, pdf_document *doc, fz_output *out, const pdf_write_options *in_opts)
3979
0
{
3980
0
  pdf_write_options opts_defaults = pdf_default_write_options;
3981
0
  pdf_write_state opts = { 0 };
3982
3983
0
  if (!doc || !out)
3984
0
    return;
3985
3986
0
  if (!in_opts)
3987
0
    in_opts = &opts_defaults;
3988
3989
0
  if (in_opts->do_incremental && doc->repair_attempted)
3990
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't do incremental writes on a repaired file");
3991
0
  if (in_opts->do_incremental && in_opts->do_garbage)
3992
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't do incremental writes with garbage collection");
3993
0
  if (in_opts->do_incremental && in_opts->do_linear)
3994
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't do incremental writes with linearisation");
3995
0
  if (in_opts->do_incremental && in_opts->do_encrypt != PDF_ENCRYPT_KEEP)
3996
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't do incremental writes when changing encryption");
3997
0
  if (in_opts->do_snapshot)
3998
0
  {
3999
0
    if (in_opts->do_incremental == 0 ||
4000
0
      in_opts->do_pretty ||
4001
0
      in_opts->do_ascii ||
4002
0
      in_opts->do_compress ||
4003
0
      in_opts->do_compress_images ||
4004
0
      in_opts->do_compress_fonts ||
4005
0
      in_opts->do_decompress ||
4006
0
      in_opts->do_garbage ||
4007
0
      in_opts->do_linear ||
4008
0
      in_opts->do_clean ||
4009
0
      in_opts->do_sanitize ||
4010
0
      in_opts->do_appearance ||
4011
0
      in_opts->do_encrypt != PDF_ENCRYPT_KEEP)
4012
0
      fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't use these options when snapshotting!");
4013
0
  }
4014
0
  if (pdf_has_unsaved_sigs(ctx, doc) && !fz_output_supports_stream(ctx, out))
4015
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't write pdf that has unsaved sigs to a fz_output unless it supports fz_stream_from_output!");
4016
4017
0
  prepare_for_save(ctx, doc, in_opts);
4018
4019
0
  opts.out = out;
4020
4021
0
  do_pdf_save_document(ctx, doc, &opts, in_opts);
4022
0
}
4023
4024
void pdf_save_document(fz_context *ctx, pdf_document *doc, const char *filename, const pdf_write_options *in_opts)
4025
0
{
4026
0
  pdf_write_options opts_defaults = pdf_default_write_options;
4027
0
  pdf_write_state opts = { 0 };
4028
4029
0
  if (!doc)
4030
0
    return;
4031
4032
0
  if (!in_opts)
4033
0
    in_opts = &opts_defaults;
4034
4035
0
  if (in_opts->do_incremental && !doc->file)
4036
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't do incremental writes on a new document");
4037
0
  if (in_opts->do_incremental && doc->repair_attempted)
4038
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't do incremental writes on a repaired file");
4039
0
  if (in_opts->do_incremental && in_opts->do_garbage)
4040
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't do incremental writes with garbage collection");
4041
0
  if (in_opts->do_incremental && in_opts->do_linear)
4042
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't do incremental writes with linearisation");
4043
0
  if (in_opts->do_incremental && in_opts->do_encrypt != PDF_ENCRYPT_KEEP)
4044
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't do incremental writes when changing encryption");
4045
0
  if (in_opts->do_snapshot)
4046
0
  {
4047
0
    if (in_opts->do_incremental == 0 ||
4048
0
      in_opts->do_pretty ||
4049
0
      in_opts->do_ascii ||
4050
0
      in_opts->do_compress ||
4051
0
      in_opts->do_compress_images ||
4052
0
      in_opts->do_compress_fonts ||
4053
0
      in_opts->do_decompress ||
4054
0
      in_opts->do_garbage ||
4055
0
      in_opts->do_linear ||
4056
0
      in_opts->do_clean ||
4057
0
      in_opts->do_sanitize ||
4058
0
      in_opts->do_appearance ||
4059
0
      in_opts->do_encrypt != PDF_ENCRYPT_KEEP)
4060
0
      fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't use these options when snapshotting!");
4061
0
  }
4062
4063
0
  if (in_opts->do_appearance > 0)
4064
0
  {
4065
0
    int i, n = pdf_count_pages(ctx, doc);
4066
0
    for (i = 0; i < n; ++i)
4067
0
    {
4068
0
      pdf_page *page = pdf_load_page(ctx, doc, i);
4069
0
      fz_try(ctx)
4070
0
      {
4071
0
        pdf_annot *annot;
4072
0
        for (annot = pdf_first_annot(ctx, page); annot; annot = pdf_next_annot(ctx, annot))
4073
0
          if (in_opts->do_appearance > 1)
4074
0
            pdf_annot_request_resynthesis(ctx, annot);
4075
0
          else
4076
0
            pdf_annot_request_synthesis(ctx, annot);
4077
0
        for (annot = pdf_first_widget(ctx, page); annot; annot = pdf_next_widget(ctx, annot))
4078
0
          if (in_opts->do_appearance > 1)
4079
0
            pdf_annot_request_resynthesis(ctx, annot);
4080
0
          else
4081
0
            pdf_annot_request_synthesis(ctx, annot);
4082
0
        pdf_update_page(ctx, page);
4083
0
      }
4084
0
      fz_always(ctx)
4085
0
        fz_drop_page(ctx, &page->super);
4086
0
      fz_catch(ctx)
4087
0
        fz_warn(ctx, "could not create annotation appearances");
4088
0
    }
4089
0
  }
4090
4091
0
  prepare_for_save(ctx, doc, in_opts);
4092
4093
0
  if (in_opts->do_incremental)
4094
0
  {
4095
0
    opts.out = fz_new_output_with_path(ctx, filename, 1);
4096
0
  }
4097
0
  else
4098
0
  {
4099
0
    opts.out = fz_new_output_with_path(ctx, filename, 0);
4100
0
  }
4101
0
  fz_try(ctx)
4102
0
  {
4103
0
    do_pdf_save_document(ctx, doc, &opts, in_opts);
4104
0
    fz_close_output(ctx, opts.out);
4105
0
  }
4106
0
  fz_always(ctx)
4107
0
  {
4108
0
    fz_drop_output(ctx, opts.out);
4109
0
    opts.out = NULL;
4110
0
  }
4111
0
  fz_catch(ctx)
4112
0
  {
4113
0
    fz_rethrow(ctx);
4114
0
  }
4115
0
}
4116
4117
void pdf_save_snapshot(fz_context *ctx, pdf_document *doc, const char *filename)
4118
0
{
4119
0
  pdf_save_document(ctx, doc, filename, &pdf_snapshot_write_options);
4120
0
}
4121
4122
void pdf_write_snapshot(fz_context *ctx, pdf_document *doc, fz_output *out)
4123
0
{
4124
0
  pdf_write_document(ctx, doc, out, &pdf_snapshot_write_options);
4125
0
}
4126
4127
char *
4128
pdf_format_write_options(fz_context *ctx, char *buffer, size_t buffer_len, const pdf_write_options *opts)
4129
0
{
4130
0
#define ADD_OPT(S) do { if (!first) fz_strlcat(buffer, ",", buffer_len); fz_strlcat(buffer, (S), buffer_len); first = 0; } while (0)
4131
4132
0
  int first = 1;
4133
0
  *buffer = 0;
4134
0
  if (opts->do_decompress)
4135
0
    ADD_OPT("decompress=yes");
4136
0
  if (opts->do_compress)
4137
0
    ADD_OPT("compress=yes");
4138
0
  if (opts->do_compress_fonts)
4139
0
    ADD_OPT("compress-fonts=yes");
4140
0
  if (opts->do_compress_images)
4141
0
    ADD_OPT("compress-images=yes");
4142
0
  if (opts->do_ascii)
4143
0
    ADD_OPT("ascii=yes");
4144
0
  if (opts->do_pretty)
4145
0
    ADD_OPT("pretty=yes");
4146
0
  if (opts->do_linear)
4147
0
    ADD_OPT("linearize=yes");
4148
0
  if (opts->do_clean)
4149
0
    ADD_OPT("clean=yes");
4150
0
  if (opts->do_sanitize)
4151
0
    ADD_OPT("sanitize=yes");
4152
0
  if (opts->do_incremental)
4153
0
    ADD_OPT("incremental=yes");
4154
0
  if (opts->do_encrypt == PDF_ENCRYPT_NONE)
4155
0
    ADD_OPT("decrypt=yes");
4156
0
  else if (opts->do_encrypt == PDF_ENCRYPT_KEEP)
4157
0
    ADD_OPT("decrypt=no");
4158
0
  switch(opts->do_encrypt)
4159
0
  {
4160
0
  default:
4161
0
  case PDF_ENCRYPT_UNKNOWN:
4162
0
    break;
4163
0
  case PDF_ENCRYPT_NONE:
4164
0
    ADD_OPT("encrypt=no");
4165
0
    break;
4166
0
  case PDF_ENCRYPT_KEEP:
4167
0
    ADD_OPT("encrypt=keep");
4168
0
    break;
4169
0
  case PDF_ENCRYPT_RC4_40:
4170
0
    ADD_OPT("encrypt=rc4-40");
4171
0
    break;
4172
0
  case PDF_ENCRYPT_RC4_128:
4173
0
    ADD_OPT("encrypt=rc4-128");
4174
0
    break;
4175
0
  case PDF_ENCRYPT_AES_128:
4176
0
    ADD_OPT("encrypt=aes-128");
4177
0
    break;
4178
0
  case PDF_ENCRYPT_AES_256:
4179
0
    ADD_OPT("encrypt=aes-256");
4180
0
    break;
4181
0
  }
4182
0
  if (strlen(opts->opwd_utf8)) {
4183
0
    ADD_OPT("owner-password=");
4184
0
    fz_strlcat(buffer, opts->opwd_utf8, buffer_len);
4185
0
  }
4186
0
  if (strlen(opts->upwd_utf8)) {
4187
0
    ADD_OPT("user-password=");
4188
0
    fz_strlcat(buffer, opts->upwd_utf8, buffer_len);
4189
0
  }
4190
0
  {
4191
0
    char temp[32];
4192
0
    ADD_OPT("permissions=");
4193
0
    fz_snprintf(temp, sizeof(temp), "%d", opts->permissions);
4194
0
    fz_strlcat(buffer, temp, buffer_len);
4195
0
  }
4196
0
  switch(opts->do_garbage)
4197
0
  {
4198
0
  case 0:
4199
0
    break;
4200
0
  case 1:
4201
0
    ADD_OPT("garbage=yes");
4202
0
    break;
4203
0
  case 2:
4204
0
    ADD_OPT("garbage=compact");
4205
0
    break;
4206
0
  case 3:
4207
0
    ADD_OPT("garbage=deduplicate");
4208
0
    break;
4209
0
  default:
4210
0
  {
4211
0
    char temp[32];
4212
0
    fz_snprintf(temp, sizeof(temp), "%d", opts->do_garbage);
4213
0
    ADD_OPT("garbage=");
4214
0
    fz_strlcat(buffer, temp, buffer_len);
4215
0
    break;
4216
0
  }
4217
0
  }
4218
0
  switch(opts->do_appearance)
4219
0
  {
4220
0
  case 1:
4221
0
    ADD_OPT("appearance=yes");
4222
0
    break;
4223
0
  case 2:
4224
0
    ADD_OPT("appearance=all");
4225
0
    break;
4226
0
  }
4227
4228
0
#undef ADD_OPT
4229
4230
0
  return buffer;
4231
0
}
4232
4233
typedef struct
4234
{
4235
  fz_document_writer super;
4236
  pdf_document *pdf;
4237
  pdf_write_options opts;
4238
  fz_output *out;
4239
4240
  fz_rect mediabox;
4241
  pdf_obj *resources;
4242
  fz_buffer *contents;
4243
} pdf_writer;
4244
4245
static fz_device *
4246
pdf_writer_begin_page(fz_context *ctx, fz_document_writer *wri_, fz_rect mediabox)
4247
0
{
4248
0
  pdf_writer *wri = (pdf_writer*)wri_;
4249
0
  wri->mediabox = mediabox; // TODO: handle non-zero x0,y0
4250
0
  return pdf_page_write(ctx, wri->pdf, wri->mediabox, &wri->resources, &wri->contents);
4251
0
}
4252
4253
static void
4254
pdf_writer_end_page(fz_context *ctx, fz_document_writer *wri_, fz_device *dev)
4255
0
{
4256
0
  pdf_writer *wri = (pdf_writer*)wri_;
4257
0
  pdf_obj *obj = NULL;
4258
4259
0
  fz_var(obj);
4260
4261
0
  fz_try(ctx)
4262
0
  {
4263
0
    fz_close_device(ctx, dev);
4264
0
    obj = pdf_add_page(ctx, wri->pdf, wri->mediabox, 0, wri->resources, wri->contents);
4265
0
    pdf_insert_page(ctx, wri->pdf, -1, obj);
4266
0
  }
4267
0
  fz_always(ctx)
4268
0
  {
4269
0
    fz_drop_device(ctx, dev);
4270
0
    pdf_drop_obj(ctx, obj);
4271
0
    fz_drop_buffer(ctx, wri->contents);
4272
0
    wri->contents = NULL;
4273
0
    pdf_drop_obj(ctx, wri->resources);
4274
0
    wri->resources = NULL;
4275
0
  }
4276
0
  fz_catch(ctx)
4277
0
    fz_rethrow(ctx);
4278
0
}
4279
4280
static void
4281
pdf_writer_close_writer(fz_context *ctx, fz_document_writer *wri_)
4282
0
{
4283
0
  pdf_writer *wri = (pdf_writer*)wri_;
4284
0
  pdf_write_document(ctx, wri->pdf, wri->out, &wri->opts);
4285
0
  fz_close_output(ctx, wri->out);
4286
0
}
4287
4288
static void
4289
pdf_writer_drop_writer(fz_context *ctx, fz_document_writer *wri_)
4290
0
{
4291
0
  pdf_writer *wri = (pdf_writer*)wri_;
4292
0
  fz_drop_buffer(ctx, wri->contents);
4293
0
  pdf_drop_obj(ctx, wri->resources);
4294
0
  pdf_drop_document(ctx, wri->pdf);
4295
0
  fz_drop_output(ctx, wri->out);
4296
0
}
4297
4298
fz_document_writer *
4299
fz_new_pdf_writer_with_output(fz_context *ctx, fz_output *out, const char *options)
4300
0
{
4301
0
  pdf_writer *wri;
4302
4303
0
  fz_var(wri);
4304
4305
0
  fz_try(ctx)
4306
0
  {
4307
0
    wri = fz_new_derived_document_writer(ctx, pdf_writer, pdf_writer_begin_page, pdf_writer_end_page, pdf_writer_close_writer, pdf_writer_drop_writer);
4308
0
    pdf_parse_write_options(ctx, &wri->opts, options);
4309
0
    wri->out = out;
4310
0
    wri->pdf = pdf_create_document(ctx);
4311
0
  }
4312
0
  fz_catch(ctx)
4313
0
  {
4314
0
    fz_drop_output(ctx, out);
4315
0
    pdf_drop_document(ctx, wri->pdf);
4316
0
    fz_free(ctx, wri);
4317
0
    fz_rethrow(ctx);
4318
0
  }
4319
4320
0
  return (fz_document_writer*)wri;
4321
0
}
4322
4323
fz_document_writer *
4324
fz_new_pdf_writer(fz_context *ctx, const char *path, const char *options)
4325
0
{
4326
0
  fz_output *out = fz_new_output_with_path(ctx, path ? path : "out.pdf", 0);
4327
0
  return fz_new_pdf_writer_with_output(ctx, out, options);
4328
0
}
4329
4330
void pdf_write_journal(fz_context *ctx, pdf_document *doc, fz_output *out)
4331
0
{
4332
0
  if (!doc || !out)
4333
0
    return;
4334
4335
0
  if (!doc->journal)
4336
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Can't write non-existent journal");
4337
4338
0
  pdf_serialise_journal(ctx, doc, out);
4339
0
}
4340
4341
void pdf_save_journal(fz_context *ctx, pdf_document *doc, const char *filename)
4342
0
{
4343
0
  fz_output *out;
4344
4345
0
  if (!doc)
4346
0
    return;
4347
4348
0
  out = fz_new_output_with_path(ctx, filename, 0);
4349
0
  fz_try(ctx)
4350
0
  {
4351
0
    pdf_write_journal(ctx, doc, out);
4352
0
    fz_close_output(ctx, out);
4353
0
  }
4354
0
  fz_always(ctx)
4355
0
    fz_drop_output(ctx, out);
4356
0
  fz_catch(ctx)
4357
0
    fz_rethrow(ctx);
4358
0
}
4359
4360
void pdf_read_journal(fz_context *ctx, pdf_document *doc, fz_stream *stm)
4361
0
{
4362
0
  pdf_deserialise_journal(ctx, doc, stm);
4363
0
}
4364
4365
void pdf_load_journal(fz_context *ctx, pdf_document *doc, const char *filename)
4366
0
{
4367
0
  fz_stream *stm;
4368
4369
0
  if (!doc)
4370
0
    return;
4371
4372
0
  stm = fz_open_file(ctx, filename);
4373
0
  fz_try(ctx)
4374
0
    pdf_read_journal(ctx, doc, stm);
4375
0
  fz_always(ctx)
4376
0
    fz_drop_stream(ctx, stm);
4377
0
  fz_catch(ctx)
4378
0
    fz_rethrow(ctx);
4379
0
}