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