| //======================================================================== |
| // |
| // Outline.cc |
| // |
| // Copyright 2002-2003 Glyph & Cog, LLC |
| // |
| //======================================================================== |
| |
| //======================================================================== |
| // |
| // Modified under the Poppler project - http://poppler.freedesktop.org |
| // |
| // All changes made under the Poppler project to this file are licensed |
| // under GPL version 2 or later |
| // |
| // Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com> |
| // Copyright (C) 2008, 2016-2019 Albert Astals Cid <aacid@kde.org> |
| // Copyright (C) 2009 Nick Jones <nick.jones@network-box.com> |
| // Copyright (C) 2016 Jason Crain <jason@aquaticape.us> |
| // Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com> |
| // 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 |
| // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de> |
| // Copyright (C) 2019 Oliver Sander <oliver.sander@tu-dresden.de> |
| // |
| // 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 |
| // |
| //======================================================================== |
| |
| #include <config.h> |
| |
| #include "goo/gmem.h" |
| #include "goo/GooString.h" |
| #include "XRef.h" |
| #include "Link.h" |
| #include "PDFDocEncoding.h" |
| #include "Outline.h" |
| #include "UTF.h" |
| |
| //------------------------------------------------------------------------ |
| |
| Outline::Outline(const Object *outlineObj, XRef *xref) { |
| items = nullptr; |
| if (!outlineObj->isDict()) { |
| return; |
| } |
| const Object &first = outlineObj->dictLookupNF("First"); |
| items = OutlineItem::readItemList(nullptr, &first, xref); |
| } |
| |
| Outline::~Outline() { |
| if (items) { |
| for (auto entry : *items) { |
| delete entry; |
| } |
| delete items; |
| } |
| } |
| |
| //------------------------------------------------------------------------ |
| |
| OutlineItem::OutlineItem(const Dict *dict, int refNumA, OutlineItem *parentA, XRef *xrefA) { |
| Object obj1; |
| |
| refNum = refNumA; |
| parent = parentA; |
| xref = xrefA; |
| title = nullptr; |
| action = nullptr; |
| kids = nullptr; |
| |
| |
| obj1 = dict->lookup("Title"); |
| if (obj1.isString()) { |
| const GooString *s = obj1.getString(); |
| titleLen = TextStringToUCS4(s, &title); |
| } else { |
| titleLen = 0; |
| } |
| |
| obj1 = dict->lookup("Dest"); |
| if (!obj1.isNull()) { |
| action = LinkAction::parseDest(&obj1); |
| } else { |
| obj1 = dict->lookup("A"); |
| if (!obj1.isNull()) { |
| action = LinkAction::parseAction(&obj1); |
| } |
| } |
| |
| firstRef = dict->lookupNF("First").copy(); |
| lastRef = dict->lookupNF("Last").copy(); |
| nextRef = dict->lookupNF("Next").copy(); |
| |
| startsOpen = false; |
| obj1 = dict->lookup("Count"); |
| if (obj1.isInt()) { |
| if (obj1.getInt() > 0) { |
| startsOpen = true; |
| } |
| } |
| } |
| |
| OutlineItem::~OutlineItem() { |
| close(); |
| if (title) { |
| gfree(title); |
| } |
| if (action) { |
| delete action; |
| } |
| } |
| |
| std::vector<OutlineItem*> *OutlineItem::readItemList(OutlineItem *parent, const Object *firstItemRef, XRef *xrefA) { |
| auto items = new std::vector<OutlineItem*>(); |
| |
| char* alreadyRead = (char *)gmalloc(xrefA->getNumObjects()); |
| memset(alreadyRead, 0, xrefA->getNumObjects()); |
| |
| OutlineItem *parentO = parent; |
| while (parentO) { |
| alreadyRead[parentO->refNum] = 1; |
| parentO = parentO->parent; |
| } |
| |
| const Object *p = firstItemRef; |
| while (p->isRef() && |
| (p->getRefNum() >= 0) && |
| (p->getRefNum() < xrefA->getNumObjects()) && |
| !alreadyRead[p->getRefNum()]) { |
| Object obj = p->fetch(xrefA); |
| if (!obj.isDict()) { |
| break; |
| } |
| alreadyRead[p->getRefNum()] = 1; |
| OutlineItem *item = new OutlineItem(obj.getDict(), p->getRefNum(), parent, xrefA); |
| items->push_back(item); |
| p = &item->nextRef; |
| } |
| |
| gfree(alreadyRead); |
| |
| if (items->empty()) { |
| delete items; |
| items = nullptr; |
| } |
| |
| return items; |
| } |
| |
| void OutlineItem::open() { |
| if (!kids) { |
| kids = readItemList(this, &firstRef, xref); |
| } |
| } |
| |
| void OutlineItem::close() { |
| if (kids) { |
| for (auto entry : *kids) { |
| delete entry; |
| } |
| delete kids; |
| kids = nullptr; |
| } |
| } |