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