Coverage Report

Created: 2026-07-30 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poppler/poppler/Linearization.cc
Line
Count
Source
1
//========================================================================
2
//
3
// Linearization.cc
4
//
5
// This file is licensed under the GPLv2 or later
6
//
7
// Copyright 2010, 2012 Hib Eris <hib@hiberis.nl>
8
// Copyright 2015 Jason Crain <jason@aquaticape.us>
9
// Copyright 2017, 2019, 2025 Albert Astals Cid <aacid@kde.org>
10
// Copyright 2019 Adam Reichold <adam.reichold@t-online.de>
11
// Copyright 2019 Even Rouault <even.rouault@spatialys.com>
12
// Copyright 2025 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk>
13
// Copyright (C) 2025 Jonathan Hähne <jonathan.haehne@hotmail.com>
14
// Copyright (C) 2025 Arnav V <arnav0872@gmail.com>
15
// Copyright (C) 2026 Adam Sampson <ats@offog.org>
16
//
17
//========================================================================
18
19
#include "Linearization.h"
20
#include "Parser.h"
21
22
//------------------------------------------------------------------------
23
// Linearization
24
//------------------------------------------------------------------------
25
26
Linearization::Linearization(BaseStream *str)
27
7.13k
{
28
7.13k
    Parser *parser;
29
30
7.13k
    (void)str->rewind();
31
7.13k
    parser = new Parser(nullptr, str->makeSubStream(str->getStart(), false, 0, Object::null()), false);
32
7.13k
    Object obj1 = parser->getObj();
33
7.13k
    Object obj2 = parser->getObj();
34
7.13k
    Object obj3 = parser->getObj();
35
7.13k
    linDict = parser->getObj();
36
7.13k
    if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && linDict.isDict()) {
37
1.26k
        Object obj5 = linDict.dictLookup("Linearized");
38
1.26k
        if (!obj5.isNum() || obj5.getNum() <= 0) {
39
1.26k
            linDict.setToNull();
40
1.26k
        }
41
5.86k
    } else {
42
5.86k
        linDict.setToNull();
43
5.86k
    }
44
7.13k
    delete parser;
