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