Outline.cc 4.1 KB
Newer Older
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1 2 3 4 5 6 7 8
//========================================================================
//
// Outline.cc
//
// Copyright 2002-2003 Glyph & Cog, LLC
//
//========================================================================

9 10 11 12
//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
13 14 15
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
16
// Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
17
// Copyright (C) 2008, 2016-2019 Albert Astals Cid <aacid@kde.org>
18
// Copyright (C) 2009 Nick Jones <nick.jones@network-box.com>
Albert Astals Cid's avatar
Albert Astals Cid committed
19
// Copyright (C) 2016 Jason Crain <jason@aquaticape.us>
Albert Astals Cid's avatar
Albert Astals Cid committed
20
// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
21
// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
Albert Astals Cid's avatar
Albert Astals Cid committed
22
// Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
23
// Copyright (C) 2019 Oliver Sander <oliver.sander@tu-dresden.de>
24 25 26 27 28 29
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================

Kristian Høgsberg's avatar
Kristian Høgsberg committed
30 31 32 33
#include <config.h>

#include "goo/gmem.h"
#include "goo/GooString.h"
34
#include "XRef.h"
Kristian Høgsberg's avatar
Kristian Høgsberg committed
35 36 37
#include "Link.h"
#include "PDFDocEncoding.h"
#include "Outline.h"
38
#include "UTF.h"
Kristian Høgsberg's avatar
Kristian Høgsberg committed
39 40 41

//------------------------------------------------------------------------

Albert Astals Cid's avatar
Albert Astals Cid committed
42
Outline::Outline(const Object *outlineObj, XRef *xref) {
Albert Astals Cid's avatar
Albert Astals Cid committed
43
  items = nullptr;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
44 45 46
  if (!outlineObj->isDict()) {
    return;
  }
47
  const Object &first = outlineObj->dictLookupNF("First");
48
  items = OutlineItem::readItemList(nullptr, &first, xref);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
49 50 51 52
}

Outline::~Outline() {
  if (items) {
53 54 55 56
    for (auto entry : *items) {
      delete entry;
    }
    delete items;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
57 58 59 60 61
  }
}

//------------------------------------------------------------------------

Albert Astals Cid's avatar
Albert Astals Cid committed
62
OutlineItem::OutlineItem(const Dict *dict, int refNumA, OutlineItem *parentA, XRef *xrefA) {
63
  Object obj1;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
64

65 66
  refNum = refNumA;
  parent = parentA;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
67
  xref = xrefA;
68 69 70
  title = nullptr;
  action = nullptr;
  kids = nullptr;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
71

Albert Astals Cid's avatar
Albert Astals Cid committed
72

Adrian Johnson's avatar
Adrian Johnson committed
73
  obj1 = dict->lookup("Title");
Albert Astals Cid's avatar
Albert Astals Cid committed
74
  if (obj1.isString()) {
75
    const GooString *s = obj1.getString();
76
    titleLen = TextStringToUCS4(s, &title);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
77 78 79 80
  } else {
    titleLen = 0;
  }

Albert Astals Cid's avatar
Albert Astals Cid committed
81 82
  obj1 = dict->lookup("Dest");
  if (!obj1.isNull()) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
83 84
    action = LinkAction::parseDest(&obj1);
  } else {
Albert Astals Cid's avatar
Albert Astals Cid committed
85 86 87 88
    obj1 = dict->lookup("A");
    if (!obj1.isNull()) {
      action = LinkAction::parseAction(&obj1);
    }
89
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
90

91 92 93
  firstRef = dict->lookupNF("First").copy();
  lastRef = dict->lookupNF("Last").copy();
  nextRef = dict->lookupNF("Next").copy();
Kristian Høgsberg's avatar
Kristian Høgsberg committed
94

95
  startsOpen = false;
Albert Astals Cid's avatar
Albert Astals Cid committed
96 97
  obj1 = dict->lookup("Count");
  if (obj1.isInt()) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
98
    if (obj1.getInt() > 0) {
99
      startsOpen = true;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
100 101 102 103 104 105 106 107 108 109 110 111 112 113
    }
  }
}

OutlineItem::~OutlineItem() {
  close();
  if (title) {
    gfree(title);
  }
  if (action) {
    delete action;
  }
}

114 115
std::vector<OutlineItem*> *OutlineItem::readItemList(OutlineItem *parent, const Object *firstItemRef, XRef *xrefA) {
  auto items = new std::vector<OutlineItem*>();
Kristian Høgsberg's avatar
Kristian Høgsberg committed
116

117
  char* alreadyRead = (char *)gmalloc(xrefA->getNumObjects());
118 119
  memset(alreadyRead, 0, xrefA->getNumObjects());

120 121 122 123 124 125
  OutlineItem *parentO = parent;
  while (parentO) {
    alreadyRead[parentO->refNum] = 1;
    parentO = parentO->parent;
  }

Albert Astals Cid's avatar
Albert Astals Cid committed
126
  const Object *p = firstItemRef;
127 128
  while (p->isRef() && 
	 (p->getRefNum() >= 0) && 
129
         (p->getRefNum() < xrefA->getNumObjects()) &&
130
         !alreadyRead[p->getRefNum()]) {
Albert Astals Cid's avatar
Albert Astals Cid committed
131 132
    Object obj = p->fetch(xrefA);
    if (!obj.isDict()) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
133 134
      break;
    }
135
    alreadyRead[p->getRefNum()] = 1;
136
    OutlineItem *item = new OutlineItem(obj.getDict(), p->getRefNum(), parent, xrefA);
137
    items->push_back(item);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
138 139
    p = &item->nextRef;
  }
140

141 142
  gfree(alreadyRead);

143
  if (items->empty()) {
144
    delete items;
145
    items = nullptr;
146 147
  }

Kristian Høgsberg's avatar
Kristian Høgsberg committed
148 149 150 151 152
  return items;
}

void OutlineItem::open() {
  if (!kids) {
153
    kids = readItemList(this, &firstRef, xref);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
154 155 156 157 158
  }
}

void OutlineItem::close() {
  if (kids) {
159 160 161 162
    for (auto entry : *kids) {
      delete entry;
    }
    delete kids;
163
    kids = nullptr;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
164 165
  }
}