blob: c6b12dc0366718d6bd144bca3c6ca62c5f2b03d8 [file] [log] [blame]
//========================================================================
//
// 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-2018 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
//
// 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>
#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
#include "goo/gmem.h"
#include "goo/GooString.h"
#include "goo/GooList.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;
}
Object first = outlineObj->dictLookupNF("First");
items = OutlineItem::readItemList(nullptr, &first, xref);
}
Outline::~Outline() {
if (items) {
deleteGooList(items, OutlineItem);
}
}
//------------------------------------------------------------------------
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");
lastRef = dict->lookupNF("Last");
nextRef = dict->lookupNF("Next");
startsOpen = gFalse;
obj1 = dict->lookup("Count");
if (obj1.isInt()) {
if (obj1.getInt() > 0) {
startsOpen = gTrue;
}
}
}
OutlineItem::~OutlineItem() {
close();
if (title) {
gfree(title);
}
if (action) {
delete action;
}
}
GooList *OutlineItem::readItemList(OutlineItem *parent, const Object *firstItemRef, XRef *xrefA) {
GooList *items = new GooList();
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->append(item);
p = &item->nextRef;
}
gfree(alreadyRead);
if (!items->getLength()) {
delete items;
items = nullptr;
}
return items;
}
void OutlineItem::open() {
if (!kids) {
kids = readItemList(this, &firstRef, xref);
}
}
void OutlineItem::close() {
if (kids) {
deleteGooList(kids, OutlineItem);
kids = nullptr;
}
}