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