PdfReader.java

1
/*
2
 * $Id: PdfReader.java 4096 2009-11-12 15:31:13Z blowagie $
3
 *
4
 * Copyright 2001, 2002 Paulo Soares
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * (the "License"); you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at http://www.mozilla.org/MPL/
9
 *
10
 * Software distributed under the License is distributed on an "AS IS" basis,
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
 * for the specific language governing rights and limitations under the License.
13
 *
14
 * The Original Code is 'iText, a free JAVA-PDF library'.
15
 *
16
 * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
17
 * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
18
 * All Rights Reserved.
19
 * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
20
 * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
21
 *
22
 * Contributor(s): all the names of the contributors are added in the source code
23
 * where applicable.
24
 *
25
 * Alternatively, the contents of this file may be used under the terms of the
26
 * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
27
 * provisions of LGPL are applicable instead of those above.  If you wish to
28
 * allow use of your version of this file only under the terms of the LGPL
29
 * License and not to allow others to use your version of this file under
30
 * the MPL, indicate your decision by deleting the provisions above and
31
 * replace them with the notice and other provisions required by the LGPL.
32
 * If you do not delete the provisions above, a recipient may use your version
33
 * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
34
 *
35
 * This library is free software; you can redistribute it and/or modify it
36
 * under the terms of the MPL as stated above or under the terms of the GNU
37
 * Library General Public License as published by the Free Software Foundation;
38
 * either version 2 of the License, or any later version.
39
 *
40
 * This library is distributed in the hope that it will be useful, but WITHOUT
41
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
42
 * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
43
 * details.
44
 *
45
 * If you didn't download this code from the following link, you should check if
46
 * you aren't using an obsolete version:
47
 * http://www.lowagie.com/iText/
48
 */
49
50
package com.lowagie.text.pdf;
51
52
import com.lowagie.bouncycastle.BouncyCastleHelper;
53
54
import com.lowagie.text.PageSize;
55
import com.lowagie.text.Rectangle;
56
import com.lowagie.text.error_messages.MessageLocalization;
57
import com.lowagie.text.exceptions.BadPasswordException;
58
import com.lowagie.text.ExceptionConverter;
59
import com.lowagie.text.exceptions.InvalidPdfException;
60
import com.lowagie.text.exceptions.UnsupportedPdfException;
61
import com.lowagie.text.pdf.interfaces.PdfViewerPreferences;
62
import com.lowagie.text.pdf.internal.PdfViewerPreferencesImp;
63
64
import java.io.ByteArrayInputStream;
65
import java.io.ByteArrayOutputStream;
66
import java.io.Closeable;
67
import java.io.DataInputStream;
68
import java.io.IOException;
69
import java.io.InputStream;
70
import java.net.URL;
71
import java.security.Key;
72
import java.security.MessageDigest;
73
import java.security.cert.Certificate;
74
import java.util.ArrayList;
75
import java.util.Arrays;
76
import java.util.Collections;
77
import java.util.HashMap;
78
import java.util.Iterator;
79
import java.util.List;
80
import java.util.Map;
81
import java.util.Set;
82
import java.util.Stack;
83
import java.util.zip.InflaterInputStream;
84
85
/**
86
 * Reads a PDF document.
87
 * 
88
 * @author Paulo Soares (psoares@consiste.pt)
89
 * @author Kazuya Ujihara
90
 */