45
7.13k
}
46
47
7.13k
Linearization::~Linearization() = default;
48
49
unsigned int Linearization::getLength() const
50
57.6k
{
51
57.6k
    if (!linDict.isDict()) {
52
57.6k
        return 0;
53
57.6k
    }
54
55
0
    int length;
56
0
    if (linDict.getDict()->lookupInt("L", {}, &length) && length > 0) {
57
0
        return length;
58
0
    }
59
0
    error(errSyntaxWarning, -1, "Length in linearization table is invalid");
60
0
    return 0;
61
0
}
62
63
unsigned int Linearization::getHintsOffset() const
64
0
{
65
0
    int hintsOffset;
66
67
0
    Object obj1, obj2;
68
0
    if (linDict.isDict() && (obj1 = linDict.dictLookup("H"), obj1.isArrayOfLengthAtLeast(2)) && (obj2 = obj1.arrayGet(0), obj2.isInt()) && obj2.getInt() > 0) {
69
0
        hintsOffset = obj2.getInt();
70
0
    } else {
71
0
        error(errSyntaxWarning, -1, "Hints table offset in linearization table is invalid");
72
0
        hintsOffset = 0;
73
0
    }
74
75
0
    return hintsOffset;
76
0
}
77
78
unsigned int Linearization::getHintsLength() const
79
0
{
80
0
    int hintsLength;
81
82
0
    Object obj1, obj2;
83
0
    if (linDict.isDict() && (obj1 = linDict.dictLookup("H"), obj1.isArrayOfLengthAtLeast(2)) && (obj2 = obj1.arrayGet(1), obj2.isInt()) && obj2.getInt() > 0) {
84
0
        hintsLength = obj2.getInt();
85
0
    } else {
86
0
        error(errSyntaxWarning, -1, "Hints table length in linearization table is invalid");
87
0
        hintsLength = 0;
88
0
    }
89
90
0
    return hintsLength;
91
0
}
92
93
unsigned int Linearization::getHintsOffset2() const
94
0
{
95
0
    int hintsOffset2 = 0; // default to 0
96
97
0
    Object obj1;
98
0
    if (linDict.isDict() && (obj1 = linDict.dictLookup("H"), obj1.isArrayOfLengthAtLeast(4))) {
99
0
        Object obj2 = obj1.arrayGet(2);
100
0
        if (obj2.isInt() && obj2.getInt() > 0) {
101
0
            hintsOffset2 = obj2.getInt();
102
0
        } else {
103
0
            error(errSyntaxWarning, -1, "Second hints table offset in linearization table is invalid");
104
0
            hintsOffset2 = 0;
105
0
        }
106
0
    }
107
108
0
    return hintsOffset2;
109
0
}
110
111
unsigned int Linearization::getHintsLength2() const
112
0
{
113
0
    int hintsLength2 = 0; // default to 0
114
115
0
    Object obj1;
116
0
    if (linDict.isDict() && (obj1 = linDict.dictLookup("H"), obj1.isArrayOfLengthAtLeast(4))) {
117
0
        Object obj2 = obj1.arrayGet(3);
118
0
        if (obj2.isInt() && obj2.getInt() > 0) {
119
0
            hintsLength2 = obj2.getInt();
120
0
        } else {
121
0
            error(errSyntaxWarning, -1, "Second hints table length in linearization table is invalid");
122
0
            hintsLength2 = 0;
123
0
        }
124
0
    }
125
126
0
    return hintsLength2;
127
0
}
128
129
int Linearization::getObjectNumberFirst() const
130
0
{
131
0
    int objectNumberFirst = 0;
132
0
    if (linDict.isDict() && linDict.getDict()->lookupInt("O", {}, &objectNumberFirst) && objectNumberFirst > 0) {
133
0
        return objectNumberFirst;
134
0
    }
135
0
    error(errSyntaxWarning, -1, "Object number of first page in linearization table is invalid");
136
0
    return 0;
137
0
}
138
139
unsigned int Linearization::getEndFirst() const
140
0
{
141
0
    int pageEndFirst = 0;
142
0
    if (linDict.isDict() && linDict.getDict()->lookupInt("E", {}, &pageEndFirst) && pageEndFirst > 0) {
143
0
        return pageEndFirst;
144
0
    }
145
0
    error(errSyntaxWarning, -1, "First page end offset in linearization table is invalid");
146
0
    return 0;
147
0
}
148
149
int Linearization::getNumPages() const
150
0
{
151
0
    int numPages = 0;
152
0
    if (linDict.isDict() && linDict.getDict()->lookupInt("N", {}, &numPages) && numPages > 0) {
153
0
        return numPages;
154
0
    }
155
0
    error(errSyntaxWarning, -1, "Page count in linearization table is invalid");
156
0
    return 0;
157
0
}
158
159
unsigned int Linearization::getMainXRefEntriesOffset() const
160
0
{
161
0
    int mainXRefEntriesOffset = 0;
162
0
    if (linDict.isDict() && linDict.getDict()->lookupInt("T", {}, &mainXRefEntriesOffset) && mainXRefEntriesOffset > 0) {
163
0
        return mainXRefEntriesOffset;
164
0
    }
165
0
    error(errSyntaxWarning, -1, "Main Xref offset in linearization table is invalid");
166
0
    return 0;
167
0
}
168
169
int Linearization::getPageFirst() const
170
0
{
171
0
    int pageFirst = 0; // Optional, defaults to 0.
172
173
0
    if (linDict.isDict()) {
174
0
        linDict.getDict()->lookupInt("P", {}, &pageFirst);
175
0
    }
176
177
0
    if ((pageFirst < 0) || (pageFirst >= getNumPages())) {
178
0
        error(errSyntaxWarning, -1, "First page in linearization table is invalid");
179
0
        return 0;
180
0
    }
181
182
0
    return pageFirst;
183
0
}