Coverage Report

Created: 2026-08-13 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xpdf-4.06/xpdf/Outline.cc
Line
Count
Source
1
//========================================================================
2
//
3
// Outline.cc
4
//
5
// Copyright 2002-2013 Glyph & Cog, LLC
6
//
7
//========================================================================
8
9
#include <aconf.h>
10
11
#include "gmem.h"
12
#include "gmempp.h"
13
#include "GString.h"
14
#include "GList.h"
15
#include "Error.h"
16
#include "Link.h"
17
#include "TextString.h"
18
#include "Outline.h"
19
20
//------------------------------------------------------------------------
21
22
17.1k
Outline::Outline(Object *outlineObj, XRef *xref) {
23
17.1k
  Object first, last;
24
25
17.1k
  items = NULL;
26
17.1k
  if (!outlineObj->isDict()) {
27
16.7k
    return;
28
16.7k
  }
29
403
  outlineObj->dictLookupNF("First", &first);
30
403
  outlineObj->dictLookupNF("Last", &last);
31
403
  if (first.isRef() && last.isRef()) {
32
133
    items = OutlineItem::readItemList(&first, &last, NULL, xref);
33
133
  }
34
403
  first.free();
35
403
  last.free();
36
403
}
37
38
17.1k
Outline::~Outline() {
39
17.1k
  if (items) {
40
133
    deleteGList(items, OutlineItem);
41
133
  }
42
17.1k
}
43
44
//------------------------------------------------------------------------
45
46
OutlineItem::OutlineItem(Object *itemRefA, Dict *dict,
47
657
       OutlineItem *parentA, XRef *xrefA) {
48
657
  Object obj1;
49
50
657
  xref = xrefA;
51
657
  title = NULL;
52
657
  action = NULL;
53
657
  kids = NULL;
54
657
  parent = parentA;
55
56
657
  if (dict->lookup("Title", &obj1)->isString()) {
57
427
    title = new TextString(obj1.getString());
58
427
  }
59
657
  obj1.free();
60
61
657
  if (!dict->lookup("Dest", &obj1)->isNull()) {
62
82
    action = LinkAction::parseDest(&obj1);
63
575
  } else {
64
575
    obj1.free();
65
575
    if (!dict->lookup("A", &obj1)->isNull()) {
66
333
      action = LinkAction::parseAction(&obj1);
67
333
    }
68
575
  }
69
657
  obj1.free();
70
71
657
  itemRefA->copy(&itemRef);
72
657
  dict->lookupNF("First", &firstRef);
73
657
  dict->lookupNF("Last", &lastRef);
74
657
  dict->lookupNF("Next", &nextRef);
75
76
657
  startsOpen = gFalse;
77
657
  if (dict->lookup("Count", &obj1)->isInt()) {
78
68
    if (obj1.getInt() > 0) {
79
28
      startsOpen = gTrue;
80
28
    }
81
68
  }
82
657
  obj1.free();
83
84
657
  pageNum = -1;
85
657
}
86
87
657
OutlineItem::~OutlineItem() {
88
657
  close();
89
657
  if (title) {
90
427
    delete title;
91
427
  }
92
657
  if (action) {
93
239
    delete action;
94
239
  }
95
657
  itemRef.free();
96
657
  firstRef.free();
97
657
  lastRef.free();
98
657
  nextRef.free();
99
657
}
100
101
GList *OutlineItem::readItemList(Object *firstItemRef, Object *lastItemRef,
102
133
         OutlineItem *parentA, XRef *xrefA) {
103
133
  GList *items;
104
133
  OutlineItem *item, *sibling;
105
133
  Object obj;
106
133
  Object *p;
107
133
  OutlineItem *ancestor;
108
133
  int i;
109
110
133
  items = new GList();
111
133
  if (!firstItemRef->isRef() || !lastItemRef->isRef()) {
112
0
    return items;
113
0
  }
114
133
  p = firstItemRef;
115
696
  do {
116
696
    if (!p->fetch(xrefA, &obj)->isDict()) {
117
39
      obj.free();
118
39
      break;
119
39
    }
120
657
    item = new OutlineItem(p, obj.getDict(), parentA, xrefA);
121
657
    obj.free();
122
123
    // check for loops with parents
124
657
    for (ancestor = parentA; ancestor; ancestor = ancestor->parent) {
125
0
      if (p->getRefNum() == ancestor->itemRef.getRefNum() &&
126
0
    p->getRefGen() == ancestor->itemRef.getRefGen()) {
127
0
  error(errSyntaxError, -1, "Loop detected in outline");
128
0
  break;
129
0
      }
130
0
    }
131
657
    if (ancestor) {
132
0
      delete item;
133
0
      break;
134
0
    }
135
136
    // check for loops with siblings
137
3.42k
    for (i = 0; i < items->getLength(); ++i) {
138
2.79k
      sibling = (OutlineItem *)items->get(i);
139
2.79k
      if (p->getRefNum() == sibling->itemRef.getRefNum() &&
140
31
    p->getRefGen() == sibling->itemRef.getRefGen()) {
141
24
  error(errSyntaxError, -1, "Loop detected in outline");
142
24
  break;
143
24
      }
144
2.79k
    }
145
657
    if (i < items->getLength()) {
146
24
      delete item;
147
24
      break;
148
24
    }
149
150
633
    items->append(item);
151
633
    if (p->getRefNum() == lastItemRef->getRef().num &&
152
55
  p->getRefGen() == lastItemRef->getRef().gen) {
153
55
      break;
154
55
    }
155
578
    p = &item->nextRef;
156
578
    if (!p->isRef()) {
157
15
      break;
158
15
    }
159
578
  } while (p);
160
133
  return items;
161
133
}
162
163
0
void OutlineItem::open() {
164
0
  if (!kids) {
165
0
    kids = readItemList(&firstRef, &lastRef, this, xref);
166
0
  }
167
0
}
168
169
657
void OutlineItem::close() {
170
657
  if (kids) {
171
0
    deleteGList(kids, OutlineItem);
172
0
    kids = NULL;
173
0
  }
174
657
}
175
176
0
Unicode *OutlineItem::getTitle() {
177
0
  return title ? title->getUnicode() : (Unicode *)NULL;
178
0
}
179
180
0
int OutlineItem::getTitleLength() {
181
0
  return title ? title->getLength() : 0;
182
0
}