91
public class PdfReader implements PdfViewerPreferences, Closeable {
92
93
  static final PdfName[] pageInhCandidates = {PdfName.MEDIABOX,
94
          PdfName.ROTATE, PdfName.RESOURCES, PdfName.CROPBOX};
95
96
  private static final byte[] endstream = PdfEncodings
97
          .convertToBytes("endstream", null);
98
  private static final byte[] endobj = PdfEncodings.convertToBytes("endobj", null);
99
  protected PRTokeniser tokens;
100
  // Each xref pair is a position
101
  // type 0 -> -1, 0
102
  // type 1 -> offset, 0
103
  // type 2 -> index, obj num
104
  protected int[] xref;
105
  protected Map<Integer, IntHashtable> objStmMark;
106
  protected IntHashtable objStmToOffset;
107
  protected boolean newXrefType;
108
  private List<PdfObject> xrefObj;
109
  PdfDictionary rootPages;
110
  protected PdfDictionary trailer;
111
  protected PdfDictionary catalog;
112
  protected PageRefs pageRefs;
113
  protected PRAcroForm acroForm = null;
114
  protected boolean acroFormParsed = false;
115
  protected boolean encrypted = false;
116
  protected boolean rebuilt = false;
117
  protected int freeXref;
118
  protected boolean tampered = false;
119
  protected int lastXref;
120
  protected int eofPos;
121
  protected char pdfVersion;
122
  protected PdfEncryption decrypt;
123
  protected byte[] password = null; // added by ujihara for decryption
124
  protected Key certificateKey = null; // added by Aiken Sam for certificate
125
                                       // decryption
126
  protected Certificate certificate = null; // added by Aiken Sam for
127
                                            // certificate decryption
128
  protected String certificateKeyProvider = null; // added by Aiken Sam for
129
                                                  // certificate decryption
130
  private boolean ownerPasswordUsed;
131
132
  // allow the PDF to be modified even if the owner password was not supplied
133
  // if encrypted (non-encrypted documents may be modified regardless)
134
  private boolean modificationAllowedWithoutOwnerPassword = true;
135
136
  protected List<PdfObject> strings = new ArrayList<>();
137
  protected boolean sharedStreams = true;
138
  protected boolean consolidateNamedDestinations = false;
139
  protected boolean remoteToLocalNamedDestinations = false;
140
  protected int rValue;
141
  protected int pValue;
142
  private int objNum;
143
  private int objGen;
144
  private int fileLength;
145
  private boolean hybridXref;
146
  private int lastXrefPartial = -1;
147
  private boolean partial;
148
149
  private PRIndirectReference cryptoRef;
150
  private final PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp();
151
  private boolean encryptionError;
152
153
  /**
154
   * Holds value of property appendable.
155
   */
156
  private boolean appendable;
157
158
  protected PdfReader() {
159
  }
160
161
  /**
162
   * Reads and parses a PDF document.
163
   * 
164
   * @param filename
165
   *          the file name of the document
166
   * @throws IOException
167
   *           on error
168
   */
169
  public PdfReader(String filename) throws IOException {
170
    this(filename, null);
171
  }
172
173
  /**
174
   * Reads and parses a PDF document.
175
   * 
176
   * @param filename
177
   *          the file name of the document
178
   * @param ownerPassword
179
   *          the password to read the document
180
   * @throws IOException
181
   *           on error
182
   */
183
  public PdfReader(String filename, byte[] ownerPassword) throws IOException {
184
    password = ownerPassword;
185
    tokens = new PRTokeniser(filename);
186 1 1. : removed call to com/lowagie/text/pdf/PdfReader::readPdf → NO_COVERAGE
    readPdf();
187
  }
188
189
  /**
190
   * Reads and parses a PDF document.
191
   * 
192
   * @param pdfIn
193
   *          the byte array with the document
194
   * @throws IOException
195
   *           on error
196
   */
197
  public PdfReader(byte[] pdfIn) throws IOException {
198
    this(pdfIn, null);
199
  }
200
201
  /**
202
   * Reads and parses a PDF document.
203
   * 
204
   * @param pdfIn
205
   *          the byte array with the document
206
   * @param ownerPassword
207
   *          the password to read the document
208
   * @throws IOException
209
   *           on error
210
   */
211
  public PdfReader(byte[] pdfIn, byte[] ownerPassword) throws IOException {
212
    password = ownerPassword;
213
    tokens = new PRTokeniser(pdfIn);
214 1 1. : removed call to com/lowagie/text/pdf/PdfReader::readPdf → NO_COVERAGE
    readPdf();
215
  }
216
217
  /**
218
   * Reads and parses a PDF document.
219
   * 
220
   * @param filename
221
   *          the file name of the document
222
   * @param certificate
223
   *          the certificate to read the document
224
   * @param certificateKey
225
   *          the private key of the certificate
226
   * @param certificateKeyProvider
227
   *          the security provider for certificateKey
228
   * @throws IOException
229
   *           on error
230
   */
231
  public PdfReader(String filename, Certificate certificate,
232
      Key certificateKey, String certificateKeyProvider) throws IOException {
233
    this.certificate = certificate;
234
    this.certificateKey = certificateKey;
235
    this.certificateKeyProvider = certificateKeyProvider;
236
    tokens = new PRTokeniser(filename);
237 1 1. : removed call to com/lowagie/text/pdf/PdfReader::readPdf → NO_COVERAGE
    readPdf();
238
  }
239
240
  /**
241
   * Reads and parses a PDF document.
242
   * 
243
   * @param url
244
   *          the URL of the document
245
   * @throws IOException
246
   *           on error
247
   */
248
  public PdfReader(URL url) throws IOException {
249
    this(url, null);
250
  }
251
252
  /**
253
   * Reads and parses a PDF document.
254
   * 
255
   * @param url
256
   *          the URL of the document
257
   * @param ownerPassword
258
   *          the password to read the document
259
   * @throws IOException
260
   *           on error
261
   */
262
  public PdfReader(URL url, byte[] ownerPassword) throws IOException {
263
    password = ownerPassword;
264
    tokens = new PRTokeniser(new RandomAccessFileOrArray(url));
265 1 1. : removed call to com/lowagie/text/pdf/PdfReader::readPdf → NO_COVERAGE
    readPdf();
266
  }
267
268
  /**
269
   * Reads and parses a PDF document.
270
   * 
271
   * @param is
272
   *          the <CODE>InputStream</CODE> containing the document. The stream
273
   *          is read to the end but is not closed
274
   * @param ownerPassword
275
   *          the password to read the document
276
   * @throws IOException
277
   *           on error
278
   */
279
  public PdfReader(InputStream is, byte[] ownerPassword) throws IOException {
280
    password = ownerPassword;
281
    tokens = new PRTokeniser(new RandomAccessFileOrArray(is));
282 1 1. : removed call to com/lowagie/text/pdf/PdfReader::readPdf → NO_COVERAGE
    readPdf();
283
  }
284
285
  /**
286
   * Reads and parses a PDF document.
287
   * 
288
   * @param is
289
   *          the <CODE>InputStream</CODE> containing the document. The stream
290
   *          is read to the end but is not closed
291
   * @throws IOException
292
   *           on error
293
   */
294
  public PdfReader(InputStream is) throws IOException {
295
    this(is, null);
296
  }
297
298
  /**
299
   * Reads and parses a pdf document. Contrary to the other constructors only
300
   * the xref is read into memory. The reader is said to be working in "partial"
301
   * mode as only parts of the pdf are read as needed. The pdf is left open but
302
   * may be closed at any time with <CODE>PdfReader.close()</CODE>, reopen is
303
   * automatic.
304
   * 
305
   * @param raf
306
   *          the document location
307
   * @param ownerPassword
308
   *          the password or <CODE>null</CODE> for no password
309
   * @throws IOException
310
   *           on error
311
   */
312
  public PdfReader(RandomAccessFileOrArray raf, byte[] ownerPassword)
313
      throws IOException {
314
    password = ownerPassword;
315
    partial = true;
316
    tokens = new PRTokeniser(raf);
317 1 1. : removed call to com/lowagie/text/pdf/PdfReader::readPdfPartial → NO_COVERAGE
    readPdfPartial();
318
  }
319
320
  /**
321
   * Creates an independent duplicate.
322
   * 
323
   * @param reader
324
   *          the <CODE>PdfReader</CODE> to duplicate
325
   */
326
  public PdfReader(PdfReader reader) {
327
    this.appendable = reader.appendable;
328
    this.consolidateNamedDestinations = reader.consolidateNamedDestinations;
329
    this.encrypted = reader.encrypted;
330
    this.rebuilt = reader.rebuilt;
331
    this.sharedStreams = reader.sharedStreams;
332
    this.tampered = reader.tampered;
333
    this.password = reader.password;
334
    this.pdfVersion = reader.pdfVersion;
335
    this.eofPos = reader.eofPos;
336
    this.freeXref = reader.freeXref;
337
    this.lastXref = reader.lastXref;
338
    this.tokens = new PRTokeniser(reader.tokens.getSafeFile());
339 1 1. : negated conditional → NO_COVERAGE
    if (reader.decrypt != null)
340
      this.decrypt = new PdfEncryption(reader.decrypt);
341
    this.pValue = reader.pValue;
342
    this.rValue = reader.rValue;
343
    this.xrefObj = new ArrayList<>(reader.xrefObj);
344 2 1. : changed conditional boundary → NO_COVERAGE
2. : negated conditional → NO_COVERAGE
    for (int k = 0; k < reader.xrefObj.size(); ++k) {
345
      this.xrefObj.set(k,
346
              duplicatePdfObject(reader.xrefObj.get(k), this));
347
    }
348
    this.pageRefs = new PageRefs(reader.pageRefs, this);
349
    this.trailer = (PdfDictionary) duplicatePdfObject(reader.trailer, this);
350
    this.catalog = trailer.getAsDict(PdfName.ROOT);
351
    this.rootPages = catalog.getAsDict(PdfName.PAGES);
352
    this.fileLength = reader.fileLength;
353
    this.partial = reader.partial;
354
    this.hybridXref = reader.hybridXref;
355
    this.objStmToOffset = reader.objStmToOffset;
356
    this.xref = reader.xref;
357
    this.cryptoRef = (PRIndirectReference) duplicatePdfObject(reader.cryptoRef,
358
        this);
359
    this.ownerPasswordUsed = reader.ownerPasswordUsed;
360
  }
361
362
  /**
363
   * Gets a new file instance of the original PDF document.
364
   * 
365
   * @return a new file instance of the original PDF document
366
   */
367
  public RandomAccessFileOrArray getSafeFile() {
368
    return tokens.getSafeFile();
369
  }
370
371
  protected PdfReaderInstance getPdfReaderInstance(PdfWriter writer) {
372 1 1. getPdfReaderInstance : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfReaderInstance to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return new PdfReaderInstance(this, writer);
373
  }
374
375
  /**
376
   * Gets the number of pages in the document.
377
   * 
378
   * @return the number of pages in the document
379
   */
380
  public int getNumberOfPages() {
381
    return pageRefs.size();
382
  }
383
384
  /**
385
   * Returns the document's catalog. This dictionary is not a copy, any changes
386
   * will be reflected in the catalog.
387
   * 
388
   * @return the document's catalog
389
   */
390
  public PdfDictionary getCatalog() {
391
    return catalog;
392
  }
393
394
  /**
395
   * Returns the document's acroform, if it has one.
396
   * 
397
   * @return the document's acroform
398
   */
399
  public PRAcroForm getAcroForm() {
400 1 1. getAcroForm : negated conditional → NO_COVERAGE
    if (!acroFormParsed) {
401
      acroFormParsed = true;
402
      PdfObject form = catalog.get(PdfName.ACROFORM);
403 1 1. getAcroForm : negated conditional → NO_COVERAGE
      if (form != null) {
404
        try {
405
          acroForm = new PRAcroForm(this);
406 1 1. getAcroForm : removed call to com/lowagie/text/pdf/PRAcroForm::readAcroForm → NO_COVERAGE
          acroForm.readAcroForm((PdfDictionary) getPdfObject(form));
407
        } catch (Exception e) {
408
          acroForm = null;
409
        }
410
      }
411
    }
412 1 1. getAcroForm : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getAcroForm to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return acroForm;
413
  }
414
415
  /**
416
   * Gets the page rotation. This value can be 0, 90, 180 or 270.
417
   * 
418
   * @param index
419
   *          the page number. The first page is 1
420
   * @return the page rotation
421
   */
422
  public int getPageRotation(int index) {
423 1 1. getPageRotation : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
    return getPageRotation(pageRefs.getPageNRelease(index));
424
  }
425
426
  int getPageRotation(PdfDictionary page) {
427
    PdfNumber rotate = page.getAsNumber(PdfName.ROTATE);
428 1 1. getPageRotation : negated conditional → NO_COVERAGE
    if (rotate == null)
429 1 1. getPageRotation : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
      return 0;
430
    else {
431
      int n = rotate.intValue();
432 1 1. getPageRotation : Replaced integer modulus with multiplication → NO_COVERAGE
      n %= 360;
433 4 1. getPageRotation : changed conditional boundary → NO_COVERAGE
2. getPageRotation : Replaced integer addition with subtraction → NO_COVERAGE
3. getPageRotation : negated conditional → NO_COVERAGE
4. getPageRotation : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
      return n < 0 ? n + 360 : n;
434
    }
435
  }
436
437
  /**
438
   * Gets the page size, taking rotation into account. This is a
439
   * <CODE>Rectangle</CODE> with the value of the /MediaBox and the /Rotate key.
440
   * 
441
   * @param index
442
   *          the page number. The first page is 1
443
   * @return a <CODE>Rectangle</CODE>
444
   */
445
  public Rectangle getPageSizeWithRotation(int index) {
446 1 1. getPageSizeWithRotation : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageSizeWithRotation to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return getPageSizeWithRotation(pageRefs.getPageNRelease(index));
447
  }
448
449
  /**
450
   * Gets the rotated page from a page dictionary.
451
   * 
452
   * @param page
453
   *          the page dictionary
454
   * @return the rotated page
455
   */
456
  public Rectangle getPageSizeWithRotation(PdfDictionary page) {
457
    Rectangle rect = getPageSize(page);
458
    int rotation = getPageRotation(page);
459 2 1. getPageSizeWithRotation : changed conditional boundary → NO_COVERAGE
2. getPageSizeWithRotation : negated conditional → NO_COVERAGE
    while (rotation > 0) {
460
      rect = rect.rotate();
461 1 1. getPageSizeWithRotation : Changed increment from -90 to 90 → NO_COVERAGE
      rotation -= 90;
462
    }
463 1 1. getPageSizeWithRotation : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageSizeWithRotation to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return rect;
464
  }
465
466
  /**
467
   * Gets the page size without taking rotation into account. This is the value
468
   * of the /MediaBox key.
469
   * 
470
   * @param index
471
   *          the page number. The first page is 1
472
   * @return the page size
473
   */
474
  public Rectangle getPageSize(int index) {
475 1 1. getPageSize : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageSize to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return getPageSize(pageRefs.getPageNRelease(index));
476
  }
477
478
  /**
479
   * Gets the page from a page dictionary
480
   * 
481
   * @param page
482
   *          the page dictionary
483
   * @return the page
484
   */
485
  public Rectangle getPageSize(PdfDictionary page) {
486
    PdfArray mediaBox = page.getAsArray(PdfName.MEDIABOX);
487 1 1. getPageSize : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageSize to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return getNormalizedRectangle(mediaBox);
488
  }
489
490
  /**
491
   * Gets the crop box without taking rotation into account. This is the value
492
   * of the /CropBox key. The crop box is the part of the document to be
493
   * displayed or printed. It usually is the same as the media box but may be
494
   * smaller. If the page doesn't have a crop box the page size will be
495
   * returned.
496
   * 
497
   * @param index
498
   *          the page number. The first page is 1
499
   * @return the crop box
500
   */
501
  public Rectangle getCropBox(int index) {
502
    PdfDictionary page = pageRefs.getPageNRelease(index);
503
    PdfArray cropBox = (PdfArray) getPdfObjectRelease(page.get(PdfName.CROPBOX));
504 1 1. getCropBox : negated conditional → NO_COVERAGE
    if (cropBox == null)
505 1 1. getCropBox : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getCropBox to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return getPageSize(page);
506 1 1. getCropBox : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getCropBox to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return getNormalizedRectangle(cropBox);
507
  }
508
509
  /**
510
   * Gets the box size. Allowed names are: "crop", "trim", "art", "bleed" and
511
   * "media".
512
   * 
513
   * @param index
514
   *          the page number. The first page is 1
515
   * @param boxName
516
   *          the box name
517
   * @return the box rectangle or null
518
   */
519
  public Rectangle getBoxSize(int index, String boxName) {
520
    PdfDictionary page = pageRefs.getPageNRelease(index);
521
    PdfArray box = null;
522
      switch (boxName) {
523
          case "trim":
524
              box = (PdfArray) getPdfObjectRelease(page.get(PdfName.TRIMBOX));
525
              break;
526
          case "art":
527
              box = (PdfArray) getPdfObjectRelease(page.get(PdfName.ARTBOX));
528
              break;
529
          case "bleed":
530
              box = (PdfArray) getPdfObjectRelease(page.get(PdfName.BLEEDBOX));
531
              break;
532
          case "crop":
533
              box = (PdfArray) getPdfObjectRelease(page.get(PdfName.CROPBOX));
534
              break;
535
          case "media":
536
              box = (PdfArray) getPdfObjectRelease(page.get(PdfName.MEDIABOX));
537
              break;
538
      }
539 1 1. getBoxSize : negated conditional → NO_COVERAGE
    if (box == null)
540 1 1. getBoxSize : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getBoxSize to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
541 1 1. getBoxSize : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getBoxSize to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return getNormalizedRectangle(box);
542
  }
543
544
  /**
545
   * Returns the content of the document information dictionary as a
546
   * <CODE>HashMap</CODE> of <CODE>String</CODE>.
547
   * 
548
   * @return content of the document information dictionary
549
   */
550
  public Map<String, String> getInfo() {
551
    Map<String, String> map = new HashMap<>();
552
    PdfDictionary info = trailer.getAsDict(PdfName.INFO);
553 1 1. getInfo : negated conditional → NO_COVERAGE
    if (info == null)
554 1 1. getInfo : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getInfo to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return map;
555
    for (Object o : info.getKeys()) {
556
      PdfName key = (PdfName) o;
557
      PdfObject obj = getPdfObject(info.get(key));
558 1 1. getInfo : negated conditional → NO_COVERAGE
      if (obj == null)
559
        continue;
560
      String value = obj.toString();
561
      switch (obj.type()) {
562
        case PdfObject.STRING: {
563
          value = ((PdfString) obj).toUnicodeString();
564
          break;
565
        }
566
        case PdfObject.NAME: {
567
          value = PdfName.decodeName(value);
568
          break;
569
        }
570
      }
571
      map.put(PdfName.decodeName(key.toString()), value);
572
    }
573 1 1. getInfo : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getInfo to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return map;
574
  }
575
576
  /**
577
   * Normalizes a <CODE>Rectangle</CODE> so that llx and lly are smaller than
578
   * urx and ury.
579
   * 
580
   * @param box
581
   *          the original rectangle
582
   * @return a normalized <CODE>Rectangle</CODE>
583
   */
584
  public static Rectangle getNormalizedRectangle(PdfArray box) {
585
    float llx = ((PdfNumber) getPdfObjectRelease(box.getPdfObject(0)))
586
        .floatValue();
587
    float lly = ((PdfNumber) getPdfObjectRelease(box.getPdfObject(1)))
588
        .floatValue();
589
    float urx = ((PdfNumber) getPdfObjectRelease(box.getPdfObject(2)))
590
        .floatValue();
591
    float ury = ((PdfNumber) getPdfObjectRelease(box.getPdfObject(3)))
592
        .floatValue();
593 1 1. getNormalizedRectangle : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getNormalizedRectangle to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return new Rectangle(Math.min(llx, urx), Math.min(lly, ury), Math.max(llx,
594
        urx), Math.max(lly, ury));
595
  }
596
597
  protected void readPdf() throws IOException {
598
    try {
599
      fileLength = tokens.getFile().length();
600
      pdfVersion = tokens.checkPdfHeader();
601
      try {
602 1 1. readPdf : removed call to com/lowagie/text/pdf/PdfReader::readXref → NO_COVERAGE
        readXref();
603
      } catch (Exception e) {
604
        try {
605
          rebuilt = true;
606 1 1. readPdf : removed call to com/lowagie/text/pdf/PdfReader::rebuildXref → NO_COVERAGE
          rebuildXref();
607
          lastXref = -1;
608
        } catch (Exception ne) {
609
          throw new InvalidPdfException(MessageLocalization.getComposedMessage(
610
              "rebuild.failed.1.original.message.2", ne.getMessage(),
611
              e.getMessage()));
612
        }
613
      }
614
      try {
615 1 1. readPdf : removed call to com/lowagie/text/pdf/PdfReader::readDocObj → NO_COVERAGE
        readDocObj();
616
      } catch (Exception e) {
617 1 1. readPdf : negated conditional → NO_COVERAGE
        if (e instanceof BadPasswordException)
618
          throw new BadPasswordException(e.getMessage());
619 2 1. readPdf : negated conditional → NO_COVERAGE
2. readPdf : negated conditional → NO_COVERAGE
        if (rebuilt || encryptionError)
620
          throw new InvalidPdfException(e.getMessage());
621
        rebuilt = true;
622
        encrypted = false;
623 1 1. readPdf : removed call to com/lowagie/text/pdf/PdfReader::rebuildXref → NO_COVERAGE
        rebuildXref();
624
        lastXref = -1;
625 1 1. readPdf : removed call to com/lowagie/text/pdf/PdfReader::readDocObj → NO_COVERAGE
        readDocObj();
626
      }
627
628 1 1. readPdf : removed call to java/util/List::clear → NO_COVERAGE
      strings.clear();
629 1 1. readPdf : removed call to com/lowagie/text/pdf/PdfReader::readPages → NO_COVERAGE
      readPages();
630 1 1. readPdf : removed call to com/lowagie/text/pdf/PdfReader::eliminateSharedStreams → NO_COVERAGE
      eliminateSharedStreams();
631
      removeUnusedObjects();
632
    } finally {
633
      try {
634 1 1. readPdf : removed call to com/lowagie/text/pdf/PRTokeniser::close → NO_COVERAGE
        tokens.close();
635
      } catch (Exception e) {
636
        // empty on purpose
637
      }
638
    }
639
  }
640
641
  protected void readPdfPartial() throws IOException {
642
    try {
643
      fileLength = tokens.getFile().length();
644
      pdfVersion = tokens.checkPdfHeader();
645
      try {
646 1 1. readPdfPartial : removed call to com/lowagie/text/pdf/PdfReader::readXref → NO_COVERAGE
        readXref();
647
      } catch (Exception e) {
648
        try {
649
          rebuilt = true;
650 1 1. readPdfPartial : removed call to com/lowagie/text/pdf/PdfReader::rebuildXref → NO_COVERAGE
          rebuildXref();
651
          lastXref = -1;
652
        } catch (Exception ne) {
653
          throw new InvalidPdfException(MessageLocalization.getComposedMessage(
654
              "rebuild.failed.1.original.message.2", ne.getMessage(),
655
              e.getMessage()));
656
        }
657
      }
658 1 1. readPdfPartial : removed call to com/lowagie/text/pdf/PdfReader::readDocObjPartial → NO_COVERAGE
      readDocObjPartial();
659 1 1. readPdfPartial : removed call to com/lowagie/text/pdf/PdfReader::readPages → NO_COVERAGE
      readPages();
660
    } catch (IOException e) {
661
      try {
662 1 1. readPdfPartial : removed call to com/lowagie/text/pdf/PRTokeniser::close → NO_COVERAGE
        tokens.close();
663
      } catch (Exception ignored) {
664
      }
665
      throw e;
666
    }
667
  }
668
669
  private boolean equalsArray(byte[] ar1, byte[] ar2, int size) {
670 3 1. equalsArray : changed conditional boundary → NO_COVERAGE
2. equalsArray : Changed increment from 1 to -1 → NO_COVERAGE
3. equalsArray : negated conditional → NO_COVERAGE
    for (int k = 0; k < size; ++k) {
671 1 1. equalsArray : negated conditional → NO_COVERAGE
      if (ar1[k] != ar2[k])
672 1 1. equalsArray : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
        return false;
673
    }
674 1 1. equalsArray : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
    return true;
675
  }
676
677
  /**
678
   */
679
  private void readDecryptedDocObj() throws IOException {
680 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
    if (encrypted)
681
      return;
682 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
    if (trailer == null) {
683
      return;
684
    }
685
    PdfObject encDic = trailer.get(PdfName.ENCRYPT);
686 2 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
2. readDecryptedDocObj : negated conditional → NO_COVERAGE
    if (encDic == null || encDic.toString().equals("null"))
687
      return;
688
    encryptionError = true;
689
    byte[] encryptionKey = null;
690
    encrypted = true;
691
    PdfDictionary enc = (PdfDictionary) getPdfObject(encDic);
692
693
    String s;
694
    PdfObject o;
695
696
    PdfArray documentIDs = trailer.getAsArray(PdfName.ID);
697
    byte[] documentID = null;
698 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
    if (documentIDs != null) {
699
      o = documentIDs.getPdfObject(0);
700
      strings.remove(o);
701
      s = o.toString();
702
      documentID = com.lowagie.text.DocWriter.getISOBytes(s);
703 2 1. readDecryptedDocObj : changed conditional boundary → NO_COVERAGE
2. readDecryptedDocObj : negated conditional → NO_COVERAGE
      if (documentIDs.size() > 1)
704
        strings.remove(documentIDs.getPdfObject(1));
705
    }
706
    // just in case we have a broken producer
707 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
    if (documentID == null)
708
      documentID = new byte[0];
709
    byte[] uValue = null;
710
    byte[] oValue = null;
711
    int cryptoMode = PdfWriter.STANDARD_ENCRYPTION_40;
712
    int lengthValue = 0;
713
714
    PdfObject filter = getPdfObjectRelease(enc.get(PdfName.FILTER));
715
716 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
    if (filter.equals(PdfName.STANDARD)) {
717
      s = enc.get(PdfName.U).toString();
718
      strings.remove(enc.get(PdfName.U));
719
      uValue = com.lowagie.text.DocWriter.getISOBytes(s);
720
      s = enc.get(PdfName.O).toString();
721
      strings.remove(enc.get(PdfName.O));
722
      oValue = com.lowagie.text.DocWriter.getISOBytes(s);
723
724
      o = enc.get(PdfName.P);
725 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
      if (!o.isNumber())
726
        throw new InvalidPdfException(
727
            MessageLocalization.getComposedMessage("illegal.p.value"));
728
      pValue = ((PdfNumber) o).intValue();
729
730
      o = enc.get(PdfName.R);
731 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
      if (!o.isNumber())
732
        throw new InvalidPdfException(
733
            MessageLocalization.getComposedMessage("illegal.r.value"));
734
      rValue = ((PdfNumber) o).intValue();
735
736
      switch (rValue) {
737
      case 2:
738
        cryptoMode = PdfWriter.STANDARD_ENCRYPTION_40;
739
        break;
740
      case 3:
741
        o = enc.get(PdfName.LENGTH);
742 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (!o.isNumber())
743
          throw new InvalidPdfException(
744
              MessageLocalization.getComposedMessage("illegal.length.value"));
745
        lengthValue = ((PdfNumber) o).intValue();
746 6 1. readDecryptedDocObj : changed conditional boundary → NO_COVERAGE
2. readDecryptedDocObj : changed conditional boundary → NO_COVERAGE
3. readDecryptedDocObj : Replaced integer modulus with multiplication → NO_COVERAGE
4. readDecryptedDocObj : negated conditional → NO_COVERAGE
5. readDecryptedDocObj : negated conditional → NO_COVERAGE
6. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (lengthValue > 128 || lengthValue < 40 || lengthValue % 8 != 0)
747
          throw new InvalidPdfException(
748
              MessageLocalization.getComposedMessage("illegal.length.value"));
749
        cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128;
750
        break;
751
      case 4:
752
        PdfDictionary dic = (PdfDictionary) enc.get(PdfName.CF);
753 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (dic == null)
754
          throw new InvalidPdfException(
755
              MessageLocalization.getComposedMessage("cf.not.found.encryption"));
756
        dic = (PdfDictionary) dic.get(PdfName.STDCF);
757 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (dic == null)
758
          throw new InvalidPdfException(
759
              MessageLocalization
760
                  .getComposedMessage("stdcf.not.found.encryption"));
761 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (PdfName.V2.equals(dic.get(PdfName.CFM)))
762
          cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128;
763 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
        else if (PdfName.AESV2.equals(dic.get(PdfName.CFM)))
764
          cryptoMode = PdfWriter.ENCRYPTION_AES_128;
765
        else
766
          throw new UnsupportedPdfException(
767
              MessageLocalization
768
                  .getComposedMessage("no.compatible.encryption.found"));
769
        PdfObject em = enc.get(PdfName.ENCRYPTMETADATA);
770 2 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
2. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (em != null && em.toString().equals("false"))
771 1 1. readDecryptedDocObj : Replaced bitwise OR with AND → NO_COVERAGE
          cryptoMode |= PdfWriter.DO_NOT_ENCRYPT_METADATA;
772
        break;
773
      default:
774
        throw new UnsupportedPdfException(
775
            MessageLocalization.getComposedMessage(
776
                "unknown.encryption.type.r.eq.1", rValue));
777
      }
778 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
    } else if (filter.equals(PdfName.PUBSEC)) {
779
      PdfArray recipients;
780
781
      o = enc.get(PdfName.V);
782 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
      if (!o.isNumber())
783
        throw new InvalidPdfException(
784
            MessageLocalization.getComposedMessage("illegal.v.value"));
785
      int vValue = ((PdfNumber) o).intValue();
786
      switch (vValue) {
787
      case 1:
788
        cryptoMode = PdfWriter.STANDARD_ENCRYPTION_40;
789
        lengthValue = 40;
790
        recipients = (PdfArray) enc.get(PdfName.RECIPIENTS);
791
        break;
792
      case 2:
793
        o = enc.get(PdfName.LENGTH);
794 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (!o.isNumber())
795
          throw new InvalidPdfException(
796
              MessageLocalization.getComposedMessage("illegal.length.value"));
797
        lengthValue = ((PdfNumber) o).intValue();
798 6 1. readDecryptedDocObj : changed conditional boundary → NO_COVERAGE
2. readDecryptedDocObj : changed conditional boundary → NO_COVERAGE
3. readDecryptedDocObj : Replaced integer modulus with multiplication → NO_COVERAGE
4. readDecryptedDocObj : negated conditional → NO_COVERAGE
5. readDecryptedDocObj : negated conditional → NO_COVERAGE
6. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (lengthValue > 128 || lengthValue < 40 || lengthValue % 8 != 0)
799
          throw new InvalidPdfException(
800
              MessageLocalization.getComposedMessage("illegal.length.value"));
801
        cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128;
802
        recipients = (PdfArray) enc.get(PdfName.RECIPIENTS);
803
        break;
804
      case 4:
805
        PdfDictionary dic = (PdfDictionary) enc.get(PdfName.CF);
806 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (dic == null)
807
          throw new InvalidPdfException(
808
              MessageLocalization.getComposedMessage("cf.not.found.encryption"));
809
        dic = (PdfDictionary) dic.get(PdfName.DEFAULTCRYPTFILTER);
810 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (dic == null)
811
          throw new InvalidPdfException(
812
              MessageLocalization
813
                  .getComposedMessage("defaultcryptfilter.not.found.encryption"));
814 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (PdfName.V2.equals(dic.get(PdfName.CFM))) {
815
          cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128;
816
          lengthValue = 128;
817 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
        } else if (PdfName.AESV2.equals(dic.get(PdfName.CFM))) {
818
          cryptoMode = PdfWriter.ENCRYPTION_AES_128;
819
          lengthValue = 128;
820
        } else
821
          throw new UnsupportedPdfException(
822
              MessageLocalization
823
                  .getComposedMessage("no.compatible.encryption.found"));
824
        PdfObject em = dic.get(PdfName.ENCRYPTMETADATA);
825 2 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
2. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (em != null && em.toString().equals("false"))
826 1 1. readDecryptedDocObj : Replaced bitwise OR with AND → NO_COVERAGE
          cryptoMode |= PdfWriter.DO_NOT_ENCRYPT_METADATA;
827
828
        recipients = (PdfArray) dic.get(PdfName.RECIPIENTS);
829
        break;
830
      default:
831
        throw new UnsupportedPdfException(
832
            MessageLocalization.getComposedMessage(
833
                "unknown.encryption.type.v.eq.1", rValue));
834
      }
835 1 1. readDecryptedDocObj : removed call to com/lowagie/bouncycastle/BouncyCastleHelper::checkCertificateEncodingOrThrowException → NO_COVERAGE
      BouncyCastleHelper.checkCertificateEncodingOrThrowException(certificate);
836
      byte[] envelopedData = BouncyCastleHelper.getEnvelopedData(recipients, strings, certificate, certificateKey, certificateKeyProvider);
837
838 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
      if (envelopedData == null) {
839
        throw new UnsupportedPdfException(
840
            MessageLocalization.getComposedMessage("bad.certificate.and.key"));
841
      }
842
843
      MessageDigest md;
844
845
      try {
846
        md = MessageDigest.getInstance("SHA-1");
847 1 1. readDecryptedDocObj : removed call to java/security/MessageDigest::update → NO_COVERAGE
        md.update(envelopedData, 0, 20);
848 2 1. readDecryptedDocObj : changed conditional boundary → NO_COVERAGE
2. readDecryptedDocObj : negated conditional → NO_COVERAGE
        for (int i = 0; i < recipients.size(); i++) {
849
          byte[] encodedRecipient = recipients.getPdfObject(i).getBytes();
850 1 1. readDecryptedDocObj : removed call to java/security/MessageDigest::update → NO_COVERAGE
          md.update(encodedRecipient);
851
        }
852 2 1. readDecryptedDocObj : Replaced bitwise AND with OR → NO_COVERAGE
2. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if ((cryptoMode & PdfWriter.DO_NOT_ENCRYPT_METADATA) != 0)
853 1 1. readDecryptedDocObj : removed call to java/security/MessageDigest::update → NO_COVERAGE
          md.update(new byte[] { (byte) 255, (byte) 255, (byte) 255, (byte) 255 });
854
        encryptionKey = md.digest();
855
      } catch (Exception f) {
856
        throw new ExceptionConverter(f);
857
      }
858
    }
859
860
    decrypt = new PdfEncryption();
861 1 1. readDecryptedDocObj : removed call to com/lowagie/text/pdf/PdfEncryption::setCryptoMode → NO_COVERAGE
    decrypt.setCryptoMode(cryptoMode, lengthValue);
862
863 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
    if (filter.equals(PdfName.STANDARD)) {
864
      // check by owner password
865
      decrypt
866 1 1. readDecryptedDocObj : removed call to com/lowagie/text/pdf/PdfEncryption::setupByOwnerPassword → NO_COVERAGE
          .setupByOwnerPassword(documentID, password, uValue, oValue, pValue);
867 3 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
2. readDecryptedDocObj : negated conditional → NO_COVERAGE
3. readDecryptedDocObj : negated conditional → NO_COVERAGE
      if (!equalsArray(uValue, decrypt.userKey,
868
          (rValue == 3 || rValue == 4) ? 16 : 32)) {
869
        // check by user password
870 1 1. readDecryptedDocObj : removed call to com/lowagie/text/pdf/PdfEncryption::setupByUserPassword → NO_COVERAGE
        decrypt.setupByUserPassword(documentID, password, oValue, pValue);
871 3 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
2. readDecryptedDocObj : negated conditional → NO_COVERAGE
3. readDecryptedDocObj : negated conditional → NO_COVERAGE
        if (!equalsArray(uValue, decrypt.userKey,
872
            (rValue == 3 || rValue == 4) ? 16 : 32)) {
873
          throw new BadPasswordException(
874
              MessageLocalization.getComposedMessage("bad.user.password"));
875
        }
876
      } else
877
        ownerPasswordUsed = true;
878 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
    } else if (filter.equals(PdfName.PUBSEC)) {
879 1 1. readDecryptedDocObj : removed call to com/lowagie/text/pdf/PdfEncryption::setupByEncryptionKey → NO_COVERAGE
      decrypt.setupByEncryptionKey(encryptionKey, lengthValue);
880
      ownerPasswordUsed = true;
881
    }
882
883
    for (Object string : strings) {
884
      PdfString str = (PdfString) string;
885 1 1. readDecryptedDocObj : removed call to com/lowagie/text/pdf/PdfString::decrypt → NO_COVERAGE
      str.decrypt(this);
886
    }
887
888 1 1. readDecryptedDocObj : negated conditional → NO_COVERAGE
    if (encDic.isIndirect()) {
889
      cryptoRef = (PRIndirectReference) encDic;
890
      xrefObj.set(cryptoRef.getNumber(), null);
891
    }
892
    encryptionError = false;
893
  }
894
895
    /**
896
   * @return a PdfObject
897
   */
898
  public static PdfObject getPdfObjectRelease(PdfObject obj) {
899
    PdfObject obj2 = getPdfObject(obj);
900 1 1. getPdfObjectRelease : removed call to com/lowagie/text/pdf/PdfReader::releaseLastXrefPartial → NO_COVERAGE
    releaseLastXrefPartial(obj);
901 1 1. getPdfObjectRelease : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObjectRelease to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return obj2;
902
  }
903
904
  /**
905
   * Reads a <CODE>PdfObject</CODE> resolving an indirect reference if needed.
906
   * 
907
   * @param obj
908
   *          the <CODE>PdfObject</CODE> to read
909
   * @return the resolved <CODE>PdfObject</CODE>
910
   */
911
  public static PdfObject getPdfObject(PdfObject obj) {
912 1 1. getPdfObject : negated conditional → NO_COVERAGE
    if (obj == null)
913 1 1. getPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
914 1 1. getPdfObject : negated conditional → NO_COVERAGE
    if (!obj.isIndirect())
915 1 1. getPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return obj;
916
    try {
917
      PRIndirectReference ref = (PRIndirectReference) obj;
918
      int idx = ref.getNumber();
919
      boolean appendable = ref.getReader().appendable;
920
      obj = ref.getReader().getPdfObject(idx);
921 1 1. getPdfObject : negated conditional → NO_COVERAGE
      if (obj == null) {
922 1 1. getPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return null;
923
      } else {
924 1 1. getPdfObject : negated conditional → NO_COVERAGE
        if (appendable) {
925
          switch (obj.type()) {
926
          case PdfObject.NULL:
927
            obj = new PdfNull();
928
            break;
929
          case PdfObject.BOOLEAN:
930
            obj = new PdfBoolean(((PdfBoolean) obj).booleanValue());
931
            break;
932
          case PdfObject.NAME:
933
            obj = new PdfName(obj.getBytes());
934
            break;
935
          }
936 1 1. getPdfObject : removed call to com/lowagie/text/pdf/PdfObject::setIndRef → NO_COVERAGE
          obj.setIndRef(ref);
937
        }
938 1 1. getPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return obj;
939
      }
940
    } catch (Exception e) {
941
      throw new ExceptionConverter(e);
942
    }
943
  }
944
945
  /**
946
   * Reads a <CODE>PdfObject</CODE> resolving an indirect reference if needed.
947
   * If the reader was opened in partial mode the object will be released to
948
   * save memory.
949
   * 
950
   * @param obj
951
   *          the <CODE>PdfObject</CODE> to read
952
   * @return a PdfObject
953
   */
954
  public static PdfObject getPdfObjectRelease(PdfObject obj, PdfObject parent) {
955
    PdfObject obj2 = getPdfObject(obj, parent);
956 1 1. getPdfObjectRelease : removed call to com/lowagie/text/pdf/PdfReader::releaseLastXrefPartial → NO_COVERAGE
    releaseLastXrefPartial(obj);
957 1 1. getPdfObjectRelease : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObjectRelease to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return obj2;
958
  }
959
960
  /**
961
   * @return a PdfObject
962
   */
963
  public static PdfObject getPdfObject(PdfObject obj, PdfObject parent) {
964 1 1. getPdfObject : negated conditional → NO_COVERAGE
    if (obj == null)
965 1 1. getPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
966 1 1. getPdfObject : negated conditional → NO_COVERAGE
    if (!obj.isIndirect()) {
967
      PRIndirectReference ref;
968 2 1. getPdfObject : negated conditional → NO_COVERAGE
2. getPdfObject : negated conditional → NO_COVERAGE
      if (parent != null && (ref = parent.getIndRef()) != null
969 1 1. getPdfObject : negated conditional → NO_COVERAGE
          && ref.getReader().isAppendable()) {
970
        switch (obj.type()) {
971
        case PdfObject.NULL:
972
          obj = new PdfNull();
973
          break;
974
        case PdfObject.BOOLEAN:
975
          obj = new PdfBoolean(((PdfBoolean) obj).booleanValue());
976
          break;
977
        case PdfObject.NAME:
978
          obj = new PdfName(obj.getBytes());
979
          break;
980
        }
981 1 1. getPdfObject : removed call to com/lowagie/text/pdf/PdfObject::setIndRef → NO_COVERAGE
        obj.setIndRef(ref);
982
      }
983 1 1. getPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return obj;
984
    }
985 1 1. getPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return getPdfObject(obj);
986
  }
987
988
  /**
989
   * @return a PdfObject
990
   */
991
  public PdfObject getPdfObjectRelease(int idx) {
992
    PdfObject obj = getPdfObject(idx);
993 1 1. getPdfObjectRelease : removed call to com/lowagie/text/pdf/PdfReader::releaseLastXrefPartial → NO_COVERAGE
    releaseLastXrefPartial();
994 1 1. getPdfObjectRelease : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObjectRelease to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return obj;
995
  }
996
997
  /**
998
   * @return aPdfObject
999
   */
1000
  public PdfObject getPdfObject(int idx) {
1001
    try {
1002
      lastXrefPartial = -1;
1003 4 1. getPdfObject : changed conditional boundary → NO_COVERAGE
2. getPdfObject : changed conditional boundary → NO_COVERAGE
3. getPdfObject : negated conditional → NO_COVERAGE
4. getPdfObject : negated conditional → NO_COVERAGE
      if (idx < 0 || idx >= xrefObj.size())
1004 1 1. getPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return null;
1005
      PdfObject obj = xrefObj.get(idx);
1006 2 1. getPdfObject : negated conditional → NO_COVERAGE
2. getPdfObject : negated conditional → NO_COVERAGE
      if (!partial || obj != null)
1007 1 1. getPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return obj;
1008 3 1. getPdfObject : changed conditional boundary → NO_COVERAGE
2. getPdfObject : Replaced integer multiplication with division → NO_COVERAGE
3. getPdfObject : negated conditional → NO_COVERAGE
      if (idx * 2 >= xref.length)
1009 1 1. getPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return null;
1010
      obj = readSingleObject(idx);
1011
      lastXrefPartial = -1;
1012 1 1. getPdfObject : negated conditional → NO_COVERAGE
      if (obj != null)
1013
        lastXrefPartial = idx;
1014 1 1. getPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return obj;
1015
    } catch (Exception e) {
1016
      throw new ExceptionConverter(e);
1017
    }
1018
  }
1019
1020
  /**
1021
     *
1022
     */
1023
  public void resetLastXrefPartial() {
1024
    lastXrefPartial = -1;
1025
  }
1026
1027
  /**
1028
     *
1029
     */
1030
  public void releaseLastXrefPartial() {
1031 2 1. releaseLastXrefPartial : negated conditional → NO_COVERAGE
2. releaseLastXrefPartial : negated conditional → NO_COVERAGE
    if (partial && lastXrefPartial != -1) {
1032
      xrefObj.set(lastXrefPartial, null);
1033
      lastXrefPartial = -1;
1034
    }
1035
  }
1036
1037
  /**
1038
   */
1039
  public static void releaseLastXrefPartial(PdfObject obj) {
1040 1 1. releaseLastXrefPartial : negated conditional → NO_COVERAGE
    if (obj == null)
1041
      return;
1042 1 1. releaseLastXrefPartial : negated conditional → NO_COVERAGE
    if (!obj.isIndirect())
1043
      return;
1044 1 1. releaseLastXrefPartial : negated conditional → NO_COVERAGE
    if (!(obj instanceof PRIndirectReference))
1045
      return;
1046
1047
    PRIndirectReference ref = (PRIndirectReference) obj;
1048
    PdfReader reader = ref.getReader();
1049 2 1. releaseLastXrefPartial : negated conditional → NO_COVERAGE
2. releaseLastXrefPartial : negated conditional → NO_COVERAGE
    if (reader.partial && reader.lastXrefPartial != -1
1050 1 1. releaseLastXrefPartial : negated conditional → NO_COVERAGE
        && reader.lastXrefPartial == ref.getNumber()) {
1051
      reader.xrefObj.set(reader.lastXrefPartial, null);
1052
    }
1053
    reader.lastXrefPartial = -1;
1054
  }
1055
1056
  private void setXrefPartialObject(int idx, PdfObject obj) {
1057 3 1. setXrefPartialObject : changed conditional boundary → NO_COVERAGE
2. setXrefPartialObject : negated conditional → NO_COVERAGE
3. setXrefPartialObject : negated conditional → NO_COVERAGE
    if (!partial || idx < 0)
1058
      return;
1059
    xrefObj.set(idx, obj);
1060
  }
1061
1062
  /**
1063
   * @return an indirect reference
1064
   */
1065
  public PRIndirectReference addPdfObject(PdfObject obj) {
1066
    xrefObj.add(obj);
1067 2 1. addPdfObject : Replaced integer subtraction with addition → NO_COVERAGE
2. addPdfObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::addPdfObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return new PRIndirectReference(this, xrefObj.size() - 1);
1068
  }
1069
1070
  protected void readPages() throws IOException {
1071
    catalog = trailer.getAsDict(PdfName.ROOT);
1072
    rootPages = catalog.getAsDict(PdfName.PAGES);
1073
    pageRefs = new PageRefs(this);
1074
  }
1075
1076
  protected void readDocObjPartial() throws IOException {
1077 1 1. readDocObjPartial : Replaced integer division with multiplication → NO_COVERAGE
    xrefObj = new ArrayList<>(xref.length / 2);
1078 1 1. readDocObjPartial : Replaced integer division with multiplication → NO_COVERAGE
    xrefObj.addAll(Collections.nCopies(xref.length / 2, null));
1079 1 1. readDocObjPartial : removed call to com/lowagie/text/pdf/PdfReader::readDecryptedDocObj → NO_COVERAGE
    readDecryptedDocObj();
1080 1 1. readDocObjPartial : negated conditional → NO_COVERAGE
    if (objStmToOffset != null) {
1081
      int[] keys = objStmToOffset.getKeys();
1082
      for (int n : keys) {
1083 1 1. readDocObjPartial : Replaced integer multiplication with division → NO_COVERAGE
        objStmToOffset.put(n, xref[n * 2]);
1084 1 1. readDocObjPartial : Replaced integer multiplication with division → NO_COVERAGE
        xref[n * 2] = -1;
1085
      }
1086
    }
1087
  }
1088
1089
  protected PdfObject readSingleObject(int k) throws IOException {
1090 1 1. readSingleObject : removed call to java/util/List::clear → NO_COVERAGE
    strings.clear();
1091 1 1. readSingleObject : Replaced integer multiplication with division → NO_COVERAGE
    int k2 = k * 2;
1092
    int pos = xref[k2];
1093 2 1. readSingleObject : changed conditional boundary → NO_COVERAGE
2. readSingleObject : negated conditional → NO_COVERAGE
    if (pos < 0)
1094 1 1. readSingleObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readSingleObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
1095 3 1. readSingleObject : changed conditional boundary → NO_COVERAGE
2. readSingleObject : Replaced integer addition with subtraction → NO_COVERAGE
3. readSingleObject : negated conditional → NO_COVERAGE
    if (xref[k2 + 1] > 0)
1096 1 1. readSingleObject : Replaced integer addition with subtraction → NO_COVERAGE
      pos = objStmToOffset.get(xref[k2 + 1]);
1097 1 1. readSingleObject : negated conditional → NO_COVERAGE
    if (pos == 0)
1098 1 1. readSingleObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readSingleObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
1099 1 1. readSingleObject : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
    tokens.seek(pos);
1100 1 1. readSingleObject : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
    tokens.nextValidToken();
1101 1 1. readSingleObject : negated conditional → NO_COVERAGE
    if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
1102 1 1. readSingleObject : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
      tokens.throwError(MessageLocalization
1103
          .getComposedMessage("invalid.object.number"));
1104
    objNum = tokens.intValue();
1105 1 1. readSingleObject : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
    tokens.nextValidToken();
1106 1 1. readSingleObject : negated conditional → NO_COVERAGE
    if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
1107 1 1. readSingleObject : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
      tokens.throwError(MessageLocalization
1108
          .getComposedMessage("invalid.generation.number"));
1109
    objGen = tokens.intValue();
1110 1 1. readSingleObject : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
    tokens.nextValidToken();
1111 1 1. readSingleObject : negated conditional → NO_COVERAGE
    if (!tokens.getStringValue().equals("obj"))
1112 1 1. readSingleObject : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
      tokens.throwError(MessageLocalization
1113
          .getComposedMessage("token.obj.expected"));
1114
    PdfObject obj;
1115
    try {
1116
      obj = readPRObject();
1117
      for (PdfObject string : strings) {
1118
        PdfString str = (PdfString) string;
1119 1 1. readSingleObject : removed call to com/lowagie/text/pdf/PdfString::decrypt → NO_COVERAGE
        str.decrypt(this);
1120
      }
1121 1 1. readSingleObject : negated conditional → NO_COVERAGE
      if (obj.isStream()) {
1122 1 1. readSingleObject : removed call to com/lowagie/text/pdf/PdfReader::checkPRStreamLength → NO_COVERAGE
        checkPRStreamLength((PRStream) obj);
1123
      }
1124
    } catch (Exception e) {
1125
      obj = null;
1126
    }
1127 3 1. readSingleObject : changed conditional boundary → NO_COVERAGE
2. readSingleObject : Replaced integer addition with subtraction → NO_COVERAGE
3. readSingleObject : negated conditional → NO_COVERAGE
    if (xref[k2 + 1] > 0) {
1128
      obj = readOneObjStm((PRStream) obj, xref[k2]);
1129
    }
1130
    xrefObj.set(k, obj);
1131 1 1. readSingleObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readSingleObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return obj;
1132
  }
1133
1134
  protected PdfObject readOneObjStm(PRStream stream, int idx)
1135
      throws IOException {
1136
    int first = stream.getAsNumber(PdfName.FIRST).intValue();
1137
    byte[] b = getStreamBytes(stream, tokens.getFile());
1138
    PRTokeniser saveTokens = tokens;
1139
    tokens = new PRTokeniser(b);
1140
    try {
1141
      int address = 0;
1142
      boolean ok = true;
1143 1 1. readOneObjStm : Changed increment from 1 to -1 → NO_COVERAGE
      ++idx;
1144 3 1. readOneObjStm : changed conditional boundary → NO_COVERAGE
2. readOneObjStm : Changed increment from 1 to -1 → NO_COVERAGE
3. readOneObjStm : negated conditional → NO_COVERAGE
      for (int k = 0; k < idx; ++k) {
1145
        ok = tokens.nextToken();
1146 1 1. readOneObjStm : negated conditional → NO_COVERAGE
        if (!ok)
1147
          break;
1148 1 1. readOneObjStm : negated conditional → NO_COVERAGE
        if (tokens.getTokenType() != PRTokeniser.TK_NUMBER) {
1149
          ok = false;
1150
          break;
1151
        }
1152
        ok = tokens.nextToken();
1153 1 1. readOneObjStm : negated conditional → NO_COVERAGE
        if (!ok)
1154
          break;
1155 1 1. readOneObjStm : negated conditional → NO_COVERAGE
        if (tokens.getTokenType() != PRTokeniser.TK_NUMBER) {
1156
          ok = false;
1157
          break;
1158
        }
1159 1 1. readOneObjStm : Replaced integer addition with subtraction → NO_COVERAGE
        address = tokens.intValue() + first;
1160
      }
1161 1 1. readOneObjStm : negated conditional → NO_COVERAGE
      if (!ok)
1162
        throw new InvalidPdfException(
1163
            MessageLocalization.getComposedMessage("error.reading.objstm"));
1164 1 1. readOneObjStm : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
      tokens.seek(address);
1165 1 1. readOneObjStm : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readOneObjStm to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return readPRObject();
1166
    } finally {
1167
      tokens = saveTokens;
1168
    }
1169
  }
1170
1171
  /**
1172
   * @return the percentage of the cross reference table that has been read
1173
   */
1174
  public double dumpPerc() {
1175
    int total = 0;
1176
    for (PdfObject aXrefObj : xrefObj) {
1177 1 1. dumpPerc : negated conditional → NO_COVERAGE
      if (aXrefObj != null)
1178 1 1. dumpPerc : Changed increment from 1 to -1 → NO_COVERAGE
        ++total;
1179
    }
1180 3 1. dumpPerc : Replaced double multiplication with division → NO_COVERAGE
2. dumpPerc : Replaced double division with multiplication → NO_COVERAGE
3. dumpPerc : replaced return of double value with -(x + 1) for com/lowagie/text/pdf/PdfReader::dumpPerc → NO_COVERAGE
    return (total * 100.0 / xrefObj.size());
1181
  }
1182
1183
  protected void readDocObj() throws IOException {
1184
    List<PdfObject> streams = new ArrayList<>();
1185 1 1. readDocObj : Replaced integer division with multiplication → NO_COVERAGE
    xrefObj = new ArrayList<>(xref.length / 2);
1186 1 1. readDocObj : Replaced integer division with multiplication → NO_COVERAGE
    xrefObj.addAll(Collections.nCopies(xref.length / 2, null));
1187 3 1. readDocObj : changed conditional boundary → NO_COVERAGE
2. readDocObj : Changed increment from 2 to -2 → NO_COVERAGE
3. readDocObj : negated conditional → NO_COVERAGE
    for (int k = 2; k < xref.length; k += 2) {
1188
      int pos = xref[k];
1189 5 1. readDocObj : changed conditional boundary → NO_COVERAGE
2. readDocObj : changed conditional boundary → NO_COVERAGE
3. readDocObj : Replaced integer addition with subtraction → NO_COVERAGE
4. readDocObj : negated conditional → NO_COVERAGE
5. readDocObj : negated conditional → NO_COVERAGE
      if (pos <= 0 || xref[k + 1] > 0)
1190
        continue;
1191 1 1. readDocObj : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
      tokens.seek(pos);
1192 1 1. readDocObj : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
      tokens.nextValidToken();
1193 1 1. readDocObj : negated conditional → NO_COVERAGE
      if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
1194 1 1. readDocObj : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
        tokens.throwError(MessageLocalization
1195
            .getComposedMessage("invalid.object.number"));
1196
      objNum = tokens.intValue();
1197 1 1. readDocObj : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
      tokens.nextValidToken();
1198 1 1. readDocObj : negated conditional → NO_COVERAGE
      if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
1199 1 1. readDocObj : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
        tokens.throwError(MessageLocalization
1200
            .getComposedMessage("invalid.generation.number"));
1201
      objGen = tokens.intValue();
1202 1 1. readDocObj : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
      tokens.nextValidToken();
1203 1 1. readDocObj : negated conditional → NO_COVERAGE
      if (!tokens.getStringValue().equals("obj"))
1204 1 1. readDocObj : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
        tokens.throwError(MessageLocalization
1205
            .getComposedMessage("token.obj.expected"));
1206
      PdfObject obj;
1207
      try {
1208
        obj = readPRObject();
1209 1 1. readDocObj : negated conditional → NO_COVERAGE
        if (obj.isStream()) {
1210
          streams.add(obj);
1211
        }
1212
      } catch (Exception e) {
1213
        obj = null;
1214
      }
1215 1 1. readDocObj : Replaced integer division with multiplication → NO_COVERAGE
      xrefObj.set(k / 2, obj);
1216
    }
1217
    for (PdfObject stream : streams) {
1218 1 1. readDocObj : removed call to com/lowagie/text/pdf/PdfReader::checkPRStreamLength → NO_COVERAGE
      checkPRStreamLength((PRStream) stream);
1219
    }
1220 1 1. readDocObj : removed call to com/lowagie/text/pdf/PdfReader::readDecryptedDocObj → NO_COVERAGE
    readDecryptedDocObj();
1221 1 1. readDocObj : negated conditional → NO_COVERAGE
    if (objStmMark != null) {
1222
      for (Object o : objStmMark.entrySet()) {
1223
        Map.Entry entry = (Map.Entry) o;
1224
        int n = (Integer) entry.getKey();
1225
        IntHashtable h = (IntHashtable) entry.getValue();
1226 1 1. readDocObj : removed call to com/lowagie/text/pdf/PdfReader::readObjStm → NO_COVERAGE
        readObjStm((PRStream) xrefObj.get(n), h);
1227
        xrefObj.set(n, null);
1228
      }
1229
      objStmMark = null;
1230
    }
1231
    xref = null;
1232
  }
1233
1234
  private void checkPRStreamLength(PRStream stream) throws IOException {
1235
    int fileLength = tokens.length();
1236
    int start = stream.getOffset();
1237
    boolean calc = false;
1238
    int streamLength = 0;
1239
    PdfObject obj = getPdfObjectRelease(stream.get(PdfName.LENGTH));
1240 2 1. checkPRStreamLength : negated conditional → NO_COVERAGE
2. checkPRStreamLength : negated conditional → NO_COVERAGE
    if (obj != null && obj.type() == PdfObject.NUMBER) {
1241
      streamLength = ((PdfNumber) obj).intValue();
1242 4 1. checkPRStreamLength : changed conditional boundary → NO_COVERAGE
2. checkPRStreamLength : Replaced integer addition with subtraction → NO_COVERAGE
3. checkPRStreamLength : Replaced integer subtraction with addition → NO_COVERAGE
4. checkPRStreamLength : negated conditional → NO_COVERAGE
      if (streamLength + start > fileLength - 20)
1243
        calc = true;
1244
      else {
1245 2 1. checkPRStreamLength : Replaced integer addition with subtraction → NO_COVERAGE
2. checkPRStreamLength : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
        tokens.seek(start + streamLength);
1246
        String line = tokens.readString(20);
1247 1 1. checkPRStreamLength : negated conditional → NO_COVERAGE
        if (!line.startsWith("\nendstream")
1248 1 1. checkPRStreamLength : negated conditional → NO_COVERAGE
            && !line.startsWith("\r\nendstream")
1249 2 1. checkPRStreamLength : negated conditional → NO_COVERAGE
2. checkPRStreamLength : negated conditional → NO_COVERAGE
            && !line.startsWith("\rendstream") && !line.startsWith("endstream"))
1250
          calc = true;
1251
      }
1252
    } else
1253
      calc = true;
1254 1 1. checkPRStreamLength : negated conditional → NO_COVERAGE
    if (calc) {
1255
      byte[] tline = new byte[16];
1256 1 1. checkPRStreamLength : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
      tokens.seek(start);
1257
      while (true) {
1258
        int pos = tokens.getFilePointer();
1259 1 1. checkPRStreamLength : negated conditional → NO_COVERAGE
        if (!tokens.readLineSegment(tline))
1260
          break;
1261 1 1. checkPRStreamLength : negated conditional → NO_COVERAGE
        if (equalsn(tline, endstream)) {
1262 1 1. checkPRStreamLength : Replaced integer subtraction with addition → NO_COVERAGE
          streamLength = pos - start;
1263
          break;
1264
        }
1265 1 1. checkPRStreamLength : negated conditional → NO_COVERAGE
        if (equalsn(tline, endobj)) {
1266 2 1. checkPRStreamLength : Replaced integer subtraction with addition → NO_COVERAGE
2. checkPRStreamLength : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
          tokens.seek(pos - 16);
1267
          String s = tokens.readString(16);
1268
          int index = s.indexOf("endstream");
1269 2 1. checkPRStreamLength : changed conditional boundary → NO_COVERAGE
2. checkPRStreamLength : negated conditional → NO_COVERAGE
          if (index >= 0)
1270 2 1. checkPRStreamLength : Replaced integer subtraction with addition → NO_COVERAGE
2. checkPRStreamLength : Replaced integer addition with subtraction → NO_COVERAGE
            pos = pos - 16 + index;
1271 1 1. checkPRStreamLength : Replaced integer subtraction with addition → NO_COVERAGE
          streamLength = pos - start;
1272
          break;
1273
        }
1274
      }
1275
    }
1276 1 1. checkPRStreamLength : removed call to com/lowagie/text/pdf/PRStream::setLength → NO_COVERAGE
    stream.setLength(streamLength);
1277
  }
1278
1279
  protected void readObjStm(PRStream stream, IntHashtable map)
1280
      throws IOException {
1281
    int first = stream.getAsNumber(PdfName.FIRST).intValue();
1282
    int n = stream.getAsNumber(PdfName.N).intValue();
1283
    byte[] b = getStreamBytes(stream, tokens.getFile());
1284
    PRTokeniser saveTokens = tokens;
1285
    tokens = new PRTokeniser(b);
1286
    try {
1287
      int[] address = new int[n];
1288
      int[] objNumber = new int[n];
1289
      boolean ok = true;
1290 3 1. readObjStm : changed conditional boundary → NO_COVERAGE
2. readObjStm : Changed increment from 1 to -1 → NO_COVERAGE
3. readObjStm : negated conditional → NO_COVERAGE
      for (int k = 0; k < n; ++k) {
1291
        ok = tokens.nextToken();
1292 1 1. readObjStm : negated conditional → NO_COVERAGE
        if (!ok)
1293
          break;
1294 1 1. readObjStm : negated conditional → NO_COVERAGE
        if (tokens.getTokenType() != PRTokeniser.TK_NUMBER) {
1295
          ok = false;
1296
          break;
1297
        }
1298
        objNumber[k] = tokens.intValue();
1299
        ok = tokens.nextToken();
1300 1 1. readObjStm : negated conditional → NO_COVERAGE
        if (!ok)
1301
          break;
1302 1 1. readObjStm : negated conditional → NO_COVERAGE
        if (tokens.getTokenType() != PRTokeniser.TK_NUMBER) {
1303
          ok = false;
1304
          break;
1305
        }
1306 1 1. readObjStm : Replaced integer addition with subtraction → NO_COVERAGE
        address[k] = tokens.intValue() + first;
1307
      }
1308 1 1. readObjStm : negated conditional → NO_COVERAGE
      if (!ok)
1309
        throw new InvalidPdfException(
1310
            MessageLocalization.getComposedMessage("error.reading.objstm"));
1311 3 1. readObjStm : changed conditional boundary → NO_COVERAGE
2. readObjStm : Changed increment from 1 to -1 → NO_COVERAGE
3. readObjStm : negated conditional → NO_COVERAGE
      for (int k = 0; k < n; ++k) {
1312 1 1. readObjStm : negated conditional → NO_COVERAGE
        if (map.containsKey(k)) {
1313 1 1. readObjStm : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
          tokens.seek(address[k]);
1314
          PdfObject obj = readPRObject();
1315
          xrefObj.set(objNumber[k], obj);
1316
        }
1317
      }
1318
    } finally {
1319
      tokens = saveTokens;
1320
    }
1321
  }
1322
1323
  /**
1324
   * Eliminates the reference to the object freeing the memory used by it and
1325
   * clearing the xref entry.
1326
   * 
1327
   * @param obj
1328
   *          the object. If it's an indirect reference it will be eliminated
1329
   * @return the object or the already erased dereferenced object
1330
   */
1331
  public static PdfObject killIndirect(PdfObject obj) {
1332 2 1. killIndirect : negated conditional → NO_COVERAGE
2. killIndirect : negated conditional → NO_COVERAGE
    if (obj == null || obj.isNull())
1333 1 1. killIndirect : mutated return of Object value for com/lowagie/text/pdf/PdfReader::killIndirect to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
1334
    PdfObject ret = getPdfObjectRelease(obj);
1335 1 1. killIndirect : negated conditional → NO_COVERAGE
    if (obj.isIndirect()) {
1336
      PRIndirectReference ref = (PRIndirectReference) obj;
1337
      PdfReader reader = ref.getReader();
1338
      int n = ref.getNumber();
1339
      reader.xrefObj.set(n, null);
1340 1 1. killIndirect : negated conditional → NO_COVERAGE
      if (reader.partial)
1341 1 1. killIndirect : Replaced integer multiplication with division → NO_COVERAGE
        reader.xref[n * 2] = -1;
1342
    }
1343 1 1. killIndirect : mutated return of Object value for com/lowagie/text/pdf/PdfReader::killIndirect to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return ret;
1344
  }
1345
1346
  private void ensureXrefSize(int size) {
1347 1 1. ensureXrefSize : negated conditional → NO_COVERAGE
    if (size == 0)
1348
      return;
1349 1 1. ensureXrefSize : negated conditional → NO_COVERAGE
    if (xref == null)
1350
      xref = new int[size];
1351
    else {
1352 2 1. ensureXrefSize : changed conditional boundary → NO_COVERAGE
2. ensureXrefSize : negated conditional → NO_COVERAGE
      if (xref.length < size) {
1353
        int[] xref2 = new int[size];
1354 1 1. ensureXrefSize : removed call to java/lang/System::arraycopy → NO_COVERAGE
        System.arraycopy(xref, 0, xref2, 0, xref.length);
1355
        xref = xref2;
1356
      }
1357
    }
1358
  }
1359
1360
  protected void readXref() throws IOException {
1361
    hybridXref = false;
1362
    newXrefType = false;
1363 1 1. readXref : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
    tokens.seek(tokens.getStartxref());
1364
    tokens.nextToken();
1365 1 1. readXref : negated conditional → NO_COVERAGE
    if (!tokens.getStringValue().equals("startxref"))
1366
      throw new InvalidPdfException(
1367
          MessageLocalization.getComposedMessage("startxref.not.found"));
1368
    tokens.nextToken();
1369 1 1. readXref : negated conditional → NO_COVERAGE
    if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
1370
      throw new InvalidPdfException(
1371
          MessageLocalization
1372
              .getComposedMessage("startxref.is.not.followed.by.a.number"));
1373
    int startxref = tokens.intValue();
1374
    lastXref = startxref;
1375
    eofPos = tokens.getFilePointer();
1376
    try {
1377 1 1. readXref : negated conditional → NO_COVERAGE
      if (readXRefStream(startxref)) {
1378
        newXrefType = true;
1379
        return;
1380
      }
1381
    } catch (Exception ignored) {
1382
    }
1383
    xref = null;
1384 1 1. readXref : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
    tokens.seek(startxref);
1385
    trailer = readXrefSection();
1386
    PdfDictionary trailer2 = trailer;
1387
    while (true) {
1388
      PdfNumber prev = (PdfNumber) trailer2.get(PdfName.PREV);
1389 1 1. readXref : negated conditional → NO_COVERAGE
      if (prev == null)
1390
        break;
1391 1 1. readXref : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
      tokens.seek(prev.intValue());
1392
      trailer2 = readXrefSection();
1393
    }
1394
  }
1395
1396
  protected PdfDictionary readXrefSection() throws IOException {
1397 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
    tokens.nextValidToken();
1398 1 1. readXrefSection : negated conditional → NO_COVERAGE
    if (!tokens.getStringValue().equals("xref"))
1399 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
      tokens.throwError(MessageLocalization
1400
          .getComposedMessage("xref.subsection.not.found"));
1401
    int start;
1402
    int end;
1403
    int pos;
1404
    int gen;
1405
    while (true) {
1406 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
      tokens.nextValidToken();
1407 1 1. readXrefSection : negated conditional → NO_COVERAGE
      if (tokens.getStringValue().equals("trailer"))
1408
        break;
1409 1 1. readXrefSection : negated conditional → NO_COVERAGE
      if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
1410
        tokens
1411 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
            .throwError(MessageLocalization
1412
                .getComposedMessage("object.number.of.the.first.object.in.this.xref.subsection.not.found"));
1413
      start = tokens.intValue();
1414 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
      tokens.nextValidToken();
1415 1 1. readXrefSection : negated conditional → NO_COVERAGE
      if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
1416
        tokens
1417 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
            .throwError(MessageLocalization
1418
                .getComposedMessage("number.of.entries.in.this.xref.subsection.not.found"));
1419 1 1. readXrefSection : Replaced integer addition with subtraction → NO_COVERAGE
      end = tokens.intValue() + start;
1420 1 1. readXrefSection : negated conditional → NO_COVERAGE
      if (start == 1) { // fix incorrect start number
1421
        int back = tokens.getFilePointer();
1422 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
        tokens.nextValidToken();
1423
        pos = tokens.intValue();
1424 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
        tokens.nextValidToken();
1425
        gen = tokens.intValue();
1426 2 1. readXrefSection : negated conditional → NO_COVERAGE
2. readXrefSection : negated conditional → NO_COVERAGE
        if (pos == 0 && gen == PdfWriter.GENERATION_MAX) {
1427 1 1. readXrefSection : Changed increment from -1 to 1 → NO_COVERAGE
          --start;
1428 1 1. readXrefSection : Changed increment from -1 to 1 → NO_COVERAGE
          --end;
1429
        }
1430 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
        tokens.seek(back);
1431
      }
1432 2 1. readXrefSection : Replaced integer multiplication with division → NO_COVERAGE
2. readXrefSection : removed call to com/lowagie/text/pdf/PdfReader::ensureXrefSize → NO_COVERAGE
      ensureXrefSize(end * 2);
1433 3 1. readXrefSection : changed conditional boundary → NO_COVERAGE
2. readXrefSection : Changed increment from 1 to -1 → NO_COVERAGE
3. readXrefSection : negated conditional → NO_COVERAGE
      for (int k = start; k < end; ++k) {
1434 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
        tokens.nextValidToken();
1435
        pos = tokens.intValue();
1436 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
        tokens.nextValidToken();
1437 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
        tokens.nextValidToken();
1438 1 1. readXrefSection : Replaced integer multiplication with division → NO_COVERAGE
        int p = k * 2;
1439 1 1. readXrefSection : negated conditional → NO_COVERAGE
        if (tokens.getStringValue().equals("n")) {
1440 3 1. readXrefSection : Replaced integer addition with subtraction → NO_COVERAGE
2. readXrefSection : negated conditional → NO_COVERAGE
3. readXrefSection : negated conditional → NO_COVERAGE
          if (xref[p] == 0 && xref[p + 1] == 0) {
1441
            // if (pos == 0)
1442
            // tokens.throwError(MessageLocalization.getComposedMessage("file.position.0.cross.reference.entry.in.this.xref.subsection"));
1443
            xref[p] = pos;
1444
          }
1445 1 1. readXrefSection : negated conditional → NO_COVERAGE
        } else if (tokens.getStringValue().equals("f")) {
1446 3 1. readXrefSection : Replaced integer addition with subtraction → NO_COVERAGE
2. readXrefSection : negated conditional → NO_COVERAGE
3. readXrefSection : negated conditional → NO_COVERAGE
          if (xref[p] == 0 && xref[p + 1] == 0)
1447
            xref[p] = -1;
1448
        } else
1449
          tokens
1450 1 1. readXrefSection : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
              .throwError(MessageLocalization
1451
                  .getComposedMessage("invalid.cross.reference.entry.in.this.xref.subsection"));
1452
      }
1453
    }
1454
    PdfDictionary trailer = (PdfDictionary) readPRObject();
1455
    PdfNumber xrefSize = (PdfNumber) trailer.get(PdfName.SIZE);
1456 2 1. readXrefSection : Replaced integer multiplication with division → NO_COVERAGE
2. readXrefSection : removed call to com/lowagie/text/pdf/PdfReader::ensureXrefSize → NO_COVERAGE
    ensureXrefSize(xrefSize.intValue() * 2);
1457
    PdfObject xrs = trailer.get(PdfName.XREFSTM);
1458 2 1. readXrefSection : negated conditional → NO_COVERAGE
2. readXrefSection : negated conditional → NO_COVERAGE
    if (xrs != null && xrs.isNumber()) {
1459
      int loc = ((PdfNumber) xrs).intValue();
1460
      try {
1461
        readXRefStream(loc);
1462
        newXrefType = true;
1463
        hybridXref = true;
1464
      } catch (IOException e) {
1465
        xref = null;
1466
        throw e;
1467
      }
1468
    }
1469 1 1. readXrefSection : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readXrefSection to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return trailer;
1470
  }
1471
1472
  protected boolean readXRefStream(int ptr) throws IOException {
1473 1 1. readXRefStream : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
    tokens.seek(ptr);
1474
    int thisStream;
1475 1 1. readXRefStream : negated conditional → NO_COVERAGE
    if (!tokens.nextToken())
1476 1 1. readXRefStream : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
      return false;
1477 1 1. readXRefStream : negated conditional → NO_COVERAGE
    if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
1478 1 1. readXRefStream : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
      return false;
1479
    thisStream = tokens.intValue();
1480 2 1. readXRefStream : negated conditional → NO_COVERAGE
2. readXRefStream : negated conditional → NO_COVERAGE
    if (!tokens.nextToken() || tokens.getTokenType() != PRTokeniser.TK_NUMBER)
1481 1 1. readXRefStream : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
      return false;
1482 2 1. readXRefStream : negated conditional → NO_COVERAGE
2. readXRefStream : negated conditional → NO_COVERAGE
    if (!tokens.nextToken() || !tokens.getStringValue().equals("obj"))
1483 1 1. readXRefStream : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
      return false;
1484
    PdfObject object = readPRObject();
1485
    PRStream stm;
1486 1 1. readXRefStream : negated conditional → NO_COVERAGE
    if (object.isStream()) {
1487
      stm = (PRStream) object;
1488 1 1. readXRefStream : negated conditional → NO_COVERAGE
      if (!PdfName.XREF.equals(stm.get(PdfName.TYPE)))
1489 1 1. readXRefStream : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
        return false;
1490
    } else
1491 1 1. readXRefStream : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
      return false;
1492 1 1. readXRefStream : negated conditional → NO_COVERAGE
    if (trailer == null) {
1493
      trailer = new PdfDictionary();
1494 1 1. readXRefStream : removed call to com/lowagie/text/pdf/PdfDictionary::putAll → NO_COVERAGE
      trailer.putAll(stm);
1495
    }
1496 1 1. readXRefStream : removed call to com/lowagie/text/pdf/PRStream::setLength → NO_COVERAGE
    stm.setLength(((PdfNumber) stm.get(PdfName.LENGTH)).intValue());
1497
    int size = ((PdfNumber) stm.get(PdfName.SIZE)).intValue();
1498
    PdfArray index;
1499
    PdfObject obj = stm.get(PdfName.INDEX);
1500 1 1. readXRefStream : negated conditional → NO_COVERAGE
    if (obj == null) {
1501
      index = new PdfArray();
1502
      index.add(new int[] { 0, size });
1503
    } else
1504
      index = (PdfArray) obj;
1505
    PdfArray w = (PdfArray) stm.get(PdfName.W);
1506
    int prev = -1;
1507
    obj = stm.get(PdfName.PREV);
1508 1 1. readXRefStream : negated conditional → NO_COVERAGE
    if (obj != null)
1509
      prev = ((PdfNumber) obj).intValue();
1510
    // Each xref pair is a position
1511
    // type 0 -> -1, 0
1512
    // type 1 -> offset, 0
1513
    // type 2 -> index, obj num
1514 2 1. readXRefStream : Replaced integer multiplication with division → NO_COVERAGE
2. readXRefStream : removed call to com/lowagie/text/pdf/PdfReader::ensureXrefSize → NO_COVERAGE
    ensureXrefSize(size * 2);
1515 2 1. readXRefStream : negated conditional → NO_COVERAGE
2. readXRefStream : negated conditional → NO_COVERAGE
    if (objStmMark == null && !partial)
1516
      objStmMark = new HashMap<>();
1517 2 1. readXRefStream : negated conditional → NO_COVERAGE
2. readXRefStream : negated conditional → NO_COVERAGE
    if (objStmToOffset == null && partial)
1518
      objStmToOffset = new IntHashtable();
1519
    byte[] b = getStreamBytes(stm, tokens.getFile());
1520
    int bptr = 0;
1521
    int[] wc = new int[3];
1522 3 1. readXRefStream : changed conditional boundary → NO_COVERAGE
2. readXRefStream : Changed increment from 1 to -1 → NO_COVERAGE
3. readXRefStream : negated conditional → NO_COVERAGE
    for (int k = 0; k < 3; ++k)
1523
      wc[k] = w.getAsNumber(k).intValue();
1524 3 1. readXRefStream : changed conditional boundary → NO_COVERAGE
2. readXRefStream : Changed increment from 2 to -2 → NO_COVERAGE
3. readXRefStream : negated conditional → NO_COVERAGE
    for (int idx = 0; idx < index.size(); idx += 2) {
1525
      int start = index.getAsNumber(idx).intValue();
1526 1 1. readXRefStream : Replaced integer addition with subtraction → NO_COVERAGE
      int length = index.getAsNumber(idx + 1).intValue();
1527 3 1. readXRefStream : Replaced integer addition with subtraction → NO_COVERAGE
2. readXRefStream : Replaced integer multiplication with division → NO_COVERAGE
3. readXRefStream : removed call to com/lowagie/text/pdf/PdfReader::ensureXrefSize → NO_COVERAGE
      ensureXrefSize((start + length) * 2);
1528 3 1. readXRefStream : changed conditional boundary → NO_COVERAGE
2. readXRefStream : Changed increment from -1 to 1 → NO_COVERAGE
3. readXRefStream : negated conditional → NO_COVERAGE
      while (length-- > 0) {
1529
        int type = 1;
1530 2 1. readXRefStream : changed conditional boundary → NO_COVERAGE
2. readXRefStream : negated conditional → NO_COVERAGE
        if (wc[0] > 0) {
1531
          type = 0;
1532 3 1. readXRefStream : changed conditional boundary → NO_COVERAGE
2. readXRefStream : Changed increment from 1 to -1 → NO_COVERAGE
3. readXRefStream : negated conditional → NO_COVERAGE
          for (int k = 0; k < wc[0]; ++k)
1533 4 1. readXRefStream : Changed increment from 1 to -1 → NO_COVERAGE
2. readXRefStream : Replaced Shift Left with Shift Right → NO_COVERAGE
3. readXRefStream : Replaced bitwise AND with OR → NO_COVERAGE
4. readXRefStream : Replaced integer addition with subtraction → NO_COVERAGE
            type = (type << 8) + (b[bptr++] & 0xff);
1534
        }
1535
        int field2 = 0;
1536 3 1. readXRefStream : changed conditional boundary → NO_COVERAGE
2. readXRefStream : Changed increment from 1 to -1 → NO_COVERAGE
3. readXRefStream : negated conditional → NO_COVERAGE
        for (int k = 0; k < wc[1]; ++k)
1537 4 1. readXRefStream : Changed increment from 1 to -1 → NO_COVERAGE
2. readXRefStream : Replaced Shift Left with Shift Right → NO_COVERAGE
3. readXRefStream : Replaced bitwise AND with OR → NO_COVERAGE
4. readXRefStream : Replaced integer addition with subtraction → NO_COVERAGE
          field2 = (field2 << 8) + (b[bptr++] & 0xff);
1538
        int field3 = 0;
1539 3 1. readXRefStream : changed conditional boundary → NO_COVERAGE
2. readXRefStream : Changed increment from 1 to -1 → NO_COVERAGE
3. readXRefStream : negated conditional → NO_COVERAGE
        for (int k = 0; k < wc[2]; ++k)
1540 4 1. readXRefStream : Changed increment from 1 to -1 → NO_COVERAGE
2. readXRefStream : Replaced Shift Left with Shift Right → NO_COVERAGE
3. readXRefStream : Replaced bitwise AND with OR → NO_COVERAGE
4. readXRefStream : Replaced integer addition with subtraction → NO_COVERAGE
          field3 = (field3 << 8) + (b[bptr++] & 0xff);
1541 1 1. readXRefStream : Replaced integer multiplication with division → NO_COVERAGE
        int base = start * 2;
1542 3 1. readXRefStream : Replaced integer addition with subtraction → NO_COVERAGE
2. readXRefStream : negated conditional → NO_COVERAGE
3. readXRefStream : negated conditional → NO_COVERAGE
        if (xref[base] == 0 && xref[base + 1] == 0) {
1543
          switch (type) {
1544
          case 0:
1545
            xref[base] = -1;
1546
            break;
1547
          case 1:
1548
            xref[base] = field2;
1549
            break;
1550
          case 2:
1551
            xref[base] = field3;
1552 1 1. readXRefStream : Replaced integer addition with subtraction → NO_COVERAGE
            xref[base + 1] = field2;
1553 1 1. readXRefStream : negated conditional → NO_COVERAGE
            if (partial) {
1554
              objStmToOffset.put(field2, 0);
1555
            } else {
1556
              Integer on = field2;
1557
              IntHashtable seq = objStmMark.get(on);
1558 1 1. readXRefStream : negated conditional → NO_COVERAGE
              if (seq == null) {
1559
                seq = new IntHashtable();
1560
                seq.put(field3, 1);
1561
                objStmMark.put(on, seq);
1562
              } else
1563
                seq.put(field3, 1);
1564
            }
1565
            break;
1566
          }
1567
        }
1568 1 1. readXRefStream : Changed increment from 1 to -1 → NO_COVERAGE
        ++start;
1569
      }
1570
    }
1571 1 1. readXRefStream : Replaced integer multiplication with division → NO_COVERAGE
    thisStream *= 2;
1572 2 1. readXRefStream : changed conditional boundary → NO_COVERAGE
2. readXRefStream : negated conditional → NO_COVERAGE
    if (thisStream < xref.length)
1573
      xref[thisStream] = -1;
1574
1575 1 1. readXRefStream : negated conditional → NO_COVERAGE
    if (prev == -1)
1576 1 1. readXRefStream : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
      return true;
1577 1 1. readXRefStream : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
    return readXRefStream(prev);
1578
  }
1579
1580
  protected void rebuildXref() throws IOException {
1581
    hybridXref = false;
1582
    newXrefType = false;
1583 1 1. rebuildXref : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
    tokens.seek(0);
1584
    int[][] xr = new int[1024][];
1585
    int top = 0;
1586
    trailer = null;
1587
    byte[] line = new byte[64];
1588
    for (;;) {
1589
      int pos = tokens.getFilePointer();
1590 1 1. rebuildXref : negated conditional → NO_COVERAGE
      if (!tokens.readLineSegment(line))
1591
        break;
1592 1 1. rebuildXref : negated conditional → NO_COVERAGE
      if (line[0] == 't') {
1593 1 1. rebuildXref : negated conditional → NO_COVERAGE
        if (!PdfEncodings.convertToString(line, null).startsWith("trailer"))
1594
          continue;
1595 1 1. rebuildXref : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
        tokens.seek(pos);
1596
        tokens.nextToken();
1597
        pos = tokens.getFilePointer();
1598
        try {
1599
          PdfDictionary dic = (PdfDictionary) readPRObject();
1600 1 1. rebuildXref : negated conditional → NO_COVERAGE
          if (dic.get(PdfName.ROOT) != null)
1601
            trailer = dic;
1602
          else
1603 1 1. rebuildXref : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
            tokens.seek(pos);
1604
        } catch (Exception e) {
1605 1 1. rebuildXref : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
          tokens.seek(pos);
1606
        }
1607 4 1. rebuildXref : changed conditional boundary → NO_COVERAGE
2. rebuildXref : changed conditional boundary → NO_COVERAGE
3. rebuildXref : negated conditional → NO_COVERAGE
4. rebuildXref : negated conditional → NO_COVERAGE
      } else if (line[0] >= '0' && line[0] <= '9') {
1608
        int[] obj = PRTokeniser.checkObjectStart(line);
1609 1 1. rebuildXref : negated conditional → NO_COVERAGE
        if (obj == null)
1610
          continue;
1611
        int num = obj[0];
1612
        int gen = obj[1];
1613 2 1. rebuildXref : changed conditional boundary → NO_COVERAGE
2. rebuildXref : negated conditional → NO_COVERAGE
        if (num >= xr.length) {
1614 1 1. rebuildXref : Replaced integer multiplication with division → NO_COVERAGE
          int newLength = num * 2;
1615
          int[][] xr2 = new int[newLength][];
1616 1 1. rebuildXref : removed call to java/lang/System::arraycopy → NO_COVERAGE
          System.arraycopy(xr, 0, xr2, 0, top);
1617
          xr = xr2;
1618
        }
1619 2 1. rebuildXref : changed conditional boundary → NO_COVERAGE
2. rebuildXref : negated conditional → NO_COVERAGE
        if (num >= top)
1620 1 1. rebuildXref : Replaced integer addition with subtraction → NO_COVERAGE
          top = num + 1;
1621 3 1. rebuildXref : changed conditional boundary → NO_COVERAGE
2. rebuildXref : negated conditional → NO_COVERAGE
3. rebuildXref : negated conditional → NO_COVERAGE
        if (xr[num] == null || gen >= xr[num][1]) {
1622
          obj[0] = pos;
1623
          xr[num] = obj;
1624
        }
1625
      }
1626
    }
1627 1 1. rebuildXref : Replaced integer multiplication with division → NO_COVERAGE
    xref = new int[top * 2];
1628 3 1. rebuildXref : changed conditional boundary → NO_COVERAGE
2. rebuildXref : Changed increment from 1 to -1 → NO_COVERAGE
3. rebuildXref : negated conditional → NO_COVERAGE
    for (int k = 0; k < top; ++k) {
1629
      int[] obj = xr[k];
1630 1 1. rebuildXref : negated conditional → NO_COVERAGE
      if (obj != null)
1631 1 1. rebuildXref : Replaced integer multiplication with division → NO_COVERAGE
        xref[k * 2] = obj[0];
1632
    }
1633
  }
1634
1635
  protected PdfDictionary readDictionary() throws IOException {
1636
    PdfDictionary dic = new PdfDictionary();
1637
    while (true) {
1638 1 1. readDictionary : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
      tokens.nextValidToken();
1639 1 1. readDictionary : negated conditional → NO_COVERAGE
      if (tokens.getTokenType() == PRTokeniser.TK_END_DIC)
1640
        break;
1641 1 1. readDictionary : negated conditional → NO_COVERAGE
      if (tokens.getTokenType() != PRTokeniser.TK_NAME)
1642 1 1. readDictionary : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
        tokens.throwError(MessageLocalization
1643
            .getComposedMessage("dictionary.key.is.not.a.name"));
1644
      PdfName name = new PdfName(tokens.getStringValue(), false);
1645
      PdfObject obj = readPRObject();
1646
      int type = obj.type();
1647 2 1. readDictionary : removed negation → NO_COVERAGE
2. readDictionary : negated conditional → NO_COVERAGE
      if (-type == PRTokeniser.TK_END_DIC)
1648 1 1. readDictionary : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
        tokens.throwError(MessageLocalization
1649
            .getComposedMessage("unexpected.gt.gt"));
1650 2 1. readDictionary : removed negation → NO_COVERAGE
2. readDictionary : negated conditional → NO_COVERAGE
      if (-type == PRTokeniser.TK_END_ARRAY)
1651 1 1. readDictionary : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
        tokens.throwError(MessageLocalization
1652
            .getComposedMessage("unexpected.close.bracket"));
1653 1 1. readDictionary : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE
      dic.put(name, obj);
1654
    }
1655 1 1. readDictionary : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readDictionary to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return dic;
1656
  }
1657
1658
  protected PdfArray readArray() throws IOException {
1659
    PdfArray array = new PdfArray();
1660
    while (true) {
1661
      PdfObject obj = readPRObject();
1662
      int type = obj.type();
1663 2 1. readArray : removed negation → NO_COVERAGE
2. readArray : negated conditional → NO_COVERAGE
      if (-type == PRTokeniser.TK_END_ARRAY)
1664
        break;
1665 2 1. readArray : removed negation → NO_COVERAGE
2. readArray : negated conditional → NO_COVERAGE
      if (-type == PRTokeniser.TK_END_DIC)
1666 1 1. readArray : removed call to com/lowagie/text/pdf/PRTokeniser::throwError → NO_COVERAGE
        tokens.throwError(MessageLocalization
1667
            .getComposedMessage("unexpected.gt.gt"));
1668
      array.add(obj);
1669
    }
1670 1 1. readArray : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readArray to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return array;
1671
  }
1672
1673
  // Track how deeply nested the current object is, so
1674
  // we know when to return an individual null or boolean, or
1675
  // reuse one of the static ones.
1676
  private int readDepth = 0;
1677
1678
  protected PdfObject readPRObject() throws IOException {
1679 1 1. readPRObject : removed call to com/lowagie/text/pdf/PRTokeniser::nextValidToken → NO_COVERAGE
    tokens.nextValidToken();
1680
    int type = tokens.getTokenType();
1681
    switch (type) {
1682
    case PRTokeniser.TK_START_DIC: {
1683 1 1. readPRObject : Replaced integer addition with subtraction → NO_COVERAGE
      ++readDepth;
1684
      PdfDictionary dic = readDictionary();
1685 1 1. readPRObject : Replaced integer subtraction with addition → NO_COVERAGE
      --readDepth;
1686
      int pos = tokens.getFilePointer();
1687
      // be careful in the trailer. May not be a "next" token.
1688
      boolean hasNext;
1689
      do {
1690
        hasNext = tokens.nextToken();
1691 2 1. readPRObject : negated conditional → NO_COVERAGE
2. readPRObject : negated conditional → NO_COVERAGE
      } while (hasNext && tokens.getTokenType() == PRTokeniser.TK_COMMENT);
1692
1693 2 1. readPRObject : negated conditional → NO_COVERAGE
2. readPRObject : negated conditional → NO_COVERAGE
      if (hasNext && tokens.getStringValue().equals("stream")) {
1694
        // skip whitespaces
1695
        int ch;
1696
        do {
1697
          ch = tokens.read();
1698 4 1. readPRObject : negated conditional → NO_COVERAGE
2. readPRObject : negated conditional → NO_COVERAGE
3. readPRObject : negated conditional → NO_COVERAGE
4. readPRObject : negated conditional → NO_COVERAGE
        } while (ch == 32 || ch == 9 || ch == 0 || ch == 12);
1699 1 1. readPRObject : negated conditional → NO_COVERAGE
        if (ch != '\n')
1700
          ch = tokens.read();
1701 1 1. readPRObject : negated conditional → NO_COVERAGE
        if (ch != '\n')
1702 1 1. readPRObject : removed call to com/lowagie/text/pdf/PRTokeniser::backOnePosition → NO_COVERAGE
          tokens.backOnePosition(ch);
1703
        PRStream stream = new PRStream(this, tokens.getFilePointer());
1704 1 1. readPRObject : removed call to com/lowagie/text/pdf/PRStream::putAll → NO_COVERAGE
        stream.putAll(dic);
1705
        // crypto handling
1706 1 1. readPRObject : removed call to com/lowagie/text/pdf/PRStream::setObjNum → NO_COVERAGE
        stream.setObjNum(objNum, objGen);
1707
1708 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return stream;
1709
      } else {
1710 1 1. readPRObject : removed call to com/lowagie/text/pdf/PRTokeniser::seek → NO_COVERAGE
        tokens.seek(pos);
1711 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return dic;
1712
      }
1713
    }
1714
    case PRTokeniser.TK_START_ARRAY: {
1715 1 1. readPRObject : Replaced integer addition with subtraction → NO_COVERAGE
      ++readDepth;
1716
      PdfArray arr = readArray();
1717 1 1. readPRObject : Replaced integer subtraction with addition → NO_COVERAGE
      --readDepth;
1718 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return arr;
1719
    }
1720
    case PRTokeniser.TK_NUMBER:
1721 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return new PdfNumber(tokens.getStringValue());
1722
    case PRTokeniser.TK_STRING:
1723
      PdfString str = new PdfString(tokens.getStringValue(), null)
1724
          .setHexWriting(tokens.isHexString());
1725
      // crypto handling
1726 1 1. readPRObject : removed call to com/lowagie/text/pdf/PdfString::setObjNum → NO_COVERAGE
      str.setObjNum(objNum, objGen);
1727 1 1. readPRObject : negated conditional → NO_COVERAGE
      if (strings != null)
1728
        strings.add(str);
1729
1730 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return str;
1731
    case PRTokeniser.TK_NAME: {
1732
      PdfName cachedName = PdfName.staticNames.get(tokens
1733
          .getStringValue());
1734 3 1. readPRObject : changed conditional boundary → NO_COVERAGE
2. readPRObject : negated conditional → NO_COVERAGE
3. readPRObject : negated conditional → NO_COVERAGE
      if (readDepth > 0 && cachedName != null) {
1735 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return cachedName;
1736
      } else {
1737
        // an indirect name (how odd...), or a non-standard one
1738 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return new PdfName(tokens.getStringValue(), false);
1739
      }
1740
    }
1741
    case PRTokeniser.TK_REF:
1742
      int num = tokens.getReference();
1743
      PRIndirectReference ref = new PRIndirectReference(this, num,
1744
          tokens.getGeneration());
1745 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return ref;
1746
    case PRTokeniser.TK_ENDOFFILE:
1747
      throw new IOException(
1748
          MessageLocalization.getComposedMessage("unexpected.end.of.file"));
1749
    default:
1750
      String sv = tokens.getStringValue();
1751 1 1. readPRObject : negated conditional → NO_COVERAGE
      if ("null".equals(sv)) {
1752 1 1. readPRObject : negated conditional → NO_COVERAGE
        if (readDepth == 0) {
1753 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
          return new PdfNull();
1754
        } // else
1755 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return PdfNull.PDFNULL;
1756 1 1. readPRObject : negated conditional → NO_COVERAGE
      } else if ("true".equals(sv)) {
1757 1 1. readPRObject : negated conditional → NO_COVERAGE
        if (readDepth == 0) {
1758 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
          return new PdfBoolean(true);
1759
        } // else
1760 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return PdfBoolean.PDFTRUE;
1761 1 1. readPRObject : negated conditional → NO_COVERAGE
      } else if ("false".equals(sv)) {
1762 1 1. readPRObject : negated conditional → NO_COVERAGE
        if (readDepth == 0) {
1763 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
          return new PdfBoolean(false);
1764
        } // else
1765 1 1. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return PdfBoolean.PDFFALSE;
1766
      }
1767 2 1. readPRObject : removed negation → NO_COVERAGE
2. readPRObject : mutated return of Object value for com/lowagie/text/pdf/PdfReader::readPRObject to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return new PdfLiteral(-type, tokens.getStringValue());
1768
    }
1769
  }
1770
1771
  /**
1772
   * Decodes a stream that has the FlateDecode filter.
1773
   * 
1774
   * @param in
1775
   *          the input data
1776
   * @return the decoded data
1777
   */
1778
  public static byte[] FlateDecode(byte[] in) {
1779
    byte[] b = FlateDecode(in, true);
1780 1 1. FlateDecode : negated conditional → NO_COVERAGE
    if (b == null)
1781 1 1. FlateDecode : mutated return of Object value for com/lowagie/text/pdf/PdfReader::FlateDecode to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return FlateDecode(in, false);
1782 1 1. FlateDecode : mutated return of Object value for com/lowagie/text/pdf/PdfReader::FlateDecode to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return b;
1783
  }
1784
1785
  /**
1786
   * @return a byte array
1787
   */
1788
  public static byte[] decodePredictor(byte[] in, PdfObject dicPar) {
1789 2 1. decodePredictor : negated conditional → NO_COVERAGE
2. decodePredictor : negated conditional → NO_COVERAGE
    if (dicPar == null || !dicPar.isDictionary())
1790 1 1. decodePredictor : mutated return of Object value for com/lowagie/text/pdf/PdfReader::decodePredictor to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return in;
1791
    PdfDictionary dic = (PdfDictionary) dicPar;
1792
    PdfObject obj = getPdfObject(dic.get(PdfName.PREDICTOR));
1793 2 1. decodePredictor : negated conditional → NO_COVERAGE
2. decodePredictor : negated conditional → NO_COVERAGE
    if (obj == null || !obj.isNumber())
1794 1 1. decodePredictor : mutated return of Object value for com/lowagie/text/pdf/PdfReader::decodePredictor to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return in;
1795
    int predictor = ((PdfNumber) obj).intValue();
1796 2 1. decodePredictor : changed conditional boundary → NO_COVERAGE
2. decodePredictor : negated conditional → NO_COVERAGE
    if (predictor < 10)
1797 1 1. decodePredictor : mutated return of Object value for com/lowagie/text/pdf/PdfReader::decodePredictor to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return in;
1798
    int width = 1;
1799
    obj = getPdfObject(dic.get(PdfName.COLUMNS));
1800 2 1. decodePredictor : negated conditional → NO_COVERAGE
2. decodePredictor : negated conditional → NO_COVERAGE
    if (obj != null && obj.isNumber())
1801
      width = ((PdfNumber) obj).intValue();
1802
    int colors = 1;
1803
    obj = getPdfObject(dic.get(PdfName.COLORS));
1804 2 1. decodePredictor : negated conditional → NO_COVERAGE
2. decodePredictor : negated conditional → NO_COVERAGE
    if (obj != null && obj.isNumber())
1805
      colors = ((PdfNumber) obj).intValue();
1806
    int bpc = 8;
1807
    obj = getPdfObject(dic.get(PdfName.BITSPERCOMPONENT));
1808 2 1. decodePredictor : negated conditional → NO_COVERAGE
2. decodePredictor : negated conditional → NO_COVERAGE
    if (obj != null && obj.isNumber())
1809
      bpc = ((PdfNumber) obj).intValue();
1810
    DataInputStream dataStream = new DataInputStream(new ByteArrayInputStream(
1811
        in));
1812
    ByteArrayOutputStream fout = new ByteArrayOutputStream(in.length);
1813 2 1. decodePredictor : Replaced integer multiplication with division → NO_COVERAGE
2. decodePredictor : Replaced integer division with multiplication → NO_COVERAGE
    int bytesPerPixel = colors * bpc / 8;
1814 4 1. decodePredictor : Replaced integer multiplication with division → NO_COVERAGE
2. decodePredictor : Replaced integer multiplication with division → NO_COVERAGE
3. decodePredictor : Replaced integer addition with subtraction → NO_COVERAGE
4. decodePredictor : Replaced integer division with multiplication → NO_COVERAGE
    int bytesPerRow = (colors * width * bpc + 7) / 8;
1815
    byte[] curr = new byte[bytesPerRow];
1816
    byte[] prior = new byte[bytesPerRow];
1817
1818
    // Decode the (sub)image row-by-row
1819
    while (true) {
1820
      // Read the filter type byte and a row of data
1821
      int filter;
1822
      try {
1823
        filter = dataStream.read();
1824 2 1. decodePredictor : changed conditional boundary → NO_COVERAGE
2. decodePredictor : negated conditional → NO_COVERAGE
        if (filter < 0) {
1825 1 1. decodePredictor : mutated return of Object value for com/lowagie/text/pdf/PdfReader::decodePredictor to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
          return fout.toByteArray();
1826
        }
1827 1 1. decodePredictor : removed call to java/io/DataInputStream::readFully → NO_COVERAGE
        dataStream.readFully(curr, 0, bytesPerRow);
1828
      } catch (Exception e) {
1829 1 1. decodePredictor : mutated return of Object value for com/lowagie/text/pdf/PdfReader::decodePredictor to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return fout.toByteArray();
1830
      }
1831
1832
      switch (filter) {
1833
      case 0: // PNG_FILTER_NONE
1834
        break;
1835
      case 1: // PNG_FILTER_SUB
1836 3 1. decodePredictor : changed conditional boundary → NO_COVERAGE
2. decodePredictor : Changed increment from 1 to -1 → NO_COVERAGE
3. decodePredictor : negated conditional → NO_COVERAGE
        for (int i = bytesPerPixel; i < bytesPerRow; i++) {
1837 2 1. decodePredictor : Replaced integer subtraction with addition → NO_COVERAGE
2. decodePredictor : Replaced integer addition with subtraction → NO_COVERAGE
          curr[i] += curr[i - bytesPerPixel];
1838
        }
1839
        break;
1840
      case 2: // PNG_FILTER_UP
1841 3 1. decodePredictor : changed conditional boundary → NO_COVERAGE
2. decodePredictor : Changed increment from 1 to -1 → NO_COVERAGE
3. decodePredictor : negated conditional → NO_COVERAGE
        for (int i = 0; i < bytesPerRow; i++) {
1842 1 1. decodePredictor : Replaced integer addition with subtraction → NO_COVERAGE
          curr[i] += prior[i];
1843
        }
1844
        break;
1845
      case 3: // PNG_FILTER_AVERAGE
1846 3 1. decodePredictor : changed conditional boundary → NO_COVERAGE
2. decodePredictor : Changed increment from 1 to -1 → NO_COVERAGE
3. decodePredictor : negated conditional → NO_COVERAGE
        for (int i = 0; i < bytesPerPixel; i++) {
1847 2 1. decodePredictor : Replaced integer division with multiplication → NO_COVERAGE
2. decodePredictor : Replaced integer addition with subtraction → NO_COVERAGE
          curr[i] += prior[i] / 2;
1848
        }
1849 3 1. decodePredictor : changed conditional boundary → NO_COVERAGE
2. decodePredictor : Changed increment from 1 to -1 → NO_COVERAGE
3. decodePredictor : negated conditional → NO_COVERAGE
        for (int i = bytesPerPixel; i < bytesPerRow; i++) {
1850 6 1. decodePredictor : Replaced integer subtraction with addition → NO_COVERAGE
2. decodePredictor : Replaced bitwise AND with OR → NO_COVERAGE
3. decodePredictor : Replaced bitwise AND with OR → NO_COVERAGE
4. decodePredictor : Replaced integer addition with subtraction → NO_COVERAGE
5. decodePredictor : Replaced integer division with multiplication → NO_COVERAGE
6. decodePredictor : Replaced integer addition with subtraction → NO_COVERAGE
          curr[i] += ((curr[i - bytesPerPixel] & 0xff) + (prior[i] & 0xff)) / 2;
1851
        }
1852
        break;
1853
      case 4: // PNG_FILTER_PAETH
1854 3 1. decodePredictor : changed conditional boundary → NO_COVERAGE
2. decodePredictor : Changed increment from 1 to -1 → NO_COVERAGE
3. decodePredictor : negated conditional → NO_COVERAGE
        for (int i = 0; i < bytesPerPixel; i++) {
1855 1 1. decodePredictor : Replaced integer addition with subtraction → NO_COVERAGE
          curr[i] += prior[i];
1856
        }
1857
1858 3 1. decodePredictor : changed conditional boundary → NO_COVERAGE
2. decodePredictor : Changed increment from 1 to -1 → NO_COVERAGE
3. decodePredictor : negated conditional → NO_COVERAGE
        for (int i = bytesPerPixel; i < bytesPerRow; i++) {
1859 2 1. decodePredictor : Replaced integer subtraction with addition → NO_COVERAGE
2. decodePredictor : Replaced bitwise AND with OR → NO_COVERAGE
          int a = curr[i - bytesPerPixel] & 0xff;
1860 1 1. decodePredictor : Replaced bitwise AND with OR → NO_COVERAGE
          int b = prior[i] & 0xff;
1861 2 1. decodePredictor : Replaced integer subtraction with addition → NO_COVERAGE
2. decodePredictor : Replaced bitwise AND with OR → NO_COVERAGE
          int c = prior[i - bytesPerPixel] & 0xff;
1862
1863 2 1. decodePredictor : Replaced integer addition with subtraction → NO_COVERAGE
2. decodePredictor : Replaced integer subtraction with addition → NO_COVERAGE
          int p = a + b - c;
1864 1 1. decodePredictor : Replaced integer subtraction with addition → NO_COVERAGE
          int pa = Math.abs(p - a);
1865 1 1. decodePredictor : Replaced integer subtraction with addition → NO_COVERAGE
          int pb = Math.abs(p - b);
1866 1 1. decodePredictor : Replaced integer subtraction with addition → NO_COVERAGE
          int pc = Math.abs(p - c);
1867
1868
          int ret;
1869
1870 4 1. decodePredictor : changed conditional boundary → NO_COVERAGE
2. decodePredictor : changed conditional boundary → NO_COVERAGE
3. decodePredictor : negated conditional → NO_COVERAGE
4. decodePredictor : negated conditional → NO_COVERAGE
          if ((pa <= pb) && (pa <= pc)) {
1871
            ret = a;
1872 2 1. decodePredictor : changed conditional boundary → NO_COVERAGE
2. decodePredictor : negated conditional → NO_COVERAGE
          } else if (pb <= pc) {
1873
            ret = b;
1874
          } else {
1875
            ret = c;
1876
          }
1877 1 1. decodePredictor : Replaced integer addition with subtraction → NO_COVERAGE
          curr[i] += (byte) (ret);
1878
        }
1879
        break;
1880
      default:
1881
        // Error -- unknown filter type
1882
        throw new RuntimeException(
1883
            MessageLocalization.getComposedMessage("png.filter.unknown"));
1884
      }
1885
      try {
1886 1 1. decodePredictor : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
        fout.write(curr);
1887
      } catch (IOException ioe) {
1888
        // Never happens
1889
      }
1890
1891
      // Swap curr and prior
1892
      byte[] tmp = prior;
1893
      prior = curr;
1894
      curr = tmp;
1895
    }
1896
  }
1897
1898
  /**
1899
   * A helper to FlateDecode.
1900
   * 
1901
   * @param in
1902
   *          the input data
1903
   * @param strict
1904
   *          <CODE>true</CODE> to read a correct stream. <CODE>false</CODE> to
1905
   *          try to read a corrupted stream
1906
   * @return the decoded data
1907
   */
1908
  public static byte[] FlateDecode(byte[] in, boolean strict) {
1909
    ByteArrayInputStream stream = new ByteArrayInputStream(in);
1910
    InflaterInputStream zip = new InflaterInputStream(stream);
1911
    ByteArrayOutputStream out = new ByteArrayOutputStream();
1912 1 1. FlateDecode : negated conditional → NO_COVERAGE
    byte[] b = new byte[strict ? 4092 : 1];
1913
    try {
1914
      int n;
1915 2 1. FlateDecode : changed conditional boundary → NO_COVERAGE
2. FlateDecode : negated conditional → NO_COVERAGE
      while ((n = zip.read(b)) >= 0) {
1916 1 1. FlateDecode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
        out.write(b, 0, n);
1917
      }
1918 1 1. FlateDecode : removed call to java/util/zip/InflaterInputStream::close → NO_COVERAGE
      zip.close();
1919 1 1. FlateDecode : removed call to java/io/ByteArrayOutputStream::close → NO_COVERAGE
      out.close();
1920 1 1. FlateDecode : mutated return of Object value for com/lowagie/text/pdf/PdfReader::FlateDecode to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return out.toByteArray();
1921
    } catch (Exception e) {
1922 1 1. FlateDecode : negated conditional → NO_COVERAGE
      if (strict)
1923 1 1. FlateDecode : mutated return of Object value for com/lowagie/text/pdf/PdfReader::FlateDecode to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return null;
1924 1 1. FlateDecode : mutated return of Object value for com/lowagie/text/pdf/PdfReader::FlateDecode to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return out.toByteArray();
1925
    }
1926
  }
1927
1928
  /**
1929
   * Decodes a stream that has the ASCIIHexDecode filter.
1930
   * 
1931
   * @param in
1932
   *          the input data
1933
   * @return the decoded data
1934
   */
1935
  public static byte[] ASCIIHexDecode(byte[] in) {
1936
    ByteArrayOutputStream out = new ByteArrayOutputStream();
1937
    boolean first = true;
1938
    int n1 = 0;
1939
      for (byte b : in) {
1940 1 1. ASCIIHexDecode : Replaced bitwise AND with OR → NO_COVERAGE
          int ch = b & 0xff;
1941 1 1. ASCIIHexDecode : negated conditional → NO_COVERAGE
          if (ch == '>')
1942
              break;
1943 1 1. ASCIIHexDecode : negated conditional → NO_COVERAGE
          if (PRTokeniser.isWhitespace(ch))
1944
              continue;
1945
          int n = PRTokeniser.getHex(ch);
1946 1 1. ASCIIHexDecode : negated conditional → NO_COVERAGE
          if (n == -1)
1947
              throw new RuntimeException(
1948
                      MessageLocalization
1949
                              .getComposedMessage("illegal.character.in.asciihexdecode"));
1950 1 1. ASCIIHexDecode : negated conditional → NO_COVERAGE
          if (first)
1951
              n1 = n;
1952
          else
1953 3 1. ASCIIHexDecode : Replaced Shift Left with Shift Right → NO_COVERAGE
2. ASCIIHexDecode : Replaced integer addition with subtraction → NO_COVERAGE
3. ASCIIHexDecode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
              out.write((byte) ((n1 << 4) + n));
1954 1 1. ASCIIHexDecode : negated conditional → NO_COVERAGE
          first = !first;
1955
      }
1956 1 1. ASCIIHexDecode : negated conditional → NO_COVERAGE
    if (!first)
1957 2 1. ASCIIHexDecode : Replaced Shift Left with Shift Right → NO_COVERAGE
2. ASCIIHexDecode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
      out.write((byte) (n1 << 4));
1958 1 1. ASCIIHexDecode : mutated return of Object value for com/lowagie/text/pdf/PdfReader::ASCIIHexDecode to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return out.toByteArray();
1959
  }
1960
1961
  /**
1962
   * Decodes a stream that has the ASCII85Decode filter.
1963
   * 
1964
   * @param in
1965
   *          the input data
1966
   * @return the decoded data
1967
   */
1968
  public static byte[] ASCII85Decode(byte[] in) {
1969
    ByteArrayOutputStream out = new ByteArrayOutputStream();
1970
    int state = 0;
1971
    int[] chn = new int[5];
1972
      for (byte b : in) {
1973 1 1. ASCII85Decode : Replaced bitwise AND with OR → NO_COVERAGE
          int ch = b & 0xff;
1974 1 1. ASCII85Decode : negated conditional → NO_COVERAGE
          if (ch == '~')
1975
              break;
1976 1 1. ASCII85Decode : negated conditional → NO_COVERAGE
          if (PRTokeniser.isWhitespace(ch))
1977
              continue;
1978 2 1. ASCII85Decode : negated conditional → NO_COVERAGE
2. ASCII85Decode : negated conditional → NO_COVERAGE
          if (ch == 'z' && state == 0) {
1979 1 1. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
              out.write(0);
1980 1 1. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
              out.write(0);
1981 1 1. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
              out.write(0);
1982 1 1. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
              out.write(0);
1983
              continue;
1984
          }
1985 4 1. ASCII85Decode : changed conditional boundary → NO_COVERAGE
2. ASCII85Decode : changed conditional boundary → NO_COVERAGE
3. ASCII85Decode : negated conditional → NO_COVERAGE
4. ASCII85Decode : negated conditional → NO_COVERAGE
          if (ch < '!' || ch > 'u')
1986
              throw new RuntimeException(
1987
                      MessageLocalization
1988
                              .getComposedMessage("illegal.character.in.ascii85decode"));
1989 1 1. ASCII85Decode : Replaced integer subtraction with addition → NO_COVERAGE
          chn[state] = ch - '!';
1990 1 1. ASCII85Decode : Changed increment from 1 to -1 → NO_COVERAGE
          ++state;
1991 1 1. ASCII85Decode : negated conditional → NO_COVERAGE
          if (state == 5) {
1992
              state = 0;
1993
              int r = 0;
1994 3 1. ASCII85Decode : changed conditional boundary → NO_COVERAGE
2. ASCII85Decode : Changed increment from 1 to -1 → NO_COVERAGE
3. ASCII85Decode : negated conditional → NO_COVERAGE
              for (int j = 0; j < 5; ++j)
1995 2 1. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
2. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
                  r = r * 85 + chn[j];
1996 2 1. ASCII85Decode : Replaced Shift Right with Shift Left → NO_COVERAGE
2. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
              out.write((byte) (r >> 24));
1997 2 1. ASCII85Decode : Replaced Shift Right with Shift Left → NO_COVERAGE
2. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
              out.write((byte) (r >> 16));
1998 2 1. ASCII85Decode : Replaced Shift Right with Shift Left → NO_COVERAGE
2. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
              out.write((byte) (r >> 8));
1999 1 1. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
              out.write((byte) r);
2000
          }
2001
      }
2002
    int r;
2003
    // We'll ignore the next two lines for the sake of perpetuating broken
2004
    // PDFs
2005
    // if (state == 1)
2006
    // throw new
2007
    // RuntimeException(MessageLocalization.getComposedMessage("illegal.length.in.ascii85decode"));
2008 1 1. ASCII85Decode : negated conditional → NO_COVERAGE
    if (state == 2) {
2009 11 1. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
2. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
3. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
4. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
5. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
6. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
7. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
8. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
9. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
10. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
11. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
      r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + 85 * 85 * 85
2010
          + 85 * 85 + 85;
2011 2 1. ASCII85Decode : Replaced Shift Right with Shift Left → NO_COVERAGE
2. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
      out.write((byte) (r >> 24));
2012 1 1. ASCII85Decode : negated conditional → NO_COVERAGE
    } else if (state == 3) {
2013 13 1. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
2. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
3. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
4. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
5. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
6. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
7. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
8. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
9. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
10. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
11. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
12. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
13. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
      r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + chn[2] * 85 * 85
2014
          + 85 * 85 + 85;
2015 2 1. ASCII85Decode : Replaced Shift Right with Shift Left → NO_COVERAGE
2. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
      out.write((byte) (r >> 24));
2016 2 1. ASCII85Decode : Replaced Shift Right with Shift Left → NO_COVERAGE
2. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
      out.write((byte) (r >> 16));
2017 1 1. ASCII85Decode : negated conditional → NO_COVERAGE
    } else if (state == 4) {
2018 14 1. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
2. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
3. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
4. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
5. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
6. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
7. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
8. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
9. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
10. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
11. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
12. ASCII85Decode : Replaced integer multiplication with division → NO_COVERAGE
13. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
14. ASCII85Decode : Replaced integer addition with subtraction → NO_COVERAGE
      r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + chn[2] * 85 * 85
2019
          + chn[3] * 85 + 85;
2020 2 1. ASCII85Decode : Replaced Shift Right with Shift Left → NO_COVERAGE
2. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
      out.write((byte) (r >> 24));
2021 2 1. ASCII85Decode : Replaced Shift Right with Shift Left → NO_COVERAGE
2. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
      out.write((byte) (r >> 16));
2022 2 1. ASCII85Decode : Replaced Shift Right with Shift Left → NO_COVERAGE
2. ASCII85Decode : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
      out.write((byte) (r >> 8));
2023
    }
2024 1 1. ASCII85Decode : mutated return of Object value for com/lowagie/text/pdf/PdfReader::ASCII85Decode to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return out.toByteArray();
2025
  }
2026
2027
  /**
2028
   * Decodes a stream that has the LZWDecode filter.
2029
   * 
2030
   * @param in
2031
   *          the input data
2032
   * @return the decoded data
2033
   */
2034
  public static byte[] LZWDecode(byte[] in) {
2035
    ByteArrayOutputStream out = new ByteArrayOutputStream();
2036
    LZWDecoder lzw = new LZWDecoder();
2037 1 1. LZWDecode : removed call to com/lowagie/text/pdf/LZWDecoder::decode → NO_COVERAGE
    lzw.decode(in, out);
2038 1 1. LZWDecode : mutated return of Object value for com/lowagie/text/pdf/PdfReader::LZWDecode to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return out.toByteArray();
2039
  }
2040
2041
  /**
2042
   * Checks if the document had errors and was rebuilt.
2043
   * 
2044
   * @return true if rebuilt.
2045
   *
2046
   */
2047
  public boolean isRebuilt() {
2048
    return this.rebuilt;
2049
  }
2050
2051
  /**
2052
   * Gets the dictionary that represents a page.
2053
   * 
2054
   * @param pageNum
2055
   *          the page number. 1 is the first
2056
   * @return the page dictionary
2057
   */
2058
  public PdfDictionary getPageN(int pageNum) {
2059
    PdfDictionary dic = pageRefs.getPageN(pageNum);
2060 1 1. getPageN : negated conditional → NO_COVERAGE
    if (dic == null)
2061 1 1. getPageN : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageN to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
2062 1 1. getPageN : negated conditional → NO_COVERAGE
    if (appendable)
2063 1 1. getPageN : removed call to com/lowagie/text/pdf/PdfDictionary::setIndRef → NO_COVERAGE
      dic.setIndRef(pageRefs.getPageOrigRef(pageNum));
2064 1 1. getPageN : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageN to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return dic;
2065
  }
2066
2067
  /**
2068
   * @return a Dictionary object
2069
   */
2070
  public PdfDictionary getPageNRelease(int pageNum) {
2071
    PdfDictionary dic = getPageN(pageNum);
2072 1 1. getPageNRelease : removed call to com/lowagie/text/pdf/PdfReader$PageRefs::releasePage → NO_COVERAGE
    pageRefs.releasePage(pageNum);
2073 1 1. getPageNRelease : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageNRelease to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return dic;
2074
  }
2075
2076
  /**
2077
   */
2078
  public void releasePage(int pageNum) {
2079
    pageRefs.releasePage(pageNum);
2080
  }
2081
2082
  /**
2083
     *
2084
     */
2085
  public void resetReleasePage() {
2086
    pageRefs.resetReleasePage();
2087
  }
2088
2089
  /**
2090
   * Gets the page reference to this page.
2091
   * 
2092
   * @param pageNum
2093
   *          the page number. 1 is the first
2094
   * @return the page reference
2095
   */
2096
  public PRIndirectReference getPageOrigRef(int pageNum) {
2097
    return pageRefs.getPageOrigRef(pageNum);
2098
  }
2099
2100
  /**
2101
   * Gets the contents of the page.
2102
   * 
2103
   * @param pageNum
2104
   *          the page number. 1 is the first
2105
   * @param file
2106
   *          the location of the PDF document
2107
   * @throws IOException
2108
   *           on error
2109
   * @return the content
2110
   */
2111
  public byte[] getPageContent(int pageNum, RandomAccessFileOrArray file)
2112
      throws IOException {
2113
    PdfDictionary page = getPageNRelease(pageNum);
2114 1 1. getPageContent : negated conditional → NO_COVERAGE
    if (page == null)
2115 1 1. getPageContent : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageContent to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
2116
    PdfObject contents = getPdfObjectRelease(page.get(PdfName.CONTENTS));
2117 1 1. getPageContent : negated conditional → NO_COVERAGE
    if (contents == null)
2118 1 1. getPageContent : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageContent to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return new byte[0];
2119
    ByteArrayOutputStream bout;
2120 1 1. getPageContent : negated conditional → NO_COVERAGE
    if (contents.isStream()) {
2121 1 1. getPageContent : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageContent to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return getStreamBytes((PRStream) contents, file);
2122 1 1. getPageContent : negated conditional → NO_COVERAGE
    } else if (contents.isArray()) {
2123
      PdfArray array = (PdfArray) contents;
2124
      bout = new ByteArrayOutputStream();
2125 2 1. getPageContent : changed conditional boundary → NO_COVERAGE
2. getPageContent : negated conditional → NO_COVERAGE
      for (int k = 0; k < array.size(); ++k) {
2126
        PdfObject item = getPdfObjectRelease(array.getPdfObject(k));
2127 2 1. getPageContent : negated conditional → NO_COVERAGE
2. getPageContent : negated conditional → NO_COVERAGE
        if (item == null || !item.isStream())
2128
          continue;
2129
        byte[] b = getStreamBytes((PRStream) item, file);
2130 1 1. getPageContent : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
        bout.write(b);
2131 2 1. getPageContent : Replaced integer subtraction with addition → NO_COVERAGE
2. getPageContent : negated conditional → NO_COVERAGE
        if (k != array.size() - 1)
2132 1 1. getPageContent : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
          bout.write('\n');
2133
      }
2134 1 1. getPageContent : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageContent to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return bout.toByteArray();
2135
    } else
2136 1 1. getPageContent : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageContent to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return new byte[0];
2137
  }
2138
2139
  /**
2140
   * Gets the contents of the page.
2141
   * 
2142
   * @param pageNum
2143
   *          the page number. 1 is the first
2144
   * @throws IOException
2145
   *           on error
2146
   * @return the content
2147
   */
2148
  public byte[] getPageContent(int pageNum) throws IOException {
2149
    RandomAccessFileOrArray rf = getSafeFile();
2150
    try {
2151 1 1. getPageContent : removed call to com/lowagie/text/pdf/RandomAccessFileOrArray::reOpen → NO_COVERAGE
      rf.reOpen();
2152 1 1. getPageContent : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getPageContent to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return getPageContent(pageNum, rf);
2153
    } finally {
2154
      try {
2155 1 1. getPageContent : removed call to com/lowagie/text/pdf/RandomAccessFileOrArray::close → NO_COVERAGE
        rf.close();
2156
      } catch (Exception ignored) {
2157
      }
2158
    }
2159
  }
2160
2161
  protected void killXref(PdfObject obj) {
2162 1 1. killXref : negated conditional → NO_COVERAGE
    if (obj == null)
2163
      return;
2164 2 1. killXref : negated conditional → NO_COVERAGE
2. killXref : negated conditional → NO_COVERAGE
    if ((obj instanceof PdfIndirectReference) && !obj.isIndirect())
2165
      return;
2166
    switch (obj.type()) {
2167
    case PdfObject.INDIRECT: {
2168
      int xr = ((PRIndirectReference) obj).getNumber();
2169
      obj = xrefObj.get(xr);
2170
      xrefObj.set(xr, null);
2171
      freeXref = xr;
2172 1 1. killXref : removed call to com/lowagie/text/pdf/PdfReader::killXref → NO_COVERAGE
      killXref(obj);
2173
      break;
2174
    }
2175
    case PdfObject.ARRAY: {
2176
      PdfArray t = (PdfArray) obj;
2177 2 1. killXref : changed conditional boundary → NO_COVERAGE
2. killXref : negated conditional → NO_COVERAGE
      for (int i = 0; i < t.size(); ++i)
2178 1 1. killXref : removed call to com/lowagie/text/pdf/PdfReader::killXref → NO_COVERAGE
        killXref(t.getPdfObject(i));
2179
      break;
2180
    }
2181
    case PdfObject.STREAM:
2182
    case PdfObject.DICTIONARY: {
2183
      PdfDictionary dic = (PdfDictionary) obj;
2184
      for (Object o : dic.getKeys()) {
2185 1 1. killXref : removed call to com/lowagie/text/pdf/PdfReader::killXref → NO_COVERAGE
        killXref(dic.get((PdfName) o));
2186
      }
2187
      break;
2188
    }
2189
    }
2190
  }
2191
2192
  /**
2193
   * Sets the contents of the page.
2194
   * 
2195
   * @param content
2196
   *          the new page content
2197
   * @param pageNum
2198
   *          the page number. 1 is the first
2199
   */
2200
  public void setPageContent(int pageNum, byte[] content) {
2201 1 1. setPageContent : removed call to com/lowagie/text/pdf/PdfReader::setPageContent → NO_COVERAGE
    setPageContent(pageNum, content, PdfStream.DEFAULT_COMPRESSION);
2202
  }
2203
2204
  /**
2205
   * Sets the contents of the page.
2206
   * 
2207
   * @param content
2208
   *          the new page content
2209
   * @param pageNum
2210
   *          the page number. 1 is the first
2211
   * @since 2.1.3 (the method already existed without param compressionLevel)
2212
   */
2213
  public void setPageContent(int pageNum, byte[] content, int compressionLevel) {
2214
    PdfDictionary page = getPageN(pageNum);
2215 1 1. setPageContent : negated conditional → NO_COVERAGE
    if (page == null)
2216
      return;
2217
    PdfObject contents = page.get(PdfName.CONTENTS);
2218
    freeXref = -1;
2219 1 1. setPageContent : removed call to com/lowagie/text/pdf/PdfReader::killXref → NO_COVERAGE
    killXref(contents);
2220 1 1. setPageContent : negated conditional → NO_COVERAGE
    if (freeXref == -1) {
2221
      xrefObj.add(null);
2222 1 1. setPageContent : Replaced integer subtraction with addition → NO_COVERAGE
      freeXref = xrefObj.size() - 1;
2223
    }
2224 1 1. setPageContent : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE
    page.put(PdfName.CONTENTS, new PRIndirectReference(this, freeXref));
2225
    xrefObj.set(freeXref, new PRStream(this, content, compressionLevel));
2226
  }
2227
2228
  /**
2229
   * Get the content from a stream applying the required filters.
2230
   * 
2231
   * @param stream
2232
   *          the stream
2233
   * @param file
2234
   *          the location where the stream is
2235
   * @throws IOException
2236
   *           on error
2237
   * @return the stream content
2238
   */
2239
  public static byte[] getStreamBytes(PRStream stream,
2240
      RandomAccessFileOrArray file) throws IOException {
2241
    PdfObject filter = getPdfObjectRelease(stream.get(PdfName.FILTER));
2242
    byte[] b = getStreamBytesRaw(stream, file);
2243
    List<PdfObject> filters = new ArrayList<>();
2244
    filters = addFilters(filters, filter);
2245
    List<PdfObject> dp = new ArrayList<>();
2246
    PdfObject dpo = getPdfObjectRelease(stream.get(PdfName.DECODEPARMS));
2247 3 1. getStreamBytes : negated conditional → NO_COVERAGE
2. getStreamBytes : negated conditional → NO_COVERAGE
3. getStreamBytes : negated conditional → NO_COVERAGE
    if (dpo == null || (!dpo.isDictionary() && !dpo.isArray()))
2248
      dpo = getPdfObjectRelease(stream.get(PdfName.DP));
2249 1 1. getStreamBytes : negated conditional → NO_COVERAGE
    if (dpo != null) {
2250 1 1. getStreamBytes : negated conditional → NO_COVERAGE
      if (dpo.isDictionary())
2251
        dp.add(dpo);
2252 1 1. getStreamBytes : negated conditional → NO_COVERAGE
      else if (dpo.isArray())
2253
        dp = ((PdfArray) dpo).getElements();
2254
    }
2255
    String name;
2256 3 1. getStreamBytes : changed conditional boundary → NO_COVERAGE
2. getStreamBytes : Changed increment from 1 to -1 → NO_COVERAGE
3. getStreamBytes : negated conditional → NO_COVERAGE
    for (int j = 0; j < filters.size(); ++j) {
2257
      name = getPdfObjectRelease(filters.get(j))
2258
          .toString();
2259
        switch (name) {
2260
            case "/FlateDecode":
2261
            case "/Fl": {
2262
                b = FlateDecode(b);
2263
                PdfObject dicParam;
2264 2 1. getStreamBytes : changed conditional boundary → NO_COVERAGE
2. getStreamBytes : negated conditional → NO_COVERAGE
                if (j < dp.size()) {
2265
                    dicParam = dp.get(j);
2266
                    b = decodePredictor(b, dicParam);
2267
                }
2268
                break;
2269
            }
2270
            case "/ASCIIHexDecode":
2271
            case "/AHx":
2272
                b = ASCIIHexDecode(b);
2273
                break;
2274
            case "/ASCII85Decode":
2275
            case "/A85":
2276
                b = ASCII85Decode(b);
2277
                break;
2278
            case "/LZWDecode": {
2279
                b = LZWDecode(b);
2280
                PdfObject dicParam;
2281 2 1. getStreamBytes : changed conditional boundary → NO_COVERAGE
2. getStreamBytes : negated conditional → NO_COVERAGE
                if (j < dp.size()) {
2282
                    dicParam = dp.get(j);
2283
                    b = decodePredictor(b, dicParam);
2284
                }
2285
                break;
2286
            }
2287
            case "/Crypt":
2288
                break;
2289
            default:
2290
                throw new UnsupportedPdfException(
2291
                        MessageLocalization.getComposedMessage(
2292
                                "the.filter.1.is.not.supported", name));
2293
        }
2294
    }
2295 1 1. getStreamBytes : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getStreamBytes to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return b;
2296
  }
2297
2298
  /**
2299
   * Get the content from a stream applying the required filters.
2300
   * 
2301
   * @param stream
2302
   *          the stream
2303
   * @throws IOException
2304
   *           on error
2305
   * @return the stream content
2306
   */
2307
  public static byte[] getStreamBytes(PRStream stream) throws IOException {
2308
    RandomAccessFileOrArray rf = stream.getReader().getSafeFile();
2309
    try {
2310 1 1. getStreamBytes : removed call to com/lowagie/text/pdf/RandomAccessFileOrArray::reOpen → NO_COVERAGE
      rf.reOpen();
2311 1 1. getStreamBytes : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getStreamBytes to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return getStreamBytes(stream, rf);
2312
    } finally {
2313
      try {
2314 1 1. getStreamBytes : removed call to com/lowagie/text/pdf/RandomAccessFileOrArray::close → NO_COVERAGE
        rf.close();
2315
      } catch (Exception e) {
2316
      }
2317
    }
2318
  }
2319
2320
  /**
2321
   * Get the content from a stream as it is without applying any filter.
2322
   * 
2323
   * @param stream
2324
   *          the stream
2325
   * @param file
2326
   *          the location where the stream is
2327
   * @throws IOException
2328
   *           on error
2329
   * @return the stream content
2330
   */
2331
  public static byte[] getStreamBytesRaw(PRStream stream,
2332
      RandomAccessFileOrArray file) throws IOException {
2333
    PdfReader reader = stream.getReader();
2334
    byte[] b;
2335 2 1. getStreamBytesRaw : changed conditional boundary → NO_COVERAGE
2. getStreamBytesRaw : negated conditional → NO_COVERAGE
    if (stream.getOffset() < 0)
2336
      b = stream.getBytes();
2337
    else {
2338
      b = new byte[stream.getLength()];
2339 1 1. getStreamBytesRaw : removed call to com/lowagie/text/pdf/RandomAccessFileOrArray::seek → NO_COVERAGE
      file.seek(stream.getOffset());
2340 1 1. getStreamBytesRaw : removed call to com/lowagie/text/pdf/RandomAccessFileOrArray::readFully → NO_COVERAGE
      file.readFully(b);
2341
      PdfEncryption decrypt = reader.getDecrypt();
2342 1 1. getStreamBytesRaw : negated conditional → NO_COVERAGE
      if (decrypt != null) {
2343
        PdfObject filter = getPdfObjectRelease(stream.get(PdfName.FILTER));
2344
        List<PdfObject> filters = new ArrayList<>();
2345
        filters = addFilters(filters, filter);
2346
        boolean skip = false;
2347
        for (PdfObject filter1 : filters) {
2348
          PdfObject obj = getPdfObjectRelease(filter1);
2349 2 1. getStreamBytesRaw : negated conditional → NO_COVERAGE
2. getStreamBytesRaw : negated conditional → NO_COVERAGE
          if (obj != null && obj.toString().equals("/Crypt")) {
2350
            skip = true;
2351
            break;
2352
          }
2353
        }
2354 1 1. getStreamBytesRaw : negated conditional → NO_COVERAGE
        if (!skip) {
2355 1 1. getStreamBytesRaw : removed call to com/lowagie/text/pdf/PdfEncryption::setHashKey → NO_COVERAGE
          decrypt.setHashKey(stream.getObjNum(), stream.getObjGen());
2356
          b = decrypt.decryptByteArray(b);
2357
        }
2358
      }
2359
    }
2360 1 1. getStreamBytesRaw : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getStreamBytesRaw to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return b;
2361
  }
2362
2363
  private static List<PdfObject> addFilters(List<PdfObject> filters, PdfObject filter) {
2364 1 1. addFilters : negated conditional → NO_COVERAGE
    if (filter != null) {
2365 1 1. addFilters : negated conditional → NO_COVERAGE
      if (filter.isName())
2366
        filters.add(filter);
2367 1 1. addFilters : negated conditional → NO_COVERAGE
      else if (filter.isArray())
2368
        filters = ((PdfArray) filter).getElements();
2369
    }
2370 1 1. addFilters : mutated return of Object value for com/lowagie/text/pdf/PdfReader::addFilters to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return filters;
2371
  }
2372
2373
  /**
2374
   * Get the content from a stream as it is without applying any filter.
2375
   * 
2376
   * @param stream
2377
   *          the stream
2378
   * @throws IOException
2379
   *           on error
2380
   * @return the stream content
2381
   */
2382
  public static byte[] getStreamBytesRaw(PRStream stream) throws IOException {
2383
    RandomAccessFileOrArray rf = stream.getReader().getSafeFile();
2384
    try {
2385 1 1. getStreamBytesRaw : removed call to com/lowagie/text/pdf/RandomAccessFileOrArray::reOpen → NO_COVERAGE
      rf.reOpen();
2386 1 1. getStreamBytesRaw : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getStreamBytesRaw to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return getStreamBytesRaw(stream, rf);
2387
    } finally {
2388
      try {
2389 1 1. getStreamBytesRaw : removed call to com/lowagie/text/pdf/RandomAccessFileOrArray::close → NO_COVERAGE
        rf.close();
2390
      } catch (Exception ignored) {
2391
      }
2392
    }
2393
  }
2394
2395
  /** Eliminates shared streams if they exist. */
2396
  public void eliminateSharedStreams() {
2397 1 1. eliminateSharedStreams : negated conditional → NO_COVERAGE
    if (!sharedStreams)
2398
      return;
2399
    sharedStreams = false;
2400 1 1. eliminateSharedStreams : negated conditional → NO_COVERAGE
    if (pageRefs.size() == 1)
2401
      return;
2402
    List<PdfObject> newRefs = new ArrayList<>();
2403
    List<PdfObject> newStreams = new ArrayList<>();
2404
    IntHashtable visited = new IntHashtable();
2405 3 1. eliminateSharedStreams : changed conditional boundary → NO_COVERAGE
2. eliminateSharedStreams : Changed increment from 1 to -1 → NO_COVERAGE
3. eliminateSharedStreams : negated conditional → NO_COVERAGE
    for (int k = 1; k <= pageRefs.size(); ++k) {
2406
      PdfDictionary page = pageRefs.getPageN(k);
2407 1 1. eliminateSharedStreams : negated conditional → NO_COVERAGE
      if (page == null)
2408
        continue;
2409
      PdfObject contents = getPdfObject(page.get(PdfName.CONTENTS));
2410 1 1. eliminateSharedStreams : negated conditional → NO_COVERAGE
      if (contents == null)
2411
        continue;
2412 1 1. eliminateSharedStreams : negated conditional → NO_COVERAGE
      if (contents.isStream()) {
2413
        PRIndirectReference ref = (PRIndirectReference) page
2414
            .get(PdfName.CONTENTS);
2415 1 1. eliminateSharedStreams : negated conditional → NO_COVERAGE
        if (visited.containsKey(ref.getNumber())) {
2416
          // need to duplicate
2417
          newRefs.add(ref);
2418
          newStreams.add(new PRStream((PRStream) contents, null));
2419
        } else
2420
          visited.put(ref.getNumber(), 1);
2421 1 1. eliminateSharedStreams : negated conditional → NO_COVERAGE
      } else if (contents.isArray()) {
2422
        PdfArray array = (PdfArray) contents;
2423 2 1. eliminateSharedStreams : changed conditional boundary → NO_COVERAGE
2. eliminateSharedStreams : negated conditional → NO_COVERAGE
        for (int j = 0; j < array.size(); ++j) {
2424
          PRIndirectReference ref = (PRIndirectReference) array.getPdfObject(j);
2425 1 1. eliminateSharedStreams : negated conditional → NO_COVERAGE
          if (visited.containsKey(ref.getNumber())) {
2426
            // need to duplicate
2427
            newRefs.add(ref);
2428
            newStreams.add(new PRStream((PRStream) getPdfObject(ref), null));
2429
          } else
2430
            visited.put(ref.getNumber(), 1);
2431
        }
2432
      }
2433
    }
2434 1 1. eliminateSharedStreams : negated conditional → NO_COVERAGE
    if (newStreams.isEmpty())
2435
      return;
2436 2 1. eliminateSharedStreams : changed conditional boundary → NO_COVERAGE
2. eliminateSharedStreams : negated conditional → NO_COVERAGE
    for (int k = 0; k < newStreams.size(); ++k) {
2437
      xrefObj.add(newStreams.get(k));
2438
      PRIndirectReference ref = (PRIndirectReference) newRefs.get(k);
2439 2 1. eliminateSharedStreams : Replaced integer subtraction with addition → NO_COVERAGE
2. eliminateSharedStreams : removed call to com/lowagie/text/pdf/PRIndirectReference::setNumber → NO_COVERAGE
      ref.setNumber(xrefObj.size() - 1, 0);
2440
    }
2441
  }
2442
2443
  /**
2444
   * Checks if the document was changed.
2445
   * 
2446
   * @return <CODE>true</CODE> if the document was changed, <CODE>false</CODE>
2447
   *         otherwise
2448
   */
2449
  public boolean isTampered() {
2450
    return tampered;
2451
  }
2452
2453
  /**
2454
   * Sets the tampered state. A tampered PdfReader cannot be reused in
2455
   * PdfStamper.
2456
   * 
2457
   * @param tampered
2458
   *          the tampered state
2459
   */
2460
  public void setTampered(boolean tampered) {
2461
    this.tampered = tampered;
2462 1 1. setTampered : removed call to com/lowagie/text/pdf/PdfReader$PageRefs::keepPages → NO_COVERAGE
    pageRefs.keepPages();
2463
  }
2464
2465
  /**
2466
   * Gets the XML metadata.
2467
   * 
2468
   * @throws IOException
2469
   *           on error
2470
   * @return the XML metadata
2471
   */
2472
  public byte[] getMetadata() throws IOException {
2473
    PdfObject obj = getPdfObject(catalog.get(PdfName.METADATA));
2474 1 1. getMetadata : negated conditional → NO_COVERAGE
    if (!(obj instanceof PRStream))
2475 1 1. getMetadata : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getMetadata to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
2476
    RandomAccessFileOrArray rf = getSafeFile();
2477
    byte[] b;
2478
    try {
2479 1 1. getMetadata : removed call to com/lowagie/text/pdf/RandomAccessFileOrArray::reOpen → NO_COVERAGE
      rf.reOpen();
2480
      b = getStreamBytes((PRStream) obj, rf);
2481
    } finally {
2482
      try {
2483 1 1. getMetadata : removed call to com/lowagie/text/pdf/RandomAccessFileOrArray::close → NO_COVERAGE
        rf.close();
2484
      } catch (Exception e) {
2485
        // empty on purpose
2486
      }
2487
    }
2488 1 1. getMetadata : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getMetadata to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return b;
2489
  }
2490
2491
  /**
2492
   * Gets the byte address of the last xref table.
2493
   * 
2494
   * @return the byte address of the last xref table
2495
   */
2496
  public int getLastXref() {
2497
    return lastXref;
2498
  }
2499
2500
  /**
2501
   * Gets the number of xref objects.
2502
   * 
2503
   * @return the number of xref objects
2504
   */
2505
  public int getXrefSize() {
2506
    return xrefObj.size();
2507
  }
2508
2509
  /**
2510
   * Gets the byte address of the %%EOF marker.
2511
   * 
2512
   * @return the byte address of the %%EOF marker
2513
   */
2514
  public int getEofPos() {
2515
    return eofPos;
2516
  }
2517
2518
  /**
2519
   * Gets the PDF version. Only the last version char is returned. For example
2520
   * version 1.4 is returned as '4'.
2521
   * 
2522
   * @return the PDF version
2523
   */
2524
  public char getPdfVersion() {
2525
    return pdfVersion;
2526
  }
2527
2528
  /**
2529
   * Returns <CODE>true</CODE> if the PDF is encrypted.
2530
   * 
2531
   * @return <CODE>true</CODE> if the PDF is encrypted
2532
   */
2533
  public boolean isEncrypted() {
2534
    return encrypted;
2535
  }
2536
2537
  /**
2538
   * Gets the encryption permissions. It can be used directly in
2539
   * <CODE>PdfWriter.setEncryption()</CODE>.
2540
   * 
2541
   * @return the encryption permissions
2542
   */
2543
  public int getPermissions() {
2544
    return pValue;
2545
  }
2546
2547
  /**
2548
   * Returns <CODE>true</CODE> if the PDF has a 128 bit key encryption.
2549
   * 
2550
   * @return <CODE>true</CODE> if the PDF has a 128 bit key encryption
2551
   */
2552
  public boolean is128Key() {
2553 2 1. is128Key : negated conditional → NO_COVERAGE
2. is128Key : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
    return rValue == 3;
2554
  }
2555
2556
  /**
2557
   * Gets the trailer dictionary
2558
   * 
2559
   * @return the trailer dictionary
2560
   */
2561
  public PdfDictionary getTrailer() {
2562
    return trailer;
2563
  }
2564
2565
  PdfEncryption getDecrypt() {
2566
    return decrypt;
2567
  }
2568
2569
  private static boolean equalsn(byte[] a1, byte[] a2) {
2570
    int length = a2.length;
2571 3 1. equalsn : changed conditional boundary → NO_COVERAGE
2. equalsn : Changed increment from 1 to -1 → NO_COVERAGE
3. equalsn : negated conditional → NO_COVERAGE
    for (int k = 0; k < length; ++k) {
2572 1 1. equalsn : negated conditional → NO_COVERAGE
      if (a1[k] != a2[k])
2573 1 1. equalsn : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
        return false;
2574
    }
2575 1 1. equalsn : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
    return true;
2576
  }
2577
2578
  private static boolean existsName(PdfDictionary dic, PdfName key, PdfName value) {
2579
    PdfObject type = getPdfObjectRelease(dic.get(key));
2580 2 1. existsName : negated conditional → NO_COVERAGE
2. existsName : negated conditional → NO_COVERAGE
    if (type == null || !type.isName())
2581 1 1. existsName : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
      return false;
2582
    PdfName name = (PdfName) type;
2583 1 1. existsName : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
    return name.equals(value);
2584
  }
2585
2586
  static String getFontNameFromDescriptor(PdfDictionary dic) {
2587 1 1. getFontNameFromDescriptor : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getFontNameFromDescriptor to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return getFontName(dic, PdfName.FONTNAME);
2588
  }
2589
2590
  private static String getFontName(PdfDictionary dic) {
2591 1 1. getFontName : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getFontName to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return getFontName(dic, PdfName.BASEFONT);
2592
  }
2593
2594
  private static String getFontName(PdfDictionary dic, PdfName property) {
2595 1 1. getFontName : negated conditional → NO_COVERAGE
    if (dic == null)
2596 1 1. getFontName : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getFontName to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
2597
    PdfObject type = getPdfObjectRelease(dic.get(property));
2598 2 1. getFontName : negated conditional → NO_COVERAGE
2. getFontName : negated conditional → NO_COVERAGE
    if (type == null || !type.isName())
2599 1 1. getFontName : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getFontName to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
2600 1 1. getFontName : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getFontName to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return PdfName.decodeName(type.toString());
2601
  }
2602
2603
  static boolean isFontSubset(String fontName) {
2604 4 1. isFontSubset : changed conditional boundary → NO_COVERAGE
2. isFontSubset : negated conditional → NO_COVERAGE
3. isFontSubset : negated conditional → NO_COVERAGE
4. isFontSubset : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
    return fontName != null && fontName.length() >= 8
2605 1 1. isFontSubset : negated conditional → NO_COVERAGE
        && fontName.charAt(6) == '+';
2606
  }
2607
2608
  private static String getSubsetPrefix(PdfDictionary dic) {
2609 1 1. getSubsetPrefix : negated conditional → NO_COVERAGE
    if (dic == null)
2610 1 1. getSubsetPrefix : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getSubsetPrefix to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
2611
    String s = getFontName(dic);
2612 1 1. getSubsetPrefix : negated conditional → NO_COVERAGE
    if (s == null)
2613 1 1. getSubsetPrefix : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getSubsetPrefix to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
2614 3 1. getSubsetPrefix : changed conditional boundary → NO_COVERAGE
2. getSubsetPrefix : negated conditional → NO_COVERAGE
3. getSubsetPrefix : negated conditional → NO_COVERAGE
    if (s.length() < 8 || s.charAt(6) != '+')
2615 1 1. getSubsetPrefix : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getSubsetPrefix to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
2616 3 1. getSubsetPrefix : changed conditional boundary → NO_COVERAGE
2. getSubsetPrefix : Changed increment from 1 to -1 → NO_COVERAGE
3. getSubsetPrefix : negated conditional → NO_COVERAGE
    for (int k = 0; k < 6; ++k) {
2617
      char c = s.charAt(k);
2618 4 1. getSubsetPrefix : changed conditional boundary → NO_COVERAGE
2. getSubsetPrefix : changed conditional boundary → NO_COVERAGE
3. getSubsetPrefix : negated conditional → NO_COVERAGE
4. getSubsetPrefix : negated conditional → NO_COVERAGE
      if (c < 'A' || c > 'Z')
2619 1 1. getSubsetPrefix : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getSubsetPrefix to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return null;
2620
    }
2621 1 1. getSubsetPrefix : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getSubsetPrefix to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return s;
2622
  }
2623
2624
  /**
2625
   * Finds all the font subsets and changes the prefixes to some random values.
2626
   * 
2627
   * @return the number of font subsets altered
2628
   */
2629
  public int shuffleSubsetNames() {
2630
    int total = 0;
2631 2 1. shuffleSubsetNames : changed conditional boundary → NO_COVERAGE
2. shuffleSubsetNames : negated conditional → NO_COVERAGE
    for (int k = 1; k < xrefObj.size(); ++k) {
2632
      PdfObject obj = getPdfObjectRelease(k);
2633 2 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
2. shuffleSubsetNames : negated conditional → NO_COVERAGE
      if (obj == null || !obj.isDictionary())
2634
        continue;
2635
      PdfDictionary dic = (PdfDictionary) obj;
2636 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
      if (!existsName(dic, PdfName.TYPE, PdfName.FONT))
2637
        continue;
2638 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
      if (existsName(dic, PdfName.SUBTYPE, PdfName.TYPE1)
2639 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
          || existsName(dic, PdfName.SUBTYPE, PdfName.MMTYPE1)
2640 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
          || existsName(dic, PdfName.SUBTYPE, PdfName.TRUETYPE)) {
2641
        String s = getSubsetPrefix(dic);
2642 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
        if (s == null)
2643
          continue;
2644
        String ns = BaseFont.createSubsetPrefix() + s.substring(7);
2645
        PdfName newName = new PdfName(ns);
2646 1 1. shuffleSubsetNames : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE
        dic.put(PdfName.BASEFONT, newName);
2647 1 1. shuffleSubsetNames : removed call to com/lowagie/text/pdf/PdfReader::setXrefPartialObject → NO_COVERAGE
        setXrefPartialObject(k, dic);
2648 1 1. shuffleSubsetNames : Changed increment from 1 to -1 → NO_COVERAGE
        ++total;
2649
        PdfDictionary fd = dic.getAsDict(PdfName.FONTDESCRIPTOR);
2650 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
        if (fd == null)
2651
          continue;
2652 1 1. shuffleSubsetNames : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE
        fd.put(PdfName.FONTNAME, newName);
2653 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
      } else if (existsName(dic, PdfName.SUBTYPE, PdfName.TYPE0)) {
2654
        String s = getSubsetPrefix(dic);
2655
        PdfArray arr = dic.getAsArray(PdfName.DESCENDANTFONTS);
2656 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
        if (arr == null)
2657
          continue;
2658 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
        if (arr.isEmpty())
2659
          continue;
2660
        PdfDictionary desc = arr.getAsDict(0);
2661
        String sde = getSubsetPrefix(desc);
2662 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
        if (sde == null)
2663
          continue;
2664
        String ns = BaseFont.createSubsetPrefix();
2665 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
        if (s != null)
2666 1 1. shuffleSubsetNames : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE
          dic.put(PdfName.BASEFONT, new PdfName(ns + s.substring(7)));
2667 1 1. shuffleSubsetNames : removed call to com/lowagie/text/pdf/PdfReader::setXrefPartialObject → NO_COVERAGE
        setXrefPartialObject(k, dic);
2668
        PdfName newName = new PdfName(ns + sde.substring(7));
2669 1 1. shuffleSubsetNames : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE
        desc.put(PdfName.BASEFONT, newName);
2670 1 1. shuffleSubsetNames : Changed increment from 1 to -1 → NO_COVERAGE
        ++total;
2671
        PdfDictionary fd = desc.getAsDict(PdfName.FONTDESCRIPTOR);
2672 1 1. shuffleSubsetNames : negated conditional → NO_COVERAGE
        if (fd == null)
2673
          continue;
2674 1 1. shuffleSubsetNames : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE
        fd.put(PdfName.FONTNAME, newName);
2675
      }
2676
    }
2677 1 1. shuffleSubsetNames : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
    return total;
2678
  }
2679
2680
  /**
2681
   * Finds all the fonts not subset but embedded and marks them as subset.
2682
   * 
2683
   * @return the number of fonts altered
2684
   */
2685
  public int createFakeFontSubsets() {
2686
    int total = 0;
2687 2 1. createFakeFontSubsets : changed conditional boundary → NO_COVERAGE
2. createFakeFontSubsets : negated conditional → NO_COVERAGE
    for (int k = 1; k < xrefObj.size(); ++k) {
2688
      PdfObject obj = getPdfObjectRelease(k);
2689 2 1. createFakeFontSubsets : negated conditional → NO_COVERAGE
2. createFakeFontSubsets : negated conditional → NO_COVERAGE
      if (obj == null || !obj.isDictionary())
2690
        continue;
2691
      PdfDictionary dic = (PdfDictionary) obj;
2692 1 1. createFakeFontSubsets : negated conditional → NO_COVERAGE
      if (!existsName(dic, PdfName.TYPE, PdfName.FONT))
2693
        continue;
2694 1 1. createFakeFontSubsets : negated conditional → NO_COVERAGE
      if (existsName(dic, PdfName.SUBTYPE, PdfName.TYPE1)
2695 1 1. createFakeFontSubsets : negated conditional → NO_COVERAGE
          || existsName(dic, PdfName.SUBTYPE, PdfName.MMTYPE1)
2696 1 1. createFakeFontSubsets : negated conditional → NO_COVERAGE
          || existsName(dic, PdfName.SUBTYPE, PdfName.TRUETYPE)) {
2697
        String s = getSubsetPrefix(dic);
2698 1 1. createFakeFontSubsets : negated conditional → NO_COVERAGE
        if (s != null)
2699
          continue;
2700
        s = getFontName(dic);
2701 1 1. createFakeFontSubsets : negated conditional → NO_COVERAGE
        if (s == null)
2702
          continue;
2703
        String ns = BaseFont.createSubsetPrefix() + s;
2704
        PdfDictionary fd = (PdfDictionary) getPdfObjectRelease(dic
2705
            .get(PdfName.FONTDESCRIPTOR));
2706 1 1. createFakeFontSubsets : negated conditional → NO_COVERAGE
        if (fd == null)
2707
          continue;
2708 1 1. createFakeFontSubsets : negated conditional → NO_COVERAGE
        if (fd.get(PdfName.FONTFILE) == null
2709 1 1. createFakeFontSubsets : negated conditional → NO_COVERAGE
            && fd.get(PdfName.FONTFILE2) == null
2710 1 1. createFakeFontSubsets : negated conditional → NO_COVERAGE
            && fd.get(PdfName.FONTFILE3) == null)
2711
          continue;
2712
        fd = dic.getAsDict(PdfName.FONTDESCRIPTOR);
2713
        PdfName newName = new PdfName(ns);
2714 1 1. createFakeFontSubsets : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE
        dic.put(PdfName.BASEFONT, newName);
2715 1 1. createFakeFontSubsets : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE
        fd.put(PdfName.FONTNAME, newName);
2716 1 1. createFakeFontSubsets : removed call to com/lowagie/text/pdf/PdfReader::setXrefPartialObject → NO_COVERAGE
        setXrefPartialObject(k, dic);
2717 1 1. createFakeFontSubsets : Changed increment from 1 to -1 → NO_COVERAGE
        ++total;
2718
      }
2719
    }
2720 1 1. createFakeFontSubsets : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE
    return total;
2721
  }
2722
2723
  private static PdfArray getNameArray(PdfObject obj) {
2724 1 1. getNameArray : negated conditional → NO_COVERAGE
    if (obj == null)
2725 1 1. getNameArray : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getNameArray to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
2726
    obj = getPdfObjectRelease(obj);
2727 1 1. getNameArray : negated conditional → NO_COVERAGE
    if (obj == null)
2728 1 1. getNameArray : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getNameArray to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return null;
2729 1 1. getNameArray : negated conditional → NO_COVERAGE
    if (obj.isArray())
2730 1 1. getNameArray : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getNameArray to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return (PdfArray) obj;
2731 1 1. getNameArray : negated conditional → NO_COVERAGE
    else if (obj.isDictionary()) {
2732
      PdfObject arr2 = getPdfObjectRelease(((PdfDictionary) obj).get(PdfName.D));
2733 2 1. getNameArray : negated conditional → NO_COVERAGE
2. getNameArray : negated conditional → NO_COVERAGE
      if (arr2 != null && arr2.isArray())
2734 1 1. getNameArray : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getNameArray to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return (PdfArray) arr2;
2735
    }
2736 1 1. getNameArray : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getNameArray to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return null;
2737
  }
2738
2739
  /**
2740
   * Gets all the named destinations as an <CODE>HashMap</CODE>. The key is the
2741
   * name and the value is the destinations array.
2742
   * 
2743
   * @return gets all the named destinations
2744
   */
2745
  public HashMap getNamedDestination() {
2746 1 1. getNamedDestination : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getNamedDestination to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return getNamedDestination(false);
2747
  }
2748
2749
  /**
2750
   * Gets all the named destinations as an <CODE>HashMap</CODE>. The key is the
2751
   * name and the value is the destinations array.
2752
   * 
2753
   * @param keepNames
2754
   *          true if you want the keys to be real PdfNames instead of Strings
2755
   * @return gets all the named destinations
2756
   * @since 2.1.6
2757
   */
2758
  public HashMap getNamedDestination(boolean keepNames) {
2759
    HashMap names = getNamedDestinationFromNames(keepNames);
2760 1 1. getNamedDestination : removed call to java/util/HashMap::putAll → NO_COVERAGE
    names.putAll(getNamedDestinationFromStrings());
2761 1 1. getNamedDestination : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getNamedDestination to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return names;
2762
  }
2763
2764
  /**
2765
   * Gets the named destinations from the /Dests key in the catalog as an
2766
   * <CODE>HashMap</CODE>. The key is the name and the value is the destinations
2767
   * array.
2768
   * 
2769
   * @return gets the named destinations
2770
   */
2771
  public HashMap getNamedDestinationFromNames() {
2772 1 1. getNamedDestinationFromNames : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getNamedDestinationFromNames to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return getNamedDestinationFromNames(false);
2773
  }
2774
2775
  /**
2776
   * Gets the named destinations from the /Dests key in the catalog as an
2777
   * <CODE>HashMap</CODE>. The key is the name and the value is the destinations
2778
   * array.
2779
   * 
2780
   * @param keepNames
2781
   *          true if you want the keys to be real PdfNames instead of Strings
2782
   * @return gets the named destinations
2783
   * @since 2.1.6
2784
   */
2785
  public HashMap getNamedDestinationFromNames(boolean keepNames) {
2786
    HashMap names = new HashMap();
2787 1 1. getNamedDestinationFromNames : negated conditional → NO_COVERAGE
    if (catalog.get(PdfName.DESTS) != null) {
2788
      PdfDictionary dic = (PdfDictionary) getPdfObjectRelease(catalog
2789
          .get(PdfName.DESTS));
2790 1 1. getNamedDestinationFromNames : negated conditional → NO_COVERAGE
      if (dic == null)
2791 1 1. getNamedDestinationFromNames : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getNamedDestinationFromNames to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
        return names;
2792
      Set keys = dic.getKeys();
2793
        for (Object key1 : keys) {
2794
            PdfName key = (PdfName) key1;
2795
            PdfArray arr = getNameArray(dic.get(key));
2796 1 1. getNamedDestinationFromNames : negated conditional → NO_COVERAGE
            if (arr == null)
2797
                continue;
2798 1 1. getNamedDestinationFromNames : negated conditional → NO_COVERAGE
            if (keepNames) {
2799
                names.put(key, arr);
2800
            } else {
2801
                String name = PdfName.decodeName(key.toString());
2802
                names.put(name, arr);
2803
            }
2804
        }
2805
    }
2806 1 1. getNamedDestinationFromNames : mutated return of Object value for com/lowagie/text/pdf/PdfReader::getNamedDestinationFromNames to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return names;
2807
  }
2808
2809
  /**
2810
   * Gets the named destinations from the /Names key in the catalog as an
2811
   * <CODE>HashMap</CODE>. The key is the name and the value is the destinations
2812
   * array.
2813
   * 
2814
   * @return gets the named destinations
2815
   */
2816
  public HashMap getNamedDestinationFromStrings() {
2817 1 1. getNamedDestinationFromStrings : negated conditional → NO_COVERAGE
    if (catalog.get(PdfName.NAMES) != null) {
2818
      PdfDictionary dic = (PdfDictionary) getPdfObjectRelease(catalog
2819
          .get(PdfName.NAMES));
2820 1 1. getNamedDestinationFromStrings : negated conditional → NO_COVERAGE
      if (dic != null) {
2821
        dic = (PdfDictionary) getPdfObjectRelease(dic.get(PdfName.DESTS));
2822 1 1. getNamedDestinationFromStrings : negated conditional → NO_COVERAGE
        if (dic != null) {
2823
          HashMap names = PdfNameTree.readTree(dic);
2824 1 1. getNamedDestinationFromStrings : negated conditional → NO_COVERAGE
          for (Iterator it = names.entrySet().iterator(); it.hasNext();) {
2825
            Map.Entry entry = (Map.Entry) it.next();
2826
            PdfArray arr = getNameArray((PdfObject) entry.getValue());
2827 1 1. getNamedDestinationFromStrings : negated conditional → NO_COVERAGE
            if (arr != null)
2828
              entry.setValue(arr);
2829
            else
2830 1 1. getNamedDestinationFromStrings : removed call to java/util/Iterator::remove → NO_COVERAGE