text: //========================================================================
  //
  // 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, 2017 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>
  //
  // 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(Object *outlineObj, XRef *xref) {
    items = nullptr;
    if (!outlineObj->isDict()) {
      return;
    }
    Object first = outlineObj->dictLookupNF("First");
    items = OutlineItem::readItemList(&first, xref);
  }
  
  Outline::~Outline() {
    if (items) {
      deleteGooList(items, OutlineItem);
    }
  }
  
  //------------------------------------------------------------------------
  
  OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) {
    Object obj1;
  
    xref = xrefA;
    title = NULL;
    action = NULL;
    kids = NULL;
  
  
    obj1 = dict->lookup("Title");
    if (obj1.isString()) {
      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(Object *firstItemRef, XRef *xrefA) {
    GooList *items;
    char* alreadyRead;
    OutlineItem *item;
    Object *p;
  
    items = new GooList();
  
    alreadyRead = (char *)gmalloc(xrefA->getNumObjects());
    memset(alreadyRead, 0, xrefA->getNumObjects());
  
    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;
      item = new OutlineItem(obj.getDict(), xrefA);
      items->append(item);
      p = &item->nextRef;
    }
  
    gfree(alreadyRead);
  
    if (!items->getLength()) {
      delete items;
      items = NULL;
    }
  
    return items;
  }
  
  void OutlineItem::open() {
    if (!kids) {
      kids = readItemList(&firstRef, xref);
    }
  }
  
  void OutlineItem::close() {
    if (kids) {
      deleteGooList(kids, OutlineItem);
      kids = NULL;
    }
  }
  